diff --git a/applications/test/foamCellZoneToVTK/Make/files b/applications/test/foamCellZoneToVTK/Make/files new file mode 100644 index 0000000000..a4be1f0e87 --- /dev/null +++ b/applications/test/foamCellZoneToVTK/Make/files @@ -0,0 +1,3 @@ +foamCellZoneToVTK.C + +EXE = $(FOAM_USER_APPBIN)/foamCellZoneToVTK diff --git a/applications/test/foamCellZoneToVTK/Make/options b/applications/test/foamCellZoneToVTK/Make/options new file mode 100644 index 0000000000..d820876f44 --- /dev/null +++ b/applications/test/foamCellZoneToVTK/Make/options @@ -0,0 +1,7 @@ +EXE_INC = \ + -I$(LIB_SRC)/fileFormats/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude + +EXE_LIBS = \ + -lfileFormats \ + -lmeshTools diff --git a/applications/test/foamCellZoneToVTK/foamCellZoneToVTK.C b/applications/test/foamCellZoneToVTK/foamCellZoneToVTK.C new file mode 100644 index 0000000000..a2f265db03 --- /dev/null +++ b/applications/test/foamCellZoneToVTK/foamCellZoneToVTK.C @@ -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 . + +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; +} + + +// ************************************************************************* // diff --git a/applications/test/foamMeshToTet-vtk/Make/files b/applications/test/foamMeshToTet-vtk/Make/files new file mode 100644 index 0000000000..576d08e8c1 --- /dev/null +++ b/applications/test/foamMeshToTet-vtk/Make/files @@ -0,0 +1,4 @@ +foamMeshToTet-vtk.C +writeVTKtetMesh.C + +EXE = $(FOAM_USER_APPBIN)/foamMeshToTet-vtk diff --git a/applications/test/foamMeshToTet-vtk/Make/options b/applications/test/foamMeshToTet-vtk/Make/options new file mode 100644 index 0000000000..d820876f44 --- /dev/null +++ b/applications/test/foamMeshToTet-vtk/Make/options @@ -0,0 +1,7 @@ +EXE_INC = \ + -I$(LIB_SRC)/fileFormats/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude + +EXE_LIBS = \ + -lfileFormats \ + -lmeshTools diff --git a/applications/test/foamMeshToTet-vtk/foamMeshToTet-vtk.C b/applications/test/foamMeshToTet-vtk/foamMeshToTet-vtk.C new file mode 100644 index 0000000000..d1d078949e --- /dev/null +++ b/applications/test/foamMeshToTet-vtk/foamMeshToTet-vtk.C @@ -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 . + +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; +} + + +// ************************************************************************* // diff --git a/applications/test/foamMeshToTet-vtk/writeVTKtetMesh.C b/applications/test/foamMeshToTet-vtk/writeVTKtetMesh.C new file mode 100644 index 0000000000..ea7157fac0 --- /dev/null +++ b/applications/test/foamMeshToTet-vtk/writeVTKtetMesh.C @@ -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 . + +\*---------------------------------------------------------------------------*/ + +#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 + + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/convertVolumeFields.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/convertVolumeFields.H index c98ba86456..add182f7ec 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToVTK/convertVolumeFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/convertVolumeFields.H @@ -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(); } } } diff --git a/src/conversion/vtk/output/foamVtkPatchWriterTemplates.C b/src/conversion/vtk/output/foamVtkPatchWriterTemplates.C index 9dc41948e4..0219a3b835 100644 --- a/src/conversion/vtk/output/foamVtkPatchWriterTemplates.C +++ b/src/conversion/vtk/output/foamVtkPatchWriterTemplates.C @@ -149,7 +149,7 @@ void Foam::vtk::patchWriter::write << exit(FatalError); } - label nFaces = nLocalFaces_; + label nFaces = nLocalPolys_; if (parallel_) { diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files index 2686cefc43..f7fd57b853 100644 --- a/src/fileFormats/Make/files +++ b/src/fileFormats/Make/files @@ -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 diff --git a/src/fileFormats/vtk/base/foamVtkCore.C b/src/fileFormats/vtk/base/foamVtkCore.C index 14f832fec6..b9488e8824 100644 --- a/src/fileFormats/vtk/base/foamVtkCore.C +++ b/src/fileFormats/vtk/base/foamVtkCore.C @@ -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" }, +}); + + // ************************************************************************* // diff --git a/src/fileFormats/vtk/base/foamVtkCore.H b/src/fileFormats/vtk/base/foamVtkCore.H index 2524964a0a..08615850ec 100644 --- a/src/fileFormats/vtk/base/foamVtkCore.H +++ b/src/fileFormats/vtk/base/foamVtkCore.H @@ -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 contentNames; - //- Legacy data type names (CELL_DATA, POINT_DATA) - extern const Foam::Enum dataTypeNames; + //- Legacy file tags (eg, LINES, CELL_DATA, POINT_DATA, ...) + extern const Foam::Enum fileTagNames; + + //- Legacy attributes (eg, OFFSETS) + extern const Foam::Enum dataArrayAttrNames; + } // End namespace legacy diff --git a/src/fileFormats/vtk/file/foamVtkFileWriter.C b/src/fileFormats/vtk/file/foamVtkFileWriter.C index aff45b9017..3cc8b7e72a 100644 --- a/src/fileFormats/vtk/file/foamVtkFileWriter.C +++ b/src/fileFormats/vtk/file/foamVtkFileWriter.C @@ -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