Merge branch 'feature-function-objects-2206' into 'develop'

New function objects

See merge request Development/openfoam!541
This commit is contained in:
Sergio Ferraris 2022-05-25 23:18:20 +00:00
commit c6d9c0317d
14 changed files with 1134 additions and 140 deletions

View File

@ -20,7 +20,6 @@ fieldValues/fieldValue/fieldValue.C
fieldValues/fieldValue/fieldValueNew.C
fieldValues/volFieldValue/volFieldValue.C
fieldValues/surfaceFieldValue/surfaceFieldValue.C
fieldValues/multiFieldValue/multiFieldValue.C
heatTransferCoeff/heatTransferCoeff.C
heatTransferCoeff/heatTransferCoeffModels/heatTransferCoeffModel/heatTransferCoeffModel.C
@ -31,6 +30,8 @@ heatTransferCoeff/heatTransferCoeffModels/ReynoldsAnalogy/ReynoldsAnalogy.C
limitFields/limitFields.C
multiFieldValue/multiFieldValue.C
nearWallFields/nearWallFields.C
nearWallFields/findCellParticle.C
nearWallFields/findCellParticleCloud.C

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2015-2021 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -63,48 +63,36 @@ Foam::functionObjects::fieldValues::multiFieldValue::operationTypeNames_
void Foam::functionObjects::fieldValues::multiFieldValue::writeFileHeader
(
const wordList& foNames,
const List<wordList>& entries,
const List<wordList>& types,
Ostream& os
) const
{
const wordList& fields0 = functions_[0].fields();
const word groupPrefix("Group");
DynamicList<word> commonFields(fields0.size());
for (const word& fieldName : fields0)
forAll(entries, i)
{
bool common = true;
writeCommented(os, groupPrefix + Foam::name(i));
os << nl;
for (label functioni=1; functioni < functions_.size(); ++functioni)
forAll(entries[i], functioni)
{
if (!functions_[functioni].fields().found(fieldName))
{
common = false;
break;
}
writeCommented
(
os,
" - " + foNames[functioni] + ":" + entries[i][functioni]
);
os << nl;
}
if (common)
{
commonFields.append(fieldName);
}
}
forAll(functions_, functioni)
{
writeHeaderValue
(
os,
"Source" + Foam::name(functioni),
functions_[functioni].name()
);
}
writeHeaderValue(os, "Operation", operationTypeNames_[operation_]);
writeCommented(os, "Time");
for (const word& fieldName : commonFields)
forAll(entries, entryi)
{
os << tab << fieldName;
writeTabbed(os, groupPrefix + Foam::name(entryi));
}
os << endl;
@ -125,10 +113,7 @@ Foam::functionObjects::fieldValues::multiFieldValue::multiFieldValue
operation_(opSubtract),
functions_()
{
if (read(dict))
{
writeFileHeader(file());
}
read(dict);
}
@ -139,52 +124,73 @@ bool Foam::functionObjects::fieldValues::multiFieldValue::read
const dictionary& dict
)
{
if (stateFunctionObject::read(dict) && writeFile::read(dict))
if (!stateFunctionObject::read(dict) || !writeFile::read(dict))
{
const dictionary& functionsDict = dict.subDict("functions");
functions_.resize(functionsDict.size());
if (functions_.empty())
{
WarningInFunction
<< "No functions specified"
<< endl;
return false;
}
label functioni = 0;
for (const entry& dEntry : functionsDict)
{
if (!dEntry.isDict())
{
FatalIOErrorInFunction(dict)
<< "Functions must be specified in dictionary format"
<< exit(FatalIOError);
}
const dictionary& localDict = dEntry.dict();
functions_.set
(
functioni,
fieldValue::New
(
IOobject::scopedName(name(), localDict.dictName()),
time(),
localDict,
false
)
);
++functioni;
}
operation_ = operationTypeNames_.get("operation", dict);
return true;
return false;
}
return false;
operation_ = operationTypeNames_.get("operation", dict);
const dictionary& functionsDict = dict.subDict("functions");
functions_.resize(functionsDict.size());
if (functions_.empty())
{
WarningInFunction
<< "No functions specified"
<< endl;
return false;
}
resultFields_.resize(functions_.size());
label functioni = 0;
for (const entry& dEntry : functionsDict)
{
if (!dEntry.isDict())
{
FatalIOErrorInFunction(dict)
<< "Functions must be specified in dictionary format"
<< exit(FatalIOError);
}
const dictionary& localDict = dEntry.dict();
functions_.set
(
functioni,
functionObject::New
(
IOobject::scopedName(name(), localDict.dictName()),
time(),
localDict
).ptr()
);
// Deactivate logging for child function objects
//functions_[functioni].log = false;
// Get result field names; not specified implies all
resultFields_[functioni] =
localDict.getOrDefault<wordList>("resultFields", wordList());
Info<< type() << ' ' << name() << ':' << nl;
if (resultFields_[functioni].size())
{
Info<< " " << functions_[functioni].name()
<< " " << resultFields_[functioni];
}
else
{
Info<< " " << functions_[functioni].name()
<< " - using all available entries";
}
Info<< nl << endl;
++functioni;
}
return true;
}
@ -201,19 +207,25 @@ bool Foam::functionObjects::fieldValues::multiFieldValue::write()
wordList entries0;
label nEntries = -1;
wordList names(nFunction);
wordList foNames(nFunction);
List<wordList> entries;
List<wordList> types;
forAll(functions_, functioni)
{
auto& f = functions_[functioni];
names[functioni] = f.name();
foNames[functioni] = f.name();
// Note: results are not available until the call to write()
// Note: replicating functionObjectList execute() and write()
// - results may be written on either
f.execute();
f.write();
const wordList e(objectResultEntries(f.name()));
wordList e = resultFields_[functioni];
if (e.empty())
{
e = objectResultEntries(f.name());
}
if (functioni == 0)
{
@ -237,54 +249,72 @@ bool Foam::functionObjects::fieldValues::multiFieldValue::write()
<< "Inconsistent number of result entries" << nl
<< " " << f0Name << " entries:" << entries0 << nl
<< " " << f.name() << " entries:" << e
<< abort(FatalError);
<< exit(FatalError);
}
forAll(e, entryi)
{
entries[entryi][functioni] = e[entryi];
types[entryi][functioni] = objectResultType(f.name(), e[entryi]);
if (types[entryi][functioni] == word::null)
{
FatalErrorInFunction
<< "Unable to find function object result" << nl
<< " function object : " << f.name() << nl
<< " result name : " << e[entryi] << nl
<< " available results : "
<< objectResultEntries(f.name())
<< exit(FatalError);
}
}
}
if (!writtenHeader_)
{
writeFileHeader(foNames, entries, types, file());
writtenHeader_ = true;
}
writeCurrentTime(file());
forAll(entries, entryi)
forAll(entries, i)
{
const wordList& entriesi = entries[entryi];
const word& t0 = types[entryi][0];
const wordList& typesi = types[entryi];
forAll(typesi, functioni)
{
const word& t = typesi[functioni];
const wordList& entryi = entries[i];
const word& expectedType = types[i][0];
const wordList& foTypes = types[i];
if (t != t0)
forAll(foTypes, functioni)
{
const word& foType = foTypes[functioni];
if (foType != expectedType)
{
FatalErrorInFunction
<< "Inconsistent function result types" << nl
<< " " << functions_[0].name()
<< " result type:" << t0 << nl
<< " result type:" << expectedType << nl
<< " " << functions_[functioni].name()
<< " result type:" << typesi[functioni]
<< abort(FatalError);
<< " result type:" << foType
<< exit(FatalError);
}
}
const bool ok
(
applyOperation<scalar>(t0, names, entriesi)
|| applyOperation<vector>(t0, names, entriesi)
|| applyOperation<sphericalTensor>(t0, names, entriesi)
|| applyOperation<symmTensor>(t0, names, entriesi)
|| applyOperation<tensor>(t0, names, entriesi)
applyOperation<scalar>(expectedType, foNames, entryi)
|| applyOperation<vector>(expectedType, foNames, entryi)
|| applyOperation<sphericalTensor>(expectedType, foNames, entryi)
|| applyOperation<symmTensor>(expectedType, foNames, entryi)
|| applyOperation<tensor>(expectedType, foNames, entryi)
);
if (!ok)
{
Log << "Operation not applied between functions:" << nl
<< flatOutput(names, FlatOutput::BareComma{}) << nl
<< flatOutput(foNames, FlatOutput::BareComma{}) << nl
<< "with result names:" << nl
<< flatOutput(entriesi, FlatOutput::BareComma{})
<< flatOutput(entryi, FlatOutput::BareComma{})
<< endl;
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,10 +30,9 @@ Group
grpFieldFunctionObjects
Description
Computes a selected operation between multiple \c fieldValue function
objects.
Computes a selected operation between multiple function objects.
The operation is applied to all results of each \c fieldValue object.
The operation is applied to all results of each object.
Note
Each object must generate the same number and type of results.
@ -43,11 +42,9 @@ Usage
\verbatim
multiFieldValue1
{
// Mandatory entries (unmodifiable)
type multiFieldValue;
libs (fieldFunctionObjects);
// Mandatory entries (runtime modifiable)
// Mandatory entries
type multiFieldValue;
libs (fieldFunctionObjects);
operation average;
// List of fieldValue function objects as dictionaries
@ -56,10 +53,14 @@ Usage
region1
{
...
// Optional
resultFields (field1 field2);
}
region2
{
...
// Optional
resultFields (field1 field2);
}
...
@ -67,41 +68,41 @@ Usage
regionN
{
...
// Optional
resultFields (field1 field2);
}
}
// Optional (inherited) entries
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Req'd | Dflt
type | Type name: multiFieldValue | word | yes | -
libs | Library name: fieldFunctionObjects | word | yes | -
operation | Operation type to apply to values | word | yes | -
functions | List of fieldValue function objects | dict | yes | -
Property | Description | Type | Reqd | Deflt
type | Type name: multiFieldValue | word | yes | -
libs | Library name: fieldFunctionObjects | word | yes | -
operation | Operation type to apply to values | word | yes | -
functions | List of function objects | dict | yes | -
\endtable
Options for the \c operation entry:
\plaintable
add | add
subtract | subtract
min | minimum
max | maximum
average | average
sum | Sum of values
add | Add values (same as sum)
subtract | Subtract values from first entry
min | Minimum value
max | Maximum value
average | Average value
\endplaintable
The \c resultFields entry can be used to set the name of the function object
result fields to process. If omitted, all available values are employed.
The inherited entries are elaborated in:
- \link fieldValue.H \endlink
Usage by the \c postProcess utility is not available.
See also
- Foam::functionObject
- Foam::functionObjects::fieldValue
- ExtendedCodeGuide::functionObjects::field::multiFieldValue
- \link stateFunctionObject.H \endlink
- \link writeFile.H \endlink
SourceFiles
multiFieldValue.C
@ -114,7 +115,6 @@ SourceFiles
#include "stateFunctionObject.H"
#include "writeFile.H"
#include "fieldValue.H"
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -161,8 +161,11 @@ private:
//- Operation to apply to values
operationType operation_;
//- List of fieldValue function objects
PtrList<fieldValue> functions_;
//- List of function objects
PtrList<functionObject> functions_;
//- List of result fields per function object
List<wordList> resultFields_;
// Private Member Functions
@ -183,7 +186,13 @@ protected:
// Protected Member Functions
//- Output file header information
virtual void writeFileHeader(Ostream& os) const;
virtual void writeFileHeader
(
const wordList& foNames,
const List<wordList>& entries,
const List<wordList>& types,
Ostream& os
) const;
public:

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2015-2021 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -34,7 +34,7 @@ template<class Type>
bool Foam::functionObjects::fieldValues::multiFieldValue::applyOperation
(
const word& resultType,
const wordList& names,
const wordList& foNames,
const wordList& entryNames
)
{
@ -45,10 +45,10 @@ bool Foam::functionObjects::fieldValues::multiFieldValue::applyOperation
Type result = Zero;
Field<Type> values(names.size());
Field<Type> values(foNames.size());
forAll(values, i)
{
values[i] = this->getObjectResult<Type>(names[i], entryNames[i]);
values[i] = this->getObjectResult<Type>(foNames[i], entryNames[i]);
}
const word& opName = operationTypeNames_[operation_];

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2018 OpenFOAM Foundation
Copyright (C) 2020-2021 OpenCFD Ltd.
Copyright (C) 2020-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -37,6 +37,7 @@ License
#include "ParticleErosion.H"
#include "ParticleTracks.H"
#include "ParticleTrap.H"
#include "ParticleZoneInfo.H"
#include "PatchCollisionDensity.H"
#include "PatchInteractionFields.H"
#include "PatchPostProcessing.H"
@ -57,6 +58,7 @@ License
makeCloudFunctionObjectType(ParticleErosion, CloudType); \
makeCloudFunctionObjectType(ParticleTracks, CloudType); \
makeCloudFunctionObjectType(ParticleTrap, CloudType); \
makeCloudFunctionObjectType(ParticleZoneInfo, CloudType); \
makeCloudFunctionObjectType(PatchCollisionDensity, CloudType); \
makeCloudFunctionObjectType(PatchInteractionFields, CloudType); \
makeCloudFunctionObjectType(PatchPostProcessing, CloudType); \

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2018 OpenFOAM Foundation
Copyright (C) 2020-2021 OpenCFD Ltd.
Copyright (C) 2020-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -37,6 +37,7 @@ License
#include "ParticleErosion.H"
#include "ParticleTracks.H"
#include "ParticleTrap.H"
#include "ParticleZoneInfo.H"
#include "PatchCollisionDensity.H"
#include "PatchInteractionFields.H"
#include "PatchPostProcessing.H"
@ -60,6 +61,7 @@ License
makeCloudFunctionObjectType(ParticleErosion, CloudType); \
makeCloudFunctionObjectType(ParticleTracks, CloudType); \
makeCloudFunctionObjectType(ParticleTrap, CloudType); \
makeCloudFunctionObjectType(ParticleZoneInfo, CloudType); \
makeCloudFunctionObjectType(PatchCollisionDensity, CloudType); \
makeCloudFunctionObjectType(PatchInteractionFields, CloudType); \
makeCloudFunctionObjectType(PatchPostProcessing, CloudType); \

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -36,6 +36,7 @@ License
#include "ParticleErosion.H"
#include "ParticleTracks.H"
#include "ParticleTrap.H"
#include "ParticleZoneInfo.H"
#include "PatchCollisionDensity.H"
#include "PatchInteractionFields.H"
#include "PatchPostProcessing.H"
@ -58,6 +59,7 @@ License
makeCloudFunctionObjectType(ParticleErosion, CloudType); \
makeCloudFunctionObjectType(ParticleTracks, CloudType); \
makeCloudFunctionObjectType(ParticleTrap, CloudType); \
makeCloudFunctionObjectType(ParticleZoneInfo, CloudType); \
makeCloudFunctionObjectType(PatchCollisionDensity, CloudType); \
makeCloudFunctionObjectType(PatchInteractionFields, CloudType); \
makeCloudFunctionObjectType(PatchPostProcessing, CloudType); \

View File

@ -0,0 +1,458 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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 "ParticleZoneInfo.H"
#include "DynamicField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
struct particleInfoCombineOp
{
void operator()(particleInfo& p1, const particleInfo& p2) const
{
// p2 not set
if (p2.origID == -1)
{
return;
}
// p1 not set - initialise with p2
if (p1.origID == -1)
{
p1 = p2;
return;
}
// Set initial values
if (p2.time0 < p1.time0)
{
p1.time0 = p2.time0;
p1.d0 = p2.d0;
p1.mass0 = p2.mass0;
}
// Accumulate age
p1.age += p2.age;
// Set latest available values
if (p2.isOlderThan(p1))
{
p1.position = p2.position;
p1.d = p2.d;
p1.mass = p2.mass;
}
}
};
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type>
Foam::Field<Type> getData
(
const Foam::UList<Foam::particleInfo>& data,
Type Foam::particleInfo::* field
)
{
Field<Type> result(data.size());
forAll(data, i)
{
result[i] = data[i].*field;
}
return result;
}
template<class Type>
Foam::Field<Type> getParData
(
const Foam::List<Foam::List<Foam::particleInfo>>& parData,
Type Foam::particleInfo::* field
)
{
DynamicField<Type> result;
for (const auto& particles : parData)
{
for (const auto& p : particles)
{
if (p.origID != -1)
{
result.append(p.*field);
}
}
}
return std::move(result);
}
template<class CloudType>
void Foam::ParticleZoneInfo<CloudType>::writeWriter
(
const DynamicList<particleInfo>& data
)
{
coordSet coords
(
"zoneParticles",
"xyz",
getData(data_, &particleInfo::position),
scalarList(data.size(), Zero)
);
writerPtr_->open(coords, this->baseTimeDir() / "zoneParticles");
writerPtr_->beginTime(this->owner().time());
#undef writeLocal
#define writeLocal(field) \
writerPtr_->write(#field, getData(data, &particleInfo::field));
writeLocal(origID);
writeLocal(origProc);
writeLocal(time0);
writeLocal(age);
writeLocal(d0);
writeLocal(d);
writeLocal(mass0);
writeLocal(mass);
#undef writeLocal
writerPtr_->endTime();
writerPtr_->close();
}
template<class CloudType>
void Foam::ParticleZoneInfo<CloudType>::writeWriter
(
const List<List<particleInfo>>& procData
)
{
vectorField points(getParData(procData, &particleInfo::position));
coordSet coords
(
"zoneParticles",
"xyz",
std::move(points),
scalarList(points.size(), Zero)
);
writerPtr_->open(coords, this->baseTimeDir() / "zoneParticles");
writerPtr_->beginTime(this->owner().time());
#undef writeLocal
#define writeLocal(field) \
writerPtr_->write(#field, getParData(procData, &particleInfo::field));
writeLocal(origID);
writeLocal(origProc);
writeLocal(time0);
writeLocal(age);
writeLocal(d0);
writeLocal(d);
writeLocal(mass0);
writeLocal(mass);
#undef writeLocal
writerPtr_->endTime();
writerPtr_->close();
}
template<class CloudType>
void Foam::ParticleZoneInfo<CloudType>::writeFileHeader(Ostream& os) const
{
this->writeHeaderValue(os, "cellZone", cellZoneName_);
this->writeHeaderValue(os, "time", this->owner().time().timeOutputValue());
this->writeHeader(os, "");
this->writeCommented(os, "origID");
os << tab << "origProc"
<< tab << "(x y z)"
<< tab << "time0"
<< tab << "age"
<< tab << "d0"
<< tab << "d"
<< tab << "mass0"
<< tab << "mass"
<< endl;
}
template<class CloudType>
bool Foam::ParticleZoneInfo<CloudType>::inZone(const label celli) const
{
return this->owner().mesh().cellZones()[cellZoneId_].whichCell(celli) != -1;
}
template<class CloudType>
Foam::label Foam::ParticleZoneInfo<CloudType>::getParticleID
(
const particleInfo& p
) const
{
forAll(data_, i)
{
const auto& d = data_[i];
if ((d.origProc == p.origProc) && (d.origID == p.origID))
{
return i;
}
}
return -1;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CloudType>
Foam::ParticleZoneInfo<CloudType>::ParticleZoneInfo
(
const dictionary& dict,
CloudType& owner,
const word& modelName
)
:
CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
functionObjects::writeFile
(
owner,
this->localPath(),
typeName,
this->coeffDict()
),
cellZoneName_(this->coeffDict().getWord("cellZone")),
cellZoneId_(-1),
data_(),
movedParticles_(),
maxIDs_(Pstream::nProcs(), Zero),
writerPtr_
(
Pstream::master()
? coordSetWriter::New
(
this->coeffDict().getWord("writer"),
this->coeffDict().subOrEmptyDict("formatOptions")
)
: nullptr
)
{
const auto& cellZones = owner.mesh().cellZones();
cellZoneId_ = cellZones.findZoneID(cellZoneName_);
if (cellZoneId_ == -1)
{
FatalIOErrorInFunction(this->coeffDict())
<< "Unable to find cellZone " << cellZoneName_
<< ". Available cellZones are:" << cellZones.names()
<< exit(FatalIOError);
}
Info<< " Processing cellZone" << cellZoneName_ << " with id "
<< cellZoneId_ << endl;
}
template<class CloudType>
Foam::ParticleZoneInfo<CloudType>::ParticleZoneInfo
(
const ParticleZoneInfo<CloudType>& pzi
)
:
CloudFunctionObject<CloudType>(pzi),
writeFile(pzi),
cellZoneName_(pzi.cellZoneName_),
cellZoneId_(pzi.cellZoneId_),
data_(pzi.data_),
movedParticles_(pzi.movedParticles_),
maxIDs_(Pstream::nProcs()),
writerPtr_(nullptr)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CloudType>
void Foam::ParticleZoneInfo<CloudType>::preEvolve
(
const typename parcelType::trackingData& td
)
{}
template<class CloudType>
void Foam::ParticleZoneInfo<CloudType>::postEvolve
(
const typename parcelType::trackingData& td
)
{
Info<< this->type() << ":" << nl
<< " Cell zone = " << cellZoneName_ << nl
<< " Contributions = "
<< returnReduce(movedParticles_.size(), sumOp<label>())
<< endl;
if (!this->writeTime())
{
Info<< endl;
}
for (const auto& p : movedParticles_)
{
const label id = getParticleID(p);
if (id == -1)
{
// New particle
data_.append(p);
maxIDs_[p.origProc] = max(maxIDs_[p.origProc], p.origID);
}
else
{
// Add to existing particle
data_[id] += p;
}
}
movedParticles_.clear();
// Calls write
CloudFunctionObject<CloudType>::postEvolve(td);
}
template<class CloudType>
void Foam::ParticleZoneInfo<CloudType>::postMove
(
parcelType& p,
const scalar dt,
const point&,
bool&
)
{
if (inZone(p.cell()))
{
particleInfo newData;
newData.origID = p.origId();
newData.origProc = p.origProc();
newData.position = p.position();
newData.time0 = this->owner().time().value() + dt;
newData.age = dt;
newData.d0 = p.d();
newData.d = p.d();
newData.mass0 = p.mass();
newData.mass = newData.mass0;
movedParticles_.append(newData);
}
}
template<class CloudType>
void Foam::ParticleZoneInfo<CloudType>::write()
{
autoPtr<OFstream> osPtr =
this->createFile("particles", this->owner().time().timeOutputValue());
if (Pstream::parRun())
{
// Find number of particles per proc
labelList allMaxIDs(maxIDs_);
Pstream::listCombineGather(allMaxIDs, maxEqOp<label>());
Pstream::scatterList(allMaxIDs);
List<List<particleInfo>> procParticles(Pstream::nProcs());
forAll(procParticles, proci)
{
procParticles[proci].resize(allMaxIDs[proci] + 1);
}
// Insert into bins for accumulation
for (const auto& d : data_)
{
procParticles[d.origProc][d.origID] = d;
}
for (auto& particles : procParticles)
{
Pstream::listCombineGather(particles, particleInfoCombineOp());
}
if (Pstream::master())
{
writeWriter(procParticles);
auto& os = osPtr();
writeFileHeader(os);
label nData = 0;
for (const auto& particles : procParticles)
{
for (const auto& p : particles)
{
if (p.origID != -1)
{
os << p << endl;
++nData;
}
}
}
Info<< " Number of particles = " << nData << nl
<< " Written data to " << os.name() << endl;
}
}
else
{
writeWriter(data_);
auto& os = osPtr();
writeFileHeader(os);
for (const auto& p : data_)
{
os << p << nl;
}
Info<< " Number of particles = " << data_.size() << nl
<< " Written data to " << os.name() << endl;
}
Info<< endl;
}
// ************************************************************************* //

View File

@ -0,0 +1,334 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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/>.
Class
Foam::ParticleZoneInfo
Group
grpLagrangianIntermediateFunctionObjects
Description
Reports cloud information for particles passing through a specified cell
zone.
Usage
Example usage:
\verbatim
cloudFunctions
{
particleZoneInfo1
{
// Mandatory entries
type particleZoneInfo;
cellZone leftFluid;
// Optional entries
writer vtk;
}
}
\endverbatim
Results are written to file:
- \<case\>/postProcessing/lagrangian/\<cloudName\>/\<functionName\>/\<time\>
\verbatim
# cellZone : leftFluid
# time : 1.0000000000e+00
#
# origID origProc (x y z) time0 age d0 d mass0 mass
\endverbatim
Where
- origID : particle ID
- origProc : processor ID
- (x y z) : Cartesian co-ordinates
- time0 : time particle enters the cellZone
- age : time spent in the cellZone
- d0 : diameter on entry to the cellZone
- d : current diameter
- mass0 : mass on entry to the cellZone
- mass : current mass
If the optional \c writer entry is supplied, cloud data is written in the
specified format.
During the run, output statistics are reported after the cloud solution,
e.g.:
\verbatim
particleZoneInfo:
Cell zone = leftFluid
Contributions = 257
\endverbatim
Here, 'Contributions' refers to the number of incremental particle-move
contributions recorded during this time step. At write times, the output
is extended, e.g.:
\verbatim
particleZoneInfo:
Cell zone = leftFluid
Contributions = 822
Number of particles = 199
Written data to "postProcessing/lagrangian/reactingCloud1/
\endverbatim
SourceFiles
ParticleZoneInfo.C
\*---------------------------------------------------------------------------*/
#ifndef ParticleZoneInfo_H
#define ParticleZoneInfo_H
#include "CloudFunctionObject.H"
#include "writeFile.H"
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
struct particleInfo Declaration
\*---------------------------------------------------------------------------*/
struct particleInfo
{
label origID = -1;
label origProc = -1;
vector position = Zero;
scalar time0 = 0;
scalar age = 0;
scalar d0 = 0;
scalar d = 0;
scalar mass0 = 0;
scalar mass = 0;
void operator+=(const particleInfo& p)
{
// Increment age
age += p.age;
// Set current values
position = p.position;
d = p.d;
mass = p.mass;
}
scalar isOlderThan(const particleInfo& p) const
{
// Cannot just use time0 - particle may leave/re-enter and
// so age is decoupled
return (p.time0 + p.age) < (time0 + age);
}
friend bool operator==(const particleInfo& a, const particleInfo& b)
{
return
a.origID == b.origID
&& a.origProc == b.origProc
&& a.position == b.position
&& a.time0 == b.time0
&& a.age == b.age
&& a.d0 == b.d0
&& a.d == b.d
&& a.mass0 == b.mass0
&& a.mass == b.mass;
}
friend bool operator!=(const particleInfo& a, const particleInfo& b)
{
return !(a == b);
}
// IOstream Operators
friend Istream& operator>>(Istream& is, particleInfo& pi)
{
is >> pi.origID
>> pi.origProc
>> pi.position
>> pi.time0
>> pi.age
>> pi.d0
>> pi.d
>> pi.mass0
>> pi.mass;
return is;
}
friend Ostream& operator<<(Ostream& os, const particleInfo& pi)
{
os << pi.origID
<< " " << pi.origProc
<< " " << pi.position
<< " " << pi.time0
<< " " << pi.age
<< " " << pi.d0
<< " " << pi.d
<< " " << pi.mass0
<< " " << pi.mass;
return os;
}
};
/*---------------------------------------------------------------------------*\
Class ParticleZoneInfo Declaration
\*---------------------------------------------------------------------------*/
template<class CloudType>
class ParticleZoneInfo
:
public CloudFunctionObject<CloudType>,
public functionObjects::writeFile
{
// Private Data
// Typedefs
//- Convenience typedef for parcel type
typedef typename CloudType::parcelType parcelType;
//- Cell zone name
word cellZoneName_;
//- Cell zone index
label cellZoneId_;
//- Stored data
DynamicList<particleInfo> data_;
//- Work storage
DynamicList<particleInfo> movedParticles_;
//- Maximum particle ID per processor
labelList maxIDs_;
//- Set writer
autoPtr<coordSetWriter> writerPtr_;
// Private Member Functions
//- Write output file header
void writeFileHeader(Ostream& os) const;
//- Return true if celli is in the cellZone
bool inZone(const label celli) const;
//- Return the index of the particle in the storage (data_)
//- Returns -1 if not found
label getParticleID(const particleInfo& p) const;
//- Write fields using writerPtr_ for serial runs
void writeWriter(const DynamicList<particleInfo>& data);
//- Write fields using writerPtr_ for parallel runs
void writeWriter(const List<List<particleInfo>>& procData);
public:
//- Runtime type information
TypeName("particleZoneInfo");
// Constructors
//- Construct from dictionary
ParticleZoneInfo
(
const dictionary& dict,
CloudType& owner,
const word& modelName
);
//- Construct copy
ParticleZoneInfo(const ParticleZoneInfo<CloudType>& pe);
//- Construct and return a clone
virtual autoPtr<CloudFunctionObject<CloudType>> clone() const
{
return autoPtr<CloudFunctionObject<CloudType>>
(
new ParticleZoneInfo<CloudType>(*this)
);
}
//- Destructor
virtual ~ParticleZoneInfo() = default;
// Member Functions
//- Pre-evolve hook
virtual void preEvolve
(
const typename parcelType::trackingData& td
);
//- Post-evolve hook
virtual void postEvolve
(
const typename parcelType::trackingData& td
);
//- Post-move hook
virtual void postMove
(
parcelType& p,
const scalar dt,
const point& position0,
bool& keepParticle
);
//- Write
virtual void write();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ParticleZoneInfo.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,4 +5,6 @@ cd "${0%/*}" || exit # Run from this directory
cleanCase0
rm -rf procs.old
#------------------------------------------------------------------------------

View File

@ -13,4 +13,21 @@ runParallel topoSet
runParallel $(getApplication)
runApplication reconstructPar
latestTime=$(foamListTimes -latestTime)
mv -f "$latestTime" "$latestTime".bak
mkdir procs.old
mv -f processor* procs.old
runParallel -s "decompose" redistributePar -decompose -time 9.5
runParallel -s 2 $(getApplication)
runParallel -s "reconstruct" redistributePar -reconstruct -latestTime
#------------------------------------------------------------------------------

View File

@ -0,0 +1,129 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2112 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
sampleEpsilon1
{
type sets;
libs (sampling);
interpolationScheme cellPointFace;
setFormat raw;
fields ( epsilon );
sets
(
cloud
{
type cloud;
axis xyz;
points
(
(0.0025 0.05 0.005)
);
}
);
}
multiFieldValue_add
{
// Mandatory entries
type multiFieldValue;
libs (fieldFunctionObjects);
operation add;
functions
{
movingWallEpsilon
{
type surfaceFieldValue;
operation areaAverage;
regionType patch;
name movingWall;
fields (epsilon);
writeFields no;
writeToFile no;
log no;
resultFields (areaAverage(movingWall,epsilon));
}
fixedWallsEpsilon
{
type surfaceFieldValue;
operation areaAverage;
regionType patch;
name fixedWalls;
fields (epsilon);
writeFields no;
writeToFile no;
log yes;
}
averageEpsilon
{
type valueAverage;
functionObject sampleEpsilon1;
fields (average(epsilon));
writeToFile no;
log no;
}
}
// Inherited entries
writePrecision 10;
writeToFile true;
useUserTime true;
region region0;
enabled true;
log true;
timeStart 0;
timeEnd 1000;
executeControl timeStep;
executeInterval 1;
writeControl writeTime;
writeInterval -1;
}
multiFieldValue_sum
{
${multiFieldValue_add}
operation sum;
}
multiFieldValue_subtract
{
${multiFieldValue_add}
operation subtract;
}
multiFieldValue_min
{
${multiFieldValue_add}
operation min;
}
multiFieldValue_max
{
${multiFieldValue_add}
operation max;
}
multiFieldValue_average
{
${multiFieldValue_add}
operation average;
}
// ************************************************************************* //

View File

@ -16,7 +16,7 @@ FoamFile
application pisoFoam;
startFrom startTime;
startFrom latestTime;
startTime 0;
@ -68,6 +68,7 @@ functions
#include "FOlog"
#include "FOmag"
#include "FOmagSqr"
#include "FOmultiFieldValue"
#include "FOmultiply"
#include "FOmomentum"
#include "FOnearWallFields"

View File

@ -160,6 +160,13 @@ subModels
cloudFunctions
{
particleZoneInfo1
{
type particleZoneInfo;
cellZone leftFluid;
writer vtk;
}
patchParticleHistogram1
{
type patchParticleHistogram;