mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: refactor surface writer collated time management (#1600)
- abstracted out from ensight surface writer for potential reuse by other surface writers.
This commit is contained in:
@ -62,6 +62,7 @@ triSurface/patches/surfacePatch.C
|
||||
writers = writers
|
||||
|
||||
$(writers)/surfaceWriter.C
|
||||
$(writers)/caching/surfaceWriterCaching.C
|
||||
$(writers)/boundaryData/boundaryDataSurfaceWriter.C
|
||||
$(writers)/ensight/ensightSurfaceWriter.C
|
||||
$(writers)/foam/foamSurfaceWriter.C
|
||||
|
||||
275
src/surfMesh/writers/caching/surfaceWriterCaching.C
Normal file
275
src/surfMesh/writers/caching/surfaceWriterCaching.C
Normal file
@ -0,0 +1,275 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2020 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/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "surfaceWriterCaching.H"
|
||||
#include "ListOps.H"
|
||||
#include "Fstream.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Compare time values with tolerance
|
||||
static const equalOp<scalar> equalTimes(ROOTSMALL);
|
||||
|
||||
// Use ListOps findLower (with tolerance), to find the location of the next
|
||||
// time-related index.
|
||||
// The returned index is always 0 or larger (no negative values).
|
||||
static label findTimeIndex(const UList<scalar>& list, const scalar val)
|
||||
{
|
||||
label idx =
|
||||
findLower
|
||||
(
|
||||
list,
|
||||
val,
|
||||
0,
|
||||
[](const scalar a, const scalar b)
|
||||
{
|
||||
return (a < b) && (Foam::mag(b - a) > ROOTSMALL);
|
||||
}
|
||||
);
|
||||
|
||||
if (idx < 0 || !equalTimes(list[idx], val))
|
||||
{
|
||||
++idx;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::surfaceWriters::writerCaching::writerCaching(const word& cacheFileName)
|
||||
:
|
||||
dictName_(cacheFileName)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
const Foam::dictionary& Foam::surfaceWriters::writerCaching::fieldsDict() const
|
||||
{
|
||||
const dictionary* dictptr = cache_.findDict("fields", keyType::LITERAL);
|
||||
|
||||
if (!dictptr)
|
||||
{
|
||||
dictptr = &dictionary::null;
|
||||
}
|
||||
|
||||
return *dictptr;
|
||||
}
|
||||
|
||||
|
||||
Foam::dictionary& Foam::surfaceWriters::writerCaching::fieldDict
|
||||
(
|
||||
const word& fieldName
|
||||
)
|
||||
{
|
||||
return
|
||||
cache_
|
||||
.subDictOrAdd("fields", keyType::LITERAL)
|
||||
.subDictOrAdd(fieldName, keyType::LITERAL);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::surfaceWriters::writerCaching::remove(const word& fieldName)
|
||||
{
|
||||
dictionary* dictptr = cache_.findDict("fields", keyType::LITERAL);
|
||||
|
||||
if (dictptr)
|
||||
{
|
||||
return dictptr->remove(fieldName);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Foam::surfaceWriters::writerCaching::clear()
|
||||
{
|
||||
times_.clear();
|
||||
geoms_.clear();
|
||||
cache_.clear();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::label Foam::surfaceWriters::writerCaching::readPreviousTimes
|
||||
(
|
||||
const fileName& dictFile,
|
||||
const scalar timeValue
|
||||
)
|
||||
{
|
||||
// In 1906 and earlier, the fieldsDict contained "meshes" and "times"
|
||||
// entries, each with their own time values.
|
||||
// This makes it more difficult to define the exact correspondence
|
||||
// between geometry intervals and times.
|
||||
//
|
||||
// Now track the used geometry intervals as a bitSet.
|
||||
|
||||
|
||||
// Only called from master
|
||||
label timeIndex = 0;
|
||||
cache_.clear();
|
||||
|
||||
IFstream is(dictFile);
|
||||
|
||||
if (is.good() && cache_.read(is))
|
||||
{
|
||||
geoms_.clear();
|
||||
|
||||
cache_.readIfPresent("times", times_);
|
||||
timeIndex = findTimeIndex(times_, timeValue);
|
||||
|
||||
labelList geomIndices;
|
||||
scalarList meshTimes;
|
||||
|
||||
if (cache_.readIfPresent("geometry", geomIndices))
|
||||
{
|
||||
// Convert indices to bitSet entries
|
||||
geoms_.set(geomIndices);
|
||||
}
|
||||
else if (cache_.readIfPresent("meshes", meshTimes))
|
||||
{
|
||||
WarningInFunction
|
||||
<< nl
|
||||
<< "Setting geometry timeset information from time values"
|
||||
<< " (cache from an older OpenFOAM version)." << nl
|
||||
<< "This may not be fully reliable." << nl
|
||||
<< nl;
|
||||
|
||||
for (const scalar meshTime : meshTimes)
|
||||
{
|
||||
const label geomIndex = findTimeIndex(times_, meshTime);
|
||||
geoms_.set(geomIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Make length consistent with time information.
|
||||
// We read/write the indices instead of simply dumping the bitSet.
|
||||
// This makes the contents more human readable.
|
||||
geoms_.resize(times_.size());
|
||||
}
|
||||
|
||||
return timeIndex;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::surfaceWriters::writerCaching::update
|
||||
(
|
||||
const fileName& baseDir,
|
||||
const scalar timeValue,
|
||||
const bool geomChanged,
|
||||
const word& fieldName,
|
||||
const word& fieldType,
|
||||
const word& varName
|
||||
)
|
||||
{
|
||||
const fileName dictFile(baseDir/dictName_);
|
||||
|
||||
bool stateChanged = false;
|
||||
|
||||
const label timeIndex =
|
||||
(
|
||||
times_.empty()
|
||||
? readPreviousTimes(dictFile, timeValue)
|
||||
: findTimeIndex(times_, timeValue)
|
||||
);
|
||||
|
||||
|
||||
// Update stored times list and geometry index
|
||||
|
||||
if (timeIndex < geoms_.size()-1)
|
||||
{
|
||||
// Clear old content when shrinking
|
||||
geoms_.unset(timeIndex);
|
||||
}
|
||||
|
||||
// Extend or truncate list
|
||||
geoms_.resize(timeIndex+1);
|
||||
times_.resize(timeIndex+1, VGREAT);
|
||||
|
||||
if (!equalTimes(times_[timeIndex], timeValue))
|
||||
{
|
||||
stateChanged = true;
|
||||
times_[timeIndex] = timeValue;
|
||||
}
|
||||
|
||||
if (geomChanged)
|
||||
{
|
||||
stateChanged = true;
|
||||
geoms_.set(timeIndex);
|
||||
}
|
||||
|
||||
|
||||
// Update time/geometry information in dictionary
|
||||
cache_.set("times", times_);
|
||||
cache_.set("geometry", geoms_.sortedToc());
|
||||
|
||||
// Debugging, or if needed for older versions:
|
||||
//// cache_.set
|
||||
//// (
|
||||
//// "meshes",
|
||||
//// IndirectList<scalar>(times_, geoms_.sortedToc())
|
||||
//// );
|
||||
|
||||
// Add field information to dictionary
|
||||
dictionary& dict = fieldDict(fieldName);
|
||||
|
||||
if (dict.empty())
|
||||
{
|
||||
stateChanged = true;
|
||||
|
||||
dict.set("type", fieldType);
|
||||
if (!varName.empty() && varName != fieldName)
|
||||
{
|
||||
// Use variable name, if it differs from fieldName
|
||||
dict.set("name", varName);
|
||||
}
|
||||
}
|
||||
|
||||
if (stateChanged)
|
||||
{
|
||||
OFstream os(dictFile);
|
||||
os << "// State file for surface writer output" << nl << nl;
|
||||
cache_.write(os, false);
|
||||
|
||||
os << nl << "// End" << nl;
|
||||
}
|
||||
|
||||
return stateChanged;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
163
src/surfMesh/writers/caching/surfaceWriterCaching.H
Normal file
163
src/surfMesh/writers/caching/surfaceWriterCaching.H
Normal file
@ -0,0 +1,163 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2020 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/>.
|
||||
|
||||
Class
|
||||
Foam::surfaceWriters::writerCaching
|
||||
|
||||
Description
|
||||
Information for surface writers with collated times.
|
||||
|
||||
The class maintains an internal list of the known times
|
||||
as well as a file-cached version with the field information.
|
||||
The information is used for restarts.
|
||||
|
||||
SourceFiles
|
||||
surfaceWriterCaching.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef surfaceWriters_writerCaching_H
|
||||
#define surfaceWriters_writerCaching_H
|
||||
|
||||
#include "bitSet.H"
|
||||
#include "dictionary.H"
|
||||
#include "scalarList.H"
|
||||
#include "DynamicList.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
namespace surfaceWriters
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class writerCaching Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class writerCaching
|
||||
{
|
||||
// Private Data
|
||||
|
||||
//- Cache dictionary file name
|
||||
word dictName_;
|
||||
|
||||
//- The output times
|
||||
DynamicList<scalar> times_;
|
||||
|
||||
//- Indices in times_ when geometry (mesh) has been written
|
||||
bitSet geoms_;
|
||||
|
||||
//- Cached information for geometry, times, fields
|
||||
dictionary cache_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Read time information from dictFileName.
|
||||
// Returns timeIndex corresponding to timeValue
|
||||
label readPreviousTimes
|
||||
(
|
||||
const fileName& dictFile,
|
||||
const scalar timeValue
|
||||
);
|
||||
|
||||
//- Get or create a sub-dictionary for named field
|
||||
dictionary& fieldDict(const word& fieldName);
|
||||
|
||||
//- Remove named field
|
||||
bool remove(const word& fieldName);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct with specified cache name
|
||||
explicit writerCaching(const word& cacheFileName);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~writerCaching() = default;
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- The output times for fields
|
||||
const scalarList& times() const
|
||||
{
|
||||
return times_;
|
||||
}
|
||||
|
||||
//- Indices in times() when geometry (mesh) has been written
|
||||
const bitSet& geometries() const
|
||||
{
|
||||
return geoms_;
|
||||
}
|
||||
|
||||
//- The most current time index
|
||||
label latestTimeIndex() const
|
||||
{
|
||||
return max(0, times_.size()-1);
|
||||
}
|
||||
|
||||
//- The most current geometry index
|
||||
label latestGeomIndex() const
|
||||
{
|
||||
return max(0, geoms_.find_last());
|
||||
}
|
||||
|
||||
//- Get or create the 'fields' information dictionary.
|
||||
const dictionary& fieldsDict() const;
|
||||
|
||||
//- Clear all values
|
||||
void clear();
|
||||
|
||||
//- Update time/geometry information and file cache.
|
||||
//- This routine should only be called from the master process
|
||||
// \return True if there is a state change, which is either a
|
||||
// geometry change or a new time interval
|
||||
bool update
|
||||
(
|
||||
const fileName& baseDir, //!< Directory containing the cache file
|
||||
const scalar timeValue, //!< The current time value
|
||||
const bool geomChanged, //!< Monitored geometry changed
|
||||
const word& fieldName, //!< Name of field
|
||||
const word& fieldType, //!< Type of field
|
||||
const word& varName = word::null //!< Alternative field name
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace surfaceWriters
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -56,7 +56,7 @@ void Foam::surfaceWriters::ensightWriter::printTimeset
|
||||
(
|
||||
OSstream& os,
|
||||
const label ts,
|
||||
const scalar& timeValue
|
||||
const scalar timeValue
|
||||
)
|
||||
{
|
||||
os
|
||||
@ -176,7 +176,8 @@ Foam::surfaceWriters::ensightWriter::ensightWriter()
|
||||
:
|
||||
surfaceWriter(),
|
||||
writeFormat_(IOstream::ASCII),
|
||||
collateTimes_(true)
|
||||
collateTimes_(true),
|
||||
caching_("fieldsDict") // Historic name
|
||||
{}
|
||||
|
||||
|
||||
@ -190,7 +191,8 @@ Foam::surfaceWriters::ensightWriter::ensightWriter
|
||||
(
|
||||
IOstreamOption::formatEnum("format", options, IOstream::ASCII)
|
||||
),
|
||||
collateTimes_(options.getOrDefault("collateTimes", true))
|
||||
collateTimes_(options.getOrDefault("collateTimes", true)),
|
||||
caching_("fieldsDict") // Historic name
|
||||
{}
|
||||
|
||||
|
||||
@ -227,15 +229,13 @@ Foam::surfaceWriters::ensightWriter::ensightWriter
|
||||
|
||||
void Foam::surfaceWriters::ensightWriter::close()
|
||||
{
|
||||
times_.clear();
|
||||
meshes_.clear();
|
||||
cache_.clear();
|
||||
caching_.clear();
|
||||
surfaceWriter::close();
|
||||
}
|
||||
|
||||
|
||||
// Note that ensight does supports geometry in a separate file,
|
||||
// but setting this true leaves mesh files in the wrong places
|
||||
// but setting this true leaves geometry files in the wrong places
|
||||
// (when there are fields).
|
||||
//
|
||||
// Make this false to let the field writers take back control
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2019 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2020 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -61,8 +61,7 @@ SourceFiles
|
||||
#define ensightSurfaceWriter_H
|
||||
|
||||
#include "surfaceWriter.H"
|
||||
#include "bitSet.H"
|
||||
#include "DynamicList.H"
|
||||
#include "surfaceWriterCaching.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -87,27 +86,12 @@ class ensightWriter
|
||||
//- Collate times (default: true)
|
||||
bool collateTimes_;
|
||||
|
||||
//- The collated output times
|
||||
DynamicList<scalar> times_;
|
||||
|
||||
//- Indices in times_ when geometry (mesh) has been written (collated)
|
||||
bitSet meshes_;
|
||||
|
||||
//- Cached information for times, geometry, fields (collated)
|
||||
dictionary cache_;
|
||||
writerCaching caching_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Read time information from baseDir / dictName.
|
||||
// Returns timeIndex corresponding to timeValue
|
||||
label readPreviousTimes
|
||||
(
|
||||
const fileName& baseDir,
|
||||
const word& dictName,
|
||||
const scalar& timeValue
|
||||
);
|
||||
|
||||
//- The geometry can be any of the following:
|
||||
//
|
||||
// 0: constant/static
|
||||
@ -120,7 +104,7 @@ class ensightWriter
|
||||
(
|
||||
OSstream& os,
|
||||
const label ts,
|
||||
const scalar& timeValue
|
||||
const scalar timeValue
|
||||
);
|
||||
|
||||
//- Print time-set for ensight case file, with N times and 0-based
|
||||
|
||||
@ -26,122 +26,20 @@ License
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Compare time values with tolerance
|
||||
static const equalOp<scalar> equalTimes(ROOTSMALL);
|
||||
|
||||
// Use ListOps findLower (with tolerance), to find the location of the next
|
||||
// time-related index.
|
||||
// The returned index is always 0 or larger (no negative values).
|
||||
static label findTimeIndex(const UList<scalar>& list, const scalar val)
|
||||
{
|
||||
label idx =
|
||||
findLower
|
||||
(
|
||||
list,
|
||||
val,
|
||||
0,
|
||||
[](const scalar a, const scalar b)
|
||||
{
|
||||
return (a < b) && (Foam::mag(b - a) > ROOTSMALL);
|
||||
}
|
||||
);
|
||||
|
||||
if (idx < 0 || !equalTimes(list[idx], val))
|
||||
{
|
||||
++idx;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::label Foam::surfaceWriters::ensightWriter::readPreviousTimes
|
||||
(
|
||||
const fileName& baseDir,
|
||||
const word& dictName,
|
||||
const scalar& timeValue
|
||||
)
|
||||
{
|
||||
// In 1906 and earlier, the fieldsDict contained "meshes" and "times"
|
||||
// entries, each with their own time values.
|
||||
// This makes it more difficult to define the exact correspondence
|
||||
// between geometry intervals and times.
|
||||
//
|
||||
// We now instead track used geometry intervals as a bitSet.
|
||||
|
||||
|
||||
// Only called from master
|
||||
|
||||
label timeIndex = 0;
|
||||
|
||||
labelList geomIndices;
|
||||
scalarList meshTimes;
|
||||
|
||||
cache_.clear();
|
||||
|
||||
const fileName dictFile(baseDir/dictName);
|
||||
|
||||
if (isFile(dictFile))
|
||||
{
|
||||
IFstream is(dictFile);
|
||||
|
||||
if (is.good() && cache_.read(is))
|
||||
{
|
||||
meshes_.clear();
|
||||
|
||||
cache_.readIfPresent("times", times_);
|
||||
timeIndex = findTimeIndex(times_, timeValue);
|
||||
|
||||
if (cache_.readIfPresent("geometry", geomIndices))
|
||||
{
|
||||
// Convert indices to bitSet entries
|
||||
meshes_.set(geomIndices);
|
||||
}
|
||||
else if (cache_.readIfPresent("meshes", meshTimes))
|
||||
{
|
||||
WarningInFunction
|
||||
<< nl
|
||||
<< "Setting geometry timeset information from time values"
|
||||
<< " (fieldsDict from an older OpenFOAM version)." << nl
|
||||
<< "This may not be fully reliable." << nl
|
||||
<< nl;
|
||||
|
||||
for (const scalar& meshTime : meshTimes)
|
||||
{
|
||||
const label meshIndex = findTimeIndex(times_, meshTime);
|
||||
meshes_.set(meshIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Make length consistent with time information.
|
||||
// We read/write the indices instead of simply dumping the bitSet.
|
||||
// This makes the contents more human readable.
|
||||
meshes_.resize(times_.size());
|
||||
}
|
||||
}
|
||||
|
||||
return timeIndex;
|
||||
}
|
||||
|
||||
|
||||
int Foam::surfaceWriters::ensightWriter::geometryTimeset() const
|
||||
{
|
||||
if (meshes_.count() <= 1)
|
||||
const scalarList& times = caching_.times();
|
||||
const bitSet& geoms = caching_.geometries();
|
||||
|
||||
if (geoms.count() <= 1)
|
||||
{
|
||||
// Static
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (meshes_.size() == times_.size() && meshes_.all())
|
||||
if (geoms.size() == times.size() && geoms.all())
|
||||
{
|
||||
// Geometry changing is the same as fields changing
|
||||
return 1;
|
||||
@ -158,7 +56,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated()
|
||||
{
|
||||
// Collated?
|
||||
// ========
|
||||
// Geometry: rootdir/surfaceName/surfaceName.case
|
||||
// CaseFile: rootdir/surfaceName/surfaceName.case
|
||||
// Geometry: rootdir/surfaceName/surfaceName.mesh
|
||||
|
||||
wroteGeom_ = true;
|
||||
@ -173,6 +71,9 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
const Field<Type>& localValues
|
||||
)
|
||||
{
|
||||
// Geometry changed since last output? Capture now before any merging.
|
||||
const bool geomChanged = (!upToDate_);
|
||||
|
||||
checkOpen();
|
||||
|
||||
const ensight::FileName surfName(outputPath_.name());
|
||||
@ -181,7 +82,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
|
||||
// Collated
|
||||
// ========
|
||||
// Geometry: rootdir/surfaceName/surfaceName.case
|
||||
// CaseFile: rootdir/surfaceName/surfaceName.case
|
||||
// Geometry: rootdir/surfaceName/data/<index>/geometry
|
||||
// Field: rootdir/surfaceName/data/<index>/field
|
||||
|
||||
@ -210,11 +111,8 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
}
|
||||
|
||||
|
||||
// Mesh changed since last output? Do before any merging.
|
||||
const bool meshChanged = (!upToDate_);
|
||||
|
||||
|
||||
// geometry merge() implicit
|
||||
// Implicit geometry merge()
|
||||
tmp<Field<Type>> tfield = mergeField(localValues);
|
||||
|
||||
const meshedSurf& surf = surface();
|
||||
@ -226,42 +124,21 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
mkDir(outputFile.path());
|
||||
}
|
||||
|
||||
bool stateChanged = meshChanged;
|
||||
|
||||
const label timeIndex =
|
||||
(
|
||||
times_.empty()
|
||||
? readPreviousTimes(baseDir, "fieldsDict", timeValue)
|
||||
: findTimeIndex(times_, timeValue)
|
||||
);
|
||||
const bool stateChanged =
|
||||
caching_.update
|
||||
(
|
||||
baseDir,
|
||||
timeValue,
|
||||
geomChanged,
|
||||
fieldName,
|
||||
ensightPTraits<Type>::typeName,
|
||||
varName
|
||||
);
|
||||
|
||||
|
||||
// Update stored times list and mesh index
|
||||
|
||||
if (timeIndex < meshes_.size()-1)
|
||||
{
|
||||
// Clear old content when shrinking
|
||||
meshes_.unset(timeIndex);
|
||||
}
|
||||
|
||||
// Extend or truncate list
|
||||
meshes_.resize(timeIndex+1);
|
||||
times_.resize(timeIndex+1, VGREAT);
|
||||
|
||||
if (meshChanged)
|
||||
{
|
||||
meshes_.set(timeIndex);
|
||||
}
|
||||
|
||||
if (!equalTimes(times_[timeIndex], timeValue))
|
||||
{
|
||||
stateChanged = true;
|
||||
times_[timeIndex] = timeValue;
|
||||
}
|
||||
|
||||
|
||||
// The most current geometry index
|
||||
const label geomIndex(max(0, meshes_.find_last()));
|
||||
// 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,
|
||||
@ -273,126 +150,97 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
|
||||
|
||||
// Do case file
|
||||
if (stateChanged)
|
||||
{
|
||||
// Add time information to dictionary
|
||||
cache_.set("geometry", meshes_.sortedToc());
|
||||
cache_.set("times", times_);
|
||||
OFstream osCase(outputFile, IOstream::ASCII);
|
||||
|
||||
// Debugging, or if needed for older versions:
|
||||
//// cache_.set
|
||||
//// (
|
||||
//// "meshes",
|
||||
//// IndirectList<scalar>(times_, meshes_.sortedToc())
|
||||
//// );
|
||||
// Format options
|
||||
osCase.setf(ios_base::left);
|
||||
osCase.setf(ios_base::scientific, ios_base::floatfield);
|
||||
osCase.precision(5);
|
||||
|
||||
// Add field information to dictionary
|
||||
dictionary& fieldsDict = cache_.subDictOrAdd("fields");
|
||||
dictionary& fieldDict = fieldsDict.subDictOrAdd(fieldName);
|
||||
|
||||
if (fieldDict.empty())
|
||||
if (verbose_)
|
||||
{
|
||||
fieldDict.set("type", ensightPTraits<Type>::typeName);
|
||||
fieldDict.set("name", varName); // ensight variable name
|
||||
stateChanged = true;
|
||||
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
|
||||
|
||||
if (stateChanged)
|
||||
const label tsGeom = geometryTimeset();
|
||||
|
||||
osCase
|
||||
<< "FORMAT" << nl
|
||||
<< "type: ensight gold" << nl
|
||||
<< nl
|
||||
<< "GEOMETRY" << nl;
|
||||
|
||||
|
||||
if (tsGeom)
|
||||
{
|
||||
if (verbose_)
|
||||
{
|
||||
Info<< "Writing state file to fieldsDict" << endl;
|
||||
}
|
||||
{
|
||||
OFstream os(baseDir/"fieldsDict");
|
||||
os << "// Summary of Ensight fields, times" << nl << nl;
|
||||
cache_.write(os, false);
|
||||
}
|
||||
|
||||
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 = geometryTimeset();
|
||||
|
||||
// moving
|
||||
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;
|
||||
}
|
||||
|
||||
<< "model: " << tsGeom << " " // time-set (1|2)
|
||||
<< mask << geometryName.name() << nl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// steady
|
||||
osCase
|
||||
<< nl
|
||||
<< "VARIABLE" << nl;
|
||||
<< "model: "
|
||||
<< geometryName.c_str() << nl;
|
||||
}
|
||||
|
||||
osCase
|
||||
<< nl
|
||||
<< "VARIABLE" << nl;
|
||||
|
||||
|
||||
for (const entry& dEntry : fieldsDict)
|
||||
{
|
||||
const dictionary& subDict = dEntry.dict();
|
||||
for (const entry& dEntry : caching_.fieldsDict())
|
||||
{
|
||||
const dictionary& subDict = dEntry.dict();
|
||||
|
||||
const word fieldType(subDict.get<word>("type"));
|
||||
const word varName
|
||||
const word varType(subDict.get<word>("type"));
|
||||
const word varName
|
||||
(
|
||||
subDict.getOrDefault<word>
|
||||
(
|
||||
subDict.getOrDefault<word>
|
||||
(
|
||||
"name",
|
||||
dEntry.keyword() // fieldName as fallback
|
||||
)
|
||||
);
|
||||
|
||||
osCase
|
||||
<< fieldType
|
||||
<<
|
||||
(
|
||||
this->isPointData()
|
||||
? " per node: 1 " // time-set 1
|
||||
: " per element: 1 " // time-set 1
|
||||
)
|
||||
<< setw(15) << varName << ' '
|
||||
<< mask << varName << nl;
|
||||
}
|
||||
"name",
|
||||
dEntry.keyword() // fieldName as fallback
|
||||
)
|
||||
);
|
||||
|
||||
osCase
|
||||
<< nl
|
||||
<< "TIME" << nl;
|
||||
|
||||
printTimeset(osCase, 1, times_);
|
||||
if (tsGeom == 2)
|
||||
{
|
||||
printTimeset(osCase, 2, times_, meshes_);
|
||||
}
|
||||
|
||||
osCase << "# end" << nl;
|
||||
<< varType
|
||||
<<
|
||||
(
|
||||
this->isPointData()
|
||||
? " per node: 1 " // time-set 1
|
||||
: " per element: 1 " // time-set 1
|
||||
)
|
||||
<< setw(15) << varName << ' '
|
||||
<< mask << varName << nl;
|
||||
}
|
||||
|
||||
osCase
|
||||
<< nl
|
||||
<< "TIME" << nl;
|
||||
|
||||
printTimeset(osCase, 1, caching_.times());
|
||||
if (tsGeom == 2)
|
||||
{
|
||||
printTimeset
|
||||
(
|
||||
osCase,
|
||||
tsGeom,
|
||||
caching_.times(),
|
||||
caching_.geometries()
|
||||
);
|
||||
}
|
||||
|
||||
osCase << "# end" << nl;
|
||||
}
|
||||
|
||||
|
||||
@ -403,27 +251,28 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
||||
mkDir(dataDir);
|
||||
|
||||
|
||||
const fileName meshFile(baseDir/geometryName);
|
||||
const fileName geomFile(baseDir/geometryName);
|
||||
|
||||
// Ensight Geometry
|
||||
ensightOutputSurface part
|
||||
(
|
||||
surf.points(),
|
||||
surf.faces(),
|
||||
meshFile.name()
|
||||
geomFile.name()
|
||||
);
|
||||
|
||||
if (!exists(meshFile))
|
||||
if (!exists(geomFile))
|
||||
{
|
||||
if (verbose_)
|
||||
{
|
||||
Info<< "Writing mesh file to " << meshFile.name() << endl;
|
||||
Info<< "Writing geometry to " << geomFile.name() << endl;
|
||||
}
|
||||
|
||||
// Two-argument form for path-name to avoid validating base-dir
|
||||
ensightGeoFile osGeom
|
||||
(
|
||||
meshFile.path(),
|
||||
meshFile.name(),
|
||||
geomFile.path(),
|
||||
geomFile.name(),
|
||||
writeFormat_
|
||||
);
|
||||
part.write(osGeom); // serial
|
||||
|
||||
@ -37,7 +37,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated()
|
||||
|
||||
// Uncollated
|
||||
// ==========
|
||||
// Geometry: rootdir/<TIME>/surfaceName.case
|
||||
// CaseFile: rootdir/<TIME>/surfaceName.case
|
||||
// Geometry: rootdir/<TIME>/surfaceName.00000000.mesh
|
||||
|
||||
fileName outputDir;
|
||||
@ -85,7 +85,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated()
|
||||
<< nl
|
||||
<< "TIME" << nl;
|
||||
|
||||
printTimeset(osCase, 1, 0.0);
|
||||
printTimeset(osCase, 1, scalar(0));
|
||||
|
||||
ensightOutputSurface part
|
||||
(
|
||||
@ -116,9 +116,9 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated
|
||||
|
||||
// Uncollated
|
||||
// ==========
|
||||
// geometry: rootdir/time/<field>/surfaceName.case
|
||||
// geometry: rootdir/time/<field>/surfaceName.<index>.mesh
|
||||
// field: rootdir/time/<field>/surfaceName.<index>.<field>
|
||||
// CaseFile: rootdir/time/<field>/surfaceName.case
|
||||
// Geometry: rootdir/time/<field>/surfaceName.<index>.mesh
|
||||
// Field: rootdir/time/<field>/surfaceName.<index>.<field>
|
||||
|
||||
// Variable name as sub-directory for results. Eg,
|
||||
// - VAR1/SURF1.case
|
||||
|
||||
Reference in New Issue
Block a user