mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: reduce startup time for ensight conversion (issue #240).
- Less looping when detecting lagrangian clouds and their fields. - Avoid using Time::setTime() and IOobjectList in tight loops. They both kill performance immensely. ENH: provide a -noLagrangian option to foamToEnsight and foamToEnsightParts for even more control.
This commit is contained in:
@ -12,14 +12,16 @@ if (timeDirs.size() > 1 && Pstream::master())
|
|||||||
Info<< "Search for moving mesh ... " << flush;
|
Info<< "Search for moving mesh ... " << flush;
|
||||||
forAll(timeDirs, timeI)
|
forAll(timeDirs, timeI)
|
||||||
{
|
{
|
||||||
|
const word& timeName = timeDirs[timeI].name();
|
||||||
|
|
||||||
meshMoving =
|
meshMoving =
|
||||||
(
|
(
|
||||||
timeDirs[timeI].name() != mesh.pointsInstance()
|
timeName != mesh.pointsInstance()
|
||||||
&& isDir(baseDir/timeDirs[timeI].name()/polyMesh::meshSubDir)
|
&& isDir(baseDir/timeName/polyMesh::meshSubDir)
|
||||||
&& IOobject
|
&& IOobject
|
||||||
(
|
(
|
||||||
"points",
|
"points",
|
||||||
timeDirs[timeI].name(),
|
timeName,
|
||||||
polyMesh::meshSubDir,
|
polyMesh::meshSubDir,
|
||||||
mesh,
|
mesh,
|
||||||
IOobject::NO_READ,
|
IOobject::NO_READ,
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
// check all time directories for the following:
|
||||||
|
|
||||||
|
// The fields for each cloud:
|
||||||
|
HashTable<HashTable<word>> cloudFields;
|
||||||
|
|
||||||
|
// Identify if lagrangian data exist at any time step.
|
||||||
|
if (timeDirs.size() && !noLagrangian)
|
||||||
|
{
|
||||||
|
const fileName& baseDir = mesh.time().path();
|
||||||
|
const fileName& cloudPrefix = regionPrefix/cloud::prefix;
|
||||||
|
|
||||||
|
Info<< "Searching for lagrangian ... " << flush;
|
||||||
|
|
||||||
|
forAll(timeDirs, timeI)
|
||||||
|
{
|
||||||
|
const word& timeName = timeDirs[timeI].name();
|
||||||
|
|
||||||
|
// DO NOT USE -->> runTime.setTime(timeDirs[timeI], timeI); <<--
|
||||||
|
// It incurs a large overhead when done so frequently.
|
||||||
|
|
||||||
|
fileNameList cloudDirs = readDir
|
||||||
|
(
|
||||||
|
baseDir/timeName/cloudPrefix,
|
||||||
|
fileName::DIRECTORY
|
||||||
|
);
|
||||||
|
|
||||||
|
forAll(cloudDirs, cloudI)
|
||||||
|
{
|
||||||
|
const word& cloudName = cloudDirs[cloudI];
|
||||||
|
|
||||||
|
IOobjectList cloudObjs
|
||||||
|
(
|
||||||
|
mesh,
|
||||||
|
timeName,
|
||||||
|
cloudPrefix/cloudName
|
||||||
|
);
|
||||||
|
|
||||||
|
// clouds always require "positions"
|
||||||
|
if (cloudObjs.found("positions"))
|
||||||
|
{
|
||||||
|
HashTable<HashTable<word>>::iterator cloudIter =
|
||||||
|
cloudFields.find(cloudName);
|
||||||
|
|
||||||
|
if (cloudIter == cloudFields.end())
|
||||||
|
{
|
||||||
|
// A newly discovered cloud
|
||||||
|
cloudFields.insert(cloudName, HashTable<word>());
|
||||||
|
cloudIter = cloudFields.find(cloudName);
|
||||||
|
}
|
||||||
|
|
||||||
|
forAllConstIter(IOobjectList, cloudObjs, fieldIter)
|
||||||
|
{
|
||||||
|
const IOobject obj = *fieldIter();
|
||||||
|
|
||||||
|
// Add field and field type
|
||||||
|
cloudIter().insert
|
||||||
|
(
|
||||||
|
obj.name(),
|
||||||
|
obj.headerClassName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prune out "positions" again since it gets treated specially
|
||||||
|
forAllIter(HashTable<HashTable<word>>, cloudFields, cloudIter)
|
||||||
|
{
|
||||||
|
cloudIter().erase("positions");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cloudFields.empty())
|
||||||
|
{
|
||||||
|
Info<< "none detected." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// sorted list of cloud names
|
||||||
|
const wordList cloudNames(cloudFields.sortedToc());
|
||||||
|
|
||||||
|
if (cloudNames.size())
|
||||||
|
{
|
||||||
|
// complete the echo information
|
||||||
|
Info<< "(";
|
||||||
|
forAll(cloudNames, cloudNo)
|
||||||
|
{
|
||||||
|
Info<< ' ' << cloudNames[cloudNo];
|
||||||
|
}
|
||||||
|
Info<< " ) " << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -42,13 +42,16 @@ Usage
|
|||||||
\param -noZero \n
|
\param -noZero \n
|
||||||
Exclude the often incomplete initial conditions.
|
Exclude the often incomplete initial conditions.
|
||||||
|
|
||||||
\param -patches patchList \n
|
\param -noLagrangian \n
|
||||||
Specify particular patches to write.
|
Suppress writing lagrangian positions and fields.
|
||||||
Specifying an empty list suppresses writing the internalMesh.
|
|
||||||
|
|
||||||
\param -noPatches \n
|
\param -noPatches \n
|
||||||
Suppress writing any patches.
|
Suppress writing any patches.
|
||||||
|
|
||||||
|
\param -patches patchList \n
|
||||||
|
Specify particular patches to write.
|
||||||
|
Specifying an empty list suppresses writing the internalMesh.
|
||||||
|
|
||||||
\param -faceZones zoneList \n
|
\param -faceZones zoneList \n
|
||||||
Specify faceZones to write, with wildcards
|
Specify faceZones to write, with wildcards
|
||||||
|
|
||||||
@ -126,6 +129,11 @@ int main(int argc, char *argv[])
|
|||||||
"write values in nodes"
|
"write values in nodes"
|
||||||
);
|
);
|
||||||
argList::addBoolOption
|
argList::addBoolOption
|
||||||
|
(
|
||||||
|
"noLagrangian",
|
||||||
|
"suppress writing lagrangian positions and fields"
|
||||||
|
);
|
||||||
|
argList::addBoolOption
|
||||||
(
|
(
|
||||||
"noPatches",
|
"noPatches",
|
||||||
"suppress writing any patches"
|
"suppress writing any patches"
|
||||||
@ -298,6 +306,8 @@ int main(int argc, char *argv[])
|
|||||||
fieldPatterns = wordReList(args.optionLookup("fields")());
|
fieldPatterns = wordReList(args.optionLookup("fields")());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool noLagrangian = args.optionFound("noLagrangian");
|
||||||
|
|
||||||
word cellZoneName;
|
word cellZoneName;
|
||||||
const bool doCellZone = args.optionReadIfPresent("cellZone", cellZoneName);
|
const bool doCellZone = args.optionReadIfPresent("cellZone", cellZoneName);
|
||||||
|
|
||||||
@ -334,6 +344,7 @@ int main(int argc, char *argv[])
|
|||||||
IOobjectList objects(mesh, runTime.timeName());
|
IOobjectList objects(mesh, runTime.timeName());
|
||||||
|
|
||||||
#include "checkMeshMoving.H"
|
#include "checkMeshMoving.H"
|
||||||
|
#include "findCloudFields.H"
|
||||||
|
|
||||||
if (Pstream::master())
|
if (Pstream::master())
|
||||||
{
|
{
|
||||||
@ -356,99 +367,19 @@ int main(int argc, char *argv[])
|
|||||||
<< setw(16) << "model:"
|
<< setw(16) << "model:"
|
||||||
<< ensightMesh::geometryName << nl;
|
<< ensightMesh::geometryName << nl;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Identify if lagrangian data exists any time step, and add clouds
|
|
||||||
// to the 'cloudNames' (sorted list)
|
|
||||||
wordList cloudNames;
|
|
||||||
{
|
|
||||||
wordHashSet allCloudNames;
|
|
||||||
|
|
||||||
forAll(timeDirs, timeI)
|
// Add the name of the cloud(s) to the case file header
|
||||||
{
|
|
||||||
runTime.setTime(timeDirs[timeI], timeI);
|
|
||||||
|
|
||||||
fileNameList cloudDirs = readDir
|
|
||||||
(
|
|
||||||
runTime.timePath()/regionPrefix/cloud::prefix,
|
|
||||||
fileName::DIRECTORY
|
|
||||||
);
|
|
||||||
|
|
||||||
forAll(cloudDirs, cloudI)
|
|
||||||
{
|
|
||||||
IOobjectList cloudObjs
|
|
||||||
(
|
|
||||||
mesh,
|
|
||||||
runTime.timeName(),
|
|
||||||
cloud::prefix/cloudDirs[cloudI]
|
|
||||||
);
|
|
||||||
|
|
||||||
IOobject* positionsPtr = cloudObjs.lookup(word("positions"));
|
|
||||||
|
|
||||||
if (positionsPtr)
|
|
||||||
{
|
|
||||||
allCloudNames.insert(cloudDirs[cloudI]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sorted for consistency
|
|
||||||
cloudNames = allCloudNames.sortedToc();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore special fields (_0 fields),
|
|
||||||
// ignore fields we don't handle,
|
|
||||||
// ignore fields that are not available for all time-steps
|
|
||||||
HashTable<bool> fieldsToUse;
|
|
||||||
|
|
||||||
HashTable<HashTable<word>> allCloudFields;
|
|
||||||
forAll(cloudNames, cloudNo)
|
forAll(cloudNames, cloudNo)
|
||||||
{
|
{
|
||||||
const word& cloudName = cloudNames[cloudNo];
|
const word& cloudName = cloudNames[cloudNo];
|
||||||
|
|
||||||
// Add the name of the cloud(s) to the case file header
|
|
||||||
if (Pstream::master())
|
|
||||||
{
|
|
||||||
ensightCaseFile
|
ensightCaseFile
|
||||||
<< setw(16) << "measured: 1"
|
<< setw(16) << "measured: 1"
|
||||||
<< fileName(dataMask/cloud::prefix/cloudName/"positions").c_str()
|
<< fileName
|
||||||
<< nl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new hash table for each cloud
|
|
||||||
allCloudFields.insert(cloudName, HashTable<word>());
|
|
||||||
|
|
||||||
// Identify the new cloud in the hash table
|
|
||||||
HashTable<HashTable<word>>::iterator newCloudIter =
|
|
||||||
allCloudFields.find(cloudName);
|
|
||||||
|
|
||||||
// Loop over all times to build list of fields and field types
|
|
||||||
// for each cloud
|
|
||||||
forAll(timeDirs, timeI)
|
|
||||||
{
|
|
||||||
runTime.setTime(timeDirs[timeI], timeI);
|
|
||||||
|
|
||||||
IOobjectList cloudObjs
|
|
||||||
(
|
(
|
||||||
mesh,
|
dataMask/cloud::prefix/cloudName/"positions"
|
||||||
runTime.timeName(),
|
).c_str() << nl;
|
||||||
cloud::prefix/cloudName
|
|
||||||
);
|
|
||||||
|
|
||||||
forAllConstIter(IOobjectList, cloudObjs, fieldIter)
|
|
||||||
{
|
|
||||||
const IOobject obj = *fieldIter();
|
|
||||||
|
|
||||||
if (obj.name() != "positions")
|
|
||||||
{
|
|
||||||
// Add field and field type
|
|
||||||
newCloudIter().insert
|
|
||||||
(
|
|
||||||
obj.name(),
|
|
||||||
obj.headerClassName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,6 +387,11 @@ int main(int argc, char *argv[])
|
|||||||
<< timer.cpuTimeIncrement() << " s, "
|
<< timer.cpuTimeIncrement() << " s, "
|
||||||
<< mem.update().size() << " kB" << nl << endl;
|
<< mem.update().size() << " kB" << nl << endl;
|
||||||
|
|
||||||
|
// ignore special fields (_0 fields),
|
||||||
|
// ignore fields we don't handle,
|
||||||
|
// ignore fields that are not available for all time-steps
|
||||||
|
HashTable<bool> fieldsToUse;
|
||||||
|
|
||||||
label nTimeSteps = 0;
|
label nTimeSteps = 0;
|
||||||
forAll(timeDirs, timeIndex)
|
forAll(timeDirs, timeIndex)
|
||||||
{
|
{
|
||||||
@ -740,13 +676,7 @@ int main(int argc, char *argv[])
|
|||||||
forAll(cloudNames, cloudNo)
|
forAll(cloudNames, cloudNo)
|
||||||
{
|
{
|
||||||
const word& cloudName = cloudNames[cloudNo];
|
const word& cloudName = cloudNames[cloudNo];
|
||||||
if (!allCloudFields.found(cloudName))
|
const HashTable<word>& theseCloudFields = cloudFields[cloudName];
|
||||||
{
|
|
||||||
// extra safety
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const HashTable<word>& cloudFields = allCloudFields[cloudName];
|
|
||||||
|
|
||||||
fileNameList currentCloudDirs = readDir
|
fileNameList currentCloudDirs = readDir
|
||||||
(
|
(
|
||||||
@ -769,7 +699,7 @@ int main(int argc, char *argv[])
|
|||||||
format
|
format
|
||||||
);
|
);
|
||||||
|
|
||||||
forAllConstIter(HashTable<word>, cloudFields, fieldIter)
|
forAllConstIter(HashTable<word>, theseCloudFields, fieldIter)
|
||||||
{
|
{
|
||||||
const word& fieldName = fieldIter.key();
|
const word& fieldName = fieldIter.key();
|
||||||
const word& fieldType = fieldIter();
|
const word& fieldType = fieldIter();
|
||||||
|
|||||||
@ -8,7 +8,10 @@ HashTable<HashTable<word>> cloudFields;
|
|||||||
|
|
||||||
if (timeDirs.size())
|
if (timeDirs.size())
|
||||||
{
|
{
|
||||||
IOobjectList objs(mesh, timeDirs.last().name());
|
const fileName& cloudPrefix = regionPrefix/cloud::prefix;
|
||||||
|
const word& lastTimeName = timeDirs.last().name();
|
||||||
|
|
||||||
|
IOobjectList objs(mesh, lastTimeName);
|
||||||
|
|
||||||
forAllConstIter(IOobjectList, objs, fieldIter)
|
forAllConstIter(IOobjectList, objs, fieldIter)
|
||||||
{
|
{
|
||||||
@ -31,14 +34,17 @@ if (timeDirs.size())
|
|||||||
//
|
//
|
||||||
// now check for lagrangian/<cloudName>
|
// now check for lagrangian/<cloudName>
|
||||||
//
|
//
|
||||||
fileNameList cloudDirs = readDir
|
fileNameList cloudDirs;
|
||||||
|
if (!noLagrangian)
|
||||||
|
{
|
||||||
|
cloudDirs = readDir
|
||||||
(
|
(
|
||||||
runTime.path()
|
runTime.path()
|
||||||
/ timeDirs.last().name()
|
/ lastTimeName
|
||||||
/ regionPrefix
|
/ cloudPrefix,
|
||||||
/ cloud::prefix,
|
|
||||||
fileName::DIRECTORY
|
fileName::DIRECTORY
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
forAll(cloudDirs, cloudI)
|
forAll(cloudDirs, cloudI)
|
||||||
{
|
{
|
||||||
@ -54,8 +60,8 @@ if (timeDirs.size())
|
|||||||
IOobjectList objs
|
IOobjectList objs
|
||||||
(
|
(
|
||||||
mesh,
|
mesh,
|
||||||
timeDirs.last().name(),
|
lastTimeName,
|
||||||
cloud::prefix/cloudName
|
cloudPrefix/cloudName
|
||||||
);
|
);
|
||||||
|
|
||||||
bool hasPositions = false;
|
bool hasPositions = false;
|
||||||
@ -89,17 +95,27 @@ if (timeDirs.size())
|
|||||||
//
|
//
|
||||||
for (label i=0; volumeFields.size() && i < timeDirs.size(); ++i)
|
for (label i=0; volumeFields.size() && i < timeDirs.size(); ++i)
|
||||||
{
|
{
|
||||||
IOobjectList objs(mesh, timeDirs[i].name());
|
const word& timeName = timeDirs[i].name();
|
||||||
|
|
||||||
forAllIter(HashTable<word>, volumeFields, fieldIter)
|
// Everything is potentially missing, unless we discover otherwise
|
||||||
|
wordHashSet missing(volumeFields);
|
||||||
|
|
||||||
|
// Avoid -->> IOobjectList objs(mesh, timeName); <<--
|
||||||
|
// Too much overhead when done so frequently.
|
||||||
|
|
||||||
|
fileNameList contents = readDir
|
||||||
|
(
|
||||||
|
runTime.path()
|
||||||
|
/ timeName,
|
||||||
|
fileName::FILE
|
||||||
|
);
|
||||||
|
|
||||||
|
forAll(contents, fileI)
|
||||||
{
|
{
|
||||||
const word& fieldName = fieldIter.key();
|
missing.erase(contents[fileI].name());
|
||||||
|
}
|
||||||
|
|
||||||
if (!objs.found(fieldName))
|
volumeFields.erase(missing);
|
||||||
{
|
|
||||||
volumeFields.erase(fieldIter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,9 @@ Usage
|
|||||||
\param -noZero \n
|
\param -noZero \n
|
||||||
Exclude the often incomplete initial conditions.
|
Exclude the often incomplete initial conditions.
|
||||||
|
|
||||||
|
\param -noLagrangian \n
|
||||||
|
Suppress writing lagrangian positions and fields.
|
||||||
|
|
||||||
\param -index \<start\>\n
|
\param -index \<start\>\n
|
||||||
Ignore the time index contained in the time file and use a
|
Ignore the time index contained in the time file and use a
|
||||||
simple indexing when creating the \c Ensight/data/######## files.
|
simple indexing when creating the \c Ensight/data/######## files.
|
||||||
@ -101,6 +104,11 @@ int main(int argc, char *argv[])
|
|||||||
"and use simple indexing when creating the files"
|
"and use simple indexing when creating the files"
|
||||||
);
|
);
|
||||||
argList::addBoolOption
|
argList::addBoolOption
|
||||||
|
(
|
||||||
|
"noLagrangian",
|
||||||
|
"suppress writing lagrangian positions and fields"
|
||||||
|
);
|
||||||
|
argList::addBoolOption
|
||||||
(
|
(
|
||||||
"noMesh",
|
"noMesh",
|
||||||
"suppress writing the geometry. "
|
"suppress writing the geometry. "
|
||||||
@ -158,7 +166,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// control for renumbering iterations
|
// control for renumbering iterations
|
||||||
label indexingNumber = 0;
|
label indexingNumber = 0;
|
||||||
bool optIndex = args.optionReadIfPresent("index", indexingNumber);
|
const bool optIndex = args.optionReadIfPresent("index", indexingNumber);
|
||||||
|
const bool noLagrangian = args.optionFound("noLagrangian");
|
||||||
|
|
||||||
// always write the geometry, unless the -noMesh option is specified
|
// always write the geometry, unless the -noMesh option is specified
|
||||||
bool optNoMesh = args.optionFound("noMesh");
|
bool optNoMesh = args.optionFound("noMesh");
|
||||||
@ -389,15 +398,9 @@ int main(int argc, char *argv[])
|
|||||||
forAllConstIter(HashTable<HashTable<word>>, cloudFields, cloudIter)
|
forAllConstIter(HashTable<HashTable<word>>, cloudFields, cloudIter)
|
||||||
{
|
{
|
||||||
const word& cloudName = cloudIter.key();
|
const word& cloudName = cloudIter.key();
|
||||||
|
const fileName& cloudPrefix = regionPrefix/cloud::prefix;
|
||||||
|
|
||||||
if
|
if (!isDir(runTime.timePath()/cloudPrefix/cloudName))
|
||||||
(
|
|
||||||
!isDir
|
|
||||||
(
|
|
||||||
runTime.timePath()/regionPrefix/
|
|
||||||
cloud::prefix/cloudName
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -406,13 +409,15 @@ int main(int argc, char *argv[])
|
|||||||
(
|
(
|
||||||
mesh,
|
mesh,
|
||||||
runTime.timeName(),
|
runTime.timeName(),
|
||||||
cloud::prefix/cloudName
|
cloudPrefix/cloudName
|
||||||
);
|
);
|
||||||
|
|
||||||
// check that the positions field is present for this time
|
// check that the positions field is present for this time
|
||||||
IOobject* positionPtr = cloudObjs.lookup(word("positions"));
|
if (!cloudObjs.found("positions"))
|
||||||
if (positionPtr != NULL)
|
|
||||||
{
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ensightParticlePositions
|
ensightParticlePositions
|
||||||
(
|
(
|
||||||
mesh,
|
mesh,
|
||||||
@ -421,11 +426,6 @@ int main(int argc, char *argv[])
|
|||||||
cloudName,
|
cloudName,
|
||||||
format
|
format
|
||||||
);
|
);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Info<< "write " << cloudName << " (" << flush;
|
Info<< "write " << cloudName << " (" << flush;
|
||||||
|
|
||||||
@ -439,7 +439,7 @@ int main(int argc, char *argv[])
|
|||||||
if (!fieldObject)
|
if (!fieldObject)
|
||||||
{
|
{
|
||||||
Info<< "missing "
|
Info<< "missing "
|
||||||
<< runTime.timeName()/cloud::prefix/cloudName
|
<< runTime.timeName()/cloudPrefix/cloudName
|
||||||
/ fieldName
|
/ fieldName
|
||||||
<< endl;
|
<< endl;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user