ENH: provide OpenFOAM/VTK low-level transcription routines

- Zero-copy does not work for several reasons, but this uses the
  OpenFOAM structures to write VTK-compatible formats into external
  arrays.
This commit is contained in:
Mark Olesen
2017-05-12 15:35:08 +02:00
parent 710f23aa35
commit 12353e71e7
13 changed files with 2311 additions and 969 deletions

View File

@ -25,6 +25,8 @@ starcd/STARCDMeshWriter.C
polyDualMesh/polyDualMesh.C
vtk/part/foamVtkCells.C
vtk/part/foamVtkMeshMaps.C
vtk/part/foamVtuSizing.C
vtk/output/foamVtkOutput.C
LIB = $(FOAM_LIBBIN)/libconversion

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2107 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -80,7 +80,7 @@ public:
//- Write a value component-wise.
template<class Type>
inline static void write(foamVtkFormatter&, const Type&);
inline static void write(foamVtkFormatter& fmt, const Type& val);
//- Write a list of values.
@ -88,8 +88,8 @@ public:
template<class Type>
static void writeList
(
foamVtkFormatter&,
const UList<Type>&
foamVtkFormatter& fmt,
const UList<Type>& lst
);
@ -98,20 +98,29 @@ public:
template<class Type>
static void writeList
(
foamVtkFormatter&,
const UList<Type>&,
foamVtkFormatter& fmt,
const UList<Type>& lst,
const UList<label>& addressing
);
//- Write volField with cell values (including decomposed cells).
//- Write internalField for mesh
// The output includes the payload size and flush.
template<class Type>
static void writeField
(
foamVtkFormatter&,
const GeometricField<Type, fvPatchField, volMesh>&,
const UList<label>& superCells
foamVtkFormatter& fmt,
const GeometricField<Type, fvPatchField, volMesh>& vf
);
//- Write internalField based on the cellMap
// The output includes the payload size and flush.
template<class Type>
static void writeField
(
foamVtkFormatter& fmt,
const GeometricField<Type, fvPatchField, volMesh>& vf,
const UList<label>& cellMap
);
};

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2107 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -73,19 +73,36 @@ template<class Type>
void Foam::foamVtkOutput::writeField
(
foamVtkFormatter& fmt,
const GeometricField<Type, fvPatchField, volMesh>& vf,
const UList<label>& superCells
const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
const uint64_t payLoad =
(
(vf.size() + superCells.size())
* pTraits<Type>::nComponents * sizeof(float)
vf.size() * pTraits<Type>::nComponents * sizeof(float)
);
fmt.writeSize(payLoad);
writeList(fmt, vf.internalField());
writeList(fmt, vf, superCells);
fmt.flush();
}
template<class Type>
void Foam::foamVtkOutput::writeField
(
foamVtkFormatter& fmt,
const GeometricField<Type, fvPatchField, volMesh>& vf,
const UList<label>& cellMap
)
{
const uint64_t payLoad =
(
cellMap.size() * pTraits<Type>::nComponents * sizeof(float)
);
fmt.writeSize(payLoad);
writeList(fmt, vf.internalField(), cellMap);
fmt.flush();
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,624 +25,133 @@ License
#include "foamVtkCells.H"
#include "polyMesh.H"
#include "cellShape.H"
#include "cellModeller.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::foamVtkCells::correct()
{
// Clear derived data
// clearGeom();
const cellModel& tet = *(cellModeller::lookup("tet"));
const cellModel& pyr = *(cellModeller::lookup("pyr"));
const cellModel& prism = *(cellModeller::lookup("prism"));
const cellModel& wedge = *(cellModeller::lookup("wedge"));
const cellModel& tetWedge = *(cellModeller::lookup("tetWedge"));
const cellModel& hex = *(cellModeller::lookup("hex"));
const cellShapeList& cellShapes = mesh_.cellShapes();
// face owner is needed to determine the face orientation
const labelList& owner = mesh_.faceOwner();
// Unique vertex labels per polyhedral
HashSet<label> hashUniqId(2*256);
// =======================
// PASS 1: Determine sizes
label nVertLabels = 0;
label nFaceLabels = 0;
label nAddPoints = 0;
label nAddCells = 0;
label nAddVerts = 0;
forAll(cellShapes, cellI)
{
const cellShape& shape = cellShapes[cellI];
const cellModel& model = shape.model();
if
(
model == tet
|| model == pyr
|| model == prism
|| model == hex
)
{
// normal primitives
nVertLabels += shape.size();
}
else if (model == tetWedge && decompose_.requested())
{
// Treat as squeezed prism (VTK_WEDGE)
nVertLabels += 6;
}
else if (model == wedge && decompose_.requested())
{
// Treat as squeezed hex
nVertLabels += 8;
}
else if (decompose_.requested())
{
// Polyhedral: Decompose into tets + pyramids.
// Count vertices in first decomposed cell
bool first = true;
const cell& cFaces = mesh_.cells()[cellI];
forAll(cFaces, cFaceI)
{
const face& f = mesh_.faces()[cFaces[cFaceI]];
// Face decomposed into triangles and quads
// Tri -> Tet, Quad -> Pyr
label nTria = 0, nQuad = 0;
f.nTrianglesQuads(mesh_.points(), nTria, nQuad);
nAddCells += nTria + nQuad;
nAddVerts += (nTria * 4) + (nQuad * 5);
if (first)
{
const label nvrt = (nQuad ? 5 : 4);
nAddCells--;
nAddVerts -= nvrt;
nVertLabels += nvrt;
first = false;
}
}
++nAddPoints;
}
else
{
// Polyhedral: Not decomposed.
const labelList& cFaces = mesh_.cells()[cellI];
// establish unique node ids used (only needed for XML)
hashUniqId.clear();
// determing sizing for face stream
// number of faces, size of each face, vertices per face
// [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
forAll(cFaces, cFaceI)
{
const face& f = mesh_.faces()[cFaces[cFaceI]];
nFaceLabels += f.size();
forAll(f, fp)
{
hashUniqId.insert(f[fp]);
}
}
nVertLabels += hashUniqId.size();
nFaceLabels += 1 + cFaces.size();
}
}
//
// adjust/reserve sizes
//
// Cell types (including added cells) in vtk numbering
cellTypes_.setSize(cellShapes.size() + nAddCells);
// List of vertex labels in VTK ordering
vertLabels_.setSize(nVertLabels + nAddVerts);
vertOffset_.setSize(cellShapes.size() + nAddCells);
faceLabels_.clear();
faceOffset_.clear();
if (nFaceLabels)
{
faceLabels_.setSize(nFaceLabels);
// only need nCells (without nAddCells)
// set to -1 (primitive)
faceOffset_.setSize(cellShapes.size(), -1);
}
if (decompose_.requested())
{
decompose_.addPointCellLabels_.setSize(nAddPoints);
decompose_.superCells_.setSize(nAddCells);
}
// ======================
// PASS 2: Fill in arrays
// Need this offset later, but only for decomposed polys
const label offsetAddVerts = nVertLabels;
// Reset counters
nVertLabels = 0;
nFaceLabels = 0;
nAddPoints = 0;
nAddCells = 0;
nAddVerts = 0;
forAll(cellShapes, cellI)
{
const cellShape& shape = cellShapes[cellI];
const cellModel& model = shape.model();
if (model == tet)
{
cellTypes_[cellI] = foamVtkCore::VTK_TETRA;
forAll(shape, i)
{
vertLabels_[nVertLabels++] = shape[i];
}
vertOffset_[cellI] = nVertLabels;
}
else if (model == pyr)
{
cellTypes_[cellI] = foamVtkCore::VTK_PYRAMID;
forAll(shape, i)
{
vertLabels_[nVertLabels++] = shape[i];
}
vertOffset_[cellI] = nVertLabels;
}
else if (model == hex)
{
cellTypes_[cellI] = foamVtkCore::VTK_HEXAHEDRON;
forAll(shape, i)
{
vertLabels_[nVertLabels++] = shape[i];
}
vertOffset_[cellI] = nVertLabels;
}
else if (model == prism)
{
cellTypes_[cellI] = foamVtkCore::VTK_WEDGE;
// VTK_WEDGE triangles point outwards (swap 1<->2, 4<->5)
vertLabels_[nVertLabels++] = shape[0];
vertLabels_[nVertLabels++] = shape[2];
vertLabels_[nVertLabels++] = shape[1];
vertLabels_[nVertLabels++] = shape[3];
vertLabels_[nVertLabels++] = shape[5];
vertLabels_[nVertLabels++] = shape[4];
vertOffset_[cellI] = nVertLabels;
}
else if (model == tetWedge && decompose_.requested())
{
// Treat as squeezed prism (VTK_WEDGE)
cellTypes_[cellI] = foamVtkCore::VTK_WEDGE;
vertLabels_[nVertLabels++] = shape[0];
vertLabels_[nVertLabels++] = shape[2];
vertLabels_[nVertLabels++] = shape[1];
vertLabels_[nVertLabels++] = shape[3];
vertLabels_[nVertLabels++] = shape[4];
vertLabels_[nVertLabels++] = shape[3];
vertOffset_[cellI] = nVertLabels;
}
else if (model == wedge && decompose_.requested())
{
// Treat as squeezed hex
cellTypes_[cellI] = foamVtkCore::VTK_HEXAHEDRON;
vertLabels_[nVertLabels++] = shape[0];
vertLabels_[nVertLabels++] = shape[1];
vertLabels_[nVertLabels++] = shape[2];
vertLabels_[nVertLabels++] = shape[2];
vertLabels_[nVertLabels++] = shape[3];
vertLabels_[nVertLabels++] = shape[4];
vertLabels_[nVertLabels++] = shape[5];
vertLabels_[nVertLabels++] = shape[6];
vertOffset_[cellI] = nVertLabels;
}
else if (decompose_.requested())
{
// Polyhedral cell - decompose into tet/pyr.
// Ensure we have the correct orientation for the base of the
// primitive cell shape.
// If the cell is face owner, the orientation needs to be flipped
// to avoid defining negative cells.
// VTK doesn't seem to care, but we'll do it anyhow for safety.
// The new vertex from the cell-centre
const label newVertexLabel = mesh_.nPoints() + nAddPoints;
// Mapping from additional point to cell
decompose_.addPointCellLabels_[nAddPoints++] = cellI;
// Whether to insert cell in place of original or not.
bool first = true;
const labelList& cFaces = mesh_.cells()[cellI];
forAll(cFaces, cFaceI)
{
const face& f = mesh_.faces()[cFaces[cFaceI]];
const bool isOwner = (owner[cFaces[cFaceI]] == cellI);
// Count triangles/quads in decomposition
label nTria = 0;
label nQuad = 0;
f.nTrianglesQuads(mesh_.points(), nTria, nQuad);
// Do actual decomposition
faceList faces3(nTria);
faceList faces4(nQuad);
nTria = 0, nQuad = 0;
f.trianglesQuads(mesh_.points(), nTria, nQuad, faces3, faces4);
forAll(faces4, fci)
{
const face& quad = faces4[fci];
label celLoc;
label vrtLoc;
if (first)
{
celLoc = cellI;
vrtLoc = nVertLabels;
nVertLabels += 5;
vertOffset_[celLoc] = nVertLabels;
first = false;
}
else
{
celLoc = mesh_.nCells() + nAddCells;
vrtLoc = offsetAddVerts + nAddVerts;
nAddVerts += 5;
vertOffset_[celLoc] = nAddVerts;
decompose_.superCells_[nAddCells++] = cellI;
}
cellTypes_[celLoc] = foamVtkCore::VTK_PYRAMID;
// See note above about the orientation.
if (isOwner)
{
vertLabels_[vrtLoc++] = quad[3];
vertLabels_[vrtLoc++] = quad[2];
vertLabels_[vrtLoc++] = quad[1];
vertLabels_[vrtLoc++] = quad[0];
}
else
{
vertLabels_[vrtLoc++] = quad[0];
vertLabels_[vrtLoc++] = quad[1];
vertLabels_[vrtLoc++] = quad[2];
vertLabels_[vrtLoc++] = quad[3];
}
vertLabels_[vrtLoc++] = newVertexLabel;
}
forAll(faces3, fci)
{
const face& tria = faces3[fci];
label celLoc;
label vrtLoc;
if (first)
{
celLoc = cellI;
vrtLoc = nVertLabels;
nVertLabels += 4;
vertOffset_[celLoc] = nVertLabels;
first = false;
}
else
{
celLoc = mesh_.nCells() + nAddCells;
vrtLoc = offsetAddVerts + nAddVerts;
nAddVerts += 4;
vertOffset_[celLoc] = nAddVerts;
decompose_.superCells_[nAddCells++] = cellI;
}
cellTypes_[celLoc] = foamVtkCore::VTK_TETRA;
// See note above about the orientation.
if (isOwner)
{
vertLabels_[vrtLoc++] = tria[2];
vertLabels_[vrtLoc++] = tria[1];
vertLabels_[vrtLoc++] = tria[0];
}
else
{
vertLabels_[vrtLoc++] = tria[0];
vertLabels_[vrtLoc++] = tria[1];
vertLabels_[vrtLoc++] = tria[2];
}
vertLabels_[vrtLoc++] = newVertexLabel;
}
}
}
else
{
// Polyhedral cell - not decomposed
hashUniqId.clear(); // unique node ids used (only needed for XML)
// face-stream
// [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
cellTypes_[cellI] = foamVtkCore::VTK_POLYHEDRON;
const labelList& cFaces = mesh_.cells()[cellI];
faceLabels_[nFaceLabels++] = cFaces.size();
forAll(cFaces, cFaceI)
{
const face& f = mesh_.faces()[cFaces[cFaceI]];
const bool isOwner = (owner[cFaces[cFaceI]] == cellI);
forAll(f, fp)
{
hashUniqId.insert(f[fp]);
}
// number of labels for this face
faceLabels_[nFaceLabels++] = f.size();
if (isOwner)
{
forAll(f, fp)
{
faceLabels_[nFaceLabels++] = f[fp];
}
}
else
{
// fairly immaterial if we reverse the list
// or use face::reverseFace()
forAllReverse(f, fp)
{
faceLabels_[nFaceLabels++] = f[fp];
}
}
}
faceOffset_[cellI] = nFaceLabels;
const labelList uniq = hashUniqId.sortedToc();
forAll(uniq, i)
{
vertLabels_[nVertLabels++] = uniq[i];
}
vertOffset_[cellI] = nVertLabels;
}
}
// ===========================================
// PASS 3: Repair offsets for additional cells
// Info<<"vertOffset: " << vertOffset_.size() << " VS. " << (mesh_.nCells()) << endl;
// Info<<"nAddCells: " << nAddCells << " VS. " << (mesh_.nCells()) << endl;
if (nAddCells)
{
const label beg = mesh_.nCells();
const label add = vertOffset_[beg-1];
for (label i = beg; i < vertOffset_.size(); ++i)
{
vertOffset_[i] += add;
}
}
// Some basic programming/sanity checks
if ((nVertLabels + nAddVerts) != vertOffset_[mesh_.nCells()-1 + nAddCells])
{
WarningInFunction
<< "predicted offsets (" << nVertLabels << " + " << nAddVerts << ") != "
<< vertOffset_[mesh_.nCells()-1 + nAddCells]
<< endl;
}
if (offsetAddVerts != vertOffset_[mesh_.nCells()-1])
{
WarningInFunction
<< "predicted regular offset " << offsetAddVerts
<< " != " << vertOffset_[mesh_.nCells()]
<< endl;
}
// nFaceLabels = 0;
// nAddPoints = 0;
// nAddCells = 0;
// Pout<<"vertLabels: " << vertLabels_.size() << " vs. " << (nVertLabels + nAddVerts) << endl;
// Pout<<"faceLabels: " << faceLabels_.size() << " vs. " << nFaceLabels << endl;
#if 0
if (decompose_.requested())
{
Pout<< " Original cells:" << mesh_.nCells()
<< " points:" << mesh_.nPoints()
<< " Additional cells:" << decompose_.superCells_.size()
<< " additional points:" << decompose_.addPointCellLabels_.size()
<< nl << endl;
}
#endif
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::foamVtkCells::decomp::decomp(const bool decomposePoly)
Foam::foamVtkCells::foamVtkCells
(
const contentType output,
const bool decompose
)
:
addPointCellLabels_(),
superCells_(),
pointMap_(),
requested_(decomposePoly)
foamVtuSizing(),
output_(output),
decomposeRequest_(decompose),
cellTypes_(),
vertLabels_(),
vertOffset_(),
faceLabels_(),
faceOffset_(),
maps_()
{}
Foam::foamVtkCells::foamVtkCells
(
const polyMesh& mesh,
const bool decomposePoly,
const bool lazy
const contentType output,
const bool decompose
)
:
mesh_(mesh),
cellTypes_(),
vertLabels_(),
vertOffset_(),
faceLabels_(),
faceOffset_(),
decompose_(decomposePoly),
needsUpdate_(true)
foamVtkCells(output, decompose)
{
if (!lazy)
{
correct();
}
reset(mesh);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::foamVtkCells::decomp::~decomp()
{}
Foam::foamVtkCells::~foamVtkCells()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::foamVtkCells::decomp::clear()
void Foam::foamVtkCells::clear()
{
superCells_.clear();
addPointCellLabels_.clear();
pointMap_.clear();
foamVtuSizing::clear();
cellTypes_.clear();
vertLabels_.clear();
vertOffset_.clear();
faceLabels_.clear();
faceOffset_.clear();
maps_.clear();
}
Foam::label Foam::foamVtkCells::nFieldPoints() const
void Foam::foamVtkCells::reset(const polyMesh& mesh)
{
return mesh_.nPoints() + decompose_.addPointCellLabels_.size();
}
foamVtuSizing::reset(mesh, decomposeRequest_);
cellTypes_.setSize(nFieldCells());
vertLabels_.setSize(slotSize(output_, slotType::CELLS));
vertOffset_.setSize(slotSize(output_, slotType::CELLS_OFFSETS));
faceLabels_.setSize(slotSize(output_, slotType::FACES));
faceOffset_.setSize(slotSize(output_, slotType::FACES_OFFSETS));
Foam::label Foam::foamVtkCells::legacyCellPayLoad() const
{
label payLoad = cellTypes_.size();
if (faceOffset_.size())
switch (output_)
{
// also has polys with face streams
label begVert = 0;
label begFace = 0;
forAll(faceOffset_, i)
{
label endFace = faceOffset_[i];
label endVert = vertOffset_[i];
if (endFace > 0)
{
// poly with face stream
payLoad += endFace - begFace;
begFace = endFace;
}
else
{
// primitive without face stream
payLoad += endVert - begVert;
}
begVert = endVert;
}
case contentType::LEGACY:
populateLegacy
(
mesh,
cellTypes_,
vertLabels_,
maps_
);
break;
case contentType::XML:
populateXml
(
mesh,
cellTypes_,
vertLabels_,
vertOffset_,
faceLabels_,
faceOffset_,
maps_
);
break;
case contentType::INTERNAL:
populateInternal
(
mesh,
cellTypes_,
vertLabels_,
vertOffset_,
faceLabels_,
faceOffset_,
maps_
);
break;
}
else if (vertOffset_.size())
{
// primitives only, trivial
payLoad += vertOffset_[vertOffset_.size()-1];
}
return payLoad;
}
bool Foam::foamVtkCells::needsUpdate() const
void Foam::foamVtkCells::reset
(
const polyMesh& mesh,
const enum contentType output,
const bool decompose
)
{
return needsUpdate_;
output_ = output;
decomposeRequest_ = decompose;
reset(mesh);
}
bool Foam::foamVtkCells::expire()
void Foam::foamVtkCells::renumberCells(const UList<label>& mapping)
{
// Clear any stored topologies
// Clear derived data
// clearGeom();
// already marked as expired
if (needsUpdate_)
{
return false;
}
needsUpdate_ = true;
return true;
maps_.renumberCells(mapping);
}
bool Foam::foamVtkCells::update()
void Foam::foamVtkCells::renumberPoints(const UList<label>& mapping)
{
if (!needsUpdate_)
{
return false;
}
correct();
needsUpdate_ = false;
return true;
maps_.renumberPoints(mapping);
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2011-2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,53 +25,32 @@ Class
Foam::foamVtkCells
Description
The deep-copy description of an OpenFOAM volume mesh in data structures
corresponding to an VTK UnstructuredGrid, including the possiblity of
A deep-copy description of an OpenFOAM volume mesh in data structures
suitable for VTK UnstructuredGrid, including the possibility of
decomposing polyhedral cells into primitive cell types.
Knowledge of the vtkUnstructuredGrid and the corresponding \c .vtu
xml file-format aids in understanding this class.
For flexibilty, support for the legacy vtk file-format is also provided.
The class can be used for the VTK xml format, legacy format, as well as a
VTK internal representation. The internal representation is somewhat
related to the xml format, but not entirely.
Primitive cell types are straighforward, polyhedral cells are represented
by a face stream:
\verbatim
[nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
\endverbatim
For the legacy format, the face stream is simply passed as vertex labels
(connectivity).
For the xml format, the face stream is saved separately:
\verbatim
"connectivity"
== the unique vertex labels used by the cell (optionally sorted).
"offsets":
== offset + sizeof(connectivity)
"faces":
[nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
"faceoffsets":
== faceoffsets + sizeof(faces)
\endverbatim
The storage of "connectivity" and "offsets" strongly resembles a
CompactListList, but the "offsets" point to the end of the respective
sub-lists.
SeeAlso
Foam::foamVtuSizing
SourceFiles
foamVtkCells.C
foamVtkCellsI.H
\*---------------------------------------------------------------------------*/
#ifndef foamVtkCells_H
#define foamVtkCells_H
#include "foamVtkMeshMaps.H"
#include "foamVtuSizing.H"
#include "foamVtkCore.H"
#include "DynamicList.H"
#include "SubList.H"
#include "labelList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -83,119 +62,48 @@ namespace Foam
class polyMesh;
/*---------------------------------------------------------------------------*\
Class foamVtkCells Declaration
Class foamVtkCells Declaration
\*---------------------------------------------------------------------------*/
class foamVtkCells
:
public fileFormats::foamVtkCore
public fileFormats::foamVtkCore,
public foamVtuSizing
{
public:
//- Bookkeeping for polyhedral cell decomposition
class decomp
{
private:
friend foamVtkCells;
// Private data
//- Cell-centre labels for additional points of decomposed cells
DynamicList<label> addPointCellLabels_;
//- Label of original cell for decomposed cells
DynamicList<label> superCells_;
//- Point labels for subsetted meshes
DynamicList<label> pointMap_;
//- Track if decomposition was requested
const bool requested_;
// Private Member Functions
//- Disallow default bitwise copy construct
decomp(const decomp&) = delete;
//- Disallow default bitwise assignment
void operator=(const decomp&) = delete;
public:
// Constructors
//- Construct null
decomp(const bool decomposePoly = false);
//- Destructor
~decomp();
// Member Functions
// Access
//- Polyhedral decomposition requested
inline bool requested() const;
//- Polyhedral decomposition used
inline bool used() const;
//- Label of original cell for decomposed cells
inline const labelList& superCells() const;
//- Cell-centre labels for additional points of decomposed cells
inline const labelList& addPointCellLabels() const;
//- Point labels for subsetted meshes
inline const labelList& pointMap() const;
// Edit
//- Clear
void clear();
};
private:
// Private data
//- Reference to underlying mesh or mesh sub-set
const polyMesh& mesh_;
// Requested output types
//- Output content type
contentType output_;
//- Bookkeeping for polyhedral cell decomposition
bool decomposeRequest_;
// Storage of output
//- Cell types (including added cells) in vtk numbering
// Range is 1-255
List<uint8_t> cellTypes_;
//- Vertices per cell (including added cells) in vtk ordering
DynamicList<label> vertLabels_;
List<label> vertLabels_;
//- Vertices per cell (including added cells) in vtk ordering
DynamicList<label> vertOffset_;
//- Connectivity (vertices) offset for the end of each cell
List<label> vertOffset_;
//- Face lists per polyhedral cell
DynamicList<label> faceLabels_;
List<label> faceLabels_;
//- Face label offsets
DynamicList<label> faceOffset_;
List<label> faceOffset_;
//- Bookkeeping for polyhedral cell decomposition
decomp decompose_;
//- Needs update
bool needsUpdate_;
foamVtkMeshMaps maps_;
// Private Member Functions
//- Create the geometry
void correct();
//- Disallow default bitwise copy construct
foamVtkCells(const foamVtkCells&) = delete;
@ -208,13 +116,20 @@ public:
// Constructors
//- Construct from components.
// Optionally with polyhedral decomposition and/or lazy evaluation.
// A 'lazy' evaluation avoids fully creation within the constructor.
// Optionally with polyhedral decomposition.
foamVtkCells
(
const polyMesh&,
const bool decomposePoly = false,
const bool lazy = false
const enum contentType output = contentType::XML,
const bool decompose = false
);
//- Construct from components and create the output information
// immediately
foamVtkCells
(
const polyMesh& mesh,
const enum contentType output = contentType::XML,
const bool decompose = false
);
@ -224,113 +139,68 @@ public:
// Member Functions
// Access
// Access
//- Query the poly decompose flag.
inline bool decomposeRequested() const;
//- The output content type
inline enum contentType content() const;
//- Values for "connectivity" (XML) or basis for "CELLS" (legacy)
// In the legacy format, the size (offset) must be prefixed.
inline const labelList& vertLabels() const;
//- Query the polyhedral decompose requested flag.
inline bool decomposeRequested() const;
//- Values for "offsets" (XML)
// or sizes to prefix for for "CELLS" (legacy)
inline const labelList& vertOffsets() const;
//- True if no cellTypes are populated.
inline bool empty() const;
//- Values for "types" (XML) and "CELL_TYPES" (legacy)
inline const List<uint8_t>& cellTypes() const;
//- Values for "faces" (XML)
inline const labelList& faceLabels() const;
//- Values for "faceoffsets" (XML)
inline const labelList& faceOffsets() const;
//- Additional point addressing (from added point to original cell)
inline const labelList& addPointCellLabels() const;
//- Additional cells mapping (from added cell to original cell)
inline const labelList& superCells() const;
//- The size of populated cellTypes.
inline label size() const;
//- Number of field cells
inline label nFieldCells() const;
// Edit
//- Number of field points
label nFieldPoints() const;
//- Reset all sizes to zero.
void clear();
//- The field size for legacy "CELLS".
// In the legacy format, the size (offset) must be prefixed.
label legacyCellPayLoad() const;
//- Create the geometry using the previously requested output and
// decomposition types.
void reset(const polyMesh& mesh);
//- Respecify requested output and decomposition type prior to
// creating the geometry
void reset
(
const polyMesh& mesh,
const enum contentType output,
const bool decompose
);
//- Renumber cell ids to account for subset meshes
void renumberCells(const UList<label>& mapping);
//- Renumber point ids to account for subset meshes
void renumberPoints(const UList<label>& mapping);
//- Does the mapping need an update?
bool needsUpdate() const;
// Storage Access
//- Mark as needing an update.
// May also free up unneeded data.
// Return false if it was already marked as expired.
bool expire();
//- Values for "types" (XML) and "CELL_TYPES" (legacy)
inline const List<uint8_t>& cellTypes() const;
//- Update the description (and decomposition) as required.
// Do nothing (and return false) if no update was required
bool update();
//- Values for "connectivity" (XML) or "CELLS" (legacy)
inline const labelList& vertLabels() const;
//- Values for "offsets" (XML only)
inline const labelList& vertOffsets() const;
//- The const_iterator for foamVtkCells
class const_iterator
{
friend class foamVtkCells;
//- Values for "faces" (XML only)
inline const labelList& faceLabels() const;
protected:
//- Values for "faceoffset" (XML only)
inline const labelList& faceOffsets() const;
// Protected Data
//- Additional point addressing (from added point to original cell)
inline const labelList& addPointCellLabels() const;
//- Reference to parent list
const foamVtkCells& parent_;
//- Element index
label index_;
//- Begin of connectivity sub-list
mutable label begVert_;
//- Begin of faces sub-list
mutable label begFace_;
//- On-demand legacy pointer
mutable autoPtr<SubList<label>> legacy_;
// Constructors
//- Construct begin/end iterator
inline const_iterator
(
const foamVtkCells&,
bool isEnd = false
);
public:
// Member operators
//- On-demand legacy cell labels (primitive or faces)
inline const labelUList& legacyCell() const;
//- Compare position
inline bool operator!=(const const_iterator&) const;
//- Pre-increment iterator
inline const_iterator& operator++();
};
//- const_iterator set to the beginning
inline const_iterator begin() const;
//- const_iterator set to beyond the end
inline const_iterator end() const;
//- Original cell ids for all cells (regular and decomposed).
inline const labelList& cellMap() const;
};

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,44 +25,37 @@ License
#include "foamVtkCells.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::foamVtkCells::decomp::requested() const
inline enum Foam::foamVtkCells::contentType Foam::foamVtkCells::content() const
{
return requested_;
}
inline bool Foam::foamVtkCells::decomp::used() const
{
return !superCells_.empty();
}
inline const Foam::labelList&
Foam::foamVtkCells::decomp::superCells() const
{
return superCells_;
}
inline const Foam::labelList&
Foam::foamVtkCells::decomp::addPointCellLabels() const
{
return addPointCellLabels_;
}
inline const Foam::labelList&
Foam::foamVtkCells::decomp::pointMap() const
{
return pointMap_;
return output_;
}
inline bool Foam::foamVtkCells::decomposeRequested() const
{
return decompose_.requested();
return decomposeRequest_;
}
inline bool Foam::foamVtkCells::empty() const
{
return cellTypes_.empty();
}
inline Foam::label Foam::foamVtkCells::size() const
{
return cellTypes_.size();
}
inline const Foam::List<uint8_t>&
Foam::foamVtkCells::cellTypes() const
{
return cellTypes_;
}
@ -80,13 +73,6 @@ Foam::foamVtkCells::vertOffsets() const
}
inline const Foam::List<uint8_t>&
Foam::foamVtkCells::cellTypes() const
{
return cellTypes_;
}
inline const Foam::labelList&
Foam::foamVtkCells::faceLabels() const
{
@ -104,135 +90,14 @@ Foam::foamVtkCells::faceOffsets() const
inline const Foam::labelList&
Foam::foamVtkCells::addPointCellLabels() const
{
return decompose_.addPointCellLabels();
return maps_.additionalIds();
}
inline const Foam::labelList&
Foam::foamVtkCells::superCells() const
Foam::foamVtkCells::cellMap() const
{
return decompose_.superCells();
}
inline Foam::label
Foam::foamVtkCells::nFieldCells() const
{
return cellTypes_.size();
}
inline Foam::foamVtkCells::const_iterator
Foam::foamVtkCells::begin() const
{
return const_iterator(*this);
}
inline Foam::foamVtkCells::const_iterator
Foam::foamVtkCells::end() const
{
return const_iterator(*this, true);
}
// * * * * * * * * * * * * * * * * Iterators * * * * * * * * * * * * * * * * //
inline Foam::foamVtkCells::const_iterator::const_iterator
(
const foamVtkCells& cells,
bool isEnd
)
:
parent_(cells),
index_(0),
begVert_(0),
begFace_(0),
legacy_()
{
if (isEnd)
{
index_ = parent_.vertOffsets().size();
}
}
inline
Foam::foamVtkCells::const_iterator&
Foam::foamVtkCells::const_iterator::operator++()
{
++index_;
legacy_.clear();
return *this;
}
inline
const Foam::UList<Foam::label>&
Foam::foamVtkCells::const_iterator::legacyCell() const
{
if
(
legacy_.valid()
|| index_ >= parent_.vertOffsets().size()
)
{
return legacy_();
}
const label endVert = parent_.vertOffsets()[index_];
const label endFace =
(
parent_.faceOffsets().size()
? parent_.faceOffsets()[index_]
: -1
);
if (endFace > 0)
{
// poly with face stream
legacy_.reset
(
new SubList<label>
(
parent_.faceLabels(),
endFace - begFace_,
begFace_
)
);
begFace_ = endFace;
}
else
{
// primitive without face stream
legacy_.reset
(
new SubList<label>
(
parent_.vertLabels(),
endVert - begVert_,
begVert_
)
);
}
begVert_ = endVert;
return legacy_();
}
inline bool
Foam::foamVtkCells::const_iterator::operator!=
(
const const_iterator& rhs
) const
{
return (index_ != rhs.index_);
return maps_.cellMap();
}

View File

@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ 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 "foamVtkMeshMaps.H"
#include "ListOps.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::foamVtkMeshMaps::renumberCells(const UList<label>& mapping)
{
inplaceRenumber(mapping, cellMap_);
inplaceRenumber(mapping, additionalIds_);
}
void Foam::foamVtkMeshMaps::renumberPoints(const UList<label>& mapping)
{
inplaceRenumber(mapping, pointMap_);
}
// ************************************************************************* //

View File

@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ 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/>.
Class
Foam::foamVtkMeshMaps
Description
Bookkeeping for mesh subsetting and/or polyhedral cell decomposition.
The cellMap is a local-to-global lookup for normal and decomposed cells.
The pointMap is an optional local-to-global lookup for point ids.
The additional ids is typically used to store the cell-centre labels
for additional points of decomposed cells
SourceFiles
foamVtkMeshMapsI.H
\*---------------------------------------------------------------------------*/
#ifndef foamVtkMeshMaps_H
#define foamVtkMeshMaps_H
#include "DynamicList.H"
#include "labelList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class foamVtkMeshMaps Declaration
\*---------------------------------------------------------------------------*/
class foamVtkMeshMaps
{
// Private data
//- Original cell ids for all cells (regular and decomposed)
DynamicList<label> cellMap_;
//- Point labels for subsetted meshes
DynamicList<label> pointMap_;
//- Any additional (user) labels.
// Eg, cell-centre labels for additional points of decomposed cells
DynamicList<label> additionalIds_;
public:
// Constructors
//- Construct null
inline foamVtkMeshMaps(const label size = 0);
//- Destructor
inline ~foamVtkMeshMaps();
// Member Functions
// Access
//- Original cell ids for all cells (regular and decomposed).
// A regular mesh comprising only primitive cell types, this will just
// be an identity list. However, for subsetted meshes and decomposed
// cells this becomes a useful means of mapping from the original mesh.
inline const labelList& cellMap() const;
//- Point labels for subsetted meshes
inline const labelList& pointMap() const;
//- Any additional (user) labels.
// Eg, cell-centre labels for additional points of decomposed cells
inline const labelList& additionalIds() const;
// Edit
//- Clear
inline void clear();
//- Renumber cell ids to account for subset meshes
void renumberCells(const UList<label>& mapping);
//- Renumber point ids to account for subset meshes
void renumberPoints(const UList<label>& mapping);
//- Original cell ids for all cells (regular and decomposed).
// A regular mesh comprising only primitive cell types, this will just
// be an identity list. However, for subsetted meshes and decomposed
// cells this becomes a useful means of mapping from the original mesh.
inline DynamicList<label>& cellMap();
//- Point labels for subsetted meshes
inline DynamicList<label>& pointMap();
//- Any additional (user) labels.
// Eg, cell-centre labels for additional points of decomposed cells
inline DynamicList<label>& additionalIds();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "foamVtkMeshMapsI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ 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 "foamVtkMeshMaps.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::foamVtkMeshMaps::foamVtkMeshMaps(const label size)
:
cellMap_(size),
pointMap_(size),
additionalIds_(size)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
inline Foam::foamVtkMeshMaps::~foamVtkMeshMaps()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline void Foam::foamVtkMeshMaps::clear()
{
cellMap_.clear();
pointMap_.clear();
additionalIds_.clear();
}
inline const Foam::labelList&
Foam::foamVtkMeshMaps::cellMap() const
{
return cellMap_;
}
inline Foam::DynamicList<Foam::label>&
Foam::foamVtkMeshMaps::cellMap()
{
return cellMap_;
}
inline const Foam::labelList&
Foam::foamVtkMeshMaps::pointMap() const
{
return pointMap_;
}
inline Foam::DynamicList<Foam::label>&
Foam::foamVtkMeshMaps::pointMap()
{
return pointMap_;
}
inline const Foam::labelList&
Foam::foamVtkMeshMaps::additionalIds() const
{
return additionalIds_;
}
inline Foam::DynamicList<Foam::label>&
Foam::foamVtkMeshMaps::additionalIds()
{
return additionalIds_;
}
// ************************************************************************* //

View File

@ -0,0 +1,578 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\/ 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 "foamVtuSizing.H"
#include "foamVtkCore.H"
#include "polyMesh.H"
#include "cellShape.H"
#include "cellModeller.H"
// only used in this file
#include "foamVtuSizingTemplates.C"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::foamVtuSizing::presizeMaps(foamVtkMeshMaps& maps) const
{
maps.cellMap().setSize(this->nFieldCells());
maps.additionalIds().setSize(this->nAddPoints());
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::foamVtuSizing::foamVtuSizing
(
const polyMesh& mesh,
const bool decompose
)
{
clear();
reset(mesh, decompose);
}
Foam::foamVtuSizing::foamVtuSizing()
{
clear();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::foamVtuSizing::~foamVtuSizing()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::foamVtuSizing::reset
(
const polyMesh& mesh,
const bool decompose
)
{
const cellModel& tet = *(cellModeller::lookup("tet"));
const cellModel& pyr = *(cellModeller::lookup("pyr"));
const cellModel& prism = *(cellModeller::lookup("prism"));
const cellModel& wedge = *(cellModeller::lookup("wedge"));
const cellModel& tetWedge = *(cellModeller::lookup("tetWedge"));
const cellModel& hex = *(cellModeller::lookup("hex"));
const cellShapeList& shapes = mesh.cellShapes();
// Unique vertex labels per polyhedral
HashSet<label> hashUniqId(2*256);
decompose_ = decompose;
nCells_ = mesh.nCells();
nPoints_ = mesh.nPoints();
nAddCells_ = 0;
nAddVerts_ = 0;
nCellsPoly_ = nCells_;
nVertLabels_ = 0;
nFaceLabels_ = 0;
nVertPoly_ = 0;
forAll(shapes, celli)
{
const cellShape& shape = shapes[celli];
const cellModel& model = shape.model();
if
(
model == tet
|| model == pyr
|| model == prism
|| model == hex
)
{
// Normal primitive - not a poly
--nCellsPoly_;
nVertLabels_ += shape.size();
}
else if (model == tetWedge && decompose)
{
nVertLabels_ += 6; // Treat as squeezed prism (VTK_WEDGE)
}
else if (model == wedge && decompose)
{
nVertLabels_ += 8; // Treat as squeezed hex
}
else if (decompose)
{
// Polyhedral: Decompose into tets + pyramids.
++nAddPoints_;
// Count vertices into first decomposed cell
bool first = true;
const cell& cFaces = mesh.cells()[celli];
forAll(cFaces, cFaceI)
{
const face& f = mesh.faces()[cFaces[cFaceI]];
// Face decomposed into triangles and quads
// Tri -> Tet, Quad -> Pyr
label nTria = 0, nQuad = 0;
f.nTrianglesQuads(mesh.points(), nTria, nQuad);
nAddCells_ += nTria + nQuad;
nAddVerts_ += (nTria * 4) + (nQuad * 5);
if (first)
{
first = false;
--nAddCells_;
const label nvrt = (nQuad ? 5 : 4);
nAddVerts_ -= nvrt;
nVertLabels_ += nvrt;
}
}
}
else
{
// Polyhedral: Not decomposed
const labelList& cFaces = mesh.cells()[celli];
// Unique node ids used (only needed for XML)
hashUniqId.clear();
// Face stream sizing:
// number of faces, size of each face, vertices per face
// [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
forAll(cFaces, cFaceI)
{
const face& f = mesh.faces()[cFaces[cFaceI]];
nFaceLabels_ += f.size();
hashUniqId.insert(f);
}
// Legacy format only uses the face-stream.
// - track what *NOT* to use for legacy
nVertLabels_ += hashUniqId.size();
nVertPoly_ += hashUniqId.size();
nFaceLabels_ += 1 + cFaces.size();
}
}
// decompose requested and needed
decompose_ = (decompose && nCellsPoly_);
}
Foam::label Foam::foamVtuSizing::slotSize
(
const enum contentType output,
const enum slotType slot
) const
{
switch (output)
{
case contentType::LEGACY:
{
switch (slot)
{
case slotType::CELLS:
// legacy uses connectivity for primitives, but directly
// stores face streams into connectivity as well.
// size-prefix per cell
return
(
nVertLabels() + nAddVerts() - nVertPoly() // primitives
+ nFaceLabels() // face-stream (poly)
+ nFieldCells() // nFieldCells (size prefix)
);
break;
default:
break;
}
break;
}
case contentType::XML:
{
switch (slot)
{
case slotType::CELLS:
return (nVertLabels() + nAddVerts());
break;
case slotType::CELLS_OFFSETS:
return nFieldCells();
break;
case slotType::FACES:
return nFaceLabels();
break;
case slotType::FACES_OFFSETS:
return nFaceLabels() ? nFieldCells() : 0;
break;
}
break;
}
case contentType::INTERNAL:
{
switch (slot)
{
case slotType::CELLS:
// size-prefix per cell
return (nVertLabels() + nAddVerts() + nFieldCells());
break;
case slotType::CELLS_OFFSETS:
return nFieldCells();
break;
case slotType::FACES:
return nFaceLabels();
break;
case slotType::FACES_OFFSETS:
return nFaceLabels() ? nFieldCells() : 0;
break;
}
break;
}
}
return 0;
}
void Foam::foamVtuSizing::populateLegacy
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<label>& vertLabels,
foamVtkMeshMaps& maps
) const
{
// Leave as zero-sized so that populateArrays doesn't fill it.
List<label> unused;
presizeMaps(maps);
populateArrays
(
mesh,
*this,
cellTypes,
vertLabels,
unused, // offsets
unused, // faces
unused, // facesOffsets
contentType::LEGACY,
maps.cellMap(),
maps.additionalIds()
);
}
void Foam::foamVtuSizing::populateXml
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<label>& connectivity,
UList<label>& offsets,
UList<label>& faces,
UList<label>& facesOffsets,
foamVtkMeshMaps& maps
) const
{
presizeMaps(maps);
populateArrays
(
mesh,
*this,
cellTypes,
connectivity,
offsets,
faces,
facesOffsets,
contentType::XML,
maps.cellMap(),
maps.additionalIds()
);
}
void Foam::foamVtuSizing::populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<int>& connectivity,
UList<int>& offsets,
UList<int>& faces,
UList<int>& facesOffsets,
foamVtkMeshMaps& maps
) const
{
presizeMaps(maps);
populateArrays
(
mesh,
*this,
cellTypes,
connectivity,
offsets,
faces,
facesOffsets,
contentType::INTERNAL,
maps.cellMap(),
maps.additionalIds()
);
}
void Foam::foamVtuSizing::populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long>& connectivity,
UList<long>& offsets,
UList<long>& faces,
UList<long>& facesOffsets,
foamVtkMeshMaps& maps
) const
{
presizeMaps(maps);
populateArrays
(
mesh,
*this,
cellTypes,
connectivity,
offsets,
faces,
facesOffsets,
contentType::INTERNAL,
maps.cellMap(),
maps.additionalIds()
);
}
void Foam::foamVtuSizing::populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long long>& connectivity,
UList<long long>& offsets,
UList<long long>& faces,
UList<long long>& facesOffsets,
foamVtkMeshMaps& maps
) const
{
presizeMaps(maps);
populateArrays
(
mesh,
*this,
cellTypes,
connectivity,
offsets,
faces,
facesOffsets,
contentType::INTERNAL,
maps.cellMap(),
maps.additionalIds()
);
}
void Foam::foamVtuSizing::populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<int>& connectivity,
UList<int>& offsets,
UList<int>& faces,
UList<int>& facesOffsets,
UList<label>& cellMap,
UList<label>& addPointsIds
) const
{
populateArrays
(
mesh,
*this,
cellTypes,
connectivity,
offsets,
faces,
facesOffsets,
contentType::INTERNAL,
cellMap,
addPointsIds
);
}
void Foam::foamVtuSizing::populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long>& connectivity,
UList<long>& offsets,
UList<long>& faces,
UList<long>& facesOffsets,
UList<label>& cellMap,
UList<label>& addPointsIds
) const
{
populateArrays
(
mesh,
*this,
cellTypes,
connectivity,
offsets,
faces,
facesOffsets,
contentType::INTERNAL,
cellMap,
addPointsIds
);
}
void Foam::foamVtuSizing::populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long long>& connectivity,
UList<long long>& offsets,
UList<long long>& faces,
UList<long long>& facesOffsets,
UList<label>& cellMap,
UList<label>& addPointsIds
) const
{
populateArrays
(
mesh,
*this,
cellTypes,
connectivity,
offsets,
faces,
facesOffsets,
contentType::INTERNAL,
cellMap,
addPointsIds
);
}
void Foam::foamVtuSizing::clear()
{
decompose_ = false;
nCells_ = 0;
nPoints_ = 0;
nVertLabels_ = 0;
nFaceLabels_ = 0;
nCellsPoly_ = 0;
nVertPoly_ = 0;
nAddCells_ = 0;
nAddPoints_ = 0;
nAddVerts_ = 0;
}
void Foam::foamVtuSizing::info(Ostream& os) const
{
os << "nFieldCells:" << nFieldCells();
if (nAddCells_)
{
os << " (" << nCells_
<< "+" << nAddCells_ << ")";
}
else
{
os << " (poly:" << nCellsPoly_ << ")";
}
os << " nFieldPoints:" << nFieldPoints();
if (nAddPoints_)
{
os << " (" << nPoints_ << "+" << nAddPoints_ << ")";
}
os << " nVertLabels:" << (nVertLabels_ + nAddVerts_);
if (nAddVerts_)
{
os << " (" << nVertLabels_ << "+" << nAddVerts_ << ")";
}
else if (nVertPoly_)
{
os << " (poly:" << nVertPoly_ << ")";
}
os << " nFaceLabels:" << nFaceLabels_;
os << " legacy-count:" << sizeLegacy();
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
bool Foam::foamVtuSizing::operator==(const foamVtuSizing& rhs) const
{
return
(
decompose() == rhs.decompose()
&& nCells() == rhs.nCells()
&& nPoints() == rhs.nPoints()
&& nVertLabels() == rhs.nVertLabels()
&& nFaceLabels() == rhs.nFaceLabels()
&& nCellsPoly() == rhs.nCellsPoly()
&& nVertPoly() == rhs.nVertPoly()
&& nAddCells() == rhs.nAddCells()
&& nAddPoints() == rhs.nAddPoints()
&& nAddVerts() == rhs.nAddVerts()
);
}
bool Foam::foamVtuSizing::operator!=(const foamVtuSizing& rhs) const
{
return !operator==(rhs);
}
// ************************************************************************* //

View File

@ -0,0 +1,408 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\/ 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/>.
Class
Foam::foamVtuSizing
Description
Sizing descriptions and routines for transcribing an OpenFOAM volume mesh
into a VTK unstructured grid, with possible decomposition of polyhedral
cells into primitive cell types.
This class is intended to populate externally allocated arrays with content
that is compatible with what VTK expects. This approach allows an improved
separation of the OpenFOAM mesh description and the storage, and allows
support of alternative storage containers (eg, std::vector, vtkDataArray).
The ideal goal would be a zero-copy mechanism, but this does not work for
several reasons:
\par
- OpenFOAM and VTK have different point ordering for prism
- polyhedral decomposition
- face-stream are required for VTK
- VTK internal storage includes list size as part of the data
- VTK includes storage may be a different base size (eg, long long)
compared to the OpenFOAM label.
\par Data Entries (slots)
These are the storage entries normally associate with each output-type:
\table
legacy output
\c types | vtk cell type (1-255)
\c cells | nLabels and unique vertex labels used by the cell, or
| [nLabels nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
\endtable
\table
xml output
\c types | vtk cell type (1-255)
\c connectivity | unique vertex labels used by the cell
\c offsets | end offset for each of \c connectivity
\c faces | face stream for polyhedral cells
| [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
\c faceoffsets | end offset for each of \c faces, with -1 for primitive cells
\endtable
\table
internal storage
\c types | vtk cell type (1-255)
\c connectivity | nLabels and unique vertex labels used by the cell
\c location | begin location for each of \c connectivity
\c faces | face stream for polyhedral cells
| [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
\c facelocation | begin location for each of \c faces, with -1 for primitive cells
\endtable
The VTK storage concept for "connectivity" and "faces" somewhat resemble
a CompactListList.
SourceFiles
foamVtuSizing.C
foamVtuSizingI.H
\*---------------------------------------------------------------------------*/
#ifndef foamVtuSizing_H
#define foamVtuSizing_H
#include "label.H"
#include "labelList.H"
#include "foamVtkMeshMaps.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
class polyMesh;
/*---------------------------------------------------------------------------*\
Class foamVtuSizing Declaration
\*---------------------------------------------------------------------------*/
class foamVtuSizing
{
public:
// Public data
//- Types of content that the storage may represent
enum contentType
{
LEGACY, //!< Legacy VTK content
XML, //!< XML (VTU) content
INTERNAL //!< Internal vtkUnstructuredGrid content
};
//- The storage 'slots' required
enum slotType
{
CELLS, //!< Cell connectivity (ALL)
CELLS_OFFSETS, //!< Begin (XML) or end (INTERNAL) offsets into cells
FACES, //!< Face-stream (XML, INTERNAL)
FACES_OFFSETS //!< Begin (XML) or end (INTERNAL) offsets into faces
};
private:
// Private Member Data
//- Polyhedral decomposition requested
bool decompose_;
//- Number of cells in the mesh
label nCells_;
//- Number of points in the mesh
label nPoints_;
//- Number of vertex labels to represent the mesh
label nVertLabels_;
// Polyhedrals
//- Number of polyhedral face labels for the mesh
label nFaceLabels_;
//- Number of polyhedral cells (informational)
label nCellsPoly_;
//- Number of vertex labels used by polyhedrals
label nVertPoly_;
// Decomposed polyhedrals
//- Number of additional (decomposed) cells for the mesh
label nAddCells_;
//- Number of additional (decomposed) points for the mesh
label nAddPoints_;
//- Number of additional (decomposed) vertices for the mesh
label nAddVerts_;
// Private Member Functions
//- set-size for cellMap and additionalIds
void presizeMaps(foamVtkMeshMaps& maps) const;
//- Populate lists for internal VTK representation
template<class LabelType, class LabelType2>
static void populateArrays
(
const polyMesh& mesh,
const foamVtuSizing& sizing,
UList<uint8_t>& cellTypes,
UList<LabelType>& vertLabels,
UList<LabelType>& vertOffset,
UList<LabelType>& faceLabels,
UList<LabelType>& faceOffset,
const enum contentType output,
UList<LabelType2>& cellMap,
UList<LabelType2>& addPointsIds
);
// Allow default bitwise copy/assignment
public:
// Constructors
//- Construct null.
foamVtuSizing();
//- Construct sizes by analyzing the mesh,
// optionally with polyhedral decomposition.
foamVtuSizing(const polyMesh& mesh, const bool decompose=false);
//- Destructor
~foamVtuSizing();
// Member Functions
// Edit
//- Construct sizes by analyzing the mesh,
// optionally with polyhedral decomposition.
void reset(const polyMesh& mesh, const bool decompose=false);
//- Reset all sizes to zero.
void clear();
// Access
//- Query the decompose flag
inline bool decompose() const;
//- Number of cells for the mesh
inline label nCells() const;
//- Number of points for the mesh
inline label nPoints() const;
//- Number of vertex labels for the mesh
inline label nVertLabels() const;
//- Number of polyhedral face labels for the mesh
inline label nFaceLabels() const;
//- Number of polyhedral cells for the mesh
inline label nCellsPoly() const;
//- Number of vertex labels for polyhedral cells of the mesh
inline label nVertPoly() const;
//- Number of additional (decomposed) cells for the mesh
inline label nAddCells() const;
//- Number of additional (decomposed) points for the mesh
inline label nAddPoints() const;
//- Number of additional (decomposed) vertices for the mesh
inline label nAddVerts() const;
//- Number of field cells = nCells + nAddCells
inline label nFieldCells() const;
//- Number of field points = nPoints + nAddPoints
inline label nFieldPoints() const;
// Derived sizes
//- Return the required size for the storage slot
label slotSize
(
const enum contentType output,
const enum slotType slot
) const;
//- The calculated size for legacy storage
inline label sizeLegacy() const;
//- The calculated size for legacy storage of the specified slot
inline label sizeLegacy(const enum slotType slot) const;
//- The calculated size for xml storage of the specified slot
inline label sizeXml(const enum slotType slot) const;
//- The calculated size for vtk-internal storage of the specified slot
inline label sizeInternal(const enum slotType slot) const;
// Utilty routines
//- Populate lists for Legacy output
void populateLegacy
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<label>& connectivity,
foamVtkMeshMaps& maps
) const;
//- Populate lists for XML output
void populateXml
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<label>& connectivity,
UList<label>& offsets,
UList<label>& faces,
UList<label>& facesOffsets,
foamVtkMeshMaps& maps
) const;
//- Populate lists for Internal VTK format
void populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<int>& connectivity,
UList<int>& offsets,
UList<int>& faces,
UList<int>& facesOffsets,
foamVtkMeshMaps& maps
) const;
//- Populate lists for Internal VTK format
void populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long>& connectivity,
UList<long>& offsets,
UList<long>& faces,
UList<long>& facesOffsets,
foamVtkMeshMaps& maps
) const;
//- Populate lists for Internal VTK format
void populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long long>& connectivity,
UList<long long>& offsets,
UList<long long>& faces,
UList<long long>& facesOffsets,
foamVtkMeshMaps& maps
) const;
//- Populate lists for Internal VTK format
void populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<int>& connectivity,
UList<int>& offsets,
UList<int>& faces,
UList<int>& facesOffsets,
UList<label>& cellMap,
UList<label>& addPointsIds
) const;
//- Populate lists for Internal VTK format
void populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long>& connectivity,
UList<long>& offsets,
UList<long>& faces,
UList<long>& facesOffsets,
UList<label>& cellMap,
UList<label>& addPointsIds
) const;
//- Populate lists for Internal VTK format
void populateInternal
(
const polyMesh& mesh,
UList<uint8_t>& cellTypes,
UList<long long>& connectivity,
UList<long long>& offsets,
UList<long long>& faces,
UList<long long>& facesOffsets,
UList<label>& cellMap,
UList<label>& addPointsIds
) const;
// Write
//- Report some information
void info(Ostream& os) const;
// Member Operators
//- Test equality
bool operator==(const foamVtuSizing& rhs) const;
//- Test inequality
bool operator!=(const foamVtuSizing& rhs) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "foamVtuSizingI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,135 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ 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 "foamVtuSizing.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::foamVtuSizing::decompose() const
{
return decompose_;
}
inline Foam::label Foam::foamVtuSizing::nCells() const
{
return nCells_;
}
inline Foam::label Foam::foamVtuSizing::nPoints() const
{
return nPoints_;
}
inline Foam::label Foam::foamVtuSizing::nVertLabels() const
{
return nVertLabels_;
}
inline Foam::label Foam::foamVtuSizing::nFaceLabels() const
{
return nFaceLabels_;
}
inline Foam::label Foam::foamVtuSizing::nCellsPoly() const
{
return nCellsPoly_;
}
inline Foam::label Foam::foamVtuSizing::nVertPoly() const
{
return nVertPoly_;
}
inline Foam::label Foam::foamVtuSizing::nAddCells() const
{
return nAddCells_;
}
inline Foam::label Foam::foamVtuSizing::nAddPoints() const
{
return nAddPoints_;
}
inline Foam::label Foam::foamVtuSizing::nAddVerts() const
{
return nAddVerts_;
}
inline Foam::label Foam::foamVtuSizing::nFieldCells() const
{
return nCells_ + nAddCells_;
}
inline Foam::label Foam::foamVtuSizing::nFieldPoints() const
{
return nPoints_ + nAddPoints_;
}
inline Foam::label Foam::foamVtuSizing::sizeLegacy() const
{
return slotSize(contentType::LEGACY, slotType::CELLS);
}
inline Foam::label Foam::foamVtuSizing::sizeLegacy
(
const enum slotType slot
) const
{
return slotSize(contentType::LEGACY, slot);
}
inline Foam::label Foam::foamVtuSizing::sizeXml
(
const enum slotType slot
) const
{
return slotSize(contentType::XML, slot);
}
inline Foam::label Foam::foamVtuSizing::sizeInternal
(
const enum slotType slot
) const
{
return slotSize(contentType::INTERNAL, slot);
}
// ************************************************************************* //

View File

@ -0,0 +1,670 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\/ 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 "foamVtuSizing.H"
#include "foamVtkCore.H"
#include "polyMesh.H"
#include "cellShape.H"
#include "cellModeller.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class LabelType, class LabelType2>
void Foam::foamVtuSizing::populateArrays
(
const polyMesh& mesh,
const foamVtuSizing& sizing,
UList<uint8_t>& cellTypes,
UList<LabelType>& vertLabels,
UList<LabelType>& vertOffset,
UList<LabelType>& faceLabels,
UList<LabelType>& faceOffset,
const enum contentType output,
UList<LabelType2>& cellMap,
UList<LabelType2>& addPointsIds
)
{
using vtkTypes = fileFormats::foamVtkCore::vtkTypes;
// STAGE 1: Verify storage sizes
if (cellTypes.size() != sizing.nFieldCells())
{
FatalErrorInFunction
<< " cellTypes size=" << cellTypes.size()
<< " expected " << sizing.nFieldCells()
<< exit(FatalError);
}
if (cellMap.size() != sizing.nFieldCells())
{
FatalErrorInFunction
<< " cellMap size=" << cellMap.size()
<< " expected " << sizing.nFieldCells()
<< exit(FatalError);
}
if (addPointsIds.size() != sizing.nAddPoints())
{
FatalErrorInFunction
<< " addPointsIds size=" << addPointsIds.size()
<< " expected " << sizing.nAddPoints()
<< exit(FatalError);
}
// Prefix vertLabels with the size too?
// Also use as the size of the prefixed information
const int prefix = (output != contentType::XML) ? 1 : 0;
switch (output)
{
case contentType::LEGACY:
{
if (vertLabels.size() != sizing.sizeLegacy())
{
FatalErrorInFunction
<< " legacy size=" << vertLabels.size()
<< " expected " << sizing.sizeLegacy()
<< exit(FatalError);
}
break;
}
case contentType::XML:
{
// XML uses connectivity/offset pair.
if
(
vertLabels.size()
!= sizing.sizeXml(slotType::CELLS)
)
{
FatalErrorInFunction
<< " connectivity size=" << vertLabels.size()
<< " expected "
<< sizing.sizeXml(slotType::CELLS)
<< exit(FatalError);
}
if
(
vertOffset.size()
!= sizing.sizeXml(slotType::CELLS_OFFSETS)
)
{
FatalErrorInFunction
<< " offsets size=" << vertOffset.size()
<< " expected "
<< sizing.sizeXml(slotType::CELLS_OFFSETS)
<< exit(FatalError);
}
if (sizing.nFaceLabels())
{
if
(
faceLabels.size()
!= sizing.sizeXml(slotType::FACES)
)
{
FatalErrorInFunction
<< " faces size=" << faceLabels.size()
<< " expected "
<< sizing.sizeXml(slotType::FACES)
<< exit(FatalError);
}
if
(
faceOffset.size()
!= sizing.sizeXml(slotType::FACES_OFFSETS)
)
{
FatalErrorInFunction
<< " facesOffsets size=" << faceOffset.size()
<< " expected "
<< sizing.sizeXml(slotType::FACES_OFFSETS)
<< exit(FatalError);
}
}
break;
}
case contentType::INTERNAL:
{
// VTK-internal connectivity/offset pair.
if
(
vertLabels.size()
!= sizing.sizeInternal(slotType::CELLS)
)
{
FatalErrorInFunction
<< " connectivity size=" << vertLabels.size()
<< " expected "
<< sizing.sizeInternal(slotType::CELLS)
<< exit(FatalError);
}
if
(
vertOffset.size()
!= sizing.sizeInternal(slotType::CELLS_OFFSETS)
)
{
FatalErrorInFunction
<< " offsets size=" << vertOffset.size()
<< " expected "
<< sizing.sizeInternal(slotType::CELLS_OFFSETS)
<< exit(FatalError);
}
if (sizing.nFaceLabels())
{
if
(
faceLabels.size()
!= sizing.sizeInternal(slotType::FACES)
)
{
FatalErrorInFunction
<< " faces size=" << faceLabels.size()
<< " expected "
<< sizing.sizeInternal(slotType::FACES)
<< exit(FatalError);
}
if
(
faceOffset.size()
!= sizing.sizeInternal(slotType::FACES_OFFSETS)
)
{
FatalErrorInFunction
<< " facesOffsets size=" << faceOffset.size()
<< " expected "
<< sizing.sizeInternal(slotType::FACES_OFFSETS)
<< exit(FatalError);
}
}
break;
}
}
faceOffset = -1;
const cellModel& tet = *(cellModeller::lookup("tet"));
const cellModel& pyr = *(cellModeller::lookup("pyr"));
const cellModel& prism = *(cellModeller::lookup("prism"));
const cellModel& wedge = *(cellModeller::lookup("wedge"));
const cellModel& tetWedge = *(cellModeller::lookup("tetWedge"));
const cellModel& hex = *(cellModeller::lookup("hex"));
const cellShapeList& shapes = mesh.cellShapes();
// face owner is needed to determine the face orientation
const labelList& owner = mesh.faceOwner();
// Unique vertex labels per polyhedral
HashSet<label> hashUniqId(2*256);
// Index into vertLabels, faceLabels for normal cells
label nVertLabels = 0;
label nFaceLabels = 0;
// Index into vertLabels for decomposed polys
label nVertDecomp = sizing.nVertLabels() + prefix*sizing.nCells();
// Placement of decomposed cells
label nCellDecomp = mesh.nCells();
// Placement of additional point labels
label nPointDecomp = 0;
// Non-decomposed polyhedral are represented as a face-stream.
// For legacy format, this stream replaces the normal connectivity
// information. Use references to alias where the face output should land.
UList<LabelType>& faceOutput =
(
output == contentType::LEGACY
? vertLabels
: faceLabels
);
label& faceIndexer =
(
output == contentType::LEGACY
? nVertLabels
: nFaceLabels
);
// ===========================================
// STAGE 2: Rewrite in VTK form
// During this stage, the vertOffset contains the *size* associated with
// the per-cell vertLabels entries, and the faceOffset contains the *size*
// associated with the per-cell faceLabels.
forAll(shapes, celli)
{
const cellShape& shape = shapes[celli];
const cellModel& model = shape.model();
cellMap[celli] = celli;
if (model == tet)
{
cellTypes[celli] = vtkTypes::VTK_TETRA;
if (vertOffset.size())
{
vertOffset[celli] = shape.size();
}
if (prefix)
{
vertLabels[nVertLabels++] = shape.size();
}
forAll(shape, i)
{
vertLabels[nVertLabels++] = shape[i];
}
}
else if (model == pyr)
{
cellTypes[celli] = vtkTypes::VTK_PYRAMID;
if (vertOffset.size())
{
vertOffset[celli] = shape.size();
}
if (prefix)
{
vertLabels[nVertLabels++] = shape.size();
}
forAll(shape, i)
{
vertLabels[nVertLabels++] = shape[i];
}
}
else if (model == hex)
{
cellTypes[celli] = vtkTypes::VTK_HEXAHEDRON;
if (vertOffset.size())
{
vertOffset[celli] = shape.size();
}
if (prefix)
{
vertLabels[nVertLabels++] = shape.size();
}
forAll(shape, i)
{
vertLabels[nVertLabels++] = shape[i];
}
}
else if (model == prism)
{
cellTypes[celli] = vtkTypes::VTK_WEDGE;
if (vertOffset.size())
{
vertOffset[celli] = shape.size();
}
if (prefix)
{
vertLabels[nVertLabels++] = shape.size();
}
// VTK_WEDGE triangles point outwards (swap 1<->2, 4<->5)
vertLabels[nVertLabels++] = shape[0];
vertLabels[nVertLabels++] = shape[2];
vertLabels[nVertLabels++] = shape[1];
vertLabels[nVertLabels++] = shape[3];
vertLabels[nVertLabels++] = shape[5];
vertLabels[nVertLabels++] = shape[4];
}
else if (model == tetWedge && sizing.decompose())
{
// Treat as squeezed prism
cellTypes[celli] = vtkTypes::VTK_WEDGE;
if (vertOffset.size())
{
vertOffset[celli] = 6;
}
if (prefix)
{
vertLabels[nVertLabels++] = 6;
}
vertLabels[nVertLabels++] = shape[0];
vertLabels[nVertLabels++] = shape[2];
vertLabels[nVertLabels++] = shape[1];
vertLabels[nVertLabels++] = shape[3];
vertLabels[nVertLabels++] = shape[4];
vertLabels[nVertLabels++] = shape[3];
}
else if (model == wedge && sizing.decompose())
{
// Treat as squeezed hex
cellTypes[celli] = vtkTypes::VTK_HEXAHEDRON;
if (vertOffset.size())
{
vertOffset[celli] = 8;
}
if (prefix)
{
vertLabels[nVertLabels++] = 8;
}
vertLabels[nVertLabels++] = shape[0];
vertLabels[nVertLabels++] = shape[1];
vertLabels[nVertLabels++] = shape[2];
vertLabels[nVertLabels++] = shape[2];
vertLabels[nVertLabels++] = shape[3];
vertLabels[nVertLabels++] = shape[4];
vertLabels[nVertLabels++] = shape[5];
vertLabels[nVertLabels++] = shape[6];
}
else if (sizing.decompose())
{
// Polyhedral cell - decompose into tet/pyr.
// Ensure we have the correct orientation for the base of the
// primitive cell shape.
// If the cell is face owner, the orientation needs to be flipped
// to avoid defining negative cells.
// VTK may not care, but we'll do it anyhow for safety.
// Mapping from additional point to cell, and the new vertex from
// the cell-centre
const label newVertexLabel = mesh.nPoints() + nPointDecomp;
addPointsIds[nPointDecomp++] = celli;
// Whether to insert cell in place of original or not.
bool first = true;
const labelList& cFaces = mesh.cells()[celli];
forAll(cFaces, cFaceI)
{
const face& f = mesh.faces()[cFaces[cFaceI]];
const bool isOwner = (owner[cFaces[cFaceI]] == celli);
// Count triangles/quads in decomposition
label nTria = 0, nQuad = 0;
f.nTrianglesQuads(mesh.points(), nTria, nQuad);
// Do actual decomposition
faceList faces3(nTria);
faceList faces4(nQuad);
nTria = 0, nQuad = 0;
f.trianglesQuads(mesh.points(), nTria, nQuad, faces3, faces4);
forAll(faces4, fci)
{
// Quad becomes a pyramid
const face& quad = faces4[fci];
const label nShapePoints = 5; // pyr (5 vertices)
label celLoc, vrtLoc;
if (first)
{
first = false;
celLoc = celli;
vrtLoc = nVertLabels;
nVertLabels += prefix + nShapePoints;
}
else
{
celLoc = nCellDecomp++;
vrtLoc = nVertDecomp;
nVertDecomp += prefix + nShapePoints;
}
cellMap[celLoc] = celli;
cellTypes[celLoc] = vtkTypes::VTK_PYRAMID;
if (vertOffset.size())
{
vertOffset[celLoc] = nShapePoints;
}
if (prefix)
{
vertLabels[vrtLoc++] = nShapePoints;
}
// See note above about the orientation.
if (isOwner)
{
vertLabels[vrtLoc++] = quad[3];
vertLabels[vrtLoc++] = quad[2];
vertLabels[vrtLoc++] = quad[1];
vertLabels[vrtLoc++] = quad[0];
}
else
{
vertLabels[vrtLoc++] = quad[0];
vertLabels[vrtLoc++] = quad[1];
vertLabels[vrtLoc++] = quad[2];
vertLabels[vrtLoc++] = quad[3];
}
vertLabels[vrtLoc++] = newVertexLabel; // apex
}
forAll(faces3, fci)
{
// Triangle becomes a tetrahedral
const face& tria = faces3[fci];
const label nShapePoints = 4; // tet (4 vertices)
label celLoc, vrtLoc;
if (first)
{
first = false;
celLoc = celli;
vrtLoc = nVertLabels;
nVertLabels += prefix + nShapePoints;
}
else
{
celLoc = nCellDecomp++;
vrtLoc = nVertDecomp;
nVertDecomp += prefix + nShapePoints;
}
cellMap[celLoc] = celli;
cellTypes[celLoc] = vtkTypes::VTK_TETRA;
if (vertOffset.size())
{
vertOffset[celLoc] = nShapePoints;
}
if (prefix)
{
vertLabels[vrtLoc++] = nShapePoints;
}
cellTypes[celLoc] = vtkTypes::VTK_TETRA;
// See note above about the orientation.
if (isOwner)
{
vertLabels[vrtLoc++] = tria[2];
vertLabels[vrtLoc++] = tria[1];
vertLabels[vrtLoc++] = tria[0];
}
else
{
vertLabels[vrtLoc++] = tria[0];
vertLabels[vrtLoc++] = tria[1];
vertLabels[vrtLoc++] = tria[2];
}
vertLabels[vrtLoc++] = newVertexLabel; // apex
}
}
}
else
{
// Polyhedral cell - not decomposed
hashUniqId.clear(); // unique node ids used (XML, INTERNAL)
// face-stream
// [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
cellTypes[celli] = vtkTypes::VTK_POLYHEDRON;
const labelList& cFaces = mesh.cells()[celli];
const label startLabel = faceIndexer;
if (output == contentType::LEGACY)
{
faceOutput[startLabel] = 0; // placeholder for size
++faceIndexer;
}
faceOutput[faceIndexer++] = cFaces.size();
forAll(cFaces, cFaceI)
{
const face& f = mesh.faces()[cFaces[cFaceI]];
const bool isOwner = (owner[cFaces[cFaceI]] == celli);
forAll(f, fp)
{
hashUniqId.insert(f[fp]);
}
// number of labels for this face
faceOutput[faceIndexer++] = f.size();
if (isOwner)
{
forAll(f, fp)
{
faceOutput[faceIndexer++] = f[fp];
}
}
else
{
// fairly immaterial if we reverse the list
// or use face::reverseFace()
forAllReverse(f, fp)
{
faceOutput[faceIndexer++] = f[fp];
}
}
}
if (output == contentType::LEGACY)
{
// Update size for legacy face stream
faceOutput[startLabel] = (faceIndexer - startLabel);
}
else
{
// Size for face stream
faceOffset[celli] = (faceIndexer - startLabel);
vertOffset[celli] = hashUniqId.size();
if (prefix)
{
vertLabels[nVertLabels++] = hashUniqId.size();
}
const labelList uniq = hashUniqId.sortedToc();
forAll(uniq, i)
{
vertLabels[nVertLabels++] = uniq[i];
}
}
}
}
// ===========================================
// STAGE 3: Adjust vertOffset for all cells
// A second pass is needed for several reasons.
// - Additional (decomposed) cells are placed out of sequence
// - Internal format has the size prefixed, XML format does not.
// - XML format expects end-offsets, Internal expects begin-offsets
switch (output)
{
case contentType::LEGACY: // nothing to do
break;
case contentType::XML:
{
// No prefix, determine end offsets
// vertOffset[0] already contains its size
for (label i = 1; i < vertOffset.size(); ++i)
{
vertOffset[i] += vertOffset[i-1];
}
if (sizing.nFaceLabels())
{
// End face offsets, leaving -1 untouched
label prev = 0;
forAll(faceOffset, i)
{
const label sz = faceOffset[i];
if (sz > 0)
{
prev += sz;
faceOffset[i] = prev;
}
}
}
break;
}
case contentType::INTERNAL:
{
// Has prefix, determine begin offsets
label beg = 0;
forAll(vertOffset, i)
{
const label sz = vertOffset[i];
vertOffset[i] = beg;
beg += 1 + sz;
}
// Begin face offsets, leaving -1 untouched
if (sizing.nFaceLabels())
{
beg = 0;
forAll(faceOffset, i)
{
const label sz = faceOffset[i];
if (sz > 0)
{
faceOffset[i] = beg;
beg += sz;
}
}
}
break;
}
}
}
// ************************************************************************* //