Merge branch 'feature-isosurface-snapping' into 'develop'

add point snapping to iso-surface topo algorithm (#2210)

See merge request Development/openfoam!488
This commit is contained in:
Andrew Heather
2021-09-27 15:46:13 +00:00
50 changed files with 3962 additions and 1492 deletions

View File

@ -0,0 +1,3 @@
foamCellZoneToVTK.C
EXE = $(FOAM_USER_APPBIN)/foamCellZoneToVTK

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \
-lfileFormats \
-lmeshTools

View File

@ -0,0 +1,161 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
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/>.
Application
foamCellZoneToVTK.C
Description
Write tet-decomposed OpenFOAM mesh in VTK format.
For diagnostic purposes.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "timeSelector.H"
#include "Time.H"
#include "polyMesh.H"
#include "foamVtkInternalMeshWriter.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
argList::addNote
(
"Write OpenFOAM cellZone mesh to VTK"
);
argList::addOption
(
"cellZone",
"name",
"Convert mesh subset corresponding to specified cellZone"
);
argList::addBoolOption
(
"list",
"List names of cellZones and exit"
);
timeSelector::addOptions();
#include "setRootCase.H"
word cellZoneName;
args.readIfPresent("cellZone", cellZoneName);
const bool optList = args.found("list");
if (optList)
{
if (!cellZoneName.empty())
{
Info<< "specify -list or -cellZone, but not both!" << nl;
return 1;
}
}
else if (cellZoneName.empty())
{
Info<< "Did not specify a cellZone!!" << nl;
return 1;
}
#include "createTime.H"
instantList timeDirs = timeSelector::select0(runTime, args);
fileName exportName("zonemesh-" + cellZoneName);
#include "createPolyMesh.H"
forAll(timeDirs, timei)
{
runTime.setTime(timeDirs[timei], timei);
polyMesh::readUpdateState state = mesh.readUpdate();
if (!timei || state != polyMesh::UNCHANGED)
{
fileName meshName(exportName);
if (state != polyMesh::UNCHANGED)
{
meshName += '_' + runTime.timeName();
}
if (optList)
{
Info<< "cellZones:" << nl;
for (const word& name : mesh.cellZones().names())
{
Info<< " " << name << nl;
}
}
else
{
const cellZone* zonePtr =
mesh.cellZones().cfindZone(cellZoneName);
Info<< "cellZone " << cellZoneName;
if (!zonePtr)
{
Info<< " ... not found" << nl;
continue;
}
Info<< nl;
const cellZone& zn = *zonePtr;
// Define a subset
vtk::vtuCells vtuCells;
vtuCells.reset(mesh, zn);
vtk::internalMeshWriter writer
(
mesh,
vtuCells,
fileName
(
mesh.time().globalPath() / meshName
)
);
writer.writeGeometry();
writer.beginCellData();
writer.writeProcIDs();
Info<< "Wrote " << writer.output().name() << nl;
}
}
}
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,4 @@
foamMeshToTet-vtk.C
writeVTKtetMesh.C
EXE = $(FOAM_USER_APPBIN)/foamMeshToTet-vtk

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \
-lfileFormats \
-lmeshTools

View File

@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
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/>.
Application
foamMeshToTet-vtk
Description
Write tet-decomposed OpenFOAM mesh in VTK format.
For diagnostic purposes.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "timeSelector.H"
#include "Time.H"
#include "polyMesh.H"
namespace Foam
{
void writeVTKtetMesh(const fileName& output, const polyMesh& mesh);
}
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
argList::addNote
(
"Write tet-decomposed OpenFOAM mesh in VTK"
);
argList::noParallel();
timeSelector::addOptions();
#include "setRootCase.H"
#include "createTime.H"
instantList timeDirs = timeSelector::select0(runTime, args);
fileName exportName = "tetmesh";
if (args.found("case"))
{
exportName += '-' + args.globalCaseName();
}
#include "createPolyMesh.H"
forAll(timeDirs, timei)
{
runTime.setTime(timeDirs[timei], timei);
polyMesh::readUpdateState state = mesh.readUpdate();
if (!timei || state != polyMesh::UNCHANGED)
{
fileName meshName(exportName);
if (state != polyMesh::UNCHANGED)
{
meshName += '_' + runTime.timeName();
}
writeVTKtetMesh(meshName, mesh);
}
}
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,204 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "polyMesh.H"
#include "Fstream.H"
#include "tetMatcher.H"
#include "foamVtkInternalMeshWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
void writeVTKtetMesh(const fileName& output, const polyMesh& mesh_)
{
#if WM_LABEL_SIZE == 64
# define FOAM_VTK_LABEL_NAME "vtktypeint64"
#else
# define FOAM_VTK_LABEL_NAME "int"
#endif
const faceList& faces = mesh_.faces();
const labelList& faceOwner = mesh_.faceOwner();
label nTets = 0;
for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
{
nTets += 2 * faces[facei].nTriangles();
}
for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); ++facei)
{
nTets += faces[facei].nTriangles();
}
const label nPoints = (mesh_.nPoints() + mesh_.nCells());
OFstream os(output + ".vtk");
Info<< "Write: " << os.name() << nl;
os << "# vtk DataFile Version 5.1" << nl
<< "tet-mesh" << nl
<< "ASCII" << nl
<< "DATASET UNSTRUCTURED_GRID" << nl
<< nl;
os << "POINTS " << nPoints << " float" << nl;
for (const point& p : mesh_.points())
{
os << float(p.x()) << ' '
<< float(p.y()) << ' '
<< float(p.z()) << nl;
}
for (const point& p : mesh_.cellCentres())
{
os << float(p.x()) << ' '
<< float(p.y()) << ' '
<< float(p.z()) << nl;
}
os << nl;
os << "CELLS " << (1 + nTets) << ' ' << (4 * nTets) << nl;
os << "OFFSETS " << FOAM_VTK_LABEL_NAME << nl
<< 0; // begin offset = 0
{
label offset = 0;
for (label teti = 0; teti < nTets; ++teti)
{
offset += 4;
os << ' ' << offset;
}
os << nl << nl;
}
labelList nLocalTets(mesh_.nCells(), Zero);
os << nl
<< "CONNECTIVITY " << FOAM_VTK_LABEL_NAME << nl;
for (label celli = 0; celli < mesh_.nCells(); ++celli)
{
const cell& cFaces = mesh_.cells()[celli];
if (tetMatcher::test(mesh_, celli))
{
// Tet: no cell-centre decomposition
const label facei = cFaces[0];
const face& f0 = faces[facei];
// Get the other point from f1. Tbd: check if not duplicate face
// (ACMI / ignoreBoundaryFaces_).
const face& f1 = faces[cFaces[1]];
label apexi = -1;
forAll(f1, fp)
{
apexi = f1[fp];
if (!f0.found(apexi))
{
break;
}
}
const label p0 = f0[0];
label p1 = f0[1];
label p2 = f0[2];
if (faceOwner[facei] == celli)
{
std::swap(p1, p2);
}
++nLocalTets[celli];
os << p0 << ' ' << p1 << ' ' << p2 << ' ' << apexi << nl;
}
else
{
for (const label facei : cFaces)
{
const face& f = faces[facei];
label fp0 = mesh_.tetBasePtIs()[facei];
// Fallback
if (fp0 < 0)
{
fp0 = 0;
}
const label p0 = f[fp0];
label fp = f.fcIndex(fp0);
for (label i = 2; i < f.size(); ++i)
{
label p1 = f[fp];
fp = f.fcIndex(fp);
label p2 = f[fp];
if (faceOwner[facei] == celli)
{
std::swap(p1, p2);
}
++nLocalTets[celli];
os << p0 << ' ' << p1 << ' ' << p2 << ' '
<< (mesh_.nPoints() + celli) << nl;
}
}
}
}
os << nl
<< "CELL_TYPES " << nTets << nl;
for (label teti = 0; teti < nTets; ++teti)
{
if (teti) os << ' ';
os << vtk::cellType::VTK_TETRA;
}
os << nl;
os << nl << "CELL_DATA " << nTets << nl
<< "FIELD FieldData " << 1 << nl;
os << "cellID " << 1 << ' ' << nTets << " int" << nl;
forAll(nLocalTets, celli)
{
label n = nLocalTets[celli];
while (n--)
{
os << ' ' << celli;
}
os << nl;
}
}
} // End namespace Foam
// ************************************************************************* //

View File

@ -264,7 +264,7 @@ Description
// Begin CellData
if (internalWriter)
{
// Optionally with cellID and procID fields
// Optionally with (cellID, procID) fields
internalWriter->beginCellData
(
(withMeshIds ? 1 + (internalWriter->parallel() ? 1 : 0) : 0)
@ -278,20 +278,21 @@ Description
}
}
if (nVolFields)
if (nVolFields || withMeshIds)
{
for (vtk::patchWriter& writer : patchWriters)
{
// Optionally with patchID field
// Optionally with (patchID, procID) fields
writer.beginCellData
(
(withMeshIds ? 1 : 0)
(withMeshIds ? 2 : 0)
+ nVolFields
);
if (withMeshIds)
{
writer.writePatchIDs();
writer.writeProcIDs();
}
}
}

View File

@ -149,7 +149,7 @@ void Foam::vtk::patchWriter::write
<< exit(FatalError);
}
label nFaces = nLocalFaces_;
label nFaces = nLocalPolys_;
if (parallel_)
{

View File

@ -59,6 +59,7 @@ vtk/part/foamVtuCells.C
vtk/part/foamVtuSizing.C
vtk/read/vtkUnstructuredReader.C
vtk/write/foamVtkLineWriter.C
vtk/write/foamVtkPolyWriter.C
vtk/write/foamVtkSurfaceWriter.C

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2018 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -113,6 +113,8 @@ Foam::vtk::dataArrayAttrNames
});
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Legacy
const Foam::word Foam::vtk::legacy::fileExtension("vtk");
@ -132,11 +134,27 @@ const Foam::Enum
<
Foam::vtk::fileTag
>
Foam::vtk::legacy::dataTypeNames
Foam::vtk::legacy::fileTagNames
({
{ vtk::fileTag::CELL_DATA, "CELL_DATA" },
{ vtk::fileTag::POINTS, "POINTS" },
{ vtk::fileTag::CELLS, "CELLS" },
{ vtk::fileTag::POLYS, "POLYGONS" },
{ vtk::fileTag::VERTS, "VERTICES" },
{ vtk::fileTag::LINES, "LINES" },
{ vtk::fileTag::CELL_DATA, "CELL_DATA" },
{ vtk::fileTag::POINT_DATA, "POINT_DATA" },
});
const Foam::Enum
<
Foam::vtk::dataArrayAttr
>
Foam::vtk::legacy::dataArrayAttrNames
({
{ vtk::dataArrayAttr::OFFSETS, "OFFSETS" },
{ vtk::dataArrayAttr::CONNECTIVITY, "CONNECTIVITY" },
});
// ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2018 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -183,8 +183,12 @@ namespace legacy
//- Legacy content names (POLYDATA, UNSTRUCTURED_GRID)
extern const Foam::Enum<vtk::fileTag> contentNames;
//- Legacy data type names (CELL_DATA, POINT_DATA)
extern const Foam::Enum<vtk::fileTag> dataTypeNames;
//- Legacy file tags (eg, LINES, CELL_DATA, POINT_DATA, ...)
extern const Foam::Enum<vtk::fileTag> fileTagNames;
//- Legacy attributes (eg, OFFSETS)
extern const Foam::Enum<dataArrayAttr> dataArrayAttrNames;
} // End namespace legacy

View File

@ -26,6 +26,7 @@ License
\*---------------------------------------------------------------------------*/
#include "foamVtkFileWriter.H"
#include "globalIndex.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -342,7 +343,7 @@ bool Foam::vtk::fileWriter::open(const fileName& file, bool parallel)
// Open a file and attach a formatter
// - on master (always)
// - on slave if not parallel
// - on subproc (if not parallel)
//
// This means we can always check if format_ is defined to know if output
// is desired on any particular process.
@ -515,7 +516,7 @@ void Foam::vtk::fileWriter::writeTimeValue(scalar timeValue)
<< exit(FatalError);
}
// No collectives - can skip on slave processors
// No collectives - can skip on sub-procs
if (!format_) return;
if (legacy())
@ -529,4 +530,66 @@ void Foam::vtk::fileWriter::writeTimeValue(scalar timeValue)
}
bool Foam::vtk::fileWriter::writeProcIDs(const label nValues)
{
// Write procIDs whenever running in parallel
if (!Pstream::parRun())
{
return false; // Non-parallel: skip
}
if (isState(outputState::CELL_DATA))
{
++nCellData_;
}
else
{
reportBadState(FatalErrorInFunction, outputState::CELL_DATA)
<< " for procID field" << nl << endl
<< exit(FatalError);
return false;
}
const globalIndex procSizes
(
parallel_
? globalIndex(nValues)
: globalIndex()
);
const label totalCount = (parallel_ ? procSizes.size() : nValues);
this->beginDataArray<label>("procID", totalCount);
bool good = false;
if (parallel_)
{
if (Pstream::master())
{
// Per-processor ids
for (const int proci : Pstream::allProcs())
{
vtk::write(format(), label(proci), procSizes.localSize(proci));
}
good = true;
}
}
else
{
vtk::write(format(), label(Pstream::myProcNo()), totalCount);
good = true;
}
this->endDataArray();
// MPI barrier
return parallel_ ? returnReduce(good, orOp<bool>()) : good;
}
// ************************************************************************* //

View File

@ -107,10 +107,10 @@ protected:
//- The output file name
fileName outputFile_;
//- The VTK formatter in use (master process)
//- The VTK formatter in use (only valid on master process)
autoPtr<vtk::formatter> format_;
//- The backend ostream in use (master process)
//- The backend ostream in use (only opened on master process)
std::ofstream os_;
@ -123,16 +123,16 @@ protected:
Ostream& reportBadState(Ostream&, outputState, outputState) const;
//- The backend ostream in use
inline std::ofstream& os();
inline std::ofstream& os() noexcept;
//- The VTK formatter in use
inline vtk::formatter& format();
//- True if the output state corresponds to the test state.
inline bool isState(outputState test) const;
//- True if output state corresponds to the test state.
inline bool isState(outputState test) const noexcept;
//- True if the output state does not correspond to the test state.
inline bool notState(outputState test) const;
//- True if output state does not correspond to the test state.
inline bool notState(outputState test) const noexcept;
//- Start of a field or DataArray output (legacy or non-legacy).
template<class Type>
@ -151,26 +151,6 @@ protected:
//- End of a POINTS DataArray
void endPoints();
//- Write uniform field content.
// No context checking (eg, file-open, CellData, PointData, etc)
template<class Type>
void writeUniform
(
const word& fieldName,
const Type& val,
const label nValues
);
//- Write basic (primitive) field content
// No context checking (eg, file-open, CellData, PointData, etc)
template<class Type>
void writeBasicField
(
const word& fieldName,
const UList<Type>& field
);
//- Trigger change state to Piece. Resets nCellData_, nPointData_.
bool enter_Piece();
@ -194,6 +174,34 @@ protected:
bool exit_File();
// Field writing
//- Write uniform field content.
// No context checking (eg, file-open, CellData, PointData, etc)
// The value and count can be different on each processor
template<class Type>
void writeUniform
(
const word& fieldName,
const Type& val,
const label nValues
);
//- Write basic (primitive) field content
// No context checking (eg, file-open, CellData, PointData, etc)
template<class Type>
void writeBasicField
(
const word& fieldName,
const UList<Type>& field
);
//- Write nValues of processor ids as CellData (no-op in serial)
bool writeProcIDs(const label nValues);
// Other
//- No copy construct
fileWriter(const fileWriter&) = delete;

View File

@ -27,7 +27,7 @@ License
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
inline std::ofstream& Foam::vtk::fileWriter::os()
inline std::ofstream& Foam::vtk::fileWriter::os() noexcept
{
return os_;
}
@ -39,13 +39,13 @@ inline Foam::vtk::formatter& Foam::vtk::fileWriter::format()
}
inline bool Foam::vtk::fileWriter::isState(outputState test) const
inline bool Foam::vtk::fileWriter::isState(outputState test) const noexcept
{
return (test == state_);
}
inline bool Foam::vtk::fileWriter::notState(outputState test) const
inline bool Foam::vtk::fileWriter::notState(outputState test) const noexcept
{
return (test != state_);
}

View File

@ -89,14 +89,25 @@ void Foam::vtk::fileWriter::writeUniform
(
const word& fieldName,
const Type& val,
const label nValues
const label nLocalValues
)
{
this->beginDataArray<Type>(fieldName, nValues);
label nTotal = nLocalValues;
if (format_)
if (parallel_)
{
vtk::write(format(), val, nValues);
reduce(nTotal, sumOp<label>());
}
this->beginDataArray<Type>(fieldName, nTotal);
if (parallel_)
{
vtk::writeValueParallel(format_.ref(), val, nLocalValues);
}
else
{
vtk::write(format(), val, nLocalValues);
}
this->endDataArray();

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -39,7 +39,7 @@ License
#include "globalIndex.H"
#include "instant.H"
#include "Fstream.H"
#include "Pstream.H"
#include "PstreamBuffers.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * //
@ -99,7 +99,7 @@ void Foam::vtk::writeIdentity
label start
)
{
// No nComponents for label, so use fmt.write() directly
// No nComponents for label, can use fmt.write() directly
for (label i=0; i < len; ++i)
{
fmt.write(start);
@ -114,7 +114,7 @@ void Foam::vtk::writeList
const UList<uint8_t>& values
)
{
// No nComponents for char, so use fmt.write() directly
// No nComponents for char, can use fmt.write() directly
for (const uint8_t val : values)
{
fmt.write(val);
@ -122,42 +122,6 @@ void Foam::vtk::writeList
}
void Foam::vtk::writeListParallel
(
vtk::formatter& fmt,
const UList<uint8_t>& values
)
{
if (Pstream::master())
{
vtk::writeList(fmt, values);
List<uint8_t> recv;
// Receive and write
for (const int slave : Pstream::subProcs())
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> recv;
vtk::writeList(fmt, recv);
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster << values;
}
}
void Foam::vtk::writeListParallel
(
vtk::formatter& fmt,
@ -165,45 +129,55 @@ void Foam::vtk::writeListParallel
const globalIndex& procOffset
)
{
// List sizes
const globalIndex sizes(values.size());
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send to master
if (!Pstream::master())
{
UOPstream os(Pstream::masterNo(), pBufs);
os.write
(
reinterpret_cast<const char*>(values.cdata()),
values.size_bytes()
);
}
pBufs.finishedSends();
if (Pstream::master())
{
// Master data
// Write with offset
const label offsetId = procOffset.offset(0);
for (const label val : values)
{
vtk::write(fmt, val + offsetId);
}
labelList recv;
// Receive and write
for (const int slave : Pstream::subProcs())
for (const int proci : Pstream::subProcs())
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
List<label> recv(sizes.localSize(proci));
fromSlave >> recv;
const label offsetId = procOffset.offset(slave);
UIPstream is(proci, pBufs);
is.read
(
reinterpret_cast<char*>(recv.data()),
recv.size_bytes()
);
// Write with offset
const label offsetId = procOffset.offset(proci);
for (const label val : recv)
{
vtk::write(fmt, val + offsetId);
}
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster << values;
}
}
@ -219,6 +193,9 @@ void Foam::vtk::legacy::fileHeader
// Line 1:
os << "# vtk DataFile Version 2.0" << nl;
// OR
// os << "# vtk DataFile Version 5.1" << nl;
// Line 2: title
const auto truncate = title.find('\n');

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2019 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -59,7 +59,7 @@ SourceFiles
namespace Foam
{
// Forward declarations
// Forward Declarations
class instant;
class globalIndex;
@ -94,14 +94,20 @@ namespace vtk
// The output does not include the payload size.
void writeList(vtk::formatter& fmt, const UList<uint8_t>& values);
//- Write a list of uint8_t values.
// The output does not include the payload size.
void writeListParallel(vtk::formatter& fmt, const UList<uint8_t>& values);
//- Component-wise write of a value (N times)
template<class Type>
inline void write(vtk::formatter& fmt, const Type& val, const label n=1);
//- Component-wise write of a value (N times) in parallel
// The value and count may differ on each processor
template<class Type>
inline void writeValueParallel
(
vtk::formatter& fmt,
const Type& val,
const label count=1
);
//- Write a list of values.
// The output does not include the payload size.
@ -215,7 +221,7 @@ namespace legacy
// Functions
//- Emit header for legacy file.
//- Emit header for legacy file (vtk DataFile Version 2.0)
// Writes "ASCII" or "BINARY" depending on specified type.
void fileHeader(std::ostream& os, const std::string& title, bool binary);
@ -248,6 +254,12 @@ namespace legacy
//- Emit header for POINTS (with trailing newline).
inline void beginPoints(std::ostream& os, label nPoints);
//- Emit header for LINES (with trailing newline).
// The nConnectivity is the sum of all connectivity points used,
// but \b without additional space for the size prefixes.
// The additional prefix sizes are added internally.
inline void beginLines(std::ostream& os, label nLines, label nConnectivity);
//- Emit header for POLYGONS (with trailing newline).
// The nConnectivity is the sum of all connectivity points used,
// but \b without additional space for the size prefixes.

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -113,7 +113,23 @@ inline void Foam::vtk::legacy::fileHeader
inline void Foam::vtk::legacy::beginPoints(std::ostream& os, label nPoints)
{
os << nl
<< "POINTS " << nPoints << " float" << nl;
<< legacy::fileTagNames[vtk::fileTag::POINTS]
<< ' ' << nPoints
<< " float" << nl;
}
inline void Foam::vtk::legacy::beginLines
(
std::ostream& os,
label nLines,
label nConnectivity
)
{
os << nl
<< legacy::fileTagNames[vtk::fileTag::LINES]
<< ' ' << nLines
<< ' ' << (nLines + nConnectivity) << nl;
}
@ -125,7 +141,9 @@ inline void Foam::vtk::legacy::beginPolys
)
{
os << nl
<< "POLYGONS " << nPolys << ' ' << (nPolys + nConnectivity) << nl;
<< legacy::fileTagNames[vtk::fileTag::POLYS]
<< ' ' << nPolys
<< ' ' << (nPolys + nConnectivity) << nl;
}
@ -159,7 +177,7 @@ inline void Foam::vtk::legacy::beginCellData
{
fmt.os()
<< nl
<< legacy::dataTypeNames[vtk::fileTag::CELL_DATA]
<< legacy::fileTagNames[vtk::fileTag::CELL_DATA]
<< ' ' << nCells << nl;
legacy::fieldData(fmt, nFields);
}
@ -174,7 +192,7 @@ inline void Foam::vtk::legacy::beginPointData
{
fmt.os()
<< nl
<< legacy::dataTypeNames[vtk::fileTag::POINT_DATA]
<< legacy::fileTagNames[vtk::fileTag::POINT_DATA]
<< ' ' << nPoints << nl;
legacy::fieldData(fmt, nFields);
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,7 +25,8 @@ License
\*---------------------------------------------------------------------------*/
#include "Pstream.H"
#include "globalIndex.H"
#include "PstreamBuffers.H"
#include "ListOps.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -122,6 +123,44 @@ void Foam::vtk::writeLists
}
template<class Type>
void Foam::vtk::writeValueParallel
(
vtk::formatter& fmt,
const Type& val,
const label count
)
{
if (Pstream::master())
{
vtk::write(fmt, val, count);
label subCount;
Type subValue;
// Receive each [size, value] tuple
for (const int proci : Pstream::subProcs())
{
IPstream is(Pstream::commsTypes::blocking, proci);
is >> subCount >> subValue;
vtk::write(fmt, subValue, subCount);
}
}
else
{
OPstream os
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
// Send [size, value] tuple
os << count << val;
}
}
template<class Type>
void Foam::vtk::writeListParallel
(
@ -129,32 +168,59 @@ void Foam::vtk::writeListParallel
const UList<Type>& values
)
{
if (Pstream::master())
// List sizes
const globalIndex sizes(values.size());
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send to master
if (!Pstream::master())
{
vtk::writeList(fmt, values);
List<Type> recv;
// Receive and write
for (const int slave : Pstream::subProcs())
UOPstream os(Pstream::masterNo(), pBufs);
if (is_contiguous<Type>::value)
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> recv;
vtk::writeList(fmt, recv);
os.write
(
reinterpret_cast<const char*>(values.cdata()),
values.size_bytes()
);
}
else
{
os << values;
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster << values;
pBufs.finishedSends();
if (Pstream::master())
{
// Write master data
vtk::writeList(fmt, values);
// Receive and write
for (const int proci : Pstream::subProcs())
{
UIPstream is(proci, pBufs);
{
List<Type> recv(sizes.localSize(proci));
if (is_contiguous<Type>::value)
{
is.read
(
reinterpret_cast<char*>(recv.data()),
recv.size_bytes()
);
}
else
{
is >> recv;
}
vtk::writeList(fmt, recv);
}
}
}
}
@ -167,33 +233,39 @@ void Foam::vtk::writeListParallel
const labelUList& addressing
)
{
UIndirectList<Type> send(values, addressing);
// List sizes
const globalIndex sizes(send.size());
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send to master
if (!Pstream::master())
{
UOPstream os(Pstream::masterNo(), pBufs);
os << send;
}
pBufs.finishedSends();
if (Pstream::master())
{
// Write master data
vtk::writeList(fmt, values, addressing);
List<Type> recv;
// Receive and write
for (const int slave : Pstream::subProcs())
for (const int proci : Pstream::subProcs())
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
UIPstream is(proci, pBufs);
fromSlave >> recv;
vtk::writeList(fmt, recv);
{
List<Type> recv;
is >> recv;
vtk::writeList(fmt, recv);
}
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster << List<Type>(values, addressing);
}
}
@ -205,32 +277,66 @@ void Foam::vtk::writeListParallel
const bitSet& selected
)
{
if (Pstream::master())
List<Type> send;
if (!Pstream::master())
{
vtk::writeList(fmt, values, selected);
send = subset(selected, values);
}
List<Type> recv;
// List sizes.
// NOTE okay to skip proc0 since we only need sizes (not offsets)
const globalIndex sizes(send.size());
// Receive and write
for (const int slave : Pstream::subProcs())
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send to master
if (!Pstream::master())
{
UOPstream os(Pstream::masterNo(), pBufs);
if (is_contiguous<Type>::value)
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> recv;
vtk::writeList(fmt, recv);
os.write
(
reinterpret_cast<const char*>(send.cdata()),
send.size_bytes()
);
}
else
{
os << send;
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster << subset(selected, values);
pBufs.finishedSends();
if (Pstream::master())
{
// Write master data
vtk::writeList(fmt, values, selected);
// Receive and write
for (const int proci : Pstream::subProcs())
{
UIPstream is(proci, pBufs);
{
List<Type> recv(sizes.localSize(proci));
if (is_contiguous<Type>::value)
{
is.read
(
reinterpret_cast<char*>(recv.data()),
recv.size_bytes()
);
}
else
{
is >> recv;
}
vtk::writeList(fmt, recv);
}
}
}
}
@ -243,34 +349,90 @@ void Foam::vtk::writeListsParallel
const UList<Type>& values2
)
{
// List sizes
const globalIndex sizes1(values1.size());
const globalIndex sizes2(values2.size());
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send to master
if (!Pstream::master())
{
UOPstream os(Pstream::masterNo(), pBufs);
if (is_contiguous<Type>::value)
{
os.write
(
reinterpret_cast<const char*>(values1.cdata()),
values1.size_bytes()
);
os.write
(
reinterpret_cast<const char*>(values2.cdata()),
values2.size_bytes()
);
}
else
{
os << values1 << values2;
}
}
pBufs.finishedSends();
if (Pstream::master())
{
// Write master data
vtk::writeList(fmt, values1);
vtk::writeList(fmt, values2);
List<Type> recv1, recv2;
// Receive and write
for (const int slave : Pstream::subProcs())
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> recv1 >> recv2;
vtk::writeList(fmt, recv1);
vtk::writeList(fmt, recv2);
}
}
else
{
// Send to master
OPstream toMaster
// Reserve max receive size
DynamicList<Type> recv
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
max(sizes1.maxNonLocalSize(), sizes2.maxNonLocalSize())
);
toMaster << values1 << values2;
// Receive and write
for (const int proci : Pstream::subProcs())
{
UIPstream is(proci, pBufs);
// values1
{
List<Type> recv(sizes1.localSize(proci));
if (is_contiguous<Type>::value)
{
is.read
(
reinterpret_cast<char*>(recv.data()),
recv.size_bytes()
);
}
else
{
is >> recv;
}
vtk::writeList(fmt, recv);
}
// values2
{
List<Type> recv(sizes2.localSize(proci));
if (is_contiguous<Type>::value)
{
is.read
(
reinterpret_cast<char*>(recv.data()),
recv.size_bytes()
);
}
else
{
is >> recv;
}
vtk::writeList(fmt, recv);
}
}
}
}
@ -284,35 +446,45 @@ void Foam::vtk::writeListsParallel
const labelUList& addressing
)
{
UIndirectList<Type> send2(values2, addressing);
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send to master
if (!Pstream::master())
{
UOPstream os(Pstream::masterNo(), pBufs);
os << values1 << send2;
}
pBufs.finishedSends();
if (Pstream::master())
{
// Write master data
vtk::writeList(fmt, values1);
vtk::writeList(fmt, values2, addressing);
List<Type> recv1, recv2;
// Receive and write
for (const int slave : Pstream::subProcs())
for (const int proci : Pstream::subProcs())
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
UIPstream is(proci, pBufs);
fromSlave >> recv1 >> recv2;
// values1
{
List<Type> recv;
is >> recv;
vtk::writeList(fmt, recv);
}
vtk::writeList(fmt, recv1);
vtk::writeList(fmt, recv2);
// values2 (send2)
{
List<Type> recv;
is >> recv;
vtk::writeList(fmt, recv);
}
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster << values1 << List<Type>(values2, addressing);
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2020 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -75,11 +75,8 @@ public:
// Constructors
//- Default construct: zero-sized, no reserved size
inline foamVtkMeshMaps();
//- Construct with reserved size
inline explicit foamVtkMeshMaps(const label size);
//- Default construct: zero-sized, no reserved sizes
foamVtkMeshMaps() = default;
// Member Functions
@ -87,26 +84,26 @@ public:
// Access
//- Original cell ids for all cells (regular and decomposed).
// A regular mesh comprising only primitive cell types, this will just
// For regular mesh comprising only primitive cell types, this will
// 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;
inline const labelList& cellMap() const noexcept;
//- Write access to original cell ids
inline DynamicList<label>& cellMap();
inline DynamicList<label>& cellMap() noexcept;
//- Point labels for subsetted meshes
inline const labelList& pointMap() const;
inline const labelList& pointMap() const noexcept;
//- Write access to point labels for subsetted meshes
inline DynamicList<label>& pointMap();
inline DynamicList<label>& pointMap() noexcept;
//- Any additional (user) labels.
// Eg, cell-centre labels for additional points of decomposed cells
inline const labelList& additionalIds() const;
inline const labelList& additionalIds() const noexcept;
//- Write access to additional (user) labels.
inline DynamicList<label>& additionalIds();
inline DynamicList<label>& additionalIds() noexcept;
// Edit
@ -115,7 +112,7 @@ public:
inline void clear();
//- Renumber cell ids (cellMap and additionalIds) to account for
// subset meshes
//- subset meshes
void renumberCells(const labelUList& mapping);
//- Renumber point ids (pointMap) to account for subset meshes

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2020 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,24 +27,6 @@ License
#include "foamVtkMeshMaps.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::foamVtkMeshMaps::foamVtkMeshMaps()
:
cellMap_(0),
pointMap_(0),
additionalIds_(0)
{}
inline Foam::foamVtkMeshMaps::foamVtkMeshMaps(const label size)
:
cellMap_(size),
pointMap_(size),
additionalIds_(size)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline void Foam::foamVtkMeshMaps::clear()
@ -56,42 +38,42 @@ inline void Foam::foamVtkMeshMaps::clear()
inline const Foam::labelList&
Foam::foamVtkMeshMaps::cellMap() const
Foam::foamVtkMeshMaps::cellMap() const noexcept
{
return cellMap_;
}
inline Foam::DynamicList<Foam::label>&
Foam::foamVtkMeshMaps::cellMap()
Foam::foamVtkMeshMaps::cellMap() noexcept
{
return cellMap_;
}
inline const Foam::labelList&
Foam::foamVtkMeshMaps::pointMap() const
Foam::foamVtkMeshMaps::pointMap() const noexcept
{
return pointMap_;
}
inline Foam::DynamicList<Foam::label>&
Foam::foamVtkMeshMaps::pointMap()
Foam::foamVtkMeshMaps::pointMap() noexcept
{
return pointMap_;
}
inline const Foam::labelList&
Foam::foamVtkMeshMaps::additionalIds() const
Foam::foamVtkMeshMaps::additionalIds() const noexcept
{
return additionalIds_;
}
inline Foam::DynamicList<Foam::label>&
Foam::foamVtkMeshMaps::additionalIds()
Foam::foamVtkMeshMaps::additionalIds() noexcept
{
return additionalIds_;
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -89,30 +89,23 @@ Foam::vtk::vtuCells::vtuCells
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::vtk::vtuCells::clear()
void Foam::vtk::vtuCells::resize_all()
{
vtuSizing::clear();
cellTypes_.clear();
vertLabels_.clear();
vertOffset_.clear();
faceLabels_.clear();
faceOffset_.clear();
maps_.clear();
}
void Foam::vtk::vtuCells::repopulate(const polyMesh& mesh)
{
// vtuSizing::reset() called prior to this method
cellTypes_.resize(nFieldCells());
vertLabels_.resize(sizeOf(output_, slotType::CELLS));
vertOffset_.resize(sizeOf(output_, slotType::CELLS_OFFSETS));
faceLabels_.resize(sizeOf(output_, slotType::FACES));
faceOffset_.resize(sizeOf(output_, slotType::FACES_OFFSETS));
}
void Foam::vtk::vtuCells::populateOutput(const polyMesh& mesh)
{
// Already called
// - vtuSizing::reset
// - resize_all();
switch (output_)
{
@ -163,10 +156,103 @@ void Foam::vtk::vtuCells::repopulate(const polyMesh& mesh)
}
void Foam::vtk::vtuCells::populateOutput(const UList<cellShape>& shapes)
{
if (output_ != contentType::LEGACY && output_ != contentType::XML)
{
WarningInFunction
<< "Internal formats not supported for shape cells - using XML"
<< nl << nl;
output_ = contentType::XML;
}
vtuSizing::resetShapes(shapes);
maps_.clear();
resize_all();
// Done in populate routine:
/// maps_.cellMap() = identity(vtuSizing::nCells());
switch (output_)
{
case contentType::LEGACY:
{
populateShapesLegacy
(
shapes,
cellTypes_,
vertLabels_,
maps_
);
break;
}
case contentType::XML:
{
populateShapesXml
(
shapes,
cellTypes_,
vertLabels_,
vertOffset_,
faceLabels_,
faceOffset_,
maps_
);
break;
}
default:
{
FatalErrorInFunction
<< "Unhandled VTK format " << int(output_) << nl
<< exit(FatalError);
break;
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::vtk::vtuCells::clear()
{
vtuSizing::clear();
cellTypes_.clear();
vertLabels_.clear();
vertOffset_.clear();
faceLabels_.clear();
faceOffset_.clear();
maps_.clear();
}
void Foam::vtk::vtuCells::reset(const polyMesh& mesh)
{
vtuSizing::reset(mesh, decomposeRequest_);
repopulate(mesh);
resize_all();
populateOutput(mesh);
}
void Foam::vtk::vtuCells::reset
(
const polyMesh& mesh,
const labelUList& subsetCellsIds
)
{
vtuSizing::reset(mesh, subsetCellsIds, decomposeRequest_);
resize_all();
if (selectionMode() == selectionModeType::SUBSET_MESH)
{
maps_.cellMap() = subsetCellsIds;
}
populateOutput(mesh);
}
@ -184,6 +270,75 @@ void Foam::vtk::vtuCells::reset
}
void Foam::vtk::vtuCells::resetShapes
(
const UList<cellShape>& shapes
)
{
if (output_ != contentType::LEGACY && output_ != contentType::XML)
{
WarningInFunction
<< "VTK internal format is not supported for shape cells"
<< " switching to xml" << nl << nl;
output_ = contentType::XML;
}
decomposeRequest_ = false;
vtuSizing::resetShapes(shapes);
maps_.clear();
resize_all();
maps_.cellMap() = identity(vtuSizing::nCells());
switch (output_)
{
case contentType::LEGACY:
{
populateShapesLegacy
(
shapes,
cellTypes_,
vertLabels_,
maps_
);
break;
}
case contentType::XML:
{
populateShapesXml
(
shapes,
cellTypes_,
vertLabels_,
vertOffset_,
faceLabels_,
faceOffset_,
maps_
);
break;
}
default:
{
FatalErrorInFunction
<< "Unhandled VTK format " << int(output_) << nl
<< exit(FatalError);
break;
}
}
}
void Foam::vtk::vtuCells::addPointCellLabels(const labelUList& cellIds)
{
maps_.additionalIds() = cellIds;
setNumAddPoints(maps_.additionalIds().size());
}
void Foam::vtk::vtuCells::renumberCells(const labelUList& mapping)
{
maps_.renumberCells(mapping);

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2014-2020 OpenCFD Ltd.
Copyright (C) 2014-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -59,9 +59,6 @@ SourceFiles
namespace Foam
{
// Forward Declarations
class polyMesh;
namespace vtk
{
// Forward Declarations
@ -110,9 +107,14 @@ class vtuCells
// Private Member Functions
//- Create the geometry using the previously requested output and
//- decomposition types.
void repopulate(const polyMesh& mesh);
//- Resize storage
void resize_all();
//- Create the geometry entries
void populateOutput(const polyMesh& mesh);
//- Create the geometry entries from shapes
void populateOutput(const UList<cellShape>& shapes);
//- No copy construct
vtuCells(const vtuCells&) = delete;
@ -162,10 +164,10 @@ public:
// Access
//- The output content type
inline enum contentType content() const;
inline enum contentType content() const noexcept;
//- Query the polyhedral decompose requested flag.
inline bool decomposeRequested() const;
inline bool decomposeRequested() const noexcept;
//- True if no cellTypes are populated.
inline bool empty() const noexcept;
@ -183,6 +185,14 @@ public:
//- decomposition types.
void reset(const polyMesh& mesh);
//- Create the geometry for a mesh subset,
//- using previously requested output and decomposition types.
void reset
(
const polyMesh& mesh,
const labelUList& subsetCellsIds
);
//- Respecify requested output and decomposition type prior to
//- creating the geometry
void reset
@ -192,35 +202,42 @@ public:
const bool decompose
);
//- Reset sizing using primitive shapes only (ADVANCED USAGE)
// Effectively removes any polyhedrals!
void resetShapes(const UList<cellShape>& shapes);
//- Renumber cell ids to account for subset meshes
void renumberCells(const labelUList& mapping);
//- Renumber point ids to account for subset meshes
void renumberPoints(const labelUList& mapping);
//- Define which additional cell-centres are to be used (ADVANCED!)
void addPointCellLabels(const labelUList& cellIds);
// Storage Access
//- Values for "types" (XML) and "CELL_TYPES" (legacy)
inline const List<uint8_t>& cellTypes() const;
inline const List<uint8_t>& cellTypes() const noexcept;
//- Values for "connectivity" (XML) or "CELLS" (legacy)
inline const labelList& vertLabels() const;
inline const labelList& vertLabels() const noexcept;
//- Values for "offsets" (XML only)
inline const labelList& vertOffsets() const;
inline const labelList& vertOffsets() const noexcept;
//- Values for "faces" (XML only)
inline const labelList& faceLabels() const;
inline const labelList& faceLabels() const noexcept;
//- Values for "faceoffset" (XML only)
inline const labelList& faceOffsets() const;
inline const labelList& faceOffsets() const noexcept;
//- Additional point addressing (from added point to original cell)
inline const labelList& addPointCellLabels() const;
inline const labelList& addPointCellLabels() const noexcept;
//- Original cell ids for all cells (regular and decomposed).
inline const labelList& cellMap() const;
inline const labelList& cellMap() const noexcept;
};

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,13 +30,13 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline enum Foam::vtk::vtuCells::contentType
Foam::vtk::vtuCells::content() const
Foam::vtk::vtuCells::content() const noexcept
{
return output_;
}
inline bool Foam::vtk::vtuCells::decomposeRequested() const
inline bool Foam::vtk::vtuCells::decomposeRequested() const noexcept
{
return decomposeRequest_;
}
@ -55,49 +55,49 @@ inline Foam::label Foam::vtk::vtuCells::size() const noexcept
inline const Foam::List<uint8_t>&
Foam::vtk::vtuCells::cellTypes() const
Foam::vtk::vtuCells::cellTypes() const noexcept
{
return cellTypes_;
}
inline const Foam::labelList&
Foam::vtk::vtuCells::vertLabels() const
Foam::vtk::vtuCells::vertLabels() const noexcept
{
return vertLabels_;
}
inline const Foam::labelList&
Foam::vtk::vtuCells::vertOffsets() const
Foam::vtk::vtuCells::vertOffsets() const noexcept
{
return vertOffset_;
}
inline const Foam::labelList&
Foam::vtk::vtuCells::faceLabels() const
Foam::vtk::vtuCells::faceLabels() const noexcept
{
return faceLabels_;
}
inline const Foam::labelList&
Foam::vtk::vtuCells::faceOffsets() const
Foam::vtk::vtuCells::faceOffsets() const noexcept
{
return faceOffset_;
}
inline const Foam::labelList&
Foam::vtk::vtuCells::addPointCellLabels() const
Foam::vtk::vtuCells::addPointCellLabels() const noexcept
{
return maps_.additionalIds();
}
inline const Foam::labelList&
Foam::vtk::vtuCells::cellMap() const
Foam::vtk::vtuCells::cellMap() const noexcept
{
return maps_.cellMap();
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -31,7 +31,7 @@ License
#include "cellShape.H"
// Only used in this file
#include "foamVtuSizingTemplates.C"
#include "foamVtuSizingImpl.C"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -42,6 +42,162 @@ void Foam::vtk::vtuSizing::presizeMaps(foamVtkMeshMaps& maps) const
}
void Foam::vtk::vtuSizing::checkSizes
(
const vtk::vtuSizing& sizing,
const label cellTypes_size,
const label vertLabels_size,
const label vertOffset_size,
const label faceLabels_size,
const label faceOffset_size,
const enum contentType output,
const label cellMap_size,
const label addPointsIds_size
)
{
label nErrors = 0;
#undef CHECK_SIZING
#define CHECK_SIZING(what, sizeInput, sizeExpected) \
if (sizeInput != sizeExpected) \
{ \
if (!nErrors++) \
{ \
FatalErrorInFunction << "VTK sizing error" << nl; \
} \
FatalError \
<< " " << what << " size=" << sizeInput \
<< " expected " << sizeExpected << nl; \
}
CHECK_SIZING("cellTypes", cellTypes_size, sizing.nFieldCells());
CHECK_SIZING("cellMap", cellMap_size, sizing.nFieldCells());
CHECK_SIZING("addPointsIds", addPointsIds_size, sizing.nAddPoints());
switch (output)
{
case contentType::LEGACY:
{
CHECK_SIZING("legacy", vertLabels_size, sizing.sizeLegacy());
break;
}
case contentType::XML:
{
// XML uses connectivity/offset pair.
CHECK_SIZING
(
"connectivity",
vertLabels_size,
sizing.sizeXml(slotType::CELLS)
);
CHECK_SIZING
(
"offsets",
vertOffset_size,
sizing.sizeXml(slotType::CELLS_OFFSETS)
);
if (sizing.nFaceLabels())
{
CHECK_SIZING
(
"faces",
faceLabels_size,
sizing.sizeXml(slotType::FACES)
);
CHECK_SIZING
(
"faceOffsets",
faceOffset_size,
sizing.sizeXml(slotType::FACES_OFFSETS)
);
}
break;
}
case contentType::INTERNAL1:
{
// VTK-internal1 connectivity/offset pair.
CHECK_SIZING
(
"connectivity",
vertLabels_size,
sizing.sizeInternal1(slotType::CELLS)
);
CHECK_SIZING
(
"offsets",
vertOffset_size,
sizing.sizeInternal1(slotType::CELLS_OFFSETS)
);
if (sizing.nFaceLabels())
{
CHECK_SIZING
(
"faces",
faceLabels_size,
sizing.sizeInternal1(slotType::FACES)
);
CHECK_SIZING
(
"faceOffsets",
faceOffset_size,
sizing.sizeInternal1(slotType::FACES_OFFSETS)
);
}
break;
}
case contentType::INTERNAL2:
{
// VTK-internal2 connectivity/offset pair.
CHECK_SIZING
(
"connectivity",
vertLabels_size,
sizing.sizeInternal2(slotType::CELLS)
);
CHECK_SIZING
(
"offsets",
vertOffset_size,
sizing.sizeInternal2(slotType::CELLS_OFFSETS)
);
if (sizing.nFaceLabels())
{
CHECK_SIZING
(
"faces",
faceLabels_size,
sizing.sizeInternal2(slotType::FACES)
);
CHECK_SIZING
(
"faceOffsets",
faceOffset_size,
sizing.sizeInternal2(slotType::FACES_OFFSETS)
);
}
break;
}
}
if (nErrors)
{
FatalError
<< nl
<< "Total of " << nErrors << " sizing errors encountered!"
<< exit(FatalError);
}
#undef CHECK_SIZING
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::vtk::vtuSizing::vtuSizing() noexcept
@ -66,6 +222,7 @@ Foam::vtk::vtuSizing::vtuSizing
void Foam::vtk::vtuSizing::clear() noexcept
{
decompose_ = false;
selectionMode_ = FULL_MESH;
nCells_ = 0;
nPoints_ = 0;
nVertLabels_ = 0;
@ -86,20 +243,56 @@ void Foam::vtk::vtuSizing::reset
const bool decompose
)
{
const cellModel& tet = cellModel::ref(cellModel::TET);
const cellModel& pyr = cellModel::ref(cellModel::PYR);
const cellModel& prism = cellModel::ref(cellModel::PRISM);
reset(mesh, labelUList::null(), decompose);
}
void Foam::vtk::vtuSizing::reset
(
const polyMesh& mesh,
const labelUList& subsetCellsIds,
const bool decompose
)
{
// References to cell shape models
const cellModel& tet = cellModel::ref(cellModel::TET);
const cellModel& pyr = cellModel::ref(cellModel::PYR);
const cellModel& prism = cellModel::ref(cellModel::PRISM);
const cellModel& hex = cellModel::ref(cellModel::HEX);
const cellModel& wedge = cellModel::ref(cellModel::WEDGE);
const cellModel& tetWedge = cellModel::ref(cellModel::TETWEDGE);
const cellModel& hex = cellModel::ref(cellModel::HEX);
const cellShapeList& shapes = mesh.cellShapes();
// Unique vertex labels per polyhedral
labelHashSet hashUniqId(2*256);
decompose_ = decompose;
nCells_ = mesh.nCells();
// Special treatment for mesh subsets.
const bool isSubsetMesh
(
notNull(subsetCellsIds)
);
if (isSubsetMesh)
{
decompose_ = false; // Disallow decomposition for subset mode
selectionMode_ = selectionModeType::SUBSET_MESH;
}
else
{
decompose_ = decompose; // Disallow decomposition
selectionMode_ = selectionModeType::FULL_MESH;
}
const label nInputCells =
(
isSubsetMesh
? subsetCellsIds.size()
: shapes.size()
);
nCells_ = nInputCells;
nPoints_ = mesh.nPoints();
nAddCells_ = 0;
nAddVerts_ = 0;
@ -109,10 +302,10 @@ void Foam::vtk::vtuSizing::reset
nFaceLabels_ = 0;
nVertPoly_ = 0;
const label len = mesh.nCells();
for (label celli=0; celli < len; ++celli)
for (label inputi = 0; inputi < nInputCells; ++inputi)
{
const label celli(isSubsetMesh ? subsetCellsIds[inputi] : inputi);
const cellShape& shape = shapes[celli];
const cellModel& model = shape.model();
@ -128,15 +321,15 @@ void Foam::vtk::vtuSizing::reset
--nCellsPoly_;
nVertLabels_ += shape.size();
}
else if (model == tetWedge && decompose)
else if (model == tetWedge && decompose_)
{
nVertLabels_ += 6; // Treat as squeezed prism (VTK_WEDGE)
}
else if (model == wedge && decompose)
else if (model == wedge && decompose_)
{
nVertLabels_ += 8; // Treat as squeezed hex
}
else if (decompose)
else if (decompose_)
{
// Polyhedral: Decompose into tets + pyramids.
++nAddPoints_;
@ -199,7 +392,78 @@ void Foam::vtk::vtuSizing::reset
}
// Requested and actually required
decompose_ = (decompose && nCellsPoly_);
decompose_ = (decompose_ && nCellsPoly_);
}
// Synchronize changes here with the following:
// - vtuSizing::resetShapes
// - vtuSizing::populateArrays
//
void Foam::vtk::vtuSizing::resetShapes
(
const UList<cellShape>& shapes
)
{
const cellModel& tet = cellModel::ref(cellModel::TET);
const cellModel& pyr = cellModel::ref(cellModel::PYR);
const cellModel& prism = cellModel::ref(cellModel::PRISM);
const cellModel& hex = cellModel::ref(cellModel::HEX);
decompose_ = false; // Disallow decomposition
selectionMode_ = SHAPE_MESH;
const label nInputCells = shapes.size();
nCells_ = nInputCells;
nPoints_ = 0;
nAddCells_ = 0;
nAddVerts_ = 0;
nCellsPoly_ = 0;
nVertLabels_ = 0;
nFaceLabels_ = 0;
nVertPoly_ = 0;
label nIgnored = 0;
for (label inputi = 0; inputi < nInputCells; ++inputi)
{
const cellShape& shape = shapes[inputi];
const cellModel& model = shape.model();
if
(
model == tet
|| model == pyr
|| model == prism
|| model == hex
)
{
nVertLabels_ += shape.size();
// Guess for number of addressed points
nPoints_ = max(nPoints_, max(shape));
}
else
{
--nCells_;
++nIgnored;
}
}
if (nIgnored)
{
FatalErrorInFunction
<< "Encountered " << nIgnored << " unsupported cell shapes"
<< " ... this is likely not good" << nl
<< exit(FatalError);
}
if (nCells_)
{
++nPoints_;
}
}
@ -339,6 +603,35 @@ void Foam::vtk::vtuSizing::populateLegacy
}
void Foam::vtk::vtuSizing::populateShapesLegacy
(
const UList<cellShape>& shapes,
UList<uint8_t>& cellTypes,
labelUList& vertLabels,
foamVtkMeshMaps& maps
) const
{
// Leave as zero-sized so that populateArrays doesn't fill it.
List<label> unused;
presizeMaps(maps);
populateArrays
(
shapes,
*this,
cellTypes,
vertLabels,
unused, // offsets
unused, // faces
unused, // facesOffsets
contentType::LEGACY,
maps.cellMap(),
maps.additionalIds()
);
}
void Foam::vtk::vtuSizing::populateXml
(
const polyMesh& mesh,
@ -368,6 +661,38 @@ void Foam::vtk::vtuSizing::populateXml
}
void Foam::vtk::vtuSizing::populateShapesXml
(
const UList<cellShape>& shapes,
UList<uint8_t>& cellTypes,
labelUList& connectivity,
labelUList& offsets,
labelUList& faces,
labelUList& facesOffsets,
foamVtkMeshMaps& maps
) const
{
// Leave as zero-sized so that populateArrays doesn't fill it.
List<label> unused;
presizeMaps(maps);
populateArrays
(
shapes,
*this,
cellTypes,
connectivity,
offsets,
unused, // faces
unused, // facesOffsets
contentType::XML,
maps.cellMap(),
maps.additionalIds()
);
}
#undef definePopulateInternalMethod
#define definePopulateInternalMethod(Type) \
\

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -49,7 +49,7 @@ Description
These are the storage entries normally associate with each output-type:
\table
legacy output
legacy output (vtk DataFile Version 2.0)
\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, ...]
@ -118,6 +118,7 @@ namespace Foam
{
// Forward Declarations
class cellShape;
class polyMesh;
namespace vtk
@ -134,7 +135,7 @@ public:
// Public Data
//- Types of content that the storage may represent
enum contentType
enum contentType : char
{
LEGACY, //!< Legacy VTK content
XML, //!< XML (VTU) content
@ -143,7 +144,7 @@ public:
};
//- The possible storage 'slots' that can be used
enum slotType
enum slotType : char
{
CELLS, //!< Cell connectivity (ALL)
CELLS_OFFSETS, //!< Cell end-offsets (XML), locations (INTERNAL1)
@ -152,6 +153,14 @@ public:
FACES_OFFSETS //!< Faces end-offsets (XML) or locations (INTERNAL1)
};
//- How the mesh cells have been selected or defined
enum selectionModeType : char
{
FULL_MESH,
SUBSET_MESH,
SHAPE_MESH
};
private:
@ -160,6 +169,9 @@ private:
//- Polyhedral decomposition requested
bool decompose_;
//- How the mesh cells have been selected or defined
selectionModeType selectionMode_;
//- Number of cells in the mesh
label nCells_;
@ -199,8 +211,35 @@ private:
//- set-size for cellMap and additionalIds
void presizeMaps(foamVtkMeshMaps& maps) const;
//- Verify list sizes
static void checkSizes
(
const vtk::vtuSizing& sizing,
const label cellTypes_size,
const label vertLabels_size,
const label vertOffset_size,
const label faceLabels_size,
const label faceOffset_size,
const enum contentType output,
const label cellMap_size,
const label addPointsIds_size
);
//- Adjust cell/face offsets
template<class LabelType>
static void adjustOffsets
(
UList<LabelType>& vertOffset,
UList<LabelType>& faceOffset,
const enum contentType output,
const bool hasFaceStream
);
//- Populate lists. For (legacy | xml | internal) VTK representations
template<class LabelType, class LabelType2>
template<class LabelType>
static void populateArrays
(
const polyMesh& mesh,
@ -211,10 +250,52 @@ private:
UList<LabelType>& faceLabels,
UList<LabelType>& faceOffset,
const enum contentType output,
UList<LabelType2>& cellMap,
UList<LabelType2>& addPointsIds
labelUList& cellMap,
labelUList& addPointsIds
);
//- Populate lists - Primitive mesh shapes only!!
template<class LabelType>
static void populateArrays
(
const UList<cellShape>& shapes,
const vtk::vtuSizing& sizing,
UList<uint8_t>& cellTypes,
UList<LabelType>& vertLabels,
UList<LabelType>& vertOffset,
UList<LabelType>& faceLabels, // unused
UList<LabelType>& faceOffset, // unused
const enum contentType output,
labelUList& cellMap,
labelUList& addPointsIds // unused
);
protected:
// Protected Member Functions
//- Reset list for primitive shapes only (ADVANCED USAGE)
void populateShapesLegacy
(
const UList<cellShape>& shapes,
UList<uint8_t>& cellTypes,
labelUList& connectivity,
foamVtkMeshMaps& maps
) const;
//- Reset list for primitive shapes only (ADVANCED USAGE)
void populateShapesXml
(
const UList<cellShape>& shapes,
UList<uint8_t>& cellTypes,
labelUList& connectivity,
labelUList& offsets,
labelUList& faces,
labelUList& facesOffsets,
foamVtkMeshMaps& maps
) const;
public:
@ -240,6 +321,20 @@ public:
// Optionally with polyhedral decomposition.
void reset(const polyMesh& mesh, const bool decompose=false);
//- Reset sizing by analyzing a subset of the mesh.
// A labelUList::null() selection corresponds to the entire mesh.
// Polyhedral decomposition is disabled for subsets.
void reset
(
const polyMesh& mesh,
const labelUList& subsetCellsIds,
const bool decompose = false
);
//- Reset sizing using primitive shapes only (ADVANCED USAGE)
// Effectively removes any polyhedrals!
void resetShapes(const UList<cellShape>& shapes);
//- Reset all sizes to zero.
void clear() noexcept;
@ -247,44 +342,56 @@ public:
// Access
//- Query the decompose flag (normally off)
inline bool decompose() const;
inline bool decompose() const noexcept;
//- Query how the mesh cells have been selected or defined
inline selectionModeType selectionMode() const noexcept;
//- Number of cells for the mesh
inline label nCells() const;
inline label nCells() const noexcept;
//- Number of points for the mesh
inline label nPoints() const;
inline label nPoints() const noexcept;
//- Number of vertex labels for the mesh
inline label nVertLabels() const;
inline label nVertLabels() const noexcept;
//- Number of polyhedral face labels for the mesh
inline label nFaceLabels() const;
inline label nFaceLabels() const noexcept;
//- Number of polyhedral cells for the mesh
inline label nCellsPoly() const;
inline label nCellsPoly() const noexcept;
//- Number of vertex labels for polyhedral cells of the mesh
inline label nVertPoly() const;
inline label nVertPoly() const noexcept;
//- Number of additional (decomposed) cells for the mesh
inline label nAddCells() const;
inline label nAddCells() const noexcept;
//- Number of additional (decomposed) points for the mesh
inline label nAddPoints() const;
inline label nAddPoints() const noexcept;
//- Number of additional (decomposed) vertices for the mesh
inline label nAddVerts() const;
inline label nAddVerts() const noexcept;
//- Number of field cells = nCells + nAddCells
inline label nFieldCells() const;
inline label nFieldCells() const noexcept;
//- Number of field points = nPoints + nAddPoints
inline label nFieldPoints() const;
inline label nFieldPoints() const noexcept;
// Derived sizes
// Edit
//- Alter number of mesh points (ADVANCED USAGE)
void setNumPoints(label n) noexcept { nPoints_ = n; }
//- Alter number of additional (cell-centre) points (ADVANCED USAGE)
void setNumAddPoints(label n) noexcept { nAddPoints_ = n; }
// Derived Sizes
//- Return the required size for the storage slot
label sizeOf

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2020 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -29,75 +29,82 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::vtk::vtuSizing::decompose() const
inline bool Foam::vtk::vtuSizing::decompose() const noexcept
{
return decompose_;
}
inline Foam::label Foam::vtk::vtuSizing::nCells() const
inline Foam::vtk::vtuSizing::selectionModeType
Foam::vtk::vtuSizing::selectionMode() const noexcept
{
return selectionMode_;
}
inline Foam::label Foam::vtk::vtuSizing::nCells() const noexcept
{
return nCells_;
}
inline Foam::label Foam::vtk::vtuSizing::nPoints() const
inline Foam::label Foam::vtk::vtuSizing::nPoints() const noexcept
{
return nPoints_;
}
inline Foam::label Foam::vtk::vtuSizing::nVertLabels() const
inline Foam::label Foam::vtk::vtuSizing::nVertLabels() const noexcept
{
return nVertLabels_;
}
inline Foam::label Foam::vtk::vtuSizing::nFaceLabels() const
inline Foam::label Foam::vtk::vtuSizing::nFaceLabels() const noexcept
{
return nFaceLabels_;
}
inline Foam::label Foam::vtk::vtuSizing::nCellsPoly() const
inline Foam::label Foam::vtk::vtuSizing::nCellsPoly() const noexcept
{
return nCellsPoly_;
}
inline Foam::label Foam::vtk::vtuSizing::nVertPoly() const
inline Foam::label Foam::vtk::vtuSizing::nVertPoly() const noexcept
{
return nVertPoly_;
}
inline Foam::label Foam::vtk::vtuSizing::nAddCells() const
inline Foam::label Foam::vtk::vtuSizing::nAddCells() const noexcept
{
return nAddCells_;
}
inline Foam::label Foam::vtk::vtuSizing::nAddPoints() const
inline Foam::label Foam::vtk::vtuSizing::nAddPoints() const noexcept
{
return nAddPoints_;
}
inline Foam::label Foam::vtk::vtuSizing::nAddVerts() const
inline Foam::label Foam::vtk::vtuSizing::nAddVerts() const noexcept
{
return nAddVerts_;
}
inline Foam::label Foam::vtk::vtuSizing::nFieldCells() const
inline Foam::label Foam::vtk::vtuSizing::nFieldCells() const noexcept
{
return nCells_ + nAddCells_;
return (nCells_ + nAddCells_);
}
inline Foam::label Foam::vtk::vtuSizing::nFieldPoints() const
inline Foam::label Foam::vtk::vtuSizing::nFieldPoints() const noexcept
{
return nPoints_ + nAddPoints_;
return (nPoints_ + nAddPoints_);
}

View File

@ -32,21 +32,170 @@ License
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class LabelType, class LabelType2>
template<class LabelType>
void Foam::vtk::vtuSizing::adjustOffsets
(
UList<LabelType>& vertOffset,
UList<LabelType>& faceOffset,
const enum contentType output,
const bool hasFaceStream
)
{
// ===========================================
// Adjust vertOffset for all cells
// A second pass is needed for several reasons.
// - Additional (decomposed) cells are placed out of sequence
// - INTERNAL1 connectivity has size prefixed
//
// Cell offsets:
// - XML format expects end-offsets,
// - INTERNAL1 expects begin-offsets
// - INTERNAL2 expects begin/end-offsets
switch (output)
{
case contentType::LEGACY: // Nothing to do
break;
case contentType::XML:
{
// Transform cell sizes (vertOffset) into begin offsets
// vertOffset[0] already contains its size, leave untouched
for (label i = 1; i < vertOffset.size(); ++i)
{
vertOffset[i] += vertOffset[i-1];
}
// The end face offsets, leaving -1 untouched
if (hasFaceStream)
{
LabelType prev(0);
for (LabelType& off : faceOffset)
{
const LabelType sz(off);
if (sz > 0)
{
prev += sz;
off = prev;
}
}
}
break;
}
case contentType::INTERNAL1:
{
// Transform cell sizes (vertOffset) into begin offsets
{
LabelType beg(0);
for (LabelType& off : vertOffset)
{
const LabelType sz(off);
off = beg;
beg += 1 + sz; // Additional 1 to skip embedded prefix
}
}
// The begin face offsets, leaving -1 untouched
if (hasFaceStream)
{
LabelType beg(0);
for (LabelType& off : faceOffset)
{
const LabelType sz(off);
if (sz > 0)
{
off = beg;
beg += sz;
}
}
}
break;
}
case contentType::INTERNAL2:
{
// Transform cell sizes (vertOffset) into begin/end offsets
// input [n1, n2, n3, ..., 0]
// becomes [0, n1, n1+n2, n1+n2+n3, ..., nTotal]
// The last entry of vertOffset was initialized as zero and
// never revisited, so the following loop is OK
{
LabelType total(0);
for (LabelType& off : vertOffset)
{
const LabelType sz(off);
off = total;
total += sz;
}
}
// The begin face offsets, leaving -1 untouched
if (hasFaceStream)
{
LabelType beg(0);
for (LabelType& off : faceOffset)
{
const LabelType sz(off);
if (sz > 0)
{
off = beg;
beg += sz;
}
}
}
break;
}
}
}
template<class LabelType>
void Foam::vtk::vtuSizing::populateArrays
(
const polyMesh& mesh,
const vtk::vtuSizing& 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
labelUList& cellMap,
labelUList& addPointsIds
)
{
if (sizing.selectionMode() == selectionModeType::SHAPE_MESH)
{
FatalErrorInFunction
<< "Programming error ... attempting to populate a VTU mesh"
<< " but it was originally sized using independent cell shapes"
<< exit(FatalError);
}
// Verify storage sizes
checkSizes
(
sizing,
cellTypes.size(),
vertLabels.size(), vertOffset.size(),
faceLabels.size(), faceOffset.size(),
output,
cellMap.size(),
addPointsIds.size()
);
// Characteristics
// Are vertLabels prefixed with the size?
@ -58,228 +207,6 @@ void Foam::vtk::vtuSizing::populateArrays
) ? 1 : 0;
// 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);
}
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::INTERNAL1:
{
// VTK-internal1 connectivity/offset pair.
if
(
vertLabels.size()
!= sizing.sizeInternal1(slotType::CELLS)
)
{
FatalErrorInFunction
<< " connectivity size=" << vertLabels.size()
<< " expected "
<< sizing.sizeInternal1(slotType::CELLS)
<< exit(FatalError);
}
if
(
vertOffset.size()
!= sizing.sizeInternal1(slotType::CELLS_OFFSETS)
)
{
FatalErrorInFunction
<< " offsets size=" << vertOffset.size()
<< " expected "
<< sizing.sizeInternal1(slotType::CELLS_OFFSETS)
<< exit(FatalError);
}
if (sizing.nFaceLabels())
{
if
(
faceLabels.size()
!= sizing.sizeInternal1(slotType::FACES)
)
{
FatalErrorInFunction
<< " faces size=" << faceLabels.size()
<< " expected "
<< sizing.sizeInternal1(slotType::FACES)
<< exit(FatalError);
}
if
(
faceOffset.size()
!= sizing.sizeInternal1(slotType::FACES_OFFSETS)
)
{
FatalErrorInFunction
<< " facesOffsets size=" << faceOffset.size()
<< " expected "
<< sizing.sizeInternal1(slotType::FACES_OFFSETS)
<< exit(FatalError);
}
}
break;
}
case contentType::INTERNAL2:
{
// VTK-internal2 connectivity/offset pair.
if
(
vertLabels.size()
!= sizing.sizeInternal2(slotType::CELLS)
)
{
FatalErrorInFunction
<< " connectivity size=" << vertLabels.size()
<< " expected "
<< sizing.sizeInternal2(slotType::CELLS)
<< exit(FatalError);
}
if
(
vertOffset.size()
!= sizing.sizeInternal2(slotType::CELLS_OFFSETS)
)
{
FatalErrorInFunction
<< " offsets size=" << vertOffset.size()
<< " expected "
<< sizing.sizeInternal2(slotType::CELLS_OFFSETS)
<< exit(FatalError);
}
if (sizing.nFaceLabels())
{
if
(
faceLabels.size()
!= sizing.sizeInternal2(slotType::FACES)
)
{
FatalErrorInFunction
<< " faces size=" << faceLabels.size()
<< " expected "
<< sizing.sizeInternal2(slotType::FACES)
<< exit(FatalError);
}
if
(
faceOffset.size()
!= sizing.sizeInternal2(slotType::FACES_OFFSETS)
)
{
FatalErrorInFunction
<< " facesOffsets size=" << faceOffset.size()
<< " expected "
<< sizing.sizeInternal2(slotType::FACES_OFFSETS)
<< exit(FatalError);
}
}
break;
}
}
// Initialization
faceOffset = -1;
@ -297,9 +224,9 @@ void Foam::vtk::vtuSizing::populateArrays
const cellModel& tet = cellModel::ref(cellModel::TET);
const cellModel& pyr = cellModel::ref(cellModel::PYR);
const cellModel& prism = cellModel::ref(cellModel::PRISM);
const cellModel& hex = cellModel::ref(cellModel::HEX);
const cellModel& wedge = cellModel::ref(cellModel::WEDGE);
const cellModel& tetWedge = cellModel::ref(cellModel::TETWEDGE);
const cellModel& hex = cellModel::ref(cellModel::HEX);
const cellShapeList& shapes = mesh.cellShapes();
@ -316,11 +243,11 @@ void Foam::vtk::vtuSizing::populateArrays
// Index into vertLabels for decomposed polys
label nVertDecomp = sizing.nVertLabels() + prefix*sizing.nCells();
// Placement of decomposed cells
// Placement of additional decomposed cells
label nCellDecomp = mesh.nCells();
// Placement of additional point labels
label nPointDecomp = 0;
label nPointDecomp = mesh.nPoints();
// Non-decomposed polyhedral are represented as a face-stream.
// For legacy format, this stream replaces the normal connectivity
@ -346,23 +273,48 @@ void Foam::vtk::vtuSizing::populateArrays
// the per-cell vertLabels entries, and the faceOffset contains the *size*
// associated with the per-cell faceLabels.
const label len = shapes.size();
for (label celli=0; celli < len; ++celli)
// Special treatment for mesh subsets
// Here the cellMap is the list of input cells!
const bool isSubsetMesh
(
sizing.selectionMode() == selectionModeType::SUBSET_MESH
);
const label nInputCells =
(
isSubsetMesh
? cellMap.size()
: shapes.size()
);
for
(
label inputi = 0, cellIndex = 0; // cellIndex: the ouput location
inputi < nInputCells;
++inputi, ++cellIndex
)
{
const label celli(isSubsetMesh ? cellMap[inputi] : inputi);
const cellShape& shape = shapes[celli];
const cellModel& model = shape.model();
cellMap[celli] = celli;
if (!isSubsetMesh)
{
cellMap[cellIndex] = celli;
}
if (model == tet)
{
cellTypes[celli] = vtk::cellType::VTK_TETRA;
cellTypes[cellIndex] = vtk::cellType::VTK_TETRA;
constexpr label nShapePoints = 4; // OR shape.size();
if (vertOffset.size())
{
vertOffset[celli] = nShapePoints;
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
@ -376,12 +328,12 @@ void Foam::vtk::vtuSizing::populateArrays
}
else if (model == pyr)
{
cellTypes[celli] = vtk::cellType::VTK_PYRAMID;
cellTypes[cellIndex] = vtk::cellType::VTK_PYRAMID;
constexpr label nShapePoints = 5; // OR shape.size();
if (vertOffset.size())
{
vertOffset[celli] = nShapePoints;
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
@ -395,12 +347,12 @@ void Foam::vtk::vtuSizing::populateArrays
}
else if (model == hex)
{
cellTypes[celli] = vtk::cellType::VTK_HEXAHEDRON;
cellTypes[cellIndex] = vtk::cellType::VTK_HEXAHEDRON;
constexpr label nShapePoints = 8; // OR shape.size();
if (vertOffset.size())
{
vertOffset[celli] = nShapePoints;
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
@ -414,12 +366,12 @@ void Foam::vtk::vtuSizing::populateArrays
}
else if (model == prism)
{
cellTypes[celli] = vtk::cellType::VTK_WEDGE;
cellTypes[cellIndex] = vtk::cellType::VTK_WEDGE;
constexpr label nShapePoints = 6; // OR shape.size();
if (vertOffset.size())
{
vertOffset[celli] = nShapePoints;
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
@ -437,12 +389,12 @@ void Foam::vtk::vtuSizing::populateArrays
else if (model == tetWedge && sizing.decompose())
{
// Treat as squeezed prism
cellTypes[celli] = vtk::cellType::VTK_WEDGE;
cellTypes[cellIndex] = vtk::cellType::VTK_WEDGE;
constexpr label nShapePoints = 6;
if (vertOffset.size())
{
vertOffset[celli] = nShapePoints;
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
@ -459,12 +411,12 @@ void Foam::vtk::vtuSizing::populateArrays
else if (model == wedge && sizing.decompose())
{
// Treat as squeezed hex
cellTypes[celli] = vtk::cellType::VTK_HEXAHEDRON;
cellTypes[cellIndex] = vtk::cellType::VTK_HEXAHEDRON;
constexpr label nShapePoints = 8;
if (vertOffset.size())
{
vertOffset[celli] = nShapePoints;
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
@ -492,7 +444,7 @@ void Foam::vtk::vtuSizing::populateArrays
// Mapping from additional point to cell, and the new vertex from
// the cell-centre
const label newVertexLabel = mesh.nPoints() + nPointDecomp;
const label newVertexLabel = nPointDecomp;
addPointsIds[nPointDecomp++] = celli;
@ -526,7 +478,7 @@ void Foam::vtk::vtuSizing::populateArrays
if (firstCell)
{
firstCell = false;
celLoc = celli;
celLoc = cellIndex;
vrtLoc = nVertLabels;
nVertLabels += prefix + nShapePoints;
}
@ -578,7 +530,7 @@ void Foam::vtk::vtuSizing::populateArrays
if (firstCell)
{
firstCell = false;
celLoc = celli;
celLoc = cellIndex;
vrtLoc = nVertLabels;
nVertLabels += prefix + nShapePoints;
}
@ -626,7 +578,7 @@ void Foam::vtk::vtuSizing::populateArrays
// face-stream
// [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
cellTypes[celli] = vtk::cellType::VTK_POLYHEDRON;
cellTypes[cellIndex] = vtk::cellType::VTK_POLYHEDRON;
const labelList& cFaces = mesh.cells()[celli];
const label startLabel = faceIndexer;
@ -676,9 +628,9 @@ void Foam::vtk::vtuSizing::populateArrays
else
{
// Size for face stream
faceOffset[celli] = (faceIndexer - startLabel);
faceOffset[cellIndex] = (faceIndexer - startLabel);
vertOffset[celli] = hashUniqId.size();
vertOffset[cellIndex] = hashUniqId.size();
if (prefix)
{
vertLabels[nVertLabels++] = hashUniqId.size();
@ -703,108 +655,224 @@ void Foam::vtk::vtuSizing::populateArrays
// - INTERNAL1 expects begin-offsets
// - INTERNAL2 expects begin/end-offsets
switch (output)
adjustOffsets<LabelType>
(
vertOffset,
faceOffset,
output,
sizing.nFaceLabels() // hasFaceStream
);
}
// Synchronize changes here with the following:
// - vtuSizing::resetShapes
// - vtuSizing::populateArrays
template<class LabelType>
void Foam::vtk::vtuSizing::populateArrays
(
const UList<cellShape>& shapes,
const vtk::vtuSizing& sizing,
UList<uint8_t>& cellTypes,
UList<LabelType>& vertLabels,
UList<LabelType>& vertOffset,
UList<LabelType>& faceLabels,
UList<LabelType>& faceOffset,
const enum contentType output,
labelUList& cellMap,
labelUList& addPointsIds
)
{
if (sizing.selectionMode() != selectionModeType::SHAPE_MESH)
{
case contentType::LEGACY: // nothing to do
break;
FatalErrorInFunction
<< "Programming error ... attempting to populate a VTU mesh"
<< " from cell shapes, but sizing originated from a different"
<< " representation" << nl
<< exit(FatalError);
}
case contentType::XML:
// Verify storage sizes
checkSizes
(
sizing,
cellTypes.size(),
vertLabels.size(), vertOffset.size(),
faceLabels.size(), faceOffset.size(),
output,
cellMap.size(),
addPointsIds.size()
);
// Characteristics
// Are vertLabels prefixed with the size?
// Also use as the size of the prefixed information
const int prefix =
(
output == contentType::LEGACY
|| output == contentType::INTERNAL1
) ? 1 : 0;
// Initialization
faceOffset = -1;
// For INTERNAL2, the vertOffset is (nFieldCells+1), which means that
// the last entry is never visited. Set as zero now.
if (vertOffset.size())
{
vertOffset.first() = 0;
vertOffset.last() = 0;
}
const cellModel& tet = cellModel::ref(cellModel::TET);
const cellModel& pyr = cellModel::ref(cellModel::PYR);
const cellModel& prism = cellModel::ref(cellModel::PRISM);
const cellModel& hex = cellModel::ref(cellModel::HEX);
// Index into vertLabels for normal cells
label nVertLabels = 0;
// ===========================================
// 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.
const label nInputCells = shapes.size();
label nIgnored = 0;
for
(
label inputi = 0, cellIndex = 0; // cellIndex: the ouput location
inputi < nInputCells;
++inputi, ++cellIndex
)
{
const cellShape& shape = shapes[inputi];
const cellModel& model = shape.model();
if (model == tet)
{
// Transform cell sizes (vertOffset) into begin offsets
cellTypes[cellIndex] = vtk::cellType::VTK_TETRA;
constexpr label nShapePoints = 4; // OR shape.size();
// vertOffset[0] already contains its size, leave untouched
for (label i = 1; i < vertOffset.size(); ++i)
if (vertOffset.size())
{
vertOffset[i] += vertOffset[i-1];
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
vertLabels[nVertLabels++] = nShapePoints;
}
// The end face offsets, leaving -1 untouched
if (sizing.nFaceLabels())
for (const label cpi : shape)
{
LabelType prev(0);
for (LabelType& off : faceOffset)
{
const LabelType sz(off);
if (sz > 0)
{
prev += sz;
off = prev;
}
}
vertLabels[nVertLabels++] = cpi;
}
break;
}
case contentType::INTERNAL1:
else if (model == pyr)
{
// Transform cell sizes (vertOffset) into begin offsets
{
LabelType beg(0);
cellTypes[cellIndex] = vtk::cellType::VTK_PYRAMID;
constexpr label nShapePoints = 5; // OR shape.size();
for (LabelType& off : vertOffset)
{
const LabelType sz(off);
off = beg;
beg += 1 + sz; // Additional 1 to skip embedded prefix
}
if (vertOffset.size())
{
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
vertLabels[nVertLabels++] = nShapePoints;
}
// The begin face offsets, leaving -1 untouched
if (sizing.nFaceLabels())
for (const label cpi : shape)
{
LabelType beg(0);
for (LabelType& off : faceOffset)
{
const LabelType sz(off);
if (sz > 0)
{
off = beg;
beg += sz;
}
}
vertLabels[nVertLabels++] = cpi;
}
break;
}
case contentType::INTERNAL2:
else if (model == hex)
{
// Transform cell sizes (vertOffset) into begin/end offsets
// input [n1, n2, n3, ..., 0]
// becomes [0, n1, n1+n2, n1+n2+n3, ..., nTotal]
cellTypes[cellIndex] = vtk::cellType::VTK_HEXAHEDRON;
constexpr label nShapePoints = 8; // OR shape.size();
// The last entry of vertOffset was initialized as zero and
// never revisited, so the following loop is OK
if (vertOffset.size())
{
LabelType total(0);
for (LabelType& off : vertOffset)
{
const LabelType sz(off);
off = total;
total += sz;
}
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
vertLabels[nVertLabels++] = nShapePoints;
}
// The begin face offsets, leaving -1 untouched
if (sizing.nFaceLabels())
for (const label cpi : shape)
{
LabelType beg(0);
for (LabelType& off : faceOffset)
{
const LabelType sz(off);
if (sz > 0)
{
off = beg;
beg += sz;
}
}
vertLabels[nVertLabels++] = cpi;
}
break;
}
else if (model == prism)
{
cellTypes[cellIndex] = vtk::cellType::VTK_WEDGE;
constexpr label nShapePoints = 6; // OR shape.size();
if (vertOffset.size())
{
vertOffset[cellIndex] = nShapePoints;
}
if (prefix)
{
vertLabels[nVertLabels++] = nShapePoints;
}
// 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
{
// Silent here.
// - already complained (and skipped) during initial sizing
--cellIndex;
++nIgnored;
}
}
// May have been done by caller,
// but for additional safety set an identity mapping
ListOps::identity(cellMap);
// ===========================================
// Adjust vertOffset for all cells
// A second pass is needed for several reasons.
// - Additional (decomposed) cells are placed out of sequence
// - INTERNAL1 connectivity has size prefixed
//
// Cell offsets:
// - XML format expects end-offsets,
// - INTERNAL1 expects begin-offsets
// - INTERNAL2 expects begin/end-offsets
adjustOffsets<LabelType>
(
vertOffset,
faceOffset,
output,
sizing.nFaceLabels() // hasFaceStream
);
}

View File

@ -0,0 +1,138 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "foamVtkLineWriter.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::vtk::lineWriter::lineWriter
(
const pointField& points,
const edgeList& edges,
const vtk::outputOptions opts
)
:
vtk::polyWriter(opts),
points_(std::cref<pointField>(points)),
edges_(std::cref<edgeList>(edges)),
instant_()
{}
Foam::vtk::lineWriter::lineWriter
(
const pointField& points,
const edgeList& edges,
const fileName& file,
bool parallel
)
:
lineWriter(points, edges)
{
open(file, parallel);
}
Foam::vtk::lineWriter::lineWriter
(
const pointField& points,
const edgeList& edges,
const vtk::outputOptions opts,
const fileName& file,
bool parallel
)
:
lineWriter(points, edges, opts)
{
open(file, parallel);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::vtk::lineWriter::setTime(const instant& inst)
{
instant_ = inst;
}
bool Foam::vtk::lineWriter::beginFile(std::string title)
{
if (title.size())
{
return vtk::fileWriter::beginFile(title);
}
if (!instant_.name().empty())
{
return vtk::fileWriter::beginFile
(
"time='" + instant_.name() + "'"
);
}
// Provide default title
return vtk::fileWriter::beginFile("edges");
}
bool Foam::vtk::lineWriter::writeGeometry()
{
return writeLineGeometry(points_.get(), edges_.get());
}
void Foam::vtk::lineWriter::writeTimeValue()
{
if (!instant_.name().empty())
{
vtk::fileWriter::writeTimeValue(instant_.value());
}
}
void Foam::vtk::lineWriter::piece
(
const pointField& points,
const edgeList& edges
)
{
endPiece();
points_ = std::cref<pointField>(points);
edges_ = std::cref<edgeList>(edges);
}
bool Foam::vtk::lineWriter::writeProcIDs()
{
return vtk::fileWriter::writeProcIDs(nLocalLines_);
}
// ************************************************************************* //

View File

@ -0,0 +1,180 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
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::vtk::lineWriter
Description
Write edge/points (optionally with fields)
as a vtp file or a legacy vtk file.
The file output states are managed by the Foam::vtk::fileWriter class.
FieldData (eg, TimeValue) must appear before any geometry pieces.
Note
Parallel output is combined into a single Piece without point merging,
which is similar to using multi-piece data sets, but allows more
convenient creation as a streaming process.
In the future, the duplicate points at processor connections
may be addressed using ghost points.
SourceFiles
foamVtkLineWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_vtk_lineWriter_H
#define Foam_vtk_lineWriter_H
#include "foamVtkPolyWriter.H"
#include "instant.H"
#include <functional>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace vtk
{
/*---------------------------------------------------------------------------*\
Class vtk::lineWriter Declaration
\*---------------------------------------------------------------------------*/
class lineWriter
:
public vtk::polyWriter
{
// Private Member Data
//- Reference to the points
std::reference_wrapper<const pointField> points_;
//- Reference to the edges
std::reference_wrapper<const edgeList> edges_;
//- Time name/value
instant instant_;
// Private Member Functions
//- No copy construct
lineWriter(const lineWriter&) = delete;
//- No copy assignment
void operator=(const lineWriter&) = delete;
public:
// Constructors
//- Construct from components (default format INLINE_BASE64)
lineWriter
(
const pointField& pts,
const edgeList& edges,
const vtk::outputOptions opts = vtk::formatType::INLINE_BASE64
);
//- Construct from components (default format INLINE_BASE64),
//- and open the file for writing.
// The file name is with/without an extension.
lineWriter
(
const pointField& pts,
const edgeList& edges,
const fileName& file,
bool parallel = Pstream::parRun()
);
//- Construct from components and open the file for writing.
// The file name is with/without an extension.
lineWriter
(
const pointField& pts,
const edgeList& edges,
const vtk::outputOptions opts,
const fileName& file,
bool parallel = Pstream::parRun()
);
//- Destructor
virtual ~lineWriter() = default;
// Member Functions
//- Define a time name/value for the output
virtual void setTime(const instant& inst);
//- Write file header (non-collective)
// \note Expected calling states: (OPENED).
virtual bool beginFile(std::string title = "");
//- Write patch topology
// Also writes the file header if not previously written.
// \note Must be called prior to writing CellData or PointData
virtual bool writeGeometry();
//- Write "TimeValue" FieldData (name as per Catalyst output)
// Must be called within the FIELD_DATA state.
// \note As a convenience this can also be called from
// (OPENED | DECLARED) states, in which case it invokes
// beginFieldData(1) internally.
using vtk::fileWriter::writeTimeValue;
//- Write the currently set time as "TimeValue" FieldData
void writeTimeValue();
//- Reset point/edge references to begin a new piece
void piece(const pointField& points, const edgeList& edges);
//- Write processor ids for each line as CellData
//- (no-op in serial)
bool writeProcIDs();
//- Write a uniform field of Cell (Line) or Point values
template<class Type>
void writeUniform(const word& fieldName, const Type& val)
{
polyWriter::writeUniformValue<Type>(nLocalLines_, fieldName, val);
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace vtk
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -29,8 +29,73 @@ License
#include "foamVtkOutput.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// The connectivity count for a list of edges
static inline label countConnectivity(const edgeList& edges)
{
return 2 * edges.size(); // An edge always has two ends
}
// The connectivity count for a list of faces
static label countConnectivity(const faceList& faces)
{
label nConnectivity = 0;
for (const face& f : faces)
{
nConnectivity += f.size();
}
return nConnectivity;
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::vtk::polyWriter::beginPiece
(
const pointField& points,
const edgeList& edges
)
{
// Basic sizes
nLocalPoints_ = points.size();
nLocalLines_ = edges.size();
nLocalPolys_ = 0;
numberOfPoints_ = nLocalPoints_;
numberOfCells_ = nLocalLines_;
if (parallel_)
{
reduce(numberOfPoints_, sumOp<label>());
reduce(numberOfCells_, sumOp<label>());
}
// Nothing else to do for legacy
if (legacy()) return;
if (format_)
{
format().tag
(
vtk::fileTag::PIECE,
vtk::fileAttr::NUMBER_OF_POINTS, numberOfPoints_,
vtk::fileAttr::NUMBER_OF_LINES, numberOfCells_
// AND: vtk::fileAttr::NUMBER_OF_POLYS, 0
);
}
}
void Foam::vtk::polyWriter::beginPiece
(
const pointField& points,
@ -39,16 +104,11 @@ void Foam::vtk::polyWriter::beginPiece
{
// Basic sizes
nLocalPoints_ = points.size();
nLocalFaces_ = faces.size();
nLocalVerts_ = 0;
for (const face& f : faces)
{
nLocalVerts_ += f.size();
}
nLocalLines_ = 0;
nLocalPolys_ = faces.size();
numberOfPoints_ = nLocalPoints_;
numberOfCells_ = nLocalFaces_;
numberOfCells_ = nLocalPolys_;
if (parallel_)
{
@ -67,6 +127,7 @@ void Foam::vtk::polyWriter::beginPiece
vtk::fileTag::PIECE,
vtk::fileAttr::NUMBER_OF_POINTS, numberOfPoints_,
vtk::fileAttr::NUMBER_OF_POLYS, numberOfCells_
// AND: vtk::fileAttr::NUMBER_OF_LINES, 0
);
}
}
@ -79,48 +140,219 @@ void Foam::vtk::polyWriter::writePoints
{
this->beginPoints(numberOfPoints_);
if (parallel_ ? Pstream::master() : true)
if (parallel_)
{
{
vtk::writeList(format(), points);
}
vtk::writeListParallel(format_.ref(), points);
}
else
{
vtk::writeList(format(), points);
}
this->endPoints();
}
void Foam::vtk::polyWriter::writeLinesLegacy
(
const edgeList& edges,
const label pointOffset
)
{
// Connectivity count without additional storage (done internally)
const label nLocalConns = countConnectivity(edges);
label nLines = nLocalLines_;
label nConns = nLocalConns;
if (parallel_)
{
if (Pstream::master())
reduce(nLines, sumOp<label>());
reduce(nConns, sumOp<label>());
}
if (nLines != numberOfCells_)
{
FatalErrorInFunction
<< "Expecting " << numberOfCells_
<< " edges, but found " << nLines
<< exit(FatalError);
}
legacy::beginLines(os_, nLines, nConns);
labelList vertLabels(nLocalLines_ + nLocalConns);
{
// Legacy: size + connectivity together
// [nPts, id1, id2, ..., nPts, id1, id2, ...]
auto iter = vertLabels.begin();
const label off = pointOffset;
for (const edge& e : edges)
{
pointField recv;
*iter = e.size(); // The size prefix (always 2 for an edge)
++iter;
// Receive each point field and write
for (const int subproci : Pstream::subProcs())
{
IPstream fromProc(Pstream::commsTypes::blocking, subproci);
*iter = off + e.first(); // Vertex labels
++iter;
{
fromProc >> recv;
vtk::writeList(format(), recv);
}
}
}
else
{
// Send
OPstream toProc
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
{
toProc << points;
}
*iter = off + e.second();
++iter;
}
}
this->endPoints();
if (parallel_)
{
vtk::writeListParallel(format_.ref(), vertLabels);
}
else
{
vtk::writeList(format(), vertLabels);
}
if (format_)
{
format().flush();
}
}
void Foam::vtk::polyWriter::writeLines
(
const edgeList& edges,
const label pointOffset
)
{
// Connectivity count without additional storage (done internally)
const label nLocalConns = countConnectivity(edges);
if (format_)
{
format().tag(vtk::fileTag::LINES);
}
//
// 'connectivity'
//
{
labelList vertLabels(nLocalConns);
label nConns = nLocalConns;
if (parallel_)
{
reduce(nConns, sumOp<label>());
}
if (format_)
{
const uint64_t payLoad = vtk::sizeofData<label>(nConns);
format().beginDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY);
format().writeSize(payLoad * sizeof(label));
}
{
// XML: connectivity only
// [id1, id2, ..., id1, id2, ...]
auto iter = vertLabels.begin();
const label off = pointOffset;
for (const edge& e : edges)
{
// Edge vertex labels
*iter = off + e.first();
++iter;
*iter = off + e.second();
++iter;
}
}
if (parallel_)
{
vtk::writeListParallel(format_.ref(), vertLabels);
}
else
{
vtk::writeList(format(), vertLabels);
}
if (format_)
{
format().flush();
format().endDataArray();
}
}
//
// 'offsets' (connectivity offsets)
//
{
labelList vertOffsets(nLocalLines_);
label nOffs = vertOffsets.size();
if (parallel_)
{
reduce(nOffs, sumOp<label>());
}
if (format_)
{
const uint64_t payLoad = vtk::sizeofData<label>(nOffs);
format().beginDataArray<label>(vtk::dataArrayAttr::OFFSETS);
format().writeSize(payLoad);
}
// processor-local connectivity offsets
label off =
(
parallel_ ? globalIndex(nLocalConns).localStart() : 0
);
auto iter = vertOffsets.begin();
for (const edge& e : edges)
{
off += e.size(); // End offset
*iter = off;
++iter;
}
if (parallel_)
{
vtk::writeListParallel(format_.ref(), vertOffsets);
}
else
{
vtk::writeList(format_.ref(), vertOffsets);
}
if (format_)
{
format().flush();
format().endDataArray();
}
}
if (format_)
{
format().endTag(vtk::fileTag::LINES);
}
}
@ -131,27 +363,28 @@ void Foam::vtk::polyWriter::writePolysLegacy
)
{
// Connectivity count without additional storage (done internally)
const label nLocalConns = countConnectivity(faces);
label nFaces = nLocalFaces_;
label nVerts = nLocalVerts_;
label nPolys = nLocalPolys_;
label nConns = nLocalConns;
if (parallel_)
{
reduce(nFaces, sumOp<label>());
reduce(nVerts, sumOp<label>());
reduce(nPolys, sumOp<label>());
reduce(nConns, sumOp<label>());
}
if (nFaces != numberOfCells_)
if (nPolys != numberOfCells_)
{
FatalErrorInFunction
<< "Expecting " << numberOfCells_
<< " faces, but found " << nFaces
<< " faces, but found " << nPolys
<< exit(FatalError);
}
legacy::beginPolys(os_, nFaces, nVerts);
legacy::beginPolys(os_, nPolys, nConns);
labelList vertLabels(nLocalFaces_ + nLocalVerts_);
labelList vertLabels(nLocalPolys_ + nLocalConns);
{
// Legacy: size + connectivity together
@ -159,21 +392,18 @@ void Foam::vtk::polyWriter::writePolysLegacy
auto iter = vertLabels.begin();
label off = pointOffset;
const label off = pointOffset;
for (const face& f : faces)
{
for (const face& f : faces)
{
*iter = f.size(); // The size prefix
++iter;
*iter = f.size(); // The size prefix
++iter;
for (const label pfi : f)
{
*iter = pfi + off; // Face vertex label
++iter;
}
for (const label id : f)
{
*iter = id + off; // Vertex label
++iter;
}
// off += points.size();
}
}
@ -200,6 +430,9 @@ void Foam::vtk::polyWriter::writePolys
const label pointOffset
)
{
// Connectivity count without additional storage (done internally)
const label nLocalConns = countConnectivity(faces);
if (format_)
{
format().tag(vtk::fileTag::POLYS);
@ -209,18 +442,18 @@ void Foam::vtk::polyWriter::writePolys
// 'connectivity'
//
{
labelList vertLabels(nLocalVerts_);
labelList vertLabels(nLocalConns);
label nVerts = nLocalVerts_;
label nConns = nLocalConns;
if (parallel_)
{
reduce(nVerts, sumOp<label>());
reduce(nConns, sumOp<label>());
}
if (format_)
{
const uint64_t payLoad = vtk::sizeofData<label>(nVerts);
const uint64_t payLoad = vtk::sizeofData<label>(nConns);
format().beginDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY);
format().writeSize(payLoad * sizeof(label));
@ -234,16 +467,13 @@ void Foam::vtk::polyWriter::writePolys
label off = pointOffset;
for (const face& f : faces)
{
for (const face& f : faces)
for (const label id : f)
{
for (const label pfi : f)
{
*iter = pfi + off; // Face vertex label
++iter;
}
*iter = id + off; // Face vertex label
++iter;
}
// off += points.size();
}
}
@ -269,7 +499,7 @@ void Foam::vtk::polyWriter::writePolys
// 'offsets' (connectivity offsets)
//
{
labelList vertOffsets(nLocalFaces_);
labelList vertOffsets(nLocalPolys_);
label nOffs = vertOffsets.size();
if (parallel_)
@ -289,19 +519,17 @@ void Foam::vtk::polyWriter::writePolys
// processor-local connectivity offsets
label off =
(
parallel_ ? globalIndex(nLocalVerts_).localStart() : 0
parallel_ ? globalIndex(nLocalConns).localStart() : 0
);
auto iter = vertOffsets.begin();
for (const face& f : faces)
{
for (const face& f : faces)
{
off += f.size(); // End offset
*iter = off;
++iter;
}
off += f.size(); // End offset
*iter = off;
++iter;
}
@ -340,8 +568,8 @@ Foam::vtk::polyWriter::polyWriter
numberOfPoints_(0),
numberOfCells_(0),
nLocalPoints_(0),
nLocalFaces_(0),
nLocalVerts_(0)
nLocalLines_(0),
nLocalPolys_(0)
{
// We do not currently support append mode
opts_.append(false);
@ -387,6 +615,36 @@ bool Foam::vtk::polyWriter::writeGeometry()
}
bool Foam::vtk::polyWriter::writeLineGeometry
(
const pointField& points,
const edgeList& edges
)
{
enter_Piece();
beginPiece(points, edges);
writePoints(points);
const label pointOffset =
(
parallel_ ? globalIndex(nLocalPoints_).localStart() : 0
);
if (legacy())
{
writeLinesLegacy(edges, pointOffset);
}
else
{
writeLines(edges, pointOffset);
}
return true;
}
bool Foam::vtk::polyWriter::writePolyGeometry
(
const pointField& points,

View File

@ -51,6 +51,7 @@ SourceFiles
#include "foamVtkFileWriter.H"
#include "pointField.H"
#include "edgeList.H"
#include "faceList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -75,30 +76,53 @@ protected:
//- The number of field points for the current Piece
label numberOfPoints_;
//- The number of field cells (faces) for the current Piece
//- The number of field cells (edges or faces) for the current Piece
label numberOfCells_;
//- Local number of points
label nLocalPoints_;
//- Local number of faces
label nLocalFaces_;
//- Local number of lines (edges)
label nLocalLines_;
//- Local face vertices (connectivity) count. Sum of face sizes.
label nLocalVerts_;
//- Local number of polys (faces)
label nLocalPolys_;
// Protected Member Functions
//- Write a uniform field of Cell (Poly or Line) or Point values
template<class Type>
void writeUniformValue
(
const label nCellValues, // Could be Poly or Line!
const word& fieldName,
const Type& val
);
private:
// Private Member Functions
//- Determine sizes (nLocalPoints_, nLocalFaces_, nLocalVerts_),
//- Determine sizes (nLocalPoints_, nLocalLines_),
//- and begin piece
void beginPiece(const pointField& points, const edgeList& edges);
//- Determine sizes (nLocalPoints_, nLocalPolys_),
//- and begin piece
void beginPiece(const pointField& points, const faceList& faces);
//- Write points
void writePoints(const pointField& points);
//- Write lines, legacy format
// \param pointOffset processor-local point offset
void writeLinesLegacy(const edgeList& edges, const label pointOffset);
//- Write lines
// \param pointOffset processor-local point offset
void writeLines(const edgeList& edges, const label pointOffset);
//- Write faces, legacy format
// \param pointOffset processor-local point offset
void writePolysLegacy(const faceList& faces, const label pointOffset);
@ -163,6 +187,16 @@ public:
// their own geomety, but use writePolyGeometry() directly
virtual bool writeGeometry();
//- Low-level write edge/point topology.
//- Normally used by writeGeometry() in a derived class
// Also writes the file header if not previously written.
// \note Must be called prior to writing CellData or PointData
bool writeLineGeometry
(
const pointField& points,
const edgeList& edges
);
//- Low-level write face/point topology.
//- Normally used by writeGeometry() in a derived class
// Also writes the file header if not previously written.
@ -194,11 +228,7 @@ public:
// Write
//- Write a uniform field of Cell (Face) or Point values
template<class Type>
void writeUniform(const word& fieldName, const Type& val);
//- Write a list of Cell (Face) or Point values
//- Write a list of Cell (Poly or Line) or Point values
template<class Type>
void write(const word& fieldName, const UList<Type>& field);
};

View File

@ -25,24 +25,27 @@ License
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
void Foam::vtk::polyWriter::writeUniform
void Foam::vtk::polyWriter::writeUniformValue
(
const label nCellValues,
const word& fieldName,
const Type& val
)
{
label nValues(0);
if (isState(outputState::CELL_DATA))
{
++nCellData_;
vtk::fileWriter::writeUniform<Type>(fieldName, val, numberOfCells_);
nValues = nCellValues;
}
else if (isState(outputState::POINT_DATA))
{
++nPointData_;
vtk::fileWriter::writeUniform<Type>(fieldName, val, numberOfPoints_);
nValues = nLocalPoints_;
}
else
{
@ -54,10 +57,16 @@ void Foam::vtk::polyWriter::writeUniform
)
<< " for uniform field " << fieldName << nl << endl
<< exit(FatalError);
return;
}
vtk::fileWriter::writeUniform<Type>(fieldName, val, nValues);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
void Foam::vtk::polyWriter::write
(
@ -66,18 +75,18 @@ void Foam::vtk::polyWriter::write
)
{
// Could check sizes:
// nValues == nLocalFaces (CELL_DATA)
// nValues == nLocalPoints (POINT_DATA)
// CELL_DATA: nValues == (nLocalPolys | nLocalLines)
// POINT_DATA: nValues == nLocalPoints
// const label nValues = field.size();
if (isState(outputState::CELL_DATA))
{
++nCellData_;
vtk::fileWriter::writeBasicField<Type>(fieldName, field);
}
else if (isState(outputState::POINT_DATA))
{
++nPointData_;
vtk::fileWriter::writeBasicField<Type>(fieldName, field);
}
else
{
@ -89,7 +98,10 @@ void Foam::vtk::polyWriter::write
)
<< " for field " << fieldName << nl << endl
<< exit(FatalError);
return;
}
vtk::fileWriter::writeBasicField<Type>(fieldName, field);
}

View File

@ -88,7 +88,7 @@ bool Foam::vtk::surfaceWriter::beginFile(std::string title)
return vtk::fileWriter::beginFile(title);
}
if (instant_.name().size())
if (!instant_.name().empty())
{
return vtk::fileWriter::beginFile
(
@ -129,4 +129,10 @@ void Foam::vtk::surfaceWriter::piece
}
bool Foam::vtk::surfaceWriter::writeProcIDs()
{
return vtk::fileWriter::writeProcIDs(nLocalPolys_);
}
// ************************************************************************* //

View File

@ -42,7 +42,6 @@ Note
SourceFiles
foamVtkSurfaceWriter.C
foamVtkSurfaceWriterTemplates.C
\*---------------------------------------------------------------------------*/
@ -152,8 +151,20 @@ public:
//- Write the currently set time as "TimeValue" FieldData
void writeTimeValue();
//- Reset point, face references to begin a new piece
//- Reset point/face references to begin a new piece
void piece(const pointField& points, const faceList& faces);
//- Write processor ids for each poly as CellData
//- (no-op in serial)
bool writeProcIDs();
//- Write a uniform field of Cell (Poly) or Point values
template<class Type>
void writeUniform(const word& fieldName, const Type& val)
{
polyWriter::writeUniformValue<Type>(nLocalPolys_, fieldName, val);
}
};

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,50 +28,9 @@ License
#include "VTKedgeFormat.H"
#include "Fstream.H"
#include "clock.H"
#include "vtkUnstructuredReader.H"
#include "Time.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::fileFormats::VTKedgeFormat::writeHeader
(
Ostream& os,
const pointField& pointLst
)
{
// Write header
os << "# vtk DataFile Version 2.0" << nl
<< "featureEdgeMesh written " << clock::dateTime().c_str() << nl
<< "ASCII" << nl
<< nl
<< "DATASET POLYDATA" << nl;
// Write vertex coords
os << "POINTS " << pointLst.size() << " double" << nl;
for (const point& pt : pointLst)
{
os << float(pt.x()) << ' '
<< float(pt.y()) << ' '
<< float(pt.z()) << nl;
}
}
void Foam::fileFormats::VTKedgeFormat::writeEdges
(
Ostream& os,
const UList<edge>& edgeLst
)
{
os << "LINES " << edgeLst.size() << ' ' << 3*edgeLst.size() << nl;
for (const edge& e : edgeLst)
{
os << "2 " << e[0] << ' ' << e[1] << nl;
}
}
#include "foamVtkLineWriter.H"
#include "vtkUnstructuredReader.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -122,19 +81,21 @@ bool Foam::fileFormats::VTKedgeFormat::read
storedPoints().transfer(reader.points());
label nEdges = 0;
forAll(reader.lines(), lineI)
for (const auto& lineVerts : reader.lines())
{
nEdges += reader.lines()[lineI].size()-1;
if (lineVerts.size() > 1)
{
nEdges += (lineVerts.size()-1);
}
}
storedEdges().setSize(nEdges);
storedEdges().resize(nEdges);
nEdges = 0;
forAll(reader.lines(), lineI)
for (const auto& lineVerts : reader.lines())
{
const labelList& verts = reader.lines()[lineI];
for (label i = 1; i < verts.size(); i++)
for (label i = 1; i < lineVerts.size(); ++i)
{
storedEdges()[nEdges++] = edge(verts[i-1], verts[i]);
storedEdges()[nEdges++] = edge(lineVerts[i-1], lineVerts[i]);
}
}
@ -148,16 +109,20 @@ void Foam::fileFormats::VTKedgeFormat::write
const edgeMesh& eMesh
)
{
OFstream os(filename);
if (!os.good())
{
FatalErrorInFunction
<< "Cannot open file for writing " << filename
<< exit(FatalError);
}
// NB: restrict output to legacy ascii so that we are still able
// to read it with vtkUnstructuredReader
writeHeader(os, eMesh.points());
writeEdges(os, eMesh.edges());
vtk::lineWriter writer
(
eMesh.points(),
eMesh.edges(),
vtk::formatType::LEGACY_ASCII,
filename,
false // non-parallel write (edgeMesh already serialized)
);
writer.beginFile("OpenFOAM edgeMesh");
writer.writeGeometry();
}

View File

@ -54,37 +54,12 @@ class VTKedgeFormat
:
public edgeMesh
{
// Private Member Functions
//- No copy construct
VTKedgeFormat(const VTKedgeFormat&) = delete;
//- No copy assignment
void operator=(const VTKedgeFormat&) = delete;
protected:
// Protected Member Functions
//- Write header information with points
static void writeHeader
(
Ostream&,
const pointField&
);
//- Write edges
static void writeEdges(Ostream&, const UList<edge>&);
public:
// Constructors
//- Construct from file name
VTKedgeFormat(const fileName&);
//- Read construct from file name
explicit VTKedgeFormat(const fileName& filename);
// Selectors
@ -103,12 +78,12 @@ public:
// Member Functions
//- Write surface mesh components by proxy
static void write(const fileName&, const edgeMesh&);
static void write(const fileName& name, const edgeMesh&);
//- Read from file
virtual bool read(const fileName&);
virtual bool read(const fileName& name);
//- Write object file
//- Write object to file
virtual void write(const fileName& name) const
{
write(name, *this);

View File

@ -45,16 +45,24 @@ void Foam::vtk::internalMeshWriter::beginPiece()
if (parallel_)
{
if (debug > 1)
{
PoutInFunction
<< ": nPoints=" << numberOfPoints_
<< " nCells=" << numberOfCells_ << nl;
}
reduce(numberOfPoints_, sumOp<label>());
reduce(numberOfCells_, sumOp<label>());
}
DebugInFunction
<< "nPoints=" << numberOfPoints_
<< " nCells=" << numberOfCells_ << nl;
// Nothing else to do for legacy
if (legacy()) return;
DebugInFunction
<< "nPoints=" << numberOfPoints_ << " nCells=" << numberOfCells_ << nl;
if (format_)
{
format()
@ -178,7 +186,10 @@ void Foam::vtk::internalMeshWriter::writeCellsLegacy(const label pointOffset)
}
void Foam::vtk::internalMeshWriter::writeCellsConnectivity(const label pointOffset)
void Foam::vtk::internalMeshWriter::writeCellsConnectivity
(
const label pointOffset
)
{
//
// 'connectivity'
@ -316,7 +327,10 @@ void Foam::vtk::internalMeshWriter::writeCellsConnectivity(const label pointOffs
}
void Foam::vtk::internalMeshWriter::writeCellsFaces(const label pointOffset)
void Foam::vtk::internalMeshWriter::writeCellsFaces
(
const label pointOffset
)
{
label nFaceLabels = vtuCells_.faceLabels().size();
@ -628,39 +642,7 @@ bool Foam::vtk::internalMeshWriter::writeProcIDs()
return false;
}
if (isState(outputState::CELL_DATA))
{
++nCellData_;
}
else
{
reportBadState(FatalErrorInFunction, outputState::CELL_DATA)
<< " for procID field" << nl << endl
<< exit(FatalError);
}
const globalIndex procMaps(vtuCells_.nFieldCells());
this->beginDataArray<label>("procID", procMaps.size());
bool good = false;
if (Pstream::master())
{
// Per-processor ids
for (const int proci : Pstream::allProcs())
{
vtk::write(format(), label(proci), procMaps.localSize(proci));
}
good = true;
}
this->endDataArray();
// MPI barrier
return returnReduce(good, orOp<bool>());
return vtk::fileWriter::writeProcIDs(vtuCells_.nFieldCells());
}

View File

@ -225,6 +225,10 @@ public:
//- Write primitive field of CellData
template<class Type>
void writeCellData(const word& fieldName, const UList<Type>& field);
//- Write primitive field of PointData
template<class Type>
void writePointData(const word& fieldName, const UList<Type>& field);
};

View File

@ -37,15 +37,17 @@ void Foam::vtk::internalMeshWriter::writeUniform
const Type& val
)
{
label nValues(0);
if (isState(outputState::CELL_DATA))
{
++nCellData_;
vtk::fileWriter::writeUniform<Type>(fieldName, val, numberOfCells_);
nValues = vtuCells_.nFieldCells();
}
else if (isState(outputState::POINT_DATA))
{
++nPointData_;
vtk::fileWriter::writeUniform<Type>(fieldName, val, numberOfPoints_);
nValues = vtuCells_.nFieldPoints();
}
else
{
@ -54,9 +56,14 @@ void Foam::vtk::internalMeshWriter::writeUniform
FatalErrorInFunction,
outputState::CELL_DATA,
outputState::POINT_DATA
) << " for field " << fieldName << nl << endl
)
<< " for uniform field " << fieldName << nl << endl
<< exit(FatalError);
return;
}
vtk::fileWriter::writeUniform<Type>(fieldName, val, nValues);
}
@ -95,4 +102,37 @@ void Foam::vtk::internalMeshWriter::writeCellData
}
template<class Type>
void Foam::vtk::internalMeshWriter::writePointData
(
const word& fieldName,
const UList<Type>& field
)
{
if (isState(outputState::POINT_DATA))
{
++nPointData_;
}
else
{
reportBadState(FatalErrorInFunction, outputState::POINT_DATA)
<< " for field " << fieldName << nl << endl
<< exit(FatalError);
}
this->beginDataArray<Type>(fieldName, numberOfPoints_);
if (parallel_)
{
vtk::writeListParallel(format_.ref(), field);
}
else
{
vtk::writeList(format(), field);
}
this->endDataArray();
}
// ************************************************************************* //

View File

@ -38,14 +38,15 @@ void Foam::vtk::patchMeshWriter::beginPiece()
// Basic sizes
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
nLocalPoints_ = nLocalFaces_ = nLocalVerts_ = 0;
nLocalPoints_ = nLocalPolys_ = 0;
nLocalVerts_ = 0;
for (const label patchId : patchIDs_)
{
const polyPatch& pp = patches[patchId];
nLocalPoints_ += pp.nPoints();
nLocalFaces_ += pp.size();
nLocalPolys_ += pp.size();
for (const face& f : pp)
{
@ -54,7 +55,7 @@ void Foam::vtk::patchMeshWriter::beginPiece()
}
numberOfPoints_ = nLocalPoints_;
numberOfCells_ = nLocalFaces_;
numberOfCells_ = nLocalPolys_;
if (parallel_)
{
@ -148,26 +149,26 @@ void Foam::vtk::patchMeshWriter::writePolysLegacy(const label pointOffset)
// Connectivity count without additional storage (done internally)
label nFaces = nLocalFaces_;
label nPolys = nLocalPolys_;
label nVerts = nLocalVerts_;
if (parallel_)
{
reduce(nFaces, sumOp<label>());
reduce(nPolys, sumOp<label>());
reduce(nVerts, sumOp<label>());
}
if (nFaces != numberOfCells_)
if (nPolys != numberOfCells_)
{
FatalErrorInFunction
<< "Expecting " << numberOfCells_
<< " faces, but found " << nFaces
<< " faces, but found " << nPolys
<< exit(FatalError);
}
legacy::beginPolys(os_, nFaces, nVerts);
legacy::beginPolys(os_, nPolys, nVerts);
labelList vertLabels(nLocalFaces_ + nLocalVerts_);
labelList vertLabels(nLocalPolys_ + nLocalVerts_);
{
// Legacy: size + connectivity together
@ -186,9 +187,9 @@ void Foam::vtk::patchMeshWriter::writePolysLegacy(const label pointOffset)
*iter = f.size(); // The size prefix
++iter;
for (const label pfi : f)
for (const label id : f)
{
*iter = pfi + off; // Face vertex label
*iter = id + off; // Face vertex label
++iter;
}
}
@ -258,9 +259,9 @@ void Foam::vtk::patchMeshWriter::writePolys(const label pointOffset)
for (const face& f : pp.localFaces())
{
for (const label pfi : f)
for (const label id : f)
{
*iter = pfi + off; // Face vertex label
*iter = id + off; // Face vertex label
++iter;
}
}
@ -290,7 +291,7 @@ void Foam::vtk::patchMeshWriter::writePolys(const label pointOffset)
// 'offsets' (connectivity offsets)
//
{
labelList vertOffsets(nLocalFaces_);
labelList vertOffsets(nLocalPolys_);
label nOffs = vertOffsets.size();
if (parallel_)
@ -367,7 +368,7 @@ Foam::vtk::patchMeshWriter::patchMeshWriter
numberOfPoints_(0),
numberOfCells_(0),
nLocalPoints_(0),
nLocalFaces_(0),
nLocalPolys_(0),
nLocalVerts_(0),
mesh_(mesh),
@ -512,15 +513,15 @@ void Foam::vtk::patchMeshWriter::writePatchIDs()
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
label nFaces = nLocalFaces_;
label nPolys = nLocalPolys_;
if (parallel_)
{
reduce(nFaces, sumOp<label>());
reduce(nPolys, sumOp<label>());
}
this->beginDataArray<label>("patchID", nFaces);
this->beginDataArray<label>("patchID", nPolys);
if (parallel_ ? Pstream::master() : true)
{
@ -584,66 +585,7 @@ void Foam::vtk::patchMeshWriter::writePatchIDs()
bool Foam::vtk::patchMeshWriter::writeProcIDs()
{
// This is different than for internalWriter.
// Here we allow procIDs whenever running in parallel, even if the
// output is serial. This allow diagnosis of processor patches.
if (!Pstream::parRun())
{
// Skip in non-parallel
return false;
}
if (isState(outputState::CELL_DATA))
{
++nCellData_;
}
else
{
reportBadState(FatalErrorInFunction, outputState::CELL_DATA)
<< " for patchID field" << nl << endl
<< exit(FatalError);
}
label nFaces = nLocalFaces_;
if (parallel_)
{
reduce(nFaces, sumOp<label>());
}
this->beginDataArray<label>("procID", nFaces);
bool good = false;
if (parallel_)
{
globalIndex procSizes(nLocalFaces_);
if (Pstream::master())
{
// Per-processor ids
for (const int proci : Pstream::allProcs())
{
vtk::write(format(), label(proci), procSizes.localSize(proci));
}
good = true;
}
}
else
{
vtk::write(format(), label(Pstream::myProcNo()), nLocalFaces_);
good = true;
}
this->endDataArray();
// MPI barrier
return parallel_ ? returnReduce(good, orOp<bool>()) : good;
return vtk::fileWriter::writeProcIDs(nLocalPolys_);
}
@ -668,15 +610,15 @@ bool Foam::vtk::patchMeshWriter::writeNeighIDs()
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
label nFaces = nLocalFaces_;
label nPolys = nLocalPolys_;
if (parallel_)
{
reduce(nFaces, sumOp<label>());
reduce(nPolys, sumOp<label>());
}
this->beginDataArray<label>("neighID", nFaces);
this->beginDataArray<label>("neighID", nPolys);
bool good = false;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2019 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -82,8 +82,8 @@ protected:
//- Local number of points
label nLocalPoints_;
//- Local number of faces
label nLocalFaces_;
//- Local number of polys (faces)
label nLocalPolys_;
//- Local face vertices (connectivity) count. Sum of face sizes.
label nLocalVerts_;
@ -97,7 +97,7 @@ protected:
// Private Member Functions
//- Determine sizes (nLocalPoints_, nLocalFaces_, nLocalVerts_),
//- Determine sizes (nLocalPoints_, nLocalPolys_),
//- and begin piece.
void beginPiece();
@ -172,7 +172,7 @@ public:
}
//- The patch IDs
inline const labelList& patchIDs() const
const labelList& patchIDs() const noexcept
{
return patchIDs_;
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -37,23 +37,33 @@ void Foam::vtk::patchMeshWriter::writeUniform
const Type& val
)
{
label nValues(0);
if (isState(outputState::CELL_DATA))
{
++nCellData_;
vtk::fileWriter::writeUniform<Type>(fieldName, val, numberOfCells_);
nValues = nLocalPolys_;
}
else if (isState(outputState::POINT_DATA))
{
++nPointData_;
vtk::fileWriter::writeUniform<Type>(fieldName, val, numberOfPoints_);
nValues = nLocalPoints_;
}
else
{
WarningInFunction
<< "Ignore bad writer state (" << stateNames[state_]
<< ") for field " << fieldName << nl << endl
reportBadState
(
FatalErrorInFunction,
outputState::CELL_DATA,
outputState::POINT_DATA
)
<< " for uniform field " << fieldName << nl << endl
<< exit(FatalError);
return;
}
vtk::fileWriter::writeUniform<Type>(fieldName, val, nValues);
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd.
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -127,26 +127,6 @@ protected:
// Protected Member Functions
//- Check for tet values above/below given (iso) value
// Result encoded as a single integer
inline static constexpr int getTetCutIndex
(
const scalar a,
const scalar b,
const scalar c,
const scalar d,
const scalar isoval
) noexcept
{
return
(
(a < isoval ? 1 : 0)
| (b < isoval ? 2 : 0)
| (c < isoval ? 4 : 0)
| (d < isoval ? 8 : 0)
);
}
//- Count the number of cuts matching the mask type
// Checks as bitmask or as zero.
static label countCutType

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -52,10 +52,12 @@ const Foam::Enum
Foam::isoSurfaceParams::filterNames
({
{ filterType::NONE, "none" },
{ filterType::CELL, "cell" },
{ filterType::DIAGCELL, "diagcell" },
{ filterType::PARTIAL, "partial" },
{ filterType::FULL, "full" },
{ filterType::CLEAN, "clean" },
{ filterType::CELL, "cell" },
{ filterType::DIAGCELL, "diagcell" },
});
@ -137,6 +139,7 @@ Foam::isoSurfaceParams::isoSurfaceParams
:
algo_(algo),
filter_(filter),
snap_(true),
mergeTol_(1e-6),
clipBounds_(boundBox::invertedBox)
{}
@ -152,6 +155,7 @@ Foam::isoSurfaceParams::isoSurfaceParams
{
algo_ = getAlgorithmType(dict, algo_);
filter_ = getFilterType(dict, filter_);
snap_ = dict.getOrDefault("snap", true);
dict.readIfPresent("mergeTol", mergeTol_);
dict.readIfPresent("bounds", clipBounds_);
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -35,12 +35,22 @@ Description
isoMethod | Algorithm (cell/topo/point/default) | no | default
regularise | Face simplification (enum or bool) | no | true
mergeTol | Point merge tolerance (cell/point) | no | 1e-6
snap | Point snapping (topo) | no | true
bounds | Optional clip bounds | no | inverted
\endtable
The default algorithm denotes the use of the current \em standard
algorithm.
Filtering types (for topological iso-surface)
- \c none : leave tet cuts untouched
- \c partial , \c cell : Combine intra-cell faces
- \c full , \c diagcell : Perform \c partial and remove face-diagonal
points
- \c clean : Perform \c full and eliminate open edges as well.
(<b>May cause excessive erosion!</b>)
.
SourceFiles
isoSurfaceParams.C
@ -85,8 +95,12 @@ public:
NONE = 0, //!< No filtering
CELL, //!< Remove pyramid edge points
DIAGCELL, //!< Remove pyramid edge points, face-diagonals
NONMANIFOLD, //!< Remove pyramid edge points, face-diagonals
//!< and non-manifold faces
PARTIAL = CELL, //!< Same as CELL
FULL = DIAGCELL, //!< Same as DIAGCELL
CLEAN = NONMANIFOLD //!< Same as NONMANIFOLD
};
@ -100,6 +114,9 @@ private:
//- Filtering for iso-surface faces/points
filterType filter_;
//- Point snapping enabled
bool snap_;
//- Merge tolerance for cell/point (default: 1e-6)
scalar mergeTol_;
@ -186,6 +203,18 @@ public:
filter_ = fltr;
}
//- Get point snapping flag
bool snap() const noexcept
{
return snap_;
}
//- Set point snapping flag
void snap(bool on) noexcept
{
snap_ = on;
}
//- Get current merge tolerance
scalar mergeTol() const noexcept
{

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,7 @@ namespace Foam
{
// Forward Declarations
class cellShape;
class polyMesh;
/*---------------------------------------------------------------------------*\
@ -62,63 +63,103 @@ class isoSurfaceTopo
{
// Private Data
//- Corrected version of tetBasePtIs
labelList tetBasePtIs_;
//- Per point: originating mesh vertex/cc. See encoding above
//- Per point: originating mesh vertex/cell centre combination.
// Vertices less than nPoints are mesh vertices,
// duplicate vertices indicate a snapped point
edgeList pointToVerts_;
//- For every point the originating face in mesh
labelList pointToFace_;
//- The cell cut type
List<cutType> cellCutType_;
// Private Classes
//- Handling, bookkeeping for tet cuts
class tetCutAddressing
{
// Bookkeeping hashes used during construction
EdgeMap<label> vertsToPointLookup_;
Map<label> snapVertsLookup_;
// Filter information for face diagonals
DynamicList<label> pointToFace_;
DynamicList<bool> pointFromDiag_;
// Final output
DynamicList<edge> pointToVerts_;
DynamicList<label> cutPoints_;
//- List of cut (decomposed) cell tets. Debug use only.
DynamicList<cellShape> debugCutTets_;
bool debugCutTetsOn_;
public:
// Constructors
//- Construct with reserved sizes
tetCutAddressing
(
const label nCutCells,
const bool useSnap,
const bool useDebugCuts = false
);
// Member Functions
//- Effective number of faces
label nFaces() const { return cutPoints_.size()/3; }
DynamicList<label>& pointToFace() { return pointToFace_; }
DynamicList<bool>& pointFromDiag() { return pointFromDiag_; }
DynamicList<edge>& pointToVerts() { return pointToVerts_; }
DynamicList<label>& cutPoints() { return cutPoints_; }
DynamicList<cellShape>& debugCutTets() { return debugCutTets_; }
//- Number of debug cut tets
label nDebugTets() const { return debugCutTets_.size(); }
//- Debugging cut tets active
bool debugCutTetsOn() const { return debugCutTetsOn_; }
void clearDebug();
void clearDiagonal();
void clearHashes();
//- Generate single point on edge
label generatePoint
(
label facei, //!< Originating mesh face for cut-point
bool edgeIsDiagonal, //!< Edge on face diagonal
// 0: no snap, 1: snap first, 2: snap second
const int snapEnd,
const edge& vertices
);
//- Generate triangles from tet cut
bool generatePoints
(
const label facei,
const int tetCutIndex, //!< Encoded tet cut + tet snapping
const tetCell& tetLabels,
const FixedList<bool, 6>& edgeIsDiagonal
);
};
// Private Member Functions
//- Generate single point on edge
label generatePoint
(
const label facei,
const bool edgeIsDiag,
const edge& vertices,
DynamicList<edge>& pointToVerts,
DynamicList<label>& pointToFace,
DynamicList<bool>& pointFromDiag,
EdgeMap<label>& vertsToPoint
) const;
//- Generate triangles from tet
void generateTriPoints
(
const label facei,
const int tetCutIndex, //!< Encoded tet cuts. getTetCutIndex()
const tetCell& tetLabels,
const FixedList<bool, 6>& edgeIsDiag,
DynamicList<edge>& pointToVerts,
DynamicList<label>& pointToFace,
DynamicList<bool>& pointFromDiag,
EdgeMap<label>& vertsToPoint,
DynamicList<label>& verts
) const;
//- Generate triangles from cell
//- Generate triangle points from cell
void generateTriPoints
(
const label celli,
const bool isTet,
const labelList& tetBasePtIs,
DynamicList<edge>& pointToVerts,
DynamicList<label>& pointToFace,
DynamicList<bool>& pointFromDiag,
EdgeMap<label>& vertsToPoint,
DynamicList<label>& verts,
DynamicList<label>& faceLabels
tetCutAddressing& tetCutAddr
) const;
@ -165,12 +206,12 @@ protected:
// Sampling
//- Interpolates cCoords,pCoords.
//- Interpolates cellData and pointData fields
template<class Type>
tmp<Field<Type>> interpolateTemplate
(
const Field<Type>& cCoords,
const Field<Type>& pCoords
const Field<Type>& cellData,
const Field<Type>& pointData
) const;
public:
@ -205,14 +246,10 @@ public:
// Member Functions
//- For every point originating face (pyramid) in mesh
const labelList& pointToFace() const
{
return pointToFace_;
}
//- Per point: originating mesh vertex/cc. See encoding above
const edgeList& pointToVerts() const
//- Per point: originating mesh vertex/cell centre combination.
// Vertices less than nPoints are mesh vertices (encoding above),
// duplicate vertices indicate a snapped point
const edgeList& pointToVerts() const noexcept
{
return pointToVerts_;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2018 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -32,8 +32,8 @@ template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::isoSurfaceTopo::interpolateTemplate
(
const Field<Type>& cellCoords,
const Field<Type>& pointCoords
const Field<Type>& cellData,
const Field<Type>& pointData
) const
{
auto tfld = tmp<Field<Type>>::New(pointToVerts_.size());
@ -41,41 +41,50 @@ Foam::isoSurfaceTopo::interpolateTemplate
forAll(pointToVerts_, i)
{
const edge& verts = pointToVerts_[i];
Type& val = fld[i];
scalar s0;
Type p0;
Type v0;
{
label idx = pointToVerts_[i].first();
label idx = verts.first();
if (idx < mesh_.nPoints())
{
// Point index
s0 = pVals_[idx];
p0 = pointCoords[idx];
v0 = pointData[idx];
}
else
{
// Cell index
idx -= mesh_.nPoints();
s0 = cVals_[idx];
p0 = cellCoords[idx];
v0 = cellData[idx];
}
}
scalar s1;
Type p1;
Type v1;
{
label idx = pointToVerts_[i].second();
if (idx < mesh_.nPoints())
label idx = verts.second();
if (idx == verts.first())
{
// Duplicate index (ie, snapped)
val = v0;
continue;
}
else if (idx < mesh_.nPoints())
{
// Point index
s1 = pVals_[idx];
p1 = pointCoords[idx];
v1 = pointData[idx];
}
else
{
// Cell index
idx -= mesh_.nPoints();
s1 = cVals_[idx];
p1 = cellCoords[idx];
v1 = cellData[idx];
}
}
@ -83,11 +92,11 @@ Foam::isoSurfaceTopo::interpolateTemplate
if (mag(d) > VSMALL)
{
const scalar s = (iso_-s0)/d;
fld[i] = s*p1+(1.0-s)*p0;
val = s*v1+(1.0-s)*v0;
}
else
{
fld[i] = 0.5*(p0+p1);
val = 0.5*(v0+v1);
}
}