From cc51190a725c7a5abc87fced50e5562ca2178048 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 28 Jan 2020 19:42:51 +0100 Subject: [PATCH] ENH: revise ensight handling (#1579) - simplify internals of low-level ensight part handling and refactor the backend output routines for more reuse. There is still a fair bit of residual ugliness in the details of handling ensight output. - added cellZone support for ensightMesh - the ensightOutputSurface class is a lightweight wrapper for point/face references that is tailored for the ensightSurfaceWriter. It is uses compact face and point information and is serial only, since this is the format resulting from the surfaceWriter class. * foamToEnsight: - added cellZone support, which was previously only available using foamToEnsightParts. Will seek to deprecate and remove foamToEnsightParts in the future. - now also converts point fields --- .../foamToEnsight/convertVolumeFields.H | 9 + .../foamToEnsight/foamToEnsight.C | 68 +- .../dataConversion/foamToEnsight/readFields.H | 15 + .../foamToEnsight/writePointFields.H | 149 ++++ .../foamToEnsight/writeVolFields.H | 2 +- .../foamToEnsightParts/foamToEnsightParts.C | 2 +- .../foamToEnsightParts/writeVolFields.H | 5 +- src/conversion/ensight/mesh/ensightMesh.C | 516 ++++++++---- src/conversion/ensight/mesh/ensightMesh.H | 340 +++----- src/conversion/ensight/mesh/ensightMeshI.H | 37 +- src/conversion/ensight/mesh/ensightMeshIO.C | 747 +++--------------- .../ensight/mesh/ensightMeshOptions.C | 212 ++++- .../ensight/output/ensightOutputVolField.H | 40 +- .../output/ensightOutputVolFieldTemplates.C | 250 +++--- src/fileFormats/Make/files | 8 + src/fileFormats/ensight/file/ensightCase.C | 49 +- src/fileFormats/ensight/file/ensightCase.H | 90 ++- .../ensight/file/ensightCaseOptions.C | 10 +- .../ensight/file/ensightCaseTemplates.C | 21 +- .../ensight/output/ensightOutput.C | 490 ++++++++++++ .../ensight/output/ensightOutput.H | 240 +++++- .../ensight/output/ensightOutputTemplates.C | 371 +++++---- src/fileFormats/ensight/part/ensightCells.C | 155 ++-- src/fileFormats/ensight/part/ensightCells.H | 142 ++-- .../ensight/part/ensightCellsAddr.C | 64 ++ src/fileFormats/ensight/part/ensightCellsI.H | 59 +- src/fileFormats/ensight/part/ensightFaces.C | 241 +++--- src/fileFormats/ensight/part/ensightFaces.H | 150 ++-- src/fileFormats/ensight/part/ensightFacesI.H | 64 +- .../ensight/part/ensightOutputSurface.C | 92 +++ .../ensight/part/ensightOutputSurface.H | 114 +++ src/fileFormats/ensight/part/ensightPart.C | 62 +- src/fileFormats/ensight/part/ensightPart.H | 175 ++-- .../ensight/part/ensightPartCells.C | 286 +------ .../ensight/part/ensightPartCells.H | 91 ++- .../ensight/part/ensightPartCellsAddr.C | 113 +++ .../ensight/part/ensightPartCellsIO.C | 152 ++++ .../ensight/part/ensightPartFaces.C | 255 +----- .../ensight/part/ensightPartFaces.H | 116 +-- .../ensight/part/ensightPartFacesAddr.C | 110 +++ .../ensight/part/ensightPartFacesIO.C | 120 +++ src/fileFormats/ensight/part/ensightParts.C | 61 +- src/fileFormats/ensight/part/ensightParts.H | 27 +- .../ensightWrite/ensightWriteTemplates.C | 4 +- .../writers/ensight/ensightSurfaceWriter.C | 2 +- .../ensight/ensightSurfaceWriterCollated.C | 23 +- .../ensight/ensightSurfaceWriterUncollated.C | 29 +- 47 files changed, 3794 insertions(+), 2584 deletions(-) create mode 100644 applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H create mode 100644 src/fileFormats/ensight/output/ensightOutput.C create mode 100644 src/fileFormats/ensight/part/ensightCellsAddr.C create mode 100644 src/fileFormats/ensight/part/ensightOutputSurface.C create mode 100644 src/fileFormats/ensight/part/ensightOutputSurface.H create mode 100644 src/fileFormats/ensight/part/ensightPartCellsAddr.C create mode 100644 src/fileFormats/ensight/part/ensightPartCellsIO.C create mode 100644 src/fileFormats/ensight/part/ensightPartFacesAddr.C create mode 100644 src/fileFormats/ensight/part/ensightPartFacesIO.C diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H index f2d775a8042..439b2dc4373 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H @@ -39,6 +39,15 @@ Description writeAllDimFields(ensCase, ensMesh, objects); Info<< " )" << nl; + + // PointData + // - only construct pointMesh on request (it constructs edge addressing) + if (!noPointValues) + { + Info<< "Write point field ("; + writeAllPointFields(ensCase, ensMesh, objects); + Info<< " )" << nl; + } } diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C index 552b0b62a85..b98acb7072b 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C @@ -110,6 +110,7 @@ Note #include "readFields.H" #include "writeVolFields.H" #include "writeDimFields.H" +#include "writePointFields.H" #include "memInfo.H" @@ -155,12 +156,29 @@ int main(int argc, char *argv[]) "Suppress writing the internal mesh" ); argList::addBoolOption + ( + "no-cellZones", + "Suppress writing any cellZones" + ); + argList::addBoolOption ( "no-lagrangian", // noLagrangian "Suppress writing lagrangian positions and fields" ); argList::addOptionCompat("no-lagrangian", {"noLagrangian", 1806}); + argList::addBoolOption + ( + "no-point-data", + "Suppress conversion of pointFields. No interpolated PointData." + ); + + // argList::addBoolOption + // ( + // "one-boundary", // allPatches + // "Combine all patches into a single part" + // ); + argList::addOption ( "patches", @@ -169,6 +187,14 @@ int main(int argc, char *argv[]) "Eg, 'inlet' or '(outlet \"inlet.*\")'" ); argList::addOption + ( + "excludePatches", + "wordRes", + "Specify single patch or multiple patches to exclude from writing." + " Eg, 'outlet' or '( inlet \".*Wall\" )'", + true // mark as an advanced option + ); + argList::addOption ( "faceZones", "wordRes", @@ -182,7 +208,6 @@ int main(int argc, char *argv[]) "Specify single or multiple fields to write (all by default)\n" "Eg, 'T' or '( \"U.*\" )'" ); -#if 0 argList::addOption ( "cellZones", @@ -192,9 +217,6 @@ int main(int argc, char *argv[]) true // mark as an advanced option ); argList::addOptionCompat("cellZone", {"cellZones", 1912}); -#else - argList::ignoreOptionCompat({"cellZones", 1912}, true); // has argument -#endif argList::addOption ( @@ -264,16 +286,31 @@ int main(int argc, char *argv[]) ensightMesh::options writeOpts(format); writeOpts.useBoundaryMesh(!args.found("no-boundary")); writeOpts.useInternalMesh(!args.found("no-internal")); + writeOpts.useCellZones(!args.found("no-cellZones")); const bool doLagrangian = !args.found("no-lagrangian"); + const bool noPointValues = args.found("no-point-data"); if (args.found("patches")) { writeOpts.patchSelection(args.getList<wordRe>("patches")); } + if (args.found("excludePatches")) + { + writeOpts.patchExclude(args.getList<wordRe>("excludePatches")); + } + if (args.found("faceZones")) { writeOpts.faceZoneSelection(args.getList<wordRe>("faceZones")); } + if (args.found("cellZones")) + { + writeOpts.cellZoneSelection(args.getList<wordRe>("cellZones")); + } + + // Report the setup + writeOpts.print(Info); + // // Output configuration (field related) @@ -320,17 +357,18 @@ int main(int argc, char *argv[]) // Remove "*_0" restart fields objects.prune_0(); - // Only retain volume and dimensioned fields. - objects.filterClasses - ( - [](const word& clsName){ - return - ( - fieldTypes::volume.found(clsName) - || fieldTypes::internal.found(clsName) - ); - } - ); + if (noPointValues) + { + // Prune point fields unless specifically requested + objects.filterClasses + ( + [](const word& clsName) + { + return fieldTypes::point.found(clsName); + }, + true // prune + ); + } wordList objectNames(objects.sortedNames()); diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H index 3d79fa6b467..19e1922a16d 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H @@ -64,6 +64,21 @@ tmp<GeoField> getField } +//- Get the named field from the objects, or return nullptr. +template<class GeoField> +tmp<GeoField> getField +( + const typename GeoField::Mesh& mesh, + const IOobjectList& objects, + const word& fieldName +) +{ + // Can do something with syncPar on failure ... + + return getField<GeoField>(objects.findObject(fieldName), mesh); +} + + //- Get internal field and make it a zero-gradient volume field template<class GeoField> tmp<GeoField> diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H new file mode 100644 index 00000000000..823f94b9f63 --- /dev/null +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H @@ -0,0 +1,149 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2018 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/>. + +InNamespace + Foam + +Description + Read point fields from disk + and write with vtk::internalWriter and vtk::patchWriter + +SourceFiles + writePointFields.H + +\*---------------------------------------------------------------------------*/ + +#ifndef ensight_writePointFields_H +#define ensight_writePointFields_H + +#include "readFields.H" +#include "fvMesh.H" +// #include "foamVtkInternalWriter.H" +// #include "foamVtkPatchWriter.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +template<class Type> +bool writePointField +( + ensightCase& ensCase, + const ensightMesh& ensMesh, + const tmp<GeometricField<Type, pointPatchField, pointMesh>>& tfield +) +{ + if (!tfield.valid()) + { + return false; + } + + const auto& field = tfield(); + + // PointData = true + autoPtr<ensightFile> os = ensCase.newData<Type>(field.name(), true); + + bool wrote = ensightOutput::Detail::writePointField<Type> + ( + os.ref(), + field, + ensMesh + ); + + tfield.clear(); + return wrote; +} + + +template<class Type> +label writePointFields +( + ensightCase& ensCase, + const ensightMesh& ensMesh, + const IOobjectList& objects +) +{ + typedef GeometricField<Type, pointPatchField, pointMesh> GeoField; + + const pointMesh& ptMesh = pointMesh::New(ensMesh.mesh()); + + label count = 0; + + for (const word& fieldName : objects.sortedNames<GeoField>()) + { + if + ( + writePointField<Type> + ( + ensCase, + ensMesh, + getField<GeoField>(ptMesh, objects, fieldName) + ) + ) + { + Info<< ' ' << fieldName; + ++count; + } + } + + return count; +} + + +label writeAllPointFields +( + ensightCase& ensCase, + const ensightMesh& ensMesh, + const IOobjectList& objects +) +{ + #undef foamToEnsight_WRITE_FIELD + #define foamToEnsight_WRITE_FIELD(PrimitiveType) \ + writePointFields<PrimitiveType> \ + ( \ + ensCase, \ + ensMesh, \ + objects \ + ) + + label count = 0; + count += foamToEnsight_WRITE_FIELD(scalar); + count += foamToEnsight_WRITE_FIELD(vector); + count += foamToEnsight_WRITE_FIELD(sphericalTensor); + count += foamToEnsight_WRITE_FIELD(symmTensor); + count += foamToEnsight_WRITE_FIELD(tensor); + + #undef foamToEnsight_WRITE_FIELD + return count; +} + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H index a5da0ea9da7..9678f0d3eab 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H @@ -67,9 +67,9 @@ bool writeVolField bool wrote = ensightOutput::writeVolField<Type> ( + os.ref(), field, ensMesh, - os.ref(), nodeValues ); diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C index 9903495d42d..b5a19124f1b 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C @@ -260,7 +260,7 @@ int main(int argc, char *argv[]) info << "// Summary of ensight parts" << nl << nl; - ensParts.writeSummary(info); + ensParts.writeDict(info); } #include "checkMeshMoving.H" diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/writeVolFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/writeVolFields.H index 166408fed45..e886e16a5fb 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/writeVolFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/writeVolFields.H @@ -66,9 +66,10 @@ bool writeVolField // Currently serial only bool wrote = ensightOutput::Serial::writeVolField<Type> ( + os.ref(), field, - ensParts, - os.ref() + ensParts + // serial ); tfield.clear(); diff --git a/src/conversion/ensight/mesh/ensightMesh.C b/src/conversion/ensight/mesh/ensightMesh.C index 0b9dd7a4c2f..aee2f36934b 100644 --- a/src/conversion/ensight/mesh/ensightMesh.C +++ b/src/conversion/ensight/mesh/ensightMesh.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -33,21 +33,114 @@ License #include "emptyPolyPatch.H" #include "processorPolyPatch.H" #include "mapDistribute.H" -#include "stringListOps.H" #include "ensightFile.H" #include "ensightGeoFile.H" -#include "demandDrivenData.H" +#include "ensightOutput.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +const Foam::label Foam::ensightMesh::internalZone = -1; + + +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Find matching ids based on whitelist, blacklist +// +// An empty whitelist accepts everything that is not blacklisted. +// A regex match is trumped by a literal match. +// +// Eg, +// input: ( abc apple wall wall1 wall2 ) +// whitelist: ( abc def "wall.*" ) +// blacklist: ( "[ab].*" wall ) +// +// result: (abc wall1 wall2) +// +static labelList getSelected +( + const UList<word>& input, + const wordRes& whitelist, + const wordRes& blacklist +) +{ + const label len = input.size(); + + if (whitelist.empty() && blacklist.empty()) + { + return identity(len); + } + + labelList indices(len); + + label count = 0; + for (label i=0; i < len; ++i) + { + const auto& text = input[i]; + + bool accept = false; + + if (whitelist.size()) + { + const auto result = whitelist.matched(text); + + accept = + ( + result == wordRe::LITERAL + ? true + : (result == wordRe::REGEX && !blacklist.match(text)) + ); + } + else + { + accept = !blacklist.match(text); + } + + if (accept) + { + indices[count] = i; + ++count; + } + } + indices.resize(count); + + return indices; +} + +} // End namespace Foam + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::ensightMesh::clear() { - meshCells_.clear(); - boundaryPatchFaces_.clear(); - faceZoneFaces_.clear(); - patchLookup_.clear(); - globalPointsPtr_.clear(); + cellZoneParts_.clear(); + faceZoneParts_.clear(); + boundaryParts_.clear(); +} + + +void Foam::ensightMesh::renumber() +{ + label partNo = 0; + + for (const label zoneId : cellZoneParts_.sortedToc()) + { + cellZoneParts_[zoneId].index() = partNo++; + } + + for (const label patchId : boundaryParts_.sortedToc()) + { + boundaryParts_[patchId].index() = partNo++; + } + + for (const label zoneId : faceZoneParts_.sortedToc()) + { + faceZoneParts_[zoneId].index() = partNo++; + } } @@ -72,7 +165,7 @@ Foam::ensightMesh::ensightMesh Foam::ensightMesh::ensightMesh(const fvMesh& mesh) : - ensightMesh(mesh, IOstream::streamFormat::BINARY) + ensightMesh(mesh, ensightMesh::options(IOstream::streamFormat::BINARY)) {} @@ -82,23 +175,8 @@ Foam::ensightMesh::ensightMesh const IOstream::streamFormat format ) : - options_(new options(format)), - mesh_(mesh), - needsUpdate_(true) -{ - if (!option().lazy()) - { - correct(); - } -} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::ensightMesh::~ensightMesh() -{ - deleteDemandDrivenData(options_); -} + ensightMesh(mesh, ensightMesh::options(format)) +{} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // @@ -128,25 +206,103 @@ void Foam::ensightMesh::correct() { clear(); - // Part number - label nParts = 0; + // Track which cells are in a zone or not + bitSet cellSelection; + + // Boundary faces to be excluded from export + bitSet excludeFace; + - if (useInternalMesh()) + // All or specified cellZones first + const wordRes& czMatcher = option().cellZoneSelection(); + + if + ( + option().useCellZones() + && (option().useInternalMesh() || !czMatcher.empty()) + ) { - meshCells_.index() = nParts++; - meshCells_.classify(mesh_); + const wordList zoneNames(mesh_.cellZones().names()); - // Determine parallel shared points - globalPointsPtr_ = mesh_.globalData().mergePoints + const labelList zoneIds = ( - pointToGlobal_, - uniquePointMap_ + czMatcher.empty() + ? identity(zoneNames.size()) // Use all + : czMatcher.matching(zoneNames) // Use selected names ); + + for (const label zoneId : zoneIds) + { + const word& zoneName = zoneNames[zoneId]; + const cellZone& zn = mesh_.cellZones()[zoneId]; + + if (returnReduce(!zn.empty(), orOp<bool>())) + { + cellSelection.set(zn); + + ensightCells& part = cellZoneParts_(zoneId); + + part.clear(); + part.identifier() = zoneId; + part.rename(zoneName); + + part.classify(mesh_, zn); + + // Finalize + part.reduce(); + } + } + } + + if (option().useInternalMesh()) + { + // The internal mesh + + if (!cellZoneParts_.empty()) + { + // The unzoned cells - flip selection from zoned to unzoned + cellSelection.flip(); + + if (returnReduce(cellSelection.any(), orOp<bool>())) + { + ensightCells& part = cellZoneParts_(internalZone); + + part.clear(); + part.identifier() = internalZone; + part.rename("internalMesh"); + + part.classify(mesh_, cellSelection); + + // Finalize + part.reduce(); + } + + // Handled all cells + cellSelection.clearStorage(); + } + else if (czMatcher.empty()) + { + // The entire mesh, but only if there were no zones. + // Skip this is any zones were specified, regardless of their existence + + ensightCells& part = cellZoneParts_(internalZone); + + part.clear(); + part.identifier() = internalZone; + part.rename("internalMesh"); + + part.classify(mesh_); + + // Finalize + part.reduce(); + + // Handled all cells + cellSelection.clearStorage(); + } } - meshCells_.reduce(); - if (useBoundaryMesh()) + if (option().useBoundaryMesh()) { // Patches are output. Check that they are synced. mesh_.boundaryMesh().checkParallelSync(true); @@ -158,13 +314,14 @@ void Foam::ensightMesh::correct() patchNames.resize(mesh_.boundaryMesh().nNonProcessor()); } - const wordRes& matcher = option().patchSelection(); - - const labelList patchIds = + const labelList patchIds ( - matcher.empty() - ? identity(patchNames.size()) // Use all - : findStrings(matcher, patchNames) // Use specified names + getSelected + ( + patchNames, + option().patchSelection(), + option().patchExclude() + ) ); for (const label patchId : patchIds) @@ -174,100 +331,105 @@ void Foam::ensightMesh::correct() // Use fvPatch (not polyPatch) to automatically remove empty patches const fvPatch& p = mesh_.boundary()[patchId]; - ensightFaces& ensFaces = boundaryPatchFaces_(patchName); - ensFaces.clear(); + ensightFaces& part = boundaryParts_(patchId); + + part.clear(); + part.identifier() = patchId; + part.rename(patchName); if (p.size()) { // Local face addressing (offset = 0), // - this is what we'll need later when writing fields - ensFaces.classify(p.patch()); + part.classify(p.patch()); } else { // The patch is empty (on this processor) // or the patch is 'empty' (as fvPatch type) - ensFaces.clear(); + part.clear(); } // Finalize - ensFaces.reduce(); + part.reduce(); - if (ensFaces.total()) + if (!part.total()) { - patchLookup_.set(patchId, patchName); - ensFaces.index() = nParts++; - } - else - { - boundaryPatchFaces_.erase(patchName); + boundaryParts_.erase(patchId); } } - - // At this point, - // * patchLookup_ is a map of (patchId, name) - // * boundaryPatchFaces_ is a lookup by name for the faces elements } if (option().useFaceZones()) { - // Mark boundary faces to be excluded from export - bitSet excludeFace(mesh_.nFaces()); + const wordRes& fzMatcher = option().faceZoneSelection(); + + const wordList zoneNames(mesh_.faceZones().names()); + + const labelList zoneIds = + ( + fzMatcher.empty() + ? identity(zoneNames.size()) // Use all + : fzMatcher.matching(zoneNames) // Use selected names + ); + - for (const polyPatch& pp : mesh_.boundaryMesh()) + if (zoneIds.size()) { - const auto* procPatch = isA<processorPolyPatch>(pp); + excludeFace.resize(mesh_.nFaces()); - if (isA<emptyPolyPatch>(pp)) - { - excludeFace.set(pp.range()); - } - else if (procPatch && !procPatch->owner()) + for (const polyPatch& pp : mesh_.boundaryMesh()) { - // Exclude neighbour-side, retain owner-side only - excludeFace.set(pp.range()); + const auto* procPatch = isA<processorPolyPatch>(pp); + + if (isA<emptyPolyPatch>(pp)) + { + excludeFace.set(pp.range()); + } + else if (procPatch && !procPatch->owner()) + { + // Exclude neighbour-side, retain owner-side only + excludeFace.set(pp.range()); + } } } - // Use sorted order for later consistency - const wordList zoneNames = - mesh_.faceZones().sortedNames(option().faceZoneSelection()); - // Count face types in each selected faceZone - for (const word& zoneName : zoneNames) + for (const label zoneId : zoneIds) { - const label zoneID = mesh_.faceZones().findZoneID(zoneName); - const faceZone& fz = mesh_.faceZones()[zoneID]; + const word& zoneName = zoneNames[zoneId]; + const faceZone& zn = mesh_.faceZones()[zoneId]; - ensightFaces& ensFaces = faceZoneFaces_(zoneName); - ensFaces.clear(); + ensightFaces& part = faceZoneParts_(zoneId); - if (fz.size()) + part.clear(); + part.identifier() = zoneId; + part.rename(zoneName); + + if (zn.size()) { - ensFaces.classify + part.classify ( mesh_.faces(), - fz, - fz.flipMap(), + zn, + zn.flipMap(), excludeFace ); } // Finalize - ensFaces.reduce(); + part.reduce(); - if (ensFaces.total()) + if (!part.total()) { - ensFaces.index() = nParts++; - } - else - { - faceZoneFaces_.erase(zoneName); + faceZoneParts_.erase(zoneId); } } } + renumber(); + needsUpdate_ = false; } @@ -275,78 +437,134 @@ void Foam::ensightMesh::correct() void Foam::ensightMesh::write(ensightGeoFile& os) const { // - // Write internalMesh + // Write cellZones / internalMesh // - if (useInternalMesh()) + for (const label zoneId : cellZoneParts_.sortedToc()) { - const label nPoints = globalPoints().size(); + const ensightCells& part = cellZoneParts_[zoneId]; + + // Renumber the points/faces into unique points + autoPtr<globalIndex> globalPointsPtr; + labelList pointToGlobal; // local point to unique global index + labelList uniqueMeshPointLabels; // unique global points + + const bool usesAllCells = + returnReduce((part.size() == mesh_.nCells()), andOp<bool>()); + + if (usesAllCells) + { + // All cells used, and thus all points + + globalPointsPtr = + mesh_.globalData().mergePoints + ( + pointToGlobal, + uniqueMeshPointLabels + ); + } + else + { + // Map mesh point index to local (compact) point index + Map<label> meshPointMap(part.meshPointMap(mesh_)); + + labelList meshPoints(meshPointMap.sortedToc()); + + globalPointsPtr = + mesh_.globalData().mergePoints + ( + meshPoints, + meshPointMap, + pointToGlobal, + uniqueMeshPointLabels + ); - const pointField uniquePoints(mesh_.points(), uniquePointMap_); + meshPointMap.clear(); - // writePartHeader(os, 0, "internalMesh"); - // beginCoordinates(os, nPoints); - writeAllPoints + // The mergePoints returns pointToGlobal assuming local addressing + // (eg, patch localFaces). + // Recast as original mesh points to new global points + + labelList oldToNew(mesh_.nPoints(), -1); + + forAll(meshPoints, i) + { + const label orig = meshPoints[i]; + const label glob = pointToGlobal[i]; + + oldToNew[orig] = glob; + } + + pointToGlobal.transfer(oldToNew); + } + + ensightOutput::Detail::writeCoordinates ( - meshCells_.index(), - "internalMesh", - nPoints, - uniquePoints, - os + os, + part.index(), + part.name(), + globalPointsPtr().size(), // nPoints (global) + UIndirectList<point>(mesh_.points(), uniqueMeshPointLabels), + Pstream::parRun() //!< Collective write? ); - writeCellConnectivity(meshCells_, pointToGlobal_, os); + writeCellConnectivity(os, part, pointToGlobal); } // - // Write patches - sorted by Id + // Write patches - sorted by index // - for (const label patchId : patchLookup_.sortedToc()) + for (const label patchId : boundaryParts_.sortedToc()) { - const word& patchName = patchLookup_[patchId]; - const ensightFaces& ensFaces = boundaryPatchFaces_[patchName]; + const ensightFaces& part = boundaryParts_[patchId]; const polyPatch& pp = mesh_.boundaryMesh()[patchId]; // Renumber the patch points/faces into unique points - labelList pointToGlobal; - labelList uniqueMeshPointLabels; + labelList pointToGlobal; // local point to unique global index + labelList uniqueMeshPointLabels; // unique global points + autoPtr<globalIndex> globalPointsPtr = mesh_.globalData().mergePoints ( pp.meshPoints(), pp.meshPointMap(), - pointToGlobal, // local point to unique global index - uniqueMeshPointLabels // unique global points + pointToGlobal, + uniqueMeshPointLabels ); + + ensightOutput::Detail::writeCoordinates + ( + os, + part.index(), + part.name(), + globalPointsPtr().size(), // nPoints (global) + UIndirectList<point>(mesh_.points(), uniqueMeshPointLabels), + Pstream::parRun() //!< Collective write? + ); + // Renumber the patch faces, // from local patch indexing to unique global index faceList patchFaces(pp.localFaces()); - for (face& f : patchFaces) - { - inplaceRenumber(pointToGlobal, f); - } + ListListOps::inplaceRenumber(pointToGlobal, patchFaces); - writeAllPoints + ensightOutput::writeFaceConnectivity ( - ensFaces.index(), - patchName, - globalPointsPtr().size(), - pointField(mesh_.points(), uniqueMeshPointLabels), - os + os, + part, + patchFaces, + Pstream::parRun() //!< Collective write? ); - - writeFaceConnectivity(ensFaces, patchFaces, os); } // - // Write faceZones, if requested + // Write requested faceZones - sorted by index // - for (const word& zoneName : faceZoneFaces_.sortedToc()) + for (const label zoneId : faceZoneParts_.sortedToc()) { - const ensightFaces& ensFaces = faceZoneFaces_[zoneName]; + const ensightFaces& part = faceZoneParts_[zoneId]; // Use the properly sorted faceIds (ensightFaces) and do NOT use the // faceZone directly, otherwise the point-maps will not correspond. @@ -354,27 +572,42 @@ void Foam::ensightMesh::write(ensightGeoFile& os) const indirectPrimitivePatch pp ( - IndirectList<face>(mesh_.faces(), ensFaces.faceIds()), + IndirectList<face>(mesh_.faces(), part.faceIds()), mesh_.points() ); - // Renumber the points/faces into unique points - labelList pointToGlobal; - labelList uniqueMeshPointLabels; + // Renumber the patch points/faces into unique points + labelList pointToGlobal; // local point to unique global index + labelList uniqueMeshPointLabels; // unique global points + autoPtr<globalIndex> globalPointsPtr = mesh_.globalData().mergePoints ( pp.meshPoints(), pp.meshPointMap(), - pointToGlobal, // local point to unique global index - uniqueMeshPointLabels // unique global points + pointToGlobal, + uniqueMeshPointLabels ); + ensightOutput::Detail::writeCoordinates + ( + os, + part.index(), + part.name(), + globalPointsPtr().size(), // nPoints (global) + UIndirectList<point>(mesh_.points(), uniqueMeshPointLabels), + Pstream::parRun() //!< Collective write? + ); + // Renumber the faces belonging to the faceZone, // from local numbering to unique global index. - // Also a good place to perform face flipping - const boolList& flip = ensFaces.flipMap(); + faceList patchFaces(pp.localFaces()); + ListListOps::inplaceRenumber(pointToGlobal, patchFaces); + + // Also a good place to perform face flipping + const boolList& flip = part.flipMap(); + forAll(patchFaces, facei) { face& f = patchFaces[facei]; @@ -383,20 +616,15 @@ void Foam::ensightMesh::write(ensightGeoFile& os) const { f.flip(); } - - inplaceRenumber(pointToGlobal, f); } - writeAllPoints + ensightOutput::writeFaceConnectivityPresorted ( - ensFaces.index(), - zoneName, - globalPointsPtr().size(), - pointField(mesh_.points(), uniqueMeshPointLabels), - os + os, + part, + patchFaces, + Pstream::parRun() //!< Collective write? ); - - writeFaceConnectivity(ensFaces, patchFaces, os, true); } } diff --git a/src/conversion/ensight/mesh/ensightMesh.H b/src/conversion/ensight/mesh/ensightMesh.H index fe0b4f25dbd..41181811efc 100644 --- a/src/conversion/ensight/mesh/ensightMesh.H +++ b/src/conversion/ensight/mesh/ensightMesh.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2018 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -43,22 +43,18 @@ SourceFiles #include "ensightCells.H" #include "ensightFaces.H" #include "ensightGeoFile.H" -#include "cellList.H" -#include "faceList.H" -#include "cellShapeList.H" -#include "HashTable.H" #include "Map.H" #include "scalarField.H" #include "wordRes.H" #include "globalIndex.H" - +#include <memory> // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -// Forward declarations +// Forward Declarations class fvMesh; class ensightMesh; @@ -70,220 +66,68 @@ class ensightMesh { public: - // Forward declarations + // Forward Declarations class options; + //- The zone-id for internal mesh or unzoned cells. + static const label internalZone; + private: - // Private data + // Private Data //- Writer options - const options* options_; + const std::unique_ptr<options> options_; //- Reference to the OpenFOAM mesh const fvMesh& mesh_; - //- The volume cells (internalMesh) - ensightCells meshCells_; - - //- Face elements per patch - HashTable<ensightFaces> boundaryPatchFaces_; + //- Volume elements per cellZone, lookup by zone index. + // The zone -1 is reserved for internal mesh (unzoned cells) + Map<ensightCells> cellZoneParts_; - //- Face elements per faceZone - HashTable<ensightFaces> faceZoneFaces_; + //- Face elements per faceZone, lookup by zone index. + Map<ensightFaces> faceZoneParts_; - //- The list of patches to be output - Map<word> patchLookup_; + //- Face elements per selected patch, lookup by patch index + Map<ensightFaces> boundaryParts_; //- Track if it needs an update mutable bool needsUpdate_; - // Parallel merged points - - //- Global numbering for merged points - autoPtr<globalIndex> globalPointsPtr_; - - //- From mesh point to global merged point - labelList pointToGlobal_; - - //- Local points that are unique - labelList uniquePointMap_; - - // Private Member Functions - //- Clear some storage + //- Clear all storage void clear(); - - //- Inplace renumber of cell-shapes - static cellShapeList& renumberShapes - ( - cellShapeList& shapes, - const labelUList& pointToGlobal - ); - - //- Copy and return renumbered cell-shapes - static cellShapeList renumberShapes - ( - const cellShapeList& shapes, - const labelUList& addr, - const labelUList& pointToGlobal - ); - - //- Write list of faces - static void writeFaceList - ( - const faceList& faces, - ensightGeoFile& os - ); - - //- Write list of faces - static void writeFaceList - ( - const UIndirectList<face>& faces, - ensightGeoFile& os - ); - - //- Return sizes of faces in the list - static labelList getFaceSizes - ( - const faceList& faces - ); - - //- Return sizes of faces in the list - static labelList getFaceSizes - ( - const UIndirectList<face>& faces - ); - - //- Write sizes of faces in the list - static void writeFaceSizes - ( - const faceList& faces, - ensightGeoFile& os - ); - - //- Write sizes of faces in the list - static void writeFaceSizes - ( - const UIndirectList<face>& faces, - ensightGeoFile& os - ); - - //- Write cell connectivity via cell shapes - static void writeCellShapes - ( - const cellShapeList& shapes, - ensightGeoFile& os - ); - - //- Return the number of faces per poly element - static labelList getPolysNFaces - ( - const labelUList& polys, - const cellList& cellFaces - ); - - //- Write the number of faces per poly element - static void writePolysNFaces - ( - const labelUList& polys, - const cellList& cellFaces, - ensightGeoFile& os - ); - - //- Return the number of points per poly element - static labelList getPolysNPointsPerFace - ( - const labelUList& polys, - const cellList& cellFaces, - const faceList& faces - ); - - //- Write the number of points per poly element - static void writePolysNPointsPerFace - ( - const labelUList& polys, - const cellList& cellFaces, - const faceList& faces, - ensightGeoFile& os - ); - - //- Write the point ids per poly element - static void writePolysPoints - ( - const labelUList& addr, - const cellList& cellFaces, - const faceList& faces, - const labelList& faceOwner, - ensightGeoFile& os - ); + //- Enforce consistent index/part numbering + void renumber(); //- Write the poly connectivity void writePolysConnectivity ( + ensightGeoFile& os, const labelUList& polys, - const labelList& pointToGlobal, - ensightGeoFile& + const labelList& pointToGlobal ) const; - //- Write the regular cell connectivity for all types + //- Write cell connectivity for specified type void writeCellConnectivity ( - const ensightCells& ensCells, - const labelList& pointToGlobal, - ensightGeoFile& os + ensightGeoFile& os, + const ensightCells::elemType etype, + const ensightCells& part, + const labelList& pointToGlobal ) const; - //- Write the regular cell connectivity for specified type + //- Write the regular cell connectivity for all types void writeCellConnectivity ( - ensightCells::elemType elemType, - const ensightCells& ensCells, - const labelList& pointToGlobal, - ensightGeoFile& os - ) const; - - //- Write the regular face connectivity for specified type and - //- and specified faces - void writeFaceConnectivity - ( - ensightFaces::elemType elemType, - const label nTotal, - const faceList& faces, - const labelUList& addr, - ensightGeoFile& - ) const; - - //- Write the regular face connectivity for specified type - void writeFaceConnectivity - ( - ensightFaces::elemType elemType, - const label nTotal, - const faceList& faces, - ensightGeoFile& os - ) const; - - - void writeFaceConnectivity - ( - const ensightFaces& ensFaces, - const faceList& faces, ensightGeoFile& os, - const bool raw = false - ) const; - - - void writeAllPoints - ( - const label partId, - const word& ensightPartName, - const label nTotal, - const pointField& uniquePoints, - ensightGeoFile& + const ensightCells& part, + const labelList& pointToGlobal ) const; @@ -308,10 +152,6 @@ public: ensightMesh(const fvMesh& mesh, const IOstream::streamFormat format); - //- Destructor - ~ensightMesh(); - - // Member Functions // Access @@ -325,45 +165,18 @@ public: //- Ascii/Binary file output inline IOstream::streamFormat format() const; - //- Using internal? - inline bool useInternalMesh() const; - - //- Using boundary? - inline bool useBoundaryMesh() const; - - //- The volume cells (internalMesh) - inline const ensightCells& meshCells() const; - - //- The list of patches to be output - inline const Map<word>& patches() const; - - //- Face elements per selected patch - inline const HashTable<ensightFaces>& boundaryPatchFaces() const; - - //- Face elements per selected faceZone. - // To be output in sorted order. - inline const HashTable<ensightFaces>& faceZoneFaces() const; - + //- Face elements per selected patch, lookup by patch index + // Process in sorted order. + // May require special treatment for zone -1 (internal). + inline const Map<ensightCells>& cellZoneParts() const; - // Parallel point merging + //- Face elements per faceZone, lookup by zone index. + // Process in sorted order. + inline const Map<ensightFaces>& faceZoneParts() const; - //- Global numbering for merged points - const globalIndex& globalPoints() const - { - return globalPointsPtr_(); - } - - //- From mesh point to global merged point - const labelList& pointToGlobal() const - { - return pointToGlobal_; - } - - //- Local points that are unique - const labelList& uniquePointMap() const - { - return uniquePointMap_; - } + //- Face elements per selected patch, lookup by patch index + // Process in sorted order. + inline const Map<ensightFaces>& boundaryParts() const; // Other @@ -387,37 +200,47 @@ public: //- Write to file void write(ensightGeoFile& os) const; - }; //- Configuration options for the ensightMesh class ensightMesh::options { - //- Ascii/Binary file output - IOstream::streamFormat format_; + // Private Data + + //- Ascii/Binary file output + IOstream::streamFormat format_; + + //- Create in 'expired' mode + bool lazy_; - //- Create in 'expired' mode - bool lazy_; + //- Use the internal mesh + bool internal_; - //- Use the internal mesh - bool internal_; + //- Use the boundary mesh + bool boundary_; - //- Use the boundary mesh - bool boundary_; + //- Handle cellZones (if internal_ is true) + bool cellZones_; - //- Output of selected patches only - wordRes patchPatterns_; + //- Selected patches only + wordRes patchInclude_; - //- Output of selected faceZones - wordRes faceZonePatterns_; + //- Deselected patches + wordRes patchExclude_; + + //- Selected cellZones + wordRes cellZoneInclude_; + + //- Selected faceZones + wordRes faceZoneInclude_; public: // Constructors - //- Construct for binary output + //- Default construct, use binary output options(); //- Construct for specified format @@ -443,19 +266,28 @@ public: //- Using faceZones? bool useFaceZones() const; + //- Using cellZones? + bool useCellZones() const; + //- Selection of patches. Empty if unspecified. const wordRes& patchSelection() const; + //- Selection of black listed patches. Empty if unspecified. + const wordRes& patchExclude() const; + //- Selection of faceZones. Empty if unspecified. const wordRes& faceZoneSelection() const; + //- Selection of faceZones. Empty if unspecified. + const wordRes& cellZoneSelection() const; + // Edit //- Reset to defaults void reset(); - //- Lazy creation - ensightMesh starts as needsUpdate. + //- Lazy creation - ensightMesh starts as needsUpdate void lazy(bool beLazy); //- Alter the useBoundaryMesh state @@ -464,29 +296,49 @@ public: //- Alter the useBoundaryMesh state void useBoundaryMesh(bool on); + //- Alter the useCellZones state + void useCellZones(bool on); + //- Define patch selection matcher void patchSelection(const UList<wordRe>& patterns); //- Define patch selection matcher void patchSelection(List<wordRe>&& patterns); + //- Define patch selection blacklist + void patchExclude(const UList<wordRe>& patterns); + + //- Define patch selection blacklist + void patchExclude(List<wordRe>&& patterns); + //- Define faceZone selection matcher void faceZoneSelection(const UList<wordRe>& patterns); //- Define faceZone selection matcher void faceZoneSelection(List<wordRe>&& patterns); + //- Define cellZone selection matcher + void cellZoneSelection(const UList<wordRe>& patterns); + + //- Define cellZone selection matcher + void cellZoneSelection(List<wordRe>&& patterns); + + + // Edit + + //- Report values + void print(Ostream& os) const; + // Housekeeping //- Older name for useBoundaryMesh() - // \deprecated OCT-2018 + // \deprecated(2018-10) bool usePatches() const { return useBoundaryMesh(); } //- Older name for useBoundaryMesh() - // \deprecated OCT-2018 + // \deprecated(2018-10) void noPatches(bool off) { useBoundaryMesh(!off); } - }; diff --git a/src/conversion/ensight/mesh/ensightMeshI.H b/src/conversion/ensight/mesh/ensightMeshI.H index 8691435d298..ebd2fad67c1 100644 --- a/src/conversion/ensight/mesh/ensightMeshI.H +++ b/src/conversion/ensight/mesh/ensightMeshI.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -45,41 +45,24 @@ inline Foam::IOstream::streamFormat Foam::ensightMesh::format() const } -inline bool Foam::ensightMesh::useInternalMesh() const +inline const Foam::Map<Foam::ensightCells>& +Foam::ensightMesh::cellZoneParts() const { - return options_->useInternalMesh(); + return cellZoneParts_; } -inline bool Foam::ensightMesh::useBoundaryMesh() const +inline const Foam::Map<Foam::ensightFaces>& +Foam::ensightMesh::faceZoneParts() const { - return options_->useBoundaryMesh(); + return faceZoneParts_; } -inline const Foam::ensightCells& Foam::ensightMesh::meshCells() const +inline const Foam::Map<Foam::ensightFaces>& +Foam::ensightMesh::boundaryParts() const { - return meshCells_; -} - - -inline const Foam::Map<Foam::word>& Foam::ensightMesh::patches() const -{ - return patchLookup_; -} - - -inline const Foam::HashTable<Foam::ensightFaces>& -Foam::ensightMesh::boundaryPatchFaces() const -{ - return boundaryPatchFaces_; -} - - -inline const Foam::HashTable<Foam::ensightFaces>& -Foam::ensightMesh::faceZoneFaces() const -{ - return faceZoneFaces_; + return boundaryParts_; } diff --git a/src/conversion/ensight/mesh/ensightMeshIO.C b/src/conversion/ensight/mesh/ensightMeshIO.C index 4e3bc534041..4afb1a2de03 100644 --- a/src/conversion/ensight/mesh/ensightMeshIO.C +++ b/src/conversion/ensight/mesh/ensightMeshIO.C @@ -5,8 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2016-2018 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,588 +26,182 @@ License \*---------------------------------------------------------------------------*/ #include "ensightMesh.H" +#include "ensightOutput.H" #include "fvMesh.H" -#include "globalMeshData.H" -#include "PstreamCombineReduceOps.H" -#include "processorPolyPatch.H" -#include "mapDistribute.H" -#include "stringListOps.H" -#include "ensightFile.H" -#include "ensightGeoFile.H" +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // - -Foam::cellShapeList& Foam::ensightMesh::renumberShapes -( - cellShapeList& shapes, - const labelUList& pointToGlobal -) -{ - for (cellShape& shape : shapes) - { - inplaceRenumber(pointToGlobal, shape); - } - - return shapes; -} - - -Foam::cellShapeList Foam::ensightMesh::renumberShapes +void Foam::ensightMesh::writePolysConnectivity ( - const cellShapeList& shapes, + ensightGeoFile& os, const labelUList& addr, - const labelUList& pointToGlobal -) -{ - cellShapeList list(shapes, addr); - - renumberShapes(list, pointToGlobal); - - return list; -} - - -void Foam::ensightMesh::writeFaceList -( - const faceList& faceLst, - ensightGeoFile& os -) + const labelList& pointToGlobal +) const { - for (const face& f : faceLst) + // Number of faces per polyhedral (1/line in ASCII) { - for (const label labi : f) - { - os.write(labi + 1); - } - - os.newline(); - } -} - + labelList send + ( + ensightOutput::Detail::getPolysNFaces(mesh_, addr) + ); -void Foam::ensightMesh::writeFaceList -( - const UIndirectList<face>& faceLst, - ensightGeoFile& os -) -{ - for (const face& f : faceLst) - { - for (const label labi : f) + if (Pstream::master()) { - os.write(labi + 1); - } - - os.newline(); - } -} - - -Foam::labelList Foam::ensightMesh::getFaceSizes -( - const faceList& faceLst -) -{ - labelList list(faceLst.size()); - - auto outIter = list.begin(); - - for (const face& f : faceLst) - { - *outIter = f.size(); - ++outIter; - } + // Master + os.writeLabels(send); - return list; -} - - -Foam::labelList Foam::ensightMesh::getFaceSizes -( - const UIndirectList<face>& faceLst -) -{ - labelList list(faceLst.size()); - - auto outIter = list.begin(); - - for (const face& f : faceLst) - { - *outIter = f.size(); - ++outIter; - } - - return list; -} - - -void Foam::ensightMesh::writeFaceSizes -( - const faceList& faceLst, - ensightGeoFile& os -) -{ - for (const face& f : faceLst) - { - os.write(f.size()); - os.newline(); - } -} - - -void Foam::ensightMesh::writeFaceSizes -( - const UIndirectList<face>& faceLst, - ensightGeoFile& os -) -{ - for (const face& f : faceLst) - { - os.write(f.size()); - os.newline(); - } -} - - -void Foam::ensightMesh::writeCellShapes -( - const cellShapeList& shapes, - ensightGeoFile& os -) -{ - for (const cellShape& cellPoints : shapes) - { - // Convert global -> local index - // (note: Ensight indices start with 1) + // Slaves + for (int slave=1; slave<Pstream::nProcs(); ++slave) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - // In ASCII, write one cell per line - for (const label pointi : cellPoints) - { - os.write(pointi + 1); + labelList recv(fromSlave); + os.writeLabels(recv); + } } - - os.newline(); - } -} - - -Foam::labelList Foam::ensightMesh::getPolysNFaces -( - const labelUList& addr, - const cellList& cellFaces -) -{ - labelList list(addr.size()); - - auto outIter = list.begin(); - - // The number of faces per element - for (const label cellId : addr) - { - const labelUList& cf = cellFaces[cellId]; - - *outIter = cf.size(); - ++outIter; - } - - return list; -} - - -void Foam::ensightMesh::writePolysNFaces -( - const labelUList& addr, - const cellList& cellFaces, - ensightGeoFile& os -) -{ - // Write the number of faces per element (1/line in ASCII) - for (const label cellId : addr) - { - const labelUList& cf = cellFaces[cellId]; - - os.write(cf.size()); - os.newline(); - } -} - - -Foam::labelList Foam::ensightMesh::getPolysNPointsPerFace -( - const labelUList& addr, - const cellList& cellFaces, - const faceList& faces -) -{ - // Count the number of faces per element - - label nTotFaces = 0; - for (const label cellId : addr) - { - const labelUList& cf = cellFaces[cellId]; - - nTotFaces += cf.size(); - } - - labelList list(nTotFaces); - - auto outIter = list.begin(); - - // The number of points per element face - for (const label cellId : addr) - { - const labelUList& cf = cellFaces[cellId]; - - for (const label facei : cf) + else { - *outIter = faces[facei].size(); - ++outIter; - } - } - - return list; -} - - -void Foam::ensightMesh::writePolysNPointsPerFace -( - const labelUList& addr, - const cellList& cellFaces, - const faceList& faces, - ensightGeoFile& os -) -{ - // Write the number of points per element face (1/line in ASCII) - for (const label cellId : addr) - { - const labelUList& cf = cellFaces[cellId]; + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); - for (const label facei : cf) - { - os.write(faces[facei].size()); - os.newline(); + toMaster << send; } } -} -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::ensightMesh::writePolysPoints -( - const labelUList& addr, - const cellList& cellFaces, - const faceList& faces, - const labelList& faceOwner, - ensightGeoFile& os -) -{ - for (const label cellId : addr) + // Number of points for each polyhedral face (1/line in ASCII) { - const labelUList& cf = cellFaces[cellId]; + labelList send + ( + ensightOutput::Detail::getPolysNPointsPerFace(mesh_, addr) + ); - for (const label faceId : cf) + if (Pstream::master()) { - const face& f = faces[faceId]; // face points (in global points) + // Master + os.writeLabels(send); - if (faceId < faceOwner.size() && faceOwner[faceId] != cellId) - { - // internal face, neighbour - // - // as per face::reverseFace(), but without copying - - os.write(f[0] + 1); - for (label pti = f.size()-1; pti > 0; --pti) - { - os.write(f[pti] + 1); - } - } - else + // Slaves + for (int slave=1; slave<Pstream::nProcs(); ++slave) { - for (const label labi : f) - { - os.write(labi + 1); - } - } - - os.newline(); - } - } -} - - -void Foam::ensightMesh::writePolysConnectivity -( - const labelUList& addr, - const labelList& pointToGlobal, - ensightGeoFile& os -) const -{ - const cellList& cellFaces = mesh_.cells(); - const faceList& meshFaces = mesh_.faces(); - const labelList& faceOwner = mesh_.faceOwner(); - - // Number of faces for each poly cell - if (Pstream::master()) - { - // Master - writePolysNFaces(addr, cellFaces, os); - - // Slaves - for (int slave=1; slave<Pstream::nProcs(); ++slave) - { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - labelList addr(fromSlave); - cellList cellFaces(fromSlave); + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - writePolysNFaces(addr, cellFaces, os); + labelList recv(fromSlave); + os.writeLabels(recv); + } } - } - else - { - OPstream toMaster(Pstream::commsTypes::scheduled, Pstream::masterNo()); - toMaster - << addr - << cellFaces; - } - - // Number of points for each face of the above list - if (Pstream::master()) - { - // Master - writePolysNPointsPerFace - ( - addr, - cellFaces, - meshFaces, - os - ); - - // Slaves - for (int slave=1; slave<Pstream::nProcs(); ++slave) + else { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - labelList addr(fromSlave); - cellList cellFaces(fromSlave); - faceList meshFaces(fromSlave); - - writePolysNPointsPerFace + OPstream toMaster ( - addr, - cellFaces, - meshFaces, - os + Pstream::commsTypes::scheduled, + Pstream::masterNo() ); + + toMaster << send; } } - else - { - OPstream toMaster(Pstream::commsTypes::scheduled, Pstream::masterNo()); - toMaster - << addr - << cellFaces - << meshFaces; - } - // Renumber faces to use global point numbers - faceList faces(mesh_.faces()); - for (face& f : faces) - { - inplaceRenumber(pointToGlobal, f); - } - // List of points id for each face of the above list if (Pstream::master()) { // Master - writePolysPoints + ensightOutput::writePolysPoints ( + os, + mesh_, addr, - cellFaces, - faces, - faceOwner, - os + pointToGlobal ); // Slaves for (int slave=1; slave<Pstream::nProcs(); ++slave) { IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + cellList cells(fromSlave); labelList addr(fromSlave); - cellList cellFaces(fromSlave); faceList faces(fromSlave); - labelList faceOwner(fromSlave); + labelList owner(fromSlave); - writePolysPoints + ensightOutput::writePolysPoints ( + os, + cells, addr, - cellFaces, faces, - faceOwner, - os + owner ); } } else { - OPstream toMaster(Pstream::commsTypes::scheduled, Pstream::masterNo()); + // Renumber faces to use global point numbers + faceList faces(mesh_.faces()); + ListListOps::inplaceRenumber(pointToGlobal, faces); + + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + toMaster + << mesh_.cells() << addr - << cellFaces << faces - << faceOwner; + << mesh_.faceOwner(); } } void Foam::ensightMesh::writeCellConnectivity ( - const ensightCells::elemType elemType, - const ensightCells& ensCells, - const labelList& pointToGlobal, - ensightGeoFile& os + ensightGeoFile& os, + const ensightCells::elemType etype, + const ensightCells& part, + const labelList& pointToGlobal ) const { - const label nTotal = ensCells.total(elemType); + const label nTotal = part.total(etype); if (nTotal) { - const labelUList& addr = ensCells.cellIds(elemType); + const labelUList& addr = part.cellIds(etype); if (Pstream::master()) { - os.writeKeyword(ensightCells::key(elemType)); + os.writeKeyword(ensightCells::key(etype)); os.write(nTotal); os.newline(); } - if (elemType == ensightCells::NFACED) - { - writePolysConnectivity - ( - addr, - pointToGlobal, - os - ); - } - else - { - const cellShapeList shapes - ( - renumberShapes - ( - mesh_.cellShapes(), - addr, - pointToGlobal - ) - ); - - - if (Pstream::master()) - { - writeCellShapes(shapes, os); - - for (int slave=1; slave<Pstream::nProcs(); ++slave) - { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - cellShapeList recv(fromSlave); - - writeCellShapes(recv, os); - } - } - else - { - OPstream toMaster - ( - Pstream::commsTypes::scheduled, - Pstream::masterNo() - ); - - toMaster - << shapes; - } - } - } -} - - -void Foam::ensightMesh::writeCellConnectivity -( - const ensightCells& ensCells, - const labelList& pointToGlobal, - ensightGeoFile& os -) const -{ - for (label typei=0; typei < ensightCells::nTypes; ++typei) - { - const ensightCells::elemType what = - ensightCells::elemType(typei); - - writeCellConnectivity(what, ensCells, pointToGlobal, os); - } -} - - -void Foam::ensightMesh::writeFaceConnectivity -( - ensightFaces::elemType elemType, - const label nTotal, - const faceList& faces, - ensightGeoFile& os -) const -{ - if (nTotal) - { - if (Pstream::master()) + if (etype == ensightCells::NFACED) { - os.writeKeyword(ensightFaces::key(elemType)); - os.write(nTotal); - os.newline(); + writePolysConnectivity(os, addr, pointToGlobal); + return; } - if (elemType == ensightFaces::NSIDED) - { - // Number of points per face - - if (Pstream::master()) - { - writeFaceSizes(faces, os); - - for (int slave=1; slave<Pstream::nProcs(); ++slave) - { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - faceList recv(fromSlave); - writeFaceSizes(recv, os); - } - } - else - { - OPstream toMaster - ( - Pstream::commsTypes::scheduled, - Pstream::masterNo() - ); - - toMaster - << faces; - } - } + // Primitive shape - get subset and renumber + cellShapeList shapes(mesh_.cellShapes(), addr); + ListListOps::inplaceRenumber(pointToGlobal, shapes); - // List of points id for each face if (Pstream::master()) { - writeFaceList(faces, os); + ensightOutput::writeCellShapes(os, shapes); for (int slave=1; slave<Pstream::nProcs(); ++slave) { IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - faceList recv(fromSlave); + cellShapeList recv(fromSlave); - writeFaceList(recv, os); + ensightOutput::writeCellShapes(os, recv); } } else @@ -619,174 +212,24 @@ void Foam::ensightMesh::writeFaceConnectivity Pstream::masterNo() ); - toMaster - << faces; + toMaster << shapes; } } } -void Foam::ensightMesh::writeFaceConnectivity -( - ensightFaces::elemType elemType, - const label nTotal, - const faceList& faceLst, - const labelUList& addr, - ensightGeoFile& os -) const -{ - if (nTotal) - { - if (Pstream::master()) - { - os.writeKeyword(ensightFaces::key(elemType)); - os.write(nTotal); - os.newline(); - } - - const UIndirectList<face> faces(faceLst, addr); - - if (elemType == ensightFaces::NSIDED) - { - // Number of points per face - - if (Pstream::master()) - { - writeFaceSizes(faces, os); - - for (int slave=1; slave<Pstream::nProcs(); ++slave) - { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - faceList recv(fromSlave); - - writeFaceSizes(recv, os); - } - } - else - { - OPstream toMaster - ( - Pstream::commsTypes::scheduled, - Pstream::masterNo() - ); - - toMaster - << faces; - } - } - - // List of points id per face - if (Pstream::master()) - { - writeFaceList(faces, os); - - for (int slave=1; slave<Pstream::nProcs(); ++slave) - { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - faceList recv(fromSlave); - - writeFaceList(recv, os); - } - } - else - { - OPstream toMaster - ( - Pstream::commsTypes::scheduled, - Pstream::masterNo() - ); - - toMaster - << faces; - } - } -} - - -void Foam::ensightMesh::writeFaceConnectivity +void Foam::ensightMesh::writeCellConnectivity ( - const ensightFaces& ensFaces, - const faceList& faceLst, ensightGeoFile& os, - const bool raw -) const -{ - for (label typei=0; typei < ensightFaces::nTypes; ++typei) - { - const ensightFaces::elemType what = - ensightFaces::elemType(typei); - - if (raw) - { - writeFaceConnectivity - ( - what, - ensFaces.total(what), - SubList<face> - ( - faceLst, - ensFaces.faceIds(what).size(), - ensFaces.offset(what) - ), - os - ); - } - else - { - writeFaceConnectivity - ( - what, - ensFaces.total(what), - faceLst, - ensFaces.faceIds(what), - os - ); - } - } -} - - -void Foam::ensightMesh::writeAllPoints -( - const label partId, - const word& ensightPartName, - const label nPoints, - const pointField& uniquePoints, - ensightGeoFile& os + const ensightCells& part, + const labelList& pointToGlobal ) const { - if (Pstream::master()) - { - os.beginPart(partId, ensightPartName); - - // Write points - os.beginCoordinates(nPoints); - - for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) - { - os.writeList(uniquePoints.component(cmpt)); - - for (int slave=1; slave<Pstream::nProcs(); ++slave) - { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - scalarField recv(fromSlave); - os.writeList(recv); - } - } - } - else + for (label typei=0; typei < ensightCells::nTypes; ++typei) { - for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) - { - OPstream toMaster - ( - Pstream::commsTypes::scheduled, - Pstream::masterNo() - ); + const auto etype = ensightCells::elemType(typei); - toMaster - << uniquePoints.component(cmpt); - } + writeCellConnectivity(os, etype, part, pointToGlobal); } } diff --git a/src/conversion/ensight/mesh/ensightMeshOptions.C b/src/conversion/ensight/mesh/ensightMeshOptions.C index 73ba0bd937e..a5019e6fe2c 100644 --- a/src/conversion/ensight/mesh/ensightMeshOptions.C +++ b/src/conversion/ensight/mesh/ensightMeshOptions.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2018 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,6 +26,34 @@ License \*---------------------------------------------------------------------------*/ #include "ensightMesh.H" +#include "Switch.H" + +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // + +namespace Foam +{ + +// DIY flatOutput without a leading size indicator +static Ostream& printPatterns(Ostream& os, const wordRes& list) +{ + os << token::BEGIN_LIST; + + bool sep = false; + + for (const wordRe& item : list) + { + if (sep) os << token::SPACE; + os << item; + + sep = true; + } + os << token::END_LIST; + + return os; +} + +} // End namespace + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // @@ -41,8 +69,11 @@ Foam::ensightMesh::options::options(IOstream::streamFormat format) lazy_(false), internal_(true), boundary_(true), - patchPatterns_(), - faceZonePatterns_() + cellZones_(true), + patchInclude_(), + patchExclude_(), + cellZoneInclude_(), + faceZoneInclude_() {} @@ -72,9 +103,15 @@ bool Foam::ensightMesh::options::useBoundaryMesh() const } +bool Foam::ensightMesh::options::useCellZones() const +{ + return cellZones_; +} + + bool Foam::ensightMesh::options::useFaceZones() const { - return faceZonePatterns_.size(); + return faceZoneInclude_.size(); } @@ -82,8 +119,11 @@ void Foam::ensightMesh::options::reset() { internal_ = true; boundary_ = true; - patchPatterns_.clear(); - faceZonePatterns_.clear(); + cellZones_ = true; + patchInclude_.clear(); + patchExclude_.clear(); + faceZoneInclude_.clear(); + cellZoneInclude_.clear(); } @@ -103,12 +143,30 @@ void Foam::ensightMesh::options::useBoundaryMesh(bool on) { boundary_ = on; - if (!boundary_ && patchPatterns_.size()) + if (!boundary_) { - patchPatterns_.clear(); + if (patchInclude_.size()) + { + patchInclude_.clear(); + + WarningInFunction + << "Deactivating boundary, removed old patch selection" + << endl; + } + } +} + + +void Foam::ensightMesh::options::useCellZones(bool on) +{ + cellZones_ = on; + + if (!cellZones_ && cellZoneInclude_.size()) + { + cellZoneInclude_.clear(); WarningInFunction - << "Deactivating boundary and removing old patch selection" + << "Deactivating cellZones, removed old zone selection" << endl; } } @@ -119,14 +177,14 @@ void Foam::ensightMesh::options::patchSelection const UList<wordRe>& patterns ) { - patchPatterns_ = wordRes(patterns); + patchInclude_ = wordRes(patterns); - if (!boundary_ && patchPatterns_.size()) + if (!boundary_ && patchInclude_.size()) { - patchPatterns_.clear(); + patchInclude_.clear(); WarningInFunction - << "Ignoring patch selection, boundary is not active" + << "Ignoring patch selection, boundary is disabled" << endl; } } @@ -137,25 +195,43 @@ void Foam::ensightMesh::options::patchSelection List<wordRe>&& patterns ) { - patchPatterns_ = wordRes(std::move(patterns)); + patchInclude_ = wordRes(std::move(patterns)); - if (!boundary_ && patchPatterns_.size()) + if (!boundary_ && patchInclude_.size()) { - patchPatterns_.clear(); + patchInclude_.clear(); WarningInFunction - << "Ignoring patch selection, boundary is not active" + << "Ignoring patch selection, boundary is disabled" << endl; } } +void Foam::ensightMesh::options::patchExclude +( + const UList<wordRe>& patterns +) +{ + patchExclude_ = wordRes(patterns); +} + + +void Foam::ensightMesh::options::patchExclude +( + List<wordRe>&& patterns +) +{ + patchExclude_ = wordRes(std::move(patterns)); +} + + void Foam::ensightMesh::options::faceZoneSelection ( const UList<wordRe>& patterns ) { - faceZonePatterns_ = wordRes(patterns); + faceZoneInclude_ = wordRes(patterns); } @@ -164,19 +240,113 @@ void Foam::ensightMesh::options::faceZoneSelection List<wordRe>&& patterns ) { - faceZonePatterns_ = wordRes(std::move(patterns)); + faceZoneInclude_ = wordRes(std::move(patterns)); +} + + +void Foam::ensightMesh::options::cellZoneSelection +( + const UList<wordRe>& patterns +) +{ + cellZoneInclude_ = wordRes(patterns); + + if (!cellZones_ && cellZoneInclude_.size()) + { + cellZoneInclude_.clear(); + + WarningInFunction + << "Ignoring cellZone selection, cellZones are disabled" + << endl; + } +} + + +void Foam::ensightMesh::options::cellZoneSelection +( + List<wordRe>&& patterns +) +{ + cellZoneInclude_ = wordRes(std::move(patterns)); + + if (!cellZones_ && cellZoneInclude_.size()) + { + cellZoneInclude_.clear(); + + WarningInFunction + << "Ignoring cellZone selection, cellZones are disabled" + << endl; + } } const Foam::wordRes& Foam::ensightMesh::options::patchSelection() const { - return patchPatterns_; + return patchInclude_; +} + + +const Foam::wordRes& Foam::ensightMesh::options::patchExclude() const +{ + return patchExclude_; } const Foam::wordRes& Foam::ensightMesh::options::faceZoneSelection() const { - return faceZonePatterns_; + return faceZoneInclude_; +} + + +const Foam::wordRes& Foam::ensightMesh::options::cellZoneSelection() const +{ + return cellZoneInclude_; +} + + +void Foam::ensightMesh::options::print(Ostream& os) const +{ + os << "internal: " << Switch::name(internal_) << nl; + os << "cellZones: " << Switch::name(cellZones_) << nl; + if (cellZones_) + { + os.incrIndent(); + if (!cellZoneInclude_.empty()) + { + os.writeKeyword("include"); + printPatterns(os, cellZoneInclude_) << nl; + } + os.decrIndent(); + } + + os << "boundary: " << Switch::name(boundary_) << nl; + if (boundary_) + { + os.incrIndent(); + if (!patchInclude_.empty()) + { + os.writeKeyword("include"); + printPatterns(os, patchInclude_) << nl; + } + if (!patchExclude_.empty()) + { + os.writeKeyword("exclude"); + printPatterns(os, patchExclude_) << nl; + } + os.decrIndent(); + } + + os << "faceZones: " << Switch::name(useFaceZones()) << nl; + if (useFaceZones()) + { + os.incrIndent(); + if (!faceZoneInclude_.empty()) + { + os.writeKeyword("include"); + printPatterns(os, faceZoneInclude_) << nl; + } + os.decrIndent(); + } } diff --git a/src/conversion/ensight/output/ensightOutputVolField.H b/src/conversion/ensight/output/ensightOutputVolField.H index 21a570b4954..189d2162fef 100644 --- a/src/conversion/ensight/output/ensightOutputVolField.H +++ b/src/conversion/ensight/output/ensightOutputVolField.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -46,7 +46,7 @@ Description namespace Foam { -// Forward declarations +// Forward Declarations class ensightMesh; namespace ensightOutput @@ -63,18 +63,18 @@ namespace Detail template<class Type> bool writeVolField ( + ensightFile& os, const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightMesh& ensMesh, - ensightFile& os + const ensightMesh& ensMesh ); //- Write point field component-wise template<class Type> bool writePointField ( + ensightFile& os, const GeometricField<Type, pointPatchField, pointMesh>& pf, - const ensightMesh& ensMesh, - ensightFile& os + const ensightMesh& ensMesh ); } // End namespace Detail @@ -88,9 +88,9 @@ bool writePointField template<class Type> bool writeVolField ( - const GeometricField<Type, fvPatchField, volMesh>&, - const ensightMesh& ensMesh, ensightFile& os, + const GeometricField<Type, fvPatchField, volMesh>& vf, + const ensightMesh& ensMesh, const bool nodeValues = false ); @@ -102,33 +102,13 @@ bool writeVolField namespace Serial { -//- Write volume field component-wise for specified faces -template<class Type> -bool writeVolField -( - const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightPartFaces& part, - ensightFile& os -); - - -//- Write volume field component-wise for specified cells -template<class Type> -bool writeVolField -( - const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightPartCells& part, - ensightFile& os -); - - //- Write volume field component-wise template<class Type> bool writeVolField ( + ensightFile& os, const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightParts& list, - ensightFile& os + const ensightParts& list ); } // End namespace Serial diff --git a/src/conversion/ensight/output/ensightOutputVolFieldTemplates.C b/src/conversion/ensight/output/ensightOutputVolFieldTemplates.C index de1238cf54f..ec227df1211 100644 --- a/src/conversion/ensight/output/ensightOutputVolFieldTemplates.C +++ b/src/conversion/ensight/output/ensightOutputVolFieldTemplates.C @@ -5,8 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -31,9 +30,9 @@ License #include "fvMesh.H" #include "globalIndex.H" +#include "linear.H" #include "volPointInterpolation.H" #include "interpolation.H" -#include "linear.H" #include "processorFvPatch.H" #include "uindirectPrimitivePatch.H" @@ -42,62 +41,59 @@ License template<class Type> bool Foam::ensightOutput::Detail::writeVolField ( + ensightFile& os, const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightMesh& ensMesh, - ensightFile& os + const ensightMesh& ensMesh ) { constexpr bool parallel = true; const fvMesh& mesh = ensMesh.mesh(); - const ensightCells& meshCells = ensMesh.meshCells(); - const Map<word>& patchLookup = ensMesh.patches(); - const HashTable<ensightFaces>& patchFaces = ensMesh.boundaryPatchFaces(); - const HashTable<ensightFaces>& zoneFaces = ensMesh.faceZoneFaces(); + + const Map<ensightCells>& cellZoneParts = ensMesh.cellZoneParts(); + const Map<ensightFaces>& faceZoneParts = ensMesh.faceZoneParts(); + const Map<ensightFaces>& boundaryParts = ensMesh.boundaryParts(); // - // write internalMesh, unless patch-selection was requested + // Write internalMesh and cellZones - sorted by index // - if (ensMesh.useInternalMesh()) + for (const label zoneId : cellZoneParts.sortedToc()) { - Detail::writeCellField(vf, meshCells, os, parallel); + const ensightCells& part = cellZoneParts[zoneId]; + + Detail::writeField(os, vf, part, parallel); } // - // write patches - // use sortedToc for extra safety + // Write patches - sorted by index // - const labelList patchIds = patchLookup.sortedToc(); - for (const label patchId : patchIds) + for (const label patchId : boundaryParts.sortedToc()) { - const word& patchName = patchLookup[patchId]; - const ensightFaces& part = patchFaces[patchName]; + const ensightFaces& part = boundaryParts[patchId]; - writeFaceField + writeField ( + os, vf.boundaryField()[patchId], part, - os, - parallel + parallel, + true // localField ); } - // - // write faceZones, if requested - // use sortedToc for extra safety + // Write requested faceZones - sorted by index // - const wordList zoneNames = zoneFaces.sortedToc(); - if (!zoneNames.empty()) + if (!faceZoneParts.empty()) { - // Interpolates cell values to faces - needed only when exporting - // faceZones... + // Interpolates cell values to faces + // - only needed when exporting faceZones... GeometricField<Type, fvsPatchField, surfaceMesh> sf ( Foam::linearInterpolate(vf) ); - // flat boundary field + // Flat boundary field // similar to volPointInterpolation::flatBoundaryField() Field<Type> flat(mesh.nBoundaryFaces(), Zero); @@ -131,30 +127,33 @@ bool Foam::ensightOutput::Detail::writeVolField } } - for (const word& zoneName : zoneNames) + for (const label zoneId : faceZoneParts.sortedToc()) { - const ensightFaces& part = zoneFaces[zoneName]; - - // Field (local size) - Field<Type> values(part.size()); + const ensightFaces& part = faceZoneParts[zoneId]; // Loop over face ids to store the needed field values // - internal faces use linear interpolation // - boundary faces use the corresponding patch value - forAll(part, i) + + // Field (local size) + Field<Type> values(part.size()); + auto valIter = values.begin(); + + for (const label faceId : part.faceIds()) { - const label faceId = part[i]; - values[i] = + *valIter = ( mesh.isInternalFace(faceId) ? sf[faceId] : flat[faceId - mesh.nInternalFaces()] ); + + ++valIter; } - // The field is already copied in the proper order + // The field is already in the proper element order // - just need its corresponding sub-fields - Detail::writeFaceSubField(values, part, os, parallel); + Detail::writeFaceSubField(os, values, part, parallel); } } @@ -165,47 +164,82 @@ bool Foam::ensightOutput::Detail::writeVolField template<class Type> bool Foam::ensightOutput::Detail::writePointField ( + ensightFile& os, const GeometricField<Type, pointPatchField, pointMesh>& pf, - const ensightMesh& ensMesh, - ensightFile& os + const ensightMesh& ensMesh ) { + const char* coordKeyword = "coordinates"; + constexpr bool parallel = true; const fvMesh& mesh = ensMesh.mesh(); - const Map<word>& patchLookup = ensMesh.patches(); - const HashTable<ensightFaces>& patchFaces = ensMesh.boundaryPatchFaces(); - const HashTable<ensightFaces>& zoneFaces = ensMesh.faceZoneFaces(); + const Map<ensightCells>& cellZoneParts = ensMesh.cellZoneParts(); + const Map<ensightFaces>& faceZoneParts = ensMesh.faceZoneParts(); + const Map<ensightFaces>& boundaryParts = ensMesh.boundaryParts(); // - // write internalMesh, unless patch-selection was requested + // Write internalMesh and cellZones - sorted by index // - if (ensMesh.useInternalMesh()) + for (const label zoneId : cellZoneParts.sortedToc()) { + const ensightCells& part = cellZoneParts[zoneId]; + + const bool usesAllCells = + returnReduce((part.size() == mesh.nCells()), andOp<bool>()); + + // Renumber the points/faces into unique points + autoPtr<globalIndex> globalPointsPtr; + labelList pointToGlobal; // local point to unique global index + labelList uniqueMeshPointLabels; // unique global points + + if (usesAllCells) + { + // All cells used, and thus all points + + mesh.globalData().mergePoints + ( + pointToGlobal, + uniqueMeshPointLabels + ); + } + else + { + // Map mesh point index to local (compact) point index + Map<label> meshPointMap(part.meshPointMap(mesh)); + + globalPointsPtr = + mesh.globalData().mergePoints + ( + meshPointMap.sortedToc(), + meshPointMap, + pointToGlobal, + uniqueMeshPointLabels + ); + } + if (Pstream::master()) { - os.beginPart(0); // 0 = internalMesh + os.beginPart(part.index()); } Detail::writeFieldComponents ( - "coordinates", - Field<Type>(pf.internalField(), ensMesh.uniquePointMap()), os, + coordKeyword, + UIndirectList<Type>(pf.internalField(), uniqueMeshPointLabels), parallel ); } + // - // write patches - // use sortedToc for extra safety + // Write patches - sorted by index // - const labelList patchIds = patchLookup.sortedToc(); - for (const label patchId : patchIds) + for (const label patchId : boundaryParts.sortedToc()) { - const word& patchName = patchLookup[patchId]; - const ensightFaces& part = patchFaces[patchName]; + const ensightFaces& part = boundaryParts[patchId]; const fvPatch& p = mesh.boundary()[patchId]; @@ -228,20 +262,19 @@ bool Foam::ensightOutput::Detail::writePointField Detail::writeFieldComponents ( - "coordinates", - Field<Type>(pf.internalField(), uniqueMeshPointLabels), os, + coordKeyword, + UIndirectList<Type>(pf.internalField(), uniqueMeshPointLabels), parallel ); } // - // write faceZones, if requested + // Write requested faceZones - sorted by index // - const wordList zoneNames = zoneFaces.sortedToc(); - for (const word& zoneName : zoneNames) + for (const label zoneId : faceZoneParts.sortedToc()) { - const ensightFaces& part = zoneFaces[zoneName]; + const ensightFaces& part = faceZoneParts[zoneId]; uindirectPrimitivePatch p ( @@ -272,9 +305,9 @@ bool Foam::ensightOutput::Detail::writePointField Detail::writeFieldComponents ( - "coordinates", - Field<Type>(pf.internalField(), uniqueMeshPointLabels), os, + coordKeyword, + UIndirectList<Type>(pf.internalField(), uniqueMeshPointLabels), parallel ); } @@ -288,9 +321,9 @@ bool Foam::ensightOutput::Detail::writePointField template<class Type> bool Foam::ensightOutput::writeVolField ( + ensightFile& os, const GeometricField<Type, fvPatchField, volMesh>& vf, const ensightMesh& ensMesh, - ensightFile& os, const bool nodeValues ) { @@ -303,10 +336,10 @@ bool Foam::ensightOutput::writeVolField pfld.ref().checkOut(); pfld.ref().rename(vf.name()); - return Detail::writePointField<Type>(pfld, ensMesh, os); + return Detail::writePointField<Type>(os, pfld, ensMesh); } - return Detail::writeVolField<Type>(vf, ensMesh, os); + return Detail::writeVolField<Type>(os, vf, ensMesh); } @@ -315,73 +348,52 @@ bool Foam::ensightOutput::writeVolField template<class Type> bool Foam::ensightOutput::Serial::writeVolField ( + ensightFile& os, const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightPartFaces& part, - ensightFile& os + const ensightParts& list ) { - constexpr bool parallel = false; // serial + // serial only until the geometry is also in parallel + constexpr bool parallel = false; - const label patchi = part.patchIndex(); - - if (patchi >= 0 && patchi < vf.boundaryField().size()) + for (const ensightPart& item : list) { - return ensightOutput::Detail::writeFaceField - ( - vf.boundaryField()[patchi], - part, - os, - parallel - ); - } - - return false; -} + const ensightCells* cptr = isA<ensightCells>(item); + if (cptr) + { + const ensightCells& part = *cptr; -template<class Type> -bool Foam::ensightOutput::Serial::writeVolField -( - const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightPartCells& part, - ensightFile& os -) -{ - constexpr bool parallel = false; // serial - - return ensightOutput::Detail::writeCellField - ( - vf.internalField(), - part, - os, - parallel - ); -} + ensightOutput::Detail::writeField + ( + os, + vf.internalField(), + part, + parallel + ); + continue; + } -template<class Type> -bool Foam::ensightOutput::Serial::writeVolField -( - const GeometricField<Type, fvPatchField, volMesh>& vf, - const ensightParts& list, - ensightFile& os -) -{ - for (const ensightPart& part : list) - { - const ensightPartFaces* fptr = isA<ensightPartFaces>(part); + const ensightFaces* fptr = isA<ensightFaces>(item); if (fptr) { - Serial::writeVolField(vf, *fptr, os); - continue; - } + const ensightFaces& part = *fptr; - const ensightPartCells* cptr = isA<ensightPartCells>(part); + const label patchi = part.identifier(); - if (cptr) - { - Serial::writeVolField(vf, *cptr, os); + if (patchi >= 0 && patchi < vf.boundaryField().size()) + { + ensightOutput::Detail::writeField + ( + os, + vf.boundaryField()[patchi], + part, + parallel, + true // localField + ); + } continue; } } diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files index 62f54aaba6c..56ce6a6e48b 100644 --- a/src/fileFormats/Make/files +++ b/src/fileFormats/Make/files @@ -8,11 +8,19 @@ ensight/file/ensightFile.C ensight/file/ensightGeoFile.C ensight/part/ensightCells.C +ensight/part/ensightCellsAddr.C ensight/part/ensightFaces.C ensight/part/ensightPart.C ensight/part/ensightPartCells.C +ensight/part/ensightPartCellsAddr.C +ensight/part/ensightPartCellsIO.C ensight/part/ensightPartFaces.C +ensight/part/ensightPartFacesAddr.C +ensight/part/ensightPartFacesIO.C ensight/part/ensightParts.C +ensight/part/ensightOutputSurface.C + +ensight/output/ensightOutput.C ensight/read/ensightReadFile.C ensight/type/ensightPTraits.C diff --git a/src/fileFormats/ensight/file/ensightCase.C b/src/fileFormats/ensight/file/ensightCase.C index 7e6e6be5f18..9c0e3595377 100644 --- a/src/fileFormats/ensight/file/ensightCase.C +++ b/src/fileFormats/ensight/file/ensightCase.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2018 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,15 +26,10 @@ License \*---------------------------------------------------------------------------*/ #include "ensightCase.H" -#include "stringListOps.H" +#include "ensightGeoFile.H" #include "Time.H" #include "cloud.H" #include "IOmanip.H" -#include "globalIndex.H" - -#include "ensightFile.H" -#include "ensightGeoFile.H" -#include "demandDrivenData.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -69,7 +64,7 @@ void Foam::ensightCase::initialize() else { DetailInfo - <<"Warning: re-using existing directory" << nl + << "Warning: re-using existing directory" << nl << " " << ensightDir_ << endl; } } @@ -78,7 +73,7 @@ void Foam::ensightCase::initialize() mkDir(dataDir()); // The case file is always ASCII - os_ = new OFstream(ensightDir_/caseName_, IOstream::ASCII); + os_.reset(new OFstream(ensightDir_/caseName_, IOstream::ASCII)); // Format options os_->setf(ios_base::left); @@ -126,7 +121,7 @@ Foam::label Foam::ensightCase::checkTimeset(const labelHashSet& lookup) const void Foam::ensightCase::writeHeader() const { - if (os_) // master only + if (os_) // True on master only { this->rewind(); *os_ @@ -218,7 +213,7 @@ void Foam::ensightCase::writeTimeset const scalar timeCorrection ) const { - // make a copy + // Make a copy labelHashSet hashed(lookup); hashed.erase(-1); @@ -282,9 +277,10 @@ void Foam::ensightCase::noteGeometry(const bool moving) const void Foam::ensightCase::noteCloud(const word& cloudName) const { + // Force into existence if (!cloudVars_.found(cloudName)) { - cloudVars_.insert(cloudName, HashTable<string>()); + cloudVars_.emplace(cloudName); } cloudTimes_.insert(timeIndex_); @@ -388,9 +384,9 @@ Foam::ensightCase::ensightCase ) : options_(new options(opts)), + os_(nullptr), ensightDir_(ensightDir), caseName_(caseName + ".case"), - os_(nullptr), changed_(false), timeIndex_(0), timeValue_(0), @@ -398,6 +394,7 @@ Foam::ensightCase::ensightCase geomTimes_(), cloudTimes_(), variables_(), + nodeVariables_(), cloudVars_() { initialize(); @@ -412,9 +409,9 @@ Foam::ensightCase::ensightCase ) : options_(new options(format)), + os_(nullptr), ensightDir_(ensightDir), caseName_(caseName + ".case"), - os_(nullptr), changed_(false), timeIndex_(0), timeValue_(0), @@ -422,21 +419,13 @@ Foam::ensightCase::ensightCase geomTimes_(), cloudTimes_(), variables_(), + nodeVariables_(), cloudVars_() { initialize(); } -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::ensightCase::~ensightCase() -{ - deleteDemandDrivenData(options_); - deleteDemandDrivenData(os_); -} - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // void Foam::ensightCase::nextTime(const scalar value) @@ -580,7 +569,7 @@ void Foam::ensightCase::write() const // if (variables_.size() || cloudVars_.size()) { - // start of variables + // Start of variables *os_ << nl << "VARIABLE" << nl; @@ -598,7 +587,7 @@ void Foam::ensightCase::write() const << ensType.c_str() << ( - nodeValues() + (nodeVariables_.found(varName) || nodeValues()) ? " per node: 1 " // time-set 1 : " per element: 1 " // time-set 1 ) @@ -678,7 +667,7 @@ void Foam::ensightCase::write() const Foam::autoPtr<Foam::ensightGeoFile> Foam::ensightCase::newGeometry ( - const bool moving + bool moving ) const { autoPtr<Foam::ensightGeoFile> output; @@ -749,8 +738,12 @@ Foam::Ostream& Foam::ensightCase::printInfo(Ostream& os) const os << "Ensight case:" << nl << " path: " << ensightDir_ << nl << " name: " << caseName_ << nl - << " format: " << format() << nl - << " values per " << (nodeValues() ? "node" : "element") << nl; + << " format: " << format() << nl; + + if (nodeValues()) + { + os << " values per node" << nl; + } return os; } diff --git a/src/fileFormats/ensight/file/ensightCase.H b/src/fileFormats/ensight/file/ensightCase.H index 84791279397..d754fbee326 100644 --- a/src/fileFormats/ensight/file/ensightCase.H +++ b/src/fileFormats/ensight/file/ensightCase.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,6 +32,9 @@ Description SourceFiles ensightCase.C + ensightCaseI.H + ensightCaseOptions.C + ensightCaseTemplates.C \*---------------------------------------------------------------------------*/ @@ -42,17 +45,18 @@ SourceFiles #include "HashSet.H" #include "InfoProxy.H" #include "Map.H" +#include "HashSet.H" #include "OSspecific.H" #include "Pstream.H" - #include "ensightGeoFile.H" +#include <memory> // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -// Forward declarations +// Forward Declarations class ensightCase; class instant; class Time; @@ -65,7 +69,7 @@ class ensightCase { public: - // Forward declarations + // Forward Declarations class options; // Public Data @@ -76,12 +80,16 @@ public: //- The name for geometry files static const char* geometryName; + private: - // Private data + // Private Data //- Case writing options - const options* options_; + const std::unique_ptr<options> options_; + + //- Output stream (master only) + mutable std::unique_ptr<OFstream> os_; //- Output path (absolute) fileName ensightDir_; @@ -89,9 +97,6 @@ private: //- Case name (with ".case" ending) word caseName_; - //- Output stream (master only) - mutable OFstream* os_; - //- Track state changes since last write mutable bool changed_; @@ -119,6 +124,9 @@ private: //- Fields/Variables with the ensight type mutable HashTable<string> variables_; + //- Remember fields that are to be treated as point data + mutable HashSet<string> nodeVariables_; + //- Cloud names and variables mutable HashTable<HashTable<string>> cloudVars_; @@ -214,7 +222,7 @@ public: //- Destructor - ~ensightCase(); + ~ensightCase() = default; // Member Functions @@ -236,7 +244,7 @@ public: //- Consistent zero-padded integer value inline word padded(const label i) const; - //- Use values per nodes instead of per element + //- Force use of values per node instead of per element inline bool nodeValues() const; //- Write clouds into their own directory instead in "data" directory @@ -269,8 +277,7 @@ public: // Addition of entries to case file //- Open stream for new geometry file (on master). - autoPtr<ensightGeoFile> newGeometry(const bool moving = false) const; - + autoPtr<ensightGeoFile> newGeometry(bool moving = false) const; //- Open stream for new cloud positions (on master). // Note the use of ensightFile, not ensightGeoFile. @@ -279,11 +286,14 @@ public: const word& cloudName ) const; - //- Open stream for new data file (on master), with current index. + // Optionally marking as containing POINT_DATA template<class Type> - autoPtr<ensightFile> newData(const word& varName) const; - + autoPtr<ensightFile> newData + ( + const word& varName, + const bool isPointData = false + ) const; //- Open stream for new cloud data file (on master), with current index. template<class Type> @@ -313,28 +323,29 @@ public: //- Configuration options for the ensightCase class ensightCase::options { -private: + // Private Data + + //- Ascii/Binary file output + IOstream::streamFormat format_; - //- Ascii/Binary file output - IOstream::streamFormat format_; + //- Remove existing directory and sub-directories on creation + bool overwrite_; - //- Width of mask for subdirectories - label width_; + //- Force use of values per node instead of per element + bool nodeValues_; - //- The '*' mask appropriate for subdirectories - word mask_; + //- Write clouds into their own directory + bool separateCloud_; - //- The printf format for zero-padded subdirectory numbers - string printf_; + //- Width of mask for subdirectories + label width_; - //- Remove existing directory and sub-directories on creation - bool overwrite_; + //- The '*' mask appropriate for subdirectories + word mask_; - //- Write values at nodes - bool nodeValues_; + //- The printf format for zero-padded subdirectory numbers + string printf_; - //- Write clouds into their own directory - bool separateCloud_; public: @@ -363,9 +374,6 @@ public: //- Remove existing directory and sub-directories on creation bool overwrite() const; - //- Use values per nodes instead of per element - bool nodeValues() const; - //- Write clouds into their own directory instead in "data" directory bool separateCloud() const; @@ -379,12 +387,20 @@ public: //- Remove existing directory and sub-directories on creation void overwrite(bool); - //- Use values per nodes instead of per element - void nodeValues(bool); - //- Write clouds into their own directory instead in "data" directory void separateCloud(bool); + + // Housekeeping + + //- Force use of values per node instead of per element + bool nodeValues() const; + + //- Force use of values per node instead of per element + // Deprecated(2020-02) - The newData() method with a second parameter + // is more flexible. + // \deprecated(2020-02) - newData() with second parameter + void nodeValues(bool); }; diff --git a/src/fileFormats/ensight/file/ensightCaseOptions.C b/src/fileFormats/ensight/file/ensightCaseOptions.C index f74cc5a7e85..f3a17563851 100644 --- a/src/fileFormats/ensight/file/ensightCaseOptions.C +++ b/src/fileFormats/ensight/file/ensightCaseOptions.C @@ -32,14 +32,14 @@ License Foam::ensightCase::options::options(IOstream::streamFormat format) : format_(format), - width_(0), - mask_(), - printf_(), overwrite_(false), nodeValues_(false), - separateCloud_(false) + separateCloud_(false), + width_(0), + mask_(), + printf_() { - width(8); // Ensures that mask and printf-format are properly resized + width(8); // Fill mask and setup printf-format } diff --git a/src/fileFormats/ensight/file/ensightCaseTemplates.C b/src/fileFormats/ensight/file/ensightCaseTemplates.C index ae496c95c25..c93332e2785 100644 --- a/src/fileFormats/ensight/file/ensightCaseTemplates.C +++ b/src/fileFormats/ensight/file/ensightCaseTemplates.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -34,7 +34,8 @@ template<class Type> Foam::autoPtr<Foam::ensightFile> Foam::ensightCase::newData ( - const word& name + const word& name, + const bool isPointData ) const { autoPtr<ensightFile> output; @@ -42,9 +43,10 @@ Foam::ensightCase::newData if (Pstream::master()) { const ensight::VarName varName(name); + output = createDataFile(varName); - // description + // Description output().write ( string @@ -55,8 +57,15 @@ Foam::ensightCase::newData ); output().newline(); - // note field variable for later use + // Remember the field variable for later use noteVariable(varName, ensightPTraits<Type>::typeName); + + + // Could warn about existing variables that changed representation + if (isPointData) + { + nodeVariables_.set(varName); + } } return output; @@ -78,7 +87,7 @@ Foam::ensightCase::newCloudData const ensight::VarName varName(name); output = createCloudFile(cloudName, varName); - // description + // Description output().write ( string @@ -89,7 +98,7 @@ Foam::ensightCase::newCloudData ); output().newline(); - // note cloud variable for later use + // Remember the cloud variable for later use noteCloud(cloudName, varName, ensightPTraits<Type>::typeName); } diff --git a/src/fileFormats/ensight/output/ensightOutput.C b/src/fileFormats/ensight/output/ensightOutput.C new file mode 100644 index 00000000000..50ab425a8c2 --- /dev/null +++ b/src/fileFormats/ensight/output/ensightOutput.C @@ -0,0 +1,490 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 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 "ensightOutput.H" + +#include "cell.H" +#include "cellShape.H" +#include "face.H" +#include "polyMesh.H" +#include "ListOps.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Sizes + +Foam::labelList Foam::ensightOutput::Detail::getFaceSizes +( + const UList<face>& faces +) +{ + labelList list(faces.size()); + + auto outIter = list.begin(); + + for (const face& f : faces) + { + *outIter = f.size(); + ++outIter; + } + + return list; +} + + +Foam::labelList Foam::ensightOutput::Detail::getFaceSizes +( + const UIndirectList<face>& faces +) +{ + labelList list(faces.size()); + + auto outIter = list.begin(); + + for (const face& f : faces) + { + *outIter = f.size(); + ++outIter; + } + + return list; +} + + +Foam::labelList Foam::ensightOutput::Detail::getPolysNFaces +( + const polyMesh& mesh, + const labelUList& addr +) +{ + const cellList& meshCells = mesh.cells(); + + labelList list(addr.size()); + + auto outIter = list.begin(); + + // The number of faces per element + for (const label cellId : addr) + { + *outIter = meshCells[cellId].size(); + ++outIter; + } + + return list; +} + + +Foam::labelList Foam::ensightOutput::Detail::getPolysNPointsPerFace +( + const polyMesh& mesh, + const labelUList& addr +) +{ + const cellList& meshCells = mesh.cells(); + const faceList& meshFaces = mesh.faces(); + + // Count the number of faces per element + + label nTotFaces = 0; + for (const label cellId : addr) + { + nTotFaces += meshCells[cellId].size(); + } + + labelList list(nTotFaces); + + auto outIter = list.begin(); + + // The number of points per element face + for (const label cellId : addr) + { + for (const label facei : meshCells[cellId]) + { + *outIter = meshFaces[facei].size(); + ++outIter; + } + } + + return list; +} + + +void Foam::ensightOutput::writeFaceList +( + ensightGeoFile& os, + const UList<face>& faces +) +{ + for (const face& f : faces) + { + for (const label labi : f) + { + os.write(labi + 1); + } + + os.newline(); + } +} + + +void Foam::ensightOutput::writeFaceList +( + ensightGeoFile& os, + const UIndirectList<face>& faces +) +{ + for (const face& f : faces) + { + for (const label labi : f) + { + os.write(labi + 1); + } + + os.newline(); + } +} + + +void Foam::ensightOutput::writeCellShapes +( + ensightGeoFile& os, + const UList<cellShape>& shapes +) +{ + for (const cellShape& cellPoints : shapes) + { + // Convert global -> local index + // (note: Ensight indices start with 1) + + // In ASCII, write one cell per line + for (const label pointi : cellPoints) + { + os.write(pointi + 1); + } + + os.newline(); + } +} + + +void Foam::ensightOutput::writePolysPoints +( + ensightGeoFile& os, + const polyMesh& mesh, + const labelUList& addr, + const labelList& pointMap +) +{ + const cellList& meshCells = mesh.cells(); + const faceList& meshFaces = mesh.faces(); + const labelList& owner = mesh.faceOwner(); + + for (const label cellId : addr) + { + for (const label faceId : meshCells[cellId]) + { + const face& f = meshFaces[faceId]; // face points (in global points) + + if (faceId < owner.size() && owner[faceId] != cellId) + { + // The neighbour of an internal face + // - write as face::reverseFace() + + os.write(pointMap[f[0]] + 1); + for (label pti = f.size()-1; pti > 0; --pti) + { + os.write(pointMap[f[pti]] + 1); + } + } + else + { + for (const label pointi : f) + { + os.write(pointMap[pointi] + 1); + } + } + + os.newline(); + } + } +} + + +void Foam::ensightOutput::writePolysPoints +( + ensightGeoFile& os, + const cellUList& meshCells, + const labelUList& addr, + const faceUList& meshFaces, + const labelUList& owner +) +{ + for (const label cellId : addr) + { + for (const label faceId : meshCells[cellId]) + { + // The face points (in global points) + const face& f = meshFaces[faceId]; + + if (faceId < owner.size() && owner[faceId] != cellId) + { + // The neighbour of an internal face + // - write as face::reverseFace() + + os.write(f[0] + 1); + for (label pti = f.size()-1; pti > 0; --pti) + { + os.write(f[pti] + 1); + } + } + else + { + for (const label pointi : f) + { + os.write(pointi + 1); + } + } + + os.newline(); + } + } +} + + +void Foam::ensightOutput::writeFaceConnectivity +( + ensightGeoFile& os, + const ensightFaces::elemType etype, + const label nTotal, + const faceUList& faces, + bool parallel +) +{ + if (!nTotal) + { + return; + } + + parallel = parallel && Pstream::parRun(); + + const label nSlaves = (parallel ? Pstream::nProcs() : 0); + + if (Pstream::master()) + { + os.writeKeyword(ensightFaces::key(etype)); + os.write(nTotal); + os.newline(); + } + + if (etype == ensightFaces::NSIDED) + { + // Face sizes (number of points per face) + + labelList send(ensightOutput::Detail::getFaceSizes(faces)); + + if (Pstream::master()) + { + os.writeLabels(send); + + for (int slave=1; slave < nSlaves; ++slave) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + labelList recv(fromSlave); + + os.writeLabels(recv); + } + } + else if (nSlaves) + { + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + toMaster << send; + } + } + + + // List of points id for each face + if (Pstream::master()) + { + writeFaceList(os, faces); + + for (int slave=1; slave < nSlaves; ++slave) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + List<face> recv(fromSlave); + + writeFaceList(os, recv); + } + } + else if (nSlaves) + { + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + toMaster << faces; + } +} + + +void Foam::ensightOutput::writeFaceConnectivity +( + ensightGeoFile& os, + const ensightFaces::elemType etype, + const label nTotal, + const UIndirectList<face>& faces, + bool parallel +) +{ + if (!nTotal) + { + return; + } + + parallel = parallel && Pstream::parRun(); + + const label nSlaves = (parallel ? Pstream::nProcs() : 0); + + if (Pstream::master()) + { + os.writeKeyword(ensightFaces::key(etype)); + os.write(nTotal); + os.newline(); + } + + if (etype == ensightFaces::NSIDED) + { + // Face sizes (number of points per face) + + labelList send(ensightOutput::Detail::getFaceSizes(faces)); + + if (Pstream::master()) + { + os.writeLabels(send); + + for (int slave=1; slave < nSlaves; ++slave) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + labelList recv(fromSlave); + + os.writeLabels(recv); + } + } + else if (nSlaves) + { + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + toMaster << send; + } + } + + + // List of points id per face + if (Pstream::master()) + { + writeFaceList(os, faces); + + for (int slave=1; slave < nSlaves; ++slave) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + List<face> recv(fromSlave); + + writeFaceList(os, recv); + } + } + else if (nSlaves) + { + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + toMaster << faces; + } +} + + +void Foam::ensightOutput::writeFaceConnectivity +( + ensightGeoFile& os, + const ensightFaces& part, + const faceUList& faces, + bool parallel +) +{ + for (label typei=0; typei < ensightFaces::nTypes; ++typei) + { + const auto etype = ensightFaces::elemType(typei); + + writeFaceConnectivity + ( + os, + etype, + part.total(etype), + UIndirectList<face>(faces, part.faceIds(etype)), + parallel + ); + } +} + + +void Foam::ensightOutput::writeFaceConnectivityPresorted +( + ensightGeoFile& os, + const ensightFaces& part, + const faceUList& faces, + bool parallel +) +{ + for (label typei=0; typei < ensightFaces::nTypes; ++typei) + { + const auto etype = ensightFaces::elemType(typei); + + writeFaceConnectivity + ( + os, + etype, + part.total(etype), + SubList<face>(faces, part.range(etype)), + parallel + ); + } +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/output/ensightOutput.H b/src/fileFormats/ensight/output/ensightOutput.H index 4c6a23fb78c..35d3893bbe9 100644 --- a/src/fileFormats/ensight/output/ensightOutput.H +++ b/src/fileFormats/ensight/output/ensightOutput.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -30,6 +30,7 @@ Description A collection of functions for writing ensight file content. SourceFiles + ensightOutput.C ensightOutputTemplates.C \*---------------------------------------------------------------------------*/ @@ -38,18 +39,173 @@ SourceFiles #define ensightOutput_H #include "ensightFile.H" +#include "ensightGeoFile.H" #include "ensightCells.H" #include "ensightFaces.H" #include "ensightPTraits.H" +#include "faceListFwd.H" +#include "cellListFwd.H" + +#include "ListOps.H" +#include "ListListOps.H" +#include "IndirectList.H" + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Local definitions, could be relocated to ListListOps directly namespace Foam { +namespace ListListOps +{ + +//- Return the sizes of the sub-lists +template<class T, class Addr, class AccessOp> +labelList subSizes +( + const IndirectListBase<T, Addr>& lists, + AccessOp aop +) +{ + labelList output(lists.size()); + auto out = output.begin(); + + for (const T& sub : lists) + { + *out = aop(sub).size(); + ++out; + } + + return output; +} + + +//- Inplace renumber the values (not the indices) of a list of lists. +// Negative IntListType elements are left untouched. +template<class IntListType> +void inplaceRenumber +( + const labelUList& oldToNew, + IntListType& lists +) +{ + for (auto& sub : lists) + { + for (auto& item : sub) + { + if (item >= 0) + { + item = oldToNew[item]; + } + } + } +} + +} // End namespace ListListOps +} // End namespace Foam + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward Declarations +class cellShape; +class polyMesh; + namespace ensightOutput { +//- Write list of faces +void writeFaceList +( + ensightGeoFile& os, + const UList<face>& faces +); + +//- Write list of faces +void writeFaceList +( + ensightGeoFile& os, + const UIndirectList<face>& faces +); + +//- Write cell connectivity via cell shapes +void writeCellShapes +( + ensightGeoFile& os, + const UList<cellShape>& shapes +); + + +//- Write the point ids per poly element. +// Points have been already renumbered +void writePolysPoints +( + ensightGeoFile& os, + const cellUList& meshCells, + const labelUList& addr, //!< Cell ids to write + const faceUList& meshFaces, + const labelUList& faceOwner +); + +//- Write the point ids per poly element, with point renumbering +void writePolysPoints +( + ensightGeoFile& os, + const polyMesh& mesh, + const labelUList& addr, //!< Cell ids to write + const labelList& pointMap //!< Point map to use +); + + +//- Write the regular face connectivity for specified type and +//- and specified faces +void writeFaceConnectivity +( + ensightGeoFile& os, + const ensightFaces::elemType etype, + const label nTotal, + const UIndirectList<face>& faces, + bool parallel //!< Collective write? +); + + +//- Write the regular face connectivity for specified type +void writeFaceConnectivity +( + ensightGeoFile& os, + const ensightFaces::elemType etype, + const label nTotal, + const faceUList& faces, + bool parallel //!< Collective write? +); + + +//- Write the face connectivity for the part +void writeFaceConnectivity +( + ensightGeoFile& os, + const ensightFaces& part, + const faceUList& faces, + bool parallel //!< Collective write? +); + + +//- Write the \b presorted face connectivity for the part +// This is a special case when the list of faces is already in +// ensight sorted order +void writeFaceConnectivityPresorted +( + ensightGeoFile& os, + const ensightFaces& part, + const faceUList& faces, + bool parallel //!< Collective write? +); + + /*---------------------------------------------------------------------------*\ Namespace ensightOutput::Detail \*---------------------------------------------------------------------------*/ @@ -60,53 +216,91 @@ namespace ensightOutput namespace Detail { +//- Return sizes of faces in the list +labelList getFaceSizes(const UList<face>& faces); + +//- Return sizes of faces in the list +labelList getFaceSizes(const UIndirectList<face>& faces); + +//- The number of faces per poly element +labelList getPolysNFaces(const polyMesh& mesh, const labelUList& addr); + +//- The number of points for each face of the poly elements +labelList getPolysNPointsPerFace(const polyMesh& mesh, const labelUList& addr); + + +//- Copy specified field component into a scalarField +// works for various lists types +template<template<typename> class FieldContainer, class Type> +void copyComponent +( + scalarField& res, + const FieldContainer<Type>& input, + const direction cmpt +); + + +//- Write coordinates (component-wise) for the given part +template<template<typename> class FieldContainer> +bool writeCoordinates +( + ensightGeoFile& os, + const label partId, + const word& partName, + const label nPoints, + const FieldContainer<Foam::point>& fld, + bool parallel //!< Collective write? +); + + //- Write field content (component-wise) for the given ensight element type template<template<typename> class FieldContainer, class Type> bool writeFieldComponents ( + ensightFile& os, const char* key, const FieldContainer<Type>& fld, - ensightFile& os, - bool parallel //!< Collective write? + bool parallel //!< Collective write? ); +//- Write a field of cell values as an indirect list, +//- using the cell ids from ensightCells +template<class Type> +bool writeField +( + ensightFile& os, + const Field<Type>& fld, + const ensightCells& part, + bool parallel, //!< Collective write? + const bool localField=false //!< Use localIds instead? +); + //- Write a field of faces values as an indirect list, //- using the face ids from ensightFaces template<class Type> -bool writeFaceField +bool writeField ( + ensightFile& os, const Field<Type>& fld, const ensightFaces& part, - ensightFile& os, - bool parallel //!< Collective write? + bool parallel, //!< Collective write? + const bool localField=false //!< Use localIds instead? ); //- Write a sub-field of faces values as an indirect list, -//- using the sublist sizing information from ensightFaces +//- using the sub-list sizing information from ensightFaces template<class Type> bool writeFaceSubField ( + ensightFile& os, const Field<Type>& fld, const ensightFaces& part, - ensightFile& os, - bool parallel //!< Collective write? + bool parallel //!< Collective write? ); - -//- Write a field of cell values as an indirect list, -//- using the cell ids from ensightCells -template<class Type> -bool writeCellField -( - const Field<Type>& fld, - const ensightCells& part, - ensightFile& os, - bool parallel //!< Collective write? -); - } // End namespace Detail @@ -123,9 +317,9 @@ namespace Serial template<class Type> bool writePointField ( + ensightFile& os, const Field<Type>& fld, - const ensightFaces& part, - ensightFile& os + const ensightFaces& part ); } // End namespace Serial diff --git a/src/fileFormats/ensight/output/ensightOutputTemplates.C b/src/fileFormats/ensight/output/ensightOutputTemplates.C index 13a9eeaa01a..19b716252b8 100644 --- a/src/fileFormats/ensight/output/ensightOutputTemplates.C +++ b/src/fileFormats/ensight/output/ensightOutputTemplates.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2019 OpenCFD Ltd. + Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -30,74 +30,150 @@ License // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +template<template<typename> class FieldContainer, class Type> +void Foam::ensightOutput::Detail::copyComponent +( + scalarField& res, + const FieldContainer<Type>& input, + const direction cmpt +) +{ + res.resize(input.size()); + + auto iter = res.begin(); + + for (const Type& val : input) + { + *iter = component(val, cmpt); + ++iter; + } +} + + +template<template<typename> class FieldContainer> +bool Foam::ensightOutput::Detail::writeCoordinates +( + ensightGeoFile& os, + const label partId, + const word& partName, + const label nPoints, + const FieldContainer<Foam::point>& fld, + bool parallel +) +{ + parallel = parallel && Pstream::parRun(); + + const label nSlaves = (parallel ? Pstream::nProcs() : 0); + + // Using manual copyComponent(...) instead of fld.component() to support + // indirect lists etc. + + scalarField send(fld.size()); + + if (Pstream::master()) + { + // Serial output, or parallel (master) + + os.beginPart(partId, partName); + os.beginCoordinates(nPoints); + + for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) + { + copyComponent(send, fld, cmpt); + os.writeList(send); + + for (int slave=1; slave < nSlaves; ++slave) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + scalarField recv(fromSlave); + os.writeList(recv); + } + } + } + else if (nSlaves) + { + // Parallel (slaves) + + for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) + { + copyComponent(send, fld, cmpt); + + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + toMaster << send; + } + } + + return true; +} + + template<template<typename> class FieldContainer, class Type> bool Foam::ensightOutput::Detail::writeFieldComponents ( + ensightFile& os, const char* key, const FieldContainer<Type>& fld, - ensightFile& os, bool parallel ) { - // Preliminary checks - // ~~~~~~~~~~~~~~~~~~ - parallel = parallel && Pstream::parRun(); - bool hasField = !fld.empty(); + const label nSlaves = (parallel ? Pstream::nProcs() : 0); - if (parallel) + // Preliminary checks { - reduce(hasField, orOp<bool>()); + bool hasField = !fld.empty(); + + if (parallel) + { + reduce(hasField, orOp<bool>()); + } + + // No field + if (!hasField) return false; } - // Nothing to write - if (!hasField) return false; - // End preliminary checks - // ~~~~~~~~~~~~~~~~~~~~~~ + // Using manual copyComponent(...) instead of fld.component() to support + // indirect lists etc. + scalarField send(fld.size()); if (Pstream::master()) { + // Serial output, or parallel (master) + os.writeKeyword(key); - if (!parallel) + for (direction d=0; d < pTraits<Type>::nComponents; ++d) { - // Serial output - for (direction d=0; d < pTraits<Type>::nComponents; ++d) - { - const label cmpt = ensightPTraits<Type>::componentOrder[d]; + const direction cmpt = ensightPTraits<Type>::componentOrder[d]; - os.writeList(fld.component(cmpt)); - } - } - else - { - // Parallel (master) + copyComponent(send, fld, cmpt); + os.writeList(send); - for (direction d=0; d < pTraits<Type>::nComponents; ++d) + for (label slave=1; slave < nSlaves; ++slave) { - const label cmpt = ensightPTraits<Type>::componentOrder[d]; - - os.writeList(fld.component(cmpt)); - - for (int slave=1; slave<Pstream::nProcs(); ++slave) - { - IPstream fromSlave(Pstream::commsTypes::scheduled, slave); - scalarField received(fromSlave); - os.writeList(received); - } + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + scalarField recv(fromSlave); + os.writeList(recv); } } } - else if (parallel) + else if (nSlaves) { // Parallel (slaves) for (direction d=0; d < pTraits<Type>::nComponents; ++d) { - const label cmpt = ensightPTraits<Type>::componentOrder[d]; + const direction cmpt = ensightPTraits<Type>::componentOrder[d]; + + copyComponent(send, fld, cmpt); OPstream toMaster ( @@ -105,8 +181,7 @@ bool Foam::ensightOutput::Detail::writeFieldComponents Pstream::masterNo() ); - toMaster - << fld.component(cmpt); + toMaster << send; } } @@ -114,50 +189,62 @@ bool Foam::ensightOutput::Detail::writeFieldComponents } + template<class Type> -bool Foam::ensightOutput::Detail::writeFaceField +bool Foam::ensightOutput::Detail::writeField ( - const Field<Type>& fld, - const ensightFaces& part, ensightFile& os, - bool parallel + const Field<Type>& fld, + const ensightCells& part, + bool parallel, + const bool localField ) { - // Preliminary checks - // ~~~~~~~~~~~~~~~~~~ - parallel = parallel && Pstream::parRun(); - bool hasGeom = (parallel ? part.total() : part.size()); - bool hasField = !fld.empty(); - - if (parallel) + // Preliminary checks: total() contains pre-reduced information { - // Used 'pre-reduced' information for hasGeom - reduce(hasField, orOp<bool>()); - } + // No geometry + if (parallel ? !part.total() : !part.size()) return false; - // Nothing to write - if (!hasGeom || !hasField) return false; + bool hasField = !fld.empty(); - // End preliminary checks - // ~~~~~~~~~~~~~~~~~~~~~~ + if (parallel) + { + reduce(hasField, orOp<bool>()); + } + // No field + if (!hasField) return false; + } if (Pstream::master()) { os.beginPart(part.index()); } - for (int typei=0; typei < ensightFaces::nTypes; ++typei) + + labelList localAddr; + + for (int typei=0; typei < ensightCells::nTypes; ++typei) { - const ensightFaces::elemType what = ensightFaces::elemType(typei); + const auto etype = ensightCells::elemType(typei); - writeFieldComponents + const labelUList ids(part.cellIds(etype)); + + const labelUList* idsPtr = &ids; + + if (localField && part.start()) + { + localAddr = std::move(part.localIds(etype)); + idsPtr = &localAddr; + } + + Detail::writeFieldComponents ( - ensightFaces::key(what), - Field<Type>(fld, part.faceIds(what)), os, + ensightCells::key(etype), + UIndirectList<Type>(fld, *idsPtr), parallel ); } @@ -167,33 +254,32 @@ bool Foam::ensightOutput::Detail::writeFaceField template<class Type> -bool Foam::ensightOutput::Detail::writeFaceSubField +bool Foam::ensightOutput::Detail::writeField ( + ensightFile& os, const Field<Type>& fld, const ensightFaces& part, - ensightFile& os, - bool parallel + bool parallel, + const bool localField ) { - // Preliminary checks - // ~~~~~~~~~~~~~~~~~~ - parallel = parallel && Pstream::parRun(); - bool hasGeom = (parallel ? part.total() : part.size()); - bool hasField = !fld.empty(); - - if (parallel) + // Preliminary checks: total() contains pre-reduced information { - // Used 'pre-reduced' information for hasGeom - reduce(hasField, orOp<bool>()); - } + // No geometry + if (parallel ? !part.total() : !part.size()) return false; - // Nothing to write - if (!hasGeom || !hasField) return false; + bool hasField = !fld.empty(); - // End preliminary checks - // ~~~~~~~~~~~~~~~~~~~~~~ + if (parallel) + { + reduce(hasField, orOp<bool>()); + } + + // No field + if (!hasField) return false; + } if (Pstream::master()) @@ -201,23 +287,29 @@ bool Foam::ensightOutput::Detail::writeFaceSubField os.beginPart(part.index()); } + labelList localAddr; - label start = 0; // The start of the sub-list for (int typei=0; typei < ensightFaces::nTypes; ++typei) { - const ensightFaces::elemType what = ensightFaces::elemType(typei); + const auto etype = ensightFaces::elemType(typei); + + const labelUList ids(part.faceIds(etype)); - const label size = part.faceIds(what).size(); + const labelUList* idsPtr = &ids; + + if (localField && part.start()) + { + localAddr = std::move(part.localIds(etype)); + idsPtr = &localAddr; + } writeFieldComponents ( - ensightFaces::key(what), - SubField<Type>(fld, size, start), os, + ensightFaces::key(etype), + UIndirectList<Type>(fld, *idsPtr), parallel ); - - start += size; // Advance the start for next sub-list } return true; @@ -225,32 +317,31 @@ bool Foam::ensightOutput::Detail::writeFaceSubField template<class Type> -bool Foam::ensightOutput::Serial::writePointField +bool Foam::ensightOutput::Detail::writeFaceSubField ( + ensightFile& os, const Field<Type>& fld, const ensightFaces& part, - ensightFile& os + bool parallel ) { - // Preliminary checks - // ~~~~~~~~~~~~~~~~~~ - - bool parallel = false && Pstream::parRun(); - - bool hasGeom = (parallel ? part.total() : part.size()); - bool hasField = !fld.empty(); + parallel = parallel && Pstream::parRun(); - if (parallel) + // Preliminary checks: total() contains pre-reduced information { - // Used 'pre-reduced' information for hasGeom - reduce(hasField, orOp<bool>()); - } + // No geometry + if (parallel ? !part.total() : !part.size()) return false; - // Nothing to write - if (!hasGeom || !hasField) return false; + bool hasField = !fld.empty(); + + if (parallel) + { + reduce(hasField, orOp<bool>()); + } - // End preliminary checks - // ~~~~~~~~~~~~~~~~~~~~~~ + // No field + if (!hasField) return false; + } if (Pstream::master()) @@ -258,46 +349,53 @@ bool Foam::ensightOutput::Serial::writePointField os.beginPart(part.index()); } - ensightOutput::Detail::writeFieldComponents - ( - "coordinates", - fld, - os, - parallel - ); + labelList localAddr; + + for (int typei=0; typei < ensightFaces::nTypes; ++typei) + { + const auto etype = ensightFaces::elemType(typei); + + writeFieldComponents + ( + os, + ensightFaces::key(etype), + SubField<Type>(fld, part.range(etype)), + parallel + ); + } return true; } template<class Type> -bool Foam::ensightOutput::Detail::writeCellField +bool Foam::ensightOutput::Serial::writePointField ( - const Field<Type>& fld, - const ensightCells& part, ensightFile& os, - bool parallel + const Field<Type>& fld, + const ensightFaces& part ) { - // Preliminary checks - // ~~~~~~~~~~~~~~~~~~ - - parallel = parallel && Pstream::parRun(); + const char* coordKeyword = "coordinates"; - bool hasGeom = (parallel ? part.total() : part.size()); - bool hasField = !fld.empty(); + // bool parallel = false && Pstream::parRun(); + constexpr bool parallel = false; - if (parallel) + // Preliminary checks: total() contains pre-reduced information { - // Used 'pre-reduced' information for hasGeom - reduce(hasField, orOp<bool>()); - } + // No geometry + if (parallel ? !part.total() : !part.size()) return false; - // Nothing to write - if (!hasGeom || !hasField) return false; + bool hasField = !fld.empty(); - // End preliminary checks - // ~~~~~~~~~~~~~~~~~~~~~~ + if (parallel) + { + reduce(hasField, orOp<bool>()); + } + + // No field + if (!hasField) return false; + } if (Pstream::master()) @@ -305,18 +403,13 @@ bool Foam::ensightOutput::Detail::writeCellField os.beginPart(part.index()); } - for (int typei=0; typei < ensightCells::nTypes; ++typei) - { - const ensightCells::elemType what = ensightCells::elemType(typei); - - Detail::writeFieldComponents - ( - ensightCells::key(what), - Field<Type>(fld, part.cellIds(what)), - os, - parallel - ); - } + ensightOutput::Detail::writeFieldComponents + ( + os, + coordKeyword, + fld, + parallel + ); return true; } diff --git a/src/fileFormats/ensight/part/ensightCells.C b/src/fileFormats/ensight/part/ensightCells.C index 728366cee1a..e7f59bedc6c 100644 --- a/src/fileFormats/ensight/part/ensightCells.C +++ b/src/fileFormats/ensight/part/ensightCells.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -33,6 +33,13 @@ License // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // +namespace Foam +{ + defineTypeNameAndDebug(ensightCells, 0); +} + +static_assert(Foam::ensightCells::nTypes == 5); + const char* Foam::ensightCells::elemNames[5] = { "tetra4", "pyramid5", "penta6", "hexa8", "nfaced" }; @@ -41,23 +48,22 @@ const char* Foam::ensightCells::elemNames[5] = void Foam::ensightCells::resizeAll() { - // overall required size - label n = 0; - forAll(sizes_, typei) - { - n += sizes_[typei]; - } - address_.setSize(n, Zero); + // Assign sub-list offsets, determine overall size - // assign corresponding sub-lists - n = 0; - forAll(sizes_, typei) + label len = 0; + + auto iter = offsets_.begin(); + + *iter = 0; + for (const label n : sizes_) { - slices_[typei].setStart(n); - slices_[typei].setSize(sizes_[typei]); + len += n; - n += sizes_[typei]; + *(++iter) = len; } + + // The addressing space + addressing().resize(len, Zero); } @@ -65,39 +71,34 @@ void Foam::ensightCells::resizeAll() Foam::ensightCells::ensightCells() : - ensightCells(0) + ensightPart(), + offsets_(Zero), + sizes_(Zero) {} -Foam::ensightCells::ensightCells(const label partIndex) +Foam::ensightCells::ensightCells(const string& description) : - index_(partIndex), - address_(), - slices_(), - sizes_(Zero) + ensightCells() { - resizeAll(); // adjust allocation/sizing + rename(description); } -Foam::ensightCells::ensightCells(const ensightCells& obj) +Foam::ensightCells::ensightCells(const label partIndex) : - index_(obj.index_), - address_(obj.address_), - slices_(), - sizes_() + ensightCells() { - // Save the total (reduced) sizes - FixedList<label, 5> totSizes = obj.sizes_; - - // Need local sizes for the resize operation - this->sizes_ = obj.sizes(); + index() = partIndex; +} - resizeAll(); // Adjust allocation/sizing - // Restore total (reduced) sizes - this->sizes_ = totSizes; -} +Foam::ensightCells::ensightCells(const ensightCells& rhs) +: + ensightPart(rhs), + offsets_(rhs.offsets_), + sizes_(rhs.sizes_) +{} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // @@ -105,9 +106,10 @@ Foam::ensightCells::ensightCells(const ensightCells& obj) Foam::FixedList<Foam::label, 5> Foam::ensightCells::sizes() const { FixedList<label, 5> count; - forAll(slices_, typei) + + forAll(count, typei) { - count[typei] = slices_[typei].size(); + count[typei] = size(elemType(typei)); } return count; @@ -127,17 +129,25 @@ Foam::label Foam::ensightCells::total() const void Foam::ensightCells::clear() { - sizes_ = Zero; // reset sizes - resizeAll(); + clearOut(); + + ensightPart::clear(); + + sizes_ = Zero; + offsets_ = Zero; } +void Foam::ensightCells::clearOut() +{} + + void Foam::ensightCells::reduce() { // No listCombineGather, listCombineScatter for FixedList forAll(sizes_, typei) { - sizes_[typei] = slices_[typei].size(); + sizes_[typei] = size(elemType(typei)); Foam::reduce(sizes_[typei], sumOp<label>()); } } @@ -145,12 +155,15 @@ void Foam::ensightCells::reduce() void Foam::ensightCells::sort() { - forAll(slices_, typei) + for (int typei=0; typei < nTypes; ++typei) { - if (slices_[typei].size()) + const labelRange sub(range(elemType(typei))); + + if (!sub.empty()) { - SubList<label> idLst(address_, slices_[typei]); - Foam::sort(idLst); + SubList<label> ids(addressing(), sub); + + Foam::sort(ids); } } } @@ -178,59 +191,56 @@ void Foam::ensightCells::classifyImpl { const cellModel& model = shapes[id].model(); - enum elemType what = NFACED; + elemType etype(NFACED); if (model == tet) { - what = TETRA4; + etype = TETRA4; } else if (model == pyr) { - what = PYRAMID5; + etype = PYRAMID5; } else if (model == prism) { - what = PENTA6; + etype = PENTA6; } else if (model == hex) { - what = HEXA8; + etype = HEXA8; } - sizes_[what]++; + ++sizes_[etype]; } resizeAll(); // adjust allocation sizes_ = Zero; // reset sizes - use for local indexing here + // Pass 2: Assign cell-id per shape type for (const label id : cellIds) { const cellModel& model = shapes[id].model(); - enum elemType what = NFACED; + elemType etype(NFACED); if (model == tet) { - what = TETRA4; + etype = TETRA4; } else if (model == pyr) { - what = PYRAMID5; + etype = PYRAMID5; } else if (model == prism) { - what = PENTA6; + etype = PENTA6; } else if (model == hex) { - what = HEXA8; + etype = HEXA8; } - // eg, the processor local cellId - labelUList slice = address_[slices_[what]]; - - slice[sizes_[what]] = id; - sizes_[what]++; + add(etype, id); } } @@ -262,4 +272,29 @@ void Foam::ensightCells::classify } +void Foam::ensightCells::writeDict(Ostream& os, const bool full) const +{ + os.beginBlock(type()); + + os.writeEntry("id", index()+1); // Ensight starts with 1 + os.writeEntry("name", name()); + os.writeEntryIfDifferent<label>("start", start(), 0); + os.writeEntry("size", size()); + + if (full) + { + for (int typei=0; typei < ensightCells::nTypes; ++typei) + { + const auto etype = ensightCells::elemType(typei); + + os.writeKeyword(ensightCells::key(etype)); + + cellIds(etype).writeList(os, 0) << endEntry; // Flat output + } + } + + os.endBlock(); +} + + // ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightCells.H b/src/fileFormats/ensight/part/ensightCells.H index f2e3f3b9d3d..1bbee8c734a 100644 --- a/src/fileFormats/ensight/part/ensightCells.H +++ b/src/fileFormats/ensight/part/ensightCells.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -35,15 +35,16 @@ Description #ifndef ensightCells_H #define ensightCells_H -#include "labelList.H" +#include "ensightPart.H" #include "FixedList.H" +#include "Map.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -// Forward declarations +// Forward Declarations class bitSet; class polyMesh; @@ -52,55 +53,54 @@ class polyMesh; \*---------------------------------------------------------------------------*/ class ensightCells +: + public ensightPart { public: - // Public data + // Public Data - //- Addressable ensight element types + //- Supported ensight 'Cell' element types + // Must be zero-based since they are also for internal bookkeeping. enum elemType { - TETRA4, //!< "tetra4" + TETRA4 = 0, //!< "tetra4" PYRAMID5, //!< "pyramid5" PENTA6, //!< "penta6" HEXA8, //!< "hexa8" NFACED //!< "nfaced" }; - //- Number of element types (5) + //- Number of 'Cell' element types (5) static constexpr int nTypes = 5; - //- The ensight element type names - static const char* elemNames[5]; + //- The ensight 'Cell' element type names + static const char* elemNames[nTypes]; - // Static Member Functions + // Static Functions - //- Return the ensight element name for the specified type - inline static const char* key(const enum elemType); + //- The ensight element name for the specified 'Cell' type + inline static const char* key(const elemType etype); private: // Private Data - //- Location within a list. - // The ensight part number is typically this value +1. - label index_; - - //- Linear list of ids, sub-sectioned per element type by sub-lists - labelList address_; - - //- Slices (sub-lists) of the address ids for each element type. - FixedList<labelRange, 5> slices_; + //- Begin/end offsets for address of each element type + FixedList<label, nTypes+1> offsets_; //- List of global sizes for each element type. // Used temporarily for local sizes when building the element lists. - FixedList<label, 5> sizes_; + FixedList<label, nTypes> sizes_; // Private Member Functions + //- Low-level internal addition routine + inline void add(const elemType etype, label id); + //- Use temporarily stored sizes to redimension the element lists void resizeAll(); @@ -108,67 +108,89 @@ private: template<class Addressing> void classifyImpl(const polyMesh& mesh, const Addressing& cellIds); + +public: + + //- Declare type-name, virtual type (with debug switch) + TypeName("ensightCells"); + + + // Generated Methods + //- No copy assignment void operator=(const ensightCells&) = delete; + //- Move construct + ensightCells(ensightCells&&) = default; + + //- Move assignment + ensightCells& operator=(ensightCells&&) = default; + + //- Destructor + virtual ~ensightCells() = default; -public: // Constructors - //- Construct null, with part index 0 + //- Default construct, with part index 0 ensightCells(); - //- Construct null, with specified part index - explicit ensightCells(const label partIndex); - - //- Copy constructor. Needed for lists etc. - ensightCells(const ensightCells& obj); + //- Default construct, with description/partName + explicit ensightCells(const string& description); + //- Default construct, with specified part index + explicit ensightCells(const label partIndex); - //- Destructor - ~ensightCells() = default; + //- Copy construct + ensightCells(const ensightCells& rhs); // Member Functions // Access - //- The index in a list. - inline label index() const; - - //- The index in a list, non-const access. - inline label& index(); + //- Processor-local size of all elements. + using ensightPart::size; - //- The processor local size of all elements. - inline label size() const; + //- Processor-local size of the specified element type. + inline label size(const elemType etype) const; - //- The processor local size of the specified element type. - inline label size(const enum elemType) const; + //- Processor-local offset/size of element type. + inline labelRange range(const elemType etype) const; - //- The global number of the specified element type. + //- The global size of all element types. // This value is only meaningful after a reduce operation. - inline label total(const enum elemType) const; + label total() const; - //- The global number of all element types. + //- The global size of the specified element type. // This value is only meaningful after a reduce operation. - label total() const; + inline label total(const elemType etype) const; - //- The global numbers per element type. + //- The global sizes for each element type. // This value is only meaningful after a reduce operation. - inline const FixedList<label, 5>& totals() const; + inline const FixedList<label, nTypes>& totals() const; + + //- Processor-local sizes per element type. + FixedList<label, nTypes> sizes() const; - //- The processor local sizes per element type. - FixedList<label, 5> sizes() const; + //- Processor-local cell ids of all elements + inline const labelList& cellIds() const; - //- Processor local starting offset of element type. - inline label offset(const enum elemType what) const; + //- Processor-local cell ids of the specified element type + inline const labelUList cellIds(const elemType etype) const; - //- Return the (local) cell ids of the specified element type - inline const labelUList cellIds(const enum elemType) const; + //- Processor-local (cell) ids relative to start() + inline labelList localIds() const; - //- Return the cell ids of all elements - inline const labelUList& cellIds() const; + //- Processor-local (cell) ids relative to start() + inline labelList localIds(const elemType etype) const; + + + // Addressing + + //- Mesh point map. + // Map mesh point index to local (compact) point index + Map<label> meshPointMap(const polyMesh& mesh) const; // Edit @@ -184,6 +206,10 @@ public: //- using a subgroup of cells void classify(const polyMesh& mesh, const bitSet& selection); + + //- Clear any demand-driven data + void clearOut(); + //- Set addressable sizes to zero, free up addressing memory. void clear(); @@ -194,11 +220,11 @@ public: void sort(); - // Member Operators - - //- Return id from linear list of addressing. - inline label operator[](const label i) const; + // Output + //- Write information about the object as a dictionary, + //- optionally write all element addresses + virtual void writeDict(Ostream& os, const bool full=false) const; }; diff --git a/src/fileFormats/ensight/part/ensightCellsAddr.C b/src/fileFormats/ensight/part/ensightCellsAddr.C new file mode 100644 index 00000000000..1c936a04ffe --- /dev/null +++ b/src/fileFormats/ensight/part/ensightCellsAddr.C @@ -0,0 +1,64 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 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 "ensightCells.H" +#include "polyMesh.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::Map<Foam::label> +Foam::ensightCells::meshPointMap(const polyMesh& mesh) const +{ + const label nEstimate = 8*this->size(); + + Map<label> pointMap(nEstimate); + + // Pass 1: markup used points from cells + + for (const label celli : this->cellIds()) + { + for (const label facei : mesh.cells()[celli]) + { + for (const label pointi : mesh.faces()[facei]) + { + pointMap.insert(pointi, 0); + } + } + } + + // Compact point numbering, preserves the original order + label nPoints = 0; + for (const label pointi : pointMap.sortedToc()) + { + pointMap(pointi) = nPoints++; + } + + return pointMap; +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightCellsI.H b/src/fileFormats/ensight/part/ensightCellsI.H index dcac7ab0030..d0ebb601b6f 100644 --- a/src/fileFormats/ensight/part/ensightCellsI.H +++ b/src/fileFormats/ensight/part/ensightCellsI.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -25,76 +25,71 @@ License \*---------------------------------------------------------------------------*/ -#include "error.H" +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -inline const char* Foam::ensightCells::key(const enum elemType what) +inline void Foam::ensightCells::add(const elemType etype, label id) { - return elemNames[what]; -} - + // Linear addressing location + const label index = offsets_[etype] + sizes_[etype]++; -inline Foam::label Foam::ensightCells::index() const -{ - return index_; + addressing()[index] = id; } -inline Foam::label& Foam::ensightCells::index() +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +inline const char* Foam::ensightCells::key(const elemType etype) { - return index_; + return elemNames[etype]; } -inline Foam::label Foam::ensightCells::size() const +inline const Foam::FixedList<Foam::label,5>& Foam::ensightCells::totals() const { - return address_.size(); + return sizes_; } -inline const Foam::FixedList<Foam::label,5>& Foam::ensightCells::totals() const +inline Foam::label Foam::ensightCells::total(const elemType etype) const { - return sizes_; + return sizes_[etype]; } -inline Foam::label Foam::ensightCells::total(const enum elemType what) const +inline Foam::label Foam::ensightCells::size(const elemType etype) const { - return sizes_[what]; + return (offsets_[etype+1] - offsets_[etype]); } -inline Foam::label Foam::ensightCells::size(const enum elemType what) const +inline Foam::labelRange Foam::ensightCells::range(const elemType etype) const { - return slices_[what].size(); + return labelRange(offsets_[etype], offsets_[etype+1] - offsets_[etype]); } -inline Foam::label Foam::ensightCells::offset(const enum elemType what) const +inline const Foam::labelList& Foam::ensightCells::cellIds() const { - return slices_[what].start(); + return addressing(); } -inline const Foam::labelUList Foam::ensightCells::cellIds -( - const enum elemType what -) const +inline const Foam::labelUList +Foam::ensightCells::cellIds(const elemType etype) const { - return address_[slices_[what]]; + return addressing()[range(etype)]; } -inline const Foam::labelUList& Foam::ensightCells::cellIds() const +inline Foam::labelList Foam::ensightCells::localIds() const { - return address_; + return localAddressing(); } -inline Foam::label Foam::ensightCells::operator[](const label i) const +inline Foam::labelList Foam::ensightCells::localIds(const elemType etype) const { - return address_[i]; + return localAddressing(range(etype)); } diff --git a/src/fileFormats/ensight/part/ensightFaces.C b/src/fileFormats/ensight/part/ensightFaces.C index 425ebc6f968..009fa9bd523 100644 --- a/src/fileFormats/ensight/part/ensightFaces.C +++ b/src/fileFormats/ensight/part/ensightFaces.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2018 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -31,6 +31,13 @@ License // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // +namespace Foam +{ + defineTypeNameAndDebug(ensightFaces, 0); +} + +static_assert(Foam::ensightFaces::nTypes == 3); + const char* Foam::ensightFaces::elemNames[3] = { "tria3", "quad4", "nsided" }; @@ -40,7 +47,7 @@ const char* Foam::ensightFaces::elemNames[3] = namespace { -// Simple shape classifier +// Trivial shape classifier static inline Foam::ensightFaces::elemType whatType(const Foam::face& f) { return @@ -58,48 +65,26 @@ static inline Foam::ensightFaces::elemType whatType(const Foam::face& f) // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -// Only used in this file-scope -inline void Foam::ensightFaces::add -( - const face& f, - const label id, - const bool flip -) +void Foam::ensightFaces::resizeAll() { - const enum elemType what = whatType(f); - - // linear addressing: - const label index = offset(what) + sizes_[what]++; - - address_[index] = id; - if (flipMap_.size()) - { - flipMap_[index] = flip; - } -} + // Assign sub-list offsets, determine overall size + label len = 0; -void Foam::ensightFaces::resizeAll() -{ - // overall required size - label n = 0; - forAll(sizes_, typei) - { - n += sizes_[typei]; - } - address_.setSize(n, Zero); + auto iter = offsets_.begin(); - // assign corresponding sub-lists - n = 0; - forAll(sizes_, typei) + *iter = 0; + for (const label n : sizes_) { - slices_[typei].setStart(n); - slices_[typei].setSize(sizes_[typei]); + len += n; - n += sizes_[typei]; + *(++iter) = len; } - // normally assume no flipMap + // The addressing space + addressing().resize(len, Zero); + + // Normally assume no flipMap flipMap_.clear(); } @@ -108,40 +93,26 @@ void Foam::ensightFaces::resizeAll() Foam::ensightFaces::ensightFaces() : - ensightFaces(0) + ensightPart(), + flipMap_(), + offsets_(Zero), + sizes_(Zero) {} -Foam::ensightFaces::ensightFaces(const label partIndex) +Foam::ensightFaces::ensightFaces(const string& description) : - index_(partIndex), - address_(), - flipMap_(), - slices_(), - sizes_(Zero) + ensightFaces() { - resizeAll(); // adjust allocation/sizing + rename(description); } -Foam::ensightFaces::ensightFaces(const ensightFaces& obj) +Foam::ensightFaces::ensightFaces(const label partIndex) : - index_(obj.index_), - address_(obj.address_), - flipMap_(obj.flipMap_), - slices_(), - sizes_() + ensightFaces() { - // Save the total (reduced) sizes - FixedList<label, 3> totSizes = obj.sizes_; - - // Need local sizes for the resize operation - this->sizes_ = obj.sizes(); - - resizeAll(); // adjust allocation/sizing - - // Restore total (reduced) sizes - this->sizes_ = totSizes; + index() = partIndex; } @@ -150,9 +121,10 @@ Foam::ensightFaces::ensightFaces(const ensightFaces& obj) Foam::FixedList<Foam::label, 3> Foam::ensightFaces::sizes() const { FixedList<label, 3> count; - forAll(slices_, typei) + + forAll(count, typei) { - count[typei] = slices_[typei].size(); + count[typei] = size(elemType(typei)); } return count; @@ -172,17 +144,26 @@ Foam::label Foam::ensightFaces::total() const void Foam::ensightFaces::clear() { - sizes_ = Zero; // reset sizes - resizeAll(); + clearOut(); + + ensightPart::clear(); + + flipMap_.clear(); + sizes_ = Zero; + offsets_ = Zero; } +void Foam::ensightFaces::clearOut() +{} + + void Foam::ensightFaces::reduce() { // No listCombineGather, listCombineScatter for FixedList forAll(sizes_, typei) { - sizes_[typei] = slices_[typei].size(); + sizes_[typei] = size(elemType(typei)); Foam::reduce(sizes_[typei], sumOp<label>()); } } @@ -190,89 +171,123 @@ void Foam::ensightFaces::reduce() void Foam::ensightFaces::sort() { - if (flipMap_.size() == address_.size()) + const bool useFlip = (size() == flipMap_.size()); + + if (useFlip) { // Must sort flip map as well labelList order; - forAll(slices_, typei) + for (int typei=0; typei < nTypes; ++typei) { - if (slices_[typei].size()) + const labelRange sub(range(elemType(typei))); + + if (!sub.empty()) { - SubList<label> idLst(address_, slices_[typei]); - SubList<bool> flip(flipMap_, slices_[typei]); + SubList<label> ids(addressing(), sub); + SubList<bool> flips(flipMap_, sub); - Foam::sortedOrder(idLst, order); + Foam::sortedOrder(ids, order); - idLst = reorder<labelList>(order, idLst); - flip = reorder<boolList>(order, flip); + ids = reorder<labelList>(order, ids); + flips = reorder<boolList>(order, flips); } } } else { - // no flip-maps, simpler to sort - forAll(slices_, typei) + flipMap_.clear(); // Extra safety + + // No flip-maps, simply sort addresses + for (int typei=0; typei < nTypes; ++typei) { - if (slices_[typei].size()) + const labelRange sub(range(elemType(typei))); + + if (!sub.empty()) { - SubList<label> idLst(address_, slices_[typei]); - Foam::sort(idLst); + SubList<label> ids(addressing(), sub); + Foam::sort(ids); } } - - flipMap_.clear(); // for extra safety } } -void Foam::ensightFaces::classify(const faceList& faces) +void Foam::ensightFaces::classify(const UList<face>& faces) { - const label sz = faces.size(); + const label len = faces.size(); // Pass 1: Count the shapes sizes_ = Zero; // reset sizes - for (label listi = 0; listi < sz; ++listi) + for (label listi = 0; listi < len; ++listi) { - const enum elemType what = whatType(faces[listi]); - sizes_[what]++; + const auto etype = whatType(faces[listi]); + + ++sizes_[etype]; } resizeAll(); // adjust allocation sizes_ = Zero; // reset sizes - use for local indexing here + // Pass 2: Assign face-id per shape type - for (label listi = 0; listi < sz; ++listi) + for (label listi = 0; listi < len; ++listi) { - add(faces[listi], listi); + const auto etype = whatType(faces[listi]); + + add(etype, listi); } } void Foam::ensightFaces::classify ( - const faceList& faces, - const labelUList& addressing, + const UList<face>& faces, + const labelRange& range +) +{ + const labelRange slice(range.subset0(faces.size())); + + classify(SubList<face>(slice, faces)); + + // Adjust starting info + const label off = slice.start(); + + if (off) + { + for (label& val : addressing()) + { + val += off; + } + } +} + + +void Foam::ensightFaces::classify +( + const UList<face>& faces, + const labelUList& addr, const boolList& flipMap, const bitSet& exclude ) { - const label sz = addressing.size(); - const bool useFlip = (addressing.size() == flipMap.size()); + const label len = addr.size(); + const bool useFlip = (len == flipMap.size()); // Pass 1: Count the shapes sizes_ = Zero; // reset sizes - for (label listi = 0; listi < sz; ++listi) + for (label listi = 0; listi < len; ++listi) { - const label faceId = addressing[listi]; + const label faceId = addr[listi]; if (!exclude.test(faceId)) { - const enum elemType what = whatType(faces[faceId]); - sizes_[what]++; + const auto etype = whatType(faces[faceId]); + + ++sizes_[etype]; } } @@ -281,22 +296,50 @@ void Foam::ensightFaces::classify if (useFlip) { - flipMap_.setSize(address_.size(), false); + flipMap_.resize(len); flipMap_ = false; } // Pass 2: Assign face-id per shape type - for (label listi = 0; listi < sz; ++listi) + for (label listi = 0; listi < len; ++listi) { - const label faceId = addressing[listi]; + const label faceId = addr[listi]; const bool doFlip = useFlip && flipMap[listi]; if (!exclude.test(faceId)) { - add(faces[faceId], faceId, doFlip); + const auto etype = whatType(faces[faceId]); + + add(etype, faceId, doFlip); } } } + +void Foam::ensightFaces::writeDict(Ostream& os, const bool full) const +{ + os.beginBlock(type()); + + os.writeEntry("id", index()+1); // Ensight starts with 1 + os.writeEntry("name", name()); + os.writeEntryIfDifferent<label>("start", start(), 0); + os.writeEntry("size", size()); + + if (full) + { + for (int typei=0; typei < ensightFaces::nTypes; ++typei) + { + const auto etype = ensightFaces::elemType(typei); + + os.writeKeyword(ensightFaces::key(etype)); + + faceIds(etype).writeList(os, 0) << endEntry; // Flat output + } + } + + os.endBlock(); +} + + // ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightFaces.H b/src/fileFormats/ensight/part/ensightFaces.H index 307237279a8..359a79d7af8 100644 --- a/src/fileFormats/ensight/part/ensightFaces.H +++ b/src/fileFormats/ensight/part/ensightFaces.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2018 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,15 +27,18 @@ Class Foam::ensightFaces Description - Sorting/classification of faces (2D) into corresponding ensight types + Sorting/classification of faces (2D) into corresponding ensight types. + + Some caution may be required when handling face addressing into fields. + If it is a boundaryField, the local face ids should be used. \*---------------------------------------------------------------------------*/ #ifndef ensightFaces_H #define ensightFaces_H +#include "ensightPart.H" #include "boolList.H" -#include "labelList.H" #include "faceList.H" #include "FixedList.H" #include "bitSet.H" @@ -50,148 +53,164 @@ namespace Foam \*---------------------------------------------------------------------------*/ class ensightFaces +: + public ensightPart { public: // Public Data - //- Addressable ensight element types + //- Supported ensight 'Face' element types. + // Must be zero-based since they are also for internal bookkeeping. enum elemType { - TRIA3, //!< "tria3" + TRIA3 = 0, //!< "tria3" QUAD4, //!< "quad4" NSIDED //!< "nsided" }; - //- Number of element types (3) + //- Number of 'Face' element types (3) static constexpr int nTypes = 3; - //- The ensight element type names - static const char* elemNames[3]; + //- The ensight 'Face' element type names + static const char* elemNames[nTypes]; - // Static Member Functions + // Static Functions - //- Return the ensight element name for the specified type - static inline const char* key(const enum elemType); + //- The ensight element name for the specified 'Face' type + static inline const char* key(const elemType etype); private: - // Private data - - //- Location within a list. - // The ensight part number is typically this value +1. - label index_; - - //- Linear list of ids, sub-sectioned per element type by sub-lists - labelList address_; + // Private Data //- Linear list of face-flips boolList flipMap_; - //- Slices (sub-lists) of the address and flips for each element type. - FixedList<labelRange, 3> slices_; + //- Begin/end offsets for address/flips of each element type + FixedList<label, nTypes+1> offsets_; //- List of global sizes for each element type. // Used temporarily for local sizes when building the element lists. - FixedList<label, 3> sizes_; + FixedList<label, nTypes> sizes_; // Private Member Functions //- Low-level internal addition routine - inline void add(const face& f, const label id, const bool flip = false); + inline void add(const elemType etype, label id, bool flip=false); //- Use temporarily stored sizes to redimension the element lists void resizeAll(); + +public: + + //- Declare type-name, virtual type (with debug switch) + TypeName("ensightFaces"); + + + // Generated Methods + + //- Copy construct + ensightFaces(const ensightFaces&) = default; + //- No copy assignment void operator=(const ensightFaces&) = delete; + //- Move construct + ensightFaces(ensightFaces&&) = default; -public: + //- Move assignment + ensightFaces& operator=(ensightFaces&&) = default; - // Constructors + //- Destructor + virtual ~ensightFaces() = default; - //- Construct null, with part index 0 - ensightFaces(); - //- Construct null, with specified part index - explicit ensightFaces(const label partIndex); + // Constructors - //- Copy constructor. Needed for lists etc. - ensightFaces(const ensightFaces& obj); + //- Default construct, with part index 0 + ensightFaces(); + //- Default construct, with description/partName + explicit ensightFaces(const string& description); - //- Destructor - ~ensightFaces() = default; + //- Default construct, with specified part index + explicit ensightFaces(const label partIndex); // Member Functions // Access - //- The index in a list. - inline label index() const; + //- Processor-local size of all elements. + using ensightPart::size; - //- The index in a list, non-const access. - inline label& index(); + //- Processor-local size of the specified element type. + inline label size(const elemType etype) const; - //- The processor local size of all elements. - inline label size() const; + //- Processor-local offset/size of element type. + inline labelRange range(const elemType etype) const; - //- The processor local size of the specified element type. - inline label size(const enum elemType) const; - - //- The global number of all element types. + //- The global size of all element types. // This value is only meaningful after a reduce operation. label total() const; - //- The global number of the specified element type. + //- The global size of the specified element type. // This value is only meaningful after a reduce operation. - inline label total(const enum elemType) const; + inline label total(const elemType etype) const; - //- The global numbers per element type. + //- The global sizes for each element type. // This value is only meaningful after a reduce operation. - inline const FixedList<label, 3>& totals() const; - - //- The processor local sizes per element type. - FixedList<label, 3> sizes() const; + inline const FixedList<label, nTypes>& totals() const; - //- Processor local starting offset of element type. - inline label offset(const enum elemType what) const; + //- Processor-local sizes per element type. + FixedList<label, nTypes> sizes() const; - //- Return the (local) face ids of the specified element type - inline const labelUList faceIds(const enum elemType) const; + //- Processor-local face ids of all elements + inline const labelList& faceIds() const; - //- Return the processor local face ids of all elements - inline const labelUList& faceIds() const; + //- Processor-local face ids of the specified element type + inline const labelUList faceIds(const elemType etype) const; - //- Return the processor local flip-map of all elements + //- Processor-local flip-map of all elements inline const boolList& flipMap() const; + //- Processor-local (face) ids relative to start() + inline labelList localIds() const; + + //- Processor-local (face) ids relative to start() + inline labelList localIds(const elemType etype) const; + // Edit - //- Classify the face types, set element list. - void classify(const faceList& faces); + //- Classify the face types and set the element lists. + void classify(const UList<face>& faces); + //- Classify face types (for a sublist) and set element lists. + void classify(const UList<face>& faces, const labelRange& range); - //- Classify the face types, set element list. + //- Classify the face types and set the element lists. // The indirect addressing can be used when classifying groups of // face (eg, from a faceZone etc) with an optional flipMap. // The optional exclude marker can be used to skip faces on particular // boundary types or regions. void classify ( - const faceList& faces, - const labelUList& addressing, + const UList<face>& faces, + const labelUList& addr, const boolList& flipMap = boolList(), const bitSet& exclude = bitSet() ); + //- Clear any demand-driven data + void clearOut(); + //- Set addressable sizes to zero, free up addressing memory. void clear(); @@ -202,10 +221,11 @@ public: void sort(); - // Member Operators + // Output - //- Return element from linear-list. - inline label operator[](const label i) const; + //- Write information about the object as a dictionary, + //- optionally write all element addresses + virtual void writeDict(Ostream& os, const bool full=false) const; }; diff --git a/src/fileFormats/ensight/part/ensightFacesI.H b/src/fileFormats/ensight/part/ensightFacesI.H index 15799e5610f..90fe6fc3276 100644 --- a/src/fileFormats/ensight/part/ensightFacesI.H +++ b/src/fileFormats/ensight/part/ensightFacesI.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2017 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -25,31 +25,27 @@ License \*---------------------------------------------------------------------------*/ -#include "error.H" +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -inline const char* Foam::ensightFaces::key(const enum elemType what) +inline void Foam::ensightFaces::add(const elemType etype, label id, bool flip) { - return elemNames[what]; -} + // Linear addressing location + const label index = offsets_[etype] + sizes_[etype]++; + addressing()[index] = id; -inline Foam::label Foam::ensightFaces::index() const -{ - return index_; + if (flipMap_.size()) + { + flipMap_[index] = flip; + } } -inline Foam::label& Foam::ensightFaces::index() -{ - return index_; -} - +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -inline Foam::label Foam::ensightFaces::size() const +inline const char* Foam::ensightFaces::key(const elemType etype) { - return address_.size(); + return elemNames[etype]; } @@ -59,36 +55,34 @@ inline const Foam::FixedList<Foam::label,3>& Foam::ensightFaces::totals() const } -inline Foam::label Foam::ensightFaces::total(const enum elemType what) const +inline Foam::label Foam::ensightFaces::total(const elemType etype) const { - return sizes_[what]; + return sizes_[etype]; } -inline Foam::label Foam::ensightFaces::size(const enum elemType what) const +inline Foam::label Foam::ensightFaces::size(const elemType etype) const { - return slices_[what].size(); + return (offsets_[etype+1] - offsets_[etype]); } -inline Foam::label Foam::ensightFaces::offset(const enum elemType what) const +inline Foam::labelRange Foam::ensightFaces::range(const elemType etype) const { - return slices_[what].start(); + return labelRange(offsets_[etype], offsets_[etype+1] - offsets_[etype]); } -inline const Foam::labelUList Foam::ensightFaces::faceIds -( - const enum elemType what -) const +inline const Foam::labelList& Foam::ensightFaces::faceIds() const { - return address_[slices_[what]]; + return addressing(); } -inline const Foam::labelUList& Foam::ensightFaces::faceIds() const +inline const Foam::labelUList +Foam::ensightFaces::faceIds(const elemType etype) const { - return address_; + return addressing()[range(etype)]; } @@ -98,9 +92,15 @@ inline const Foam::boolList& Foam::ensightFaces::flipMap() const } -inline Foam::label Foam::ensightFaces::operator[](const label i) const +inline Foam::labelList Foam::ensightFaces::localIds() const +{ + return localAddressing(); +} + + +inline Foam::labelList Foam::ensightFaces::localIds(const elemType etype) const { - return address_[i]; + return localAddressing(range(etype)); } diff --git a/src/fileFormats/ensight/part/ensightOutputSurface.C b/src/fileFormats/ensight/part/ensightOutputSurface.C new file mode 100644 index 00000000000..7627019caed --- /dev/null +++ b/src/fileFormats/ensight/part/ensightOutputSurface.C @@ -0,0 +1,92 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 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 "ensightOutputSurface.H" +#include "ensightOutput.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::ensightOutputSurface::ensightOutputSurface +( + const pointField& points, + const faceList& faces +) +: + ensightFaces(), + points_(points), + faces_(faces) +{ + // Classify face types + classify(faces); +} + + +Foam::ensightOutputSurface::ensightOutputSurface +( + const string& description, + const pointField& points, + const faceList& faces +) +: + ensightOutputSurface(points, faces) +{ + rename(description); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::ensightOutputSurface::write(ensightGeoFile& os) const +{ + if (!total()) + { + return; + } + + // Coordinates + ensightOutput::Detail::writeCoordinates + ( + os, + index(), + name(), + points_.size(), + points_, + false // serial + ); + + // Faces + ensightOutput::writeFaceConnectivity + ( + os, + *this, + faces_, + false // serial + ); +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightOutputSurface.H b/src/fileFormats/ensight/part/ensightOutputSurface.H new file mode 100644 index 00000000000..c85f6e4f7e5 --- /dev/null +++ b/src/fileFormats/ensight/part/ensightOutputSurface.H @@ -0,0 +1,114 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 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::ensightOutputSurface + +Description + A variant of ensightFaces that holds references to continuous + points/faces for writing out. The surface is assumed to have been merged + prior so the output is serial-only. + +SourceFiles + ensightOutputSurface.C + +\*---------------------------------------------------------------------------*/ + +#ifndef ensightOutputSurface_H +#define ensightOutputSurface_H + +#include "ensightFaces.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class ensightOutputSurface Declaration +\*---------------------------------------------------------------------------*/ + +class ensightOutputSurface +: + public ensightFaces +{ + // Private Data + + //- The referenced pointField + const pointField& points_; + + //- The referenced faces + const faceList& faces_; + + + // Private Member Functions + + //- No copy construct + ensightOutputSurface(const ensightOutputSurface&) = delete; + + //- No copy assignment + void operator=(const ensightOutputSurface&) = delete; + + +public: + + // Constructors + + //- Construct from points and faces. + ensightOutputSurface + ( + const pointField& points, + const faceList& faces + ); + + //- Construct named from points and faces. + ensightOutputSurface + ( + const string& description, + const pointField& points, + const faceList& faces + ); + + + //- Destructor + virtual ~ensightOutputSurface() = default; + + + // Member Functions + + //- Write processor-local (serial) geometry + virtual void write(ensightGeoFile& os) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightPart.C b/src/fileFormats/ensight/part/ensightPart.C index 2092a33f396..1ec55759cc4 100644 --- a/src/fileFormats/ensight/part/ensightPart.C +++ b/src/fileFormats/ensight/part/ensightPart.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,28 +32,64 @@ License namespace Foam { - defineTypeNameAndDebug(ensightPart, 0); + defineTypeName(ensightPart); +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +Foam::labelList Foam::ensightPart::localAddressing() const +{ + labelList output(address_); + + if (start_) + { + for (label& val : output) + { + val += start_; + } + } + + return output; +} + + +Foam::labelList Foam::ensightPart::localAddressing(const labelRange& r) const +{ + labelList output(labelSubList(r, address_)); + + if (start_) + { + for (label& val : output) + { + val += start_; + } + } + + return output; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::ensightPart::ensightPart(const string& description) +Foam::ensightPart::ensightPart() noexcept : - name_(description) + index_(0), + identifier_(-1), + start_(0), + name_(), + address_() {} -// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // - -Foam::ensightGeoFile& Foam::operator<< -( - ensightGeoFile& os, - const ensightPart& part -) +Foam::ensightPart::ensightPart(const string& description) +: + ensightPart() { - part.write(os); - return os; + if (!description.empty()) + { + name_ = description; + } } diff --git a/src/fileFormats/ensight/part/ensightPart.H b/src/fileFormats/ensight/part/ensightPart.H index 2b9d3f9d3b9..42de12f010f 100644 --- a/src/fileFormats/ensight/part/ensightPart.H +++ b/src/fileFormats/ensight/part/ensightPart.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,7 +28,8 @@ Class Foam::ensightPart Description - Base class for ensightPartCells and ensightPartFaces + Base class for ensightCells, ensightFaces, + ensightPartCells, ensightPartFaces. SourceFiles ensightPart.C @@ -39,11 +40,8 @@ SourceFiles #define ensightPart_H #include "ensightGeoFile.H" -#include "typeInfo.H" #include "labelList.H" -#include "polyMesh.H" -#include "Field.H" -#include "IOstream.H" +#include "typeInfo.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -58,56 +56,64 @@ class ensightPart { // Private Data - //- Part name (or description) - string name_; + //- Part index within a list. + // The ensight part number is typically this value +1. + label index_; + //- OpenFOAM identifier (patch index, zone index, etc). + // An unused identifier is -1 + label identifier_; - // Private Member Functions + //- Start face-offset (for patch) + label start_; - //- No copy construct - ensightPart(const ensightPart&) = delete; + //- Part name (or description) + string name_; - //- No copy assignment - void operator=(const ensightPart&) = delete; + //- Linear list of element ids (face/cell) + // Sub-sectioning by element type is done by derived classes + labelList address_; protected: - // Protected Classes + //- Element addressing + const labelList& addressing() const + { + return address_; + } + + //- Element addressing + labelList& addressing() + { + return address_; + } - //- Track the points used by the part and map global to local indices - struct localPoints + //- Clear element addressing + void clear() { - //- Number of points used - label nPoints; - - //- Map global to local indices - labelList list; - - //- Null constructor - localPoints() - : - nPoints(0), - list() - {} - - //- Construct for mesh points - localPoints(const pointField& pts) - : - nPoints(0), - list(pts.size(), -1) - {} - }; + address_.clear(); + } + + //- Element local addressing (relattive to start) + labelList localAddressing() const; + + //- Element local addressing (relattive to start) + labelList localAddressing(const labelRange& range) const; + public: - //- Runtime type information - TypeName("ensightPart"); + //- Declare type-name, virtual type (without debug switch) + TypeNameNoDebug("ensightPart"); // Constructors - //- Construct with description + //- Default construct. Index=0, identifier = -1 + ensightPart() noexcept; + + //- Default construct, with description/partName explicit ensightPart(const string& description); @@ -115,25 +121,70 @@ public: virtual ~ensightPart() = default; - // Access + // Member Functions + + //- The index in a list (0-based) + label index() const + { + return index_; + } + + //- The index in a list (0-based) + label& index() + { + return index_; + } + + //- OpenFOAM identifier (patch, zone, etc), -1 when not in use. + label identifier() const + { + return identifier_; + } + + //- OpenFOAM identifier (patch, zone, etc), -1 when not in use. + label& identifier() + { + return identifier_; + } + + //- Processor-local test for any elements. + bool empty() const + { + return address_.empty(); + } + + //- Start face-offset (for patch) + label start() const + { + return start_; + } - //- Part index (0-based) - virtual label index() const = 0; + //- Start face-offset (for patch) + label& start() + { + return start_; + } - //- Number of elements in this part - virtual label size() const + //- Processor-local size of all elements. + label size() const { - return 0; + return address_.size(); } - //- Return the part name or description + //- The part name or description const string& name() const { return name_; } //- Change the part name or description - void rename(string value) + void rename(const string& value) + { + name_ = value; + } + + //- Change the part name or description + void rename(string&& value) { name_ = std::move(value); } @@ -141,35 +192,31 @@ public: // Output - //- Write summary information about the object - virtual void writeSummary(Ostream& os) const = 0; - - //- Print various types of debugging information - virtual void dumpInfo(Ostream& os) const = 0; + //- Write information about the object as a dictionary, + //- optionally write all element addresses + virtual void writeDict(Ostream& os, const bool full=false) const {} //- Write geometry - virtual void write(ensightGeoFile& os) const = 0; - - //- Helper: write geometry with given pointField - virtual void write(ensightGeoFile& os, const pointField&) const = 0; + virtual void write(ensightGeoFile& os) const {} - // Housekeeping + // Member Operators - //- Deprecated(2019-12) - use rename() method - // \deprecated(2019-12) - use rename() method - void FOAM_DEPRECATED_FOR(2019-12, "rename() method") - name(string value) + //- Processor-local element id from linear-list of addresses. + label operator[](const label i) const { - name_ = std::move(value); + return address_[i]; } }; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Housekeeping -//- IOstream Operator to write geometry -ensightGeoFile& operator<<(ensightGeoFile& os, const ensightPart& part); +//- Deprecated(2020-02) - use ensightOutput or member write() methods +// \deprecated(2020-02) - use ensightOutput or member write() methods +void operator<<(ensightGeoFile&, const ensightPart&) = delete; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/fileFormats/ensight/part/ensightPartCells.C b/src/fileFormats/ensight/part/ensightPartCells.C index 8a206be91f3..7f5bb5f1d22 100644 --- a/src/fileFormats/ensight/part/ensightPartCells.C +++ b/src/fileFormats/ensight/part/ensightPartCells.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,110 +28,75 @@ License #include "ensightPartCells.H" -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - defineTypeNameAndDebug(ensightPartCells, 0); -} - - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -Foam::ensightPart::localPoints Foam::ensightPartCells::calcLocalPoints() const -{ - localPoints ptList(mesh_.points()); - labelList& usedPoints = ptList.list; - label nPoints = 0; - - // Add all points from cells - const labelUList& idList = this->cellIds(); - - for (const label id : idList) - { - const labelUList& cFaces = mesh_.cells()[id]; - - forAll(cFaces, cFacei) - { - const face& f = mesh_.faces()[cFaces[cFacei]]; - - forAll(f, fp) - { - if (usedPoints[f[fp]] == -1) - { - usedPoints[f[fp]] = nPoints++; - } - } - } - } - - // this is not absolutely necessary, but renumber anyhow - nPoints = 0; - forAll(usedPoints, ptI) - { - if (usedPoints[ptI] > -1) - { - usedPoints[ptI] = nPoints++; - } - } - - ptList.nPoints = nPoints; - return ptList; -} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::ensightPartCells::ensightPartCells ( - label partIndex, const polyMesh& mesh, const string& partName ) : - ensightCells(partIndex), - ensightPart(partName), - mesh_(mesh) + ensightCells(), + mesh_(mesh), + contiguousPoints_(true), + nPointsUsed_(0), + localPointMap_(nullptr) { + if (!partName.empty()) + { + rename(partName); + } + classify(mesh); } Foam::ensightPartCells::ensightPartCells ( - label partIndex, const polyMesh& mesh, const labelUList& cellIds, const string& partName ) : - ensightCells(partIndex), - ensightPart(partName), - mesh_(mesh) + ensightCells(), + mesh_(mesh), + contiguousPoints_(false), + nPointsUsed_(0), + localPointMap_(nullptr) { + if (!partName.empty()) + { + rename(partName); + } + classify(mesh, cellIds); } Foam::ensightPartCells::ensightPartCells ( - label partIndex, const polyMesh& mesh, const bitSet& selection, const string& partName ) : - ensightCells(partIndex), - ensightPart(partName), - mesh_(mesh) + ensightCells(), + mesh_(mesh), + contiguousPoints_(false), + nPointsUsed_(0), + localPointMap_(nullptr) { + if (!partName.empty()) + { + rename(partName); + } + classify(mesh, selection); } Foam::ensightPartCells::ensightPartCells ( - label partIndex, const polyMesh& mesh, const cellZone& zn, const string& partName @@ -139,12 +104,13 @@ Foam::ensightPartCells::ensightPartCells : ensightPartCells ( - partIndex, mesh, static_cast<const labelList&>(zn), zn.name() ) { + identifier() = zn.index(); + if (!partName.empty()) { rename(partName); @@ -154,190 +120,12 @@ Foam::ensightPartCells::ensightPartCells // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void Foam::ensightPartCells::writeConnectivity -( - ensightGeoFile& os, - const word& key, - const labelUList& idList, - const labelUList& pointMap -) const +void Foam::ensightPartCells::clearOut() { - if (idList.empty()) return; - - os.writeKeyword(key); - os.write(idList.size()); - os.newline(); - - // write polyhedral - if (key == "nfaced") - { - const faceList& meshFaces = mesh_.faces(); - const labelUList& owner = mesh_.faceOwner(); - - // write the number of faces per element - forAll(idList, i) - { - const label id = idList[i]; - const labelUList& cFace = mesh_.cells()[id]; - - os.write(cFace.size()); - os.newline(); - } - - // write the number of points per element face - forAll(idList, i) - { - const label id = idList[i]; - const labelUList& cFace = mesh_.cells()[id]; - - forAll(cFace, facei) - { - const face& cf = meshFaces[cFace[facei]]; - - os.write(cf.size()); - os.newline(); - } - } - - // write the points describing each element face - forAll(idList, i) - { - const label id = idList[i]; - const labelUList& cFace = mesh_.cells()[id]; - - forAll(cFace, cFacei) - { - const label faceId = cFace[cFacei]; - const face& cf = meshFaces[faceId]; - - // convert global -> local index - // (note: Ensight indices start with 1) - - // ensight >= 9 needs consistently oriented nfaced cells - if (id == owner[faceId]) - { - forAll(cf, ptI) - { - os.write(pointMap[cf[ptI]] + 1); - } - } - else - { - // as per face::reverseFace(), but without copying - - os.write(pointMap[cf[0]] + 1); - for (label ptI = cf.size()-1; ptI > 0; --ptI) - { - os.write(pointMap[cf[ptI]] + 1); - } - } - - os.newline(); - } - } - } - else - { - // write primitive - const cellShapeList& shapes = mesh_.cellShapes(); - - forAll(idList, i) - { - const label id = idList[i]; - const cellShape& cellPoints = shapes[id]; - - // convert global -> local index - // (note: Ensight indices start with 1) - forAll(cellPoints, ptI) - { - os.write(pointMap[cellPoints[ptI]] + 1); - } - os.newline(); - } - } -} - - -void Foam::ensightPartCells::write -( - ensightGeoFile& os, - const pointField& points -) const -{ - if (size()) - { - const localPoints ptList = calcLocalPoints(); - const labelUList& pointMap = ptList.list; - - os.beginPart(index(), name()); - os.beginCoordinates(ptList.nPoints); - - for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) - { - forAll(pointMap, ptI) - { - if (pointMap[ptI] > -1) - { - os.write(points[ptI].component(cmpt)); - os.newline(); - } - } - } - - // Write each element type - for (int typei=0; typei < ensightCells::nTypes; ++typei) - { - const ensightCells::elemType what = ensightCells::elemType(typei); - - writeConnectivity - ( - os, - ensightCells::key(what), - cellIds(what), - pointMap - ); - } - } -} - - -void Foam::ensightPartCells::write(ensightGeoFile& os) const -{ - this->write(os, mesh_.points()); -} - - -void Foam::ensightPartCells::writeSummary(Ostream& os) const -{ - os.beginBlock(type()); - - os.writeEntry("id", index()+1); // Ensight starts with 1 - os.writeEntry("name", name()); - os.writeEntry("size", size()); - - os.endBlock(); -} - - -void Foam::ensightPartCells::dumpInfo(Ostream& os) const -{ - os.beginBlock(type()); - - os.writeEntry("id", index()+1); // Ensight starts with 1 - os.writeEntry("name", name()); - os.writeEntry("size", size()); - - for (int typei=0; typei < ensightCells::nTypes; ++typei) - { - const ensightCells::elemType what = ensightCells::elemType(typei); - const labelUList& addr = this->cellIds(what); - - os.writeKeyword(ensightCells::key(what)); - - addr.writeList(os, 0) << endEntry; // Flat output - } + ensightCells::clearOut(); - os.endBlock(); + nPointsUsed_ = 0; + localPointMap_.reset(nullptr); } diff --git a/src/fileFormats/ensight/part/ensightPartCells.H b/src/fileFormats/ensight/part/ensightPartCells.H index b0ddad0d4d7..07ea22f17fd 100644 --- a/src/fileFormats/ensight/part/ensightPartCells.H +++ b/src/fileFormats/ensight/part/ensightPartCells.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,15 +32,17 @@ Description SourceFiles ensightPartCells.C + ensightPartCellsAddr.C + ensightPartCellsIO.C \*---------------------------------------------------------------------------*/ #ifndef ensightPartCells_H #define ensightPartCells_H -#include "ensightPart.H" #include "ensightCells.H" -#include "typeInfo.H" +#include "polyMesh.H" +#include <memory> // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -53,29 +55,57 @@ namespace Foam class ensightPartCells : - public ensightCells, - public ensightPart + public ensightCells { // Private Data //- The referenced mesh const polyMesh& mesh_; + //- Can skip local point renumbering when points are contiguous + bool contiguousPoints_; + + + // Demand-driven data + + //- The number of points used + mutable label nPointsUsed_; + + //- Map global to local indices, with -1 for ununsed points + mutable std::unique_ptr<labelList> localPointMap_; + // Private Member Functions - //- Track points used - localPoints calcLocalPoints() const; + //- Calculate the points used + void calcLocalPoints() const; + + //- Return the number of unique points (demand-driven) + label getPointsUsed() const; + + //- Return the global to local indices (demand-driven) + labelList& getPointMap() const; + + //- Element connectivity for polyhedrals + void writePolysConnectivity + ( + ensightGeoFile& os, + const labelUList& addr, + const labelUList& pointMap + ) const; //- Element connectivity void writeConnectivity ( - ensightGeoFile&, - const word& key, + ensightGeoFile& os, + const ensightCells::elemType etype, const labelUList& idList, const labelUList& pointMap ) const; + //- Write processor-local (serial) geometry + void writeSerial(ensightGeoFile& os) const; + //- No copy construct ensightPartCells(const ensightPartCells&) = delete; @@ -86,17 +116,12 @@ class ensightPartCells public: - //- Runtime type information - TypeName("ensightCells"); - - // Constructors //- Construct from entire polyMesh without zones. //- Part receives the specified name (default: "cells"). - ensightPartCells + explicit ensightPartCells ( - label partIndex, const polyMesh& mesh, const string& partName = "cells" ); @@ -105,7 +130,6 @@ public: //- Part receives the specified name (default: "cells"). ensightPartCells ( - label partIndex, const polyMesh& mesh, const labelUList& cellIds, const string& partName = "cells" @@ -115,20 +139,18 @@ public: //- Part receives the specified name (default: "cells"). ensightPartCells ( - label partIndex, const polyMesh& mesh, const bitSet& selection, const string& partName = "cells" ); - //- Construct from polyMesh and cellZone. + //- Construct from cellZone. //- Part receives the name of the zone unless otherwise specified. ensightPartCells ( - label partIndex, const polyMesh& mesh, const cellZone& zn, - const string& partName = "" + const string& partName = string::null ); @@ -138,34 +160,11 @@ public: // Member Functions - // Access - - //- Part index (0-based) - virtual label index() const - { - return ensightCells::index(); - } - - //- Number of elements in this part - virtual label size() const - { - return ensightCells::size(); - } + //- Clear any demand-driven data + void clearOut(); - - // Output - - //- Write summary information about the object - virtual void writeSummary(Ostream& os) const; - - //- Print various types of debugging information - virtual void dumpInfo(Ostream& os) const; - - //- Write geometry + //- Write geometry (serial only) virtual void write(ensightGeoFile& os) const; - - //- Helper: write geometry with given pointField - virtual void write(ensightGeoFile& os, const pointField& points) const; }; diff --git a/src/fileFormats/ensight/part/ensightPartCellsAddr.C b/src/fileFormats/ensight/part/ensightPartCellsAddr.C new file mode 100644 index 00000000000..6ea54f3ef4e --- /dev/null +++ b/src/fileFormats/ensight/part/ensightPartCellsAddr.C @@ -0,0 +1,113 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 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 "ensightPartCells.H" +#include "ListOps.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::ensightPartCells::calcLocalPoints() const +{ + if (localPointMap_) + { + FatalErrorInFunction + << "localPointMap_ already allocated" + << abort(FatalError); + } + + localPointMap_.reset(new labelList()); + + labelList& usedPoints = *localPointMap_; + + usedPoints.resize(mesh_.points().size()); + + if (contiguousPoints_) + { + nPointsUsed_ = usedPoints.size(); + + ListOps::identity(usedPoints); + + return; + } + + + // Mark up with -1 for unused entries + usedPoints = -1; + label nPoints = 0; + + // Add all points from cells + for (const label celli : this->cellIds()) + { + for (const label facei : mesh_.cells()[celli]) + { + for (const label pointi : mesh_.faces()[facei]) + { + if (usedPoints[pointi] == -1) + { + usedPoints[pointi] = nPoints++; + } + } + } + } + + nPointsUsed_ = nPoints; + + // Compact point numbering, preserving the original order + nPoints = 0; + for (label& pointi : usedPoints) + { + if (pointi > -1) + { + pointi = nPoints++; + } + } +} + + +Foam::label Foam::ensightPartCells::getPointsUsed() const +{ + if (!localPointMap_) + { + calcLocalPoints(); + } + + return nPointsUsed_; +} + + +Foam::labelList& Foam::ensightPartCells::getPointMap() const +{ + if (!localPointMap_) + { + calcLocalPoints(); + } + + return *localPointMap_; +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightPartCellsIO.C b/src/fileFormats/ensight/part/ensightPartCellsIO.C new file mode 100644 index 00000000000..02764a73f6b --- /dev/null +++ b/src/fileFormats/ensight/part/ensightPartCellsIO.C @@ -0,0 +1,152 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2016-2020 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 "ensightPartCells.H" +#include "ensightOutput.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::ensightPartCells::writePolysConnectivity +( + ensightGeoFile& os, + const labelUList& addr, + const labelUList& pointMap +) const +{ + // The number of faces per element + { + labelList send + ( + ensightOutput::Detail::getPolysNFaces(mesh_, addr) + ); + + os.writeLabels(send); + } + + // The number of points per element face + { + labelList send + ( + ensightOutput::Detail::getPolysNPointsPerFace(mesh_, addr) + ); + + os.writeLabels(send); + } + + ensightOutput::writePolysPoints + ( + os, + mesh_, + addr, + pointMap // Remap point-ids + ); +} + + +void Foam::ensightPartCells::writeConnectivity +( + ensightGeoFile& os, + const ensightCells::elemType etype, + const labelUList& addr, + const labelUList& pointMap +) const +{ + if (addr.empty()) return; + + os.writeKeyword(ensightCells::key(etype)); + os.write(addr.size()); + os.newline(); + + if (etype == ensightCells::NFACED) + { + writePolysConnectivity(os, addr, pointMap); + return; + } + + + // Primitive shape - get subset and renumber + cellShapeList shapes(mesh_.cellShapes(), addr); + + ListListOps::inplaceRenumber(pointMap, shapes); + + ensightOutput::writeCellShapes(os, shapes); +} + + +void Foam::ensightPartCells::writeSerial +( + ensightGeoFile& os +) const +{ + const pointField& points = mesh_.points(); + + if (size()) + { + const labelUList& pointMap = getPointMap(); + const label nPoints = getPointsUsed(); + + os.beginPart(index(), name()); + os.beginCoordinates(nPoints); + + for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) + { + forAll(pointMap, pti) + { + if (pointMap[pti] > -1) + { + os.write(points[pti].component(cmpt)); + os.newline(); + } + } + } + + // Write each element type + for (int typei=0; typei < ensightCells::nTypes; ++typei) + { + const auto etype = ensightCells::elemType(typei); + + writeConnectivity + ( + os, + etype, + cellIds(etype), + pointMap + ); + } + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::ensightPartCells::write(ensightGeoFile& os) const +{ + writeSerial(os); +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightPartFaces.C b/src/fileFormats/ensight/part/ensightPartFaces.C index 6e9d2747c49..1aedd69a281 100644 --- a/src/fileFormats/ensight/part/ensightPartFaces.C +++ b/src/fileFormats/ensight/part/ensightPartFaces.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,274 +28,83 @@ License #include "ensightPartFaces.H" -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - defineTypeNameAndDebug(ensightPartFaces, 0); -} - - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -Foam::ensightPart::localPoints Foam::ensightPartFaces::calcLocalPoints() const -{ - if (contiguousPoints_) - { - localPoints ptList; - ptList.list = identity(points_.size()); - ptList.nPoints = points_.size(); - return ptList; - } - - localPoints ptList(points_); - labelList& usedPoints = ptList.list; - label nPoints = 0; - - // Add all points from faces - const labelUList& idList = this->faceIds(); - - // Add all points from faces - forAll(idList, i) - { - const label id = idList[i] + start_; - const face& f = faces_[id]; - - forAll(f, fp) - { - if (usedPoints[f[fp]] == -1) - { - usedPoints[f[fp]] = nPoints++; - } - } - } - - - // This is not absolutely necessary, but renumber anyhow - nPoints = 0; - forAll(usedPoints, ptI) - { - if (usedPoints[ptI] > -1) - { - usedPoints[ptI] = nPoints++; - } - } - - ptList.nPoints = nPoints; - return ptList; -} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::ensightPartFaces::ensightPartFaces ( - label partIndex, const string& description, const pointField& points, const faceList& faces, const bool contiguousPoints ) : - ensightFaces(partIndex), - ensightPart(description), - start_(0), - patchIndex_(-1), - faces_(faces), + ensightFaces(), points_(points), - contiguousPoints_(contiguousPoints) + faces_(faces), + contiguousPoints_(contiguousPoints), + nPointsUsed_(0), + localPointMap_(nullptr) { - // Classify the face shapes + if (!description.empty()) + { + rename(description); + } + + // Classify face types classify(faces); } Foam::ensightPartFaces::ensightPartFaces ( - label partIndex, const polyMesh& mesh, const polyPatch& patch, const string& partName ) : - ensightFaces(partIndex), - ensightPart(patch.name()), - start_(patch.start()), - patchIndex_(patch.index()), - faces_(mesh.faces()), + ensightFaces(), points_(mesh.points()), - contiguousPoints_(false) + faces_(mesh.faces()), + contiguousPoints_(false), + nPointsUsed_(0), + localPointMap_(nullptr) { + identifier() = patch.index(); + + start() = patch.start(); + if (!partName.empty()) { rename(partName); } + else + { + rename(patch.name()); + } - // Classify the face shapes - classify(patch); + // Classify face types for patch region + classify(mesh.faces(), patch.range()); } Foam::ensightPartFaces::ensightPartFaces ( - label partIndex, const polyPatch& patch, const string& partName ) : - ensightPartFaces(partIndex, patch.boundaryMesh().mesh(), patch, partName) + ensightPartFaces(patch.boundaryMesh().mesh(), patch, partName) {} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void Foam::ensightPartFaces::writeConnectivity -( - ensightGeoFile& os, - const word& key, - const faceList& faces, - const labelUList& idList, - const labelUList& pointMap -) const +void Foam::ensightPartFaces::clearOut() { - if (idList.empty()) return; - - os.writeKeyword(key); - os.write(idList.size()); - os.newline(); - - // Write (polygon) face sizes - if (key == "nsided") - { - // Write the number of points per face - forAll(idList, i) - { - const label id = idList[i] + start_; - const face& f = faces[id]; - - os.write(f.size()); - os.newline(); - } - } - - // Write the points describing the face - forAll(idList, i) - { - const label id = idList[i] + start_; - const face& f = faces[id]; - - // Convert global -> local index - // (note: Ensight indices start with 1) - forAll(f, fp) - { - os.write(pointMap[f[fp]] + 1); - } - os.newline(); - } -} - - -void Foam::ensightPartFaces::writeConnectivity -( - ensightGeoFile& os, - const word& key, - const labelUList& idList, - const labelUList& pointMap -) const -{ - writeConnectivity - ( - os, - key, - faces_, - idList, - pointMap - ); -} - - -void Foam::ensightPartFaces::write -( - ensightGeoFile& os, - const pointField& points -) const -{ - if (size()) - { - const localPoints ptList = calcLocalPoints(); - const labelUList& pointMap = ptList.list; - - os.beginPart(index(), name()); - os.beginCoordinates(ptList.nPoints); - - for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) - { - forAll(pointMap, ptI) - { - if (pointMap[ptI] > -1) - { - os.write(points[ptI].component(cmpt)); - os.newline(); - } - } - } - - // Write part - for (int typei=0; typei < ensightFaces::nTypes; ++typei) - { - const ensightFaces::elemType what = ensightFaces::elemType(typei); - - writeConnectivity - ( - os, - ensightFaces::key(what), - faceIds(what), - pointMap - ); - } - } -} - - -void Foam::ensightPartFaces::write(ensightGeoFile& os) const -{ - this->write(os, points_); -} - - -void Foam::ensightPartFaces::writeSummary(Ostream& os) const -{ - os.beginBlock(type()); - - os.writeEntry("id", index()+1); // Ensight starts with 1 - os.writeEntry("name", name()); - os.writeEntry("start", start_); - os.writeEntry("size", size()); - - os.endBlock(); -} - - -void Foam::ensightPartFaces::dumpInfo(Ostream& os) const -{ - os.beginBlock(type()); - - os.writeEntry("id", index()+1); // Ensight starts with 1 - os.writeEntry("name", name()); - os.writeEntry("start", start_); - os.writeEntry("size", size()); - - for (int typei=0; typei < ensightFaces::nTypes; ++typei) - { - const ensightFaces::elemType what = ensightFaces::elemType(typei); - const labelUList& addr = this->faceIds(what); - - os.writeKeyword(ensightFaces::key(what)); - - addr.writeList(os, 0) << endEntry; // Flat output - } + ensightFaces::clearOut(); - os.endBlock(); + nPointsUsed_ = 0; + localPointMap_.reset(nullptr); } diff --git a/src/fileFormats/ensight/part/ensightPartFaces.H b/src/fileFormats/ensight/part/ensightPartFaces.H index 08fb6af73b7..de39712f555 100644 --- a/src/fileFormats/ensight/part/ensightPartFaces.H +++ b/src/fileFormats/ensight/part/ensightPartFaces.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,6 +32,8 @@ Description SourceFiles ensightPartFaces.C + ensightPartFacesAddr.C + ensightPartFacesIO.C \*---------------------------------------------------------------------------*/ @@ -40,7 +42,8 @@ SourceFiles #include "ensightPart.H" #include "ensightFaces.H" -#include "typeInfo.H" +#include "polyMesh.H" +#include <memory> // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -53,51 +56,52 @@ namespace Foam class ensightPartFaces : - public ensightFaces, - public ensightPart + public ensightFaces { - // Private data + // Private Data - //- Start offset for patch - const label start_; - - //- Patch index - const label patchIndex_; + //- The referenced pointField + const pointField& points_; //- The referenced faces const faceList& faces_; - //- The referenced pointField - const pointField& points_; - //- Can skip local point renumbering when points are contiguous - const bool contiguousPoints_; + bool contiguousPoints_; + + + // Demand-driven data + + //- The number of points used + mutable label nPointsUsed_; + + //- Map global to local indices, with -1 for ununsed points + mutable std::unique_ptr<labelList> localPointMap_; // Private Member Functions - //- Track points used - localPoints calcLocalPoints() const; + //- Calculate the points used + void calcLocalPoints() const; - //- Element connectivity - void writeConnectivity - ( - ensightGeoFile&, - const word& key, - const labelUList& idList, - const labelUList& pointMap - ) const; + //- Return the number of unique points (demand-driven) + label getPointsUsed() const; + + //- Return the global to local indices (demand-driven) + labelList& getPointMap() const; //- Helper: write connectivity - void writeConnectivity + static void writeConnectivity ( - ensightGeoFile&, - const word& key, - const faceList&, - const labelUList& idList, + ensightGeoFile& os, + const ensightFaces::elemType etype, + const UIndirectList<face>& faces, const labelUList& pointMap - ) const; + ); + + //- Write processor-local (serial) geometry + void writeSerial(ensightGeoFile& os) const; //- No copy construct @@ -109,17 +113,12 @@ class ensightPartFaces public: - //- Runtime type information - TypeName("ensightFaces"); - - // Constructors - //- Construct part with 0-based index, description, points and faces + //- Construct from points and faces. // Can skip local point renumbering when points are contiguous ensightPartFaces ( - label partIndex, const string& description, const pointField& points, const faceList& faces, @@ -130,19 +129,17 @@ public: //- Part receives the name of the patch unless otherwise specified. ensightPartFaces ( - label partIndex, const polyMesh& mesh, const polyPatch& patch, - const string& partName = "" + const string& partName = string::null ); //- Construct from polyPatch //- Part receives the name of the patch unless otherwise specified. - ensightPartFaces + explicit ensightPartFaces ( - label partIndex, const polyPatch& patch, - const string& partName = "" + const string& partName = string::null ); @@ -152,42 +149,11 @@ public: // Member Functions - // Access - - //- Part index (0-based) - virtual label index() const - { - return ensightFaces::index(); - } - - - //- Number of elements in this part - virtual label size() const - { - return ensightFaces::size(); - } + //- Clear any demand-driven data + void clearOut(); - - //- Return the patch index, -1 when not in use. - inline label patchIndex() const - { - return patchIndex_; - } - - - // Output - - //- Write summary information about the object - virtual void writeSummary(Ostream& os) const; - - //- Print various types of debugging information - virtual void dumpInfo(Ostream& os) const; - - //- Write geometry + //- Write geometry (serial only) virtual void write(ensightGeoFile& os) const; - - //- Helper: write geometry given the pointField - virtual void write(ensightGeoFile& os, const pointField& points) const; }; diff --git a/src/fileFormats/ensight/part/ensightPartFacesAddr.C b/src/fileFormats/ensight/part/ensightPartFacesAddr.C new file mode 100644 index 00000000000..c9870d2a916 --- /dev/null +++ b/src/fileFormats/ensight/part/ensightPartFacesAddr.C @@ -0,0 +1,110 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 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 "ensightPartFaces.H" +#include "ListOps.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::ensightPartFaces::calcLocalPoints() const +{ + if (localPointMap_) + { + FatalErrorInFunction + << "localPointMap_ already allocated" + << abort(FatalError); + } + + localPointMap_.reset(new labelList()); + + labelList& usedPoints = *localPointMap_; + + usedPoints.resize(points_.size()); + + if (contiguousPoints_) + { + nPointsUsed_ = usedPoints.size(); + + ListOps::identity(usedPoints); + + return; + } + + + // Mark up with -1 for unused entries + usedPoints = -1; + label nPoints = 0; + + // Add all points from faces + for (const label facei : this->faceIds()) + { + for (const label pointi : faces_[facei]) + { + if (usedPoints[pointi] == -1) + { + usedPoints[pointi] = nPoints++; + } + } + } + + nPointsUsed_ = nPoints; + + // Compact point numbering, preserving the original order + nPoints = 0; + for (label& pointi : usedPoints) + { + if (pointi > -1) + { + pointi = nPoints++; + } + } +} + + +Foam::label Foam::ensightPartFaces::getPointsUsed() const +{ + if (!localPointMap_) + { + calcLocalPoints(); + } + + return nPointsUsed_; +} + + +Foam::labelList& Foam::ensightPartFaces::getPointMap() const +{ + if (!localPointMap_) + { + calcLocalPoints(); + } + + return *localPointMap_; +} + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightPartFacesIO.C b/src/fileFormats/ensight/part/ensightPartFacesIO.C new file mode 100644 index 00000000000..63de361fb29 --- /dev/null +++ b/src/fileFormats/ensight/part/ensightPartFacesIO.C @@ -0,0 +1,120 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2016-2020 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 "ensightPartFaces.H" +#include "ListOps.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::ensightPartFaces::writeConnectivity +( + ensightGeoFile& os, + const ensightFaces::elemType etype, + const UIndirectList<face>& faces, + const labelUList& pointMap +) +{ + if (faces.empty()) return; + + os.writeKeyword(ensightFaces::key(etype)); + os.write(faces.size()); + os.newline(); + + // Write (polygon) face sizes + if (etype == ensightFaces::NSIDED) + { + // Write the number of points per face + for (const face& f : faces) + { + os.write(f.size()); + os.newline(); + } + } + + // Write the points describing the face + // Convert global -> local index + // (note: Ensight indices start with 1) + for (const face& f : faces) + { + for (const label pointi : f) + { + os.write(pointMap[pointi] + 1); + } + os.newline(); + } +} + + +void Foam::ensightPartFaces::writeSerial(ensightGeoFile& os) const +{ + if (size()) + { + const labelUList& pointMap = getPointMap(); + const label nPoints = getPointsUsed(); + + os.beginPart(index(), name()); + os.beginCoordinates(nPoints); + + for (direction cmpt=0; cmpt < point::nComponents; ++cmpt) + { + forAll(pointMap, pointi) + { + if (pointMap[pointi] > -1) + { + os.write(points_[pointi].component(cmpt)); + os.newline(); + } + } + } + + // Write part + for (int typei=0; typei < ensightFaces::nTypes; ++typei) + { + const auto etype = ensightFaces::elemType(typei); + + writeConnectivity + ( + os, + etype, + UIndirectList<face>(faces_, faceIds(etype)), + pointMap + ); + } + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::ensightPartFaces::write(ensightGeoFile& os) const +{ + writeSerial(os); +} + + + +// ************************************************************************* // diff --git a/src/fileFormats/ensight/part/ensightParts.C b/src/fileFormats/ensight/part/ensightParts.C index 70baac46477..404d14cc26a 100644 --- a/src/fileFormats/ensight/part/ensightParts.C +++ b/src/fileFormats/ensight/part/ensightParts.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -34,8 +34,6 @@ License // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::ensightParts::ensightParts(const polyMesh& mesh) -: - StorageType() { recalculate(mesh); } @@ -45,9 +43,7 @@ Foam::ensightParts::ensightParts(const polyMesh& mesh) void Foam::ensightParts::recalculate(const polyMesh& mesh) { - StorageType::clear(); - - label nPart = 0; + this->clear(); // Track which cells are in a zone or not bitSet selection(mesh.nCells()); @@ -58,14 +54,14 @@ void Foam::ensightParts::recalculate(const polyMesh& mesh) if (returnReduce(!zn.empty(), orOp<bool>())) { selection.set(zn); - this->append(new ensightPartCells(nPart++, mesh, zn)); + this->append(new ensightPartCells(mesh, zn)); } } - if (!nPart) + if (this->empty()) { - // No zones at all? - do entire mesh. Name as per ensightMesh - this->append(new ensightPartCells(nPart++, mesh, "internalMesh")); + // No zones? - do entire mesh. Name as per ensightMesh + this->insert(new ensightPartCells(mesh, "internalMesh")); } else { @@ -74,28 +70,47 @@ void Foam::ensightParts::recalculate(const polyMesh& mesh) if (returnReduce(selection.any(), orOp<bool>())) { - this->append + // Place as first in the list + this->insert ( - new ensightPartCells(nPart++, mesh, selection, "__internal__") + new ensightPartCells(mesh, selection, "__internal__") ); } } - // Do boundaries, skipping empty and processor patches for (const polyPatch& p : mesh.boundaryMesh()) { + // Only do real (non-processor) boundaries. if (isA<processorPolyPatch>(p)) { - // No processor patches break; } - if (returnReduce(!p.empty(), orOp<bool>())) + // Skip empty patch types and zero-sized patches + // Would ideally like to check for emptyFvPatch, + // but that is not available here + if + ( + !isA<emptyPolyPatch>(p) + && returnReduce(!p.empty(), orOp<bool>()) + ) { - this->append(new ensightPartFaces(nPart++, mesh, p)); + this->append(new ensightPartFaces(p)); } } + + renumber(); +} + + +void Foam::ensightParts::renumber(label start) +{ + for (ensightPart& part : *this) + { + part.index() = start; + ++start; + } } @@ -109,24 +124,16 @@ void Foam::ensightParts::write(ensightGeoFile& os) const Info<< ' ' << part.index() << flush; part.write(os); } - Info<< " )" << endl; -} - -void Foam::ensightParts::writeSummary(Ostream& os) const -{ - for (const ensightPart& part : *this) - { - part.writeSummary(os); - } + Info<< " )" << endl; } -void Foam::ensightParts::dumpInfo(Ostream& os) const +void Foam::ensightParts::writeDict(Ostream& os, const bool full) const { for (const ensightPart& part : *this) { - part.dumpInfo(os); + part.writeDict(os, full); } } diff --git a/src/fileFormats/ensight/part/ensightParts.H b/src/fileFormats/ensight/part/ensightParts.H index 6ee3b3b1f14..df8f31d171b 100644 --- a/src/fileFormats/ensight/part/ensightParts.H +++ b/src/fileFormats/ensight/part/ensightParts.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -39,7 +39,6 @@ SourceFiles #define ensightParts_H #include "SLPtrList.H" -#include "ensightPart.H" #include "ensightPartFaces.H" #include "ensightPartCells.H" @@ -67,36 +66,32 @@ class ensightParts public: - //- Storage type used - typedef SLPtrList<ensightPart> StorageType; - - // Constructors //- Construct from polyMesh explicit ensightParts(const polyMesh& mesh); - //- Destructor - ~ensightParts() = default; - - // Member Functions + //- Any parts? + using SLPtrList<ensightPart>::empty; + //- Number of parts - using StorageType::size; + using SLPtrList<ensightPart>::size; //- Clear old information and construct anew from polyMesh void recalculate(const polyMesh& mesh); + //- Renumber each entry, starting at given index (default: 0) + void renumber(label start=0); - // Output - //- Write summary information about the objects - void writeSummary(Ostream& os) const; + // Output - //- Print various types of debugging information - void dumpInfo(Ostream& os) const; + //- Write information about the object as a dictionary, + //- optionally with all elements + void writeDict(Ostream& os, const bool full=false) const; //- Write the geometry to file void write(autoPtr<ensightGeoFile>& os) const diff --git a/src/functionObjects/utilities/ensightWrite/ensightWriteTemplates.C b/src/functionObjects/utilities/ensightWrite/ensightWriteTemplates.C index 785aca83107..8156cd0acbd 100644 --- a/src/functionObjects/utilities/ensightWrite/ensightWriteTemplates.C +++ b/src/functionObjects/utilities/ensightWrite/ensightWriteTemplates.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -58,9 +58,9 @@ Foam::label Foam::functionObjects::ensightWrite::writeVolFields ensightOutput::writeVolField<Type> ( + os.ref(), field, ensMesh(), - os.ref(), caseOpts_.nodeValues() ); diff --git a/src/surfMesh/writers/ensight/ensightSurfaceWriter.C b/src/surfMesh/writers/ensight/ensightSurfaceWriter.C index 615983b1550..19d2aae5c0d 100644 --- a/src/surfMesh/writers/ensight/ensightSurfaceWriter.C +++ b/src/surfMesh/writers/ensight/ensightSurfaceWriter.C @@ -31,8 +31,8 @@ License #include "Fstream.H" #include "OSspecific.H" #include "ensightCase.H" -#include "ensightPartFaces.H" #include "ensightOutput.H" +#include "ensightOutputSurface.H" #include "ensightPTraits.H" #include "surfaceWriterMethods.H" #include "addToRunTimeSelectionTable.H" diff --git a/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C b/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C index a92350dffb3..7f9f41c8e15 100644 --- a/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C +++ b/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2014 OpenFOAM Foundation - Copyright (C) 2015-2019 OpenCFD Ltd. + Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -405,15 +405,14 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated const fileName meshFile(baseDir/geometryName); - // Write geometry - ensightPartFaces ensPart + // Ensight Geometry + ensightOutputSurface part ( - 0, meshFile.name(), surf.points(), - surf.faces(), - true // contiguous points + surf.faces() ); + if (!exists(meshFile)) { if (verbose_) @@ -427,7 +426,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated meshFile.name(), writeFormat_ ); - osGeom << ensPart; + part.write(osGeom); // serial } // Write field @@ -450,19 +449,19 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated { ensightOutput::Serial::writePointField ( + osField, tfield(), - ensPart, - osField + part // serial ); } else { - ensightOutput::Detail::writeFaceField + ensightOutput::Detail::writeField ( - tfield(), - ensPart, osField, + tfield(), + part, false // serial ); } diff --git a/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C b/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C index e5c60b99947..c3347f7885d 100644 --- a/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C +++ b/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2014 OpenFOAM Foundation - Copyright (C) 2015-2019 OpenCFD Ltd. + Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -87,15 +87,13 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated() printTimeset(osCase, 1, 0.0); - ensightPartFaces ensPart + ensightOutputSurface part ( - 0, osGeom.name().name(), surf.points(), - surf.faces(), - true // contiguous points + surf.faces() ); - osGeom << ensPart; + part.write(osGeom); // serial } wroteGeom_ = true; @@ -212,15 +210,14 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated osCase << "# end" << nl; - ensightPartFaces ensPart + // Ensight Geometry + ensightOutputSurface part ( - 0, osGeom.name().name(), surf.points(), - surf.faces(), - true // contiguous points + surf.faces() ); - osGeom << ensPart; + part.write(osGeom); // serial // Write field osField.writeKeyword(ensightPTraits<Type>::typeName); @@ -229,19 +226,19 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated { ensightOutput::Serial::writePointField ( + osField, tfield(), - ensPart, - osField + part // serial ); } else { - ensightOutput::Detail::writeFaceField + ensightOutput::Detail::writeField ( - tfield(), - ensPart, osField, + tfield(), + part, false // serial ); } -- GitLab