Files
openfoam/src/meshTools/coordSet/writers/ensight/ensightCoordSetWriterCollated.C
Mark Olesen 1afd27db6c BUG: incorrect ensight filename references (fixes #2532)
- Ensight places restrictions both on variable names and on file
  names. When generating the variable to file name correspondence for
  use in the Ensight case file, previously used the less stringent
  variable name for both sides of the variable table.

  This would lead to situations where the (valid) variable name
  referred to the wrong file name. Now apply the file-name restriction
  consistently when creating the variable table. This is especially
  necessary since the stem of the filename additionally has
  specific characters (eg, ":<>[]") that can be problematic for the
  shell or file-system.

ENH: avoid repeated '_' in qualified ensight names.

- when replacing undesirable characters (eg, ":<>[]") with '_', avoid
  duplicates.

  Eg, "PaSR<psiReactionThermo>:Qdot" becomes
      "PaSR_psiReactionThermo_Qdot" instead of
      "PaSR_psiReactionThermo__Qdot"

ENH: additional ensightCase::padded static method
2022-07-13 19:21:11 +02:00

285 lines
7.8 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
(
const bool writeTracks
)
{
// Collated?
// ========
// CaseFile: rootdir/NAME/NAME.case
// Geometry: rootdir/NAME/NAME.mesh
wroteGeom_ = true;
return fileName::null;
}
template<class Type>
Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs,
elemOutputType elemOutput
)
{
// Geometry changed since last output? Capture now
const bool geomChanged = (!upToDate_);
checkOpen();
const ensight::FileName baseName(outputPath_.name());
const ensight::VarName varName(fieldName);
// Collated
// ========
// CaseFile: rootdir/NAME/NAME.case
// Geometry: rootdir/NAME/data/<index>/geometry
// Field: rootdir/NAME/data/<index>/field
// Use geometry name as sub-directory for results. Eg,
// - NAME1/NAME1.case
// - NAME1/data/00000000/geometry
// - NAME1/data/00000000/VAR1
// - NAME1/data/00000000/VAR2
// Names "data" and "geometry" as per ensightCase:
const int maskWidth = 8;
const char* mask = "data/********/";
// Ignore the useTimeDir setting - manage ourselves
const fileName baseDir = outputPath_;
const word timeDir = timeName();
const scalar timeValue = currTime_.value();
const fileName outputFile = baseDir / baseName + ".case";
if (verbose_)
{
Info<< "Writing case file to " << outputFile << endl;
}
// Update geometry
merge();
{
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
const bool stateChanged =
caching_.update
(
baseDir,
timeValue,
geomChanged,
fieldName,
ensightPTraits<Type>::typeName,
varName
);
// The most current time and geometry indices
const label timeIndex = caching_.latestTimeIndex();
const label geomIndex = caching_.latestGeomIndex();
// This will be used for the name of a static geometry,
// or just the masking part for moving geometries.
const fileName geometryName
(
"data"
/ ensightCase::padded(maskWidth, geomIndex)
/ ensightCase::geometryName
);
// Location for data (and possibly the geometry as well)
const fileName dataDir
(
baseDir/"data"/ensightCase::padded(maskWidth, timeIndex)
);
// As per mkdir -p "data/00000000"
mkDir(dataDir);
const fileName geomFile(baseDir/geometryName);
if (!exists(geomFile))
{
if (verbose_)
{
Info<< "Writing geometry to " << geomFile.name() << endl;
}
// Two-argument form for path-name to avoid validating base-dir
ensightGeoFile osGeom
(
geomFile.path(),
geomFile.name(),
writeFormat_
);
writeGeometry(osGeom, elemOutput);
}
// Write field
ensightFile osField
(
dataDir,
varName,
writeFormat_
);
if (verbose_)
{
Info<< "Writing field file to " << osField.name() << endl;
}
// Write field (serial only)
writeTrackField<Type>(osField, fieldPtrs);
// Update case file
if (stateChanged)
{
OFstream osCase(outputFile, IOstream::ASCII);
// Format options
osCase.setf(ios_base::left);
osCase.setf(ios_base::scientific, ios_base::floatfield);
osCase.precision(5);
if (verbose_)
{
Info<< "Writing case file to " << osCase.name() << endl;
}
// The geometry can be any of the following:
// 0: constant/static
// 1: moving, with the same frequency as the data
// 2: moving, with different frequency as the data
const label tsGeom = caching_.geometryTimeset();
osCase
<< "FORMAT" << nl
<< "type: ensight gold" << nl
<< nl
<< "GEOMETRY" << nl;
if (tsGeom)
{
// moving
osCase
<< "model: " << tsGeom << " " // time-set (1|2)
<< mask << geometryName.name() << nl;
}
else
{
// steady
osCase
<< "model: "
<< geometryName.c_str() << nl;
}
osCase
<< nl
<< "VARIABLE" << nl;
for (const entry& dEntry : caching_.fieldsDict())
{
const dictionary& subDict = dEntry.dict();
const word varType(subDict.get<word>("type"));
const word varName
(
subDict.getOrDefault<word>
(
"name",
dEntry.keyword() // fieldName as fallback
)
);
osCase
<< varType
<<
(
true // this->isPointData()
? " per node: 1 " // time-set 1
: " per element: 1 " // time-set 1
)
<< setw(15) << varName << ' '
<< mask << ensight::FileName(varName).c_str() << nl;
}
osCase
<< nl
<< "TIME" << nl;
ensightCase::printTimeset(osCase, 1, caching_.times());
if (tsGeom == 2)
{
ensightCase::printTimeset
(
osCase,
tsGeom,
caching_.times(),
caching_.geometries()
);
}
osCase << "# end" << nl;
}
// Timestamp in the directory for future reference
{
OFstream timeStamp(dataDir/"time");
timeStamp
<< "# timestep time" << nl
<< dataDir.name() << ' ' << timeValue << nl;
}
}
wroteGeom_ = true;
return outputFile;
}
// ************************************************************************* //