From 3e87a464988cb3c34b0e6e03ea078e1447daba1a Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Fri, 28 May 2021 15:05:37 +0200 Subject: [PATCH] ENH: multi-region support for foamToEnsight (#2080) - additional finite-area support too. --- .../dataConversion/foamToEnsight/Make/options | 2 + .../foamToEnsight/checkFieldAvailability.H | 61 +++++ .../foamToEnsight/checkMeshMoving.H | 79 ++++-- .../foamToEnsight/convertAreaFields.H | 32 +++ .../foamToEnsight/convertLagrangian.H | 21 +- .../foamToEnsight/convertVolumeFields.H | 24 +- .../foamToEnsight/createMeshAccounting.H | 107 ++++++++ .../foamToEnsight/findCloudFields.H | 162 +++++++---- .../foamToEnsight/foamToEnsight.C | 259 ++++++++++-------- .../foamToEnsight/getTimeIndex.H | 37 ++- .../foamToEnsight/writeAreaFields.H | 129 +++++++++ .../foamToEnsight/writeDimFields.H | 19 +- .../foamToEnsight/writePointFields.H | 22 +- .../foamToEnsight/writeVolFields.H | 19 +- .../planeTransport/Allrun-parallel | 14 +- .../multiRegionHeaterRadiation/Allrun | 8 +- .../Allrun-parallel | 8 +- 17 files changed, 719 insertions(+), 284 deletions(-) create mode 100644 applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H create mode 100644 applications/utilities/postProcessing/dataConversion/foamToEnsight/convertAreaFields.H create mode 100644 applications/utilities/postProcessing/dataConversion/foamToEnsight/createMeshAccounting.H create mode 100644 applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options index 2c48a25324..5014ceacb3 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options @@ -1,5 +1,6 @@ EXE_INC = \ -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/finiteArea/lnInclude \ -I$(LIB_SRC)/fileFormats/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude \ -I$(LIB_SRC)/conversion/lnInclude \ @@ -7,6 +8,7 @@ EXE_INC = \ EXE_LIBS = \ -lfiniteVolume \ + -lfiniteArea \ -lfileFormats \ -lconversion \ -llagrangianIntermediate \ diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H new file mode 100644 index 0000000000..b562bcdf43 --- /dev/null +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H @@ -0,0 +1,61 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. + +Description + Check field availability for last time. + Done to avoid mapping 'undefined' when a field only exists as time 0. + +Requires + readFields.H (for the checkData function) + +\*---------------------------------------------------------------------------*/ + +// Initially all possible objects that are available at the final time +List availableRegionObjectNames(meshes.size()); + +forAll(meshes, regioni) +{ + const auto& mesh = meshes[regioni]; + + IOobjectList objects(mesh, timeDirs.last().name()); + + if (!fieldPatterns.empty()) + { + objects.filterObjects(fieldPatterns); + } + + // Remove "*_0" restart fields + objects.prune_0(); + + if (!doPointValues) + { + // Prune point fields if disabled + objects.filterClasses + ( + [](const word& clsName) + { + return fieldTypes::point.found(clsName); + }, + true // prune + ); + } + + wordList objectNames(objects.sortedNames()); + + // Check availability for all times... + checkData(mesh, timeDirs, objectNames); + + availableRegionObjectNames[regioni] = objectNames; +} + + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H index bb1b2dd446..c54e45cc3b 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H @@ -1,46 +1,83 @@ -// Check for "points" in any of the result directories +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. -bool hasMovingMesh = false; +Description + Check for "points" in any of the result directories (each region) -if (timeDirs.size() > 1 && Pstream::master()) +\*---------------------------------------------------------------------------*/ + +// All regions moving, or no regions moving. Do not mix. +bool hasMovingMesh(false); + +if (timeDirs.size() > 1) { - // We already loaded a mesh (usually from constant). + // We already loaded meshes (usually from constant). // See if any other "polyMesh/points" files exist too. + // Do all regions as moving, or all as static. + + boolList isMoving(meshes.size(), false); + label nMoving = 0; + Info<< "Search for moving mesh ... " << flush; for (const instant& inst : timeDirs) { const word& timeName = inst.name(); - hasMovingMesh = - ( - timeName != mesh.pointsInstance() - && IOobject - ( - "points", - timeName, - polyMesh::meshSubDir, - mesh, - IOobject::NO_READ, - IOobject::NO_WRITE, - false // no register - ).typeHeaderOk(true, false) - ); + forAll(meshes, regioni) + { + const fvMesh& mesh = meshes[regioni]; - if (hasMovingMesh) + if + ( + !isMoving[regioni] + && (timeName != mesh.pointsInstance()) + && IOobject + ( + "points", + timeName, + polyMesh::meshSubDir, + mesh, + IOobject::NO_READ, + IOobject::NO_WRITE, + false // no register + ).typeHeaderOk(true, false) + ) + { + isMoving[regioni] = true; + ++nMoving; + } + } + + if (nMoving == isMoving.size()) { break; } } - if (hasMovingMesh) + if (nMoving) { - Info<< "found. Writing meshes for every timestep." << endl; + Info<< "found " << nMoving + << " moving regions. Writing meshes for every timestep." << endl; } else { Info<< "none detected." << endl; } + + hasMovingMesh = (nMoving != 0); } +// Ensure consistency reduce(hasMovingMesh, orOp()); + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertAreaFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertAreaFields.H new file mode 100644 index 0000000000..5f2ef2455f --- /dev/null +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertAreaFields.H @@ -0,0 +1,32 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. + +Description + Code chunk for converting area fields + included by foamToEnsight. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Area fields (finiteArea) +if (doFiniteArea && ensFaCasePtr && ensFaMeshPtr) +{ + Info<< " area field ("; + + writeAllAreaFields(*ensFaCasePtr, *ensFaMeshPtr, objects); + + Info<< " )" << nl; +} + + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertLagrangian.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertLagrangian.H index 1d016220e4..2247b6a581 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertLagrangian.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertLagrangian.H @@ -8,20 +8,7 @@ Copyright (C) 2018-2021 OpenCFD Ltd. ------------------------------------------------------------------------------- License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see . + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. Description Code chunk for post-processing conversion of cloud(s) to Ensight @@ -31,6 +18,10 @@ Description // Cloud field data output if (doLagrangian) { + // Lagrangian + const auto& cloudFields = regionCloudFields[regioni]; + const auto& cloudNames = regionCloudNames[regioni]; + for (const word& cloudName : cloudNames) { const HashTable& theseCloudFields = cloudFields[cloudName]; @@ -44,7 +35,7 @@ if (doLagrangian) ) ); - Info<< "Write " << cloudName << " ("; + Info<< "Cloud " << cloudName << " ("; const bool cloudExists = returnReduce(currentCloudDirs.found(cloudName), orOp()); diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H index 042fe86426..9b6cad2b34 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/convertVolumeFields.H @@ -5,23 +5,10 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018-2020 OpenCFD Ltd. + Copyright (C) 2018-2021 OpenCFD Ltd. ------------------------------------------------------------------------------- License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see . + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. Description Code chunk for converting volume and dimensioned fields @@ -31,9 +18,10 @@ Description // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Cell field data output +// Volume field data output +if (doBoundary || doInternal) { - Info<< "Write volume field ("; + Info<< " volume field ("; writeAllVolFields(ensCase, ensMesh, objects, nearCellValue); writeAllDimFields(ensCase, ensMesh, objects); @@ -44,7 +32,7 @@ Description // - only construct pointMesh on request (it constructs edge addressing) if (doPointValues) { - Info<< "Write point field ("; + Info<< " point field ("; writeAllPointFields(ensCase, ensMesh, objects); Info<< " )" << nl; } diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/createMeshAccounting.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/createMeshAccounting.H new file mode 100644 index 0000000000..61116489ee --- /dev/null +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/createMeshAccounting.H @@ -0,0 +1,107 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. + +Description + Additional mesh accounting (Ensight) + +\*---------------------------------------------------------------------------*/ + +PtrList ensightCases(regionNames.size()); +PtrList ensightMeshes(regionNames.size()); + +PtrList meshesFa(regionNames.size()); +PtrList ensightCasesFa(regionNames.size()); +PtrList ensightMeshesFa(regionNames.size()); + +{ + forAll(regionNames, regioni) + { + const fvMesh& mesh = meshes[regioni]; + + const word& regionName = regionNames[regioni]; + const word& regionDir = + ( + regionName != polyMesh::defaultRegion + ? regionName + : word::null + ); + + fileName ensCasePath(outputDir); + word ensCaseName(args.globalCaseName()); + + if (!regionDir.empty()) + { + ensCaseName = regionName; + ensCasePath /= regionName; + + // Handle very rare naming collision with Ensight directories + if (regionName == "data") + { + ensCasePath += "-region"; + } + } + + ensightMeshes.set + ( + regioni, + new ensightMesh(mesh, writeOpts) + ); + + // New ensight case file, initialize header etc. + ensightCases.set + ( + regioni, + new ensightCase(ensCasePath, ensCaseName, caseOpts) + ); + + if (doFiniteArea) + { + autoPtr faMeshPtr; + + const bool throwing = FatalError.throwExceptions(); + try + { + faMeshPtr.reset(new faMesh(mesh)); + } + catch (const Foam::error& err) + { + faMeshPtr.reset(nullptr); + } + FatalError.throwExceptions(throwing); + + if (faMeshPtr) + { + ensightCasesFa.set + ( + regioni, + new ensightCase + ( + ensCasePath/"finite-area", + "finite-area", + caseOpts + ) + ); + + meshesFa.set(regioni, faMeshPtr); + + ensightMeshesFa.set + ( + regioni, + new ensightFaMesh(meshesFa[regioni]) + ); + } + } + } +} + + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H index 2e092df2c0..4dde1d66ae 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H @@ -1,68 +1,100 @@ -// check all time directories for the following: +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2018-2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. + +Description + Check time directories for lagrangian data. + +\*---------------------------------------------------------------------------*/ // The fields for each cloud: -HashTable> cloudFields; +List>> regionCloudFields(meshes.size()); // Identify if lagrangian data exist at any time step. if (timeDirs.size() && doLagrangian) { - const fileName& baseDir = mesh.time().path(); - const fileName cloudPrefix(regionDir/cloud::prefix); + Info<< "Search for lagrangian ... " << flush; - Info<< "Searching for lagrangian ... " << flush; - - for (const instant& inst : timeDirs) + forAll(meshes, regioni) { - const word& timeName = inst.name(); + const fvMesh& mesh = meshes[regioni]; + auto& cloudFields = regionCloudFields[regioni]; - // DO NOT USE -->> runTime.setTime(timeDirs[timeI], timeI); <<-- - // It incurs a large overhead when done so frequently. - - fileNameList cloudDirs + const word& regionName = regionNames[regioni]; + const word& regionDir = ( - readDir - ( - baseDir/timeName/cloudPrefix, - fileName::DIRECTORY - ) + regionName != polyMesh::defaultRegion + ? regionName + : word::null ); - for (fileName& cloudDir : cloudDirs) - { - const word cloudName(std::move(cloudDir)); + const fileName cloudPrefix(regionDir/cloud::prefix); - IOobjectList cloudObjs + for (const instant& inst : timeDirs) + { + const word& timeName = inst.name(); + + // DO NOT USE -->> runTime.setTime(timeDirs[timeI], timeI); <<-- + // It incurs a large overhead when done so frequently. + + fileNameList cloudDirs ( - mesh, - timeName, - cloudPrefix/cloudName + readDir + ( + mesh.time().path()/timeName/cloudPrefix, + fileName::DIRECTORY + ) ); - // Clouds require "coordinates". - // The "positions" are for v1706 and lower. - // - detect and remove since these are treated specially - - bool isCloud = false; - if (cloudObjs.erase("coordinates")) + for (fileName& cloudDir : cloudDirs) { - isCloud = true; - } - if (cloudObjs.erase("positions")) - { - isCloud = true; - } + const word cloudName(std::move(cloudDir)); - if (isCloud) - { - // Save the cloud fields on a per cloud basis - auto& fieldsPerCloud = cloudFields(cloudName); + IOobjectList cloudObjs + ( + mesh, + timeName, + cloudPrefix/cloudName + ); - forAllConstIters(cloudObjs, fieldIter) + // Clouds require "coordinates". + // The "positions" are for v1706 and lower. + // - detect and remove since these are treated specially + + bool isCloud = false; + if (cloudObjs.erase("coordinates")) { - const IOobject* io = *fieldIter; + isCloud = true; + } + if (cloudObjs.erase("positions")) + { + isCloud = true; + } - // Field name/type - fieldsPerCloud.insert(io->name(), io->headerClassName()); + if (isCloud) + { + // Save the cloud fields on a per cloud basis + auto& fieldsPerCloud = cloudFields(cloudName); + + forAllConstIters(cloudObjs, fieldIter) + { + const IOobject* io = *fieldIter; + + // Field name/type + fieldsPerCloud.insert + ( + io->name(), + io->headerClassName() + ); + } } } } @@ -70,24 +102,42 @@ if (timeDirs.size() && doLagrangian) if (Pstream::parRun()) { - Pstream::mapCombineGather(cloudFields, HashTableOps::plusEqOp()); - Pstream::mapCombineScatter(cloudFields); - } - - if (cloudFields.empty()) - { - Info<< "none detected." << endl; + for (auto& cloudFields : regionCloudFields) + { + Pstream::mapCombineGather + ( + cloudFields, + HashTableOps::plusEqOp() + ); + Pstream::mapCombineScatter(cloudFields); + } } } - // Sorted list of cloud names -const wordList cloudNames(cloudFields.sortedToc()); +List regionCloudNames(meshes.size()); -if (cloudNames.size()) { - // Complete the echo information - as flatOutput - cloudNames.writeList(Info) << endl; + wordHashSet allRegionClouds; + + forAll(regionCloudNames, regioni) + { + regionCloudNames[regioni] = regionCloudFields[regioni].sortedToc(); + + allRegionClouds.insert(regionCloudNames[regioni]); + } + + const wordList allCloudNames(allRegionClouds.sortedToc()); + + if (allRegionClouds.empty()) + { + Info<< "none detected." << endl; + } + else + { + // Complete the echo information - as flatOutput + allRegionClouds.writeList(Info) << endl; + } } diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C index f5e44823b6..706b5ae63d 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C @@ -124,6 +124,7 @@ Usage #include "OFstream.H" #include "PstreamCombineReduceOps.H" #include "HashOps.H" +#include "regionProperties.H" #include "fvc.H" #include "fvMesh.H" @@ -135,8 +136,10 @@ Usage // file-format/conversion #include "ensightCase.H" #include "ensightGeoFile.H" +#include "ensightFaMesh.H" #include "ensightMesh.H" #include "ensightOutputCloud.H" +#include "ensightOutputAreaField.H" #include "ensightOutputVolField.H" // local files @@ -144,6 +147,7 @@ Usage #include "writeVolFields.H" #include "writeDimFields.H" #include "writePointFields.H" +#include "writeAreaFields.H" #include "memInfo.H" @@ -166,7 +170,7 @@ int main(int argc, char *argv[]) argList::setAdvanced("decomposeParDict"); argList::setAdvanced("noFunctionObjects"); - #include "addRegionOption.H" + #include "addAllRegionOptions.H" argList::addBoolOption ( @@ -253,6 +257,12 @@ int main(int argc, char *argv[]) // "one-boundary", // allPatches // "Combine all patches into a single part" // ); + argList::addBoolOption + ( + "finite-area", + "Write finite area fields", + true // mark as an advanced option + ); argList::addOption ( @@ -292,9 +302,11 @@ int main(int argc, char *argv[]) ); argList::addOptionCompat("cellZones", {"cellZone", 1912}); - #include "setRootCase.H" + // ------------------------------------------------------------------------ + // Configuration + // Default to binary output, unless otherwise specified const IOstream::streamFormat format = ( @@ -303,28 +315,11 @@ int main(int argc, char *argv[]) : IOstream::BINARY ); - cpuTime timer; - memInfo mem; - Info<< "Initial memory " << mem.update().size() << " kB" << endl; - - #include "createTime.H" - - instantList timeDirs = timeSelector::select0(runTime, args); - - #include "createNamedMesh.H" - - const word& regionDir = - ( - regionName == polyMesh::defaultRegion ? word::null : regionName - ); - - // - // Configuration - // const bool doBoundary = !args.found("no-boundary"); const bool doInternal = !args.found("no-internal"); const bool doCellZones = !args.found("no-cellZones"); const bool doLagrangian = !args.found("no-lagrangian"); + const bool doFiniteArea = args.found("finite-area"); const bool doPointValues = !args.found("no-point-data"); const bool nearCellValue = args.found("nearCellValue") && doBoundary; @@ -332,7 +327,6 @@ int main(int argc, char *argv[]) label indexingNumber(0); const bool doConsecutive = args.readIfPresent("index", indexingNumber); - // Write the geometry, unless otherwise specified bool doGeometry = !args.found("no-mesh"); @@ -361,15 +355,6 @@ int main(int argc, char *argv[]) // Can also have separate directory for lagrangian // caseOpts.separateCloud(true); - // Define sub-directory name to use for EnSight data. - // The path to the ensight directory is at case level only - // - For parallel cases, data only written from master - fileName outputDir = args.getOrDefault("name", "EnSight"); - if (!outputDir.isAbsolute()) - { - outputDir = args.globalPath()/outputDir; - } - ensightMesh::options writeOpts; writeOpts.useBoundaryMesh(doBoundary); writeOpts.useInternalMesh(doInternal); @@ -396,29 +381,64 @@ int main(int argc, char *argv[]) // Report the setup writeOpts.print(Info); - - // - // Output configuration (field related) - // - wordRes fieldPatterns; args.readListIfPresent("fields", fieldPatterns); - // New ensight case file, initialize header etc. - ensightCase ensCase(outputDir, args.globalCaseName(), caseOpts); + // ------------------------------------------------------------------------ - // Construct ensight mesh - ensightMesh ensMesh(mesh, writeOpts); + #include "createTime.H" + + instantList timeDirs = timeSelector::select0(runTime, args); + + // Handle -allRegions, -regions, -region + #include "getAllRegionOptions.H" + + // ------------------------------------------------------------------------ + // Directory management + + // Define sub-directory name to use for EnSight data. + // The path to the ensight directory is at case level only + // - For parallel cases, data only written from master + + // Sub-directory for output + const word ensDirName = args.getOrDefault("name", "EnSight"); + + fileName outputDir(args.globalPath()/ensDirName); + + if (!outputDir.isAbsolute()) + { + outputDir = args.globalPath()/outputDir; + } + + + // ------------------------------------------------------------------------ + cpuTime timer; + memInfo mem; + Info<< "Initial memory " << mem.update().size() << " kB" << endl; + + #include "createNamedMeshes.H" + #include "createMeshAccounting.H" if (Pstream::master()) { Info<< "Converting " << timeDirs.size() << " time steps" << nl; - ensCase.printInfo(Info) << endl; + // ensCase.printInfo(Info) << endl; } + // Check mesh motion #include "checkMeshMoving.H" + if (hasMovingMesh && !doGeometry) + { + Info<< "has moving mesh: ignoring '-no-mesh' option" << endl; + doGeometry = true; + } + + // Check lagrangian #include "findCloudFields.H" + // Check field availability + #include "checkFieldAvailability.H" + // test the pre-check variable if there is a moving mesh // time-set for geometries // TODO: split off into separate time-set, @@ -429,93 +449,116 @@ int main(int argc, char *argv[]) << mem.update().size() << " kB" << nl << endl; - // Initially all possible objects that are available at the final time - wordHashSet testedObjectNames; - { - IOobjectList objects(mesh, timeDirs.last().name()); - - if (!fieldPatterns.empty()) - { - objects.filterObjects(fieldPatterns); - } - - // Remove "*_0" restart fields - objects.prune_0(); - - if (!doPointValues) - { - // Prune point fields if disabled - objects.filterClasses - ( - [](const word& clsName) - { - return fieldTypes::point.found(clsName); - }, - true // prune - ); - } - - wordList objectNames(objects.sortedNames()); - - // Check availability for all times... - checkData(mesh, timeDirs, objectNames); - - testedObjectNames = objectNames; - } - - if (hasMovingMesh && !doGeometry) - { - Info<< "has moving mesh: ignoring '-no-mesh' option" << endl; - doGeometry = true; - } - forAll(timeDirs, timei) { runTime.setTime(timeDirs[timei], timei); - // Index for the Ensight case + // Index for the Ensight case(s). Continues if not possible #include "getTimeIndex.H" - ensCase.setTime(timeDirs[timei], timeIndex); - Info<< "Time [" << timeIndex << "] = " << runTime.timeName() << nl; - polyMesh::readUpdateState meshState = mesh.readUpdate(); - const bool moving = (meshState != polyMesh::UNCHANGED); - - if (moving) + forAll(regionNames, regioni) { - ensMesh.expire(); - ensMesh.correct(); - } + const word& regionName = regionNames[regioni]; + const word& regionDir = + ( + regionName != polyMesh::defaultRegion + ? regionName + : word::null + ); - if (timei == 0 || moving) - { - if (doGeometry) + if (regionNames.size() > 1) { - autoPtr os = ensCase.newGeometry(hasMovingMesh); - ensMesh.write(os); + Info<< "region=" << regionName << nl; } + + auto& mesh = meshes[regioni]; + + polyMesh::readUpdateState meshState = mesh.readUpdate(); + const bool moving = (meshState != polyMesh::UNCHANGED); + + // Ensight + auto& ensCase = ensightCases[regioni]; + auto& ensMesh = ensightMeshes[regioni]; + + // Finite-area (can be missing) + auto* ensFaCasePtr = ensightCasesFa.get(regioni); + auto* ensFaMeshPtr = ensightMeshesFa.get(regioni); + + ensCase.setTime(timeDirs[timei], timeIndex); + if (ensFaCasePtr) + { + ensFaCasePtr->setTime(timeDirs[timei], timeIndex); + } + + if (moving) + { + ensMesh.expire(); + ensMesh.correct(); + + if (ensFaMeshPtr) + { + ensFaMeshPtr->expire(); + ensFaMeshPtr->correct(); + } + } + + if ((timei == 0 || moving) && doGeometry) + { + // finite-volume + { + autoPtr os = + ensCase.newGeometry(hasMovingMesh); + ensMesh.write(os); + } + + // finite-area + if (ensFaCasePtr && ensFaMeshPtr) + { + autoPtr os = + ensFaCasePtr->newGeometry(hasMovingMesh); + ensFaMeshPtr->write(os); + } + } + + // Objects at this time + IOobjectList objects(mesh, runTime.timeName()); + + // Restrict to objects that are available for all times + objects.filterObjects + ( + availableRegionObjectNames[regioni] + ); + + // Volume, internal, point fields + #include "convertVolumeFields.H" + + // The finiteArea fields + #include "convertAreaFields.H" + + // Lagrangian fields + #include "convertLagrangian.H" } - // Objects at this time - IOobjectList objects(mesh, runTime.timeName()); - - // Restrict to objects that are available for all times - objects.filterObjects(testedObjectNames); - - // Volume, internal, point fields - #include "convertVolumeFields.H" - - // Lagrangian fields - #include "convertLagrangian.H" - Info<< "Wrote in " << timer.cpuTimeIncrement() << " s, " << mem.update().size() << " kB" << nl << nl; } - ensCase.write(); + // Write cases + forAll(ensightCases, regioni) + { + ensightCases[regioni].write(); + } + + forAll(ensightCasesFa, regioni) + { + if (ensightCasesFa.set(regioni)) + { + ensightCasesFa[regioni].write(); + } + } Info<< "\nEnd: " << timer.elapsedCpuTime() << " s, " diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/getTimeIndex.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/getTimeIndex.H index 0d8487fcac..f27848bf92 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/getTimeIndex.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/getTimeIndex.H @@ -1,8 +1,29 @@ -// Read time index from */uniform/time, but treat 0 and constant specially -// or simply increment from the '-index' option if it was supplied +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2011 OpenFOAM Foundation + Copyright (C) 2016-2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. + +Description + Read time index from ../uniform/time, but treat 0 and constant specially + or simply increment from the '-index' option if it was supplied + +Note + Does a 'continue' out of the loop if not possible to obtain an index + +\*---------------------------------------------------------------------------*/ label timeIndex = 0; { + bool goodTimeIndex = true; + if (doConsecutive) { timeIndex = indexingNumber++; @@ -21,7 +42,7 @@ label timeIndex = 0; runTime, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, - false // no register + false // no register ); if (io.typeHeaderOk(true, false)) @@ -33,8 +54,16 @@ label timeIndex = 0; } else { + goodTimeIndex = false; Info<< "skip ... missing entry " << io.objectPath() << endl; - continue; } } + + if (!goodTimeIndex) + { + continue; + } } + + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H new file mode 100644 index 0000000000..7f0609fd2f --- /dev/null +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H @@ -0,0 +1,129 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. + +InNamespace + Foam + +Description + Read finiteArea fields from disk and write ensightFaMesh + +\*---------------------------------------------------------------------------*/ + +#ifndef ensight_writeAreaFields_H +#define ensight_writeAreaFields_H + +#include "readFields.H" +#include "areaFaMesh.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +template +bool writeAreaField +( + ensightCase& ensCase, + const ensightFaMesh& ensMesh, + const tmp>& tfield +) +{ + if (!tfield.valid()) + { + return false; + } + const auto& field = tfield(); + + autoPtr os = + ensCase.newData(field.name()); + + bool wrote = ensightOutput::writeAreaField + ( + os.ref(), + field, + ensMesh + ); + + tfield.clear(); + return wrote; +} + + +template +label writeAreaFields +( + ensightCase& ensCase, + const ensightFaMesh& ensMesh, + const IOobjectList& objects +) +{ + typedef GeometricField GeoField; + + const faMesh& mesh = ensMesh.mesh(); + + label count = 0; + + for (const word& fieldName : objects.sortedNames()) + { + if + ( + writeAreaField + ( + ensCase, + ensMesh, + getField(objects.findObject(fieldName), mesh) + ) + ) + { + Info<< ' ' << fieldName; + ++count; + } + } + + return count; +} + + +label writeAllAreaFields +( + ensightCase& ensCase, + const ensightFaMesh& ensMesh, + const IOobjectList& objects +) +{ + #undef ensight_WRITE_FIELD + #define ensight_WRITE_FIELD(PrimitiveType) \ + writeAreaFields \ + ( \ + ensCase, \ + ensMesh, \ + objects \ + ) + + label count = 0; + count += ensight_WRITE_FIELD(scalar); + count += ensight_WRITE_FIELD(vector); + count += ensight_WRITE_FIELD(sphericalTensor); + count += ensight_WRITE_FIELD(symmTensor); + count += ensight_WRITE_FIELD(tensor); + + #undef ensight_WRITE_FIELD + return count; +} + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H index 6d5e335198..3573531f42 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H @@ -5,23 +5,10 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018-2020 OpenCFD Ltd. + Copyright (C) 2018-2021 OpenCFD Ltd. ------------------------------------------------------------------------------- License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see . + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. InNamespace Foam @@ -29,8 +16,6 @@ InNamespace Description Read dimensioned fields from disk and write with ensightMesh -SourceFiles - \*---------------------------------------------------------------------------*/ #ifndef ensight_writeDimFields_H diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H index 450c93611b..12256306c3 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H @@ -5,32 +5,16 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2020 OpenCFD Ltd. + Copyright (C) 2020-2021 OpenCFD Ltd. ------------------------------------------------------------------------------- License - This file is part of OpenFOAM. - - 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 . + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. InNamespace Foam Description - Read point fields from disk - and write as ensight data - -SourceFiles + Read point fields from disk and write as ensight data \*---------------------------------------------------------------------------*/ diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H index 5415a006c1..f6b6358a2a 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H @@ -5,23 +5,10 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018-2020 OpenCFD Ltd. + Copyright (C) 2018-2021 OpenCFD Ltd. ------------------------------------------------------------------------------- License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see . + This file is part of OpenFOAM, distributed under GPL-3.0-or-later. InNamespace Foam @@ -29,8 +16,6 @@ InNamespace Description Read volume fields from disk and write with ensightMesh -SourceFiles - \*---------------------------------------------------------------------------*/ #ifndef ensight_writeVolFields_H diff --git a/tutorials/finiteArea/surfactantFoam/planeTransport/Allrun-parallel b/tutorials/finiteArea/surfactantFoam/planeTransport/Allrun-parallel index 93e66772a9..0b836b1053 100755 --- a/tutorials/finiteArea/surfactantFoam/planeTransport/Allrun-parallel +++ b/tutorials/finiteArea/surfactantFoam/planeTransport/Allrun-parallel @@ -3,10 +3,11 @@ cd "${0%/*}" || exit # Run from this directory . ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions #------------------------------------------------------------------------------ -runApplication blockMesh - decompDict="-decomposeParDict system/decomposeParDict-procBoundary8" fileHandler="-fileHandler collated" +# reconstruct=true + +runApplication blockMesh runApplication $decompDict decomposePar $fileHandler @@ -14,6 +15,13 @@ runParallel $decompDict makeFaMesh $fileHandler runParallel $decompDict $(getApplication) $fileHandler -runApplication reconstructPar $fileHandler +runParallel $decompDict foamToEnsight -finite-area + +if [ "$reconstruct" = true ] +then + runApplication reconstructPar $fileHandler +else + echo "Skipping reconstructPar $fileHandler" +fi #------------------------------------------------------------------------------ diff --git a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun index 1099882346..a1d1744f36 100755 --- a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun +++ b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun @@ -24,8 +24,10 @@ done runApplication $(getApplication) -echo -echo "Use paraFoam -touch-all to create files for paraview post-processing" -echo +runApplication foamToEnsight -allRegions + +# echo +# echo "Use paraFoam -touch-all to create files for paraview post-processing" +# echo #------------------------------------------------------------------------------ diff --git a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun-parallel b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun-parallel index 041bfcf0cd..f30d3fc1b9 100755 --- a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun-parallel +++ b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/multiRegionHeaterRadiation/Allrun-parallel @@ -28,11 +28,13 @@ done # Run runParallel $(getApplication) +runParallel foamToEnsight -allRegions + # Reconstruct runApplication reconstructPar -allRegions -echo -echo "Use paraFoam -touch-all to create files for paraview post-processing" -echo +# echo +# echo "Use paraFoam -touch-all to create files for paraview post-processing" +# echo #------------------------------------------------------------------------------