holeToFace.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2020-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "holeToFace.H"
29 #include "transform.H"
30 #include "faceSet.H"
31 #include "cellSet.H"
33 #include "OBJstream.H"
34 //#include "fvMesh.H"
35 //#include "volFields.H"
36 //#include "surfaceFields.H"
37 #include "topoDistanceData.H"
38 #include "FaceCellWave.H"
39 #include "syncTools.H"
40 
41 #include "edgeTopoDistanceData.H"
42 #include "PatchEdgeFaceWave.H"
43 #include "indirectPrimitivePatch.H"
44 
45 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
46 
47 namespace Foam
48 {
49  defineTypeNameAndDebug(holeToFace, 0);
50  addToRunTimeSelectionTable(topoSetSource, holeToFace, word);
51  addToRunTimeSelectionTable(topoSetSource, holeToFace, istream);
52  addToRunTimeSelectionTable(topoSetFaceSource, holeToFace, word);
53  addToRunTimeSelectionTable(topoSetFaceSource, holeToFace, istream);
55  (
56  topoSetFaceSource,
57  holeToFace,
58  word,
59  hole
60  );
62  (
63  topoSetFaceSource,
64  holeToFace,
65  istream,
66  hole
67  );
68 }
69 
70 
71 Foam::topoSetSource::addToUsageTable Foam::holeToFace::usage_
72 (
73  holeToFace::typeName,
74  "\n Usage: holeToFace <faceSet> ((x0 y0 z0) (x1 y1 z1))\n\n"
75  " Select faces disconnecting the individual regions"
76  " (each indicated by a locations).\n"
77 );
78 
79 
80 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
81 
82 //Foam::label Foam::holeToFace::globalCount
83 //(
84 // const bitSet& isMasterFace,
85 // const bitSet& set
86 //)
87 //{
88 // if (set.size() != isMasterFace.size())
89 // {
90 // FatalErrorInFunction << "problem" << exit(FatalError);
91 // }
92 //
93 // label n = 0;
94 // for (const label facei : set)
95 // {
96 // if (isMasterFace(facei))
97 // {
98 // n++;
99 // }
100 // }
101 // return returnReduce(n, sumOp<label>());
102 //}
103 
104 
105 //void Foam::holeToFace::checkFaceSync
106 //(
107 // const string& setName,
108 // const bitSet& set
109 //) const
110 //{
111 // if (set.size() != mesh_.nFaces())
112 // {
113 // FatalErrorInFunction<< "problem" << exit(FatalError);
114 // }
115 // bitSet orSet(set);
116 // syncTools::syncFaceList(mesh_, orSet, orEqOp<unsigned int>());
117 // bitSet andSet(set);
118 // syncTools::syncFaceList(mesh_, andSet, andEqOp<unsigned int>());
119 //
120 // forAll(orSet, facei)
121 // {
122 // if (orSet[facei] != andSet[facei] || orSet[facei] != set[facei])
123 // {
124 // FatalErrorInFunction<< "problem for set " << setName
125 // << "face:" << facei
126 // << " at:" << mesh_.faceCentres()[facei]
127 // << " patch:" << mesh_.boundaryMesh().whichPatch(facei)
128 // << " set:" << set[facei]
129 // << " orSet:" << orSet[facei]
130 // << " andSet:" << andSet[facei]
131 // << exit(FatalError);
132 // }
133 // }
134 //}
135 
136 
137 //void Foam::holeToFace::checkFaceSync
138 //(
139 // const string& fldName,
140 // const labelList& fld
141 //) const
142 //{
143 // if (fld.size() != mesh_.nFaces())
144 // {
145 // FatalErrorInFunction<< "problem" << exit(FatalError);
146 // }
147 // labelList maxFld(fld);
148 // syncTools::syncFaceList(mesh_, maxFld, maxEqOp<label>());
149 // labelList minFld(fld);
150 // syncTools::syncFaceList(mesh_, minFld, minEqOp<label>());
151 //
152 // forAll(maxFld, facei)
153 // {
154 // if (maxFld[facei] != minFld[facei] || maxFld[facei] != fld[facei])
155 // {
156 // FatalErrorInFunction<< "problem for field " << fldName
157 // << "face:" << facei
158 // << " at:" << mesh_.faceCentres()[facei]
159 // << " patch:" << mesh_.boundaryMesh().whichPatch(facei)
160 // << " fld:" << fld[facei]
161 // << " maxFld:" << maxFld[facei]
162 // << " minFld:" << minFld[facei]
163 // << exit(FatalError);
164 // }
165 // }
166 //}
167 
168 
169 //void Foam::holeToFace::checkFaceSync
170 //(
171 // const string& fldName,
172 // const List<unsigned int>& fld
173 //) const
174 //{
175 // if (fld.size() != mesh_.nFaces())
176 // {
177 // FatalErrorInFunction<< "problem" << exit(FatalError);
178 // }
179 // List<unsigned int> orFld(fld);
180 // syncTools::syncFaceList(mesh_, orFld, bitOrEqOp<unsigned int>());
181 // List<unsigned int> andFld(fld);
182 // syncTools::syncFaceList(mesh_, andFld, bitAndEqOp<unsigned int>());
183 // forAll(orFld, facei)
184 // {
185 // if (orFld[facei] != andFld[facei] || orFld[facei] != fld[facei])
186 // {
187 // FatalErrorInFunction<< "problem for field " << fldName
188 // << "face:" << facei
189 // << " at:" << mesh_.faceCentres()[facei]
190 // << " patch:" << mesh_.boundaryMesh().whichPatch(facei)
191 // << " fld:" << fld[facei]
192 // << " orFld:" << orFld[facei]
193 // << " andFld:" << andFld[facei]
194 // << exit(FatalError);
195 // }
196 // }
197 //}
198 
199 
200 //void Foam::holeToFace::writeCellField
201 //(
202 // const word& name,
203 // const labelList& labelFld
204 //) const
205 //{
206 // Pout<< "Writing field " << name << endl;
207 // if (labelFld.size() != mesh_.nCells())
208 // {
209 // FatalErrorInFunction << exit(FatalError);
210 // }
211 //
212 // const fvMesh& fvm = dynamic_cast<const fvMesh&>(mesh_);
213 //
214 // volScalarField fld
215 // (
216 // IOobject
217 // (
218 // name,
219 // fvm.time().timeName(),
220 // fvm,
221 // IOobject::NO_READ,
222 // IOobject::NO_WRITE,
223 // IOobject::NO_REGISTER
224 // ),
225 // fvm,
226 // dimensionedScalar(dimless, Zero)
227 // );
228 // forAll(labelFld, i)
229 // {
230 // fld[i] = labelFld[i];
231 // }
232 // fld.correctBoundaryConditions();
233 // fld.write();
234 //}
235 
236 
237 //void Foam::holeToFace::writeFaceField
238 //(
239 // const word& name,
240 // const labelList& labelFld
241 //) const
242 //{
243 // Pout<< "Writing field " << name << endl;
244 // if (labelFld.size() != mesh_.nFaces())
245 // {
246 // FatalErrorInFunction << exit(FatalError);
247 // }
248 //
249 // const fvMesh& fvm = dynamic_cast<const fvMesh&>(mesh_);
250 //
251 // surfaceScalarField fld
252 // (
253 // IOobject
254 // (
255 // name,
256 // fvm.time().timeName(),
257 // fvm,
258 // IOobject::NO_READ,
259 // IOobject::NO_WRITE,
260 // IOobject::NO_REGISTER
261 // ),
262 // fvm,
263 // dimensionedScalar(dimless, Zero)
264 // );
265 // for (label i = 0; i < mesh_.nInternalFaces(); i++)
266 // {
267 // fld[i] = labelFld[i];
268 // }
269 // surfaceScalarField::Boundary& bfld = fld.boundaryFieldRef();
270 // forAll(bfld, patchi)
271 // {
272 // fvsPatchScalarField& pfld = bfld[patchi];
273 // forAll(pfld, i)
274 // {
275 // pfld[i] = labelFld[pfld.patch().start()+i];
276 // }
277 // }
278 // fld.write();
279 //
280 // // Write as faceSet as well
281 // const bitSet isMasterFace(syncTools::getInternalOrMasterFaces(mesh_));
282 //
283 // faceSet set(mesh_, name, 100);
284 // label nMasters = 0;
285 // forAll(labelFld, facei)
286 // {
287 // if (labelFld[facei] >= 0)
288 // {
289 // set.insert(facei);
290 // if (isMasterFace(facei))
291 // {
292 // nMasters++;
293 // }
294 // }
295 // }
296 // Pout<< "Writing " << returnReduce(nMasters, sumOp<label>())
297 // << " >= 0 faces to faceSet " << set.name() << endl;
298 // set.write();
299 //}
300 
301 
302 void Foam::holeToFace::writeFaces
303 (
304  const word& name,
305  const bitSet& faceFld
306 ) const
307 {
308  mkDir(mesh_.time().timePath());
309  OBJstream str(mesh_.time().timePath()/name);
310  Pout<< "Writing " << faceFld.count() << " faces to " << str.name() << endl;
311 
312  for (const label facei : faceFld)
313  {
314  str.write(mesh_.faces()[facei], mesh_.points(), false);
315  }
316 }
317 
318 
319 void Foam::holeToFace::calculateDistance
320 (
321  const labelList& seedFaces,
322  const bitSet& isBlockedCell,
323  const bitSet& isBlockedFace,
324  labelList& cellDist,
325  labelList& faceDist
326 ) const
327 {
328  if (isBlockedCell.size() != mesh_.nCells())
329  {
330  FatalErrorInFunction << "Problem" << exit(FatalError);
331  }
332  if (isBlockedFace.size() != mesh_.nFaces())
333  {
334  FatalErrorInFunction << "Problem" << exit(FatalError);
335  }
336 
337  //const bitSet isMasterFace(syncTools::getInternalOrMasterFaces(mesh_));
338 
339  // Field on cells and faces.
340  List<topoDistanceData<label>> cellData(mesh_.nCells());
341  List<topoDistanceData<label>> faceData(mesh_.nFaces());
342 
343  // Start of changes
344  List<topoDistanceData<label>> seedData
345  (
346  seedFaces.size(),
347  topoDistanceData<label>(0, 123)
348  );
349  //Pout<< "Seeded "
350  // << globalCount(isMasterFace, bitSet(mesh_.nFaces(), seedFaces))
351  // << " out of " << returnReduce(mesh_.nFaces(), sumOp<label>()) << endl;
352 
353  // Make sure we don't walk through inactive cells
354  //Pout<< "blocking "
355  // << returnReduce(isBlockedCell.count(), sumOp<label>())
356  // << " cells" << endl;
357  for (const label celli : isBlockedCell)
358  {
359  cellData[celli] = topoDistanceData<label>(0, 0);
360  }
361  //Pout<< "blocking "
362  // << globalCount(isMasterFace, isBlockedFace) << " faces" << endl;
363  for (const label facei : isBlockedFace)
364  {
365  faceData[facei] = topoDistanceData<label>(0, 0);
366  }
367 
368  // Propagate information inwards
369  FaceCellWave<topoDistanceData<label>> deltaCalc
370  (
371  mesh_,
372  seedFaces,
373  seedData,
374  faceData,
375  cellData,
376  mesh_.globalData().nTotalCells()+1
377  );
378 
379  // And extract
380  //bool haveWarned = false;
381  forAll(cellData, celli)
382  {
383  if (!isBlockedCell[celli])
384  {
385  if (!cellData[celli].valid(deltaCalc.data()))
386  {
387  //if (!haveWarned)
388  //{
389  // WarningInFunction
390  // << "Did not visit some cells, e.g. cell " << celli
391  // << " at " << mesh_.cellCentres()[celli] << endl;
392  // haveWarned = true;
393  //}
394  }
395  else
396  {
397  cellDist[celli] = cellData[celli].distance();
398  }
399  }
400  }
401 
402  forAll(faceDist, facei)
403  {
404  if (!isBlockedFace[facei])
405  {
406  if (!faceData[facei].valid(deltaCalc.data()))
407  {
408  //if (!haveWarned)
409  //{
410  // WarningInFunction
411  // << "Did not visit some faces, e.g. face " << facei
412  // << " at " << mesh_.faceCentres()[facei] << endl;
413  // haveWarned = true;
414  //}
415  }
416  else
417  {
418  faceDist[facei] = faceData[facei].distance();
419  }
420  }
421  }
422 }
423 
424 
425 Foam::bitSet Foam::holeToFace::frontFaces
426 (
427  const bitSet& isSurfaceFace,
428  const List<unsigned int>& locationFaces,
429  const bitSet& isHoleCell
430 ) const
431 {
432  const labelList& faceOwner = mesh_.faceOwner();
433  const labelList& faceNeighbour = mesh_.faceNeighbour();
434  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
435 
436  bitSet isFrontFace(mesh_.nFaces());
437  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
438  {
439  if (!isSurfaceFace[facei])
440  {
441  const label ownHole = isHoleCell[faceOwner[facei]];
442  const label neiHole = isHoleCell[faceNeighbour[facei]];
443 
444  if (ownHole != neiHole)
445  {
446  unsigned int masks = locationFaces[facei];
447  if (masks == 0u)
448  {
449  FatalErrorInFunction << "face:" << facei
450  << " at:" << mesh_.faceCentres()[facei]
451  << " not any front" << exit(FatalError);
452  }
453 
454  // Count number of bits set
455  const label nSet = BitOps::bit_count(masks);
456 
457  if (nSet == 1)
458  {
459  isFrontFace.set(facei);
460  }
461  }
462  }
463  }
464 
465  // Get neighbouring cell data
466  bitSet isHoleNeiCell(mesh_.nBoundaryFaces());
467  {
468  for (const polyPatch& pp : pbm)
469  {
470  label bFacei = pp.start()-mesh_.nInternalFaces();
471  const labelUList& faceCells = pp.faceCells();
472 
473  for (const label celli : faceCells)
474  {
475  isHoleNeiCell[bFacei] = isHoleCell[celli];
476  ++bFacei;
477  }
478  }
479  syncTools::swapBoundaryFaceList(mesh_, isHoleNeiCell);
480  }
481 
482 
483  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
484  {
485  if (!isSurfaceFace[facei])
486  {
487  const label ownHole = isHoleCell[faceOwner[facei]];
488  const label neiHole = isHoleNeiCell[facei-mesh_.nInternalFaces()];
489 
490  if (ownHole != neiHole)
491  {
492  unsigned int masks = locationFaces[facei];
493  if (masks == 0u)
494  {
495  FatalErrorInFunction << "face:" << facei
496  << " at:" << mesh_.faceCentres()[facei]
497  << " not any front" << exit(FatalError);
498  }
499 
500  // Count number of bits set
501  const label nSet = BitOps::bit_count(masks);
502 
503  if (nSet == 1)
504  {
505  isFrontFace.set(facei);
506  }
507  }
508  }
509  }
510  return isFrontFace;
511 }
512 
513 
514 Foam::bitSet Foam::holeToFace::findClosure
515 (
516  const bitSet& isSurfaceFace, // intersected faces
517  const bitSet& isCandidateHoleCell, // starting blockage
518  const labelListList& locationCells // cells per zone
519 ) const
520 {
521  const labelList& faceOwner = mesh_.faceOwner();
522  const labelList& faceNeighbour = mesh_.faceNeighbour();
523 
524  if (zonePoints_.size() < 2)
525  {
526  FatalErrorInFunction << "single region only : "
527  << flatOutput(zonePoints_) << exit(FatalError);
528  }
529 
530  if (zonePoints_.size() > 31)
531  {
532  FatalErrorInFunction << "only support < 32 locations in mesh."
533  << " Currently : " << flatOutput(zonePoints_) << exit(FatalError);
534  }
535 
536 
537  //const bitSet isMasterFace(syncTools::getInternalOrMasterFaces(mesh_));
538 
539  bitSet isHoleCell(isCandidateHoleCell);
540  for (const labelList& zoneCells : locationCells)
541  {
542  for (const label celli : zoneCells)
543  {
544  if (celli != -1)
545  {
546  isHoleCell.unset(celli);
547  }
548  }
549  }
550 
551  bitSet notHoleCell(isHoleCell);
552  notHoleCell.flip();
553 
554  if (debug)
555  {
556  Pout<< "holeToFace::findClosure :"
557  << " locationCells:" << flatOutput(locationCells) << nl
558  << "holeToFace::findClosure :"
559  << " initial blocked faces:" << isSurfaceFace.count()
560  << " candidate closure cells:" << isHoleCell.count()
561  << endl;
562  }
563 
564  // Distance to surface for every cell/face inside isHoleCell
565  labelList surfaceCellDist(mesh_.nCells(), -1);
566  labelList surfaceNeiCellDist(mesh_.nBoundaryFaces(), -1);
567  labelList surfaceFaceDist(mesh_.nFaces(), -1);
568  {
569  calculateDistance
570  (
571  isSurfaceFace.toc(), // seed faces
572  notHoleCell, // no need to walk through non-hole cells
573  bitSet(mesh_.nFaces()), // no blocked faces
574  surfaceCellDist,
575  surfaceFaceDist
576  );
578  (
579  mesh_,
580  surfaceCellDist,
581  surfaceNeiCellDist
582  );
583  //writeCellField("surfaceCellDistance0", surfaceCellDist);
584  //writeFaceField("surfaceFaceDistance0", surfaceFaceDist);
585  //checkFaceSync("surfaceFaceDistance0", surfaceFaceDist);
586  }
587 
588  if (debug)
589  {
590  Pout<< "holeToFace::findClosure :"
591  << " calculated topological distance to initial blocked faces."
592  << " max distance:" << gMax(surfaceCellDist)
593  << endl;
594  }
595 
596 
597  // Find faces reachable from locationCells. If the locationCell is inside
598  // the blockage it will be only the faces of the cell. If it is outside
599  // it does a full walk to find the reachable faces on the outside of
600  // the blockage.
601  // Note: actual distance itself does not matter - only if they have been
602  // visited.
603  List<unsigned int> locationFaces(mesh_.nFaces(), 0u);
604  forAll(locationCells, zonei)
605  {
606  labelList cellDist(mesh_.nCells(), -1);
607  labelList faceDist(mesh_.nFaces(), -1);
608 
609  labelList seedFaces;
610 
611  const labelList& zoneCells = locationCells[zonei];
612  for (const label celli : zoneCells)
613  {
614  if (celli != -1)
615  {
616  cellDist[celli] = 0;
617  const cell& cFaces = mesh_.cells()[celli];
618  seedFaces.append(cFaces);
619  UIndirectList<label>(faceDist, cFaces) = 0;
620  }
621  }
622 
623  // Extra par sync. Is this needed?
624  {
625  bitSet isSeedFace(mesh_.nFaces(), seedFaces);
627  (
628  mesh_,
629  isSeedFace,
630  orEqOp<unsigned int>()
631  );
632  seedFaces = isSeedFace.toc();
633  }
634 
635 
636  calculateDistance
637  (
638  seedFaces, // seed faces
639  isHoleCell, // do not walk through blocking cells
640  isSurfaceFace, // do not walk through surface
641  cellDist,
642  faceDist
643  );
644  //writeCellField("cellDistance" + Foam::name(zonei), cellDist);
645  //writeFaceField("faceDistance" + Foam::name(zonei), faceDist);
646  //checkFaceSync("faceDistance", faceDist);
647 
648  // Add all reached faces
649  const unsigned int mask = (1u << zonei);
650  forAll(faceDist, facei)
651  {
652  if (faceDist[facei] >= 0)
653  {
654  locationFaces[facei] |= mask;
655  }
656  }
657  }
658 
659  if (debug)
660  {
661  writeFaces("isSurfaceFace.obj", isSurfaceFace);
662  }
663  //if (debug)
664  //{
665  // bitSet isMultiBitFace(mesh_.nFaces());
666  // forAll(locationFaces, facei)
667  // {
668  // const unsigned int bits = locationFaces[facei];
669  // const label nSet = BitOps::bit_count(bits);
670  // if (nSet > 1)
671  // {
672  // isMultiBitFace.set(facei);
673  // }
674  // }
675  // writeFaces("isMultiBitFace.obj", isMultiBitFace);
676  //}
677 
678 
680  //- NOT CORRECT!!! At this point the walking has only done the distance
681  // outside the initial set of blocked faces. We'd have to
682  // walk through all faces before we can determine.
683  //bool haveLeak = false;
684  //forAll(locationFaces, facei)
685  //{
686  // if (!isSurfaceFace[facei])
687  // {
688  // const unsigned int bits = locationFaces[facei];
689  // const label nSet = BitOps::bit_count(bits);
690  // if (nSet > 1)
691  // {
692  // haveLeak = true;
693  //
694  // if (debug)
695  // {
696  // // Collect points
697  // DynamicList<pointField> connected;
698  // forAll(zonePoints_, zonei)
699  // {
700  // if (bits & (1u << zonei))
701  // {
702  // connected.append(zonePoints_[zonei]);
703  // }
704  // }
705  // Pout<< "holeToFace::findClosure :"
706  // << " found initial leak at face "
707  // << mesh_.faceCentres()[facei]
708  // << " between zones " << flatOutput(connected)
709  // << endl;
710  // }
711  // break;
712  // }
713  // }
714  //}
715  //
716  //if (!returnReduceOr(haveLeak))
717  //{
718  // if (debug)
719  // {
720  // Pout<< "holeToFace::findClosure :"
721  // << " did not find leak between zones "
722  // << flatOutput(zonePoints_) << endl;
723  // }
724  // return bitSet(mesh_.nFaces());
725  //}
726 
727 
728  // Front (on outside of hole cell but not connecting multiple locations
729  bitSet isFrontFace(frontFaces(isSurfaceFace, locationFaces, isHoleCell));
730 
731 
732  // Start off eroding the cells furthest away from the surface
733  label surfaceDist = gMax(surfaceCellDist);
734 
735  // Work storage
736  //List<unsigned int> newLocationFaces(mesh_.nFaces());
737  //bitSet newHoleCell(mesh_.nCells());
738 
739  while (surfaceDist >= 0)
740  {
741  // Erode cells with >= surfaceDist:
742  // - unmark cell as blockage (isHoleCell)
743  // - mark faces of cell as visible from inside/outside
744 
745  //newLocationFaces = locationFaces;
746  //newHoleCell = isHoleCell;
747 
748  label nChanged = 0;
749  for (const label facei : isFrontFace)
750  {
751  const label own = faceOwner[facei];
752  if (isHoleCell[own])
753  {
754  const label ownDist = surfaceCellDist[own];
755  if (ownDist >= surfaceDist)
756  {
757  //newHoleCell.unset(own);
758  isHoleCell.unset(own);
759  nChanged++;
760 
761  const cell& cFaces = mesh_.cells()[own];
762  // Set corresponding bits on faces
763  const unsigned int mask = locationFaces[facei];
764  for (const label fi : cFaces)
765  {
766  //newLocationFaces[fi] |= mask;
767  locationFaces[fi] |= mask;
768  }
769  }
770  }
771  else if (mesh_.isInternalFace(facei))
772  {
773  const label nei = faceNeighbour[facei];
774  const label neiDist = surfaceCellDist[nei];
775 
776  if (isHoleCell[nei] && neiDist >= surfaceDist)
777  {
778  //newHoleCell[nei] = false;
779  isHoleCell[nei] = false;
780  nChanged++;
781 
782  const cell& cFaces = mesh_.cells()[nei];
783  // Set corresponding bits on faces
784  const unsigned int mask = locationFaces[facei];
785  for (const label fi : cFaces)
786  {
787  //newLocationFaces[fi] |= mask;
788  locationFaces[fi] |= mask;
789  }
790  }
791  }
792  }
793 
794  reduce(nChanged, sumOp<label>());
795 
796 
797  if (debug)
798  {
799  Pout<< "holeToFace::findClosure :"
800  << " surfaceDist:" << surfaceDist
801  << " front:" << isFrontFace.count()
802  << " nChangedCells:" << nChanged
803  << endl;
804  }
805 
806 
807  if (nChanged == 0)
808  {
809  // Nothing eroded at this level. Erode cells nearer to surface.
810  --surfaceDist;
811  }
812  else
813  {
814  //locationFaces = newLocationFaces;
815  //isHoleCell = newHoleCell;
816 
817  // Sync locationFaces
819  (
820  mesh_,
821  locationFaces,
822  bitOrEqOp<unsigned int>()
823  );
824 
825  // Calculate new front. Never include faces that are both visible
826  // from outside and inside
827  isFrontFace = frontFaces(isSurfaceFace, locationFaces, isHoleCell);
828  }
829  }
830 
831 
832  // Debug: dump all the end fronts
833  //{
834  // forAll(locationCells, zonei)
835  // {
836  // const unsigned int mask = (1u << zonei);
837  //
838  // bitSet isZoneFace(mesh_.nFaces());
839  // forAll(locationFaces, facei)
840  // {
841  // if (locationFaces[facei] & mask)
842  // {
843  // isZoneFace.set(facei);
844  // }
845  // }
846  // writeFaces("isZoneFace"+Foam::name(zonei)+".obj", isZoneFace);
847  // }
848  //}
849 
850 
851 
852  // Find faces that are connected to more than one location
853  bitSet isCommonFace(mesh_.nFaces());
854  forAll(locationFaces, facei)
855  {
856  unsigned int masks = locationFaces[facei];
857  if (masks != 0u)
858  {
859  // Count number of bits set
860  const label nSet = BitOps::bit_count(masks);
861  if (nSet >= 2)
862  {
863  isCommonFace.set(facei);
864  }
865  }
866  }
867 
868  // Remove faces that are on the surface
869  for (const label facei : isCommonFace)
870  {
871  if (surfaceFaceDist[facei] == 0)
872  {
873  isCommonFace.unset(facei);
874  }
875  }
876 
877  if (debug)
878  {
879  Pout<< "holeToFace::findClosure :"
880  << " closure faces:" << isCommonFace.count() << endl;
881  }
882 
883  return isCommonFace;
884 }
885 
886 
887 Foam::bitSet Foam::holeToFace::erodeSet
888 (
889  const bitSet& isSurfaceFace,
890  const bitSet& isSetFace
891 ) const
892 {
893  // Detect cells with lots of faces in the set. WIP. Not parallel consistent.
894 
895  const labelList& faceOwner = mesh_.faceOwner();
896  const labelList& faceNeighbour = mesh_.faceNeighbour();
897 
898  bitSet isSetCell(mesh_.nCells());
899  for (const label facei : isSetFace)
900  {
901  isSetCell.set(faceOwner[facei]);
902  if (mesh_.isInternalFace(facei))
903  {
904  isSetCell.set(faceNeighbour[facei]);
905  }
906  }
907 
908  // Count number of faces per cell. Decide if surface would improve by
909  // moving set
910  bitSet erodedSet(isSetFace);
911  for (const label celli : isSetCell)
912  {
913  const cell& cFaces = mesh_.cells()[celli];
914 
915  label nBlockedFaces = 0;
916  label nSurfaceFaces = 0;
917  for (const label facei : cFaces)
918  {
919  if (erodedSet[facei])
920  {
921  nBlockedFaces++;
922  }
923  else if (isSurfaceFace[facei])
924  {
925  nSurfaceFaces++;
926  }
927  }
928 
929  if ((nSurfaceFaces + nBlockedFaces) == cFaces.size())
930  {
931  // Single cell already disconnected by surface intersections
932  for (const label facei : cFaces)
933  {
934  erodedSet.unset(facei);
935  }
936  }
937  }
939  (
940  mesh_,
941  erodedSet,
942  andEqOp<unsigned int>()
943  );
944  //checkFaceSync("erodedSet", erodedSet);
945 
946  for (const label celli : isSetCell)
947  {
948  const cell& cFaces = mesh_.cells()[celli];
949 
950  label nBlockedFaces = 0;
951  for (const label facei : cFaces)
952  {
953  if (erodedSet[facei])
954  {
955  nBlockedFaces++;
956  }
957  }
958  if (nBlockedFaces >= cFaces.size()-2)
959  {
960  for (const label facei : cFaces)
961  {
962  erodedSet.flip(facei);
963  }
964  }
965  }
967  (
968  mesh_,
969  erodedSet,
970  andEqOp<unsigned int>()
971  );
972 
973  if (debug)
974  {
975  Pout<< "holeToFace::erodeSet :"
976  << " starting set:" << isSetFace.count()
977  << " eroded set:" << erodedSet.count() << endl;
978  }
979 
980  //checkFaceSync("erodedSet", erodedSet);
981  return erodedSet;
982 }
983 
984 
986 (
987  topoSet& set,
988  const bitSet& isSurfaceFace,
989  const bitSet& isHoleCell,
990  const bool add
991 ) const
992 {
993  labelListList locationCells(zonePoints_.size());
994  forAll(zonePoints_, zonei)
995  {
996  const pointField& zoneLocations = zonePoints_[zonei];
997  labelList& zoneCells = locationCells[zonei];
998  zoneCells.setSize(zoneLocations.size());
999  forAll(zoneLocations, i)
1000  {
1001  const label celli = mesh_.findCell(zoneLocations[i]);
1002  zoneCells[i] = celli;
1003 
1004  // Check that cell has at least one unblocked face so front can
1005  // 'escape'.
1006  if (celli != -1)
1007  {
1008  const cell& cFaces = mesh_.cells()[celli];
1009  bool hasUnblocked = false;
1010  for (const label facei : cFaces)
1011  {
1012  if (!isSurfaceFace[facei])
1013  {
1014  hasUnblocked = true;
1015  break;
1016  }
1017  }
1018 
1019  if (!hasUnblocked)
1020  {
1022  << "problem : location:" << zoneLocations[i]
1023  << " in zone:" << zonei
1024  << " is found in cell at:" << celli
1025  << mesh_.cellCentres()[celli]
1026  << " which is completely surrounded by blocked faces"
1027  << exit(FatalError);
1028  }
1029  }
1030  }
1031  }
1032 
1033  bitSet isClosingFace
1034  (
1035  findClosure
1036  (
1037  isSurfaceFace, // intersected faces
1038  isHoleCell, // starting blockage
1039  locationCells // cells for zonePoints_
1040  )
1041  );
1042 
1043  if (erode_)
1044  {
1045  isClosingFace = erodeSet(isSurfaceFace, isClosingFace);
1046  }
1047 
1048  if (debug)
1049  {
1050  writeFaces("isClosingFace.obj", isClosingFace);
1051  //checkFaceSync("isClosingFace", isCommonFace);
1052  }
1053 
1054  for (const label facei : isClosingFace)
1055  {
1056  addOrDelete(set, facei, add);
1057  }
1058 }
1059 
1060 
1061 Foam::List<Foam::pointField> Foam::holeToFace::expand(const pointField& pts)
1062 {
1063  List<pointField> allPts(pts.size());
1064  forAll(pts, i)
1065  {
1066  pointField& onePt = allPts[i];
1067  onePt.setSize(1, pts[i]);
1068  }
1069  return allPts;
1070 }
1071 
1073 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1074 
1076 (
1077  const polyMesh& mesh,
1078  const List<pointField>& zonePoints,
1079  const wordList& blockedFaceNames,
1080  const wordList& blockedCellNames,
1081  const bool erode
1082 )
1083 :
1085  zonePoints_(zonePoints),
1086  blockedFaceNames_(blockedFaceNames),
1087  blockedCellNames_(blockedCellNames),
1088  erode_(erode)
1089 {}
1090 
1091 
1093 (
1094  const polyMesh& mesh,
1095  const dictionary& dict
1096 )
1097 :
1099  zonePoints_(dict.get<List<pointField>>("points")),
1100  blockedFaceNames_(),
1101  blockedCellNames_(),
1102  erode_(dict.getOrDefault<bool>("erode", false))
1103 {
1104  // Look for 'sets' or 'set'
1105  word setName;
1106  if (!dict.readIfPresent("faceSets", blockedFaceNames_))
1107  {
1108  if (dict.readEntry("faceSet", setName))
1109  {
1110  blockedFaceNames_.resize(1);
1111  blockedFaceNames_.front() = std::move(setName);
1112  }
1113  }
1114  if (!dict.readIfPresent("cellSets", blockedCellNames_))
1115  {
1116  if (dict.readEntry("cellSet", setName))
1117  {
1118  blockedCellNames_.resize(1);
1119  blockedCellNames_.front() = std::move(setName);
1120  }
1121  }
1123 
1124 
1126 (
1127  const polyMesh& mesh,
1128  Istream& is
1129 )
1130 :
1132  zonePoints_(expand(pointField(is))),
1133  blockedFaceNames_(one{}, word(checkIs(is))),
1134  blockedCellNames_(),
1135  erode_(false)
1136 {}
1137 
1139 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1140 
1142 (
1143  const topoSetSource::setAction action,
1144  topoSet& set
1145 ) const
1146 {
1147  // Set of additional blocked (internal or coupled) faces
1148  bitSet isBlockedFace(mesh_.nFaces());
1149  for (const word& setName : blockedFaceNames_)
1150  {
1151  const faceSet loadedSet(mesh_, setName);
1152  isBlockedFace.set(loadedSet.toc());
1153  }
1154 
1155  // Optional initial blocked cells
1156  bitSet isCandidateCell(mesh_.nCells());
1157  if (blockedFaceNames_.size())
1158  {
1159  for (const word& setName : blockedCellNames_)
1160  {
1161  const cellSet loadedSet(mesh_, setName);
1162  isCandidateCell.set(loadedSet.toc());
1163  }
1164  }
1165  else
1166  {
1167  isCandidateCell = true;
1168  }
1169 
1170  if (action == topoSetSource::ADD || action == topoSetSource::NEW)
1171  {
1172  if (verbose_)
1173  {
1174  Info<< " Adding all faces to disconnect regions: "
1175  << flatOutput(zonePoints_) << " ..." << endl;
1176  }
1177 
1178  combine(set, isBlockedFace, isCandidateCell, true);
1179  }
1180  else if (action == topoSetSource::SUBTRACT)
1181  {
1182  if (verbose_)
1183  {
1184  Info<< " Removing all faces to disconnect regions: "
1185  << flatOutput(zonePoints_) << " ..." << endl;
1186  }
1187 
1188  combine(set, isBlockedFace, isCandidateCell, false);
1189  }
1191 
1192 
1194 (
1195  const polyMesh& mesh,
1196  const List<pointField>& zonePoints,
1197  const labelList& blockedFaces,
1198  const globalIndex& globalBlockedFaces,
1199  const bool erode,
1200 
1201  labelList& closureFaces, // local faces to close gap
1202  labelList& closureToBlocked
1203 )
1204 {
1205  if (blockedFaces.size() != globalBlockedFaces.localSize())
1206  {
1207  FatalErrorInFunction << "problem : blockedFaces:" << blockedFaces.size()
1208  << " globalBlockedFaces:" << globalBlockedFaces.localSize()
1209  << exit(FatalError);
1210  }
1211 
1212 
1213  // Calculate faces needed to close hole (closureFaces)
1214  {
1215  const holeToFace faceSetSource
1216  (
1217  mesh,
1218  zonePoints,
1219  wordList(0),
1220  wordList(0),
1221  erode //false
1222  );
1223  faceSet closureFaceSet(mesh, "calcClosure", 256);
1224 
1225  const bitSet isBlockedFace(mesh.nFaces(), blockedFaces);
1226  const bitSet isActiveCell(mesh.nCells(), true);
1227 
1228  faceSetSource.combine
1229  (
1230  closureFaceSet,
1231  isBlockedFace,
1232  isActiveCell,
1233  true
1234  );
1235 
1236  closureFaces = closureFaceSet.sortedToc();
1237  }
1238 
1239 
1240  if (returnReduceAnd(closureFaces.empty()))
1241  {
1242  closureToBlocked.clear();
1243  return nullptr;
1244  }
1245 
1246 
1247  //- Seed edges of closureFaces patch with (global) index of blockedFace
1248 
1250  (
1251  IndirectList<face>(mesh.faces(), closureFaces),
1252  mesh.points()
1253  );
1254  const edgeList& edges = pp.edges();
1255  const labelList& mp = pp.meshPoints();
1256  const label nBndEdges = pp.nEdges() - pp.nInternalEdges();
1257 
1258  // For all faces in blockedFaces mark the edge with a face. No special
1259  // handling for multiple faces sharing the edge - first one wins
1260  EdgeMap<label> edgeMap(pp.nEdges());
1261  forAll(blockedFaces, i)
1262  {
1263  const label globalBlockedi = globalBlockedFaces.toGlobal(i);
1264  const label facei = blockedFaces[i];
1265  const face& f = mesh.faces()[facei];
1266  forAll(f, fp)
1267  {
1268  label nextFp = f.fcIndex(fp);
1269  edgeMap.insert(edge(f[fp], f[nextFp]), globalBlockedi);
1270  }
1271  }
1272  syncTools::syncEdgeMap(mesh, edgeMap, maxEqOp<label>());
1273 
1274 
1275 
1276  // Seed
1277  DynamicList<label> initialEdges(2*nBndEdges);
1278  DynamicList<edgeTopoDistanceData<label, indirectPrimitivePatch>>
1279  initialEdgesInfo(2*nBndEdges);
1280  forAll(edges, edgei)
1281  {
1282  const edge& e = edges[edgei];
1283  const edge meshE = edge(mp[e[0]], mp[e[1]]);
1284 
1285  auto iter = edgeMap.cfind(meshE);
1286  if (iter.good())
1287  {
1288  // Found edge on patch connected to blocked face. Seed with the
1289  // (global) index of that blocked face
1290 
1291  initialEdges.append(edgei);
1292  initialEdgesInfo.append
1293  (
1294  edgeTopoDistanceData<label, indirectPrimitivePatch>
1295  (
1296  0, // distance
1297  iter() // globalBlockedi
1298  )
1299  );
1300  }
1301  }
1302 
1303  // Data on all edges and faces
1304  List<edgeTopoDistanceData<label, indirectPrimitivePatch>> allEdgeInfo
1305  (
1306  pp.nEdges()
1307  );
1308  List<edgeTopoDistanceData<label, indirectPrimitivePatch>> allFaceInfo
1309  (
1310  pp.size()
1311  );
1312 
1313  // Walk
1314  PatchEdgeFaceWave
1315  <
1317  edgeTopoDistanceData<label, indirectPrimitivePatch>
1318  > calc
1319  (
1320  mesh,
1321  pp,
1322  initialEdges,
1323  initialEdgesInfo,
1324  allEdgeInfo,
1325  allFaceInfo,
1326  returnReduce(pp.nEdges(), sumOp<label>())+1
1327  );
1328 
1329 
1330  // Per closure face the seed face
1331  closureToBlocked.resize_nocopy(pp.size());
1332  closureToBlocked = -1;
1333  forAll(allFaceInfo, facei)
1334  {
1335  if (allFaceInfo[facei].valid(calc.data()))
1336  {
1337  closureToBlocked[facei] = allFaceInfo[facei].data();
1338  }
1339  }
1340  // Above wave only guarantees unique data on coupled edges, not on
1341  // coupled faces (?) so explicitly sync faces
1342  {
1343  labelList syncFld(mesh.nFaces(), -1);
1344  UIndirectList<label>(syncFld, pp.addressing()) = closureToBlocked;
1345  syncTools::syncFaceList(mesh, syncFld, maxEqOp<label>());
1346  closureToBlocked = UIndirectList<label>(syncFld, pp.addressing());
1347  }
1348 
1349  List<Map<label>> compactMap;
1351  (
1352  globalBlockedFaces,
1353  closureToBlocked,
1354  compactMap
1355  );
1356 }
1357 
1358 
1359 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
const polyBoundaryMesh & pbm
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A list of face labels.
Definition: faceSet.H:47
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
fileName timePath() const
Return current time path = path/timeName.
Definition: Time.H:520
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:517
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
Create a new set and ADD elements to it.
Add elements to current set.
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:489
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition: UListI.H:272
T & front()
Access first element of the list, position [0].
Definition: UListI.H:237
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
label nInternalEdges() const
Number of internal edges.
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:432
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:175
label nFaces() const noexcept
Number of mesh faces.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
virtual const fileName & name() const override
Get the name of the output serial stream. (eg, the name of the Fstream file name) ...
Definition: OSstream.H:128
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.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Macros for easy insertion into run-time selection tables.
virtual void applyToSet(const topoSetSource::setAction action, topoSet &) const
Apply specified action to the topoSet.
Definition: holeToFace.C:1138
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
const labelList & meshPoints() const
Return labelList of mesh points in patch.
addNamedToRunTimeSelectionTable(topoSetCellSource, badQualityToCell, word, badQuality)
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition: UListI.H:97
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
AccessType combine(const UList< T > &lists, AccessOp aop=accessOp< T >())
Combines sub-lists into a single list.
Definition: ListListOps.C:62
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
A class for handling words, derived from Foam::string.
Definition: word.H:63
const Time & time() const noexcept
Return time registry.
void combine(topoSet &set, const bitSet &isBlockedFace, const bitSet &isActiveCell, const bool add) const
Optional direct use to generate a faceSet.
Definition: holeToFace.C:982
The topoSetFaceSource is a intermediate class for handling topoSet sources for selecting faces...
3D tensor transformation operations.
setAction
Enumeration defining various actions.
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
label localSize(const label proci) const
Size of proci data.
Definition: globalIndexI.H:257
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1103
const polyMesh & mesh_
Reference to the mesh.
label nEdges() const
Number of edges in patch.
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
int debug
Static debugging option.
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
labelList f(nPoints)
General set of labels of mesh quantity (points, cells, faces).
Definition: topoSet.H:59
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
List< word > wordList
List of word.
Definition: fileName.H:59
Subtract elements from current set.
label toGlobal(const label proci, const label i) const
From local to global on proci.
Definition: globalIndexI.H:308
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
Class with constructor to add usage string to table.
label nCells() const noexcept
Number of mesh cells.
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:53
A collection of cell labels.
Definition: cellSet.H:47
unsigned int bit_count(UIntType x)
Count arbitrary number of bits (of an integral type)
Definition: BitOps.H:245
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)
static autoPtr< mapDistribute > calcClosure(const polyMesh &mesh, const List< pointField > &zonePoints, const labelList &blockedFaces, const globalIndex &globalBlockedFaces, const bool erode, labelList &closureFaces, labelList &closureToBlocked)
Optional direct use to generate the set of faces and the method to.
Definition: holeToFace.C:1190
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:124
List< label > labelList
A List of labels.
Definition: List.H:62
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
holeToFace(const polyMesh &mesh, const List< pointField > &zonePoints, const wordList &blockedFaceNames, const wordList &blockedCellNames, const bool erode)
Construct from components.
Definition: holeToFace.C:1072
static void syncEdgeMap(const polyMesh &mesh, EdgeMap< T > &edgeValues, const CombineOp &cop, const TransformOp &top)
Synchronize values on selected edges.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
const dimensionedScalar mp
Proton mass.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:485
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
A class representing the concept of 1 (one) that can be used to avoid manipulating objects known to b...
Definition: one.H:56
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225
const pointField & pts
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Expand occurrences of variables according to the mapping and return the expanded string.
Definition: stringOps.C:705