ENH: support format readOptions for surfaceReader types (#2609)

- similar to surface writing formats, also support optional
  dictionary of reading options. The main beneficiary of this is the
  ensight surface reader:

  readOptions
  {
      ensight
      {
          masterOnly true;
      }
  }

  This will restrict reading to the master rank. Surfaces and values
  read will be broadcast to the other ranks, with the intention of
  reducing load on the filesystem.

ENH: add writing of Dimensioned fields for areaWrite functionObject

- can be useful for examining finite-area source terms
This commit is contained in:
Mark Olesen
2022-12-07 16:53:58 +01:00
parent b69db76b67
commit 8afd6ff729
27 changed files with 813 additions and 401 deletions

View File

@ -65,7 +65,11 @@ Foam::fa::externalFileSource::externalFileSource
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false // Do not register
(
dict.getOrDefault("store", false)
? IOobject::REGISTER
: IOobject::NO_REGISTER
)
),
regionMesh(),
dimensionedScalar(dimPressure, Zero)
@ -75,6 +79,10 @@ Foam::fa::externalFileSource::externalFileSource
{
fieldNames_.resize(1, fieldName_);
/// FUTURE?
/// // Optional entry (mandatory = false)
/// pExt_.dimensions().readEntry("dimensions", dict, false);
fa::option::resetApplied();
read(dict);
@ -155,7 +163,7 @@ bool Foam::fa::externalFileSource::read(const dictionary& dict)
new PatchFunction1Types::MappedFile<scalar>
(
p,
"uniformValue",
"uniformValue", // entryName
dict,
tableName_, // field table name
true // face values

View File

@ -54,6 +54,7 @@ Usage
type | Type name: externalFileSource | word | yes | -
fieldName | Name of operand field | word | yes | -
tableName | Name of operand table file | word | yes | -
store | Register external field 'pExt' | bool | no | false
\endtable
The inherited entries are elaborated in:

View File

@ -1,3 +1,4 @@
common/fileFormats.C
common/manifoldCellsMeshObject.C
colours/colourTable.C

View File

@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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/>.
\*---------------------------------------------------------------------------*/
#include "fileFormats.H"
#include "dictionary.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Extract and merge 'default' + formatName from list of dictionaries
//
// \returns dictionary of merged options
static dictionary combineFormatOptions
(
const word& formatName,
std::initializer_list<const dictionary*> dicts
)
{
dictionary options;
// Default specification. Merge from all levels
// - literal search only
for (const dictionary* dict : dicts)
{
if
(
dict
&& (dict = dict->findDict("default", keyType::LITERAL)) != nullptr
)
{
options.merge(*dict);
}
}
// Format specification. Merge from all levels
// - allow REGEX search
if (!formatName.empty())
{
for (const dictionary* dict : dicts)
{
if
(
dict
&& (dict = dict->findDict(formatName)) != nullptr
)
{
options.merge(*dict);
}
}
}
return options;
}
} // End namespace Foam
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
Foam::dictionary Foam::fileFormats::getFormatOptions
(
const dictionary& dict,
const word& formatName,
const word& entryName
)
{
return combineFormatOptions
(
formatName,
{
dict.findDict(entryName, keyType::LITERAL)
}
);
}
Foam::dictionary Foam::fileFormats::getFormatOptions
(
const dictionary& dict,
const dictionary& altDict,
const word& formatName,
const word& entryName
)
{
return combineFormatOptions
(
formatName,
{
dict.findDict(entryName, keyType::LITERAL),
altDict.findDict(entryName, keyType::LITERAL)
}
);
}
// ************************************************************************* //

View File

@ -0,0 +1,102 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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/>.
Namespace
Foam::fileFormats
Description
Namespace to isolate specifics for file formats,
and some common utilities.
SourceFiles
fileFormats.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_fileFormats_H
#define Foam_fileFormats_H
#include "word.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class dictionary;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace fileFormats
{
//- Find "formatOptions" in a top-level dictionary.
//- Extract and merge 'default' + formatName values.
//
// \returns dictionary of merged formatOptions
dictionary getFormatOptions
(
//! The top-level dictionary to search
const dictionary& dict,
//! The format name. Eg, \c ensight
const word& formatName,
//! Dictionary sub-entry to search for
const word& entryName = "formatOptions"
);
//- Find "formatOptions" in a top-level dictionary,
//- and optional override dictionary.
//- Extract and merge 'default' + formatName values.
//
// \returns dictionary of merged formatOptions
dictionary getFormatOptions
(
//! The top-level dictionary to search
const dictionary& dict,
//! Additional dictionary to search
const dictionary& altDict,
//! The format name. Eg, \c ensight
const word& formatName,
//! Dictionary sub-entry to search for
const word& entryName = "formatOptions"
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fileFormats
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -180,7 +180,27 @@ Foam::Istream& Foam::ensightReadFile::read(label& value)
}
Foam::Istream& Foam::ensightReadFile::read(scalar& value)
Foam::Istream& Foam::ensightReadFile::read(float& value)
{
if (format() == IOstreamOption::BINARY)
{
read
(
reinterpret_cast<char*>(&value),
sizeof(value)
);
}
else
{
stdStream() >> value;
syncState();
}
return *this;
}
Foam::Istream& Foam::ensightReadFile::read(double& value)
{
float fvalue;
@ -191,15 +211,14 @@ Foam::Istream& Foam::ensightReadFile::read(scalar& value)
reinterpret_cast<char*>(&fvalue),
sizeof(fvalue)
);
value = fvalue;
}
else
{
stdStream() >> value;
stdStream() >> fvalue;
syncState();
}
value = fvalue;
return *this;
}

View File

@ -27,7 +27,8 @@ Class
Foam::ensightReadFile
Description
Ensight output with specialized read() for strings, integers and floats.
A variant of IFstream with specialised read() for
strings, integers and floats.
Correctly handles binary read as well.
\*---------------------------------------------------------------------------*/
@ -98,13 +99,16 @@ public:
virtual Istream& read(char* buf, std::streamsize count);
//- Read string as "%80s" or as binary
Istream& read(string& value);
virtual Istream& read(string& value);
//- Read integer as "%10d" or as binary
Istream& read(label& value);
virtual Istream& read(label& value);
//- Read float as "%12.5e" or as binary
Istream& read(scalar& value);
//- Read floating-point as "%12.5e" or as binary
virtual Istream& read(float& value);
//- Read floating-point as "%12.5e" or as a binary (narrowed) float
virtual Istream& read(double& value);
//- Read element keyword
virtual Istream& readKeyword(string& key);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2018 OpenCFD Ltd.
Copyright (C) 2018-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -92,5 +92,14 @@ const Foam::wordList Foam::fieldTypes::area
"areaTensorField"
});
const Foam::wordList Foam::fieldTypes::area_internal
({
"areaScalarField::Internal",
"areaVectorField::Internal",
"areaSphericalTensorField::Internal",
"areaSymmTensorField::Internal",
"areaTensorField::Internal"
});
// ************************************************************************* //

View File

@ -92,6 +92,9 @@ namespace fieldTypes
//- Standard area field types (scalar, vector, tensor, etc)
extern const wordList area;
//- Standard dimensioned field types (scalar, vector, tensor, etc)
extern const wordList area_internal;
} // End namespace fieldTypes

View File

@ -53,6 +53,10 @@ namespace Foam
Foam::scalar Foam::areaWrite::mergeTol_ = 1e-10;
// Implementation
#include "areaWriteImpl.C"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::areaWrite::areaWrite
@ -110,7 +114,7 @@ Foam::areaWrite::areaWrite
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::areaWrite::verbose(const bool on)
bool Foam::areaWrite::verbose(const bool on) noexcept
{
bool old(verbose_);
verbose_ = on;
@ -137,7 +141,7 @@ bool Foam::areaWrite::read(const dictionary& dict)
obr_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false
IOobject::NO_REGISTER
)
)
);
@ -299,7 +303,11 @@ bool Foam::areaWrite::write()
const word& clsName = iter.key();
const label n = iter.val().size();
if (fieldTypes::area.found(clsName))
if
(
fieldTypes::area.found(clsName)
|| fieldTypes::area_internal.found(clsName)
)
{
nAreaFields += n;
}
@ -318,11 +326,43 @@ bool Foam::areaWrite::write()
// Write fields
performAction<areaScalarField>(outWriter, areaMesh, objects);
performAction<areaVectorField>(outWriter, areaMesh, objects);
performAction<areaSphericalTensorField>(outWriter, areaMesh, objects);
performAction<areaSymmTensorField>(outWriter, areaMesh, objects);
performAction<areaTensorField>(outWriter, areaMesh, objects);
{
// Area fields
#undef doLocalCode
#define doLocalCode(Type) \
performAction \
< \
GeometricField<Type, Foam::faPatchField, Foam::areaMesh> \
> \
( \
outWriter, areaMesh, objects \
); \
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
// Area internal fields
#undef doLocalCode
#define doLocalCode(Type) \
performAction \
< \
DimensionedField<Type, Foam::areaMesh> \
> \
( \
outWriter, areaMesh, objects \
);
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
}
// Finish this time step
@ -384,17 +424,17 @@ void Foam::areaWrite::readUpdate(const polyMesh::readUpdateState state)
}
Foam::scalar Foam::areaWrite::mergeTol()
Foam::scalar Foam::areaWrite::mergeTol() noexcept
{
return mergeTol_;
}
Foam::scalar Foam::areaWrite::mergeTol(const scalar tol)
Foam::scalar Foam::areaWrite::mergeTol(const scalar tol) noexcept
{
const scalar prev(mergeTol_);
scalar old(mergeTol_);
mergeTol_ = tol;
return prev;
return old;
}

View File

@ -210,7 +210,7 @@ public:
//- Enable/disable verbose output
// \return old value
bool verbose(const bool on);
bool verbose(const bool on) noexcept;
//- Read the areaWrite dictionary
virtual bool read(const dictionary& dict);
@ -231,10 +231,10 @@ public:
virtual void readUpdate(const polyMesh::readUpdateState state);
//- Get merge tolerance
static scalar mergeTol();
static scalar mergeTol() noexcept;
//- Set merge tolerance and return old value
static scalar mergeTol(const scalar tol);
static scalar mergeTol(const scalar tol) noexcept;
};
@ -244,12 +244,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "areaWriteTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -27,93 +27,14 @@ License
#include "polyMesh.H"
#include "rawIOField.H"
#include "clockTime.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>
Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
(
const polyPatch& pp,
const word& redirectType,
const word& entryName,
const dictionary& dict,
const bool faceValues
)
:
PatchFunction1<Type>(pp, entryName, dict, faceValues),
dictConstructed_(true),
setAverage_(dict.getOrDefault("setAverage", false)),
perturb_(dict.getOrDefault<scalar>("perturb", 1e-5)),
fieldTableName_(dict.getOrDefault<word>("fieldTable", entryName)),
pointsName_(dict.getOrDefault<word>("points", "points")),
mapMethod_(),
filterRadius_(dict.getOrDefault<scalar>("filterRadius", 0)),
filterSweeps_(dict.getOrDefault<label>("filterSweeps", 0)),
filterFieldPtr_(nullptr),
readerFormat_(),
readerFile_(),
readerPtr_(nullptr),
mapperPtr_(nullptr),
sampleTimes_(),
sampleIndex_(-1, -1),
sampleAverage_(Zero, Zero),
sampleValues_(),
offset_(Function1<Type>::NewIfPresent("offset", dict))
{
// Simple sanity check
if ((filterSweeps_ < 1) || (filterRadius_ <= VSMALL))
{
filterRadius_ = 0;
filterSweeps_ = 0;
}
if (dict.readIfPresent("sampleFormat", readerFormat_))
{
dict.readEntry("sampleFile", readerFile_);
fileName fName(readerFile_);
fName.expand();
readerPtr_ = surfaceReader::New(readerFormat_, fName);
}
if (debug)
{
Info<< "mappedFile:" << nl;
if (readerFormat_.empty())
{
Info<< " boundary format" << nl;
}
else
{
Info<< " format:" << readerFormat_
<< " file:" << readerFile_ << nl;
}
Info<< " filter radius=" << filterRadius_
<< " sweeps=" << filterSweeps_ << endl;
}
if
(
dict.readIfPresent("mapMethod", mapMethod_)
&& !mapMethod_.empty()
&& mapMethod_ != "nearest"
&& !mapMethod_.starts_with("planar")
)
{
FatalIOErrorInFunction(dict)
<< "Unknown mapMethod type " << mapMethod_
<< "\n\nValid mapMethod types :\n"
<< "(nearest planar)" << nl
<< exit(FatalIOError);
}
}
template<class Type>
Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
(
const bool dictConstructed,
const polyPatch& pp,
const word& entryName,
const dictionary& dict,
@ -122,7 +43,7 @@ Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
)
:
PatchFunction1<Type>(pp, entryName, dict, faceValues),
dictConstructed_(false),
dictConstructed_(dictConstructed),
setAverage_(dict.getOrDefault("setAverage", false)),
perturb_(dict.getOrDefault<scalar>("perturb", 1e-5)),
fieldTableName_(fieldTableName),
@ -141,6 +62,11 @@ Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
sampleValues_(),
offset_(Function1<Type>::NewIfPresent("offset", dict))
{
if (fieldTableName_.empty())
{
fieldTableName_ = entryName;
}
// Simple sanity check
if ((filterSweeps_ < 1) || (filterRadius_ <= VSMALL))
{
@ -155,7 +81,12 @@ Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
fileName fName(readerFile_);
fName.expand();
readerPtr_ = surfaceReader::New(readerFormat_, fName);
readerPtr_ = surfaceReader::New
(
readerFormat_,
fName,
surfaceReader::formatOptions(dict, readerFormat_, "readOptions")
);
}
if (debug)
@ -192,6 +123,50 @@ Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
}
template<class Type>
Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
(
const polyPatch& pp,
const word& redirectType,
const word& entryName,
const dictionary& dict,
const bool faceValues
)
:
MappedFile<Type>
(
true, // dictConstructed = true
pp,
entryName,
dict,
dict.getOrDefault<word>("fieldTable", entryName),
faceValues
)
{}
template<class Type>
Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
(
const polyPatch& pp,
const word& entryName,
const dictionary& dict,
const word& fieldTableName,
const bool faceValues
)
:
MappedFile<Type>
(
false, // dictConstructed = false
pp,
entryName,
dict,
fieldTableName,
faceValues
)
{}
template<class Type>
Foam::PatchFunction1Types::MappedFile<Type>::MappedFile
(
@ -313,9 +288,20 @@ void Foam::PatchFunction1Types::MappedFile<Type>::updateSampledValues
label fieldIndex = fieldNames.find(fieldTableName_);
DebugInfo
<< "checkTable : Update index=" << sampleIndex
if (fieldIndex < 0)
{
FatalErrorInFunction
<< "Sample field='" << fieldTableName_
<< "' not found. Known field names: "
<< flatOutput(fieldNames) << nl
<< exit(FatalError);
}
if (debug)
{
Pout<< "checkTable : Update index=" << sampleIndex
<< " field=" << fieldNames[fieldIndex] << endl;
}
tvalues = readerPtr_->field
(
@ -418,6 +404,8 @@ void Foam::PatchFunction1Types::MappedFile<Type>::checkTable
// Initialise
if (!mapperPtr_ && readerPtr_)
{
clockTime timing;
auto& reader = readerPtr_();
const meshedSurface& geom = reader.geometry(0);
@ -436,7 +424,8 @@ void Foam::PatchFunction1Types::MappedFile<Type>::checkTable
<< "Read " << samplePoints.size() << " sample points from "
<< readerFile_ << endl
<< "Found times "
<< pointToPointPlanarInterpolation::timeNames(sampleTimes_) << nl;
<< pointToPointPlanarInterpolation::timeNames(sampleTimes_) << nl
<< "... in " << timing.timeIncrement() << 's' << endl;
// tbd: run-time selection
const bool nearestOnly =
@ -444,7 +433,6 @@ void Foam::PatchFunction1Types::MappedFile<Type>::checkTable
!mapMethod_.empty() && !mapMethod_.starts_with("planar")
);
// Allocate the interpolator
if (this->faceValues())
{
@ -473,10 +461,19 @@ void Foam::PatchFunction1Types::MappedFile<Type>::checkTable
);
}
DebugInfo
<< "Created point/point planar interpolation"
<< " - in " << timing.timeIncrement() << 's' << endl;
// Setup median filter (if any)
if (filterSweeps_ > 0)
{
filterFieldPtr_.reset(new FilterField(geom, filterRadius_));
DebugInfo
<< "Calculated field-filter"
<< " - in " << timing.timeIncrement() << 's' << endl;
}
else
{
@ -485,6 +482,8 @@ void Foam::PatchFunction1Types::MappedFile<Type>::checkTable
}
else if (!mapperPtr_)
{
clockTime timing;
// Reread values and interpolate
const fileName samplePointsFile
(
@ -509,16 +508,23 @@ void Foam::PatchFunction1Types::MappedFile<Type>::checkTable
// Read data (no average value!)
const rawIOField<point> samplePoints(io);
// Read the times for which data is available
sampleTimes_ = Time::findTimes(samplePointsFile.path());
DebugInfo
<< "Read " << samplePoints.size() << " sample points from "
<< samplePointsFile << endl
<< "Found times "
<< pointToPointPlanarInterpolation::timeNames(sampleTimes_) << nl
<< "... in " << timing.timeIncrement() << 's' << endl;
// tbd: run-time selection
const bool nearestOnly =
(
!mapMethod_.empty() && !mapMethod_.starts_with("planar")
);
DebugInfo
<< "Read " << samplePoints.size() << " sample points from "
<< samplePointsFile << endl;
// Allocate the interpolator
if (this->faceValues())
{
@ -547,19 +553,19 @@ void Foam::PatchFunction1Types::MappedFile<Type>::checkTable
);
}
// Read the times for which data is available
const fileName samplePointsDir = samplePointsFile.path();
sampleTimes_ = Time::findTimes(samplePointsDir);
DebugInfo
<< "Found times "
<< pointToPointPlanarInterpolation::timeNames(sampleTimes_)
<< endl;
<< "Created point/point planar interpolation"
<< " - in " << timing.timeIncrement() << 's' << endl;
// Setup median filter (if any)
if (filterSweeps_ > 0)
{
filterFieldPtr_.reset(new FilterField(samplePoints, filterRadius_));
DebugInfo
<< "Calculated field-filter"
<< " - in " << timing.timeIncrement() << 's' << endl;
}
else
{

View File

@ -62,6 +62,7 @@ Description
sampleFile | <case>/foo/bar/window.case
filterRadius | Search radius [m] for median filter neighbours
filterSweeps | Filter sweeps for median filter
readOptions | Format options for surfaceReader format (eg, ensight)
\endtable
Note
@ -173,6 +174,17 @@ class MappedFile
Type& avg
) const;
//- Construct from entry name and dictionary
MappedFile
(
const bool dictConstructed,
const polyPatch& pp,
const word& entryName,
const dictionary& dict,
const word& fieldTableName,
const bool faceValues
);
public:
//- Runtime type information
@ -204,7 +216,7 @@ public:
const word& entryName,
const dictionary& dict,
const word& fieldTableName,
const bool faceValues
const bool faceValues = true
);
//- Copy construct

View File

@ -227,7 +227,7 @@ void Foam::PatchFunction1Types::FilterField::buildWeightsImpl
total += n;
}
Info<< "Weight neighbours: min=" << limits.min()
Pout<< "Weight neighbours: min=" << limits.min()
<< " avg=" << (total / addressing_.size())
<< " max=" << limits.max() << endl;
}
@ -279,7 +279,7 @@ void Foam::PatchFunction1Types::FilterField::reset
if (debug)
{
Info<< "Apply " << RBF_typeNames_[interp] << " filter,"
Pout<< "Apply " << RBF_typeNames_[interp] << " filter,"
<< " radius=" << radius << nl
<< "Create tree..." << endl;
}
@ -325,15 +325,9 @@ void Foam::PatchFunction1Types::FilterField::reset
if (debug)
{
Info<< "Apply " << RBF_typeNames_[interp] << " filter,";
if (relative)
{
Info<< " relative";
}
Info<< " radius=" << radius << endl;
Info<< "Create tree..." << endl;
Pout<< "Apply " << RBF_typeNames_[interp] << " filter,"
<< (relative ? " relative" : "") << " radius=" << radius << nl
<< "Create tree..." << endl;
}
autoPtr<indexedOctree<treeDataPoint>> treePtr

View File

@ -27,6 +27,7 @@ License
#include "coordSet.H"
#include "coordSetWriter.H"
#include "fileFormats.H"
#include "Time.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -78,46 +79,6 @@ Foam::word Foam::coordSetWriter::suffix
}
Foam::dictionary Foam::coordSetWriter::formatOptions
(
const word& formatName,
std::initializer_list<const dictionary*> dicts
)
{
dictionary options;
// Default specification. Top-level and surface-specific
// - literal search only
for (const dictionary* dict : dicts)
{
if
(
dict
&& (dict = dict->findDict("default", keyType::LITERAL)) != nullptr
)
{
options.merge(*dict);
}
}
// Format specification. Top-level and surface-specific
// - allow REGEX search
for (const dictionary* dict : dicts)
{
if
(
dict && !formatName.empty()
&& (dict = dict->findDict(formatName)) != nullptr
)
{
options.merge(*dict);
}
}
return options;
}
Foam::dictionary Foam::coordSetWriter::formatOptions
(
const dictionary& dict,
@ -125,13 +86,7 @@ Foam::dictionary Foam::coordSetWriter::formatOptions
const word& entryName
)
{
return formatOptions
(
formatName,
{
dict.findDict(entryName, keyType::LITERAL)
}
);
return fileFormats::getFormatOptions(dict, formatName, entryName);
}
@ -143,14 +98,7 @@ Foam::dictionary Foam::coordSetWriter::formatOptions
const word& entryName
)
{
return formatOptions
(
formatName,
{
dict.findDict(entryName, keyType::LITERAL),
setDict.findDict(entryName, keyType::LITERAL)
}
);
return fileFormats::getFormatOptions(dict, setDict, formatName, entryName);
}

View File

@ -274,16 +274,6 @@ protected:
//- No copy assignment
void operator=(const coordSetWriter&) = delete;
//- Extract and merge 'default' + formatName from
//- top-level and set-specific formatOptions dictionaries
//
// \returns dictionary of merged formatOptions
static dictionary formatOptions
(
const word& formatName,
std::initializer_list<const dictionary*> dicts
);
public:
@ -314,10 +304,7 @@ public:
// Helpers
//- Find "formatOptions" in a top-level dictionary.
//- Extract and merge 'default' + formatName values.
//
// \returns dictionary of merged formatOptions
//- Same as fileFormats::getFormatOptions
static dictionary formatOptions
(
const dictionary& dict,
@ -325,11 +312,7 @@ public:
const word& entryName = "formatOptions"
);
//- Find "formatOptions" in a top-level dictionary,
//- and in a set-specific dictionary.
//- Extract and merge 'default' + formatName values.
//
// \returns dictionary of merged formatOptions
//- Same as fileFormats::getFormatOptions
static dictionary formatOptions
(
const dictionary& dict,

View File

@ -178,6 +178,12 @@ public:
return nPoints_;
}
//- Number of target points
label targetSize() const noexcept
{
return nearestVertex_.size();
}
//- Interpolation addressing to face centres of underlying patch
const List<FixedList<label, 3>>& nearestVertex() const noexcept
{

View File

@ -150,13 +150,26 @@ Foam::boundaryDataSurfaceReader::boundaryDataSurfaceReader
const word& pointsName
)
:
surfaceReader(fName),
boundaryDataSurfaceReader(fName, dictionary(), pointsName)
{}
Foam::boundaryDataSurfaceReader::boundaryDataSurfaceReader
(
const fileName& fName,
const dictionary& options,
const word& pointsName
)
:
surfaceReader(fName, options),
baseDir_(fName.path()),
pointsName_(pointsName),
timeValues_(),
fieldNames_(),
surfPtr_(nullptr)
{
options.readIfPresent("points", pointsName_);
baseDir_.toAbsolute();
debug = 1;
DebugInFunction << endl;

View File

@ -37,8 +37,25 @@ Description
// Values
<case>/constant/region0/"boundaryData"/patchName/TIME/field
\verbatim
readOptions
{
boundaryData
{
points points;
}
}
\endverbatim
Format options for boundaryData:
\table
Property | Description | Required | Default
points | Name of the "points" file | no | points
\endtable
SourceFiles
boundaryDataSurfaceReader.C
boundaryDataSurfaceReaderTemplates.C
\*---------------------------------------------------------------------------*/
@ -113,6 +130,14 @@ public:
const word& pointsName = "points"
);
//- Construct from fileName with reader options
boundaryDataSurfaceReader
(
const fileName& fName,
const dictionary& options,
const word& pointsName = "points"
);
//- Destructor
virtual ~boundaryDataSurfaceReader() = default;

View File

@ -26,6 +26,7 @@ License
\*---------------------------------------------------------------------------*/
#include "surfaceReader.H"
#include "fileFormats.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -36,21 +37,48 @@ namespace Foam
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::dictionary Foam::surfaceReader::formatOptions
(
const dictionary& dict,
const word& formatName,
const word& entryName
)
{
return fileFormats::getFormatOptions(dict, formatName, entryName);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::surfaceReader::surfaceReader(const fileName& fName)
Foam::surfaceReader::surfaceReader
(
const fileName& fName
)
:
fileName_(fName)
{}
Foam::surfaceReader::surfaceReader
(
const fileName& fName,
const dictionary& options
)
:
surfaceReader(fName)
{}
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::surfaceReader>
Foam::surfaceReader::New
(
const word& readerType,
const fileName& fName
const fileName& fName,
const dictionary& options
)
{
auto* ctorPtr = fileNameConstructorTable(readerType);
@ -65,7 +93,7 @@ Foam::surfaceReader::New
) << exit(FatalError);
}
return autoPtr<surfaceReader>(ctorPtr(fName));
return autoPtr<surfaceReader>(ctorPtr(fName, options));
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2015 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -29,6 +29,24 @@ Class
Description
Abstract base class for surface readers with fields.
Some readers support different input options, these are typically
specified as 'readOptions' in the containing dictionary.
\verbatim
readOptions
{
default
{
verbose false;
}
ensight
{
masterOnly false;
}
}
\endverbatim
SourceFiles
surfaceReader.C
@ -73,9 +91,21 @@ public:
surfaceReader,
fileName,
(
const fileName& fName
const fileName& fName,
const dictionary& options
),
(fName)
(fName, options)
);
// Helpers
//- Same as fileFormats::getFormatOptions
static dictionary formatOptions
(
const dictionary& dict,
const word& formatName,
const word& entryName = "formatOptions"
);
@ -85,7 +115,8 @@ public:
static autoPtr<surfaceReader> New
(
const word& readType,
const fileName& fName
const fileName& fName,
const dictionary& options = dictionary()
);
@ -94,6 +125,9 @@ public:
//- Construct from fileName
explicit surfaceReader(const fileName& fName);
//- Construct from fileName and specified options
surfaceReader(const fileName& fName, const dictionary& options);
//- Destructor
virtual ~surfaceReader() = default;

View File

@ -337,9 +337,18 @@ void Foam::ensightSurfaceReader::readCase(ISstream& is)
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::ensightSurfaceReader::ensightSurfaceReader(const fileName& fName)
Foam::ensightSurfaceReader::ensightSurfaceReader
(
const fileName& fName,
const dictionary& options
)
:
surfaceReader(fName),
surfaceReader(fName, options),
masterOnly_
(
Pstream::parRun()
&& options.getOrDefault("masterOnly", false)
),
readFormat_(IOstreamOption::ASCII), // Placeholder value
baseDir_(fName.path()),
meshFileName_(),
@ -350,25 +359,47 @@ Foam::ensightSurfaceReader::ensightSurfaceReader(const fileName& fName)
timeIncrement_(1),
timeValues_(),
surfPtr_(nullptr)
{
if (options.getOrDefault("debug", false))
{
debug |= 1;
}
if (!masterOnly_ || UPstream::master(UPstream::worldComm))
{
IFstream is(fName);
readCase(is);
}
if (masterOnly_ && Pstream::parRun())
{
Pstream::broadcasts
(
UPstream::worldComm,
meshFileName_,
fieldNames_,
fieldFileNames_,
nTimeSteps_,
timeStartIndex_,
timeIncrement_,
timeValues_
);
}
}
// * * * * * * * * * * * * * Public Member Functions * * * * * * * * * * * //
const Foam::meshedSurface& Foam::ensightSurfaceReader::geometry
Foam::meshedSurface Foam::ensightSurfaceReader::readGeometry
(
const label timeIndex
const fileName& geometryFile
)
{
DebugInFunction << endl;
if (!surfPtr_)
{
// Auto-detect ascii/binary format
ensightReadFile is(baseDir_/replaceMask(meshFileName_, timeIndex));
ensightReadFile is(geometryFile);
// Format detected from the geometry
readFormat_ = is.format();
@ -573,15 +604,8 @@ const Foam::meshedSurface& Foam::ensightSurfaceReader::geometry
}
}
faceTypeInfo_.transfer(faceTypeInfo);
faceList faces(std::move(dynFaces));
DebugInfo
<< "read nFaces: " << faces.size() << nl
<< "file schema: " << faceTypeInfo_ << nl;
// Convert from 1-based Ensight addressing to 0-based OF addressing
for (face& f : faces)
// From 1-based Ensight addressing to 0-based OF addressing
for (face& f : dynFaces)
{
for (label& fp : f)
{
@ -589,7 +613,42 @@ const Foam::meshedSurface& Foam::ensightSurfaceReader::geometry
}
}
surfPtr_.reset(new meshedSurface(std::move(points), std::move(faces)));
faceTypeInfo_.transfer(faceTypeInfo);
faceList faces(std::move(dynFaces));
DebugInfo
<< "read nFaces: " << faces.size() << nl
<< "file schema: " << faceTypeInfo_ << nl;
return meshedSurface(std::move(points), std::move(faces));
}
}
const Foam::meshedSurface& Foam::ensightSurfaceReader::geometry
(
const label timeIndex
)
{
DebugInFunction << endl;
if (!surfPtr_)
{
surfPtr_.reset(new meshedSurface);
auto& surf = *surfPtr_;
fileName geomFile(baseDir_/replaceMask(meshFileName_, timeIndex));
if (!masterOnly_ || UPstream::master(UPstream::worldComm))
{
surf = readGeometry(geomFile);
}
if (masterOnly_ && Pstream::parRun())
{
// Note: don't need faceTypeInfo_ on (non-reading) ranks
Pstream::broadcast(surf, UPstream::worldComm);
}
}
return *surfPtr_;

View File

@ -29,6 +29,24 @@ Class
Description
Ensight format surface reader
\verbatim
readOptions
{
ensight
{
debug false;
masterOnly false;
}
}
\endverbatim
Format options for ensight:
\table
Property | Description | Required | Default
debug | Add debug flag | no | false
masterOnly | Read files on master and broadcast values | no | true
\endtable
SourceFiles
ensightSurfaceReader.C
ensightSurfaceReaderTemplates.C
@ -76,6 +94,9 @@ protected:
// Protected Data
//- Read on master and broadcast (in parallel)
bool masterOnly_;
//- Format flag
IOstreamOption::streamFormat readFormat_;
@ -135,6 +156,9 @@ protected:
//- Read the case file
void readCase(ISstream& is);
//- Read and return surface geometry. Updates faceTypeInfo_
meshedSurface readGeometry(const fileName& geometryFile);
//- Helper function to return Type after skipping n tokens
template<class Type>
void readFromLine(const label nSkip, Istream& is, Type& value) const;
@ -148,6 +172,14 @@ protected:
Type& value
) const;
//- Helper function to return a field
template<class Type>
tmp<Field<Type>> readField
(
const fileName& dataFile,
const word& fieldName
) const;
//- Helper function to return a field
template<class Type>
tmp<Field<Type>> readField
@ -165,8 +197,12 @@ public:
// Constructors
//- Construct from fileName
explicit ensightSurfaceReader(const fileName& fName);
//- Construct from fileName, with reader options
explicit ensightSurfaceReader
(
const fileName& fName,
const dictionary& options = dictionary()
);
//- Destructor

View File

@ -61,21 +61,17 @@ void Foam::ensightSurfaceReader::readFromLine
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
(
const label timeIndex,
const label fieldIndex
const fileName& dataFile,
const word& fieldName
) const
{
DebugInFunction << endl;
const word& fieldName = fieldNames_[fieldIndex];
const label fileIndex = timeStartIndex_ + timeIndex*timeIncrement_;
auto tfield = tmp<Field<Type>>::New(surfPtr_->nFaces(), Zero);
auto& field = tfield.ref();
if (!masterOnly_ || UPstream::master(UPstream::worldComm))
{
// Use previously detected ascii/binary format
ensightReadFile is
(
baseDir_/replaceMask(fieldFileNames_[fieldIndex], fileIndex),
readFormat_
);
ensightReadFile is(dataFile, readFormat_);
if (!is.good())
{
@ -102,12 +98,10 @@ Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
<< "Expected <" << ensightPTraits<Type>::typeName
<< "> values for <" << pTraits<Type>::typeName
<< "> but found " << primitiveType << nl
<< " This may be okay, but could indicate an error" << nl << nl;
<< " This may be okay, but could indicate an error"
<< nl << nl;
}
auto tfield = tmp<Field<Type>>::New(surfPtr_->nFaces(), Zero);
auto& field = tfield.ref();
string strValue;
label iValue;
@ -145,7 +139,8 @@ Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
for (direction d = 0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt = ensightPTraits<Type>::componentOrder[d];
const direction cmpt =
ensightPTraits<Type>::componentOrder[d];
for (label facei = begFace; facei < endFace; ++facei)
{
@ -158,9 +153,50 @@ Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
begFace = endFace;
}
}
}
if (masterOnly_ && Pstream::parRun())
{
Pstream::broadcast(field, UPstream::worldComm);
}
return tfield;
}
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::ensightSurfaceReader::readField
(
const label timeIndex,
const label fieldIndex
) const
{
if (fieldIndex < 0 || fieldIndex >= fieldNames_.size())
{
FatalErrorInFunction
<< "Invalid timeIndex:" << timeIndex
<< " should be in range [0.." << fieldNames_.size() << ')' << nl
<< "Possibly used incorrect field lookup name. Known field names: "
<< flatOutput(fieldNames_) << nl
<< exit(FatalError);
}
const word& fieldName = fieldNames_[fieldIndex];
const label fileIndex = timeStartIndex_ + timeIndex*timeIncrement_;
const fileName dataFile
(
baseDir_/replaceMask(fieldFileNames_[fieldIndex], fileIndex)
);
if (debug)
{
Pout<< "Read <" << pTraits<Type>::typeName << "> field, file="
<< dataFile << endl;
}
return readField<Type>(dataFile, fieldName);
}
// ************************************************************************* //

View File

@ -29,6 +29,7 @@ License
#include "proxySurfaceWriter.H"
#include "MeshedSurfaceProxy.H"
#include "fileFormats.H"
#include "Time.H"
#include "coordinateRotation.H"
#include "transformField.H"
@ -59,46 +60,6 @@ bool Foam::surfaceWriter::supportedType(const word& writeType)
}
Foam::dictionary Foam::surfaceWriter::formatOptions
(
const word& formatName,
std::initializer_list<const dictionary*> dicts
)
{
dictionary options;
// Default specification. Top-level and surface-specific
// - literal search only
for (const dictionary* dict : dicts)
{
if
(
dict
&& (dict = dict->findDict("default", keyType::LITERAL)) != nullptr
)
{
options.merge(*dict);
}
}
// Format specification. Top-level and surface-specific
// - allow REGEX search
for (const dictionary* dict : dicts)
{
if
(
dict && !formatName.empty()
&& (dict = dict->findDict(formatName)) != nullptr
)
{
options.merge(*dict);
}
}
return options;
}
Foam::dictionary Foam::surfaceWriter::formatOptions
(
const dictionary& dict,
@ -106,13 +67,7 @@ Foam::dictionary Foam::surfaceWriter::formatOptions
const word& entryName
)
{
return formatOptions
(
formatName,
{
dict.findDict(entryName, keyType::LITERAL)
}
);
return fileFormats::getFormatOptions(dict, formatName, entryName);
}
@ -124,14 +79,7 @@ Foam::dictionary Foam::surfaceWriter::formatOptions
const word& entryName
)
{
return formatOptions
(
formatName,
{
dict.findDict(entryName, keyType::LITERAL),
surfDict.findDict(entryName, keyType::LITERAL)
}
);
return fileFormats::getFormatOptions(dict, surfDict, formatName, entryName);
}

View File

@ -272,18 +272,6 @@ protected:
return fileName::null;
}
//- Extract and merge 'default' + formatName from
//- top-level and surface-specific formatOptions dictionaries
//
// \returns dictionary of merged formatOptions
static dictionary formatOptions
(
const word& formatName,
std::initializer_list<const dictionary*> dicts
);
public:
// Public Data
@ -320,10 +308,7 @@ public:
// Helpers
//- Find "formatOptions" in a top-level dictionary.
//- Extract and merge 'default' + formatName values.
//
// \returns dictionary of merged formatOptions
//- Same as fileFormats::getFormatOptions
static dictionary formatOptions
(
const dictionary& dict,
@ -331,11 +316,7 @@ public:
const word& entryName = "formatOptions"
);
//- Find "formatOptions" in a top-level dictionary,
//- and in a set-specific dictionary.
//- Extract and merge 'default' + formatName values.
//
// \returns dictionary of merged formatOptions
//- Same as fileFormats::getFormatOptions
static dictionary formatOptions
(
const dictionary& dict,