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 = writers
|
||||||
|
|
||||||
$(writers)/surfaceWriter.C
|
$(writers)/surfaceWriter.C
|
||||||
|
$(writers)/caching/surfaceWriterCaching.C
|
||||||
$(writers)/boundaryData/boundaryDataSurfaceWriter.C
|
$(writers)/boundaryData/boundaryDataSurfaceWriter.C
|
||||||
$(writers)/ensight/ensightSurfaceWriter.C
|
$(writers)/ensight/ensightSurfaceWriter.C
|
||||||
$(writers)/foam/foamSurfaceWriter.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,
|
OSstream& os,
|
||||||
const label ts,
|
const label ts,
|
||||||
const scalar& timeValue
|
const scalar timeValue
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
os
|
os
|
||||||
@ -176,7 +176,8 @@ Foam::surfaceWriters::ensightWriter::ensightWriter()
|
|||||||
:
|
:
|
||||||
surfaceWriter(),
|
surfaceWriter(),
|
||||||
writeFormat_(IOstream::ASCII),
|
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)
|
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()
|
void Foam::surfaceWriters::ensightWriter::close()
|
||||||
{
|
{
|
||||||
times_.clear();
|
caching_.clear();
|
||||||
meshes_.clear();
|
|
||||||
cache_.clear();
|
|
||||||
surfaceWriter::close();
|
surfaceWriter::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Note that ensight does supports geometry in a separate file,
|
// 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).
|
// (when there are fields).
|
||||||
//
|
//
|
||||||
// Make this false to let the field writers take back control
|
// Make this false to let the field writers take back control
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2011 OpenFOAM Foundation
|
Copyright (C) 2011 OpenFOAM Foundation
|
||||||
Copyright (C) 2015-2019 OpenCFD Ltd.
|
Copyright (C) 2015-2020 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -61,8 +61,7 @@ SourceFiles
|
|||||||
#define ensightSurfaceWriter_H
|
#define ensightSurfaceWriter_H
|
||||||
|
|
||||||
#include "surfaceWriter.H"
|
#include "surfaceWriter.H"
|
||||||
#include "bitSet.H"
|
#include "surfaceWriterCaching.H"
|
||||||
#include "DynamicList.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -87,27 +86,12 @@ class ensightWriter
|
|||||||
//- Collate times (default: true)
|
//- Collate times (default: true)
|
||||||
bool collateTimes_;
|
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)
|
//- Cached information for times, geometry, fields (collated)
|
||||||
dictionary cache_;
|
writerCaching caching_;
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// 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:
|
//- The geometry can be any of the following:
|
||||||
//
|
//
|
||||||
// 0: constant/static
|
// 0: constant/static
|
||||||
@ -120,7 +104,7 @@ class ensightWriter
|
|||||||
(
|
(
|
||||||
OSstream& os,
|
OSstream& os,
|
||||||
const label ts,
|
const label ts,
|
||||||
const scalar& timeValue
|
const scalar timeValue
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Print time-set for ensight case file, with N times and 0-based
|
//- 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 * * * * * * * * * * * //
|
// * * * * * * * * * * * * * 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
|
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
|
// Static
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meshes_.size() == times_.size() && meshes_.all())
|
if (geoms.size() == times.size() && geoms.all())
|
||||||
{
|
{
|
||||||
// Geometry changing is the same as fields changing
|
// Geometry changing is the same as fields changing
|
||||||
return 1;
|
return 1;
|
||||||
@ -158,7 +56,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated()
|
|||||||
{
|
{
|
||||||
// Collated?
|
// Collated?
|
||||||
// ========
|
// ========
|
||||||
// Geometry: rootdir/surfaceName/surfaceName.case
|
// CaseFile: rootdir/surfaceName/surfaceName.case
|
||||||
// Geometry: rootdir/surfaceName/surfaceName.mesh
|
// Geometry: rootdir/surfaceName/surfaceName.mesh
|
||||||
|
|
||||||
wroteGeom_ = true;
|
wroteGeom_ = true;
|
||||||
@ -173,6 +71,9 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
const Field<Type>& localValues
|
const Field<Type>& localValues
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
// Geometry changed since last output? Capture now before any merging.
|
||||||
|
const bool geomChanged = (!upToDate_);
|
||||||
|
|
||||||
checkOpen();
|
checkOpen();
|
||||||
|
|
||||||
const ensight::FileName surfName(outputPath_.name());
|
const ensight::FileName surfName(outputPath_.name());
|
||||||
@ -181,7 +82,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
|
|
||||||
// Collated
|
// Collated
|
||||||
// ========
|
// ========
|
||||||
// Geometry: rootdir/surfaceName/surfaceName.case
|
// CaseFile: rootdir/surfaceName/surfaceName.case
|
||||||
// Geometry: rootdir/surfaceName/data/<index>/geometry
|
// Geometry: rootdir/surfaceName/data/<index>/geometry
|
||||||
// Field: rootdir/surfaceName/data/<index>/field
|
// 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_);
|
|
||||||
|
|
||||||
|
// Implicit geometry merge()
|
||||||
// geometry merge() implicit
|
|
||||||
tmp<Field<Type>> tfield = mergeField(localValues);
|
tmp<Field<Type>> tfield = mergeField(localValues);
|
||||||
|
|
||||||
const meshedSurf& surf = surface();
|
const meshedSurf& surf = surface();
|
||||||
@ -226,42 +124,21 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
mkDir(outputFile.path());
|
mkDir(outputFile.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stateChanged = meshChanged;
|
const bool stateChanged =
|
||||||
|
caching_.update
|
||||||
const label timeIndex =
|
|
||||||
(
|
(
|
||||||
times_.empty()
|
baseDir,
|
||||||
? readPreviousTimes(baseDir, "fieldsDict", timeValue)
|
timeValue,
|
||||||
: findTimeIndex(times_, timeValue)
|
geomChanged,
|
||||||
|
fieldName,
|
||||||
|
ensightPTraits<Type>::typeName,
|
||||||
|
varName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Update stored times list and mesh index
|
// The most current time and geometry indices
|
||||||
|
const label timeIndex = caching_.latestTimeIndex();
|
||||||
if (timeIndex < meshes_.size()-1)
|
const label geomIndex = caching_.latestGeomIndex();
|
||||||
{
|
|
||||||
// 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()));
|
|
||||||
|
|
||||||
|
|
||||||
// This will be used for the name of a static geometry,
|
// This will be used for the name of a static geometry,
|
||||||
@ -273,42 +150,8 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
|
|
||||||
|
|
||||||
// Do case file
|
// Do case file
|
||||||
{
|
|
||||||
// Add time information to dictionary
|
|
||||||
cache_.set("geometry", meshes_.sortedToc());
|
|
||||||
cache_.set("times", times_);
|
|
||||||
|
|
||||||
// Debugging, or if needed for older versions:
|
|
||||||
//// cache_.set
|
|
||||||
//// (
|
|
||||||
//// "meshes",
|
|
||||||
//// IndirectList<scalar>(times_, meshes_.sortedToc())
|
|
||||||
//// );
|
|
||||||
|
|
||||||
// Add field information to dictionary
|
|
||||||
dictionary& fieldsDict = cache_.subDictOrAdd("fields");
|
|
||||||
dictionary& fieldDict = fieldsDict.subDictOrAdd(fieldName);
|
|
||||||
|
|
||||||
if (fieldDict.empty())
|
|
||||||
{
|
|
||||||
fieldDict.set("type", ensightPTraits<Type>::typeName);
|
|
||||||
fieldDict.set("name", varName); // ensight variable name
|
|
||||||
stateChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (stateChanged)
|
if (stateChanged)
|
||||||
{
|
{
|
||||||
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);
|
OFstream osCase(outputFile, IOstream::ASCII);
|
||||||
|
|
||||||
// Format options
|
// Format options
|
||||||
@ -355,11 +198,11 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
<< "VARIABLE" << nl;
|
<< "VARIABLE" << nl;
|
||||||
|
|
||||||
|
|
||||||
for (const entry& dEntry : fieldsDict)
|
for (const entry& dEntry : caching_.fieldsDict())
|
||||||
{
|
{
|
||||||
const dictionary& subDict = dEntry.dict();
|
const dictionary& subDict = dEntry.dict();
|
||||||
|
|
||||||
const word fieldType(subDict.get<word>("type"));
|
const word varType(subDict.get<word>("type"));
|
||||||
const word varName
|
const word varName
|
||||||
(
|
(
|
||||||
subDict.getOrDefault<word>
|
subDict.getOrDefault<word>
|
||||||
@ -370,7 +213,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
);
|
);
|
||||||
|
|
||||||
osCase
|
osCase
|
||||||
<< fieldType
|
<< varType
|
||||||
<<
|
<<
|
||||||
(
|
(
|
||||||
this->isPointData()
|
this->isPointData()
|
||||||
@ -385,15 +228,20 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
<< nl
|
<< nl
|
||||||
<< "TIME" << nl;
|
<< "TIME" << nl;
|
||||||
|
|
||||||
printTimeset(osCase, 1, times_);
|
printTimeset(osCase, 1, caching_.times());
|
||||||
if (tsGeom == 2)
|
if (tsGeom == 2)
|
||||||
{
|
{
|
||||||
printTimeset(osCase, 2, times_, meshes_);
|
printTimeset
|
||||||
|
(
|
||||||
|
osCase,
|
||||||
|
tsGeom,
|
||||||
|
caching_.times(),
|
||||||
|
caching_.geometries()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
osCase << "# end" << nl;
|
osCase << "# end" << nl;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Location for data (and possibly the geometry as well)
|
// Location for data (and possibly the geometry as well)
|
||||||
@ -403,27 +251,28 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
|
|||||||
mkDir(dataDir);
|
mkDir(dataDir);
|
||||||
|
|
||||||
|
|
||||||
const fileName meshFile(baseDir/geometryName);
|
const fileName geomFile(baseDir/geometryName);
|
||||||
|
|
||||||
// Ensight Geometry
|
// Ensight Geometry
|
||||||
ensightOutputSurface part
|
ensightOutputSurface part
|
||||||
(
|
(
|
||||||
surf.points(),
|
surf.points(),
|
||||||
surf.faces(),
|
surf.faces(),
|
||||||
meshFile.name()
|
geomFile.name()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!exists(meshFile))
|
if (!exists(geomFile))
|
||||||
{
|
{
|
||||||
if (verbose_)
|
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
|
// Two-argument form for path-name to avoid validating base-dir
|
||||||
ensightGeoFile osGeom
|
ensightGeoFile osGeom
|
||||||
(
|
(
|
||||||
meshFile.path(),
|
geomFile.path(),
|
||||||
meshFile.name(),
|
geomFile.name(),
|
||||||
writeFormat_
|
writeFormat_
|
||||||
);
|
);
|
||||||
part.write(osGeom); // serial
|
part.write(osGeom); // serial
|
||||||
|
|||||||
@ -37,7 +37,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated()
|
|||||||
|
|
||||||
// Uncollated
|
// Uncollated
|
||||||
// ==========
|
// ==========
|
||||||
// Geometry: rootdir/<TIME>/surfaceName.case
|
// CaseFile: rootdir/<TIME>/surfaceName.case
|
||||||
// Geometry: rootdir/<TIME>/surfaceName.00000000.mesh
|
// Geometry: rootdir/<TIME>/surfaceName.00000000.mesh
|
||||||
|
|
||||||
fileName outputDir;
|
fileName outputDir;
|
||||||
@ -85,7 +85,7 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated()
|
|||||||
<< nl
|
<< nl
|
||||||
<< "TIME" << nl;
|
<< "TIME" << nl;
|
||||||
|
|
||||||
printTimeset(osCase, 1, 0.0);
|
printTimeset(osCase, 1, scalar(0));
|
||||||
|
|
||||||
ensightOutputSurface part
|
ensightOutputSurface part
|
||||||
(
|
(
|
||||||
@ -116,9 +116,9 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated
|
|||||||
|
|
||||||
// Uncollated
|
// Uncollated
|
||||||
// ==========
|
// ==========
|
||||||
// geometry: rootdir/time/<field>/surfaceName.case
|
// CaseFile: rootdir/time/<field>/surfaceName.case
|
||||||
// geometry: rootdir/time/<field>/surfaceName.<index>.mesh
|
// Geometry: rootdir/time/<field>/surfaceName.<index>.mesh
|
||||||
// field: rootdir/time/<field>/surfaceName.<index>.<field>
|
// Field: rootdir/time/<field>/surfaceName.<index>.<field>
|
||||||
|
|
||||||
// Variable name as sub-directory for results. Eg,
|
// Variable name as sub-directory for results. Eg,
|
||||||
// - VAR1/SURF1.case
|
// - VAR1/SURF1.case
|
||||||
|
|||||||
Reference in New Issue
Block a user