paraFoam -block: Added support for vertex and block names

Patch contributed by Mattijs Janssens
This commit is contained in:
Henry Weller
2016-11-04 17:29:02 +00:00
parent 7781656347
commit 3ab919d407
21 changed files with 398 additions and 199 deletions

View File

@ -72,12 +72,17 @@ void Foam::vtkPVblockMesh::updateInfoBlocks
arrayRangeBlocks_.reset( arraySelection->GetNumberOfArrays() );
const blockMesh& blkMesh = *meshPtr_;
const int nBlocks = blkMesh.size();
for (int blockI = 0; blockI < nBlocks; ++blockI)
{
const blockDescriptor& blockDef = blkMesh[blockI];
word partName = Foam::name(blockI);
// Display either blockI as a number or with its name
// (looked up from blockMeshDict)
OStringStream os;
blockDescriptor::write(os, blockI, blkMesh.meshDict());
word partName(os.str());
// append the (optional) zone name
if (!blockDef.zoneName().empty())
@ -121,9 +126,10 @@ void Foam::vtkPVblockMesh::updateInfoEdges
forAll(edges, edgeI)
{
OStringStream ostr;
ostr<< edges[edgeI].start() << ":" << edges[edgeI].end() << " - "
<< edges[edgeI].type();
blockVertex::write(ostr, edges[edgeI].start(), blkMesh.meshDict());
ostr<< ":";
blockVertex::write(ostr, edges[edgeI].end(), blkMesh.meshDict());
ostr << " - " << edges[edgeI].type();
// Add "beg:end - type" to GUI list
arraySelection->AddArray(ostr.str().c_str());
@ -352,7 +358,9 @@ void Foam::vtkPVblockMesh::updateFoamMesh()
dictPath = dbPtr_().constant()/polyMesh::meshSubDir/dictName;
}
IOdictionary meshDict
// Store dictionary since is used as database inside blockMesh class
// for names of vertices and blocks
IOdictionary* meshDictPtr = new IOdictionary
(
IOobject
(
@ -360,11 +368,12 @@ void Foam::vtkPVblockMesh::updateFoamMesh()
dbPtr_(),
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE,
false
true
)
);
meshDictPtr->store();
meshPtr_ = new blockMesh(meshDict, meshRegion_);
meshPtr_ = new blockMesh(*meshDictPtr, meshRegion_);
}
@ -429,15 +438,22 @@ void Foam::vtkPVblockMesh::renderPointNumbers
if (show && meshPtr_)
{
const pointField& cornerPts = meshPtr_->vertices();
const scalar scaleFactor = meshPtr_->scaleFactor();
const blockMesh& blkMesh = *meshPtr_;
const pointField& cornerPts = blkMesh.vertices();
const scalar scaleFactor = blkMesh.scaleFactor();
pointNumberTextActorsPtrs_.setSize(cornerPts.size());
forAll(cornerPts, pointi)
{
vtkTextActor* txt = vtkTextActor::New();
txt->SetInput(Foam::name(pointi).c_str());
// Display either pointi as a number or with its name
// (looked up from blockMeshDict)
{
OStringStream os;
blockVertex::write(os, pointi, blkMesh.meshDict());
txt->SetInput(os.str().c_str());
}
// Set text properties
vtkTextProperty* tprop = txt->GetTextProperty();

View File

@ -630,6 +630,21 @@ const Foam::dictionary* Foam::dictionary::subDictPtr(const word& keyword) const
}
Foam::dictionary* Foam::dictionary::subDictPtr(const word& keyword)
{
entry* entryPtr = lookupEntryPtr(keyword, false, true);
if (entryPtr)
{
return &entryPtr->dict();
}
else
{
return nullptr;
}
}
const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const
{
const entry* entryPtr = lookupEntryPtr(keyword, false, true);

View File

@ -379,6 +379,10 @@ public:
// otherwise return nullptr.
const dictionary* subDictPtr(const word&) const;
//- Find and return a sub-dictionary pointer if present
// otherwise return nullptr.
dictionary* subDictPtr(const word&);
//- Find and return a sub-dictionary
const dictionary& subDict(const word&) const;

View File

@ -36,6 +36,8 @@ blockMesh/blockMeshCheck.C
blockMesh/blockMeshMerge.C
blockMesh/blockMeshMergeFast.C
blockMeshTools/blockMeshTools.C
searchableCurve/searchableCurve.C
LIB = $(FOAM_LIBBIN)/libblockMesh

View File

@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "blockDescriptor.H"
#include "blockMeshTools.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -128,90 +129,6 @@ void Foam::blockDescriptor::findCurvedFaces()
}
void Foam::blockDescriptor::read
(
Istream& is,
label& val,
const dictionary& dict
)
{
token t(is);
if (t.isLabel())
{
val = t.labelToken();
}
else if (t.isWord())
{
const word& varName = t.wordToken();
const entry* ePtr = dict.lookupScopedEntryPtr
(
varName,
true,
true
);
if (ePtr)
{
// Read as label
val = Foam::readLabel(ePtr->stream());
}
else
{
FatalIOErrorInFunction(is)
<< "Undefined variable "
<< varName << ". Valid variables are " << dict
<< exit(FatalIOError);
}
}
else
{
FatalIOErrorInFunction(is)
<< "Illegal token " << t.info()
<< " when trying to read label"
<< exit(FatalIOError);
}
is.fatalCheck
(
"operator>>(Istream&, List<T>&) : reading entry"
);
}
Foam::label Foam::blockDescriptor::read
(
Istream& is,
const dictionary& dict
)
{
label val;
read(is, val, dict);
return val;
}
void Foam::blockDescriptor::write
(
Ostream& os,
const label val,
const dictionary& dict
)
{
forAllConstIter(dictionary, dict, iter)
{
if (iter().isStream())
{
label keyVal(Foam::readLabel(iter().stream()));
if (keyVal == val)
{
os << iter().keyword();
return;
}
}
}
os << val;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::blockDescriptor::blockDescriptor
@ -270,7 +187,7 @@ Foam::blockDescriptor::blockDescriptor
blockShape_ = cellShape
(
model,
read<label>
blockMeshTools::read<label>
(
is,
dict.subOrEmptyDict("namedVertices")
@ -444,6 +361,25 @@ void Foam::blockDescriptor::correctFacePoints
}
void Foam::blockDescriptor::write
(
Ostream& os,
const label val,
const dictionary& d
)
{
const dictionary* varDictPtr = d.subDictPtr("namedBlocks");
if (varDictPtr)
{
blockMeshTools::write(os, val, *varDictPtr);
}
else
{
os << val;
}
}
// * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const blockDescriptor& bd)

View File

@ -238,22 +238,8 @@ public:
// to lie on the faces of the block
void correctFacePoints(FixedList<pointField, 6>&) const;
//- In-place read with dictionary lookup
static void read(Istream&, label&, const dictionary&);
//- In-place read with dictionary lookup
template<class T>
static void read(Istream&, List<T>&, const dictionary&);
//- Return-read with dictionary lookup
static label read(Istream&, const dictionary&);
//- Return-read with dictionary lookup
template<class T>
static List<T> read(Istream& is, const dictionary&);
//- Write with dictionary lookup
static void write(Ostream&, const label, const dictionary&);
//- Write block index with dictionary lookup
static void write(Ostream&, const label blocki, const dictionary&);
// IOstream Operators
@ -270,10 +256,6 @@ public:
#include "blockDescriptorI.H"
#ifdef NoRepository
#include "blockDescriptorTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif

View File

@ -24,7 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "blockEdge.H"
#include "blockDescriptor.H"
#include "blockVertex.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -59,8 +59,8 @@ Foam::blockEdge::blockEdge
)
:
points_(points),
start_(blockDescriptor::read(is, dict.subOrEmptyDict("namedVertices"))),
end_(blockDescriptor::read(is, dict.subOrEmptyDict("namedVertices")))
start_(blockVertex::read(is, dict)),
end_(blockVertex::read(is, dict))
{}
@ -146,20 +146,10 @@ Foam::blockEdge::position(const scalarList& lambdas) const
void Foam::blockEdge::write(Ostream& os, const dictionary& d) const
{
const dictionary* varDictPtr = d.subDictPtr("namedVertices");
if (varDictPtr)
{
const dictionary& varDict = *varDictPtr;
blockDescriptor::write(os, start_, varDict);
os << tab;
blockDescriptor::write(os, end_, varDict);
os << endl;
}
else
{
os << start_ << tab << end_ << endl;
}
blockVertex::write(os, start_, d);
os << tab;
blockVertex::write(os, end_, d);
os << endl;
}

View File

@ -24,7 +24,8 @@ License
\*---------------------------------------------------------------------------*/
#include "blockFace.H"
#include "blockDescriptor.H"
#include "blockMeshTools.H"
#include "blockVertex.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -52,7 +53,7 @@ Foam::blockFace::blockFace
:
vertices_
(
blockDescriptor::read<label>
blockMeshTools::read<label>
(
is,
dict.subOrEmptyDict("namedVertices")
@ -104,28 +105,18 @@ Foam::autoPtr<Foam::blockFace> Foam::blockFace::New
void Foam::blockFace::write(Ostream& os, const dictionary& d) const
{
const dictionary* varDictPtr = d.subDictPtr("namedVertices");
if (varDictPtr)
// Write size and start delimiter
os << vertices_.size() << token::BEGIN_LIST;
// Write contents
forAll(vertices_, i)
{
const dictionary& varDict = *varDictPtr;
// Write size and start delimiter
os << vertices_.size() << token::BEGIN_LIST;
// Write contents
forAll(vertices_, i)
{
if (i > 0) os << token::SPACE;
blockDescriptor::write(os, vertices_[i], varDict);
}
// Write end delimiter
os << token::END_LIST;
}
else
{
os << vertices_ << endl;
if (i > 0) os << token::SPACE;
blockVertex::write(os, vertices_[i], d);
}
// Write end delimiter
os << token::END_LIST;
}

View File

@ -38,33 +38,34 @@ namespace Foam
Foam::blockMesh::blockMesh(const IOdictionary& dict, const word& regionName)
:
verboseOutput(dict.lookupOrDefault<Switch>("verbose", true)),
meshDict_(dict),
verboseOutput(meshDict_.lookupOrDefault<Switch>("verbose", true)),
geometry_
(
IOobject
(
"geometry", // dummy name
dict.time().constant(), // instance
meshDict_.time().constant(), // instance
"geometry", // local
dict.time(), // registry
meshDict_.time(), // registry
IOobject::MUST_READ,
IOobject::NO_WRITE
),
dict.found("geometry")
? dict.subDict("geometry")
meshDict_.found("geometry")
? meshDict_.subDict("geometry")
: dictionary(),
true
),
scaleFactor_(1.0),
blockVertices_
(
dict.lookup("vertices"),
blockVertex::iNew(dict, geometry_)
meshDict_.lookup("vertices"),
blockVertex::iNew(meshDict_, geometry_)
),
vertices_(Foam::vertices(blockVertices_)),
topologyPtr_(createTopology(dict, regionName))
topologyPtr_(createTopology(meshDict_, regionName))
{
Switch fastMerge(dict.lookupOrDefault<Switch>("fastMerge", false));
Switch fastMerge(meshDict_.lookupOrDefault<Switch>("fastMerge", false));
if (fastMerge)
{

View File

@ -65,6 +65,9 @@ class blockMesh
{
// Private data
//- Reference to mesh dictionary
const IOdictionary& meshDict_;
//- Switch for verbose output
bool verboseOutput;
@ -178,6 +181,12 @@ public:
// Access
//- Access to input dictionary
const dictionary& meshDict() const
{
return meshDict_;
}
//- Optional searchable geometry to project face-points to
const searchableSurfaces& geometry() const
{

View File

@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "blockMesh.H"
#include "blockMeshTools.H"
#include "Time.H"
#include "preservePatchTypes.H"
#include "emptyPolyPatch.H"
@ -165,7 +166,7 @@ void Foam::blockMesh::readPatches
>> patchNames[nPatches];
// Read patch faces
tmpBlocksPatches[nPatches] = blockDescriptor::read<face>
tmpBlocksPatches[nPatches] = blockMeshTools::read<face>
(
patchStream,
varDict
@ -300,7 +301,7 @@ void Foam::blockMesh::readBoundary
patchDicts.set(patchi, new dictionary(patchInfo.dict()));
// Read block faces
tmpBlocksPatches[patchi] = blockDescriptor::read<face>
tmpBlocksPatches[patchi] = blockMeshTools::read<face>
(
patchDicts[patchi].lookup("faces"),
varDict

View File

@ -0,0 +1,136 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "blockMeshTools.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::blockMeshTools::read
(
Istream& is,
label& val,
const dictionary& dict
)
{
token t(is);
if (t.isLabel())
{
val = t.labelToken();
}
else if (t.isWord())
{
const word& varName = t.wordToken();
const entry* ePtr = dict.lookupScopedEntryPtr
(
varName,
true,
true
);
if (ePtr)
{
// Read as label
val = Foam::readLabel(ePtr->stream());
}
else
{
FatalIOErrorInFunction(is)
<< "Undefined variable "
<< varName << ". Valid variables are " << dict
<< exit(FatalIOError);
}
}
else
{
FatalIOErrorInFunction(is)
<< "Illegal token " << t.info()
<< " when trying to read label"
<< exit(FatalIOError);
}
is.fatalCheck
(
"operator>>(Istream&, List<T>&) : reading entry"
);
}
Foam::label Foam::blockMeshTools::read
(
Istream& is,
const dictionary& dict
)
{
label val;
read(is, val, dict);
return val;
}
void Foam::blockMeshTools::write
(
Ostream& os,
const label val,
const dictionary& dict
)
{
forAllConstIter(dictionary, dict, iter)
{
if (iter().isStream())
{
label keyVal(Foam::readLabel(iter().stream()));
if (keyVal == val)
{
os << iter().keyword();
return;
}
}
}
os << val;
}
const Foam::keyType& Foam::blockMeshTools::findEntry
(
const dictionary& dict,
const label val
)
{
forAllConstIter(dictionary, dict, iter)
{
if (iter().isStream())
{
label keyVal(Foam::readLabel(iter().stream()));
if (keyVal == val)
{
return iter().keyword();
}
}
}
return keyType::null;
}
// ************************************************************************* //

View File

@ -0,0 +1,85 @@
/*---------------------------------------------------------------------------* \
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Namespace
Foam::blockMeshTools
Description
Tools for parsing label(List) with dictionary lookup.
SourceFiles
blockMeshTools.C
blockMeshToolsTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef blockMeshTools_H
#define blockMeshTools_H
#include "dictionary.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace blockMeshTools
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- In-place read with dictionary lookup
void read(Istream&, label&, const dictionary&);
//- In-place read with dictionary lookup
template<class T>
void read(Istream&, List<T>&, const dictionary&);
//- Return-read with dictionary lookup
label read(Istream&, const dictionary&);
//- Return-read with dictionary lookup
template<class T>
List<T> read(Istream& is, const dictionary&);
//- Write with dictionary lookup
void write(Ostream&, const label, const dictionary&);
//- Linear search for label entry
const keyType& findEntry(const dictionary&, const label);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace blockMeshTools
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "blockMeshToolsTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -26,7 +26,7 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T>
void Foam::blockDescriptor::read
void Foam::blockMeshTools::read
(
Istream& is,
List<T>& L,
@ -100,7 +100,7 @@ void Foam::blockDescriptor::read
template<class T>
Foam::List<T> Foam::blockDescriptor::read
Foam::List<T> Foam::blockMeshTools::read
(
Istream& is,
const dictionary& dict
@ -111,4 +111,5 @@ Foam::List<T> Foam::blockDescriptor::read
return L;
}
// ************************************************************************* //

View File

@ -25,6 +25,7 @@ License
#include "blockVertex.H"
#include "pointVertex.H"
#include "blockMeshTools.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -104,4 +105,34 @@ Foam::autoPtr<Foam::blockVertex> Foam::blockVertex::New
}
Foam::label Foam::blockVertex::read(Istream& is, const dictionary& dict)
{
const dictionary* varDictPtr = dict.subDictPtr("namedVertices");
if (varDictPtr)
{
return blockMeshTools::read(is, *varDictPtr);
}
return readLabel(is);
}
void Foam::blockVertex::write
(
Ostream& os,
const label val,
const dictionary& d
)
{
const dictionary* varDictPtr = d.subDictPtr("namedVertices");
if (varDictPtr)
{
blockMeshTools::write(os, val, *varDictPtr);
}
else
{
os << val;
}
}
// ************************************************************************* //

View File

@ -121,6 +121,12 @@ public:
// Member Functions
virtual operator point() const = 0;
//- Read vertex index with optional name lookup
static label read(Istream&, const dictionary&);
//- Write vertex index with optional name backsubstitution
static void write(Ostream&, const label, const dictionary&);
};

View File

@ -51,12 +51,9 @@ Foam::blockVertices::namedVertex::namedVertex
name_(is),
vertexPtr_(blockVertex::New(dict, index, geometry, is))
{
//Info<< "Vertex " << name_ << " at " << vertexPtr_().operator point()
// << " has index " << index << endl;
dictionary& d = const_cast<dictionary&>(dict);
const dictionary* varDictPtr = d.subDictPtr("namedVertices");
dictionary* varDictPtr = d.subDictPtr("namedVertices");
if (varDictPtr)
{
const_cast<dictionary&>(*varDictPtr).add(name_, index);

View File

@ -66,7 +66,7 @@ protected:
public:
//- Runtime type information
TypeName("named");
TypeName("name");
// Constructors

View File

@ -53,12 +53,8 @@ Foam::blocks::namedBlock::namedBlock
word(is),
block(dict, index, vertices, edges, faces, is)
{
//Info<< "Block " << static_cast<word&>(*this)
// << " has index " << index << endl;
dictionary& d = const_cast<dictionary&>(dict);
const dictionary* varDictPtr = d.subDictPtr("namedBlocks");
dictionary* varDictPtr = d.subDictPtr("namedBlocks");
if (varDictPtr)
{
const_cast<dictionary&>(*varDictPtr).add(*this, index);

View File

@ -56,7 +56,7 @@ class namedBlock
public:
//- Runtime type information
TypeName("named");
TypeName("name");
// Constructors

View File

@ -47,40 +47,40 @@ geometry
vertices
(
// Vertical cylinder
named v0 project (-1 -0.1 -1) (cylinder cylinder2)
named v1 project ( 1 -0.1 -1) (cylinder)
named v2 project ( 1 0.9 -1) (cylinder)
named v3 project (-1 0.9 -1) (cylinder cylinder2)
named v4 project (-1 -0.1 1) (cylinder cylinder2)
named v5 project ( 1 -0.1 1) (cylinder)
named v6 project ( 1 0.9 1) (cylinder)
named v7 project (-1 0.9 1) (cylinder cylinder2)
name v0 project (-1 -0.1 -1) (cylinder cylinder2)
name v1 project ( 1 -0.1 -1) (cylinder)
name v2 project ( 1 0.9 -1) (cylinder)
name v3 project (-1 0.9 -1) (cylinder cylinder2)
name v4 project (-1 -0.1 1) (cylinder cylinder2)
name v5 project ( 1 -0.1 1) (cylinder)
name v6 project ( 1 0.9 1) (cylinder)
name v7 project (-1 0.9 1) (cylinder cylinder2)
// Horizontal cylinder
named v8 project (-4 0 -0.5) (cylinder2 inletPlane)
named v9 project (-4 1 -0.5) (cylinder2 inletPlane)
named v10 project (-4 0 0.5) (cylinder2 inletPlane)
named v11 project (-4 1 0.5) (cylinder2 inletPlane)
name v8 project (-4 0 -0.5) (cylinder2 inletPlane)
name v9 project (-4 1 -0.5) (cylinder2 inletPlane)
name v10 project (-4 0 0.5) (cylinder2 inletPlane)
name v11 project (-4 1 0.5) (cylinder2 inletPlane)
// On top of vertical cylinder
named v12 project (-1 2 -1) (cylinder)
named v13 project ( 1 2 -1) (cylinder)
named v14 project ( 1 2 1) (cylinder)
named v15 project (-1 2 1) (cylinder)
name v12 project (-1 2 -1) (cylinder)
name v13 project ( 1 2 -1) (cylinder)
name v14 project ( 1 2 1) (cylinder)
name v15 project (-1 2 1) (cylinder)
// Below vertical cylinder
named v16 project (-1 -1 -1) (cylinder)
named v17 project ( 1 -1 -1) (cylinder)
named v18 project ( 1 -1 1) (cylinder)
named v19 project (-1 -1 1) (cylinder)
name v16 project (-1 -1 -1) (cylinder)
name v17 project ( 1 -1 -1) (cylinder)
name v18 project ( 1 -1 1) (cylinder)
name v19 project (-1 -1 1) (cylinder)
);
blocks
(
hex (v0 v1 v2 v3 v4 v5 v6 v7) (8 8 8) simpleGrading (1 1 1)
named sideBlock hex (v0 v3 v9 v8 v4 v7 v11 v10) (8 20 8)
name sideBlock hex (v0 v3 v9 v8 v4 v7 v11 v10) (8 20 8)
simpleGrading (1 1 1)
hex ( v7 v6 v2 v3 v15 v14 v13 v12) (8 8 8) simpleGrading (1 1 1)