ENH: improve surfaceFieldValue sampling and writing (#1999)

- ensure surface writing is time-step and nFields aware.
  This avoids overwriting (ignoring) previous output fields.

- allow sampled surfaces to be used for weight fields as well.
  Not sure why this restriction was still there.

- remove old compatibility reading of orientedFields.
  Last used in v1612, now removed.

- only use face sampling. For surfaceFieldValue we can only do
  something meaningful with face values.

ENH: modify interface methods for surfaceWriter

- replace direct modification of values with setter methods.
  Eg,
     old: writer.isPointData() = true;
     new: writer.isPointData(true);

  This makes it possible to add internal hooks to catch state changes.

ENH: allow post-construction change to sampledSurface interpolation

- rename interpolate() method to isPointData() for consistency with
  other classes and to indicate that it is a query.

- additional isPointData(bool) setter method to change the expected
  representation type after construction

- remove 'interpolate' restriction on isoSurfacePoint which was
  previously flagged as an error but within sampledSurfaces can use
  sampleScheme cellPoint and obtain representative samples.
  Relax this restriction since this particular iso-surface algorithm
  is slated for removal in the foreseeable future.
This commit is contained in:
Mark Olesen
2021-02-10 11:16:50 +01:00
parent 0990d30b73
commit 2954f55f6a
17 changed files with 176 additions and 148 deletions

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -713,7 +713,7 @@ void Foam::averageNeighbourFvGeometryScheme::movePoints()
);
// Use outputDir/TIME/surface-name
writerPtr->useTimeDir() = true;
writerPtr->useTimeDir(true);
writerPtr->beginTime(mesh_.time());
@ -765,7 +765,7 @@ void Foam::averageNeighbourFvGeometryScheme::movePoints()
faceWeights
);
if (writerPtr.valid())
if (writerPtr)
{
writerPtr->beginTime(instant(scalar(iter)));
writerPtr->write("cosAngles", cosAngles);

View File

@ -971,6 +971,8 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
needsUpdate_ = true;
writeArea_ = dict.getOrDefault("writeArea", false);
weightFieldNames_.clear();
// future?
// sampleFaceScheme_ = dict.getOrDefault<word>("sampleScheme", "cell");
totalArea_ = 0;
nFaces_ = 0;
@ -1029,15 +1031,8 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
dict.subDict("sampledSurfaceDict")
);
if (sampledPtr_->interpolate())
{
// Should probably ignore interpolate entirely,
// but the oldest isoSurface algorithm requires it!
WarningInFunction
<< type() << ' ' << name() << ": "
<< "sampledSurface with interpolate = true "
<< "is likely incorrect" << nl << nl;
}
// Internal consistency. Want face values, never point values!
sampledPtr_->isPointData(false);
}
Info<< type() << ' ' << name() << ':' << nl
@ -1055,15 +1050,6 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
if (usesWeight())
{
if (stSampled == regionType_)
{
FatalIOErrorInFunction(dict)
<< "Cannot use weighted operation '"
<< operationTypeNames_[operation_]
<< "' for sampledSurface"
<< exit(FatalIOError);
}
// Can have "weightFields" or "weightField"
bool missing = true;
@ -1109,18 +1095,6 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
}
}
// Backwards compatibility for v1612 and older
List<word> orientedFields;
if (dict.readIfPresent("orientedFields", orientedFields))
{
fields_.append(orientedFields);
WarningInFunction
<< "The 'orientedFields' option is deprecated. These fields can "
<< "and have been added to the standard 'fields' list."
<< endl;
}
if (writeFields_)
{
const word formatName(dict.get<word>("surfaceFormat"));
@ -1134,6 +1108,9 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
)
);
// Propagate field counts (per surface)
surfaceWriterPtr_->nFields(fields_.size());
if (debug)
{
surfaceWriterPtr_->verbose(true);

View File

@ -177,12 +177,11 @@ Note
Instead specify the regionType 'functionObjectSurface' and provide
the name.
- Using \c sampledSurface:
- not available for surface fields
- if interpolate=true they use \c interpolationCellPoint
otherwise they use cell values
- each triangle in \c sampledSurface is logically only in one cell
so interpolation will be wrong when triangles are larger than
cells. This can only happen for sampling on a \c triSurfaceMesh
- surface fields only supported by some surfaces
- default uses sampleScheme \c cell
- each face in \c sampledSurface is logically only in one cell
so sampling will be wrong when they are larger than cells.
This can only happen for sampling on a \c triSurfaceMesh
- take care when using isoSurfaces - these might have duplicate
triangles and so integration might be wrong

View File

@ -96,19 +96,14 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::getFieldValues
if (sampledPtr_)
{
if (sampledPtr_->interpolate())
{
const interpolationCellPoint<Type> interp(fld);
// Could be runtime selectable
// auto sampler = interpolation<Type>::New(sampleFaceScheme_, fld);
return sampledPtr_->interpolate(interp);
}
else
{
// const interpolationCellPoint<Type> interp(fld);
const interpolationCell<Type> interp(fld);
return sampledPtr_->sample(interp);
}
}
else
{
return filterField(fld);
@ -324,6 +319,30 @@ Foam::label Foam::functionObjects::fieldValues::surfaceFieldValue::writeAll
{
label nProcessed = 0;
// If using the surface writer, the points/faces parameters have already
// been merged on the master and the writeValues routine will also gather
// all data onto the master before calling the writer.
// Thus only call the writer on master!
// Begin writer time step
if (Pstream::master() && surfaceWriterPtr_ && surfaceWriterPtr_->enabled())
{
auto& writer = *surfaceWriterPtr_;
writer.open
(
points,
faces,
(
outputDir()
/ regionTypeNames_[regionType_] + ("_" + regionName_)
),
false // serial - already merged
);
writer.beginTime(time_);
}
for (const word& fieldName : fields_)
{
if
@ -349,6 +368,23 @@ Foam::label Foam::functionObjects::fieldValues::surfaceFieldValue::writeAll
}
}
// Finish writer time step
if (Pstream::master() && surfaceWriterPtr_ && surfaceWriterPtr_->enabled())
{
auto& writer = *surfaceWriterPtr_;
// Write geometry if no fields were written so that we still
// can have something to look at.
if (!writer.wroteData())
{
writer.write();
}
writer.endTime();
writer.clear();
}
return nProcessed;
}
@ -377,26 +413,6 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
if (Pstream::master())
{
surfaceWriterPtr_->open
(
points,
faces,
(
outputDir()
/ regionTypeNames_[regionType_] + ("_" + regionName_)
),
false // serial - already merged
);
// Point data? Should probably disallow
if (sampledPtr_)
{
surfaceWriterPtr_->isPointData() =
sampledPtr_->interpolate();
}
surfaceWriterPtr_->nFields() = 1; // Needed for VTK legacy
fileName outputName =
surfaceWriterPtr_->write(fieldName, allValues);
@ -404,8 +420,6 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
dictionary propsDict;
propsDict.add("file", time_.relativePath(outputName, true));
this->setProperty(fieldName, propsDict);
surfaceWriterPtr_->clear();
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd.
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -306,7 +306,7 @@ bool Foam::areaWrite::write()
// Propagate field counts (per surface)
outWriter.nFields() = nAreaFields;
outWriter.nFields(nAreaFields);
// Begin writing
@ -351,7 +351,7 @@ void Foam::areaWrite::expire()
{
surfaceWriter& writer = *(iter.val());
writer.expire();
writer.mergeDim() = mergeDim;
writer.mergeDim(mergeDim);
}
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -215,8 +215,8 @@ void Foam::FacePostProcessing<CloudType>::write()
false // serial - already merged
);
writer->nFields(2); // Legacy VTK
writer->write("massTotal", zoneMassTotal[zoneI]);
writer->write("massFlowRate", zoneMassFlowRate[zoneI]);
}
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2017 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -485,8 +485,8 @@ void Foam::ParticleCollector<CloudType>::write()
false // serial - already merged
);
writer->nFields(2); // Legacy VTK
writer->write("massFlowRate", faceMassFlowRate);
writer->write("massTotal", faceMassTotal);
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -652,13 +652,9 @@ Foam::sampledIsoSurface::sampledIsoSurface
// Not possible for ALGO_POINT
simpleSubMesh_ = false;
if (!sampledSurface::interpolate())
{
FatalIOErrorInFunction(dict)
<< "Non-interpolated iso-surface (point) not supported"
<< " since triangles span across cells." << nl
<< exit(FatalIOError);
}
// Previously emitted an error about using ALGO_POINT with
// non-interpolated, but that was before we had "sampleScheme"
// at the top level
if (isoValues_.size() > 1)
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -70,6 +70,10 @@ Usage
- triangulate is topo-only
- simpleSubMesh and multiple isoValues are not available for point.
Note
For the isoMethod \b point should use a "cellPoint" sampleScheme
since the triangles generated with this algorithm span across cells.
SourceFiles
sampledIsoSurface.C
sampledIsoSurfaceTemplates.C
@ -215,7 +219,7 @@ protected:
public:
//- Runtime type information
TypeName("samplediIsoSurfacePoint");
TypeName("sampledIsoSurface");
// Constructors

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -60,6 +60,10 @@ Usage
mergeTol | tolerance for merging points | no | 1e-6
\endtable
Note
For the isoMethod \b point should use a "cellPoint" sampleScheme
since the triangles generated with this algorithm span across cells.
SourceFiles
sampledIsoSurfacePoint.C

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -287,7 +287,7 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
// Collect the samplePoints and sampleElements
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (sampledSurface::interpolate())
if (sampledSurface::isPointData())
{
// With point interpolation
@ -422,7 +422,7 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
: mesh().cellCentres()
);
if (sampledSurface::interpolate())
if (sampledSurface::isPointData())
{
label vertI = 0;
forAll(samplePoints_, pointi)

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -97,7 +97,7 @@ Foam::sampledSurface::sampledSurface(const word& name, std::nullptr_t)
mesh_(NullObjectRef<polyMesh>()),
enabled_(true),
invariant_(false),
interpolate_(false),
isPointData_(false),
area_(-1)
{}
@ -106,14 +106,14 @@ Foam::sampledSurface::sampledSurface
(
const word& name,
const polyMesh& mesh,
const bool interpolate
const bool interpolateToPoints
)
:
name_(name),
mesh_(mesh),
enabled_(true),
invariant_(false),
interpolate_(interpolate),
isPointData_(interpolateToPoints),
area_(-1)
{}
@ -129,7 +129,7 @@ Foam::sampledSurface::sampledSurface
mesh_(mesh),
enabled_(dict.getOrDefault("enabled", true)),
invariant_(dict.getOrDefault("invariant", false)),
interpolate_(dict.getOrDefault("interpolate", false)),
isPointData_(dict.getOrDefault("interpolate", false)),
area_(-1)
{}
@ -155,6 +155,14 @@ Foam::scalar Foam::sampledSurface::area() const
}
bool Foam::sampledSurface::isPointData(const bool on)
{
bool old(isPointData_);
isPointData_ = on;
return old;
}
bool Foam::sampledSurface::withSurfaceFields() const
{
return false;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -121,8 +121,8 @@ private:
//- Geometry is invariant (never changes)
bool invariant_;
//- Interpolate information to the nodes?
bool interpolate_;
//- Is point vs cell data
bool isPointData_;
//- Total surface area (demand-driven)
mutable scalar area_;
@ -249,7 +249,7 @@ public:
(
const word& name,
const polyMesh& mesh,
const bool interpolate = false
const bool interpolateToPoints = false
);
//- Construct from dictionary
@ -311,12 +311,16 @@ public:
return invariant_;
}
//- Interpolation to nodes requested for surface
bool interpolate() const
//- Using interpolation to surface points
bool isPointData() const
{
return interpolate_;
return isPointData_;
}
//- Change point/cell representation, may trigger an expire().
// \return old value
virtual bool isPointData(const bool on);
//- Does the surface need an update?
virtual bool needsUpdate() const = 0;
@ -561,6 +565,12 @@ public:
//- Print information
virtual void print(Ostream& os) const;
// Housekeeping
//- Same as isPointData()
bool interpolate() const { return isPointData_; }
};

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -171,14 +171,14 @@ void Foam::sampledSurfaces::countFields()
const sampledSurface& s = (*this)[surfi];
surfaceWriter& outWriter = writers_[surfi];
outWriter.nFields() =
outWriter.nFields
(
nVolumeFields
+ (s.withSurfaceFields() ? nSurfaceFields : 0)
+
(
// Face-id field, but not if the writer manages that itself
!s.interpolate() && s.hasFaceIds() && !outWriter.usesFaceIds()
!s.isPointData() && s.hasFaceIds() && !outWriter.usesFaceIds()
? 1 : 0
)
);
@ -360,7 +360,7 @@ bool Foam::sampledSurfaces::read(const dictionary& dict)
newWriter(writerType, formatOptions, surfDict)
);
writers_[surfi].isPointData() = surfs[surfi].interpolate();
writers_[surfi].isPointData(surfs[surfi].isPointData());
// Use outputDir/TIME/surface-name
writers_[surfi].useTimeDir(true);
@ -426,7 +426,7 @@ bool Foam::sampledSurfaces::read(const dictionary& dict)
newWriter(writerType, formatOptions, surfDict)
);
writers_[surfi].isPointData() = surfs[surfi].interpolate();
writers_[surfi].isPointData(surfs[surfi].isPointData());
// Use outputDir/TIME/surface-name
writers_[surfi].useTimeDir(true);
@ -565,7 +565,7 @@ bool Foam::sampledSurfaces::performAction(unsigned request)
outWriter.beginTime(obr_.time());
// Face-id field, but not if the writer manages that itself
if (!s.interpolate() && s.hasFaceIds() && !outWriter.usesFaceIds())
if (!s.isPointData() && s.hasFaceIds() && !outWriter.usesFaceIds())
{
// This is still quite horrible.
@ -723,7 +723,7 @@ bool Foam::sampledSurfaces::expire(const bool force)
}
writers_[surfi].expire();
writers_[surfi].mergeDim() = mergeDim;
writers_[surfi].mergeDim(mergeDim);
nFaces_[surfi] = 0;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -108,7 +108,7 @@ void Foam::sampledSurfaces::performAction
Field<Type> values;
if (s.interpolate())
if (s.isPointData())
{
if (!interpPtr)
{
@ -151,7 +151,7 @@ void Foam::sampledSurfaces::performAction
if ((request & actions_[surfi]) & ACTION_STORE)
{
if (s.interpolate())
if (s.isPointData())
{
storeRegistryField<Type, polySurfacePointGeoMesh>
(

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -83,6 +83,9 @@ SourceFiles
#include "InfoProxy.H"
#include "runTimeSelectionTables.H"
// Deprecated methods
// #define Foam_surfaceWriter_directAccess
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
@ -254,10 +257,10 @@ public:
// Constructors
//- Construct null
//- Default construct
surfaceWriter();
//- Construct null with specified options
//- Default construct with specified options
explicit surfaceWriter(const dictionary& options);
//- Construct from components
@ -378,15 +381,17 @@ public:
// Currently only used by the legacy VTK format.
inline label nFields() const;
//- The number of expected output fields.
//- Set the number of expected output fields
// Currently only used by the legacy VTK format.
inline label& nFields();
// \return old value
inline label nFields(const label n);
//- Are the field data to be treated as point data?
inline bool isPointData() const;
//- Set handling of field data to face/point data.
inline bool& isPointData();
//- Set handling of field data to face/point data
// \return old value
inline bool isPointData(const bool on);
//- Should a time directory be spliced into the output path?
inline bool useTimeDir() const;
@ -395,9 +400,6 @@ public:
// \return old value
inline bool useTimeDir(const bool on);
//- Change handling of spliced output path.
inline bool& useTimeDir();
//- Get output verbosity
inline bool verbose() const;
@ -405,14 +407,12 @@ public:
// \return old value
inline bool verbose(const bool on);
//- Access output verbosity
inline bool& verbose();
//- The current value of the point merge dimension (metre)
inline scalar mergeDim() const;
//- The current value of the point merge dimension (metre)
inline scalar& mergeDim();
//- Change the point merge dimension (metre)
// \return old value
inline scalar mergeDim(const scalar dist);
// Time
@ -539,6 +539,28 @@ public:
Ostream& os,
const InfoProxy<surfaceWriter>& ip
);
// Housekeeping
#ifdef Foam_surfaceWriter_directAccess
//- Access number of expected output fields.
label& nFields() { return nFields_; }
//- Access handling of face/point data
bool& isPointData() { return isPointData_; }
//- Access handling of spliced output path
bool& useTimeDir() { return useTimeDir_; }
//- Access output verbosity
bool& verbose() { return verbose_; }
//- Access value of the point merge dimension
scalar& mergeDim() { return mergeDim_; }
#endif
};

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd.
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -33,9 +33,11 @@ inline Foam::label Foam::surfaceWriter::nFields() const
}
inline Foam::label& Foam::surfaceWriter::nFields()
inline Foam::label Foam::surfaceWriter::nFields(const label n)
{
return nFields_;
label old(nFields_);
nFields_ = n;
return old;
}
@ -45,9 +47,11 @@ inline bool Foam::surfaceWriter::isPointData() const
}
inline bool& Foam::surfaceWriter::isPointData()
inline bool Foam::surfaceWriter::isPointData(const bool on)
{
return isPointData_;
bool old(isPointData_);
isPointData_ = on;
return old;
}
@ -65,12 +69,6 @@ inline bool Foam::surfaceWriter::useTimeDir(const bool on)
}
inline bool& Foam::surfaceWriter::useTimeDir()
{
return useTimeDir_;
}
inline bool Foam::surfaceWriter::verbose() const
{
return verbose_;
@ -85,21 +83,17 @@ inline bool Foam::surfaceWriter::verbose(const bool on)
}
inline bool& Foam::surfaceWriter::verbose()
{
return verbose_;
}
inline Foam::scalar Foam::surfaceWriter::mergeDim() const
{
return mergeDim_;
}
inline Foam::scalar& Foam::surfaceWriter::mergeDim()
inline Foam::scalar Foam::surfaceWriter::mergeDim(const scalar dist)
{
return mergeDim_;
scalar old(mergeDim_);
mergeDim_ = dist;
return old;
}