From 294a3d05ba501fa00d74726b4510855f576e5de1 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 23 Jan 2018 15:39:45 +0100 Subject: [PATCH] BUG: problems converting clouds to ensight or vtk format (closes #708) - problems when the cloud was not available on all processors. - NB: ensight measured data only allows a single cloud, but foamToEnsight writes all clouds. --- .../foamToEnsight/ensightOutputCloud.H | 4 +- .../ensightOutputCloudTemplates.C | 19 ++- .../foamToEnsight/findCloudFields.H | 15 +- .../foamToEnsight/foamToEnsight.C | 24 +++- .../foamToEnsightParts/findFields.H | 60 ++++---- .../foamToEnsightParts/foamToEnsightParts.C | 33 +++-- .../dataConversion/foamToVTK/findClouds.H | 26 ++-- .../dataConversion/foamToVTK/foamToVTK.C | 133 ++++++++++++------ .../foamToVTK/foamVtkLagrangianWriter.C | 15 +- .../foamToVTK/foamVtkLagrangianWriter.H | 14 +- .../foamVtkLagrangianWriterTemplates.C | 42 ++++-- .../HashTables/HashTableOps/HashTableOps.H | 92 ++++++++++++ 12 files changed, 333 insertions(+), 144 deletions(-) create mode 100644 src/OpenFOAM/containers/HashTables/HashTableOps/HashTableOps.H diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.H index d8b87935eed..b768f5180ae 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.H @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -74,7 +74,7 @@ bool writeCloudField template<class Type> bool writeCloudField ( - const IOobject& fieldObject, + IOobject& fieldObject, const bool exists, autoPtr<ensightFile>& output ); diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloudTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloudTemplates.C index fcf68edc190..04fd865c2ca 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloudTemplates.C +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloudTemplates.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -36,8 +36,8 @@ License template<class Type> bool Foam::ensightCloud::writeCloudField ( - const Foam::IOField<Type>& field, - Foam::ensightFile& os + const IOField<Type>& field, + ensightFile& os ) { const bool exists = (returnReduce(field.size(), sumOp<label>()) > 0); @@ -125,14 +125,23 @@ bool Foam::ensightCloud::writeCloudField template<class Type> bool Foam::ensightCloud::writeCloudField ( - const Foam::IOobject& fieldObject, + IOobject& fieldObject, const bool exists, - Foam::autoPtr<Foam::ensightFile>& output + autoPtr<ensightFile>& output ) { if (exists) { + // when exists == true, it exists globally, + // but can still be missing on the local processor. + // Handle this by READ_IF_PRESENT instead. + + const IOobject::readOption rOpt = fieldObject.readOpt(); + fieldObject.readOpt() = IOobject::READ_IF_PRESENT; + IOField<Type> field(fieldObject); + fieldObject.readOpt() = rOpt; + writeCloudField(field, output.rawRef()); } diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H index 650258ef1f2..c7fec95c0a4 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H @@ -7,7 +7,7 @@ HashTable<HashTable<word>> cloudFields; if (timeDirs.size() && !noLagrangian) { const fileName& baseDir = mesh.time().path(); - const fileName& cloudPrefix = regionPrefix/cloud::prefix; + const fileName cloudPrefix(regionPrefix/cloud::prefix); Info<< "Searching for lagrangian ... " << flush; @@ -35,11 +35,12 @@ if (timeDirs.size() && !noLagrangian) cloudPrefix/cloudName ); - // Clouds always have "positions" (v1706 and lower) or "coordinates" - if (cloudObjs.found("positions") || cloudObjs.found("coordinates")) + // Clouds require "coordinates". + // The "positions" are for v1706 and lower. + if (cloudObjs.found("coordinates") || cloudObjs.found("positions")) { // Save the cloud fields on a per cloud basis - auto fieldsPerCloud = cloudFields(cloudName); + auto& fieldsPerCloud = cloudFields(cloudName); forAllConstIters(cloudObjs, fieldIter) { @@ -59,6 +60,12 @@ if (timeDirs.size() && !noLagrangian) cloudIter().erase("positions"); } + if (Pstream::parRun()) + { + Pstream::mapCombineGather(cloudFields, HashTablePlusEqOp<word>()); + Pstream::mapCombineScatter(cloudFields); + } + if (cloudFields.empty()) { Info<< "none detected." << endl; diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C index 737b3e5b648..d183ce5b355 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -72,6 +72,8 @@ Note #include "IOobjectList.H" #include "IOmanip.H" #include "OFstream.H" +#include "PstreamCombineReduceOps.H" +#include "HashTableOps.H" #include "fvc.H" #include "volFields.H" @@ -622,8 +624,13 @@ int main(int argc, char *argv[]) Info<< "Write " << cloudName << " ("; - bool cloudExists = currentCloudDirs.found(cloudName); - reduce(cloudExists, orOp<bool>()); + const bool cloudExists = + returnReduce + ( + currentCloudDirs.found(cloudName), + orOp<bool>() + ); + { autoPtr<ensightFile> os = ensCase.newCloud(cloudName); @@ -643,10 +650,10 @@ int main(int argc, char *argv[]) } } - forAllConstIter(HashTable<word>, theseCloudFields, fieldIter) + forAllConstIters(theseCloudFields, fieldIter) { const word& fieldName = fieldIter.key(); - const word& fieldType = fieldIter(); + const word& fieldType = fieldIter.object(); IOobject fieldObject ( @@ -657,10 +664,13 @@ int main(int argc, char *argv[]) IOobject::MUST_READ ); - // cannot have field without cloud positions - bool fieldExists = cloudExists; + bool fieldExists = cloudExists; // No field without positions if (cloudExists) { + // Want MUST_READ (globally) and valid=false (locally), + // but that combination does not work. + // So check the header and sync globally + fieldExists = fieldObject.typeHeaderOk<IOField<scalar>>(false); diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/findFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/findFields.H index 9ac1c568080..1172760228e 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/findFields.H +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/findFields.H @@ -8,8 +8,8 @@ HashTable<HashTable<word>> cloudFields; if (timeDirs.size()) { - const fileName& cloudPrefix = regionPrefix/cloud::prefix; const word& lastTimeName = timeDirs.last().name(); + const fileName cloudPrefix(regionPrefix/cloud::prefix); IOobjectList objs(mesh, lastTimeName); @@ -28,7 +28,7 @@ if (timeDirs.size()) // - // now check for lagrangian/<cloudName> + // Now check for lagrangian/<cloudName> // fileNameList cloudDirs; if (!noLagrangian) @@ -46,48 +46,45 @@ if (timeDirs.size()) { const word& cloudName = cloudDirs[cloudI]; - // Create a new hash table for each cloud - cloudFields.insert(cloudName, HashTable<word>()); - - // Identify the new cloud within the hash table - HashTable<HashTable<word>>::iterator cloudIter = - cloudFields.find(cloudName); - - IOobjectList objs + IOobjectList cloudObjs ( mesh, lastTimeName, cloudPrefix/cloudName ); - bool hasCoordinates = false; - forAllConstIter(IOobjectList, objs, fieldIter) + // Clouds require "coordinates". + // The "positions" are for v1706 and lower. + if (cloudObjs.found("coordinates") || cloudObjs.found("positions")) { - const IOobject obj = *fieldIter(); - const word& fieldName = obj.name(); - const word& fieldType = obj.headerClassName(); + // Save the cloud fields on a per cloud basis + auto& fieldsPerCloud = cloudFields(cloudName); - if (fieldName == "positions" || fieldName == "coordinates") - { - hasCoordinates = true; - } - else if (cloudFieldTypes.found(fieldType)) + forAllConstIters(cloudObjs, fieldIter) { - // simply ignore types that we don't handle - cloudIter().insert(fieldName, fieldType); - } - } + const IOobject* obj = fieldIter(); - // drop this cloud if it has no positions or is otherwise empty - if (!hasCoordinates || cloudIter().empty()) - { - Info<< "removing cloud " << cloudName << endl; - cloudFields.erase(cloudIter); + const word& fieldName = obj->name(); + const word& fieldType = obj->headerClassName(); + + if (cloudFieldTypes.found(fieldType)) + { + // Field name/type - ignore types that we don't handle + fieldsPerCloud.insert(fieldName, fieldType); + } + } } } + // Only retain a cloud that actually has fields + cloudFields.filterValues + ( + [](const HashTable<word>& v){ return v.size(); } + ); + + // - // verify that the variable is present for all times + // Verify that the variable is present for all times // for (label i=0; volumeFields.size() && i < timeDirs.size(); ++i) { @@ -114,3 +111,6 @@ if (timeDirs.size()) volumeFields.erase(missing); } } + + +// ************************************************************************* // diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C index bac5a91a440..6b6e4d15e9f 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C +++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -275,10 +275,10 @@ int main(int argc, char *argv[]) Info<< "Write volume field (" << flush; - forAllConstIter(HashTable<word>, volumeFields, fieldIter) + forAllConstIters(volumeFields, fieldIter) { const word& fieldName = fieldIter.key(); - const word& fieldType = fieldIter(); + const word& fieldType = fieldIter.object(); IOobject fieldObject ( @@ -364,10 +364,12 @@ int main(int argc, char *argv[]) Info<< " )" << endl; // Check for clouds - forAllConstIter(HashTable<HashTable<word>>, cloudFields, cloudIter) + forAllConstIters(cloudFields, cloudIter) { const word& cloudName = cloudIter.key(); - const fileName& cloudPrefix = regionPrefix/cloud::prefix; + const HashTable<word>& theseCloudFields = cloudIter.object(); + + const fileName cloudPrefix(regionPrefix/cloud::prefix); if (!isDir(runTime.timePath()/cloudPrefix/cloudName)) { @@ -381,13 +383,15 @@ int main(int argc, char *argv[]) cloudPrefix/cloudName ); - // Check that the positions/coordinates field is present for this - // time - if + // Clouds require "coordinates". + // The "positions" are for v1706 and lower. + const bool cloudExists = ( - !cloudObjs.found("positions") - || !cloudObjs.found("coordinates") - ) + cloudObjs.found("coordinates") + || cloudObjs.found("positions") + ); + + if (!cloudExists) { continue; } @@ -403,18 +407,17 @@ int main(int argc, char *argv[]) Info<< " positions"; - forAllConstIter(HashTable<word>, cloudIter(), fieldIter) + forAllConstIters(theseCloudFields, fieldIter) { const word& fieldName = fieldIter.key(); - const word& fieldType = fieldIter(); + const word& fieldType = fieldIter.object(); IOobject *fieldObject = cloudObjs.lookup(fieldName); if (!fieldObject) { Info<< "missing " - << runTime.timeName()/cloudPrefix/cloudName - / fieldName + << runTime.timeName()/cloudPrefix/cloudName/fieldName << endl; continue; } diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/findClouds.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/findClouds.H index 115c4b3d3b4..ebeb36cbff9 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToVTK/findClouds.H +++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/findClouds.H @@ -1,12 +1,12 @@ // check all time directories for the following: // Any cloud names: -HashSet<fileName> allCloudDirs; +HashSet<word> allCloudDirs; if (timeDirs.size() && !noLagrangian) { const fileName& baseDir = mesh.time().path(); - const fileName& cloudPrefix = regionPrefix/cloud::prefix; + const fileName cloudPrefix(regionPrefix/cloud::prefix); Info<< "Searching for lagrangian ... " << flush; @@ -32,14 +32,15 @@ if (timeDirs.size() && !noLagrangian) cloudPrefix/cloudName ); - // Clouds always require "positions"/"coordinates" - if (cloudObjs.found("positions") || cloudObjs.found("coordinates")) + // Clouds require "coordinates". + // The "positions" are for v1706 and lower. + if (cloudObjs.found("coordinates") || cloudObjs.found("positions")) { if (allCloudDirs.insert(cloudName)) { - Info<< "At time: " << timeName + Info<< nl << " At time: " << timeName << " detected cloud directory : " << cloudName - << endl; + << flush; } } } @@ -49,14 +50,21 @@ if (timeDirs.size() && !noLagrangian) { Info<< "none detected." << endl; } + + if (Pstream::parRun()) + { + Pstream::combineGather(allCloudDirs, HashSetPlusEqOp<word>()); + Pstream::combineScatter(allCloudDirs); + } } -// sorted list of cloud names -const fileNameList cloudNames(allCloudDirs.sortedToc()); + +// Sorted list of cloud names +const wordList cloudNames(allCloudDirs.sortedToc()); if (cloudNames.size()) { - // complete the echo information + // Complete the echo information Info<< "("; for (const word& cloudName : cloudNames) { diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C index c847be8b964..1630c793f23 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C +++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -146,6 +146,8 @@ Note #include "pointMesh.H" #include "volPointInterpolation.H" #include "emptyPolyPatch.H" +#include "PstreamCombineReduceOps.H" +#include "HashTableOps.H" #include "labelIOField.H" #include "scalarIOField.H" #include "sphericalTensorIOField.H" @@ -156,7 +158,6 @@ Note #include "passiveParticle.H" #include "stringOps.H" #include "areaFields.H" - #include "meshSubsetHelper.H" #include "readFields.H" #include "faceSet.H" @@ -190,13 +191,17 @@ void print(const char* msg, Ostream& os, const UPtrList<const GeoField>& flds) } -void print(Ostream& os, const wordList& flds) +void print(const char* msg, Ostream& os, const wordList& flds) { - forAll(flds, i) + if (flds.size()) { - os << ' ' << flds[i]; + os << msg; + forAll(flds, i) + { + os << ' ' << flds[i]; + } + os << endl; } - os << endl; } @@ -617,6 +622,16 @@ int main(int argc, char *argv[]) pointTensorField::typeName }; + // Supported cloud (lagrangian) field types + const wordHashSet cFieldTypes + { + labelIOField::typeName, + scalarIOField::typeName, + vectorIOField::typeName, + symmTensorIOField::typeName, + tensorIOField::typeName + }; + forAll(timeDirs, timei) { runTime.setTime(timeDirs[timei], timei); @@ -1446,7 +1461,7 @@ int main(int argc, char *argv[]) // //--------------------------------------------------------------------- - for (const fileName& cloudName : cloudNames) + for (const word& cloudName : cloudNames) { // Always create the cloud directory. mkDir(fvPath/cloud::prefix/cloudName); @@ -1459,50 +1474,84 @@ int main(int argc, char *argv[]) Info<< " Lagrangian: " << relativeName(runTime, outputName) << nl; - IOobjectList sprayObjs + IOobjectList cloudObjs ( mesh, runTime.timeName(), cloud::prefix/cloudName ); - if (sprayObjs.found("positions") || sprayObjs.found("coordinates")) + // Clouds require "coordinates". + // The "positions" are for v1706 and lower. + bool cloudExists = + ( + cloudObjs.found("coordinates") + || cloudObjs.found("positions") + ); + reduce(cloudExists, orOp<bool>()); + + if (cloudExists) { - wordList labelNames(sprayObjs.names(labelIOField::typeName)); - Info<< " labels :"; - print(Info, labelNames); + // Limited to types that we explicitly handle + HashTable<wordHashSet> cloudFields = cloudObjs.classes(); + cloudFields.retain(cFieldTypes); - wordList scalarNames(sprayObjs.names(scalarIOField::typeName)); - Info<< " scalars :"; - print(Info, scalarNames); + // The number of cloud fields (locally) + label nCloudFields = 0; + forAllConstIters(cloudFields, citer) + { + nCloudFields += citer.object().size(); + } - wordList vectorNames(sprayObjs.names(vectorIOField::typeName)); - Info<< " vectors :"; - print(Info, vectorNames); + // Ensure all processes have identical information + if (Pstream::parRun()) + { + Pstream::mapCombineGather + ( + cloudFields, + HashSetPlusEqOp<word>() + ); + Pstream::mapCombineScatter(cloudFields); + } - wordList sphereNames + + // Build lists of field names and echo some information + + const wordList labelNames ( - sprayObjs.names - ( - sphericalTensorIOField::typeName - ) + cloudFields(labelIOField::typeName).sortedToc() ); - Info<< " sphTensors :"; - print(Info, sphereNames); + print(" labels :", Info, labelNames); - wordList symmNames + const wordList scalarNames ( - sprayObjs.names - ( - symmTensorIOField::typeName - ) + cloudFields(scalarIOField::typeName).sortedToc() + ); + print(" scalars :", Info, scalarNames); + + const wordList vectorNames + ( + cloudFields(vectorIOField::typeName).sortedToc() + ); + print(" vectors :", Info, vectorNames); + + const wordList sphNames + ( + cloudFields(sphericalTensorIOField::typeName).sortedToc() ); - Info<< " symmTensors :"; - print(Info, symmNames); + print(" sphTensors :", Info, sphNames); - wordList tensorNames(sprayObjs.names(tensorIOField::typeName)); - Info<< " tensors :"; - print(Info, tensorNames); + const wordList symmNames + ( + cloudFields(symmTensorIOField::typeName).sortedToc() + ); + print(" symmTensors :", Info, symmNames); + + const wordList tensorNames + ( + cloudFields(tensorIOField::typeName).sortedToc() + ); + print(" tensors :", Info, tensorNames); vtk::lagrangianWriter writer ( @@ -1512,22 +1561,14 @@ int main(int argc, char *argv[]) fmtType ); - // Write number of fields - writer.beginParcelData - ( - labelNames.size() - + scalarNames.size() - + vectorNames.size() - + sphereNames.size() - + symmNames.size() - + tensorNames.size() - ); + // Write number of fields (on this processor) + writer.beginParcelData(nCloudFields); // Fields writer.writeIOField<label>(labelNames); writer.writeIOField<scalar>(scalarNames); writer.writeIOField<vector>(vectorNames); - writer.writeIOField<sphericalTensor>(sphereNames); + writer.writeIOField<sphericalTensor>(sphNames); writer.writeIOField<symmTensor>(symmNames); writer.writeIOField<tensor>(tensorNames); diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.C index 23e7621e7ff..60511094043 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.C +++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -65,7 +65,8 @@ void Foam::vtk::lagrangianWriter::writePoints() } else { - beginPiece(); // Tricky - hide in here + beginPiece(); // Tricky - hide begin piece in here + if (!nParcels_) return; // No parcels? ... skip everything else format().tag(vtk::fileTag::POINTS) .openDataArray<float,3>(vtk::dataArrayAttr::POINTS) @@ -219,16 +220,12 @@ Foam::vtk::lagrangianWriter::lagrangianWriter } -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::vtk::lagrangianWriter::~lagrangianWriter() -{} - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // void Foam::vtk::lagrangianWriter::beginParcelData(label nFields) { + if (!nParcels_) return; // Skip if there are no parcels + const vtk::fileTag dataType = ( useVerts_ @@ -249,6 +246,8 @@ void Foam::vtk::lagrangianWriter::beginParcelData(label nFields) void Foam::vtk::lagrangianWriter::endParcelData() { + if (!nParcels_) return; // Skip if there are no parcels + const vtk::fileTag dataType = ( useVerts_ diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.H index 5457ce8c605..5e6d2fc9c7b 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.H +++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.H @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -25,7 +25,7 @@ Class Foam::vtk::lagrangianWriter Description - Write fields (internal). + Write lagrangian positions and fields (clouds). SourceFiles lagrangianWriter.C @@ -36,11 +36,11 @@ SourceFiles #ifndef foamVtkLagrangianWriter_H #define foamVtkLagrangianWriter_H -#include "OFstream.H" #include "Cloud.H" #include "volFields.H" #include "pointFields.H" #include "foamVtkOutputOptions.H" +#include <fstream> // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -115,7 +115,7 @@ public: //- Destructor - ~lagrangianWriter(); + ~lagrangianWriter() = default; // Member Functions @@ -135,15 +135,17 @@ public: return nParcels_; } + //- Begin parcel data (point data). + // The nFields parameter is only needed for legacy format. void beginParcelData(label nFields); void endParcelData(); //- Write file footer void writeFooter(); - //- Write IOField + //- Write IOFields template<class Type> - void writeIOField(const wordList& objectNames); + void writeIOField(const wordList& fieldNames); }; diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriterTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriterTemplates.C index bc3a2fd6308..5b4181f55f7 100644 --- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriterTemplates.C +++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriterTemplates.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,30 +29,48 @@ License // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // template<class Type> -void Foam::vtk::lagrangianWriter::writeIOField -( - const wordList& objectNames -) +void Foam::vtk::lagrangianWriter::writeIOField(const wordList& fieldNames) { const int nCmpt(pTraits<Type>::nComponents); const bool useIntField = std::is_integral<typename pTraits<Type>::cmptType>(); - for (const word& fldName : objectNames) + const fileName cloudDir(cloud::prefix/cloudName_); + + for (const word& fldName : fieldNames) { - IOobject header + // Globally the field is expected to exist (MUST_READ), but can + // be missing on a local processor. + // + // However, constructing IOField with MUST_READ and valid=false fails. + // Workaround: READ_IF_PRESENT and verify the header globally + + IOobject fieldObject ( fldName, mesh_.time().timeName(), - cloud::prefix/cloudName_, + cloudDir, mesh_, - IOobject::MUST_READ, - IOobject::NO_WRITE, - false // no register + IOobject::READ_IF_PRESENT ); - IOField<Type> fld(header); + // Check global existence - could make an error + const bool fieldExists = + returnReduce + ( + fieldObject.typeHeaderOk<IOField<Type>>(false), + orOp<bool>() + ); + + if (!fieldExists) + { + continue; + } + + IOField<Type> fld(fieldObject); + + // NOTE: Could skip if there are no local parcels... if (useIntField) { diff --git a/src/OpenFOAM/containers/HashTables/HashTableOps/HashTableOps.H b/src/OpenFOAM/containers/HashTables/HashTableOps/HashTableOps.H new file mode 100644 index 00000000000..034742e59c7 --- /dev/null +++ b/src/OpenFOAM/containers/HashTables/HashTableOps/HashTableOps.H @@ -0,0 +1,92 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +InNamspace + Foam + +Description + Various functions to operate on HashTables. + +SourceFiles + HashTableOps.H + +\*---------------------------------------------------------------------------*/ + +#ifndef HashTableOps_H +#define HashTableOps_H + +#include "HashSet.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +//- Combine HashSet operation. Equivalent to 'a += b' +template<class Key=word, class Hash=string::hash> +struct HashSetPlusEqOp +{ + typedef HashSet<Key, Hash> value_type; + + void operator()(value_type& a, const value_type& b) const + { + a += b; + } +}; + + +//- Combine HashTable operation. Equivalent to 'a += b' +template<class T, class Key=word, class Hash=string::hash> +struct HashTablePlusEqOp +{ + typedef HashTable<T, Key, Hash> value_type; + + void operator()(value_type& a, const value_type& b) const + { + if (b.size()) + { + if (a.size()) + { + forAllConstIters(b, citer) + { + a.insert(citer.key(), citer.object()); + } + } + else + { + a = b; + } + } + } +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // -- GitLab