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);
160 boolList& flips = faceFlip[faceFlip.size()-1];
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);
204 DynamicList<label> faceIDs(fZone.size());
205 DynamicList<label> facePatchIDs(fZone.size());
206 DynamicList<bool> flips(fZone.size());
210 label facei = fZone[i];
211 const bool isFlip = fZone.flipMap()[i];
214 label facePatchID = -1;
215 if (mesh_.isInternalFace(facei))
222 facePatchID = mesh_.boundaryMesh().whichPatch(facei);
223 const polyPatch& pp = mesh_.boundaryMesh()[facePatchID];
224 const auto* cpp = isA<coupledPolyPatch>(pp);
228 faceID = (cpp->owner() ? pp.whichFace(facei) : -1);
230 else if (!isA<emptyPolyPatch>(pp))
232 faceID = pp.whichFace(facei);
245 faceIDs.append(faceID);
246 facePatchIDs.append(facePatchID);
251 faceID.append(faceIDs);
252 facePatchID.append(facePatchIDs);
253 faceFlip.append(flips);
259 const word& faceZoneName,
268 const vector refDir = dir/(
mag(dir) + ROOTVSMALL);
270 label zonei = mesh_.faceZones().findZoneID(faceZoneName);
274 <<
"Unable to find faceZone " << faceZoneName
276 << mesh_.faceZones().sortedNames() <<
nl
279 const faceZone& fZone = mesh_.faceZones()[zonei];
295 label facei = fZone[i];
298 label facePatchID = -1;
299 if (mesh_.isInternalFace(facei))
306 facePatchID = mesh_.boundaryMesh().whichPatch(facei);
307 const polyPatch& pp = mesh_.boundaryMesh()[facePatchID];
308 const auto* cpp = isA<coupledPolyPatch>(pp);
312 faceID = (cpp->owner() ? pp.whichFace(facei) : -1);
314 else if (!isA<emptyPolyPatch>(pp))
316 faceID = pp.whichFace(facei);
328 if (facePatchID != -1)
335 n = Sf[faceID]/(magSf[faceID] + ROOTVSMALL);
338 if ((
n & refDir) > tolerance_)
347 faceIDs.append(faceID);
348 facePatchIDs.append(facePatchID);
353 faceID.append(faceIDs);
354 facePatchID.append(facePatchIDs);
361 const word& cellZoneName,
370 const vector refDir = dir/(
mag(dir) + ROOTVSMALL);
372 const label cellZonei = mesh_.cellZones().findZoneID(cellZoneName);
376 <<
"Unable to find cellZone " << cellZoneName
378 << mesh_.cellZones().sortedNames() <<
nl
382 const label nInternalFaces = mesh_.nInternalFaces();
386 const labelList& cellIDs = mesh_.cellZones()[cellZonei];
388 labelList nbrFaceCellAddr(mesh_.nFaces() - nInternalFaces, -1);
398 label facei = pp.
start() + i;
399 label nbrFacei = facei - nInternalFaces;
400 label own = mesh_.faceOwner()[facei];
401 nbrFaceCellAddr[nbrFacei] = cellAddr[own];
410 DynamicList<label> faceIDs(floor(0.1*mesh_.nFaces()));
411 DynamicList<label> facePatchIDs(faceIDs.size());
412 DynamicList<label> faceLocalPatchIDs(faceIDs.size());
413 DynamicList<bool> flips(faceIDs.size());
416 for (label facei = 0; facei < nInternalFaces; facei++)
418 const label own = cellAddr[mesh_.faceOwner()[facei]];
419 const label nbr = cellAddr[mesh_.faceNeighbour()[facei]];
421 if (((own != -1) && (nbr == -1)) || ((own == -1) && (nbr != -1)))
423 vector n = mesh_.faces()[facei].unitNormal(mesh_.points());
425 if ((
n & refDir) > tolerance_)
427 faceIDs.append(facei);
428 faceLocalPatchIDs.append(facei);
429 facePatchIDs.append(-1);
432 else if ((
n & -refDir) > tolerance_)
434 faceIDs.append(facei);
435 faceLocalPatchIDs.append(facei);
436 facePatchIDs.append(-1);
445 const polyPatch& pp = pbm[patchi];
449 const label facei = pp.start() + localFacei;
450 const label own = cellAddr[mesh_.faceOwner()[facei]];
451 const label nbr = nbrFaceCellAddr[facei - nInternalFaces];
453 if ((own != -1) && (nbr == -1))
455 vector n = mesh_.faces()[facei].unitNormal(mesh_.points());
457 if ((
n & refDir) > tolerance_)
459 faceIDs.append(facei);
460 faceLocalPatchIDs.append(localFacei);
461 facePatchIDs.append(patchi);
464 else if ((
n & -refDir) > tolerance_)
466 faceIDs.append(facei);
467 faceLocalPatchIDs.append(localFacei);
468 facePatchIDs.append(patchi);
478 IndirectList<face>(mesh_.faces(), faceIDs),
484 OBJstream
os(mesh_.time().path()/
"patch.obj");
486 os.write(faces, mesh_.points(),
false);
491 List<edgeTopoDistanceData<label>> allEdgeInfo(
patch.nEdges());
492 List<edgeTopoDistanceData<label>> allFaceInfo(
patch.size());
497 <<
"initialiseCellZoneAndDirection: "
498 <<
"Starting walk to split patch into faceZones"
501 globalIndex globalFaces(
patch.size());
507 bool dummyData{
false};
511 DynamicList<label> changedEdges;
512 DynamicList<edgeTopoDistanceData<label>> changedInfo;
515 for (; oldFaceID <
patch.size(); oldFaceID++)
517 if (!allFaceInfo[oldFaceID].valid<bool>(dummyData))
519 seedFacei = globalFaces.toGlobal(oldFaceID);
523 reduce(seedFacei, minOp<label>());
530 if (globalFaces.isLocal(seedFacei))
532 const label localFacei = globalFaces.toLocal(seedFacei);
535 for (
const label edgei : fEdges)
537 if (allEdgeInfo[edgei].valid<bool>(dummyData))
540 <<
"Problem in edge face wave: attempted to assign a "
541 <<
"value to an edge that has already been visited. "
542 <<
"Edge info: " << allEdgeInfo[edgei]
546 changedEdges.append(edgei);
549 edgeTopoDistanceData<label>
562 edgeTopoDistanceData<label>
577 forAll(allFaceInfo, facei)
579 if (allFaceInfo[facei].data() == regioni)
585 Info<<
"*** region:" << regioni
594 const label nRegion = regioni;
601 <<
"Region split failed" <<
nl
606 List<DynamicList<label>> regionFaceIDs(nRegion);
607 List<DynamicList<label>> regionFacePatchIDs(nRegion);
608 List<DynamicList<bool>> regionFaceFlips(nRegion);
610 forAll(allFaceInfo, facei)
612 regioni = allFaceInfo[facei].data();
614 regionFaceIDs[regioni].append(faceLocalPatchIDs[facei]);
615 regionFacePatchIDs[regioni].append(facePatchIDs[facei]);
616 regionFaceFlips[regioni].append(flips[facei]);
620 forAll(regionFaceIDs, regioni)
622 const word zoneName = cellZoneName +
":faceZone" +
Foam::name(regioni);
624 directions.
append(refDir);
625 faceID.
append(regionFaceIDs[regioni]);
626 facePatchID.
append(regionFacePatchIDs[regioni]);
627 faceFlip.
append(regionFaceFlips[regioni]);
632 OBJstream
os(mesh_.time().path()/zoneName +
".obj");
633 faceList faces(mesh_.faces(), regionFaceIDs[regioni]);
634 os.write(faces, mesh_.points(),
false);
641 <<
" Created " << faceID.size()
642 <<
" separate face zones from cell zone " << cellZoneName <<
nl;
646 label nFaces =
returnReduce(faceID[i].size(), sumOp<label>());
648 << nFaces <<
" faces" <<
nl;
666 storedObjects().lookupObject<
polySurface>(zoneNames_[idx]);
668 sumMagSf =
sum(
s.magSf());
675 const labelList& facePatchIDs = facePatchID_[idx];
679 label facei = faceIDs[i];
681 if (facePatchIDs[i] == -1)
683 sumMagSf += magSf[facei];
687 label patchi = facePatchIDs[i];
688 sumMagSf += magSf.boundaryField()[patchi][facei];
699 for (
const word& surfName : zoneNames_)
701 const polySurface&
s =
702 storedObjects().lookupObject<polySurface>(surfName);
707 << checkFlowType(
phi.dimensions(),
phi.name()) <<
" write:" <<
nl;
713 const polySurface&
s =
714 storedObjects().lookupObject<polySurface>(zoneNames_[surfi]);
718 checkFlowType(
phi.dimensions(),
phi.name());
720 const boolList& flips = faceFlip_[surfi];
725 tmp<scalarField> tphis =
phi &
s.Sf();
730 scalar phif =
phis[i];
746 reduce(phiPos, sumOp<scalar>());
747 reduce(phiNeg, sumOp<scalar>());
749 phiPos *= scaleFactor_;
750 phiNeg *= scaleFactor_;
752 scalar netFlux = phiPos + phiNeg;
753 scalar absoluteFlux = phiPos - phiNeg;
755 Log <<
" surface " << zoneNames_[surfi] <<
':' <<
nl
756 <<
" positive : " << phiPos <<
nl
757 <<
" negative : " << phiNeg <<
nl
758 <<
" net : " << netFlux <<
nl
759 <<
" absolute : " << absoluteFlux
812 case mdFaceZoneAndDirection:
816 initialiseFaceZoneAndDirection
819 zoneDirections_[zonei],
829 case mdCellZoneAndDirection:
833 initialiseCellZoneAndDirection
836 zoneDirections_[zonei],
860 case mdSurfaceAndDirection:
864 initialiseSurfaceAndDirection
867 zoneDirections_[zonei],
879 zoneNames_.transfer(faceZoneName);
880 faceID_.transfer(faceID);
881 facePatchID_.transfer(facePatchID);
882 faceFlip_.transfer(faceFlips);
887 List<scalar> areas(zoneNames_.size());
890 const word& zoneName = zoneNames_[zonei];
891 areas[zonei] = totalArea(zonei);
895 Info<<
" Surface: " << zoneName
896 <<
", area: " << areas[zonei] <<
nl;
900 Info<<
" Zone: " << zoneName
901 <<
", area: " << areas[zonei] <<
nl;
908 filePtrs_.resize(zoneNames_.size());
912 const word& zoneName = zoneNames_[zonei];
913 filePtrs_.set(zonei, createFile(zoneName));
926 needsUpdate_ =
false;
967 mode_ = modeTypeNames_.get(
"mode",
dict);
968 phiName_ =
dict.getOrDefault<
word>(
"phi",
"phi");
969 scaleFactor_ =
dict.getOrDefault<scalar>(
"scaleFactor", 1);
970 tolerance_ =
dict.getOrDefault<scalar>(
"tolerance", 0.8);
973 zoneDirections_.clear();
981 dict.readEntry(
"faceZones", zoneNames_);
984 case mdFaceZoneAndDirection:
986 dict.readEntry(
"faceZoneAndDirection", nameAndDirection);
989 case mdCellZoneAndDirection:
991 dict.readEntry(
"cellZoneAndDirection", nameAndDirection);
996 dict.readEntry(
"surfaces", zoneNames_);
999 case mdSurfaceAndDirection:
1001 dict.readEntry(
"surfaceAndDirection", nameAndDirection);
1007 <<
"unhandled enumeration " << modeTypeNames_[mode_]
1014 if (nameAndDirection.size())
1016 zoneNames_.resize(nameAndDirection.size());
1017 zoneDirections_.resize(nameAndDirection.size());
1021 for (
const Tuple2<word, vector>& nameDirn : nameAndDirection)
1023 zoneNames_[zonei] = nameDirn.first();
1024 zoneDirections_[zonei] = nameDirn.second();
1028 nameAndDirection.clear();
1033 << modeTypeNames_[mode_] <<
") with selection:\n "
1036 return !zoneNames_.empty();
1042 const word& zoneName,
1049 if (isSurfaceMode())
1051 writeHeaderValue(
os,
"Surface", zoneName);
1055 writeHeaderValue(
os,
"Face zone", zoneName);
1057 writeHeaderValue(
os,
"Total area",
area);
1061 case mdFaceZoneAndDirection:
1062 case mdCellZoneAndDirection:
1063 case mdSurfaceAndDirection:
1065 writeHeaderValue(
os,
"Reference direction", refDir);
1072 writeHeaderValue(
os,
"Scale factor", scaleFactor_);
1074 writeCommented(
os,
"Time");
1075 os <<
tab <<
"positive"
1078 <<
tab <<
"absolute"
1093 if (isSurfaceMode())
1095 return surfaceModeWrite();
1101 << checkFlowType(
phi.dimensions(),
phi.name()) <<
" write:" <<
nl;
1103 forAll(zoneNames_, zonei)
1105 const labelList& faceID = faceID_[zonei];
1106 const labelList& facePatchID = facePatchID_[zonei];
1107 const boolList& faceFlips = faceFlip_[zonei];
1115 label facei = faceID[i];
1116 label patchi = facePatchID[i];
1120 phif =
phi.boundaryField()[patchi][facei];
1142 reduce(phiPos, sumOp<scalar>());
1143 reduce(phiNeg, sumOp<scalar>());
1145 phiPos *= scaleFactor_;
1146 phiNeg *= scaleFactor_;
1148 scalar netFlux = phiPos + phiNeg;
1149 scalar absoluteFlux = phiPos - phiNeg;
1151 Log <<
" faceZone " << zoneNames_[zonei] <<
':' <<
nl
1152 <<
" positive : " << phiPos <<
nl
1153 <<
" negative : " << phiNeg <<
nl
1154 <<
" net : " << netFlux <<
nl
1155 <<
" absolute : " << absoluteFlux