regionSplit.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) 2011-2013 OpenFOAM Foundation
9 Copyright (C) 2018-2020 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "regionSplit.H"
30#include "cyclicPolyPatch.H"
31#include "processorPolyPatch.H"
32#include "globalIndex.H"
33#include "syncTools.H"
34#include "clockValue.H"
35
36// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37
38namespace Foam
39{
41}
42
43static constexpr Foam::label UNASSIGNED = -1;
44static constexpr Foam::label BLOCKED = -2;
45
46
47// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
48
49namespace Foam
50{
51
52//- The sizes of a List of containers (eg, labelHashSet)
53template<class Container>
55{
56 const label len = input.size();
57
58 labelList output(len);
59
60 for (label i = 0; i < len; ++i)
61 {
62 output[i] = input[i].size();
63 }
64
65 return output;
66}
67
68} // End namespace Foam
69
70
71// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
72
73void Foam::regionSplit::checkBoundaryFaceSync
74(
75 const boolList& blockedFace
76) const
77{
78 if (blockedFace.size())
79 {
80 // Check that blockedFace is synced.
81 boolList syncBlockedFace(blockedFace);
82 syncTools::swapFaceList(mesh(), syncBlockedFace);
83
84 forAll(syncBlockedFace, facei)
85 {
86 if
87 (
88 blockedFace.test(facei)
89 != syncBlockedFace.test(facei)
90 )
91 {
93 << "Face " << facei << " not synchronised. My value:"
94 << blockedFace.test(facei) << " coupled value:"
95 << syncBlockedFace.test(facei) << nl
96 << abort(FatalError);
97 }
98 }
99 }
100}
101
102
103void Foam::regionSplit::updateFacePair
104(
105 const label face0,
106 const label face1,
107
108 labelList& faceRegion,
109 DynamicList<label>& facesChanged
110) const
111{
112 if (faceRegion[face0] == UNASSIGNED)
113 {
114 if (faceRegion[face1] >= 0)
115 {
116 faceRegion[face0] = faceRegion[face1];
117 facesChanged.append(face0);
118 }
119 else if (faceRegion[face1] == BLOCKED)
120 {
121 // face1 blocked but not face0.
122 // - illegal for coupled faces, OK for explicit connections.
123 }
124 }
125 else if (faceRegion[face0] >= 0)
126 {
127 if (faceRegion[face1] == UNASSIGNED)
128 {
129 faceRegion[face1] = faceRegion[face0];
130 facesChanged.append(face1);
131 }
132 else if (faceRegion[face1] == BLOCKED)
133 {
134 // face1 blocked but not face0.
135 // - illegal for coupled faces, OK for explicit connections.
136 }
137 else if (faceRegion[face1] != faceRegion[face0])
138 {
140 << "Problem : coupled face " << face0
141 << " on patch " << mesh().boundaryMesh().whichPatch(face0)
142 << " has region " << faceRegion[face0]
143 << " but coupled face " << face1
144 << " has region " << faceRegion[face1] << nl
145 << "Is your blocked faces specification"
146 << " synchronized across coupled boundaries?" << endl
147 << abort(FatalError);
148 }
149 }
150}
151
152
153void Foam::regionSplit::fillSeedMask
154(
155 const UList<labelPair>& explicitConnections,
156 const label seedCellId,
157 const label markValue,
158 labelList& cellRegion,
159 labelList& faceRegion
160) const
161{
162 // Seed cell
163 cellRegion[seedCellId] = markValue;
164
165 // Faces on seed cell
166 changedFaces_.clear();
167 for (const label facei : mesh().cells()[seedCellId])
168 {
169 if (faceRegion[facei] == UNASSIGNED)
170 {
171 faceRegion[facei] = markValue;
172 changedFaces_.append(facei);
173 }
174 }
175
176 const polyBoundaryMesh& patches = mesh().boundaryMesh();
177
178 // Loop over changed faces. FaceCellWave in small.
179
180 while (changedFaces_.size())
181 {
182 changedCells_.clear();
183
184 for (const label facei : changedFaces_)
185 {
186 const label own = mesh().faceOwner()[facei];
187
188 if (cellRegion[own] == UNASSIGNED)
189 {
190 cellRegion[own] = markValue;
191 changedCells_.append(own);
192 }
193
194 if (mesh().isInternalFace(facei))
195 {
196 const label nei = mesh().faceNeighbour()[facei];
197
198 if (cellRegion[nei] == UNASSIGNED)
199 {
200 cellRegion[nei] = markValue;
201 changedCells_.append(nei);
202 }
203 }
204 }
205
206 if (debug & 2)
207 {
208 Pout<< " Changed cells / faces : "
209 << changedCells_.size() << " / " << changedFaces_.size()
210 << " before sync" << endl;
211 }
212
213 // Loop over changedCells and collect faces
214 changedFaces_.clear();
215 for (const label celli : changedCells_)
216 {
217 for (const label facei : mesh().cells()[celli])
218 {
219 if (faceRegion[facei] == UNASSIGNED)
220 {
221 faceRegion[facei] = markValue;
222 changedFaces_.append(facei);
223 }
224 }
225 }
226
227
228 // Update locally coupled faces
229 // Global connections are done later.
230
231 for (const polyPatch& pp : patches)
232 {
233 const cyclicPolyPatch* cpp = isA<cyclicPolyPatch>(pp);
234
235 if (cpp && cpp->owner())
236 {
237 // Transfer from neighbourPatch to here or vice versa.
238 const auto& cycPatch = *cpp;
239
240 label face0 = cycPatch.start();
241
242 forAll(cycPatch, i)
243 {
244 const label face1 = cycPatch.transformGlobalFace(face0);
245
246 updateFacePair
247 (
248 face0,
249 face1,
250 faceRegion,
251 changedFaces_
252 );
253
254 ++face0;
255 }
256 }
257 }
258
259 for (const labelPair& pr : explicitConnections)
260 {
261 updateFacePair
262 (
263 pr.first(),
264 pr.second(),
265 faceRegion,
266 changedFaces_
267 );
268 }
269
270 if (debug & 2)
271 {
272 Pout<< " Changed faces : "
273 << changedFaces_.size()
274 << " after sync" << endl;
275 }
276 }
277}
278
279
280Foam::label Foam::regionSplit::localRegionSplit
281(
282 const UList<labelPair>& explicitConnections,
283
284 labelList& cellRegion,
285 labelList& faceRegion
286) const
287{
288 clockValue timing(debug);
289
290 changedCells_.reserve(mesh_.nCells());
291 changedFaces_.reserve(mesh_.nFaces());
292
293
294 // Assign local regions
295 // ~~~~~~~~~~~~~~~~~~~~
296
297 // Start with region 0
298 label nLocalRegions = 0;
299
300 for (label seedCellId = 0; seedCellId < cellRegion.size(); ++seedCellId)
301 {
302 // Find next unset cell - use as seed
303
304 for (; seedCellId < cellRegion.size(); ++seedCellId)
305 {
306 if (cellRegion[seedCellId] == UNASSIGNED)
307 {
308 break;
309 }
310 }
311
312 if (seedCellId >= cellRegion.size())
313 {
314 break;
315 }
316
317 fillSeedMask
318 (
319 explicitConnections,
320 seedCellId,
321 nLocalRegions,
322 cellRegion,
323 faceRegion
324 );
325
326 ++nLocalRegions; // Next region
327 }
328
329 // Discard temporary working data
330 changedCells_.clearStorage();
331 changedFaces_.clearStorage();
332
333 if (debug)
334 {
335 forAll(cellRegion, celli)
336 {
337 if (cellRegion[celli] < 0)
338 {
340 << "cell:" << celli << " region:" << cellRegion[celli]
341 << abort(FatalError);
342 }
343 }
344
345 forAll(faceRegion, facei)
346 {
347 if (faceRegion[facei] == UNASSIGNED)
348 {
350 << "face:" << facei << " region:" << faceRegion[facei]
351 << abort(FatalError);
352 }
353 }
354 }
355
356 DebugInfo << "regionSplit = " << double(timing.elapsed()) << "s\n";
357
358 return nLocalRegions;
359}
360
361
362// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
363
365(
366 const polyMesh& mesh,
367 const bool doGlobalRegions
368)
369:
371 (
372 mesh,
373 bitSet(), // No blockedFace
374 List<labelPair>(), // No explicitConnections
375 doGlobalRegions
376 )
377{}
378
379
381(
382 const polyMesh& mesh,
383 const bitSet& blockedFace,
384 const List<labelPair>& explicitConnections,
385 const bool doGlobalRegions
386)
387:
389 labelList(mesh.nCells(), UNASSIGNED),
390 globalNumbering_()
391{
392 // if (debug)
393 // {
394 // checkBoundaryFaceSync(blockedFace);
395 // }
396
397 labelList& cellRegion = *this;
398
399 labelList faceRegion(mesh.nFaces(), UNASSIGNED);
400
401 for (const label facei : blockedFace)
402 {
403 faceRegion[facei] = BLOCKED;
404 }
405
406 const label numLocalRegions =
407 localRegionSplit(explicitConnections, cellRegion, faceRegion);
408
409 faceRegion.clear();
410
411 if (doGlobalRegions)
412 {
413 // Wrap bitset or bools
414 bitSetOrBoolList hasBlockedFace(blockedFace);
415
416 globalNumbering_ =
417 reduceRegionsImpl(numLocalRegions, hasBlockedFace, cellRegion);
418
419 }
420 else
421 {
422 globalNumbering_ = globalIndex(numLocalRegions);
423 }
424}
425
426
428(
429 const polyMesh& mesh,
430 const boolList& blockedFace,
431 const List<labelPair>& explicitConnections,
432 const bool doGlobalRegions
433)
434:
436 labelList(mesh.nCells(), UNASSIGNED),
437 globalNumbering_()
438{
439 if (debug)
440 {
441 checkBoundaryFaceSync(blockedFace);
442 }
443
444 labelList& cellRegion = *this;
445
446 labelList faceRegion(mesh.nFaces(), UNASSIGNED);
447
448 forAll(blockedFace, facei)
449 {
450 if (blockedFace.test(facei))
451 {
452 faceRegion[facei] = BLOCKED;
453 }
454 }
455
456
457 const label numLocalRegions =
458 localRegionSplit(explicitConnections, cellRegion, faceRegion);
459
460 faceRegion.clear();
461
462 if (doGlobalRegions)
463 {
464 // Wrap bitset or bools
465 bitSetOrBoolList hasBlockedFace(blockedFace);
466
467 globalNumbering_ =
468 reduceRegionsImpl(numLocalRegions, hasBlockedFace, cellRegion);
469 }
470 else
471 {
472 globalNumbering_ = globalIndex(numLocalRegions);
473 }
474}
475
476
477// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
478
480Foam::regionSplit::reduceRegionsImpl
481(
482 const label numLocalRegions,
483 const bitSetOrBoolList& blockedFace,
484 labelList& cellRegion
485) const
486{
487 clockValue timing(debug);
488
489 if (cellRegion.size() != mesh().nCells())
490 {
492 << "The cellRegion size " << cellRegion.size()
493 << " != number of cells " << mesh().nCells() << endl
494 << abort(FatalError);
495 }
496
497
498 // (numLocalRegions < 0) to signal that region information should be
499 // determined ourselves. This is not really efficient, but can be useful
500
501 const label nLocalRegions =
502 (
503 numLocalRegions < 0
504 ? labelHashSet(cellRegion).size()
505 : numLocalRegions
506 );
507
508
509 // Preliminary global region numbers
510 const globalIndex globalRegions(nLocalRegions);
511
512
513 // Lookup table of local region to global region.
514 // Initially an identity mapping of the uncombined global values.
515
516 Map<label> localToGlobal(2*nLocalRegions);
517 for (const label regioni : cellRegion)
518 {
519 localToGlobal.insert(regioni, globalRegions.toGlobal(regioni));
520 }
521
522 // To update the localToGlobal mapping during traversal of the boundaries
523 // and later when finalizing things.
524 Map<label> updateLookup(2*nLocalRegions);
525
526
527 // Note that we use two separate maps during the process.
528 // The localToGlobal is used to map the local to global regions.
529 // Merging across processors will normally make this a many->few mapping.
530 // However, we may need to walk up and down processor boundaries several
531 // times before all the information propagates through.
532 // During these traversals, it will normally be more efficient to just
533 // update the mapping without updating the cellRegion immediately.
534 // Only after everything is finalized do we renumber all of the cell
535 // regions.
536
537
538 // Merge global regions
539 // ~~~~~~~~~~~~~~~~~~~~
540 // Regions across non-blocked proc patches get merged.
541 // This will set merged global regions to be the min of both.
542 // (this will create gaps in the global region list so they will get
543 // merged later on)
544
545 const polyBoundaryMesh& patches = mesh().boundaryMesh();
546
547 // Buffer for swapping boundary information
548 labelList nbrRegion(mesh().nBoundaryFaces());
549
550 bool emitWarning = true;
551
552 do
553 {
554 if (debug)
555 {
556 Pout<< nl << "-- Starting Iteration --" << endl;
557 }
558
559 updateLookup.clear();
560 nbrRegion = UNASSIGNED;
561
562 // Region information to send
563 for (const polyPatch& pp : patches)
564 {
565 if (pp.coupled())
566 {
567 SubList<label> patchNbrRegion
568 (
569 nbrRegion,
570 pp.size(),
571 pp.offset()
572 );
573
574 const labelUList& faceCells = pp.faceCells();
575 forAll(faceCells, patchFacei)
576 {
577 const label celli = faceCells[patchFacei];
578 const label meshFacei = pp.start()+patchFacei;
579
580 if (!blockedFace.test(meshFacei))
581 {
582 // Send the most currently updated region Id
583 const label orig = cellRegion[celli];
584
585 patchNbrRegion[patchFacei] = localToGlobal[orig];
586 }
587 }
588 }
589 }
591
592 // Receive and reduce region information
593 for (const polyPatch& pp : patches)
594 {
595 if (pp.coupled())
596 {
597 SubList<label> patchNbrRegion
598 (
599 nbrRegion,
600 pp.size(),
601 pp.offset()
602 );
603
604 const labelUList& faceCells = pp.faceCells();
605 forAll(faceCells, patchFacei)
606 {
607 const label celli = faceCells[patchFacei];
608 const label meshFacei = pp.start()+patchFacei;
609
610 if (!blockedFace.test(meshFacei))
611 {
612 // Reduction by retaining the min region id.
613
614 const label orig = cellRegion[celli];
615
616 const label sent = localToGlobal[orig];
617 const label recv = patchNbrRegion[patchFacei];
618
619 if (recv == UNASSIGNED)
620 {
621 if (emitWarning)
622 {
623 Pout<<"Warning in regionSplit:"
624 " received unassigned on "
625 << pp.name() << " at patchFace "
626 << patchFacei
627 << ". Check synchronisation in caller"
628 << nl;
629 }
630 }
631 else if (recv < sent)
632 {
633 // Record the minimum value seen
634
635 auto fnd = updateLookup.find(sent);
636 if (!fnd.found())
637 {
638 updateLookup.insert(sent, recv);
639 }
640 else if (recv < *fnd)
641 {
642 *fnd = recv;
643 }
644 }
645 }
646 }
647 }
648 }
649
650
651 // Note: by always using the minimum region number across the
652 // processor faces, we effect a consolidation of connected regions
653 // and converge to a unique number for each distinct region.
654
655
656 // Update localToGlobal according to newly exchanged information
657
658 inplaceMapValue(updateLookup, localToGlobal);
659
660 if (debug & 2)
661 {
662 labelList keys(localToGlobal.sortedToc());
663 labelList vals(keys.size());
664 forAll(keys, i)
665 {
666 vals[i] = localToGlobal[keys[i]];
667 }
668
669 Pout<< "Updated local regions:" << nl
670 << "old: " << flatOutput(keys) << nl
671 << "new: " << flatOutput(vals) << endl;
672 }
673 else if (debug)
674 {
675 Pout<< "Updated " << localToGlobal.size()
676 << " local regions" << endl;
677 }
678
679 emitWarning = false;
680 // Continue until there are no further changes
681 }
682 while (returnReduce(!updateLookup.empty(), orOp<bool>()));
683
684
685 //
686 // We will need compact numbers locally and non-locally
687 //
688
689 // Determine the local compact numbering
690 label nCompact = 0;
691 {
692 labelHashSet localRegion(2*localToGlobal.size());
693
694 forAllConstIters(localToGlobal, iter)
695 {
696 const label regioni = iter.val();
697
698 if (globalRegions.isLocal(regioni))
699 {
700 localRegion.insert(regioni);
701 }
702 }
703
704 nCompact = localRegion.size();
705 }
706
707
708 // The new global numbering using compacted local regions
709 globalIndex globalCompact(nCompact);
710
711
712 // Determine the following:
713 // - the local compact regions (store as updateLookup)
714 // - the non-local regions, ordered according to the processor on which
715 // they are local.
716
717
718 // The local compaction map (updated local to compact local numbering)
719 updateLookup.clear();
720
721 labelListList sendNonLocal(Pstream::nProcs());
722
723 {
724 List<labelHashSet> nonLocal(Pstream::nProcs(), labelHashSet(0));
725
726 // Use estimate of sizing for non-local regions
727 forAll(nonLocal, proci)
728 {
729 if (proci != Pstream::myProcNo())
730 {
731 nonLocal[proci].resize
732 (
733 2*((nLocalRegions-nCompact)/Pstream::nProcs())
734 );
735 }
736 }
737
738
739 forAllConstIters(localToGlobal, iter)
740 {
741 const label regioni = iter.val();
742
743 if (globalRegions.isLocal(regioni))
744 {
745 updateLookup.insert
746 (
747 regioni,
748 globalCompact.toGlobal(updateLookup.size())
749 );
750 }
751 else
752 {
753 nonLocal[globalRegions.whichProcID(regioni)].insert(regioni);
754 }
755 }
756
757 if (debug)
758 {
759 Pout<< " per processor nonLocal regions: "
760 << flatOutput(containerSizes(nonLocal)) << endl;
761 }
762
763
764 // Convert to label list
765 forAll(sendNonLocal, proci)
766 {
767 sendNonLocal[proci] = nonLocal[proci].toc();
768 }
769 }
770
771
772 // Get the wanted region labels into recvNonLocal
773 labelListList recvNonLocal;
774 Pstream::exchange<labelList, label>
775 (
776 sendNonLocal,
777 recvNonLocal
778 );
779
780
781 // The recvNonLocal[proci] region labels are what proci requires.
782 // Transcribe into their compacted number.
783
784 {
785 labelListList sendLocal(std::move(recvNonLocal));
786
787 for (labelList& send : sendLocal)
788 {
789 for (label& regioni : send)
790 {
791 regioni = updateLookup[regioni];
792 }
793 }
794
795 // Send back (into recvNonLocal)
796 Pstream::exchange<labelList, label>
797 (
798 sendLocal,
799 recvNonLocal
800 );
801 }
802
803
804 // Now recvNonLocal and sendNonLocal contain matched pairs with
805 // sendNonLocal being the non-compact region and recvNonLocal being
806 // the compact region.
807 //
808 // Insert these into the local compaction map.
809
810 forAll(recvNonLocal, proci)
811 {
812 const labelList& send = sendNonLocal[proci];
813 const labelList& recv = recvNonLocal[proci];
814
815 forAll(send, i)
816 {
817 updateLookup.insert(send[i], recv[i]);
818 }
819 }
820
821
822 // Now renumber the localToGlobal to use the final compact global values
823 inplaceMapValue(updateLookup, localToGlobal);
824
825
826 // Can now finally use localToGlobal to renumber cellRegion
827
828 forAll(cellRegion, celli)
829 {
830 cellRegion[celli] = localToGlobal[cellRegion[celli]];
831 }
832
834 <<"regionSplit::reduceRegions = " << double(timing.elapsed()) << "s\n";
835
836 return globalCompact;
837}
838
839
842(
843 const label numLocalRegions,
844 const bitSet& blockedFace,
845
846 labelList& cellRegion
847) const
848{
849 // Wrap bitset or bools
850 bitSetOrBoolList hasBlockedFace(blockedFace);
851
852 return reduceRegionsImpl(numLocalRegions, hasBlockedFace, cellRegion);
853}
854
855
856// ************************************************************************* //
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
Templated abstract base-class for optional mesh objects used to automate their allocation to the mesh...
Definition: MeshObject.H:91
virtual const fileName & name() const
Get the name of the stream.
Definition: OSstream.H:107
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
void clear()
Clear the PtrList. Delete allocated entries and set size to zero.
Definition: PtrListI.H:97
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:94
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type test(const label i) const
Definition: UList.H:518
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:66
Access to high-resolution clock value with some basic operations. Used to calculate time durations,...
Definition: clockValue.H:54
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1127
label nCells() const noexcept
Number of mesh cells.
label nFaces() const noexcept
Number of mesh faces.
int myProcNo() const noexcept
Return processor number.
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:144
globalIndex reduceRegions(const label numLocalRegions, const bitSet &blockedFace, labelList &cellRegion) const
Manually consolidate regions globally by swapping information.
Definition: regionSplit.C:842
static void swapFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled face values. Uses eqOp.
Definition: syncTools.H:478
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:445
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const cellShapeList & cells
#define DebugInfo
Report an information message using Foam::Info.
Namespace for OpenFOAM.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:57
List< label > labelList
A List of labels.
Definition: List.H:66
static Istream & input(Istream &is, IntRange< T > &range)
Definition: IntRanges.C:55
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
label inplaceMapValue(const labelUList &oldToNew, Container &input)
Map values. Ignore negative values.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:215
errorManip< error > abort(error &err)
Definition: errorManip.H:144
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:66
List< bool > boolList
A List of bools.
Definition: List.H:64
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
error FatalError
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
UList< label > labelUList
A UList of labels.
Definition: UList.H:85
static labelList containerSizes(const UList< Container > &input)
The sizes of a List of containers (eg, labelHashSet)
Definition: regionSplit.C:54
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
static constexpr Foam::label UNASSIGNED
Definition: regionSplit.C:43
static constexpr Foam::label BLOCKED
Definition: regionSplit.C:44
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition: stdFoam.H:278