mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
- 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
285 lines
7.8 KiB
C
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;
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|