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 -------------------------------------------------------------------------------
11 License
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 
41 Foam::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  (
53  UPstream::listGatherValues<bool>
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 
81 Foam::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 
111 Foam::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
155  List<treeBoundBoxList> procBb(Pstream::nProcs());
156 
157  if (src.nCells() > 0)
158  {
159  procBb[Pstream::myProcNo()] = AABBTree<labelList>
160  (
161  src.cellPoints(),
162  src.points(),
163  false
164  ).boundBoxes();
165  }
166  else
167  {
168  procBb[Pstream::myProcNo()] = treeBoundBoxList();
169  }
170 
171  Pstream::allGatherList(procBb);
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
187  labelListList sendMap(Pstream::nProcs());
188 
189  {
190  // per processor indices into all segments to send
191  List<DynamicList<label>> dynSendMap(Pstream::nProcs());
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 
251 void Foam::meshToMesh::distributeCells
252 (
253  const mapDistribute& map,
254  const polyMesh& tgtMesh,
255  const globalIndex& globalI,
256  List<pointField>& points,
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());
272 
273  nbrProcIDs.setSize(Pstream::nProcs());;
274  procLocalFaceIDs.setSize(Pstream::nProcs());;
275 
276 
277  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
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 
484 void 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
497  List<pointField> allPoints;
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 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:1176
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
List< treeBoundBox > treeBoundBoxList
A List of treeBoundBox.
Definition: treeBoundBox.H:83
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
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:1065
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
layoutTypes
The map layout (eg, of the constructMap)
void setSize(const label n)
Alias for resize()
Definition: List.H:316
const pointField & points
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
label nPoints
#define DebugInFunction
Report an information message using Foam::Info.
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...
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
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
int debug
Static debugging option.
Geometric merging of points. See below.
labelList f(nPoints)
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
"nonBlocking" : (MPI_Isend, MPI_Irecv)
messageStream Info
Information stream (stdout output on master, null elsewhere)
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
List< label > labelList
A List of labels.
Definition: List.H:62
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
List< bool > boolList
A List of bools.
Definition: List.H:60
labelList cellIDs
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const pointField & pts
#define InfoInFunction
Report an information message using Foam::Info.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127