domainDecompositionReconstruct.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2025 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "domainDecomposition.H"
27 #include "fvMeshAdder.H"
28 #include "processorPolyPatch.H"
30 #include "zoneGenerator.H"
31 
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
33 
35 Foam::domainDecomposition::determineCoupledFaces
36 (
37  const label masterMeshProcStart,
38  const label masterMeshProcEnd,
39  const polyMesh& masterMesh,
40  const label meshToAddProcStart,
41  const label meshToAddProcEnd,
42  const polyMesh& meshToAdd
43 )
44 {
45  const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
46  const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
47 
48  DynamicList<label> masterFaces
49  (
50  masterMesh.nFaces() - masterMesh.nInternalFaces()
51  );
52  DynamicList<label> addFaces
53  (
54  meshToAdd.nFaces() - meshToAdd.nInternalFaces()
55  );
56 
57  for
58  (
59  label masterProci = masterMeshProcStart;
60  masterProci < masterMeshProcEnd;
61  masterProci++
62  )
63  {
64  for
65  (
66  label addProci = meshToAddProcStart;
67  addProci < meshToAddProcEnd;
68  addProci++
69  )
70  {
71  const word masterToAddName
72  (
73  "procBoundary" + name(masterProci) + "to" + name(addProci)
74  );
75  const word addToMasterName
76  (
77  "procBoundary" + name(addProci) + "to" + name(masterProci)
78  );
79 
80  const label masterToAddID =
81  masterPatches.findIndex(masterToAddName);
82  const label addToMasterID =
83  addPatches.findIndex(addToMasterName);
84 
85  if (masterToAddID != -1 && addToMasterID != -1)
86  {
87  const polyPatch& masterPp = masterPatches[masterToAddID];
88 
89  forAll(masterPp, i)
90  {
91  masterFaces.append(masterPp.start() + i);
92  }
93 
94  const polyPatch& addPp = addPatches[addToMasterID];
95 
96  forAll(addPp, i)
97  {
98  addFaces.append(addPp.start() + i);
99  }
100  }
101 
102  if ((masterToAddID != -1) != (addToMasterID != -1))
103  {
104  const label foundProci =
105  masterToAddID != -1 ? masterProci : addProci;
106  const word& foundName =
107  masterToAddID != -1 ? masterToAddName : addToMasterName;
108 
109  const label missingProci =
110  masterToAddID != -1 ? addProci : masterProci;
111  const word& missingName =
112  masterToAddID != -1 ? addToMasterName : masterToAddName;
113 
115  << "Patch " << foundName << " found on processor "
116  << foundProci << " but corresponding patch "
117  << missingName << " missing on processor "
118  << missingProci << exit(FatalError);
119  }
120  }
121  }
122 
123  masterFaces.shrink();
124  addFaces.shrink();
125 
126  return autoPtr<faceCoupleInfo>
127  (
128  new faceCoupleInfo
129  (
130  masterMesh,
131  masterFaces,
132  meshToAdd,
133  addFaces
134  )
135  );
136 }
137 
138 
139 void Foam::domainDecomposition::reconstruct()
140 {
141  Info<< "Reconstructing meshes" << incrIndent << nl << endl;
142 
143  // ???
144  PtrList<fvMesh> masterMeshes(nProcs());
145 
146  // ???
147  for (label proci=0; proci<nProcs(); proci++)
148  {
149  masterMeshes.set
150  (
151  proci,
152  new fvMesh
153  (
154  IOobject
155  (
156  regionName_,
157  procMeshes()[0].facesInstance(),
158  meshPath_,
159  runTimes_.completeTime()
160  ),
161  pointField(),
162  faceList(),
163  cellList()
164  )
165  );
166  fvMesh& masterMesh = masterMeshes[proci];
167  masterMesh.setPointsInstance(procMeshes()[0].pointsInstance());
168 
169  // Initialise the addressing
170  procPointAddressing_[proci] =
171  identityMap(procMeshes()[proci].nPoints());
172  procFaceAddressing_[proci] = identityMap(procMeshes()[proci].nFaces());
173  procCellAddressing_[proci] = identityMap(procMeshes()[proci].nCells());
174 
175  // Find shared points and faces
176  autoPtr<faceCoupleInfo> couples = determineCoupledFaces
177  (
178  proci,
179  proci,
180  masterMesh,
181  proci,
182  proci,
183  procMeshes()[proci]
184  );
185 
186  // Add elements to the master mesh
187  autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
188  (
189  masterMesh,
190  procMeshes()[proci],
191  couples,
192  false
193  );
194 
195  // Renumber addressing following the add
197  (
198  map().addedPointMap(),
199  procPointAddressing_[proci]
200  );
202  (
203  map().addedFaceMap(),
204  procFaceAddressing_[proci]
205  );
207  (
208  map().addedCellMap(),
209  procCellAddressing_[proci]
210  );
211  }
212 
213  // Merge the meshes
214  for (label step=2; step<nProcs()*2; step*=2)
215  {
216  for (label proci=0; proci<nProcs(); proci+=step)
217  {
218  label procj = proci + step/2;
219 
220  if (procj >= nProcs()) continue;
221 
222  Info<< indent << "Merging mesh " << proci
223  << " with " << procj << endl;
224 
225  // Find shared points and faces
226  autoPtr<faceCoupleInfo> couples = determineCoupledFaces
227  (
228  proci,
229  procj,
230  masterMeshes[proci],
231  procj,
232  proci+step,
233  masterMeshes[procj]
234  );
235 
236  // Add elements to mesh
237  autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
238  (
239  masterMeshes[proci],
240  masterMeshes[procj],
241  couples,
242  false
243  );
244 
245  // Renumber processors that were already present
246  for
247  (
248  label mergedProci = proci;
249  mergedProci < procj;
250  mergedProci ++
251  )
252  {
254  (
255  map().oldPointMap(),
256  procPointAddressing_[mergedProci]
257  );
259  (
260  map().oldFaceMap(),
261  procFaceAddressing_[mergedProci]
262  );
264  (
265  map().oldCellMap(),
266  procCellAddressing_[mergedProci]
267  );
268  }
269 
270  // Renumber processors that were just added
271  for
272  (
273  label addedProci = procj;
274  addedProci < min(proci + step, nProcs());
275  addedProci ++
276  )
277  {
279  (
280  map().addedPointMap(),
281  procPointAddressing_[addedProci]
282  );
284  (
285  map().addedFaceMap(),
286  procFaceAddressing_[addedProci]
287  );
289  (
290  map().addedCellMap(),
291  procCellAddressing_[addedProci]
292  );
293  }
294 
295  masterMeshes.set(procj, nullptr);
296  }
297  }
298 
299  const polyBoundaryMesh& patches = masterMeshes[0].boundaryMesh();
300 
301  // Move all faces of processor cyclic patches into the associated cyclics
302  if (!patches.findIndices<processorCyclicPolyPatch>().empty())
303  {
304  // Determine what patches are to be combined into each patch
305  List<DynamicList<label>> patchPatches
306  (
307  patches.size(),
308  DynamicList<label>(1)
309  );
311  {
312  patchPatches[patchi].append(patchi);
313  }
314 
315  HashTable
316  <
317  label,
318  FixedList<label, 3>,
319  FixedList<label, 3>::Hash<>
320  > nbrProcessorCyclicIDs;
321 
323  {
324  if (!isA<processorCyclicPolyPatch>(patches[patchi])) continue;
325 
326  const processorCyclicPolyPatch& pcpp =
327  refCast<const processorCyclicPolyPatch>(patches[patchi]);
328 
329  const label proci = pcpp.myProcNo();
330  const label nbrProci = pcpp.neighbProcNo();
331  const label refPatchi = pcpp.referPatchIndex();
332  const label nbrRefPatchi = pcpp.referPatch().nbrPatchIndex();
333 
334  FixedList<label, 3> key({proci, nbrProci, refPatchi});
335  FixedList<label, 3> nbrKey({nbrProci, proci, nbrRefPatchi});
336 
337  if (nbrProcessorCyclicIDs.found(nbrKey))
338  {
339  const label nbrPatchi = nbrProcessorCyclicIDs[nbrKey];
340 
341  patchPatches[refPatchi].append
342  (
343  patchPatches[patchi].remove()
344  );
345  patchPatches[nbrRefPatchi].append
346  (
347  patchPatches[nbrPatchi].remove()
348  );
349 
350  nbrProcessorCyclicIDs.erase(nbrKey);
351  }
352  else
353  {
354  nbrProcessorCyclicIDs.insert(key, patchi);
355  }
356  }
357 
358  // Build the new patch indices and a permutation map for the mesh faces
359  labelList newPatchSizes(patches.size());
360  labelList newPatchStarts(patches.size());
361  labelList newToOldFace(masterMeshes[0].nFaces());
362  SubList<label>(newToOldFace, masterMeshes[0].nInternalFaces()) =
363  identityMap(masterMeshes[0].nInternalFaces());
365  {
366  newPatchSizes[patchi] = 0;
367  newPatchStarts[patchi] =
368  patchi == 0
369  ? masterMeshes[0].nInternalFaces()
370  : newPatchStarts[patchi-1] + newPatchSizes[patchi-1];
371 
372  forAll(patchPatches[patchi], i)
373  {
374  const polyPatch& pp = patches[patchPatches[patchi][i]];
375 
376  SubList<label>
377  (
378  newToOldFace,
379  pp.size(),
380  newPatchStarts[patchi] + newPatchSizes[patchi]
381  ) = pp.start() + identityMap(pp.size());
382 
383  newPatchSizes[patchi] += pp.size();
384  }
385  }
386 
387  // Check that the face ordering is a permutation
388  if (debug)
389  {
390  boolList newHasOldFace(newToOldFace.size(), false);
391  forAll(newToOldFace, newFacei)
392  {
393  if (newHasOldFace[newToOldFace[newFacei]])
394  {
396  << "Face re-ordering is not valid"
397  << exit(FatalError);
398  }
399  newHasOldFace[newToOldFace[newFacei]] = true;
400  }
401  }
402 
403  // Modify the mesh
404  const labelList oldToNewFace(invert(newToOldFace.size(), newToOldFace));
405  masterMeshes[0].resetPrimitives
406  (
407  NullObjectMove<pointField>(),
408  reorder(oldToNewFace, masterMeshes[0].faces()),
409  reorder(oldToNewFace, masterMeshes[0].faceOwner()),
410  reorder(oldToNewFace, masterMeshes[0].faceNeighbour()),
411  newPatchSizes,
412  newPatchStarts,
413  true
414  );
415 
416  // Update the addressing
417  forAll(procFaceAddressing_, proci)
418  {
420  (
421  oldToNewFace,
422  procFaceAddressing_[proci]
423  );
424  }
425  }
426 
427  // Filter out all processor patches
428  {
429  label nNonProcPatches = 0;
430  labelList nonProcPatchIds(patches.size(), -1);
431 
432  forAll(masterMeshes[0].boundary(), patchi)
433  {
434  if (isA<processorPolyPatch>(patches[patchi]))
435  {
436  if (patches[patchi].size() != 0)
437  {
439  << "Non-empty processor patch \""
440  << patches[patchi].name()
441  << "\" found in reconstructed mesh"
442  << exit(FatalError);
443  }
444  }
445  else
446  {
447  nonProcPatchIds[nNonProcPatches++] = patchi;
448  }
449  }
450 
451  nonProcPatchIds.resize(nNonProcPatches);
452 
453  masterMeshes[0].reorderPatches(nonProcPatchIds, false);
454  }
455 
456  // Add turning index to the face addressing
457  for (label proci=0; proci<nProcs(); proci++)
458  {
459  const fvMesh& procMesh = procMeshes_[proci];
460 
461  forAll(procFaceAddressing_[proci], procFacei)
462  {
463  const label completeFacei = procFaceAddressing_[proci][procFacei];
464 
465  if
466  (
467  !procMesh.isInternalFace(procFacei)
468  && masterMeshes[0].isInternalFace(completeFacei)
469  )
470  {
471  // Processor face is external, but the corresponding complete
472  // face is internal. Turn if the owner has changed.
473 
474  const label procOwnCelli =
475  procMesh.faceOwner()[procFacei];
476  const label completeOwnCelli =
477  masterMeshes[0].faceOwner()[completeFacei];
478 
479  if
480  (
481  procCellAddressing_[proci][procOwnCelli]
482  == completeOwnCelli
483  )
484  {
485  procFaceAddressing_[proci][procFacei] ++;
486  }
487  else
488  {
489  procFaceAddressing_[proci][procFacei] =
490  -1 - procFaceAddressing_[proci][procFacei];
491  }
492  }
493  else
494  {
495  // Processor face is the same (internal/external) as the
496  // corresponding complete face
497 
498  procFaceAddressing_[proci][procFacei] ++;
499  }
500  }
501  }
502 
503  // Clear (and thus trigger re-generation) of finite volume face addressing
504  procFaceAddressingBf_.clear();
505 
506  // Construct complete cell to proc map
507  cellProc_.resize(masterMeshes[0].nCells());
508  forAll(procCellAddressing_, proci)
509  {
510  forAll(procCellAddressing_[proci], procCelli)
511  {
512  cellProc_[procCellAddressing_[proci][procCelli]] = proci;
513  }
514  }
515 
516  // Set the complete mesh
517  completeMesh_.reset(masterMeshes.set(0, nullptr).ptr());
518  completeMesh_->setInstance(procMeshes()[0].facesInstance());
519  completeMesh_->setPointsInstance(procMeshes()[0].pointsInstance());
520 
521  // Allocate a stitcher, but do not stitch
522  completeMesh_->postConstruct(false, false, fvMesh::stitchType::none);
523 
524  Info<< decrIndent;
525 }
526 
527 
528 void Foam::domainDecomposition::reconstructPoints()
529 {
530  const label pointsCompare =
531  compareInstances
532  (
533  completeMesh().pointsInstance(),
534  procMeshes_[0].pointsInstance()
535  );
536 
537  if (pointsCompare == 1)
538  {
539  pointField completePoints(completeMesh().nPoints());
540 
541  for (label proci = 0; proci < nProcs(); proci++)
542  {
543  const fvMesh& procMesh = procMeshes_[proci];
544 
545  completePoints.rmap(procMesh.points(), procPointAddressing_[proci]);
546  }
547 
548  completeMesh_->setPoints(completePoints);
549  }
550 
551 
552  const pointZoneList& pointZones = completeMesh().pointZones();
553  const pointZoneList& pointZones0 = procMeshes_[0].pointZones();
554 
555  const label pointZonesCompare = compareInstances
556  (
557  pointZones.instance(),
558  pointZones0.instance()
559  );
560 
561  if (pointZonesCompare == 1)
562  {
563  Info<< "Reconstructing pointZones" << incrIndent << endl;
564 
565  forAll(pointZones0, pzi)
566  {
567  Info<< indent << pointZones0[pzi].name() << endl;
568 
569  boolList selected(completeMesh_->nPoints(), false);
570 
571  for (label proci=0; proci<nProcs(); proci++)
572  {
573  const labelList& pointZonei =
574  procMeshes_[proci].pointZones()[pzi];
575 
576  const labelList& ppa = procPointAddressing_[proci];
577 
578  forAll(pointZonei, zpi)
579  {
580  selected[ppa[pointZonei[zpi]]] = true;
581  }
582  }
583 
584  completeMesh_->pointZones().append
585  (
586  new pointZone
587  (
588  pointZones0[pzi].name(),
589  zoneGenerator::indices(selected),
590  completeMesh_->pointZones()
591  )
592  );
593  }
594 
595  completeMesh_->pointZones().writeOpt() = IOobject::AUTO_WRITE;
596  completeMesh_->pointZones().instance() = pointZones0.instance();
597 
598  Info<< decrIndent << endl;
599  }
600 
601 
602  const cellZoneList& cellZones = completeMesh().cellZones();
603  const cellZoneList& cellZones0 = procMeshes_[0].cellZones();
604 
605  const label cellZonesCompare = compareInstances
606  (
607  cellZones.instance(),
608  cellZones0.instance()
609  );
610 
611  if (cellZonesCompare == 1)
612  {
613  Info<< "Reconstructing cellZones" << incrIndent << endl;
614 
615  forAll(cellZones0, pzi)
616  {
617  Info << indent << cellZones0[pzi].name() << endl;
618 
619  boolList selected(completeMesh_->nCells(), false);
620 
621  for (label proci=0; proci<nProcs(); proci++)
622  {
623  const labelList& cellZonei =
624  procMeshes_[proci].cellZones()[pzi];
625 
626  const labelList& pca = procCellAddressing_[proci];
627 
628  forAll(cellZonei, zci)
629  {
630  selected[pca[cellZonei[zci]]] = true;
631  }
632  }
633 
634  completeMesh_->cellZones().append
635  (
636  new cellZone
637  (
638  cellZones0[pzi].name(),
639  zoneGenerator::indices(selected),
640  completeMesh_->cellZones()
641  )
642  );
643  }
644 
645  completeMesh_->cellZones().writeOpt() = IOobject::AUTO_WRITE;
646  completeMesh_->cellZones().instance() = cellZones0.instance();
647 
648  Info<< decrIndent << endl;
649  }
650 
651 
652  const faceZoneList& faceZones = completeMesh().faceZones();
653  const faceZoneList& faceZones0 = procMeshes_[0].faceZones();
654 
655  const label faceZonesCompare = compareInstances
656  (
657  faceZones.instance(),
658  faceZones0.instance()
659  );
660 
661  if (faceZonesCompare == 1)
662  {
663  Info<< "Reconstructing faceZones" << incrIndent << endl;
664 
665  forAll(faceZones0, pzi)
666  {
667  Info<< indent << faceZones0[pzi].name() << endl;
668 
669  boolList selectedFaces(completeMesh_->nFaces(), false);
670  boolList flipMap(completeMesh_->nFaces(), false);
671 
672  const labelList& owner = completeMesh_->owner();
673 
674  for (label proci=0; proci<nProcs(); proci++)
675  {
676  const labelList& faceZonei =
677  procMeshes_[proci].faceZones()[pzi];
678 
679  const boolList& flipMapi =
680  faceZones0[pzi].oriented()
681  ? procMeshes_[proci].faceZones()[pzi].flipMap()
682  : boolList::null();
683 
684  const labelList& owneri = procMeshes_[proci].owner();
685 
686  const labelList& pfa = procFaceAddressing_[proci];
687  const labelList& pca = procCellAddressing_[proci];
688 
689  forAll(faceZonei, zfi)
690  {
691  const label fi = mag(pfa[faceZonei[zfi]]) - 1;
692 
693  selectedFaces[fi] = true;
694 
695  // Find the owner cell of the zone face
696  // in the complete mesh
697  const label ownerZfi = owner[fi];
698 
699  // Find the owner cell of the zone face
700  // in the processor mesh and map to the complete mesh
701  const label ownerZfii = pca[owneri[faceZonei[zfi]]];
702 
703  // If the zone face owner cell is the same in the
704  // complete and processor meshes the flipMap of the face
705  // corresponds ...
706  if (flipMapi.size())
707  {
708  if (ownerZfi == ownerZfii)
709  {
710  flipMap[fi] = flipMapi[zfi];
711  }
712  // ... otherwise flip the flipMap of the face
713  else
714  {
715  flipMap[fi] = !flipMapi[zfi];
716  }
717  }
718  }
719  }
720 
721  const labelList faceIndices(zoneGenerator::indices(selectedFaces));
722 
723  if (faceZones0[pzi].oriented())
724  {
725  completeMesh_->faceZones().append
726  (
727  new faceZone
728  (
729  faceZones0[pzi].name(),
730  faceIndices,
731  boolList(flipMap, faceIndices),
732  completeMesh_->faceZones()
733  )
734  );
735  }
736  else
737  {
738  completeMesh_->faceZones().append
739  (
740  new faceZone
741  (
742  faceZones0[pzi].name(),
743  faceIndices,
744  completeMesh_->faceZones()
745  )
746  );
747  }
748  }
749 
750  completeMesh_->faceZones().writeOpt() = IOobject::AUTO_WRITE;
751  completeMesh_->faceZones().instance() = faceZones0.instance();
752 
753  Info<< decrIndent << endl;
754  }
755 }
756 
757 
758 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.H:297
static const List< bool > & null()
Return a null List.
Definition: ListI.H:118
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
bool empty() const
Return true if the UPtrList is empty (ie, size() is zero)
Definition: UPtrListI.H:36
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
static autoPtr< mapAddedPolyMesh > add(fvMesh &mesh0, const fvMesh &mesh1, const faceCoupleInfo &coupleInfo, const bool validBoundary=true)
Inplace add mesh to fvMesh. Maps all stored fields. Returns map.
Definition: fvMeshAdder.C:71
static labelList indices(const boolList &selected)
Return the list of selected indices.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
label nPoints
const fvPatchList & patches
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:242
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
List< cell > cellList
list of cells
Definition: cellList.H:42
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
labelList invert(const label len, const labelUList &)
Invert one-to-one map. Unmapped elements will be -1.
Definition: ListOps.C:37
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:235
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
void mag(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
ListType reorder(const label size, const typename ListType::value_type &defaultValue, const labelUList &oldToNew, const ListType &lst)
void inplaceRenumber(const labelUList &oldToNew, ListType &)
Inplace renumber the values of a list.
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
error FatalError
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
List< face > faceList
Definition: faceListFwd.H:41
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:228
static const char nl
Definition: Ostream.H:267
faceListList boundary(nPatches)