Loading...
Searching...
No Matches
shortestPathSet.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) 2017-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
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 "shortestPathSet.H"
29#include "meshSearch.H"
30#include "DynamicList.H"
31#include "topoDistanceData.H"
33#include "FaceCellWave.H"
34#include "syncTools.H"
35#include "fvMesh.H"
36#include "volFields.H"
37#include "OBJstream.H"
38#include "PatchTools.H"
41#include "globalIndex.H"
42
43// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44
45namespace Foam
46{
49}
50
51
52// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53
54Foam::label Foam::shortestPathSet::findMinFace
55(
56 const polyMesh& mesh,
57 const label cellI,
58 const List<topoDistanceData<label>>& allFaceInfo,
59 const bitSet& isLeakPoint,
60 const bool distanceMode,
61 const point& origin
62)
63{
64 const cell& cFaces2 = mesh.cells()[cellI];
65
66 // 1. Get topologically nearest face
67
68 label minDist = labelMax;
69 label minFaceI = -1;
70 label nMin = 0;
71 forAll(cFaces2, i)
72 {
73 label faceI = cFaces2[i];
74 const topoDistanceData<label>& info = allFaceInfo[faceI];
75 if (info.distance() < minDist)
76 {
77 minDist = info.distance();
78 minFaceI = faceI;
79 nMin = 1;
80 }
81 else if (info.distance() == minDist)
82 {
83 nMin++;
84 }
85 }
86
87 if (nMin > 1)
88 {
89 // 2. Check all faces with minDist for minimum (or maximum)
90 // distance to origin
91 if (distanceMode)
92 {
93 scalar minDist2 = ROOTVGREAT;
94 forAll(cFaces2, i)
95 {
96 label faceI = cFaces2[i];
97 if (allFaceInfo[faceI].distance() == minDist)
98 {
99 scalar d2 = magSqr(mesh.faceCentres()[faceI]-origin);
100 if (d2 < minDist2)
101 {
102 minDist2 = d2;
103 minFaceI = faceI;
104 }
105 }
106 }
107 }
108 else
109 {
110 // Avoid leak points i.e. preferentially stay away from the wall
111 label minLeakPoints = labelMax;
112 forAll(cFaces2, i)
113 {
114 label faceI = cFaces2[i];
115 if (allFaceInfo[faceI].distance() == minDist)
116 {
117 // Count number of leak points
118 label nLeak = 0;
119 {
120 const face& f = mesh.faces()[faceI];
121 forAll(f, fp)
122 {
123 if (isLeakPoint[f[fp]])
124 {
125 nLeak++;
126 }
127 }
128 }
129
130 if (nLeak < minLeakPoints)
131 {
132 minLeakPoints = nLeak;
133 minFaceI = faceI;
134 }
135 }
136 }
137 }
138 }
139
140 return minFaceI;
141}
142
143
144void Foam::shortestPathSet::calculateDistance
145(
146 const label iter,
147 const polyMesh& mesh,
148 const label cellI,
149
152) const
153{
154 int dummyTrackData = 0;
155
156 // Seed faces on cell1
158 DynamicList<label> cFaces1;
159
160 if (cellI != -1)
161 {
162 const labelList& cFaces = mesh.cells()[cellI];
163 faceDist.reserve(cFaces.size());
164 cFaces1.reserve(cFaces.size());
165
166 for (label facei : cFaces)
167 {
168 if (!allFaceInfo[facei].valid(dummyTrackData))
169 {
170 cFaces1.append(facei);
171 faceDist.append(topoDistanceData<label>(0, 123));
172 }
173 }
174 }
175
176
177
178 // Walk through face-cell wave till all cells are reached
180 <
183 (
184 mesh,
185 cFaces1,
186 faceDist,
189 mesh.globalData().nTotalCells()+1 // max iterations
190 );
191
192
193 if (debug)
194 {
195 const fvMesh& fm = refCast<const fvMesh>(mesh);
196
197 //const_cast<fvMesh&>(fm).setInstance(fm.time().timeName());
198 //fm.write();
200 (
202 (
203 "allCellInfo" + Foam::name(iter),
204 fm.time().timeName(),
205 fm,
208 ),
209 fm,
211 );
212 forAll(allCellInfo, celli)
213 {
214 fld[celli] = allCellInfo[celli].distance();
215 }
216 forAll(fld.boundaryField(), patchi)
217 {
218 const polyPatch& pp = mesh.boundaryMesh()[patchi];
220 scalarField pfld(fld.boundaryField()[patchi].size());
221 forAll(pfld, i)
222 {
223 pfld[i] = 1.0*p[i].distance();
224 }
225 fld.boundaryFieldRef()[patchi] == pfld;
226 }
227 //Note: do not swap cell values so do not do
228 //fld.correctBoundaryConditions();
229 Pout<< "Writing distance field for initial cell " << cellI
230 << " to " << fld.objectPath() << endl;
231 fld.write();
232 }
233}
234
235
236void Foam::shortestPathSet::sync
237(
238 const polyMesh& mesh,
239 bitSet& isLeakFace,
240 bitSet& isLeakPoint,
241 const label celli,
242 point& origin,
243 bool& findMinDistance
244) const
245{
247 (
248 mesh,
249 isLeakPoint,
251 0u
252 );
254 (
255 mesh,
256 isLeakFace,
258 );
259 // Sync origin, findMinDistance
260 {
261 typedef Tuple2<label, Tuple2<point, bool>> ProcData;
262
263 ProcData searchData
264 (
265 celli,
266 Tuple2<point, bool>(origin, findMinDistance)
267 );
269 (
270 searchData,
271 [](ProcData& x, const ProcData& y)
272 {
273 if (y.first() != -1)
274 {
275 x = y;
276 }
277 }
278 );
279 origin = searchData.second().first();
280 findMinDistance = searchData.second().second();
281 }
282}
283
284
285bool Foam::shortestPathSet::touchesWall
286(
287 const polyMesh& mesh,
288 const label facei,
289
290 bitSet& isLeakFace,
291 const bitSet& isLeakPoint
292) const
293{
294 // Check if facei touches leakPoint
295 const face& f = mesh.faces()[facei];
296 forAll(f, fp)
297 {
298 const label nextFp = f.fcIndex(fp);
299
300 if (isLeakPoint[f[fp]] && isLeakPoint[f[nextFp]]) // edge on boundary
301 //if (isLeakPoint[f[fp]]) // point on boundary
302 {
303 if (isLeakFace.set(facei))
304 {
305 return true;
306 }
307 }
308 }
309
310 return false;
311}
312
313
314Foam::bitSet Foam::shortestPathSet::pathFaces
315(
316 const polyMesh& mesh,
317 const bitSet& isLeakCell
318) const
319{
320 // Calculates the list of faces inbetween leak cells.
321 // Does not account for the fact that the cells might be from different
322 // paths...
323
325 const labelList& own = mesh.faceOwner();
326 const labelList& nbr = mesh.faceNeighbour();
327
328 // Get remote value of bitCell. Note: keep uncoupled boundary faces false.
329 boolList nbrLeakCell(mesh.nBoundaryFaces(), false);
330 {
331 for (const polyPatch& pp : patches)
332 {
333 if (pp.coupled())
334 {
335 label bFacei = pp.start()-mesh.nInternalFaces();
336
337 const labelUList& faceCells = pp.faceCells();
338
339 for (const label celli : faceCells)
340 {
341 nbrLeakCell[bFacei] = isLeakCell[celli];
342 ++bFacei;
343 }
344 }
345 }
346
348 (
349 mesh,
350 nbrLeakCell
351 );
352 }
353
354
355 bitSet isLeakFace(mesh.nFaces());
356
357 // Internal faces
358 for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
359 {
360 if (isLeakCell[own[facei]] && isLeakCell[nbr[facei]])
361 {
362 isLeakFace.set(facei);
363 }
364 }
365 // Boundary faces
366 for (label facei = mesh.nInternalFaces(); facei < mesh.nFaces(); facei++)
367 {
368 if (isLeakCell[own[facei]] && nbrLeakCell[facei-mesh.nInternalFaces()])
369 {
370 isLeakFace.set(facei);
371 }
372 }
373 return isLeakFace;
374}
375
376
377bool Foam::shortestPathSet::genSingleLeakPath
378(
379 const bool markLeakPath,
380 const label iter,
381 const polyMesh& mesh,
382 const bitSet& isBlockedFace,
383 const point& insidePoint,
384 const label insideCelli,
385 const point& outsidePoint,
386 const label outsideCelli,
387
388 // Generated sampling points
389 const scalar trackLength,
390 DynamicList<point>& samplingPts,
391 DynamicList<label>& samplingCells,
392 DynamicList<label>& samplingFaces,
393 DynamicList<label>& samplingSegments,
394 DynamicList<scalar>& samplingCurveDist,
395
396 // State of current leak paths
397 bitSet& isLeakCell,
398 bitSet& isLeakFace,
399 bitSet& isLeakPoint,
400
401 // Work storage
404) const
405{
408
409
410 allFaceInfo.setSize(mesh.nFaces());
412 allCellInfo.setSize(mesh.nCells());
414
415 // Mark blocked faces with high distance
416 forAll(isBlockedFace, facei)
417 {
418 if (isBlockedFace[facei])
419 {
420 allFaceInfo[facei] = maxData;
421 }
422 }
423
424 if (markLeakPath)
425 {
426 // Mark any previously found leak path. This marks all
427 // faces of all cells on the path. This will make sure that
428 // ultimately the path will go through another gap.
429 forAll(isLeakCell, celli)
430 {
431 if (celli != insideCelli && celli != outsideCelli)
432 {
433 if (isLeakCell[celli])
434 {
435 allCellInfo[celli] = maxData;
436 //- Mark all faces of the cell
437 //const cell& cFaces = mesh.cells()[celli];
438 //for (auto facei : cFaces)
439 //{
440 // allFaceInfo[facei] = maxData;
441 //}
442 }
443 }
444 }
445
446 //- Mark only faces inbetween two leak cells
447 bitSet isLeakCellWithout(isLeakCell);
448 if (insideCelli != -1)
449 {
450 isLeakCellWithout.unset(insideCelli);
451 }
452 if (outsideCelli != -1)
453 {
454 isLeakCellWithout.unset(outsideCelli);
455 }
456 const bitSet isPathFace(pathFaces(mesh, isLeakCellWithout));
457 forAll(isPathFace, facei)
458 {
459 if (isPathFace[facei])
460 {
461 allFaceInfo[facei] = maxData;
462 }
463 }
464 }
465
466 // Mark any previously found leak faces. These are faces that
467 // are (point- or edge-)connected to an existing boundary.
468 forAll(isLeakFace, facei)
469 {
470 if (isLeakFace[facei])
471 {
472 allFaceInfo[facei] = maxData;
473 }
474 }
475
476
477 // Pass1: Get distance to insideCelli
478 // Note: calculateDistance must be called on ALL processors, even if insideCelli == -1
479 // The FaceCellWave will propagate from the processor that has the seed cell
480 calculateDistance(iter, mesh, insideCelli, allFaceInfo, allCellInfo);
481
482
483
484 // Pass2: walk from outside points backwards. Note: could be done
485 // using FaceCellWave as well but is overly complex since
486 // does not allow logic comparing all faces of a cell.
487
488 // Check if target was reached - must check on processor that has outsideCelli
489 bool targetFound = false;
490 if (outsideCelli != -1)
491 {
492 int dummyTrackData;
493 targetFound = allCellInfo[outsideCelli].valid(dummyTrackData);
494 }
495
496 // Global check: reduce across all processors to see if ANY processor found the target
497 // This is necessary because outsideCelli might be on a different processor than insideCelli
498 bool globalTargetFound = returnReduceOr(targetFound);
499
500 if (iter == 0 && !globalTargetFound)
501 {
503 << "Point " << outsidePoint
504 << " not reachable by walk from " << insidePoint
505 << ". Probably mesh has island/regions."
506 << " Inside cell found: " << (insideCelli != -1 ? "yes" : "no")
507 << ", Outside cell found: " << (outsideCelli != -1 ? "yes" : "no")
508 << ". Skipped route detection." << endl;
509 }
510
511 if (!globalTargetFound)
512 {
513 //Pout<< "now :"
514 // << " nLeakCell:"
515 // << returnReduce(isLeakCell.count(), sumOp<label>())
516 // << " nLeakFace:"
517 // << returnReduce(isLeakFace.count(), sumOp<label>())
518 // << " nLeakPoint:"
519 // << returnReduce(isLeakPoint.count(), sumOp<label>())
520 // << endl;
521
522 return false;
523 }
524
525
526 // Start with given target cell and walk back
527 // CRITICAL FIX: With many processors, outsideCelli might be -1 on most processors.
528 // We need to find the nearest cell to outsidePoint that has valid distance info.
529 label frontCellI = outsideCelli;
530 point origin(outsidePoint);
531 bool findMinDistance = true;
532
533 // If outsideCelli is -1, find the nearest cell to outsidePoint with valid distance
534 // This is critical for high processor counts where outsideCelli is on a different processor
535 // CRITICAL: This reduction must be called by ALL processors, even if frontCellI != -1
536 scalar minDist = GREAT;
537 label minCellI = -1;
538 int dummyTrackData = 0;
539
540 if (frontCellI == -1)
541 {
542 // Search all local cells for the one closest to outsidePoint with valid distance
543 forAll(allCellInfo, celli)
544 {
545 if (allCellInfo[celli].valid(dummyTrackData))
546 {
547 scalar dist = mag(mesh.cellCentres()[celli] - outsidePoint);
548 if (dist < minDist)
549 {
550 minDist = dist;
551 minCellI = celli;
552 }
553 }
554 }
555 }
556
557 // Find global minimum across all processors using Tuple2 to track processor
558 // This MUST be called by ALL processors to avoid deadlock
559 typedef Tuple2<scalar, label> DistProc;
560 DistProc localMin(minDist, Pstream::myProcNo());
561 DistProc globalMin = localMin;
563
564 // Only use if we found a reasonably close cell (within mesh bounds scale)
565 // and if we're on the processor that has the minimum
566 if (frontCellI == -1)
567 {
568 const scalar searchRadius = mag(mesh.bounds().max() - mesh.bounds().min()) * 0.1;
569 if (globalMin.first() < searchRadius && globalMin.second() == Pstream::myProcNo() && minCellI != -1)
570 {
571 frontCellI = minCellI;
572 }
573 }
574
575 while (true)
576 {
577 // We have a single face front (frontFaceI). Walk from face to cell
578 // to face etc until we reach the destination cell.
579
580 label frontFaceI = -1;
581
582 // Work within same processor
583 if (frontCellI != -1)
584 {
585 // Find face with lowest distance from seed. In below figure the
586 // seed cell is marked with distance 0. It is surrounded by faces
587 // and cells with distance 1. The layer outside is marked with
588 // distance 2 etc etc.
589 //
590 // x | x 2 1 2 2 | x | x
591 // --- + --- + -1- + -2- + --- + ---
592 // x | 1 1 0 1 1 | x | x
593 // --- + --- + -1- + -2- + --- + ---
594 // x | x 2 1 2 2 3 3 4 4
595 // --- + --- + --- + -3- + -4- + -5-
596 // x | x 3 2 3 3 4 4 5 5
597 //
598 // e.g. if we start backwards search from cell with value = 4,
599 // we have neighbour faces 4, 4, 5, 5. Choose 4 (least distance
600 // to seed) and continue...
601
602 frontFaceI = findMinFace
603 (
604 mesh,
605 frontCellI,
607 isLeakPoint,
608 findMinDistance, // mode : find min or find max
609 origin
610 );
611
612
613 // Loop until we hit a boundary face
614 bitSet isNewLeakPoint(isLeakPoint);
615 while (mesh.isInternalFace(frontFaceI))
616 {
617 if (isBlockedFace.size() && isBlockedFace[frontFaceI])
618 {
619 // This should not happen since we never walk through
620 // a blocked face. However ...
621 // Pout<< " Found blocked face" << endl;
622 frontCellI = -1;
623 break;
624 }
625
626 // Step to neighbouring cell
627 label nbrCellI = mesh.faceOwner()[frontFaceI];
628 if (nbrCellI == frontCellI)
629 {
630 nbrCellI = mesh.faceNeighbour()[frontFaceI];
631 }
632
633 if (nbrCellI == insideCelli)
634 {
635 // Reached destination. This is the normal exit.
636 frontCellI = -1;
637 break;
638 }
639
640 frontCellI = nbrCellI;
641
642 // Pick best face on cell
643 frontFaceI = findMinFace
644 (
645 mesh,
646 frontCellI,
648 isLeakPoint,
649 findMinDistance,
650 origin
651 );
652
653 const topoDistanceData<label>& cInfo = allCellInfo[frontCellI];
654 const topoDistanceData<label>& fInfo = allFaceInfo[frontFaceI];
655
656 if (fInfo.distance() <= cInfo.distance())
657 {
658 // Found valid next cell,face. Mark on path
659 samplingPts.append(mesh.cellCentres()[frontCellI]);
660 samplingCells.append(frontCellI);
661 samplingFaces.append(-1);
662 samplingSegments.append(iter);
663 samplingCurveDist.append
664 (
665 trackLength+cInfo.distance()
666 );
667 isLeakCell.set(frontCellI);
668
669 // Check if front face uses a boundary point.
670 if
671 (
672 touchesWall
673 (
674 mesh,
675 frontFaceI,
676 isLeakFace,
677 isLeakPoint
678 )
679 )
680 {
681 //Pout<< "** added leak face:" << frontFaceI << " at:"
682 //<< mesh.faceCentres()[frontFaceI] << endl;
683 isNewLeakPoint.set(mesh.faces()[frontFaceI]);
684 origin = mesh.faceCentres()[frontFaceI];
685 findMinDistance = false;
686 }
687 }
688 }
689 isLeakPoint.transfer(isNewLeakPoint);
690 }
691
692 // Situation 1: we found the destination cell (do nothing),
693 // frontCellI is -1 on all processors
694 if (returnReduceAnd(frontCellI == -1))
695 {
696 //Pout<< "now :"
697 // << " nLeakCell:"
698 // << returnReduce(isLeakCell.count(), sumOp<label>())
699 // << " nLeakFace:"
700 // << returnReduce(isLeakFace.count(), sumOp<label>())
701 // << " nLeakPoint:"
702 // << returnReduce(isLeakPoint.count(), sumOp<label>())
703 // << endl;
704
705 break;
706 }
707
708 // Situation 2: we're on a coupled patch and might need to
709 // switch processor/cell. We need to transfer:
710 // -frontface -frontdistance -leak points/faces
711 boolList isFront(mesh.nBoundaryFaces(), false);
712
713 if (frontFaceI != -1)
714 {
715 isFront[frontFaceI-mesh.nInternalFaces()] = true;
716 }
718
719 label minCellDistance = labelMax;
720 if (frontCellI != -1)
721 {
722 minCellDistance = allCellInfo[frontCellI].distance();
723 }
724 reduce(minCellDistance, minOp<label>());
725
726 // Sync all leak data
727 sync
728 (
729 mesh,
730 isLeakFace,
731 isLeakPoint,
732 frontCellI,
733 origin,
734 findMinDistance
735 );
736
737
738 // Bit tricky:
739 // - processor might get frontFaceI/frontCellI in through multiple faces
740 // (even through different patches?)
741 // - so loop over all (coupled) patches and pick the best frontCellI
742
743 const label oldFrontFaceI = frontFaceI;
744 frontCellI = -1;
745 frontFaceI = -1;
746 forAll(pbm, patchI)
747 {
748 const polyPatch& pp = pbm[patchI];
749 forAll(pp, i)
750 {
751 label faceI = pp.start()+i;
752 if
753 (
754 oldFrontFaceI == -1
755 && isFront[faceI-mesh.nInternalFaces()]
756 && (isBlockedFace.empty() || !isBlockedFace[faceI])
757 )
758 {
759 frontFaceI = faceI;
760 frontCellI = pp.faceCells()[i];
761 break;
762 }
763 }
764
765 if
766 (
767 frontCellI != -1
768 && allCellInfo[frontCellI].distance() < minCellDistance
769 )
770 {
771 const topoDistanceData<label>& cInfo = allCellInfo[frontCellI];
772
773 samplingPts.append(mesh.cellCentres()[frontCellI]);
774 samplingCells.append(frontCellI);
775 samplingFaces.append(-1);
776 samplingSegments.append(iter);
777 samplingCurveDist.append
778 (
779 trackLength+cInfo.distance()
780 );
781 isLeakCell.set(frontCellI);
782
783 // Check if frontFacei touches leakPoint
784 if
785 (
786 touchesWall
787 (
788 mesh,
789 frontFaceI,
790 isLeakFace,
791 isLeakPoint
792 )
793 )
794 {
795 //Pout<< "** added leak BOUNDARY face:" << frontFaceI
796 // << " at:" << mesh.faceCentres()[frontFaceI] << endl;
797 isLeakPoint.set(mesh.faces()[frontFaceI]);
798 origin = mesh.faceCentres()[frontFaceI];
799 findMinDistance = false;
800 }
801
802 break;
803 }
804
805 // When seed cell is isolated by processor boundaries
806 if (insideCelli != -1 && frontCellI == insideCelli)
807 {
808 // Pout<< " Found connection seed cell!" << endl;
809 frontCellI = -1;
810 break;
811 }
812 }
813
814 // Sync all leak data
815 sync
816 (
817 mesh,
818 isLeakFace,
819 isLeakPoint,
820 frontCellI,
821 origin,
822 findMinDistance
823 );
824 }
825
826 return true;
827}
828
829
830// Clean up leak faces (erode open edges). These are leak faces which are
831// not connected to another leak face or leak point. Parallel consistent.
832// Returns overall number of faces deselected.
833Foam::label Foam::shortestPathSet::erodeFaceSet
834(
835 const polyMesh& mesh,
836 const bitSet& isBlockedPoint,
837 bitSet& isLeakFace
838) const
839{
840 if
841 (
842 (isBlockedPoint.size() != mesh.nPoints())
843 || (isLeakFace.size() != mesh.nFaces())
844 )
845 {
846 FatalErrorInFunction << "Problem :"
847 << " isBlockedPoint:" << isBlockedPoint.size()
848 << " isLeakFace:" << isLeakFace.size()
849 << exit(FatalError);
850 }
851
852 const globalMeshData& globalData = mesh.globalData();
853 const mapDistribute& map = globalData.globalEdgeSlavesMap();
855
856
857 label nTotalEroded = 0;
858
859 while (true)
860 {
861 bitSet newIsLeakFace(isLeakFace);
862
863 // Get number of edges
864
865 const labelList meshFaceIDs(isLeakFace.toc());
867 (
868 UIndirectList<face>(mesh.faces(), meshFaceIDs),
869 mesh.points()
870 );
871
872 // Count number of faces per edge
873 const labelListList& edgeFaces = pp.edgeFaces();
874 labelList nEdgeFaces(edgeFaces.size());
875 forAll(edgeFaces, edgei)
876 {
877 nEdgeFaces[edgei] = edgeFaces[edgei].size();
878 }
879
880 // Match pp edges to coupled edges
881 labelList patchEdges;
882 labelList coupledEdges;
883 bitSet sameEdgeOrientation;
885 (
886 pp,
887 cpp,
888 patchEdges,
889 coupledEdges,
890 sameEdgeOrientation
891 );
892
893
894 // Convert patch-edge data into cpp-edge data
895 labelList coupledNEdgeFaces(map.constructSize(), Zero);
896 UIndirectList<label>(coupledNEdgeFaces, coupledEdges) =
897 UIndirectList<label>(nEdgeFaces, patchEdges);
898
899 // Synchronise
900 globalData.syncData
901 (
902 coupledNEdgeFaces,
903 globalData.globalEdgeSlaves(),
904 globalData.globalEdgeTransformedSlaves(),
905 map,
907 );
908
909 // Convert back from cpp-edge to patch-edge
910 UIndirectList<label>(nEdgeFaces, patchEdges) =
911 UIndirectList<label>(coupledNEdgeFaces, coupledEdges);
912
913 // Remove any open edges
914 label nEroded = 0;
915 forAll(nEdgeFaces, edgei)
916 {
917 if (nEdgeFaces[edgei] == 1)
918 {
919 const edge& e = pp.edges()[edgei];
920 const label mp0 = pp.meshPoints()[e[0]];
921 const label mp1 = pp.meshPoints()[e[1]];
922
923 if (!isBlockedPoint[mp0] || !isBlockedPoint[mp1])
924 {
925 // Edge is not on wall so is open
926 const label patchFacei = edgeFaces[edgei][0];
927 const label meshFacei = pp.addressing()[patchFacei];
928 //Pout<< "Eroding face:" << meshFacei
929 // << " at:" << mesh.faceCentres()[meshFacei]
930 // << " since has open edge:" << mesh.points()[mp0]
931 // << mesh.points()[mp1] << endl;
932
933 if (newIsLeakFace.unset(meshFacei))
934 {
935 nEroded++;
936 }
937 }
938 }
939 }
940
941 reduce(nEroded, sumOp<label>());
942 nTotalEroded += nEroded;
943
944 if (nEroded == 0)
945 {
946 break;
947 }
948
949 // Make sure we make the same decision on both sides
951 (
952 mesh,
953 newIsLeakFace,
955 );
956
957 isLeakFace = std::move(newIsLeakFace);
958 }
959
960 return nTotalEroded;
961}
962
963
964void Foam::shortestPathSet::genSamples
965(
966 const bool addLeakPath,
967 const label maxIter,
968 const polyMesh& mesh,
969 const bitSet& isBoundaryFace,
970 const point& insidePoint,
971 const label insideCelli,
972 const point& outsidePoint,
973
974 DynamicList<point>& samplingPts,
975 DynamicList<label>& samplingCells,
976 DynamicList<label>& samplingFaces,
977 DynamicList<label>& samplingSegments,
978 DynamicList<scalar>& samplingCurveDist,
979 bitSet& isLeakCell,
980 bitSet& isLeakFace,
981 bitSet& isLeakPoint
982) const
983{
984 // Mark all paths needed to close a single combination of insidePoint,
985 // outsidePoint. The output is
986 // - isLeakCell : is cell along a leak path
987 // - isLeakFace : is face along a leak path (so inbetween two leakCells)
988 // - isLeakPoint : is point on a leakFace
989
990
992
993 // Find outside cell globally - handle processor boundaries
994 // Force calculation of base points (needs to be synchronised)
995 (void)mesh.tetBasePtIs();
996
997 const globalIndex& globalCells = mesh.globalData().globalMeshCellAddr();
998 label localOutsideCelli = mesh.findCell(outsidePoint);
999 label globalOutsideCelli = -1;
1000 if (localOutsideCelli != -1)
1001 {
1002 globalOutsideCelli = globalCells.toGlobal(localOutsideCelli);
1003 }
1004 reduce(globalOutsideCelli, maxOp<label>());
1005
1006 // If not found, try perturbation (points on processor boundaries)
1007 if (globalOutsideCelli == -1)
1008 {
1009 const vector perturbVec = 1e-6 * (mesh.bounds().max() - mesh.bounds().min());
1010 localOutsideCelli = mesh.findCell(outsidePoint + perturbVec);
1011 if (localOutsideCelli != -1)
1012 {
1013 globalOutsideCelli = globalCells.toGlobal(localOutsideCelli);
1014 }
1015 reduce(globalOutsideCelli, maxOp<label>());
1016 }
1017
1018 // Convert back to local cell index on the processor that has it
1019 label outsideCelli = -1;
1020 label outsideProcI = -1;
1021 if (globalOutsideCelli != -1)
1022 {
1023 outsideProcI = globalCells.whichProcID(globalOutsideCelli);
1024 if (outsideProcI == Pstream::myProcNo())
1025 {
1026 outsideCelli = globalCells.toLocal(outsideProcI, globalOutsideCelli);
1027 }
1028 }
1029
1030 // Debug output
1031 if (debug)
1032 {
1033 Pout<< "Outside point " << outsidePoint
1034 << " -> global cell " << globalOutsideCelli
1035 << " on proc " << outsideProcI
1036 << ", local cell on proc " << Pstream::myProcNo() << ": " << outsideCelli << endl;
1037 }
1038
1039 // Maintain overall track length. Used to make curve distance continuous.
1040 scalar trackLength = 0;
1041
1044
1045
1046 // Boundary face + additional temporary blocks (to force leakpath to
1047 // outside)
1049
1050 label iter;
1051 bool markLeakPath = false;
1052 bool gaveUp = false; // Track if we gave up trying to close the gap
1053
1054
1055 for (iter = 0; iter < maxIter; iter++)
1056 {
1057 const label nOldLeakFaces = returnReduce
1058 (
1059 isLeakFace.count(),
1060 sumOp<label>()
1061 );
1062 const label oldNSamplingPts(samplingPts.size());
1063
1064 bool foundPath = genSingleLeakPath
1065 (
1066 markLeakPath,
1067 iter,
1068 mesh,
1069 (isBlockedFace ? *isBlockedFace : isBoundaryFace),
1070 insidePoint,
1071 insideCelli,
1072 outsidePoint,
1073 outsideCelli,
1074
1075 // Generated sampling points
1076 trackLength,
1077 samplingPts,
1078 samplingCells,
1079 samplingFaces,
1080 samplingSegments,
1081 samplingCurveDist,
1082
1083 // State of current leak paths
1084 isLeakCell,
1085 isLeakFace,
1086 isLeakPoint,
1087
1088 // Work storage
1091 );
1092
1093 // Recalculate the overall trackLength
1094 trackLength = returnReduce
1095 (
1096 (
1097 samplingCurveDist.size()
1098 ? samplingCurveDist.last()
1099 : 0
1100 ),
1102 );
1103
1104 const label nLeakFaces = returnReduce
1105 (
1106 isLeakFace.count(),
1107 sumOp<label>()
1108 );
1109
1110 if (!foundPath && !markLeakPath)
1111 {
1112 // In mark-boundary-face-only mode and already fully blocked the
1113 // path to outsideCell so we're good
1114 break;
1115 }
1116
1117
1118 if (nLeakFaces > nOldLeakFaces)
1119 {
1120 // Normal operation: walking has closed some wall-connected faces
1121 // If previous iteration was markLeakPath-mode make sure to revert
1122 // to normal operation (i.e. face marked in isLeakFace)
1123 isBlockedFace.reset(nullptr);
1124 markLeakPath = false;
1125 }
1126 else
1127 {
1128 // Did not mark any additional faces/points. Save current state
1129 // and add faces/points on leakpath to force next walk
1130 // to pass outside of leakpath. This is done until the leakpath
1131 // 'touchesWall' (i.e. edge connected to an original boundary face)
1132
1133 if (markLeakPath && !foundPath)
1134 {
1135 // Is marking all faces on all paths and no additional path
1136 // found. Also nothing new marked (in isLeakFace) since
1137 // nLeakFaces == nOldLeakFaces) so we're
1138 // giving up. Convert all path faces into leak faces
1139 //Pout<< "** giving up" << endl;
1140 gaveUp = true; // Mark that we're giving up
1141 break;
1142 }
1143
1144
1145 // Revert to boundaryFaces only
1146 if (!isBlockedFace)
1147 {
1148 //Pout<< "** Starting from original boundary faces." << endl;
1149 isBlockedFace.reset(new bitSet(isBoundaryFace));
1150 }
1151
1152 markLeakPath = true;
1153
1154
1155 if (debug & 2)
1156 {
1157 const pointField leakCcs(mesh.cellCentres(), isLeakCell.toc());
1158 mkDir(mesh.time().timePath());
1159 OBJstream str
1160 (
1161 mesh.time().timePath()
1162 /"isLeakCell" + Foam::name(iter) + ".obj"
1163 );
1164 Pout<< "Writing new isLeakCell to " << str.name() << endl;
1165 str.write(leakCcs);
1166 }
1167 if (debug & 2)
1168 {
1169 OBJstream str
1170 (
1171 mesh.time().timePath()
1172 /"leakPath" + Foam::name(iter) + ".obj"
1173 );
1174 Pout<< "Writing new leak-path to " << str.name() << endl;
1175 for
1176 (
1177 label samplei = oldNSamplingPts+1;
1178 samplei < samplingPts.size();
1179 samplei++
1180 )
1181 {
1182 Pout<< " passing through cell "
1183 << samplingCells[samplei]
1184 << " at:" << mesh.cellCentres()[samplingCells[samplei]]
1185 << " distance:" << samplingCurveDist[samplei]
1186 << endl;
1187
1188 str.writeLine
1189 (
1190 samplingPts[samplei-1],
1191 samplingPts[samplei]
1192 );
1193 }
1194 }
1195 }
1196 }
1197
1198 if (debug)
1199 {
1200 const fvMesh& fm = refCast<const fvMesh>(mesh);
1201
1202 const_cast<fvMesh&>(fm).setInstance(fm.time().timeName());
1204 (
1205 IOobject
1206 (
1207 "isLeakCell",
1208 fm.time().timeName(),
1209 fm,
1212 ),
1213 fm,
1215 );
1216 for (const label celli : isLeakCell)
1217 {
1218 fld[celli] = scalar(1);
1219 }
1220 fld.correctBoundaryConditions();
1221 fld.write();
1222 }
1223
1224 // Warn if we didn't successfully close the gap (either exhausted iterations or gave up)
1225 // Use returnReduce to ensure consistent check across all processors
1226 const bool shouldWarn = returnReduceOr(maxIter > 1 && (iter == maxIter || gaveUp));
1227 if (shouldWarn && Pstream::master())
1228 {
1229 WarningInFunction << "Did not manage to close gap using " << iter
1230 << " leak paths" << nl << "This can cause problems when using the"
1231 << " paths to close leaks" << endl;
1232 }
1233}
1234
1235
1236void Foam::shortestPathSet::genSamples
1237(
1238 const bool markLeakPath,
1239 const label maxIter,
1240 const polyMesh& mesh,
1241 const labelUList& wallPatches,
1242 const bitSet& isBlockedFace
1243)
1244{
1245 // Storage for sample points
1246 DynamicList<point> samplingPts;
1247 DynamicList<label> samplingCells;
1248 DynamicList<label> samplingFaces;
1249 DynamicList<label> samplingSegments;
1250 DynamicList<scalar> samplingCurveDist;
1251
1252 // Seed faces and points on 'real' boundary
1253 bitSet isBlockedPoint(mesh.nPoints());
1254 {
1255 // Real boundaries
1257 for (label patchi : wallPatches)
1258 {
1259 const polyPatch& pp = pbm[patchi];
1260 forAll(pp, i)
1261 {
1262 isBlockedPoint.set(pp[i]);
1263 }
1264 }
1265
1266 // Meshed boundaries
1267 forAll(isBlockedFace, facei)
1268 {
1269 if (isBlockedFace[facei])
1270 {
1271 isBlockedPoint.set(mesh.faces()[facei]);
1272 }
1273 }
1274
1276 (
1277 mesh,
1278 isBlockedPoint,
1280 0u
1281 );
1282
1283 if (debug)
1284 {
1285 mkDir(mesh.time().timePath());
1286 OBJstream str(mesh.time().timePath()/"isBlockedPoint.obj");
1287 for (const auto& pointi : isBlockedPoint)
1288 {
1289 str.write(mesh.points()[pointi]);
1290 }
1291 Pout<< "Writing " << str.nVertices()
1292 << " points to " << str.name() << endl;
1293 }
1294 }
1295
1296
1297 bitSet isLeakPoint(isBlockedPoint);
1298 // Newly closed faces
1299 bitSet isLeakFace(mesh.nFaces());
1300 // All cells along leak paths
1301 bitSet isLeakCell(mesh.nCells());
1302
1303 label prevSegmenti = 0;
1304 scalar prevDistance = 0.0;
1305
1306 // Force calculation of base points (needs to be synchronised)
1307 (void)mesh.tetBasePtIs();
1308
1309 const globalIndex& globalCells = mesh.globalData().globalMeshCellAddr();
1310
1311 for (auto insidePoint : insidePoints_)
1312 {
1313 // Find cell globally across all processors - handle processor boundaries
1314 label localInsideCelli = mesh.findCell(insidePoint);
1315 label globalInsideCelli = -1;
1316 if (localInsideCelli != -1)
1317 {
1318 globalInsideCelli = globalCells.toGlobal(localInsideCelli);
1319 }
1320 reduce(globalInsideCelli, maxOp<label>());
1321
1322 // If not found, try perturbation (points on processor boundaries)
1323 if (globalInsideCelli == -1)
1324 {
1325 const vector perturbVec = 1e-6 * (mesh.bounds().max() - mesh.bounds().min());
1326 localInsideCelli = mesh.findCell(insidePoint + perturbVec);
1327 if (localInsideCelli != -1)
1328 {
1329 globalInsideCelli = globalCells.toGlobal(localInsideCelli);
1330 }
1331 reduce(globalInsideCelli, maxOp<label>());
1332 }
1333
1334 // Convert back to local cell index on the processor that has it
1335 // CRITICAL: We need to know which processor has the cell for calculateDistance
1336 // Even if insideCelli == -1 on this processor, calculateDistance must still be called
1337 // because FaceCellWave propagates across processor boundaries
1338 label insideCelli = -1;
1339 label insideProcI = -1;
1340 if (globalInsideCelli != -1)
1341 {
1342 insideProcI = globalCells.whichProcID(globalInsideCelli);
1343 if (insideProcI == Pstream::myProcNo())
1344 {
1345 insideCelli = globalCells.toLocal(insideProcI, globalInsideCelli);
1346 }
1347 }
1348
1349 // Debug output
1350 if (debug)
1351 {
1352 Pout<< "Inside point " << insidePoint
1353 << " -> global cell " << globalInsideCelli
1354 << " on proc " << insideProcI
1355 << ", local cell on proc " << Pstream::myProcNo() << ": " << insideCelli << endl;
1356 }
1357
1358 for (auto outsidePoint : outsidePoints_)
1359 {
1360 const label nOldSamples = samplingSegments.size();
1361
1362 // Append any leak path to sampling*
1363 genSamples
1364 (
1365 markLeakPath,
1366 maxIter,
1367 mesh,
1369 insidePoint,
1370 insideCelli,
1371 outsidePoint,
1372
1373 samplingPts,
1374 samplingCells,
1375 samplingFaces,
1376 samplingSegments,
1377 samplingCurveDist,
1378 isLeakCell,
1379 isLeakFace,
1380 isLeakPoint
1381 );
1382
1383 // Make segment, distance consecutive
1384 label maxSegment = 0;
1385 scalar maxDistance = 0.0;
1386 for (label i = nOldSamples; i < samplingSegments.size(); ++i)
1387 {
1388 samplingSegments[i] += prevSegmenti;
1389 maxSegment = max(maxSegment, samplingSegments[i]);
1390 samplingCurveDist[i] += prevDistance;
1391 maxDistance = max(maxDistance, samplingCurveDist[i]);
1392 }
1393 prevSegmenti = returnReduce(maxSegment, maxOp<label>());
1394 prevDistance = returnReduce(maxDistance, maxOp<scalar>());
1395 }
1396 }
1397
1398 // Clean up leak faces (erode open edges). These are leak faces which are
1399 // not connected to another leak face or leak point
1400 erodeFaceSet(mesh, isBlockedPoint, isLeakFace);
1401
1402 leakFaces_ = isLeakFace.sortedToc();
1403
1404
1405 if (debug)
1406 {
1407 const faceList leakFaces(mesh.faces(), leakFaces_);
1408
1409 mkDir(mesh.time().timePath());
1410 OBJstream str(mesh.time().timePath()/"isLeakFace.obj");
1411 str.write(leakFaces, mesh.points(), false);
1412 Pout<< "Writing " << leakFaces.size()
1413 << " faces to " << str.name() << endl;
1414 }
1415
1416
1417 samplingPts.shrink();
1418 samplingCells.shrink();
1419 samplingFaces.shrink();
1420 samplingSegments.shrink();
1421 samplingCurveDist.shrink();
1422
1423 // Move into *this
1424 setSamples
1425 (
1426 std::move(samplingPts),
1427 std::move(samplingCells),
1428 std::move(samplingFaces),
1429 std::move(samplingSegments),
1430 std::move(samplingCurveDist)
1431 );
1432
1433 if (debug)
1434 {
1435 write(Info);
1436 }
1437}
1438
1439
1440// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1441
1443(
1444 const word& name,
1445 const polyMesh& mesh,
1446 const meshSearch& searchEngine,
1447 const word& axis,
1448 const bool markLeakPath,
1449 const label maxIter,
1450 const labelUList& wallPatches,
1451 const pointField& insidePoints,
1452 const pointField& outsidePoints,
1453 const boolList& isBlockedFace
1454)
1455:
1457 insidePoints_(insidePoints),
1458 outsidePoints_(outsidePoints)
1459{
1460 if (debug)
1461 {
1462 fileName outputDir
1463 (
1464 mesh.time().globalPath()
1466 / mesh.pointsInstance()
1467 );
1468 outputDir.clean(); // Remove unneeded ".."
1469
1470 Info<< "shortestPathSet : Writing blocked faces to "
1471 << outputDir << endl;
1472
1473 const indirectPrimitivePatch setPatch
1474 (
1476 (
1477 mesh.faces(),
1479 ),
1480 mesh.points()
1481 );
1482
1483 if (Pstream::parRun())
1484 {
1485 // Topological merge
1486 labelList pointToGlobal;
1487 labelList uniqueMeshPointLabels;
1489 autoPtr<globalIndex> globalFaces;
1490 faceList mergedFaces;
1491 pointField mergedPoints;
1493 (
1494 mesh,
1495 setPatch.localFaces(),
1496 setPatch.meshPoints(),
1497 setPatch.meshPointMap(),
1498
1499 pointToGlobal,
1500 uniqueMeshPointLabels,
1502 globalFaces,
1503
1504 mergedFaces,
1505 mergedPoints
1506 );
1507
1508 // Write
1509 if (Pstream::master())
1510 {
1512 (
1513 mergedPoints,
1514 mergedFaces,
1515 (outputDir / "blockedFace"),
1516 false // serial only - already merged
1517 );
1518
1519 writer.writeGeometry();
1520 }
1521 }
1522 else
1523 {
1525 (
1526 setPatch.localPoints(),
1527 setPatch.localFaces(),
1528 (outputDir / "blockedFace"),
1529 false // serial only - redundant
1530 );
1531
1532 writer.writeGeometry();
1533 }
1534 }
1535
1536 genSamples
1537 (
1538 markLeakPath,
1539 maxIter,
1540 mesh,
1541 wallPatches,
1543 );
1544}
1546
1548(
1549 const word& name,
1550 const polyMesh& mesh,
1551 const meshSearch& searchEngine,
1552 const dictionary& dict
1553)
1554:
1556 insidePoints_(dict.get<pointField>("insidePoints")),
1557 outsidePoints_(dict.get<pointField>("outsidePoints"))
1558{
1559 const label maxIter(dict.getOrDefault<label>("maxIter", 50));
1560 const bool markLeakPath(dict.getOrDefault("markLeakPath", true));
1561
1562 const polyBoundaryMesh& pbm = mesh.boundaryMesh();
1563
1564 DynamicList<label> wallPatches(pbm.size());
1565 forAll(pbm, patchi)
1566 {
1567 const polyPatch& pp = pbm[patchi];
1568 if (!pp.coupled() && !isA<emptyPolyPatch>(pp))
1569 {
1570 wallPatches.append(patchi);
1571 }
1572 }
1573
1574 genSamples(markLeakPath, maxIter, mesh, wallPatches, bitSet());
1575}
1576
1577
1578// ************************************************************************* //
scalar y
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
Info<< nl;Info<< "Write faMesh in vtk format:"<< nl;{ vtk::uindirectPatchWriter writer(aMesh.patch(), fileName(aMesh.time().globalPath()/vtkBaseFileName));writer.writeGeometry();globalIndex procAddr(aMesh.nFaces());labelList cellIDs;if(UPstream::master()) { cellIDs.resize(procAddr.totalSize());for(const labelRange &range :procAddr.ranges()) { auto slice=cellIDs.slice(range);slice=identity(range);} } writer.beginCellData(4);writer.writeProcIDs();writer.write("cellID", cellIDs);writer.write("area", aMesh.S().field());writer.write("normal", aMesh.faceAreaNormals());writer.beginPointData(1);writer.write("normal", aMesh.pointAreaNormals());Info<< " "<< writer.output().name()<< nl;}{ vtk::lineWriter writer(aMesh.points(), aMesh.edges(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edges")));writer.writeGeometry();writer.beginCellData(4);writer.writeProcIDs();{ Field< scalar > fld(faMeshTools::flattenEdgeField(aMesh.magLe(), true))
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edgesCentres")))
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const polyBoundaryMesh & pbm
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
Wave propagation of information through grid. Every iteration information goes through one layer of c...
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
@ NO_READ
Nothing to be read.
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
const Addr & addressing() const noexcept
The addressing used for the list.
A List with indirect addressing.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
An OFstream that keeps track of vertices and provides convenience output methods for OBJ files.
Definition OBJstream.H:58
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition PackedList.H:387
label size() const noexcept
Number of entries.
Definition PackedList.H:392
void reset()
Clear all bits but do not adjust the addressable size.
static void matchEdges(const PrimitivePatch< FaceList1, PointField1 > &p1, const PrimitivePatch< FaceList2, PointField2 > &p2, labelList &p1EdgeLabels, labelList &p2EdgeLabels, bitSet &sameOrientation)
Find corresponding edges on patches sharing the same points.
static void gatherAndMerge(const scalar mergeDist, const PrimitivePatch< FaceList, PointField > &pp, Field< typename PrimitivePatch< FaceList, PointField >::point_type > &mergedPoints, List< typename PrimitivePatch< FaceList, PointField >::face_type > &mergedFaces, globalIndex &pointAddr, globalIndex &faceAddr, labelList &pointMergeMap=const_cast< labelList & >(labelList::null()), const bool useLocal=false)
Gather points and faces onto master and merge into single patch.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
const Map< label > & meshPointMap() const
Mesh point map.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
const Field< point_type > & localPoints() const
Return pointField of points in patch.
const labelListList & edgeFaces() const
Return edge-face addressing.
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
static void combineReduce(T &value, CombineOp cop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors.
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie,...
Definition PtrList.H:171
A non-owning sub-view of a List (allocated or unallocated storage).
Definition SubList.H:61
fileName timePath() const
Return current time path = path/timeName.
Definition Time.H:512
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition Tuple2.H:51
A List with indirect addressing. Like IndirectList but does not store addressing.
bool get(const label i) const
Definition UList.H:868
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:99
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
const point & max() const noexcept
Maximum describing the bounding box.
Definition boundBoxI.H:168
const point & min() const noexcept
Minimum describing the bounding box.
Definition boundBoxI.H:162
const word & axis() const
The sort axis name.
Definition coordSet.H:160
const scalarList & distance() const noexcept
Return the cumulative distance.
Definition coordSet.H:176
const word & name() const noexcept
The coord-set name.
Definition coordSet.H:152
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
Smooth ATC in cells next to a set of patches supplied by type.
Definition faceCells.H:55
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
A class for handling file names.
Definition fileName.H:75
static bool clean(std::string &str)
Cleanup filename string, possibly applies other transformations such as changing the path separator e...
Definition fileName.C:192
static word outputPrefix
Directory prefix.
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
const Time & time() const
Return the top-level database.
Definition fvMesh.H:360
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition globalIndex.H:77
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
const globalIndex & globalMeshCellAddr() const noexcept
Global numbering for mesh cells.
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
label nTotalCells() const noexcept
Total global number of mesh cells.
Calculates points shared by more than two processor patches or cyclic patches.
LocalMin-mean differencing scheme class.
Definition localMin.H:58
Class containing processor-to-processor mapping information.
Various (local, not parallel) searches on polyMesh; uses (demand driven) octree to search.
Definition meshSearch.H:57
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
virtual const faceList & faces() const
Return raw faces.
Definition polyMesh.C:1088
label findCell(const point &p, const cellDecomposition=CELL_TETS) const
Find cell enclosing this location and return index.
Definition polyMesh.C:1496
virtual const labelList & faceOwner() const
Return face owner.
Definition polyMesh.C:1101
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition polyMesh.C:884
const globalMeshData & globalData() const
Return parallel info (demand-driven).
Definition polyMesh.C:1296
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition polyMesh.C:1107
const boundBox & bounds() const noexcept
Return mesh bounding box.
Definition polyMesh.H:617
virtual const pointField & points() const
Return raw points.
Definition polyMesh.C:1063
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces).
const vectorField & faceCentres() const
label nInternalFaces() const noexcept
Number of internal faces.
const vectorField & cellCentres() const
label nPoints() const noexcept
Number of mesh points.
label nCells() const noexcept
Number of mesh cells.
label nFaces() const noexcept
Number of mesh faces.
const cellList & cells() const
Holds list of sampling points which is filled at construction time. Various implementations of this b...
Definition sampledSet.H:82
const meshSearch & searchEngine() const noexcept
Definition sampledSet.H:378
sampledSet(const word &name, const polyMesh &mesh, const meshSearch &searchEngine, const coordSet::coordFormat axisType)
Construct from components.
Definition sampledSet.C:405
const polyMesh & mesh() const noexcept
Definition sampledSet.H:373
Finds shortest path (in terms of cell centres) to walk on mesh from any point in insidePoints to any ...
shortestPathSet(const word &name, const polyMesh &mesh, const meshSearch &searchEngine, const word &axis, const bool markLeakPath, const label maxIter, const labelUList &wallPatches, const pointField &insidePoints, const pointField &outsidePoints, const boolList &blockedFace)
Construct from components. blockedFace is an optional specification.
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled boundary face values. Uses eqOp.
Definition syncTools.H:524
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const bool parRun=UPstream::parRun())
Synchronize values on all mesh faces.
Definition syncTools.H:465
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
For use with FaceCellWave. Determines topological distance to starting faces. Templated on passive tr...
Write faces/points (optionally with fields) as a vtp file or a legacy vtk file.
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
volScalarField & p
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
List< wallPoints > allFaceInfo(mesh_.nFaces())
const bitSet isBlockedFace(intersectedFaces())
FaceCellWave< wallPoints, wallPoints::trackData > wallDistCalc(mesh_, changedFaces, faceDist, allFaceInfo, allCellInfo, 0, td)
List< wallPoints > allCellInfo(mesh_.nCells())
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
scalar distance(const vector &p1, const vector &p2)
Definition curveTools.C:12
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
const dimensionSet dimless
Dimensionless.
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
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:616
GeometricField< scalar, fvPatchField, volMesh > volScalarField
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
constexpr label labelMax
Definition label.H:55
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
vector point
Point is a vector.
Definition point.H:37
List< bool > boolList
A List of bools.
Definition List.H:60
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
vectorField pointField
pointField is a vectorField.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Vector< scalar > vector
Definition vector.H:57
labelList findIndices(const ListType &input, typename ListType::const_reference val, label start=0)
Linear search to find all occurrences of given element.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
UList< label > labelUList
A UList of labels.
Definition UList.H:75
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
runTime write()
labelList f(nPoints)
insidePoints((1 2 3))
dictionary dict
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Assign tuple-like container to use the one with the smaller value of first.
Definition Tuple2.H:257