mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: refactor coordSet writers (#2347)
- the very old 'writer' class was fully stateless and always templated on an particular output type. This is now replaced with a 'coordSetWriter' with similar concepts as previously introduced for surface writers (#1206). - writers change from being a generic state-less set of routines to more properly conforming to the normal notion of a writer. - Parallel data is done *outside* of the writers, since they are used in a wide variety of contexts and the caller is currently still in a better position for deciding how to combine parallel data. ENH: update sampleSets to sample on per-field basis (#2347) - sample/write a field in a single step. - support for 'sampleOnExecute' to obtain values at execution intervals without writing. - support 'sets' input as a dictionary entry (as well as a list), which is similar to the changes for sampled-surface and permits use of changeDictionary to modify content. - globalIndex for gather to reduce parallel communication, less code - qualify the sampleSet results (properties) with the name of the set. The sample results were previously without a qualifier, which meant that only the last property value was actually saved (previous ones overwritten). For example, ``` sample1 { scalar { average(line,T) 349.96521; min(line,T) 349.9544281; max(line,T) 350; average(cells,T) 349.9854619; min(cells,T) 349.6589286; max(cells,T) 350.4967271; average(line,epsilon) 0.04947733869; min(line,epsilon) 0.04449639927; max(line,epsilon) 0.06452856475; } label { size(line,T) 79; size(cells,T) 1720; size(line,epsilon) 79; } } ``` ENH: update particleTracks application - use globalIndex to manage original parcel addressing and for gathering. Simplify code by introducing a helper class, storing intermediate fields in hash tables instead of separate lists. ADDITIONAL NOTES: - the regionSizeDistribution largely retains separate writers since the utility of placing sum/dev/count for all fields into a single file is questionable. - the streamline writing remains a "soft" upgrade, which means that scalar and vector fields are still collected a priori and not on-the-fly. This is due to how the streamline infrastructure is currently handled (should be upgraded in the future).
This commit is contained in:
@ -13,7 +13,6 @@ sampledSet/patchSeed/patchSeedSet.C
|
||||
sampledSet/patchEdge/patchEdgeSet.C
|
||||
sampledSet/sampledSet/sampledSet.C
|
||||
sampledSet/sampledSets/sampledSets.C
|
||||
sampledSet/sampledSets/sampledSetsGrouping.C
|
||||
sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C
|
||||
sampledSet/uniform/uniformSet.C
|
||||
sampledSet/array/arraySet.C
|
||||
|
||||
@ -57,11 +57,11 @@ void Foam::midPointAndFaceSet::genSamples()
|
||||
while (size() > 0)
|
||||
{
|
||||
// Add first face
|
||||
mpfSamplePoints[mpfSamplei] = operator[](samplei);
|
||||
mpfSamplePoints[mpfSamplei] = points()[samplei];
|
||||
mpfSampleCells[mpfSamplei] = cells_[samplei];
|
||||
mpfSampleFaces[mpfSamplei] = faces_[samplei];
|
||||
mpfSampleSegments[mpfSamplei] = segments_[samplei];
|
||||
mpfSampleCurveDist[mpfSamplei] = curveDist_[samplei];
|
||||
mpfSampleCurveDist[mpfSamplei] = distance_[samplei];
|
||||
++mpfSamplei;
|
||||
|
||||
while
|
||||
@ -70,7 +70,7 @@ void Foam::midPointAndFaceSet::genSamples()
|
||||
&& (segments_[samplei] == segments_[samplei+1])
|
||||
)
|
||||
{
|
||||
point midPoint(0.5*(operator[](samplei) + operator[](samplei+1)));
|
||||
point midPoint(0.5*(points()[samplei] + points()[samplei+1]));
|
||||
label cellm = pointInCell(midPoint, samplei);
|
||||
|
||||
if (cellm != -1)
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2021 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -30,7 +30,6 @@ License
|
||||
#include "polyMesh.H"
|
||||
#include "primitiveMesh.H"
|
||||
#include "meshSearch.H"
|
||||
#include "writer.H"
|
||||
#include "particle.H"
|
||||
#include "globalIndex.H"
|
||||
|
||||
@ -52,16 +51,16 @@ void Foam::sampledSet::checkDimensions() const
|
||||
(cells_.size() != size())
|
||||
|| (faces_.size() != size())
|
||||
|| (segments_.size() != size())
|
||||
|| (curveDist_.size() != size())
|
||||
|| (distance_.size() != size())
|
||||
)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "sizes not equal : "
|
||||
<< "Sizes not equal : "
|
||||
<< " points:" << size()
|
||||
<< " cells:" << cells_.size()
|
||||
<< " faces:" << faces_.size()
|
||||
<< " segments:" << segments_.size()
|
||||
<< " curveDist:" << curveDist_.size()
|
||||
<< " distance:" << distance_.size()
|
||||
<< abort(FatalError);
|
||||
}
|
||||
}
|
||||
@ -75,14 +74,12 @@ Foam::label Foam::sampledSet::getBoundaryCell(const label facei) const
|
||||
|
||||
Foam::label Foam::sampledSet::getNeighbourCell(const label facei) const
|
||||
{
|
||||
if (facei >= mesh().nInternalFaces())
|
||||
{
|
||||
return mesh().faceOwner()[facei];
|
||||
}
|
||||
else
|
||||
if (facei < mesh().nInternalFaces())
|
||||
{
|
||||
return mesh().faceNeighbour()[facei];
|
||||
}
|
||||
|
||||
return mesh().faceOwner()[facei];
|
||||
}
|
||||
|
||||
|
||||
@ -384,11 +381,11 @@ void Foam::sampledSet::setSamples
|
||||
const labelList& samplingCells,
|
||||
const labelList& samplingFaces,
|
||||
const labelList& samplingSegments,
|
||||
const scalarList& samplingCurveDist
|
||||
const scalarList& samplingDistance
|
||||
)
|
||||
{
|
||||
setPoints(samplingPts);
|
||||
curveDist_ = samplingCurveDist;
|
||||
setDistance(samplingDistance, false); // check=false
|
||||
|
||||
segments_ = samplingSegments;
|
||||
cells_ = samplingCells;
|
||||
@ -404,11 +401,11 @@ void Foam::sampledSet::setSamples
|
||||
labelList&& samplingCells,
|
||||
labelList&& samplingFaces,
|
||||
labelList&& samplingSegments,
|
||||
scalarList&& samplingCurveDist
|
||||
scalarList&& samplingDistance
|
||||
)
|
||||
{
|
||||
setPoints(std::move(samplingPts));
|
||||
curveDist_ = std::move(samplingCurveDist);
|
||||
setDistance(std::move(samplingDistance), false); // check=false
|
||||
|
||||
segments_ = std::move(samplingSegments);
|
||||
cells_ = std::move(samplingCells);
|
||||
@ -418,48 +415,6 @@ void Foam::sampledSet::setSamples
|
||||
}
|
||||
|
||||
|
||||
Foam::autoPtr<Foam::coordSet> Foam::sampledSet::gather
|
||||
(
|
||||
labelList& indexSet,
|
||||
labelList& allSegments
|
||||
) const
|
||||
{
|
||||
// Combine sampleSet from processors. Sort by curveDist. Return
|
||||
// ordering in indexSet.
|
||||
// Note: only master results are valid
|
||||
|
||||
List<point> allPts;
|
||||
globalIndex::gatherOp(*this, allPts);
|
||||
|
||||
globalIndex::gatherOp(segments(), allSegments);
|
||||
|
||||
scalarList allCurveDist;
|
||||
globalIndex::gatherOp(curveDist(), allCurveDist);
|
||||
|
||||
|
||||
if (Pstream::master() && allCurveDist.empty())
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Sample set " << name()
|
||||
<< " has zero points." << endl;
|
||||
}
|
||||
|
||||
// Sort curveDist and use to fill masterSamplePts
|
||||
Foam::sortedOrder(allCurveDist, indexSet); // uses stable sort
|
||||
scalarList sortedDist(allCurveDist, indexSet); // with indices for mapping
|
||||
|
||||
allSegments = UIndirectList<label>(allSegments, indexSet)();
|
||||
|
||||
return autoPtr<coordSet>::New
|
||||
(
|
||||
name(),
|
||||
axis(),
|
||||
List<point>(UIndirectList<point>(allPts, indexSet)),
|
||||
sortedDist
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::sampledSet::sampledSet
|
||||
@ -513,6 +468,25 @@ Foam::sampledSet::sampledSet
|
||||
{}
|
||||
|
||||
|
||||
// Foam::autoPtr<Foam::coordSet> Foam::sampledSet::gather
|
||||
// (
|
||||
// labelList& sortOrder,
|
||||
// labelList& allSegments
|
||||
// ) const
|
||||
// {
|
||||
// autoPtr<coordSet> result(coordSet::gatherSort(sortOrder));
|
||||
//
|
||||
// // Optional
|
||||
// if (notNull(allSegments))
|
||||
// {
|
||||
// globalIndex::gatherOp(segments(), allSegments);
|
||||
// allSegments = UIndirectList<label>(allSegments, sortOrder)();
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::autoPtr<Foam::sampledSet> Foam::sampledSet::New
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2017-2018 OpenCFD Ltd.
|
||||
Copyright (C) 2017-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -50,20 +50,20 @@ SourceFiles
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef sampledSet_H
|
||||
#define sampledSet_H
|
||||
#ifndef Foam_sampledSet_H
|
||||
#define Foam_sampledSet_H
|
||||
|
||||
#include "coordSet.H"
|
||||
#include "autoPtr.H"
|
||||
#include "typeInfo.H"
|
||||
#include "runTimeSelectionTables.H"
|
||||
#include "autoPtr.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward declarations
|
||||
// Forward Declarations
|
||||
class polyMesh;
|
||||
class meshSearch;
|
||||
|
||||
@ -75,7 +75,7 @@ class sampledSet
|
||||
:
|
||||
public coordSet
|
||||
{
|
||||
// Private data
|
||||
// Private Data
|
||||
|
||||
//- Reference to mesh
|
||||
const polyMesh& mesh_;
|
||||
@ -86,6 +86,8 @@ class sampledSet
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Data
|
||||
|
||||
//- Segment numbers
|
||||
labelList segments_;
|
||||
|
||||
@ -154,7 +156,7 @@ protected:
|
||||
const labelList& samplingCells,
|
||||
const labelList& samplingFaces,
|
||||
const labelList& samplingSegments,
|
||||
const scalarList& samplingCurveDist
|
||||
const scalarList& samplingDistance
|
||||
);
|
||||
|
||||
//- Set sample data. Move list contents.
|
||||
@ -164,7 +166,7 @@ protected:
|
||||
labelList&& samplingCells,
|
||||
labelList&& samplingFaces,
|
||||
labelList&& samplingSegments,
|
||||
scalarList&& samplingCurveDist
|
||||
scalarList&& samplingDistance
|
||||
);
|
||||
|
||||
public:
|
||||
@ -194,22 +196,58 @@ public:
|
||||
// PtrLists of sampledSet
|
||||
class iNew
|
||||
{
|
||||
//- Reference to the volume mesh
|
||||
const polyMesh& mesh_;
|
||||
const meshSearch& searchEngine_;
|
||||
const meshSearch& search_;
|
||||
|
||||
public:
|
||||
|
||||
iNew(const polyMesh& mesh, const meshSearch& searchEngine)
|
||||
:
|
||||
mesh_(mesh),
|
||||
searchEngine_(searchEngine)
|
||||
search_(searchEngine)
|
||||
{}
|
||||
|
||||
autoPtr<sampledSet> operator()(Istream& is) const
|
||||
{
|
||||
word name(is);
|
||||
dictionary dict(is);
|
||||
return sampledSet::New(name, mesh_, searchEngine_, dict);
|
||||
return sampledSet::New(name, mesh_, search_, dict);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- PtrList read-construction helper that captures dictionaries used
|
||||
//- during creation.
|
||||
class iNewCapture
|
||||
{
|
||||
//- Reference to the volume mesh
|
||||
const polyMesh& mesh_;
|
||||
const meshSearch& search_;
|
||||
|
||||
//- Captured (recorded) dictionaries
|
||||
DynamicList<dictionary>& capture_;
|
||||
|
||||
public:
|
||||
|
||||
iNewCapture
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const meshSearch& searchEngine,
|
||||
DynamicList<dictionary>& capture
|
||||
)
|
||||
:
|
||||
mesh_(mesh),
|
||||
search_(searchEngine),
|
||||
capture_(capture)
|
||||
{}
|
||||
|
||||
autoPtr<sampledSet> operator()(Istream& is) const
|
||||
{
|
||||
word name(is);
|
||||
capture_.append(dictionary(is));
|
||||
|
||||
return sampledSet::New(name, mesh_, search_, capture_.last());
|
||||
}
|
||||
};
|
||||
|
||||
@ -269,27 +307,27 @@ public:
|
||||
|
||||
// Member Functions
|
||||
|
||||
const polyMesh& mesh() const
|
||||
const polyMesh& mesh() const noexcept
|
||||
{
|
||||
return mesh_;
|
||||
}
|
||||
|
||||
const meshSearch& searchEngine() const
|
||||
const meshSearch& searchEngine() const noexcept
|
||||
{
|
||||
return searchEngine_;
|
||||
}
|
||||
|
||||
const labelList& segments() const
|
||||
const labelList& segments() const noexcept
|
||||
{
|
||||
return segments_;
|
||||
}
|
||||
|
||||
const labelList& cells() const
|
||||
const labelList& cells() const noexcept
|
||||
{
|
||||
return cells_;
|
||||
}
|
||||
|
||||
const labelList& faces() const
|
||||
const labelList& faces() const noexcept
|
||||
{
|
||||
return faces_;
|
||||
}
|
||||
@ -297,13 +335,16 @@ public:
|
||||
//- Output for debugging
|
||||
Ostream& write(Ostream&) const;
|
||||
|
||||
//- Helper: gather onto master and sort.
|
||||
// \return (on master) gathered set and overall sort order
|
||||
autoPtr<coordSet> gather
|
||||
(
|
||||
labelList& indexSet,
|
||||
labelList& allSegments
|
||||
) const;
|
||||
|
||||
// Other
|
||||
|
||||
/// //- Gather and sort.
|
||||
/// \return (on master) gathered set and overall sort order
|
||||
/// autoPtr<coordSet> gather
|
||||
/// (
|
||||
/// labelList& sortOrder,
|
||||
/// labelList& allSegments
|
||||
/// ) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2020 OpenCFD Ltd.
|
||||
Copyright (C) 2011 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -29,9 +29,12 @@ License
|
||||
#include "sampledSets.H"
|
||||
#include "dictionary.H"
|
||||
#include "Time.H"
|
||||
#include "globalIndex.H"
|
||||
#include "volFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
#include "mapPolyMesh.H"
|
||||
#include "IOobjectList.H"
|
||||
#include "UIndirectList.H"
|
||||
#include "ListOps.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
@ -48,36 +51,287 @@ namespace Foam
|
||||
);
|
||||
}
|
||||
|
||||
bool Foam::sampledSets::verbose_ = false;
|
||||
|
||||
#include "sampledSetsImpl.C"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
void Foam::sampledSets::combineSampledSets
|
||||
Foam::autoPtr<Foam::coordSetWriter> Foam::sampledSets::newWriter
|
||||
(
|
||||
PtrList<coordSet>& masterSampledSets,
|
||||
labelListList& indexSets
|
||||
word writeType,
|
||||
const dictionary& formatOptions,
|
||||
const dictionary& setDict
|
||||
)
|
||||
{
|
||||
// Combine sampleSets from processors. Sort by curveDist. Return
|
||||
// ordering in indexSets.
|
||||
// Note: only master results are valid
|
||||
// Per-set adjustment
|
||||
setDict.readIfPresent<word>("setFormat", writeType);
|
||||
|
||||
masterSampledSets_.clear();
|
||||
masterSampledSets_.setSize(size());
|
||||
indexSets_.setSize(size());
|
||||
dictionary options = formatOptions.subOrEmptyDict(writeType);
|
||||
|
||||
const PtrList<sampledSet>& sampledSets = *this;
|
||||
options.merge
|
||||
(
|
||||
setDict.subOrEmptyDict("formatOptions").subOrEmptyDict(writeType)
|
||||
);
|
||||
|
||||
forAll(sampledSets, setI)
|
||||
return coordSetWriter::New(writeType, options);
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledSets::gatherAllSets()
|
||||
{
|
||||
// Any writer references will become invalid
|
||||
for (auto& writer : writers_)
|
||||
{
|
||||
labelList segments;
|
||||
masterSampledSets.set
|
||||
(
|
||||
setI,
|
||||
sampledSets[setI].gather(indexSets[setI], segments)
|
||||
);
|
||||
writer.expire();
|
||||
}
|
||||
|
||||
const PtrList<sampledSet>& localSets = *this;
|
||||
|
||||
gatheredSets_.clear();
|
||||
gatheredSets_.resize(localSets.size());
|
||||
gatheredSorting_.resize_nocopy(localSets.size());
|
||||
globalIndices_.resize_nocopy(localSets.size());
|
||||
|
||||
forAll(localSets, seti)
|
||||
{
|
||||
const coordSet& coords = localSets[seti];
|
||||
|
||||
globalIndices_[seti].reset(coords.size(), globalIndex::gatherOnly{});
|
||||
gatheredSets_.set(seti, coords.gatherSort(gatheredSorting_[seti]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::IOobjectList Foam::sampledSets::preCheckFields()
|
||||
{
|
||||
wordList allFields; // Just needed for warnings
|
||||
HashTable<wordHashSet> selected;
|
||||
|
||||
IOobjectList objects(0);
|
||||
|
||||
if (loadFromFiles_)
|
||||
{
|
||||
// Check files for a particular time
|
||||
objects = IOobjectList(mesh_, mesh_.time().timeName());
|
||||
|
||||
allFields = objects.names();
|
||||
selected = objects.classes(fieldSelection_);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check currently available fields
|
||||
allFields = mesh_.names();
|
||||
selected = mesh_.classes(fieldSelection_);
|
||||
}
|
||||
|
||||
// Probably not needed...
|
||||
// if (Pstream::parRun())
|
||||
// {
|
||||
// Pstream::mapCombineGather(selected, HashSetOps::plusEqOp<word>());
|
||||
// Pstream::mapCombineScatter(selected);
|
||||
// }
|
||||
|
||||
|
||||
DynamicList<label> missed(fieldSelection_.size());
|
||||
|
||||
// Detect missing fields
|
||||
forAll(fieldSelection_, i)
|
||||
{
|
||||
if
|
||||
(
|
||||
fieldSelection_[i].isLiteral()
|
||||
&& !ListOps::found(allFields, fieldSelection_[i])
|
||||
)
|
||||
{
|
||||
missed.append(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (missed.size())
|
||||
{
|
||||
WarningInFunction
|
||||
<< nl
|
||||
<< "Cannot find "
|
||||
<< (loadFromFiles_ ? "field file" : "registered field")
|
||||
<< " matching "
|
||||
<< UIndirectList<wordRe>(fieldSelection_, missed) << endl;
|
||||
}
|
||||
|
||||
|
||||
// The selected field names, ordered by (scalar, vector, ...)
|
||||
// with internal sorting
|
||||
|
||||
selectedFieldNames_.clear();
|
||||
|
||||
do
|
||||
{
|
||||
#undef doLocalCode
|
||||
#define doLocalCode(InputType) \
|
||||
{ \
|
||||
const auto iter = selected.find(InputType::typeName); \
|
||||
if (iter.found()) \
|
||||
{ \
|
||||
selectedFieldNames_.append(iter.val().sortedToc()); \
|
||||
} \
|
||||
}
|
||||
|
||||
doLocalCode(volScalarField);
|
||||
doLocalCode(volVectorField);
|
||||
doLocalCode(volSphericalTensorField);
|
||||
doLocalCode(volSymmTensorField);
|
||||
doLocalCode(volTensorField);
|
||||
#undef doLocalCode
|
||||
}
|
||||
while (false);
|
||||
|
||||
|
||||
// Now propagate field counts (per surface)
|
||||
// - can update writer even when not writing without problem
|
||||
|
||||
const label nFields = selectedFieldNames_.size();
|
||||
|
||||
forAll(writers_, seti)
|
||||
{
|
||||
coordSetWriter& writer = writers_[seti];
|
||||
|
||||
writer.nFields(nFields);
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledSets::initDict(const dictionary& dict, const bool initial)
|
||||
{
|
||||
PtrList<sampledSet>::clear();
|
||||
if (initial)
|
||||
{
|
||||
writers_.clear();
|
||||
}
|
||||
|
||||
const entry* eptr = dict.findEntry("sets");
|
||||
|
||||
if (eptr && eptr->isDict())
|
||||
{
|
||||
PtrList<sampledSet> sampSets(eptr->dict().size());
|
||||
if (initial)
|
||||
{
|
||||
writers_.resize(sampSets.size());
|
||||
}
|
||||
|
||||
label seti = 0;
|
||||
|
||||
for (const entry& dEntry : eptr->dict())
|
||||
{
|
||||
if (!dEntry.isDict())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const dictionary& subDict = dEntry.dict();
|
||||
|
||||
autoPtr<sampledSet> sampSet =
|
||||
sampledSet::New
|
||||
(
|
||||
dEntry.keyword(),
|
||||
mesh_,
|
||||
searchEngine_,
|
||||
subDict
|
||||
);
|
||||
|
||||
// if (!sampSet || !sampSet->enabled())
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// Define the set
|
||||
sampSets.set(seti, sampSet);
|
||||
|
||||
// Define writer, but do not attached
|
||||
if (initial)
|
||||
{
|
||||
writers_.set
|
||||
(
|
||||
seti,
|
||||
newWriter(writeFormat_, writeFormatOptions_, subDict)
|
||||
);
|
||||
|
||||
// Use outputDir/TIME/set-name
|
||||
writers_[seti].useTimeDir(true);
|
||||
writers_[seti].verbose(verbose_);
|
||||
}
|
||||
++seti;
|
||||
}
|
||||
|
||||
sampSets.resize(seti);
|
||||
if (initial)
|
||||
{
|
||||
writers_.resize(seti);
|
||||
}
|
||||
static_cast<PtrList<sampledSet>&>(*this).transfer(sampSets);
|
||||
}
|
||||
else if (eptr)
|
||||
{
|
||||
// This is slightly trickier.
|
||||
// We want access to the individual dictionaries used for construction
|
||||
|
||||
DynamicList<dictionary> capture;
|
||||
|
||||
PtrList<sampledSet> input
|
||||
(
|
||||
eptr->stream(),
|
||||
sampledSet::iNewCapture(mesh_, searchEngine_, capture)
|
||||
);
|
||||
|
||||
PtrList<sampledSet> sampSets(input.size());
|
||||
if (initial)
|
||||
{
|
||||
writers_.resize(sampSets.size());
|
||||
}
|
||||
|
||||
label seti = 0;
|
||||
|
||||
forAll(input, inputi)
|
||||
{
|
||||
const dictionary& subDict = capture[inputi];
|
||||
|
||||
autoPtr<sampledSet> sampSet = input.release(inputi);
|
||||
|
||||
// if (!sampSet || !sampSet->enabled())
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// Define the set
|
||||
sampSets.set(seti, sampSet);
|
||||
|
||||
// Define writer, but do not attached
|
||||
if (initial)
|
||||
{
|
||||
writers_.set
|
||||
(
|
||||
seti,
|
||||
newWriter(writeFormat_, writeFormatOptions_, subDict)
|
||||
);
|
||||
|
||||
// Use outputDir/TIME/set-name
|
||||
writers_[seti].useTimeDir(true);
|
||||
writers_[seti].verbose(verbose_);
|
||||
}
|
||||
++seti;
|
||||
}
|
||||
|
||||
sampSets.resize(seti);
|
||||
if (initial)
|
||||
{
|
||||
writers_.resize(seti);
|
||||
}
|
||||
|
||||
static_cast<PtrList<sampledSet>&>(*this).transfer(sampSets);
|
||||
}
|
||||
|
||||
gatherAllSets();
|
||||
|
||||
needsCorrect_ = false;
|
||||
}
|
||||
|
||||
|
||||
@ -90,21 +344,27 @@ Foam::sampledSets::sampledSets
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
functionObjects::regionFunctionObject(name, runTime, dict),
|
||||
functionObjects::fvMeshFunctionObject(name, runTime, dict),
|
||||
PtrList<sampledSet>(),
|
||||
mesh_(refCast<const fvMesh>(obr_)),
|
||||
dict_(dict),
|
||||
loadFromFiles_(false),
|
||||
outputPath_(fileName::null),
|
||||
searchEngine_(mesh_),
|
||||
interpolationScheme_(word::null),
|
||||
writeFormat_(word::null),
|
||||
writeFormatOptions_(dict.subOrEmptyDict("formatOptions"))
|
||||
{
|
||||
outputPath_ =
|
||||
verbose_(false),
|
||||
onExecute_(false),
|
||||
needsCorrect_(false),
|
||||
outputPath_
|
||||
(
|
||||
mesh_.time().globalPath()/functionObject::outputPrefix/name
|
||||
);
|
||||
|
||||
time_.globalPath()/functionObject::outputPrefix/name
|
||||
),
|
||||
searchEngine_(mesh_),
|
||||
samplePointScheme_(),
|
||||
writeFormat_(),
|
||||
writeFormatOptions_(dict.subOrEmptyDict("formatOptions")),
|
||||
writers_(),
|
||||
selectedFieldNames_(),
|
||||
gatheredSets_(),
|
||||
gatheredSorting_(),
|
||||
globalIndices_()
|
||||
{
|
||||
if (mesh_.name() != polyMesh::defaultRegion)
|
||||
{
|
||||
outputPath_ /= mesh_.name();
|
||||
@ -124,26 +384,31 @@ Foam::sampledSets::sampledSets
|
||||
const bool loadFromFiles
|
||||
)
|
||||
:
|
||||
functionObjects::regionFunctionObject(name, obr, dict),
|
||||
functionObjects::fvMeshFunctionObject(name, obr, dict),
|
||||
PtrList<sampledSet>(),
|
||||
mesh_(refCast<const fvMesh>(obr)),
|
||||
dict_(dict),
|
||||
loadFromFiles_(loadFromFiles),
|
||||
outputPath_(fileName::null),
|
||||
searchEngine_(mesh_),
|
||||
interpolationScheme_(word::null),
|
||||
writeFormat_(word::null),
|
||||
writeFormatOptions_(dict.subOrEmptyDict("formatOptions"))
|
||||
{
|
||||
outputPath_ =
|
||||
verbose_(false),
|
||||
onExecute_(false),
|
||||
needsCorrect_(false),
|
||||
outputPath_
|
||||
(
|
||||
mesh_.time().globalPath()/functionObject::outputPrefix/name
|
||||
);
|
||||
|
||||
time_.globalPath()/functionObject::outputPrefix/name
|
||||
),
|
||||
searchEngine_(mesh_),
|
||||
samplePointScheme_(),
|
||||
writeFormat_(),
|
||||
writeFormatOptions_(dict.subOrEmptyDict("formatOptions")),
|
||||
writers_(),
|
||||
selectedFieldNames_(),
|
||||
gatheredSets_(),
|
||||
gatheredSorting_(),
|
||||
globalIndices_()
|
||||
{
|
||||
if (mesh_.name() != polyMesh::defaultRegion)
|
||||
{
|
||||
outputPath_ /= mesh_.name();
|
||||
}
|
||||
|
||||
outputPath_.clean(); // Remove unneeded ".."
|
||||
|
||||
read(dict);
|
||||
@ -152,7 +417,7 @@ Foam::sampledSets::sampledSets
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::sampledSets::verbose(const bool on)
|
||||
bool Foam::sampledSets::verbose(const bool on) noexcept
|
||||
{
|
||||
bool old(verbose_);
|
||||
verbose_ = on;
|
||||
@ -160,122 +425,205 @@ bool Foam::sampledSets::verbose(const bool on)
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledSets::read(const dictionary& dict)
|
||||
{
|
||||
if (&dict_ != &dict)
|
||||
{
|
||||
// Update local copy of dictionary
|
||||
dict_ = dict;
|
||||
}
|
||||
|
||||
fvMeshFunctionObject::read(dict);
|
||||
|
||||
PtrList<sampledSet>::clear();
|
||||
writers_.clear();
|
||||
fieldSelection_.clear();
|
||||
selectedFieldNames_.clear();
|
||||
|
||||
gatheredSets_.clear();
|
||||
gatheredSorting_.clear();
|
||||
globalIndices_.clear();
|
||||
|
||||
verbose_ = dict.getOrDefault("verbose", false);
|
||||
onExecute_ = dict.getOrDefault("sampleOnExecute", false);
|
||||
|
||||
samplePointScheme_ =
|
||||
dict.getOrDefault<word>("interpolationScheme", "cellPoint");
|
||||
|
||||
const entry* eptr = dict.findEntry("sets");
|
||||
|
||||
if (eptr)
|
||||
{
|
||||
dict.readEntry("setFormat", writeFormat_);
|
||||
}
|
||||
// const dictionary formatOptions(dict.subOrEmptyDict("formatOptions"));
|
||||
// Writer type and format options
|
||||
// const word writerType =
|
||||
// (eptr ? dict.get<word>("setFormat") : word::null);
|
||||
// writerType_ = (eptr ? dict.get<word>("setFormat") : word::null);
|
||||
|
||||
initDict(dict, true);
|
||||
|
||||
// Have some sets, so sort out which fields are needed and report
|
||||
|
||||
if (this->size())
|
||||
{
|
||||
dict_.readEntry("fields", fieldSelection_);
|
||||
fieldSelection_.uniq();
|
||||
|
||||
// Report
|
||||
forAll(*this, seti)
|
||||
{
|
||||
const sampledSet& s = (*this)[seti];
|
||||
|
||||
if (!seti)
|
||||
{
|
||||
Info<< "Sampled set:" << nl;
|
||||
}
|
||||
|
||||
Info<< " " << s.name() << " -> " << writers_[seti].type()
|
||||
<< nl;
|
||||
}
|
||||
|
||||
Info<< endl;
|
||||
}
|
||||
|
||||
if (debug && Pstream::master())
|
||||
{
|
||||
Pout<< "sample fields:" << flatOutput(fieldSelection_) << nl
|
||||
<< "sample sets:" << nl << '(' << nl;
|
||||
|
||||
for
|
||||
(
|
||||
const sampledSet& s
|
||||
: static_cast<const PtrList<sampledSet>&>(*this)
|
||||
)
|
||||
{
|
||||
Pout<< " " << s << endl;
|
||||
}
|
||||
Pout<< ')' << endl;
|
||||
}
|
||||
|
||||
// FUTURE:
|
||||
// Ensure all sets and merge information are expired
|
||||
// expire(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledSets::performAction(unsigned request)
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
else if (needsCorrect_)
|
||||
{
|
||||
searchEngine_.correct();
|
||||
initDict(dict_, false);
|
||||
}
|
||||
|
||||
// FUTURE:
|
||||
// Update sets and store
|
||||
// ...
|
||||
|
||||
// Determine availability of fields.
|
||||
// Count number of fields (only seems to be needed for VTK legacy)
|
||||
|
||||
IOobjectList objects = preCheckFields();
|
||||
|
||||
const label nFields = selectedFieldNames_.size();
|
||||
|
||||
if (!nFields)
|
||||
{
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update writers
|
||||
|
||||
forAll(*this, seti)
|
||||
{
|
||||
const coordSet& s = gatheredSets_[seti];
|
||||
|
||||
if (request & ACTION_WRITE)
|
||||
{
|
||||
coordSetWriter& writer = writers_[seti];
|
||||
|
||||
if (writer.needsUpdate())
|
||||
{
|
||||
writer.setCoordinates(s);
|
||||
}
|
||||
|
||||
if (writer.buffering())
|
||||
{
|
||||
writer.open
|
||||
(
|
||||
outputPath_
|
||||
/ word(s.name() + coordSetWriter::suffix(selectedFieldNames_))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.open(outputPath_/s.name());
|
||||
}
|
||||
|
||||
writer.beginTime(mesh_.time());
|
||||
}
|
||||
}
|
||||
|
||||
// Sample fields
|
||||
|
||||
performAction<VolumeField<scalar>>(objects, request);
|
||||
performAction<VolumeField<vector>>(objects, request);
|
||||
performAction<VolumeField<sphericalTensor>>(objects, request);
|
||||
performAction<VolumeField<symmTensor>>(objects, request);
|
||||
performAction<VolumeField<tensor>>(objects, request);
|
||||
|
||||
|
||||
// Finish this time step
|
||||
forAll(writers_, seti)
|
||||
{
|
||||
// Write geometry if no fields were written so that we still
|
||||
// can have something to look at
|
||||
|
||||
if (request & ACTION_WRITE)
|
||||
{
|
||||
/// if (!writers_[seti].wroteData())
|
||||
/// {
|
||||
/// writers_[seti].write();
|
||||
/// }
|
||||
|
||||
writers_[seti].endTime();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledSets::execute()
|
||||
{
|
||||
if (onExecute_)
|
||||
{
|
||||
return performAction(ACTION_ALL & ~ACTION_WRITE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledSets::write()
|
||||
{
|
||||
if (size())
|
||||
{
|
||||
const label nFields = classifyFields();
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "timeName = " << mesh_.time().timeName() << nl
|
||||
<< "scalarFields " << scalarFields_ << nl
|
||||
<< "vectorFields " << vectorFields_ << nl
|
||||
<< "sphTensorFields " << sphericalTensorFields_ << nl
|
||||
<< "symTensorFields " << symmTensorFields_ <<nl
|
||||
<< "tensorFields " << tensorFields_ <<nl;
|
||||
}
|
||||
|
||||
if (nFields)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Creating directory "
|
||||
<< outputPath_/mesh_.time().timeName()
|
||||
<< nl << endl;
|
||||
}
|
||||
|
||||
mkDir(outputPath_/mesh_.time().timeName());
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "No fields to sample" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (nFields)
|
||||
{
|
||||
sampleAndWrite(scalarFields_);
|
||||
sampleAndWrite(vectorFields_);
|
||||
sampleAndWrite(sphericalTensorFields_);
|
||||
sampleAndWrite(symmTensorFields_);
|
||||
sampleAndWrite(tensorFields_);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledSets::read(const dictionary& dict)
|
||||
{
|
||||
dict_ = dict;
|
||||
|
||||
if (dict_.found("sets"))
|
||||
{
|
||||
dict_.readEntry("fields", fieldSelection_);
|
||||
clearFieldGroups();
|
||||
|
||||
dict.readEntry("interpolationScheme", interpolationScheme_);
|
||||
dict.readEntry("setFormat", writeFormat_);
|
||||
|
||||
PtrList<sampledSet> newList
|
||||
(
|
||||
dict_.lookup("sets"),
|
||||
sampledSet::iNew(mesh_, searchEngine_)
|
||||
);
|
||||
transfer(newList);
|
||||
combineSampledSets(masterSampledSets_, indexSets_);
|
||||
|
||||
if (this->size())
|
||||
{
|
||||
Info<< "Reading set description:" << nl;
|
||||
forAll(*this, setI)
|
||||
{
|
||||
Info<< " " << operator[](setI).name() << nl;
|
||||
}
|
||||
Info<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (Pstream::master() && debug)
|
||||
{
|
||||
Pout<< "sample fields:" << fieldSelection_ << nl
|
||||
<< "sample sets:" << nl << "(" << nl;
|
||||
|
||||
forAll(*this, setI)
|
||||
{
|
||||
Pout<< " " << operator[](setI) << endl;
|
||||
}
|
||||
Pout<< ")" << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
return performAction(ACTION_ALL);
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledSets::correct()
|
||||
{
|
||||
if (dict_.found("sets"))
|
||||
{
|
||||
searchEngine_.correct();
|
||||
|
||||
PtrList<sampledSet> newList
|
||||
(
|
||||
dict_.lookup("sets"),
|
||||
sampledSet::iNew(mesh_, searchEngine_)
|
||||
);
|
||||
transfer(newList);
|
||||
combineSampledSets(masterSampledSets_, indexSets_);
|
||||
}
|
||||
needsCorrect_ = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2018 OpenCFD Ltd.
|
||||
Copyright (C) 2011 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -29,24 +29,86 @@ Class
|
||||
|
||||
Description
|
||||
Set of sets to sample.
|
||||
Call sampledSets.write() to sample and write files.
|
||||
|
||||
The write() method is used to sample and write files.
|
||||
|
||||
Example of function object specification:
|
||||
|
||||
\verbatim
|
||||
surfaces
|
||||
{
|
||||
type sets;
|
||||
libs (sampling);
|
||||
|
||||
// Write at same frequency as fields
|
||||
writeControl writeTime;
|
||||
writeInterval 1;
|
||||
|
||||
// Fields to be sampled
|
||||
fields (p U);
|
||||
|
||||
// Scheme to obtain values
|
||||
interpolationScheme cellPoint;
|
||||
|
||||
// Output format
|
||||
surfaceFormat vtk;
|
||||
|
||||
formatOptions
|
||||
{
|
||||
vtk
|
||||
{
|
||||
precision 10;
|
||||
}
|
||||
}
|
||||
|
||||
sets
|
||||
{
|
||||
Uref
|
||||
{
|
||||
type cloud;
|
||||
axis xyz;
|
||||
points ((-0.0508 0.0508 0.01));
|
||||
}
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
Entries:
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
type | Type-name: sets | yes |
|
||||
sets | Dictionary or list of sample sets | expected |
|
||||
fields | word/regex list of fields to sample | yes |
|
||||
interpolationScheme | scheme to obtain values | no | cellPoint
|
||||
setFormat | output format | yes |
|
||||
sampleOnExecute | Sample (store) on execution as well | no | false
|
||||
formatOptions | dictionary of format options | no |
|
||||
\endtable
|
||||
|
||||
Additional per-set entries:
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
store | Store surface/fields on registry | no |
|
||||
setFormat | output format | no |
|
||||
formatOptions | dictionary of format options | no |
|
||||
\endtable
|
||||
|
||||
SourceFiles
|
||||
sampledSets.C
|
||||
sampledSetsImpl.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef sampledSets_H
|
||||
#define sampledSets_H
|
||||
#ifndef Foam_sampledSets_H
|
||||
#define Foam_sampledSets_H
|
||||
|
||||
#include "regionFunctionObject.H"
|
||||
#include "fvMeshFunctionObject.H"
|
||||
#include "sampledSet.H"
|
||||
#include "volFieldsFwd.H"
|
||||
#include "meshSearch.H"
|
||||
#include "interpolation.H"
|
||||
#include "coordSet.H"
|
||||
#include "writer.H"
|
||||
#include "wordRes.H"
|
||||
#include "coordSetWriter.H"
|
||||
#include "volFieldsFwd.H"
|
||||
#include "IOobjectList.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -55,9 +117,8 @@ namespace Foam
|
||||
|
||||
// Forward Declarations
|
||||
class Time;
|
||||
class objectRegistry;
|
||||
class dictionary;
|
||||
class fvMesh;
|
||||
class globalIndex;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class sampledSets Declaration
|
||||
@ -65,97 +126,37 @@ class fvMesh;
|
||||
|
||||
class sampledSets
|
||||
:
|
||||
public functionObjects::regionFunctionObject,
|
||||
public functionObjects::fvMeshFunctionObject,
|
||||
public PtrList<sampledSet>
|
||||
{
|
||||
// Private Classes
|
||||
|
||||
//- Class used for grouping field types
|
||||
template<class Type>
|
||||
class fieldGroup
|
||||
:
|
||||
public DynamicList<word>
|
||||
{
|
||||
public:
|
||||
|
||||
//- The set formatter
|
||||
autoPtr<writer<Type>> formatter;
|
||||
|
||||
//- Construct null
|
||||
fieldGroup() = default;
|
||||
|
||||
//- Reset format and field list
|
||||
void clear()
|
||||
{
|
||||
DynamicList<word>::clear();
|
||||
formatter.clear();
|
||||
}
|
||||
|
||||
void setFormatter(const word& writeFormat, const dictionary& dict)
|
||||
{
|
||||
formatter = writer<Type>::New(writeFormat, dict);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- Class used for sampling volFields
|
||||
template<class Type>
|
||||
class volFieldSampler
|
||||
:
|
||||
public List<Field<Type>>
|
||||
{
|
||||
//- Name of this collection of values
|
||||
const word name_;
|
||||
|
||||
public:
|
||||
|
||||
//- Construct interpolating field to the sampleSets
|
||||
volFieldSampler
|
||||
(
|
||||
const word& interpolationScheme,
|
||||
const GeometricField<Type, fvPatchField, volMesh>& field,
|
||||
const PtrList<sampledSet>&
|
||||
);
|
||||
|
||||
//- Construct mapping field to the sampleSets
|
||||
volFieldSampler
|
||||
(
|
||||
const GeometricField<Type, fvPatchField, volMesh>& field,
|
||||
const PtrList<sampledSet>&
|
||||
);
|
||||
|
||||
//- Construct from components
|
||||
volFieldSampler
|
||||
(
|
||||
const List<Field<Type>>& values,
|
||||
const word& name
|
||||
);
|
||||
|
||||
//- Return the field name
|
||||
const word& name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Static Data Members
|
||||
|
||||
//- Output verbosity
|
||||
static bool verbose_;
|
||||
|
||||
//- Local control for sampling actions
|
||||
enum sampleActionType : unsigned
|
||||
{
|
||||
ACTION_NONE = 0,
|
||||
ACTION_WRITE = 0x1,
|
||||
ACTION_STORE = 0x2,
|
||||
ACTION_ALL = 0xF
|
||||
};
|
||||
|
||||
// Private Data
|
||||
|
||||
//- Const reference to fvMesh
|
||||
const fvMesh& mesh_;
|
||||
|
||||
//- Keep the dictionary to recreate sets for moving mesh cases
|
||||
dictionary dict_;
|
||||
|
||||
//- Load fields from files (not from objectRegistry)
|
||||
bool loadFromFiles_;
|
||||
|
||||
//- Output verbosity
|
||||
bool verbose_;
|
||||
|
||||
//- Perform sample/store actions on execute as well
|
||||
bool onExecute_;
|
||||
|
||||
//- Correct meshSearch and update sets
|
||||
bool needsCorrect_;
|
||||
|
||||
//- Output path
|
||||
fileName outputPath_;
|
||||
|
||||
@ -168,8 +169,8 @@ class sampledSets
|
||||
//- Names of fields to sample
|
||||
wordRes fieldSelection_;
|
||||
|
||||
//- Interpolation scheme to use
|
||||
word interpolationScheme_;
|
||||
//- Interpolation/sample scheme to obtain values at the points
|
||||
word samplePointScheme_;
|
||||
|
||||
//- Output format to use
|
||||
word writeFormat_;
|
||||
@ -178,61 +179,76 @@ class sampledSets
|
||||
dictionary writeFormatOptions_;
|
||||
|
||||
|
||||
// Categorized scalar/vector/tensor fields
|
||||
// Output control
|
||||
|
||||
fieldGroup<scalar> scalarFields_;
|
||||
fieldGroup<vector> vectorFields_;
|
||||
fieldGroup<sphericalTensor> sphericalTensorFields_;
|
||||
fieldGroup<symmTensor> symmTensorFields_;
|
||||
fieldGroup<tensor> tensorFields_;
|
||||
//- The coordSet writers (one per sampled set)
|
||||
PtrList<coordSetWriter> writers_;
|
||||
|
||||
//- Current list of field names selected for sampling
|
||||
DynamicList<word> selectedFieldNames_;
|
||||
|
||||
|
||||
// Merging structures
|
||||
// Merging
|
||||
|
||||
PtrList<coordSet> masterSampledSets_;
|
||||
labelListList indexSets_;
|
||||
//- Gathered coordSet. (Content only meaningful on master)
|
||||
PtrList<coordSet> gatheredSets_;
|
||||
|
||||
//- Indexed sort order for gathered coordSet.
|
||||
// (Content only meaningful on master)
|
||||
List<labelList> gatheredSorting_;
|
||||
|
||||
//- The globalIndex for gathering. (Content only meaningful on master)
|
||||
List<globalIndex> globalIndices_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Clear old field groups
|
||||
void clearFieldGroups();
|
||||
|
||||
//- Classify field types, returns the number of fields
|
||||
label classifyFields();
|
||||
|
||||
//- Combine points from all processors. Sort by curveDist and produce
|
||||
//- index list. Valid result only on master processor.
|
||||
void combineSampledSets
|
||||
//- A new coordSet writer, with per-set formatOptions
|
||||
static autoPtr<coordSetWriter> newWriter
|
||||
(
|
||||
PtrList<coordSet>& masterSampledSets,
|
||||
labelListList& indexSets
|
||||
word writeType,
|
||||
const dictionary& formatOptions,
|
||||
const dictionary& surfDict
|
||||
);
|
||||
|
||||
//- Combine values from all processors.
|
||||
// Valid result only on master processor.
|
||||
template<class T>
|
||||
void combineSampledValues
|
||||
(
|
||||
const PtrList<volFieldSampler<T>>& sampledFields,
|
||||
const labelListList& indexSets,
|
||||
PtrList<volFieldSampler<T>>& masterFields
|
||||
);
|
||||
//- Perform sampling action with store/write
|
||||
bool performAction(unsigned request);
|
||||
|
||||
//- Write set on master, return fileName
|
||||
//- Count selected/sampled fields
|
||||
// Returns empty IOobjectList if loadFromFiles_ is not active
|
||||
//
|
||||
// Adjusts selectedFieldNames_
|
||||
IOobjectList preCheckFields();
|
||||
|
||||
//- Setup the sets (optional writers)
|
||||
void initDict(const dictionary& dict, const bool initial);
|
||||
|
||||
//- Combine points from all processors.
|
||||
//- Sort by curve distance and produce index list.
|
||||
//- Valid result only on master processor.
|
||||
void gatherAllSets();
|
||||
|
||||
//- Write sampled fieldName on coordSet and on outputDir path
|
||||
template<class Type>
|
||||
fileName writeSampleFile
|
||||
void writeCoordSet
|
||||
(
|
||||
const coordSet& masterSampleSet,
|
||||
const PtrList<volFieldSampler<Type>>& masterFields,
|
||||
const label setI,
|
||||
const fileName& timeDir,
|
||||
const writer<Type>& formatter
|
||||
coordSetWriter& writer,
|
||||
const Field<Type>& values,
|
||||
const word& fieldName
|
||||
);
|
||||
|
||||
template<class Type>
|
||||
void sampleAndWrite(fieldGroup<Type>& fields);
|
||||
//- Get from registry or load from disk
|
||||
template<class GeoField>
|
||||
tmp<GeoField> getOrLoadField(const word& fieldName) const;
|
||||
|
||||
//- Sample and store/write a specific volume field
|
||||
template<class Type>
|
||||
void performAction(const VolumeField<Type>& field, unsigned request);
|
||||
|
||||
//- Sample and write all applicable sampled fields
|
||||
// Only uses IOobjectList when loadFromFiles_ is active
|
||||
template<class GeoField>
|
||||
void performAction(const IOobjectList& objects, unsigned request);
|
||||
|
||||
//- No copy construct
|
||||
sampledSets(const sampledSets&) = delete;
|
||||
@ -253,7 +269,7 @@ public:
|
||||
sampledSets
|
||||
(
|
||||
const word& name,
|
||||
const Time& time,
|
||||
const Time& runTime,
|
||||
const dictionary& dict
|
||||
);
|
||||
|
||||
@ -262,8 +278,8 @@ public:
|
||||
sampledSets
|
||||
(
|
||||
const word& name,
|
||||
const objectRegistry&,
|
||||
const dictionary&,
|
||||
const objectRegistry& obr,
|
||||
const dictionary& dict,
|
||||
const bool loadFromFiles = false
|
||||
);
|
||||
|
||||
@ -276,7 +292,7 @@ public:
|
||||
|
||||
//- Enable/disable verbose output
|
||||
// \return old value
|
||||
bool verbose(const bool on);
|
||||
bool verbose(const bool on) noexcept;
|
||||
|
||||
//- Read the sampledSets
|
||||
virtual bool read(const dictionary&);
|
||||
@ -307,12 +323,6 @@ public:
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#ifdef NoRepository
|
||||
#include "sampledSetsTemplates.C"
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -1,129 +0,0 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2017 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 "sampledSets.H"
|
||||
#include "volFields.H"
|
||||
#include "IOobjectList.H"
|
||||
#include "UIndirectList.H"
|
||||
#include "ListOps.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
void Foam::sampledSets::clearFieldGroups()
|
||||
{
|
||||
scalarFields_.clear();
|
||||
vectorFields_.clear();
|
||||
sphericalTensorFields_.clear();
|
||||
symmTensorFields_.clear();
|
||||
tensorFields_.clear();
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::sampledSets::classifyFields()
|
||||
{
|
||||
label nFields = 0;
|
||||
clearFieldGroups();
|
||||
|
||||
wordList allFields; // Just needed for warnings
|
||||
HashTable<wordHashSet> available;
|
||||
|
||||
if (loadFromFiles_)
|
||||
{
|
||||
// Check files for a particular time
|
||||
IOobjectList objects(mesh_, mesh_.time().timeName());
|
||||
|
||||
allFields = objects.names();
|
||||
available = objects.classes(fieldSelection_);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check currently available fields
|
||||
allFields = mesh_.names();
|
||||
available = mesh_.classes(fieldSelection_);
|
||||
}
|
||||
|
||||
DynamicList<label> missed(fieldSelection_.size());
|
||||
|
||||
// Detect missing fields
|
||||
forAll(fieldSelection_, i)
|
||||
{
|
||||
if (!ListOps::found(allFields, fieldSelection_[i]))
|
||||
{
|
||||
missed.append(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (missed.size())
|
||||
{
|
||||
WarningInFunction
|
||||
<< nl
|
||||
<< "Cannot find "
|
||||
<< (loadFromFiles_ ? "field file" : "registered field")
|
||||
<< " matching "
|
||||
<< UIndirectList<wordRe>(fieldSelection_, missed) << endl;
|
||||
}
|
||||
|
||||
forAllConstIters(available, iter)
|
||||
{
|
||||
const word& fieldType = iter.key();
|
||||
const wordList fieldNames = iter.val().sortedToc();
|
||||
|
||||
const label count = fieldNames.size(); // pre-filtered, so non-empty
|
||||
|
||||
if (fieldType == volScalarField::typeName)
|
||||
{
|
||||
scalarFields_.append(fieldNames);
|
||||
nFields += count;
|
||||
}
|
||||
else if (fieldType == volVectorField::typeName)
|
||||
{
|
||||
vectorFields_.append(fieldNames);
|
||||
nFields += count;
|
||||
}
|
||||
else if (fieldType == volSphericalTensorField::typeName)
|
||||
{
|
||||
sphericalTensorFields_.append(fieldNames);
|
||||
nFields += count;
|
||||
}
|
||||
else if (fieldType == volSymmTensorField::typeName)
|
||||
{
|
||||
symmTensorFields_.append(fieldNames);
|
||||
nFields += count;
|
||||
}
|
||||
else if (fieldType == volTensorField::typeName)
|
||||
{
|
||||
tensorFields_.append(fieldNames);
|
||||
nFields += count;
|
||||
}
|
||||
}
|
||||
|
||||
return nFields;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
241
src/sampling/sampledSet/sampledSets/sampledSetsImpl.C
Normal file
241
src/sampling/sampledSet/sampledSets/sampledSetsImpl.C
Normal file
@ -0,0 +1,241 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011 OpenFOAM Foundation
|
||||
Copyright (C) 2015-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 "sampledSets.H"
|
||||
#include "globalIndex.H"
|
||||
#include "interpolation.H"
|
||||
#include "volFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class GeoField>
|
||||
Foam::tmp<GeoField>
|
||||
Foam::sampledSets::getOrLoadField(const word& fieldName) const
|
||||
{
|
||||
tmp<GeoField> tfield;
|
||||
|
||||
if (loadFromFiles_)
|
||||
{
|
||||
tfield.reset
|
||||
(
|
||||
new GeoField
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
fieldName,
|
||||
mesh_.time().timeName(),
|
||||
mesh_,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
mesh_
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slightly paranoid here
|
||||
tfield.cref(mesh_.cfindObject<GeoField>(fieldName));
|
||||
}
|
||||
|
||||
return tfield;
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::sampledSets::writeCoordSet
|
||||
(
|
||||
coordSetWriter& writer,
|
||||
const Field<Type>& values,
|
||||
const word& fieldName
|
||||
)
|
||||
{
|
||||
fileName outputName;
|
||||
if (Pstream::master())
|
||||
{
|
||||
outputName = writer.write(fieldName, values);
|
||||
}
|
||||
Pstream::scatter(outputName);
|
||||
|
||||
if (outputName.size())
|
||||
{
|
||||
// Case-local file name with "<case>" to make relocatable
|
||||
|
||||
dictionary propsDict;
|
||||
propsDict.add
|
||||
(
|
||||
"file",
|
||||
time_.relativePath(outputName, true)
|
||||
);
|
||||
setProperty(fieldName, propsDict);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::sampledSets::performAction
|
||||
(
|
||||
const VolumeField<Type>& fld,
|
||||
unsigned request
|
||||
)
|
||||
{
|
||||
const word& fieldName = fld.name();
|
||||
|
||||
// The interpolator for this field
|
||||
autoPtr<interpolation<Type>> interpPtr;
|
||||
|
||||
if (!samplePointScheme_.empty() && samplePointScheme_ != "cell")
|
||||
{
|
||||
interpPtr.reset(interpolation<Type>::New(samplePointScheme_, fld));
|
||||
}
|
||||
|
||||
forAll(*this, seti)
|
||||
{
|
||||
const sampledSet& s = (*this)[seti];
|
||||
const globalIndex& globIdx = globalIndices_[seti];
|
||||
const labelList& globOrder = gatheredSorting_[seti];
|
||||
|
||||
const word& setName = s.name();
|
||||
Field<Type> values(s.size());
|
||||
|
||||
if (interpPtr)
|
||||
{
|
||||
forAll(s, samplei)
|
||||
{
|
||||
const point& p = s[samplei];
|
||||
const label celli = s.cells()[samplei];
|
||||
const label facei = s.faces()[samplei];
|
||||
|
||||
if (celli == -1 && facei == -1)
|
||||
{
|
||||
// Special condition for illegal sampling points
|
||||
values[samplei] = pTraits<Type>::max;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[samplei] = interpPtr().interpolate(p, celli, facei);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forAll(s, samplei)
|
||||
{
|
||||
const label celli = s.cells()[samplei];
|
||||
|
||||
if (celli == -1)
|
||||
{
|
||||
values[samplei] = pTraits<Type>::max;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[samplei] = fld[celli];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect data from all processors
|
||||
globIdx.gatherInplace(values);
|
||||
|
||||
// Some values only available on master
|
||||
Type avgValue, minValue, maxValue;
|
||||
label sizeValue;
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
avgValue = average(values);
|
||||
minValue = min(values);
|
||||
maxValue = max(values);
|
||||
sizeValue = values.size();
|
||||
|
||||
// Use sorted order
|
||||
values = UIndirectList<Type>(values, globOrder)();
|
||||
}
|
||||
Pstream::scatter(avgValue);
|
||||
Pstream::scatter(minValue);
|
||||
Pstream::scatter(maxValue);
|
||||
Pstream::scatter(sizeValue);
|
||||
|
||||
// Store results: min/max/average/size with the name of the set
|
||||
// for scoping.
|
||||
// Eg, average(lines,T) ...
|
||||
const word resultArg('(' + setName + ',' + fieldName + ')');
|
||||
|
||||
this->setResult("average" + resultArg, avgValue);
|
||||
this->setResult("min" + resultArg, minValue);
|
||||
this->setResult("max" + resultArg, maxValue);
|
||||
this->setResult("size" + resultArg, sizeValue);
|
||||
|
||||
if (verbose_)
|
||||
{
|
||||
Info<< name() << ' ' << setName << " : " << fieldName << nl
|
||||
<< " avg: " << avgValue << nl
|
||||
<< " min: " << minValue << nl
|
||||
<< " max: " << maxValue << nl << nl;
|
||||
}
|
||||
|
||||
if (request & ACTION_WRITE)
|
||||
{
|
||||
writeCoordSet<Type>(writers_[seti], values, fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class GeoField>
|
||||
void Foam::sampledSets::performAction
|
||||
(
|
||||
const IOobjectList& objects,
|
||||
unsigned request
|
||||
)
|
||||
{
|
||||
wordList fieldNames;
|
||||
if (loadFromFiles_)
|
||||
{
|
||||
fieldNames = objects.sortedNames<GeoField>(fieldSelection_);
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldNames = mesh_.thisDb().sortedNames<GeoField>(fieldSelection_);
|
||||
}
|
||||
|
||||
for (const word& fieldName : fieldNames)
|
||||
{
|
||||
tmp<GeoField> tfield = getOrLoadField<GeoField>(fieldName);
|
||||
|
||||
if (tfield)
|
||||
{
|
||||
performAction<typename GeoField::value_type>(tfield(), request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -1,376 +0,0 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2021 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 "sampledSets.H"
|
||||
#include "volFields.H"
|
||||
#include "globalIndex.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
Foam::sampledSets::volFieldSampler<Type>::volFieldSampler
|
||||
(
|
||||
const word& interpolationScheme,
|
||||
const GeometricField<Type, fvPatchField, volMesh>& field,
|
||||
const PtrList<sampledSet>& samplers
|
||||
)
|
||||
:
|
||||
List<Field<Type>>(samplers.size()),
|
||||
name_(field.name())
|
||||
{
|
||||
autoPtr<interpolation<Type>> interpolator
|
||||
(
|
||||
interpolation<Type>::New(interpolationScheme, field)
|
||||
);
|
||||
|
||||
forAll(samplers, setI)
|
||||
{
|
||||
Field<Type>& values = this->operator[](setI);
|
||||
const sampledSet& samples = samplers[setI];
|
||||
|
||||
values.setSize(samples.size());
|
||||
forAll(samples, sampleI)
|
||||
{
|
||||
const point& samplePt = samples[sampleI];
|
||||
label celli = samples.cells()[sampleI];
|
||||
label facei = samples.faces()[sampleI];
|
||||
|
||||
if (celli == -1 && facei == -1)
|
||||
{
|
||||
// Special condition for illegal sampling points
|
||||
values[sampleI] = pTraits<Type>::max;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[sampleI] = interpolator().interpolate
|
||||
(
|
||||
samplePt,
|
||||
celli,
|
||||
facei
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::sampledSets::volFieldSampler<Type>::volFieldSampler
|
||||
(
|
||||
const GeometricField<Type, fvPatchField, volMesh>& field,
|
||||
const PtrList<sampledSet>& samplers
|
||||
)
|
||||
:
|
||||
List<Field<Type>>(samplers.size()),
|
||||
name_(field.name())
|
||||
{
|
||||
forAll(samplers, setI)
|
||||
{
|
||||
Field<Type>& values = this->operator[](setI);
|
||||
const sampledSet& samples = samplers[setI];
|
||||
|
||||
values.setSize(samples.size());
|
||||
forAll(samples, sampleI)
|
||||
{
|
||||
label celli = samples.cells()[sampleI];
|
||||
|
||||
if (celli ==-1)
|
||||
{
|
||||
values[sampleI] = pTraits<Type>::max;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[sampleI] = field[celli];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::sampledSets::volFieldSampler<Type>::volFieldSampler
|
||||
(
|
||||
const List<Field<Type>>& values,
|
||||
const word& name
|
||||
)
|
||||
:
|
||||
List<Field<Type>>(values),
|
||||
name_(name)
|
||||
{}
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::fileName Foam::sampledSets::writeSampleFile
|
||||
(
|
||||
const coordSet& masterSampleSet,
|
||||
const PtrList<volFieldSampler<Type>>& masterFields,
|
||||
const label setI,
|
||||
const fileName& timeDir,
|
||||
const writer<Type>& formatter
|
||||
)
|
||||
{
|
||||
wordList valueSetNames(masterFields.size());
|
||||
List<const Field<Type>*> valueSets(masterFields.size());
|
||||
forAll(masterFields, fieldi)
|
||||
{
|
||||
const word& fieldName = masterFields[fieldi].name();
|
||||
|
||||
valueSetNames[fieldi] = fieldName;
|
||||
|
||||
// Values only available on master
|
||||
Type averageValue, minValue, maxValue;
|
||||
label sizeValue;
|
||||
if (Pstream::master())
|
||||
{
|
||||
valueSets[fieldi] = &masterFields[fieldi][setI];
|
||||
averageValue = average(*valueSets[fieldi]);
|
||||
minValue = min(*valueSets[fieldi]);
|
||||
maxValue = max(*valueSets[fieldi]);
|
||||
sizeValue = valueSets[fieldi]->size();
|
||||
}
|
||||
Pstream::scatter(averageValue);
|
||||
Pstream::scatter(minValue);
|
||||
Pstream::scatter(maxValue);
|
||||
Pstream::scatter(sizeValue);
|
||||
|
||||
// Set results
|
||||
|
||||
setResult("average(" + fieldName + ")", averageValue);
|
||||
setResult("min(" + fieldName + ")", minValue);
|
||||
setResult("max(" + fieldName + ")", maxValue);
|
||||
setResult("size(" + fieldName + ")", sizeValue);
|
||||
}
|
||||
|
||||
fileName fName;
|
||||
if (Pstream::master())
|
||||
{
|
||||
fName = timeDir/formatter.getFileName(masterSampleSet, valueSetNames);
|
||||
|
||||
OFstream ofs(fName);
|
||||
if (ofs.opened())
|
||||
{
|
||||
formatter.write
|
||||
(
|
||||
masterSampleSet,
|
||||
valueSetNames,
|
||||
valueSets,
|
||||
ofs
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
WarningInFunction
|
||||
<< "File " << ofs.name() << " could not be opened. "
|
||||
<< "No data will be written" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
Pstream::scatter(fName);
|
||||
|
||||
return fName;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void Foam::sampledSets::combineSampledValues
|
||||
(
|
||||
const PtrList<volFieldSampler<T>>& sampledFields,
|
||||
const labelListList& indexSets,
|
||||
PtrList<volFieldSampler<T>>& masterFields
|
||||
)
|
||||
{
|
||||
forAll(sampledFields, fieldi)
|
||||
{
|
||||
List<Field<T>> masterValues(indexSets.size());
|
||||
|
||||
forAll(indexSets, setI)
|
||||
{
|
||||
// Collect data from all processors
|
||||
|
||||
Field<T> allData;
|
||||
globalIndex::gatherOp(sampledFields[fieldi][setI], allData);
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
masterValues[setI] = UIndirectList<T>
|
||||
(
|
||||
allData,
|
||||
indexSets[setI]
|
||||
)();
|
||||
}
|
||||
}
|
||||
|
||||
masterFields.set
|
||||
(
|
||||
fieldi,
|
||||
new volFieldSampler<T>
|
||||
(
|
||||
masterValues,
|
||||
sampledFields[fieldi].name()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::sampledSets::sampleAndWrite(fieldGroup<Type>& fields)
|
||||
{
|
||||
if (fields.size())
|
||||
{
|
||||
const bool interpolate = interpolationScheme_ != "cell";
|
||||
|
||||
// Create or use existing writer
|
||||
if (!fields.formatter)
|
||||
{
|
||||
fields.setFormatter(writeFormat_, writeFormatOptions_);
|
||||
}
|
||||
|
||||
// Storage for interpolated values
|
||||
PtrList<volFieldSampler<Type>> sampledFields(fields.size());
|
||||
|
||||
forAll(fields, fieldi)
|
||||
{
|
||||
if (Pstream::master() && verbose_)
|
||||
{
|
||||
Pout<< "sampledSets::sampleAndWrite: "
|
||||
<< fields[fieldi] << endl;
|
||||
}
|
||||
|
||||
if (loadFromFiles_)
|
||||
{
|
||||
GeometricField<Type, fvPatchField, volMesh> vf
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
fields[fieldi],
|
||||
mesh_.time().timeName(),
|
||||
mesh_,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
mesh_
|
||||
);
|
||||
|
||||
if (interpolate)
|
||||
{
|
||||
sampledFields.set
|
||||
(
|
||||
fieldi,
|
||||
new volFieldSampler<Type>
|
||||
(
|
||||
interpolationScheme_,
|
||||
vf,
|
||||
*this
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
sampledFields.set
|
||||
(
|
||||
fieldi,
|
||||
new volFieldSampler<Type>(vf, *this)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (interpolate)
|
||||
{
|
||||
sampledFields.set
|
||||
(
|
||||
fieldi,
|
||||
new volFieldSampler<Type>
|
||||
(
|
||||
interpolationScheme_,
|
||||
mesh_.lookupObject
|
||||
<GeometricField<Type, fvPatchField, volMesh>>
|
||||
(fields[fieldi]),
|
||||
*this
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
sampledFields.set
|
||||
(
|
||||
fieldi,
|
||||
new volFieldSampler<Type>
|
||||
(
|
||||
mesh_.lookupObject
|
||||
<GeometricField<Type, fvPatchField, volMesh>>
|
||||
(fields[fieldi]),
|
||||
*this
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combine sampled fields from processors.
|
||||
// Note: only master results are valid
|
||||
|
||||
PtrList<volFieldSampler<Type>> masterFields(sampledFields.size());
|
||||
combineSampledValues(sampledFields, indexSets_, masterFields);
|
||||
|
||||
forAll(masterSampledSets_, setI)
|
||||
{
|
||||
fileName sampleFile = writeSampleFile
|
||||
(
|
||||
masterSampledSets_[setI],
|
||||
masterFields,
|
||||
setI,
|
||||
outputPath_/mesh_.time().timeName(),
|
||||
fields.formatter()
|
||||
);
|
||||
|
||||
if (sampleFile.size())
|
||||
{
|
||||
// Case-local file name with "<case>" to make relocatable
|
||||
|
||||
forAll(masterFields, fieldi)
|
||||
{
|
||||
dictionary propsDict;
|
||||
propsDict.add
|
||||
(
|
||||
"file",
|
||||
time_.relativePath(sampleFile, true)
|
||||
);
|
||||
|
||||
const word& fieldName = masterFields[fieldi].name();
|
||||
setProperty(fieldName, propsDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -940,7 +940,7 @@ void Foam::shortestPathSet::genSamples
|
||||
// Get the target point
|
||||
const label outsideCelli = mesh.findCell(outsidePoint);
|
||||
|
||||
// Maintain overall track length. Used to make curveDist continuous.
|
||||
// Maintain overall track length. Used to make curve distance continuous.
|
||||
scalar trackLength = 0;
|
||||
|
||||
List<topoDistanceData<label>> allFaceInfo(mesh.nFaces());
|
||||
|
||||
Reference in New Issue
Block a user