46 namespace functionObjects
59 { modeType::mdFaceZone ,
"faceZone" },
60 { modeType::mdFaceZoneAndDirection,
"faceZoneAndDirection" },
61 { modeType::mdCellZoneAndDirection,
"cellZoneAndDirection" },
62 { modeType::mdSurface,
"functionObjectSurface" },
63 { modeType::mdSurface,
"surface" },
64 { modeType::mdSurfaceAndDirection,
"surfaceAndDirection" },
97 <<
"Unsupported flux field " << fieldName <<
" with dimensions " 99 <<
". Expected either mass flow or volumetric flow rate." 108 const word& surfName,
120 <<
"Unable to find surface " << surfName
121 <<
". Valid surfaces: " 134 const word& surfName,
147 <<
"Unable to find surface " << surfName
148 <<
". Valid surfaces: " 153 const auto&
s = *surfptr;
154 const vector refDir = dir/(
mag(dir) + ROOTVSMALL);
166 const vector&
n =
s.faceNormals()[i];
168 if ((
n & refDir) > tolerance_)
182 const word& faceZoneName,
183 DynamicList<word>&
names,
184 DynamicList<vector>& directions,
185 DynamicList<labelList>& faceID,
186 DynamicList<labelList>& facePatchID,
187 DynamicList<boolList>& faceFlip
190 label zonei = mesh_.faceZones().findZoneID(faceZoneName);
194 <<
"Unable to find faceZone " << faceZoneName
196 << mesh_.faceZones().sortedNames() <<
nl 199 const faceZone& fZone = mesh_.faceZones()[zonei];
202 directions.append(
Zero);
213 const label meshFacei = fZone[i];
214 const bool isFlip = fZone.flipMap()[i];
218 label facePatchId = -1;
221 if (!mesh_.isInternalFace(meshFacei))
223 facePatchId = mesh_.boundaryMesh().whichPatch(meshFacei);
224 const polyPatch&
pp = mesh_.boundaryMesh()[facePatchId];
226 if (isA<emptyPolyPatch>(
pp))
231 const auto* cpp = isA<coupledPolyPatch>(
pp);
233 if (cpp && !cpp->owner())
244 faceIds[numFaces] =
faceId;
245 facePatchIds[numFaces] = facePatchId;
246 faceFlips[numFaces] = isFlip;
253 faceIds.resize(numFaces);
254 facePatchIds.resize(numFaces);
255 faceFlips.resize(numFaces);
257 faceID.append(std::move(faceIds));
258 facePatchID.append(std::move(facePatchIds));
259 faceFlip.append(std::move(faceFlips));
265 const word& faceZoneName,
274 const vector refDir = dir/(
mag(dir) + ROOTVSMALL);
276 label zonei = mesh_.faceZones().findZoneID(faceZoneName);
280 <<
"Unable to find faceZone " << faceZoneName
282 << mesh_.faceZones().sortedNames() <<
nl 285 const faceZone& fZone = mesh_.faceZones()[zonei];
304 const label meshFacei = fZone[i];
308 label facePatchId = -1;
311 if (!mesh_.isInternalFace(meshFacei))
313 facePatchId = mesh_.boundaryMesh().whichPatch(meshFacei);
314 const polyPatch&
pp = mesh_.boundaryMesh()[facePatchId];
316 if (isA<emptyPolyPatch>(
pp))
321 const auto* cpp = isA<coupledPolyPatch>(
pp);
323 if (cpp && !cpp->owner())
334 if (facePatchId != -1)
336 n = Sf.boundaryField()[facePatchId][
faceId]
344 if ((
n & refDir) > tolerance_)
346 faceFlips[numFaces] =
false;
350 faceFlips[numFaces] =
true;
353 faceIds[numFaces] =
faceId;
354 facePatchIds[numFaces] = facePatchId;
361 faceIds.resize(numFaces);
362 facePatchIds.resize(numFaces);
363 faceFlips.resize(numFaces);
366 facePatchID.
append(std::move(facePatchIds));
367 faceFlip.
append(std::move(faceFlips));
373 const word& cellZoneName,
382 const vector refDir = dir/(
mag(dir) + ROOTVSMALL);
384 const label cellZonei = mesh_.cellZones().findZoneID(cellZoneName);
388 <<
"Unable to find cellZone " << cellZoneName
390 << mesh_.cellZones().sortedNames() <<
nl 394 const label nInternalFaces = mesh_.nInternalFaces();
400 labelList nbrFaceCellAddr(mesh_.nBoundaryFaces(), -1);
410 label facei =
pp.start() + i;
411 label nbrFacei = facei - nInternalFaces;
412 label own = mesh_.faceOwner()[facei];
413 nbrFaceCellAddr[nbrFacei] = cellAddr[own];
422 DynamicList<label> faceIDs(floor(0.1*mesh_.nFaces()));
423 DynamicList<label> facePatchIDs(faceIDs.size());
424 DynamicList<label> faceLocalPatchIDs(faceIDs.size());
425 DynamicList<bool> flips(faceIDs.size());
428 for (label facei = 0; facei < nInternalFaces; facei++)
430 const label own = cellAddr[mesh_.faceOwner()[facei]];
431 const label nbr = cellAddr[mesh_.faceNeighbour()[facei]];
433 if (((own != -1) && (nbr == -1)) || ((own == -1) && (nbr != -1)))
435 vector n = mesh_.faces()[facei].unitNormal(mesh_.points());
437 if ((
n & refDir) > tolerance_)
439 faceIDs.append(facei);
440 faceLocalPatchIDs.append(facei);
441 facePatchIDs.append(-1);
444 else if ((
n & -refDir) > tolerance_)
446 faceIDs.append(facei);
447 faceLocalPatchIDs.append(facei);
448 facePatchIDs.append(-1);
457 const polyPatch&
pp =
pbm[patchi];
461 const label facei =
pp.start() + localFacei;
462 const label own = cellAddr[mesh_.faceOwner()[facei]];
463 const label nbr = nbrFaceCellAddr[facei - nInternalFaces];
465 if ((own != -1) && (nbr == -1))
467 vector n = mesh_.faces()[facei].unitNormal(mesh_.points());
469 if ((
n & refDir) > tolerance_)
471 faceIDs.append(facei);
472 faceLocalPatchIDs.append(localFacei);
473 facePatchIDs.append(patchi);
476 else if ((
n & -refDir) > tolerance_)
478 faceIDs.append(facei);
479 faceLocalPatchIDs.append(localFacei);
480 facePatchIDs.append(patchi);
490 IndirectList<face>(mesh_.faces(), faceIDs),
496 OBJstream
os(mesh_.time().path()/
"patch.obj");
498 os.write(faces, mesh_.points(),
false);
503 List<edgeTopoDistanceData<label>> allEdgeInfo(
patch.nEdges());
504 List<edgeTopoDistanceData<label>> allFaceInfo(
patch.size());
509 <<
"initialiseCellZoneAndDirection: " 510 <<
"Starting walk to split patch into faceZones" 513 const globalIndex globalFaces(
patch.size());
519 bool dummyData{
false};
523 DynamicList<label> changedEdges;
524 DynamicList<edgeTopoDistanceData<label>> changedInfo;
527 for (; oldFaceID <
patch.size(); oldFaceID++)
529 if (!allFaceInfo[oldFaceID].valid<bool>(dummyData))
531 seedFacei = globalFaces.toGlobal(oldFaceID);
535 reduce(seedFacei, minOp<label>());
542 if (globalFaces.isLocal(seedFacei))
544 const label localFacei = globalFaces.toLocal(seedFacei);
547 for (
const label edgei : fEdges)
549 if (allEdgeInfo[edgei].valid<bool>(dummyData))
552 <<
"Problem in edge face wave: attempted to assign a " 553 <<
"value to an edge that has already been visited. " 554 <<
"Edge info: " << allEdgeInfo[edgei]
558 changedEdges.append(edgei);
561 edgeTopoDistanceData<label>
574 edgeTopoDistanceData<label>
589 forAll(allFaceInfo, facei)
591 if (allFaceInfo[facei].data() == regioni)
597 Info<<
"*** region:" << regioni
606 const label nRegion = regioni;
613 <<
"Region split failed" <<
nl 618 List<DynamicList<label>> regionFaceIDs(nRegion);
619 List<DynamicList<label>> regionFacePatchIDs(nRegion);
620 List<DynamicList<bool>> regionFaceFlips(nRegion);
622 forAll(allFaceInfo, facei)
624 regioni = allFaceInfo[facei].data();
626 regionFaceIDs[regioni].append(faceLocalPatchIDs[facei]);
627 regionFacePatchIDs[regioni].append(facePatchIDs[facei]);
628 regionFaceFlips[regioni].append(flips[facei]);
632 forAll(regionFaceIDs, regioni)
634 const word zoneName = cellZoneName +
":faceZone" +
Foam::name(regioni);
636 directions.
append(refDir);
637 faceID.
append(regionFaceIDs[regioni]);
638 facePatchID.
append(regionFacePatchIDs[regioni]);
639 faceFlip.
append(regionFaceFlips[regioni]);
644 OBJstream
os(mesh_.time().path()/zoneName +
".obj");
645 faceList faces(mesh_.faces(), regionFaceIDs[regioni]);
646 os.write(faces, mesh_.points(),
false);
653 <<
" Created " << faceID.
size()
654 <<
" separate face zones from cell zone " << cellZoneName <<
nl;
658 label nFaces =
returnReduce(faceID[i].size(), sumOp<label>());
660 << nFaces <<
" faces" <<
nl;
678 storedObjects().lookupObject<
polySurface>(zoneNames_[idx]);
680 sumMagSf =
sum(
s.magSf());
687 const labelList& facePatchIDs = facePatchID_[idx];
691 label facei = faceIDs[i];
693 if (facePatchIDs[i] == -1)
695 sumMagSf += magSf[facei];
699 label patchi = facePatchIDs[i];
700 sumMagSf += magSf.boundaryField()[patchi][facei];
711 for (
const word& surfName : zoneNames_)
713 const polySurface&
s =
714 storedObjects().lookupObject<polySurface>(surfName);
719 << checkFlowType(
phi.dimensions(),
phi.name()) <<
" write:" <<
nl;
725 const polySurface&
s =
726 storedObjects().lookupObject<polySurface>(zoneNames_[surfi]);
730 checkFlowType(
phi.dimensions(),
phi.name());
732 const boolList& flips = faceFlip_[surfi];
737 tmp<scalarField> tphis =
phi &
s.Sf();
742 scalar phif =
phis[i];
758 reduce(phiPos, sumOp<scalar>());
759 reduce(phiNeg, sumOp<scalar>());
761 phiPos *= scaleFactor_;
762 phiNeg *= scaleFactor_;
764 scalar netFlux = phiPos + phiNeg;
765 scalar absoluteFlux = phiPos - phiNeg;
767 Log <<
" surface " << zoneNames_[surfi] <<
':' <<
nl 768 <<
" positive : " << phiPos <<
nl 769 <<
" negative : " << phiNeg <<
nl 770 <<
" net : " << netFlux <<
nl 771 <<
" absolute : " << absoluteFlux
824 case mdFaceZoneAndDirection:
828 initialiseFaceZoneAndDirection
831 zoneDirections_[zonei],
841 case mdCellZoneAndDirection:
845 initialiseCellZoneAndDirection
848 zoneDirections_[zonei],
872 case mdSurfaceAndDirection:
876 initialiseSurfaceAndDirection
879 zoneDirections_[zonei],
891 zoneNames_.transfer(faceZoneName);
892 faceID_.transfer(faceID);
893 facePatchID_.transfer(facePatchID);
894 faceFlip_.transfer(faceFlips);
899 List<scalar> areas(zoneNames_.size());
902 const word& zoneName = zoneNames_[zonei];
903 areas[zonei] = totalArea(zonei);
907 Info<<
" Surface: " << zoneName
908 <<
", area: " << areas[zonei] <<
nl;
912 Info<<
" Zone: " << zoneName
913 <<
", area: " << areas[zonei] <<
nl;
920 filePtrs_.resize(zoneNames_.size());
924 const word& zoneName = zoneNames_[zonei];
925 filePtrs_.set(zonei, newFileAtStartTime(zoneName));
938 needsUpdate_ =
false;
979 mode_ = modeTypeNames_.get(
"mode",
dict);
980 phiName_ =
dict.getOrDefault<
word>(
"phi",
"phi");
981 scaleFactor_ =
dict.getOrDefault<scalar>(
"scaleFactor", 1);
982 tolerance_ =
dict.getOrDefault<scalar>(
"tolerance", 0.8);
985 zoneDirections_.clear();
993 dict.readEntry(
"faceZones", zoneNames_);
996 case mdFaceZoneAndDirection:
998 dict.readEntry(
"faceZoneAndDirection", nameAndDirection);
1001 case mdCellZoneAndDirection:
1003 dict.readEntry(
"cellZoneAndDirection", nameAndDirection);
1008 dict.readEntry(
"surfaces", zoneNames_);
1011 case mdSurfaceAndDirection:
1013 dict.readEntry(
"surfaceAndDirection", nameAndDirection);
1019 <<
"unhandled enumeration " << modeTypeNames_[mode_]
1026 if (nameAndDirection.
size())
1028 zoneNames_.resize(nameAndDirection.
size());
1029 zoneDirections_.resize(nameAndDirection.
size());
1033 for (
const Tuple2<word, vector>& nameDirn : nameAndDirection)
1035 zoneNames_[zonei] = nameDirn.first();
1036 zoneDirections_[zonei] = nameDirn.second();
1040 nameAndDirection.clear();
1045 << modeTypeNames_[mode_] <<
") with selection:\n " 1048 return !zoneNames_.empty();
1054 const word& zoneName,
1061 if (isSurfaceMode())
1063 writeHeaderValue(
os,
"Surface", zoneName);
1067 writeHeaderValue(
os,
"Face zone", zoneName);
1069 writeHeaderValue(
os,
"Total area",
area);
1073 case mdFaceZoneAndDirection:
1074 case mdCellZoneAndDirection:
1075 case mdSurfaceAndDirection:
1077 writeHeaderValue(
os,
"Reference direction", refDir);
1084 writeHeaderValue(
os,
"Scale factor", scaleFactor_);
1086 writeCommented(
os,
"Time");
1087 os <<
tab <<
"positive" 1090 <<
tab <<
"absolute" 1105 if (isSurfaceMode())
1107 return surfaceModeWrite();
1113 << checkFlowType(
phi.dimensions(),
phi.name()) <<
" write:" <<
nl;
1115 forAll(zoneNames_, zonei)
1117 const labelList& faceID = faceID_[zonei];
1118 const labelList& facePatchID = facePatchID_[zonei];
1119 const boolList& faceFlips = faceFlip_[zonei];
1127 label facei = faceID[i];
1128 label patchi = facePatchID[i];
1132 phif =
phi.boundaryField()[patchi][facei];
1154 reduce(phiPos, sumOp<scalar>());
1155 reduce(phiNeg, sumOp<scalar>());
1157 phiPos *= scaleFactor_;
1158 phiNeg *= scaleFactor_;
1160 scalar netFlux = phiPos + phiNeg;
1161 scalar absoluteFlux = phiPos - phiNeg;
1163 Log <<
" faceZone " << zoneNames_[zonei] <<
':' <<
nl 1164 <<
" positive : " << phiPos <<
nl 1165 <<
" negative : " << phiNeg <<
nl 1166 <<
" net : " << netFlux <<
nl 1167 <<
" absolute : " << absoluteFlux
A surface mesh consisting of general polygon faces and capable of holding fields. ...
const polyBoundaryMesh & pbm
modeType mode_
Mode for face determination/to generate faces to test.
void size(const label n)
Older name for setAddressableSize.
defineTypeNameAndDebug(ObukhovLength, 0)
virtual bool write()
Write the fluxSummary.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1)
List< word > names(const UPtrList< T > &list, const UnaryMatchPredicate &matcher)
List of names generated by calling name() for each list item and filtered for matches.
static void writeHeader(Ostream &os, const word &fieldName)
dimensionedScalar log(const dimensionedScalar &ds)
errorManipArg< error, int > exit(error &err, const int errNo=1)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
scalar totalArea(const label idx) const
Calculate the total area for the surface or derived faceZone.
virtual bool read(const dictionary &dict)
Read the field fluxSummary data.
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
void append(const T &val)
Append an element at the end of the list.
constexpr char nl
The newline '\n' character (0x0a)
Fields (face and point) for polySurface.
Set of directions for each cell in the mesh. Either uniform and size=1 or one set of directions per c...
UIndirectList< label > labelUIndList
UIndirectList of labels.
fluxSummary(const word &name, const Time &runTime, const dictionary &dict)
Construct from Time and dictionary.
Ostream & endl(Ostream &os)
Add newline and flush stream.
bool update()
Initialise - after read(), before write()
constexpr char tab
The tab '\t' character(0x09)
void initialiseCellZoneAndDirection(const word &cellZoneName, const vector &refDir, DynamicList< word > &names, DynamicList< vector > &dir, DynamicList< labelList > &faceID, DynamicList< labelList > &facePatchID, DynamicList< boolList > &faceFlip) const
Initialise face set from cell zone and direction.
const Type * cfindObject(const word &name, const bool recursive=false) const
Return const pointer to the object of the given Type.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Macros for easy insertion into run-time selection tables.
bool read(const char *buf, int32_t &val)
Same as readInt32.
#define forAll(list, i)
Loop across all elements in list.
A surface with prescribed direction.
List< face > faceList
List of faces.
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
const dimensionSet dimVolume(pow3(dimLength))
Dimension set for the base types, which can be used to implement rigorous dimension checking for alge...
void setSize(const label n)
Alias for resize()
bool surfaceModeWrite()
Specialized write for surfaces.
void initialiseFaceZoneAndDirection(const word &faceZoneName, const vector &refDir, DynamicList< word > &names, DynamicList< vector > &dir, DynamicList< labelList > &faceID, DynamicList< labelList > &facePatchID, DynamicList< boolList > &faceFlip) const
Initialise face set from face zone and direction.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
bool isSurfaceMode() const
Check if surface mode instead of zone mode.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
const wordList area
Standard area field types (scalar, vector, tensor, etc)
A class for handling words, derived from Foam::string.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
static const word null
An empty word.
Foam::DimensionedField< vector, polySurfaceGeoMesh > polySurfaceVectorField
void append(const T &val)
Copy append an element to the end of this list.
errorManip< error > abort(error &err)
#define DebugInfo
Report an information message using Foam::Info.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
virtual bool execute()
Execute, currently does nothing.
edgeScalarField phis(IOobject("phis", runTime.timeName(), aMesh.thisDb(), IOobject::NO_READ, IOobject::NO_WRITE), linearEdgeInterpolate(Us) &aMesh.Le())
An Ostream is an abstract base class for all output systems (streams, files, token lists...
static const Enum< modeType > modeTypeNames_
Face mode names.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
virtual bool read(const dictionary &dict)
Read.
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
const std::string patch
OpenFOAM patch number as a std::string.
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
virtual void writeFileHeader(const word &zoneName, const scalar area, const vector &refDir, Ostream &os) const
Output file header information.
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool read(const dictionary &dict)
Read optional controls.
fileName search(const word &file, const fileName &directory)
Recursively search the given directory for the file.
Specialization of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
A subset of mesh faces organised as a primitive patch.
void initialiseSurface(const word &surfName, DynamicList< word > &names, DynamicList< vector > &dir, DynamicList< boolList > &faceFlip) const
Initialise for given surface name.
const dimensionSet dimMass(1, 0, 0, 0, 0, 0, 0)
List< label > labelList
A List of labels.
void initialiseFaceZone(const word &faceZoneName, DynamicList< word > &names, DynamicList< vector > &dir, DynamicList< labelList > &faceID, DynamicList< labelList > &facePatchID, DynamicList< boolList > &faceFlip) const
Initialise face set from face zone.
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
A patch is a list of labels that address the faces in the global face list.
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Base class for writing single files from the function objects.
word checkFlowType(const dimensionSet &fieldDims, const word &fieldName) const
Check flowType (mass or volume)
List< bool > boolList
A List of bools.
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
A functionObject surface.
const dimensionSet dimArea(sqr(dimLength))
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
void initialiseSurfaceAndDirection(const word &surfName, const vector &refDir, DynamicList< word > &names, DynamicList< vector > &dir, DynamicList< boolList > &faceFlip) const
Initialise for given surface name and direction.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
static constexpr const zero Zero
Global zero (0)