Loading...
Searching...
No Matches
meshToMeshParallelOps.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) 2012-2017 OpenFOAM Foundation
9 Copyright (C) 2015-2023 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 "meshToMesh.H"
30#include "OFstream.H"
31#include "Time.H"
32#include "globalIndex.H"
33#include "mergePoints.H"
34#include "processorPolyPatch.H"
35#include "SubField.H"
36#include "AABBTree.H"
37#include "cellBox.H"
38
39// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40
41Foam::label Foam::meshToMesh::calcDistribution
42(
43 const polyMesh& src,
44 const polyMesh& tgt
45) const
46{
47 label proci = 0;
48
49 if (Pstream::parRun())
50 {
51 const bitSet hasMesh
52 (
54 (
55 src.nCells() > 0 || tgt.nCells() > 0
56 )
57 );
58
59 const auto nHaveMesh = hasMesh.count();
60
61 if (nHaveMesh == 1)
62 {
63 proci = hasMesh.find_first();
65 << "Meshes local to processor" << proci << endl;
66 }
67 else if (nHaveMesh > 1)
68 {
69 proci = -1;
71 << "Meshes split across multiple processors" << endl;
72 }
73
74 Pstream::broadcast(proci);
75 }
76
77 return proci;
78}
79
80
81Foam::label Foam::meshToMesh::calcOverlappingProcs
82(
83 const List<treeBoundBoxList>& procBb,
84 const boundBox& bb,
85 boolList& overlaps
86) const
87{
88 overlaps = false;
89
90 label nOverlaps = 0;
91
92 forAll(procBb, proci)
93 {
94 const treeBoundBoxList& bbp = procBb[proci];
95
96 for (const treeBoundBox& b : bbp)
97 {
98 if (b.overlaps(bb))
99 {
100 overlaps[proci] = true;
101 ++nOverlaps;
102 break;
103 }
104 }
105 }
106
107 return nOverlaps;
108}
109
110
111Foam::autoPtr<Foam::mapDistribute> Foam::meshToMesh::calcProcMap
112(
113 const polyMesh& src,
114 const polyMesh& tgt
115) const
116{
117 // Uses linear construct order
118 const
119 mapDistributeBase::layoutTypes constructLayout =
121
122 switch (procMapMethod_)
123 {
124 case procMapMethod::pmLOD:
125 {
126 Info<< "meshToMesh: Using processorLOD method" << endl;
127
128 // Create processor map of overlapping faces. This map gets
129 // (possibly remote) cells from the tgt mesh such that they
130 // (together) cover all of the src mesh
131 const label nGlobalSrcCells = src.globalData().nTotalCells();
132 // Note: minimum content has to be > 1 since otherwise
133 // would keep on splitting. 16 is fairly random choice.
134 const label cellsPerBox = max(16, 0.001*nGlobalSrcCells);
135 typename processorLODs::cellBox boxLOD
136 (
137 src.cells(),
138 src.faces(),
139 src.points(),
140 tgt.cells(),
141 tgt.faces(),
142 tgt.points(),
143 cellsPerBox,
144 src.nCells()
145 );
146
147 return boxLOD.map(constructLayout);
148 break;
149 }
150 default:
151 {
152 Info<< "meshToMesh: Using AABBTree method" << endl;
153
154 // get decomposition of cells on src mesh
156
157 if (src.nCells() > 0)
158 {
160 (
161 src.cellPoints(),
162 src.points(),
163 false
164 ).boundBoxes();
165 }
166 else
167 {
169 }
170
172
173
174 if (debug)
175 {
177 << "Determining extent of src mesh per processor:" << nl
178 << "\tproc\tbb" << endl;
179 forAll(procBb, proci)
180 {
181 Info<< '\t' << proci << '\t' << procBb[proci] << endl;
182 }
183 }
184
185
186 // Determine which cells of tgt mesh overlaps src mesh per proc
188
189 {
190 // per processor indices into all segments to send
192 label iniSize = floor(tgt.nCells()/Pstream::nProcs());
193
194 forAll(dynSendMap, proci)
195 {
196 dynSendMap[proci].setCapacity(iniSize);
197 }
198
199 // work array - whether src processor bb overlaps the tgt cell
200 // bounds
201 boolList procBbOverlaps(Pstream::nProcs());
202
203 for (label celli = 0; celli < tgt.nCells(); ++celli)
204 {
205 // Bounding box of tgt cell
206 boundBox cellBb(tgt.cellBb(celli));
207
208 // find the overlapping tgt cells on each src processor
209 (void)calcOverlappingProcs(procBb, cellBb, procBbOverlaps);
210
211 forAll(procBbOverlaps, proci)
212 {
213 if (procBbOverlaps[proci])
214 {
215 dynSendMap[proci].append(celli);
216 }
217 }
218 }
219
220 if (debug)
221 {
222 Pout<< "Of my " << tgt.nCells()
223 << " target cells I need to send to:" << nl
224 << "\tproc\tcells" << endl;
225 forAll(dynSendMap, proci)
226 {
227 Pout<< '\t' << proci << '\t'
228 << dynSendMap[proci].size() << endl;
229 }
230 }
231
232 // Convert DynamicList -> List
233 forAll(sendMap, proci)
234 {
235 sendMap[proci].transfer(dynSendMap[proci]);
236 }
237 }
238
239
241 (
242 constructLayout,
243 std::move(sendMap)
244 );
245 break;
246 }
247 }
248}
249
250
251void Foam::meshToMesh::distributeCells
252(
253 const mapDistribute& map,
254 const polyMesh& tgtMesh,
255 const globalIndex& globalI,
257 List<label>& nInternalFaces,
258 List<faceList>& faces,
259 List<labelList>& faceOwner,
260 List<labelList>& faceNeighbour,
261 List<labelList>& cellIDs,
262 List<labelList>& nbrProcIDs,
263 List<labelList>& procLocalFaceIDs
264) const
265{
267 nInternalFaces.setSize(Pstream::nProcs(), 0);
268 faces.setSize(Pstream::nProcs());
269 faceOwner.setSize(Pstream::nProcs());
270 faceNeighbour.setSize(Pstream::nProcs());
271 cellIDs.setSize(Pstream::nProcs());
272
273 nbrProcIDs.setSize(Pstream::nProcs());;
274 procLocalFaceIDs.setSize(Pstream::nProcs());;
275
276
277 PstreamBuffers pBufs;
278
279 for (const int domain : Pstream::allProcs())
280 {
281 const labelList& sendElems = map.subMap()[domain];
282
283 if (sendElems.size())
284 {
285 // reverse cell map
286 labelList reverseCellMap(tgtMesh.nCells(), -1);
287 forAll(sendElems, subCelli)
288 {
289 reverseCellMap[sendElems[subCelli]] = subCelli;
290 }
291
292 DynamicList<face> subFaces(tgtMesh.nFaces());
293 DynamicList<label> subFaceOwner(tgtMesh.nFaces());
294 DynamicList<label> subFaceNeighbour(tgtMesh.nFaces());
295
296 DynamicList<label> subNbrProcIDs(tgtMesh.nFaces());
297 DynamicList<label> subProcLocalFaceIDs(tgtMesh.nFaces());
298
299 label nInternal = 0;
300
301 // internal faces
302 forAll(tgtMesh.faceNeighbour(), facei)
303 {
304 label own = tgtMesh.faceOwner()[facei];
305 label nbr = tgtMesh.faceNeighbour()[facei];
306 label subOwn = reverseCellMap[own];
307 label subNbr = reverseCellMap[nbr];
308
309 if (subOwn != -1 && subNbr != -1)
310 {
311 nInternal++;
312
313 if (subOwn < subNbr)
314 {
315 subFaces.append(tgtMesh.faces()[facei]);
316 subFaceOwner.append(subOwn);
317 subFaceNeighbour.append(subNbr);
318 subNbrProcIDs.append(-1);
319 subProcLocalFaceIDs.append(-1);
320 }
321 else
322 {
323 subFaces.append(tgtMesh.faces()[facei].reverseFace());
324 subFaceOwner.append(subNbr);
325 subFaceNeighbour.append(subOwn);
326 subNbrProcIDs.append(-1);
327 subProcLocalFaceIDs.append(-1);
328 }
329 }
330 }
331
332 // boundary faces for new region
333 forAll(tgtMesh.faceNeighbour(), facei)
334 {
335 label own = tgtMesh.faceOwner()[facei];
336 label nbr = tgtMesh.faceNeighbour()[facei];
337 label subOwn = reverseCellMap[own];
338 label subNbr = reverseCellMap[nbr];
339
340 if (subOwn != -1 && subNbr == -1)
341 {
342 subFaces.append(tgtMesh.faces()[facei]);
343 subFaceOwner.append(subOwn);
344 subFaceNeighbour.append(subNbr);
345 subNbrProcIDs.append(-1);
346 subProcLocalFaceIDs.append(-1);
347 }
348 else if (subOwn == -1 && subNbr != -1)
349 {
350 subFaces.append(tgtMesh.faces()[facei].reverseFace());
351 subFaceOwner.append(subNbr);
352 subFaceNeighbour.append(subOwn);
353 subNbrProcIDs.append(-1);
354 subProcLocalFaceIDs.append(-1);
355 }
356 }
357
358 // boundary faces of existing region
359 forAll(tgtMesh.boundaryMesh(), patchi)
360 {
361 const polyPatch& pp = tgtMesh.boundaryMesh()[patchi];
362 const auto* procPatch = isA<processorPolyPatch>(pp);
363
364 // Store info for faces on processor patches
365 const label nbrProci =
366 (procPatch ? procPatch->neighbProcNo() : -1);
367
368 forAll(pp, i)
369 {
370 label facei = pp.start() + i;
371 label own = tgtMesh.faceOwner()[facei];
372
373 if (reverseCellMap[own] != -1)
374 {
375 subFaces.append(tgtMesh.faces()[facei]);
376 subFaceOwner.append(reverseCellMap[own]);
377 subFaceNeighbour.append(-1);
378 subNbrProcIDs.append(nbrProci);
379 subProcLocalFaceIDs.append(i);
380 }
381 }
382 }
383
384 // reverse point map
385 labelList reversePointMap(tgtMesh.nPoints(), -1);
386 DynamicList<point> subPoints(tgtMesh.nPoints());
387 forAll(subFaces, subFacei)
388 {
389 face& f = subFaces[subFacei];
390 forAll(f, fp)
391 {
392 label pointi = f[fp];
393 if (reversePointMap[pointi] == -1)
394 {
395 reversePointMap[pointi] = subPoints.size();
396 subPoints.append(tgtMesh.points()[pointi]);
397 }
398
399 f[fp] = reversePointMap[pointi];
400 }
401 }
402
403 // tgt cells into global numbering
404 labelList globalElems(globalI.toGlobal(sendElems));
405
406 if (debug > 1)
407 {
408 forAll(sendElems, i)
409 {
410 Pout<< "tgtProc:" << Pstream::myProcNo()
411 << " sending tgt cell " << sendElems[i]
412 << "[" << globalElems[i] << "]"
413 << " to srcProc " << domain << endl;
414 }
415 }
416
417 // pass data
418 if (domain == Pstream::myProcNo())
419 {
420 // allocate my own data
421 points[Pstream::myProcNo()] = subPoints;
422 nInternalFaces[Pstream::myProcNo()] = nInternal;
423 faces[Pstream::myProcNo()] = subFaces;
424 faceOwner[Pstream::myProcNo()] = subFaceOwner;
425 faceNeighbour[Pstream::myProcNo()] = subFaceNeighbour;
426 cellIDs[Pstream::myProcNo()] = globalElems;
427 nbrProcIDs[Pstream::myProcNo()] = subNbrProcIDs;
428 procLocalFaceIDs[Pstream::myProcNo()] = subProcLocalFaceIDs;
429 }
430 else
431 {
432 // send data to other processor domains
433 UOPstream toDomain(domain, pBufs);
434
435 toDomain
436 << subPoints
437 << nInternal
438 << subFaces
439 << subFaceOwner
440 << subFaceNeighbour
441 << globalElems
442 << subNbrProcIDs
443 << subProcLocalFaceIDs;
444 }
445 }
446 }
447
448 // Start receiving
449 pBufs.finishedSends();
450
451 // Consume
452 for (const int domain : Pstream::allProcs())
453 {
454 const labelList& recvElems = map.constructMap()[domain];
455
456 if (domain != Pstream::myProcNo() && recvElems.size())
457 {
458 UIPstream str(domain, pBufs);
459
460 str >> points[domain]
461 >> nInternalFaces[domain]
462 >> faces[domain]
463 >> faceOwner[domain]
464 >> faceNeighbour[domain]
465 >> cellIDs[domain]
466 >> nbrProcIDs[domain]
467 >> procLocalFaceIDs[domain];
468 }
469
470 if (debug)
471 {
472 Pout<< "Target mesh send sizes[" << domain << "]"
473 << ": points="<< points[domain].size()
474 << ", faces=" << faces[domain].size()
475 << ", nInternalFaces=" << nInternalFaces[domain]
476 << ", faceOwn=" << faceOwner[domain].size()
477 << ", faceNbr=" << faceNeighbour[domain].size()
478 << ", cellIDs=" << cellIDs[domain].size() << endl;
479 }
480 }
481}
482
483
484void Foam::meshToMesh::distributeAndMergeCells
485(
486 const mapDistribute& map,
487 const polyMesh& tgt,
488 const globalIndex& globalI,
489 pointField& tgtPoints,
490 faceList& tgtFaces,
491 labelList& tgtFaceOwners,
492 labelList& tgtFaceNeighbours,
493 labelList& tgtCellIDs
494) const
495{
496 // Exchange per-processor data
498 List<label> allNInternalFaces;
499 List<faceList> allFaces;
500 List<labelList> allFaceOwners;
501 List<labelList> allFaceNeighbours;
502 List<labelList> allTgtCellIDs;
503
504 // Per target mesh face the neighbouring proc and index in
505 // processor patch (all -1 for normal boundary face)
506 List<labelList> allNbrProcIDs;
507 List<labelList> allProcLocalFaceIDs;
508
509 distributeCells
510 (
511 map,
512 tgt,
513 globalI,
514 allPoints,
515 allNInternalFaces,
516 allFaces,
517 allFaceOwners,
518 allFaceNeighbours,
519 allTgtCellIDs,
520 allNbrProcIDs,
521 allProcLocalFaceIDs
522 );
523
524 // Convert lists into format that can be used to generate a valid polyMesh
525 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
526 //
527 // Points and cells are collected into single flat lists:
528 // - i.e. proc0, proc1 ... procN
529 //
530 // Faces need to be sorted after collection to that internal faces are
531 // contiguous, followed by all boundary faces
532 //
533 // Processor patch faces between included cells on neighbouring processors
534 // are converted into internal faces
535 //
536 // Face list structure:
537 // - Per processor:
538 // - internal faces
539 // - processor faces that have been converted into internal faces
540 // - Followed by all boundary faces
541 // - from 'normal' boundary faces
542 // - from singularly-sided processor patch faces
543
544
545 // Number of internal+coupled faces
546 labelList allNIntCoupledFaces(allNInternalFaces);
547
548 // Starting offset for points
549 label nPoints = 0;
550 labelList pointOffset(Pstream::nProcs(), Zero);
551 forAll(allPoints, proci)
552 {
553 pointOffset[proci] = nPoints;
554 nPoints += allPoints[proci].size();
555 }
556
557 // Starting offset for cells
558 label nCells = 0;
559 labelList cellOffset(Pstream::nProcs(), Zero);
560 forAll(allTgtCellIDs, proci)
561 {
562 cellOffset[proci] = nCells;
563 nCells += allTgtCellIDs[proci].size();
564 }
565
566 // Count any coupled faces
567 typedef FixedList<label, 3> label3;
568 typedef HashTable<label, label3> procCoupleInfo;
569 procCoupleInfo procFaceToGlobalCell;
570
571 forAll(allNbrProcIDs, proci)
572 {
573 const labelList& nbrProci = allNbrProcIDs[proci];
574 const labelList& localFacei = allProcLocalFaceIDs[proci];
575
576 forAll(nbrProci, i)
577 {
578 if (nbrProci[i] != -1 && localFacei[i] != -1)
579 {
580 label3 key;
581 key[0] = min(proci, nbrProci[i]);
582 key[1] = max(proci, nbrProci[i]);
583 key[2] = localFacei[i];
584
585 const auto fnd = procFaceToGlobalCell.cfind(key);
586
587 if (!fnd.good())
588 {
589 procFaceToGlobalCell.insert(key, -1);
590 }
591 else
592 {
593 if (debug > 1)
594 {
595 Pout<< "Additional internal face between procs:"
596 << key[0] << " and " << key[1]
597 << " across local face " << key[2] << endl;
598 }
599
600 allNIntCoupledFaces[proci]++;
601 }
602 }
603 }
604 }
605
606
607 // Starting offset for internal faces
608 label nIntFaces = 0;
609 label nFacesTotal = 0;
610 labelList internalFaceOffset(Pstream::nProcs(), Zero);
611 forAll(allNIntCoupledFaces, proci)
612 {
613 label nCoupledFaces =
614 allNIntCoupledFaces[proci] - allNInternalFaces[proci];
615
616 internalFaceOffset[proci] = nIntFaces;
617 nIntFaces += allNIntCoupledFaces[proci];
618 nFacesTotal += allFaceOwners[proci].size() - nCoupledFaces;
619 }
620
621 tgtPoints.setSize(nPoints);
622 tgtFaces.setSize(nFacesTotal);
623 tgtFaceOwners.setSize(nFacesTotal);
624 tgtFaceNeighbours.setSize(nFacesTotal);
625 tgtCellIDs.setSize(nCells);
626
627 // Insert points
628 forAll(allPoints, proci)
629 {
630 const pointField& pts = allPoints[proci];
631 SubList<point>(tgtPoints, pts.size(), pointOffset[proci]) = pts;
632 }
633
634 // Insert cellIDs
635 forAll(allTgtCellIDs, proci)
636 {
637 const labelList& cellIDs = allTgtCellIDs[proci];
638 SubList<label>(tgtCellIDs, cellIDs.size(), cellOffset[proci]) = cellIDs;
639 }
640
641
642 // Insert internal faces (from internal faces)
643 forAll(allFaces, proci)
644 {
645 const faceList& fcs = allFaces[proci];
646 const labelList& faceOs = allFaceOwners[proci];
647 const labelList& faceNs = allFaceNeighbours[proci];
648
649 SubList<face> slice
650 (
651 tgtFaces,
652 allNInternalFaces[proci],
653 internalFaceOffset[proci]
654 );
655 slice = SubList<face>(fcs, allNInternalFaces[proci]);
656 forAll(slice, i)
657 {
658 add(slice[i], pointOffset[proci]);
659 }
660
661 SubField<label> ownSlice
662 (
663 tgtFaceOwners,
664 allNInternalFaces[proci],
665 internalFaceOffset[proci]
666 );
667 ownSlice = SubField<label>(faceOs, allNInternalFaces[proci]);
668 add(ownSlice, cellOffset[proci]);
669
670 SubField<label> nbrSlice
671 (
672 tgtFaceNeighbours,
673 allNInternalFaces[proci],
674 internalFaceOffset[proci]
675 );
676 nbrSlice = SubField<label>(faceNs, allNInternalFaces[proci]);
677 add(nbrSlice, cellOffset[proci]);
678
679 internalFaceOffset[proci] += allNInternalFaces[proci];
680 }
681
682
683 // Insert internal faces (from coupled face-pairs)
684 forAll(allNbrProcIDs, proci)
685 {
686 const labelList& nbrProci = allNbrProcIDs[proci];
687 const labelList& localFacei = allProcLocalFaceIDs[proci];
688 const labelList& faceOs = allFaceOwners[proci];
689 const faceList& fcs = allFaces[proci];
690
691 forAll(nbrProci, i)
692 {
693 if (nbrProci[i] != -1 && localFacei[i] != -1)
694 {
695 label3 key;
696 key[0] = min(proci, nbrProci[i]);
697 key[1] = max(proci, nbrProci[i]);
698 key[2] = localFacei[i];
699
700 auto fnd = procFaceToGlobalCell.find(key);
701
702 if (fnd.good())
703 {
704 label tgtFacei = fnd();
705 if (tgtFacei == -1)
706 {
707 // on first visit store the new cell on this side
708 fnd() = cellOffset[proci] + faceOs[i];
709 }
710 else
711 {
712 // get owner and neighbour in new cell numbering
713 label newOwn = cellOffset[proci] + faceOs[i];
714 label newNbr = fnd();
715 label tgtFacei = internalFaceOffset[proci]++;
716
717 if (debug > 1)
718 {
719 Pout<< " proc " << proci
720 << "\tinserting face:" << tgtFacei
721 << " connection between owner " << newOwn
722 << " and neighbour " << newNbr
723 << endl;
724 }
725
726 if (newOwn < newNbr)
727 {
728 // we have correct orientation
729 tgtFaces[tgtFacei] = fcs[i];
730 tgtFaceOwners[tgtFacei] = newOwn;
731 tgtFaceNeighbours[tgtFacei] = newNbr;
732 }
733 else
734 {
735 // reverse orientation
736 tgtFaces[tgtFacei] = fcs[i].reverseFace();
737 tgtFaceOwners[tgtFacei] = newNbr;
738 tgtFaceNeighbours[tgtFacei] = newOwn;
739 }
740
741 add(tgtFaces[tgtFacei], pointOffset[proci]);
742
743 // mark with unique value
744 fnd() = -2;
745 }
746 }
747 }
748 }
749 }
750
751
752 forAll(allNbrProcIDs, proci)
753 {
754 const labelList& nbrProci = allNbrProcIDs[proci];
755 const labelList& localFacei = allProcLocalFaceIDs[proci];
756 const labelList& faceOs = allFaceOwners[proci];
757 const labelList& faceNs = allFaceNeighbours[proci];
758 const faceList& fcs = allFaces[proci];
759
760 forAll(nbrProci, i)
761 {
762 // coupled boundary face
763 if (nbrProci[i] != -1 && localFacei[i] != -1)
764 {
765 label3 key;
766 key[0] = min(proci, nbrProci[i]);
767 key[1] = max(proci, nbrProci[i]);
768 key[2] = localFacei[i];
769
770 label tgtFacei = procFaceToGlobalCell[key];
771
772 if (tgtFacei == -1)
773 {
775 << "Unvisited " << key
776 << abort(FatalError);
777 }
778 else if (tgtFacei != -2)
779 {
780 label newOwn = cellOffset[proci] + faceOs[i];
781 label tgtFacei = nIntFaces++;
782
783 if (debug > 1)
784 {
785 Pout<< " proc " << proci
786 << "\tinserting boundary face:" << tgtFacei
787 << " from coupled face " << key
788 << endl;
789 }
790
791 tgtFaces[tgtFacei] = fcs[i];
792 add(tgtFaces[tgtFacei], pointOffset[proci]);
793
794 tgtFaceOwners[tgtFacei] = newOwn;
795 tgtFaceNeighbours[tgtFacei] = -1;
796 }
797 }
798 // normal boundary face
799 else
800 {
801 label own = faceOs[i];
802 label nbr = faceNs[i];
803 if ((own != -1) && (nbr == -1))
804 {
805 label newOwn = cellOffset[proci] + faceOs[i];
806 label tgtFacei = nIntFaces++;
807
808 tgtFaces[tgtFacei] = fcs[i];
809 add(tgtFaces[tgtFacei], pointOffset[proci]);
810
811 tgtFaceOwners[tgtFacei] = newOwn;
812 tgtFaceNeighbours[tgtFacei] = -1;
813 }
814 }
815 }
816 }
817
818
819 if (debug)
820 {
821 // only merging points in debug mode
822
823 labelList oldToNew;
824 label nChanged = Foam::inplaceMergePoints
825 (
826 tgtPoints,
827 SMALL,
828 false,
829 oldToNew
830 );
831
832 if (nChanged)
833 {
834 Pout<< "Merged from " << oldToNew.size()
835 << " down to " << tgtPoints.size() << " points" << endl;
836
837 for (auto& f : tgtFaces)
838 {
839 inplaceRenumber(oldToNew, f);
840 }
841 }
842 }
843}
844
845
846// ************************************************************************* //
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Templated tree of axis-aligned bounding boxes (AABB).
Definition AABBTree.H:116
const List< treeBoundBox > & boundBoxes() const noexcept
Return the bounding boxes making up the tree.
Definition AABBTree.H:209
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
A 1D vector of objects of type <T> with a fixed length <N>.
Definition FixedList.H:73
A HashTable similar to std::unordered_map.
Definition HashTable.H:124
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
void setSize(label n)
Alias for resize().
Definition List.H:536
Buffers for inter-processor communications streams (UOPstream, UIPstream).
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual communication.
SubField is a Field obtained as a section of another Field, without its own allocation....
Definition SubField.H:58
A non-owning sub-view of a List (allocated or unallocated storage).
Definition SubList.H:61
Input inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UIPstream.H:313
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
Output inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UOPstream.H:408
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 List< T > listGatherValues(const T &localValue, const int communicator=UPstream::worldComm)
Gather individual values into list locations.
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run.
Definition UPstream.H:1697
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition UPstream.H:1857
@ broadcast
broadcast [MPI]
Definition UPstream.H:189
static bool & parRun() noexcept
Test if this a parallel run.
Definition UPstream.H:1681
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition autoPtr.H:178
A bounding box defined in terms of min/max extrema points.
Definition boundBox.H:71
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition globalIndex.H:77
layoutTypes
The map layout (eg, of the constructMap).
Class containing processor-to-processor mapping information.
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
Creates the parallel distribution map by describing the source and target objects using box shapes.
Definition cellBox.H:54
Standard boundBox with extra functionality for use in octree.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const pointField & points
label nPoints
Geometric merging of points. See below.
#define DebugInFunction
Report an information message using Foam::Info.
#define InfoInFunction
Report an information message using Foam::Info.
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
Namespace for handling debugging switches.
Definition debug.C:45
constexpr auto key(const Type &t) noexcept
Helper function to return the enum value.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values within a list.
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
List< treeBoundBox > treeBoundBoxList
A List of treeBoundBox.
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
void add(DimensionedField< scalar, GeoMesh > &result, const dimensioned< scalar > &dt1, const DimensionedField< scalar, GeoMesh > &f2)
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
errorManip< error > abort(error &err)
Definition errorManip.H:139
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...
label inplaceMergePoints(PointList &points, const scalar mergeTol, const bool verbose, labelList &pointToUnique)
Inplace merge points, preserving the original point order. All points closer/equal mergeTol are to be...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
vectorField pointField
pointField is a vectorField.
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
labelList f(nPoints)
const pointField & pts
volScalarField & b
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299