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-2024 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 
31 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
32 
34 Foam::domainDecomposition::determineCoupledFaces
35 (
36  const label masterMeshProcStart,
37  const label masterMeshProcEnd,
38  const polyMesh& masterMesh,
39  const label meshToAddProcStart,
40  const label meshToAddProcEnd,
41  const polyMesh& meshToAdd
42 )
43 {
44  const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
45  const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
46 
47  DynamicList<label> masterFaces
48  (
49  masterMesh.nFaces() - masterMesh.nInternalFaces()
50  );
51  DynamicList<label> addFaces
52  (
53  meshToAdd.nFaces() - meshToAdd.nInternalFaces()
54  );
55 
56  for
57  (
58  label masterProci = masterMeshProcStart;
59  masterProci < masterMeshProcEnd;
60  masterProci++
61  )
62  {
63  for
64  (
65  label addProci = meshToAddProcStart;
66  addProci < meshToAddProcEnd;
67  addProci++
68  )
69  {
70  const word masterToAddName
71  (
72  "procBoundary" + name(masterProci) + "to" + name(addProci)
73  );
74  const word addToMasterName
75  (
76  "procBoundary" + name(addProci) + "to" + name(masterProci)
77  );
78 
79  const label masterToAddID =
80  masterPatches.findIndex(masterToAddName);
81  const label addToMasterID =
82  addPatches.findIndex(addToMasterName);
83 
84  if (masterToAddID != -1 && addToMasterID != -1)
85  {
86  const polyPatch& masterPp = masterPatches[masterToAddID];
87 
88  forAll(masterPp, i)
89  {
90  masterFaces.append(masterPp.start() + i);
91  }
92 
93  const polyPatch& addPp = addPatches[addToMasterID];
94 
95  forAll(addPp, i)
96  {
97  addFaces.append(addPp.start() + i);
98  }
99  }
100 
101  if ((masterToAddID != -1) != (addToMasterID != -1))
102  {
103  const label foundProci =
104  masterToAddID != -1 ? masterProci : addProci;
105  const word& foundName =
106  masterToAddID != -1 ? masterToAddName : addToMasterName;
107 
108  const label missingProci =
109  masterToAddID != -1 ? addProci : masterProci;
110  const word& missingName =
111  masterToAddID != -1 ? addToMasterName : masterToAddName;
112 
114  << "Patch " << foundName << " found on processor "
115  << foundProci << " but corresponding patch "
116  << missingName << " missing on processor "
117  << missingProci << exit(FatalError);
118  }
119  }
120  }
121 
122  masterFaces.shrink();
123  addFaces.shrink();
124 
125  return autoPtr<faceCoupleInfo>
126  (
127  new faceCoupleInfo
128  (
129  masterMesh,
130  masterFaces,
131  meshToAdd,
132  addFaces
133  )
134  );
135 }
136 
137 
138 void Foam::domainDecomposition::reconstruct()
139 {
140  Info<< "Reconstructing meshes" << incrIndent << nl << endl;
141 
142  // ???
143  PtrList<fvMesh> masterMeshes(nProcs());
144 
145  // ???
146  for (label proci=0; proci<nProcs(); proci++)
147  {
148  masterMeshes.set
149  (
150  proci,
151  new fvMesh
152  (
153  IOobject
154  (
155  regionName_,
156  procMeshes()[0].facesInstance(),
157  runTimes_.completeTime()
158  ),
159  pointField(),
160  faceList(),
161  cellList()
162  )
163  );
164  fvMesh& masterMesh = masterMeshes[proci];
165  masterMesh.setPointsInstance(procMeshes()[0].pointsInstance());
166 
167  // Initialise the addressing
168  procPointAddressing_[proci] =
169  identityMap(procMeshes()[proci].nPoints());
170  procFaceAddressing_[proci] = identityMap(procMeshes()[proci].nFaces());
171  procCellAddressing_[proci] = identityMap(procMeshes()[proci].nCells());
172 
173  // Find shared points and faces
174  autoPtr<faceCoupleInfo> couples = determineCoupledFaces
175  (
176  proci,
177  proci,
178  masterMesh,
179  proci,
180  proci,
181  procMeshes()[proci]
182  );
183 
184  // Add elements to the master mesh
185  autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
186  (
187  masterMesh,
188  procMeshes()[proci],
189  couples,
190  false
191  );
192 
193  // Renumber addressing following the add
195  (
196  map().addedPointMap(),
197  procPointAddressing_[proci]
198  );
200  (
201  map().addedFaceMap(),
202  procFaceAddressing_[proci]
203  );
205  (
206  map().addedCellMap(),
207  procCellAddressing_[proci]
208  );
209  }
210 
211  // Merge the meshes
212  for (label step=2; step<nProcs()*2; step*=2)
213  {
214  for (label proci=0; proci<nProcs(); proci+=step)
215  {
216  label procj = proci + step/2;
217 
218  if (procj >= nProcs()) continue;
219 
220  Info<< indent << "Merging mesh " << proci
221  << " with " << procj << endl;
222 
223  // Find shared points and faces
224  autoPtr<faceCoupleInfo> couples = determineCoupledFaces
225  (
226  proci,
227  procj,
228  masterMeshes[proci],
229  procj,
230  proci+step,
231  masterMeshes[procj]
232  );
233 
234  // Add elements to mesh
235  autoPtr<mapAddedPolyMesh> map = fvMeshAdder::add
236  (
237  masterMeshes[proci],
238  masterMeshes[procj],
239  couples,
240  false
241  );
242 
243  // Renumber processors that were already present
244  for
245  (
246  label mergedProci = proci;
247  mergedProci < procj;
248  mergedProci ++
249  )
250  {
252  (
253  map().oldPointMap(),
254  procPointAddressing_[mergedProci]
255  );
257  (
258  map().oldFaceMap(),
259  procFaceAddressing_[mergedProci]
260  );
262  (
263  map().oldCellMap(),
264  procCellAddressing_[mergedProci]
265  );
266  }
267 
268  // Renumber processors that were just added
269  for
270  (
271  label addedProci = procj;
272  addedProci < min(proci + step, nProcs());
273  addedProci ++
274  )
275  {
277  (
278  map().addedPointMap(),
279  procPointAddressing_[addedProci]
280  );
282  (
283  map().addedFaceMap(),
284  procFaceAddressing_[addedProci]
285  );
287  (
288  map().addedCellMap(),
289  procCellAddressing_[addedProci]
290  );
291  }
292 
293  masterMeshes.set(procj, nullptr);
294  }
295  }
296 
297  const polyBoundaryMesh& patches = masterMeshes[0].boundaryMesh();
298 
299  // Move all faces of processor cyclic patches into the associated cyclics
300  if (!patches.findIndices<processorCyclicPolyPatch>().empty())
301  {
302  // Determine what patches are to be combined into each patch
303  List<DynamicList<label>> patchPatches
304  (
305  patches.size(),
306  DynamicList<label>(1)
307  );
309  {
310  patchPatches[patchi].append(patchi);
311  }
312 
313  HashTable
314  <
315  label,
316  FixedList<label, 3>,
317  FixedList<label, 3>::Hash<>
318  > nbrProcessorCyclicIDs;
319 
321  {
322  if (!isA<processorCyclicPolyPatch>(patches[patchi])) continue;
323 
324  const processorCyclicPolyPatch& pcpp =
325  refCast<const processorCyclicPolyPatch>(patches[patchi]);
326 
327  const label proci = pcpp.myProcNo();
328  const label nbrProci = pcpp.neighbProcNo();
329  const label refPatchi = pcpp.referPatchIndex();
330  const label nbrRefPatchi = pcpp.referPatch().nbrPatchIndex();
331 
332  FixedList<label, 3> key({proci, nbrProci, refPatchi});
333  FixedList<label, 3> nbrKey({nbrProci, proci, nbrRefPatchi});
334 
335  if (nbrProcessorCyclicIDs.found(nbrKey))
336  {
337  const label nbrPatchi = nbrProcessorCyclicIDs[nbrKey];
338 
339  patchPatches[refPatchi].append
340  (
341  patchPatches[patchi].remove()
342  );
343  patchPatches[nbrRefPatchi].append
344  (
345  patchPatches[nbrPatchi].remove()
346  );
347 
348  nbrProcessorCyclicIDs.erase(nbrKey);
349  }
350  else
351  {
352  nbrProcessorCyclicIDs.insert(key, patchi);
353  }
354  }
355 
356  // Build the new patch indices and a permutation map for the mesh faces
357  labelList newPatchSizes(patches.size());
358  labelList newPatchStarts(patches.size());
359  labelList newToOldFace(masterMeshes[0].nFaces());
360  SubList<label>(newToOldFace, masterMeshes[0].nInternalFaces()) =
361  identityMap(masterMeshes[0].nInternalFaces());
363  {
364  newPatchSizes[patchi] = 0;
365  newPatchStarts[patchi] =
366  patchi == 0
367  ? masterMeshes[0].nInternalFaces()
368  : newPatchStarts[patchi-1] + newPatchSizes[patchi-1];
369 
370  forAll(patchPatches[patchi], i)
371  {
372  const polyPatch& pp = patches[patchPatches[patchi][i]];
373 
374  SubList<label>
375  (
376  newToOldFace,
377  pp.size(),
378  newPatchStarts[patchi] + newPatchSizes[patchi]
379  ) = pp.start() + identityMap(pp.size());
380 
381  newPatchSizes[patchi] += pp.size();
382  }
383  }
384 
385  // Check that the face ordering is a permutation
386  if (debug)
387  {
388  boolList newHasOldFace(newToOldFace.size(), false);
389  forAll(newToOldFace, newFacei)
390  {
391  if (newHasOldFace[newToOldFace[newFacei]])
392  {
394  << "Face re-ordering is not valid"
395  << exit(FatalError);
396  }
397  newHasOldFace[newToOldFace[newFacei]] = true;
398  }
399  }
400 
401  // Modify the mesh
402  const labelList oldToNewFace(invert(newToOldFace.size(), newToOldFace));
403  masterMeshes[0].resetPrimitives
404  (
405  NullObjectMove<pointField>(),
406  reorder(oldToNewFace, masterMeshes[0].faces()),
407  reorder(oldToNewFace, masterMeshes[0].faceOwner()),
408  reorder(oldToNewFace, masterMeshes[0].faceNeighbour()),
409  newPatchSizes,
410  newPatchStarts,
411  true
412  );
413 
414  // Update the addressing
415  forAll(procFaceAddressing_, proci)
416  {
418  (
419  oldToNewFace,
420  procFaceAddressing_[proci]
421  );
422  }
423  }
424 
425  // Filter out all processor patches
426  {
427  label nNonProcPatches = 0;
428  labelList nonProcPatchIds(patches.size(), -1);
429 
430  forAll(masterMeshes[0].boundary(), patchi)
431  {
432  if (isA<processorPolyPatch>(patches[patchi]))
433  {
434  if (patches[patchi].size() != 0)
435  {
437  << "Non-empty processor patch \""
438  << patches[patchi].name()
439  << "\" found in reconstructed mesh"
440  << exit(FatalError);
441  }
442  }
443  else
444  {
445  nonProcPatchIds[nNonProcPatches++] = patchi;
446  }
447  }
448 
449  nonProcPatchIds.resize(nNonProcPatches);
450 
451  masterMeshes[0].reorderPatches(nonProcPatchIds, false);
452  }
453 
454  // Add turning index to the face addressing
455  for (label proci=0; proci<nProcs(); proci++)
456  {
457  const fvMesh& procMesh = procMeshes_[proci];
458 
459  forAll(procFaceAddressing_[proci], procFacei)
460  {
461  const label completeFacei = procFaceAddressing_[proci][procFacei];
462 
463  if
464  (
465  !procMesh.isInternalFace(procFacei)
466  && masterMeshes[0].isInternalFace(completeFacei)
467  )
468  {
469  // Processor face is external, but the corresponding complete
470  // face is internal. Turn if the owner has changed.
471 
472  const label procOwnCelli =
473  procMesh.faceOwner()[procFacei];
474  const label completeOwnCelli =
475  masterMeshes[0].faceOwner()[completeFacei];
476 
477  if
478  (
479  procCellAddressing_[proci][procOwnCelli]
480  == completeOwnCelli
481  )
482  {
483  procFaceAddressing_[proci][procFacei] ++;
484  }
485  else
486  {
487  procFaceAddressing_[proci][procFacei] =
488  -1 - procFaceAddressing_[proci][procFacei];
489  }
490  }
491  else
492  {
493  // Processor face is the same (internal/external) as the
494  // corresponding complete face
495 
496  procFaceAddressing_[proci][procFacei] ++;
497  }
498  }
499  }
500 
501  // Clear (and thus trigger re-generation) of finite volume face addressing
502  procFaceAddressingBf_.clear();
503 
504  // Construct complete cell to proc map
505  cellProc_.resize(masterMeshes[0].nCells());
506  forAll(procCellAddressing_, proci)
507  {
508  forAll(procCellAddressing_[proci], procCelli)
509  {
510  cellProc_[procCellAddressing_[proci][procCelli]] = proci;
511  }
512  }
513 
514  // Set the complete mesh
515  completeMesh_.reset(masterMeshes.set(0, nullptr).ptr());
516  completeMesh_->setInstance(procMeshes()[0].facesInstance());
517  completeMesh_->setPointsInstance(procMeshes()[0].pointsInstance());
518 
519  // Allocate a stitcher, but do not stitch
520  completeMesh_->postConstruct(false, fvMesh::stitchType::none);
521 
522  Info<< decrIndent;
523 }
524 
525 
526 void Foam::domainDecomposition::reconstructPoints()
527 {
528  const label pointsCompare =
529  compareInstances
530  (
531  completeMesh().pointsInstance(),
532  procMeshes_[0].pointsInstance()
533  );
534 
535  if (pointsCompare == 1)
536  {
537  pointField completePoints(completeMesh().nPoints());
538 
539  for (label proci = 0; proci < nProcs(); proci++)
540  {
541  const fvMesh& procMesh = procMeshes_[proci];
542 
543  completePoints.rmap(procMesh.points(), procPointAddressing_[proci]);
544  }
545 
546  completeMesh_->setPoints(completePoints);
547  }
548 }
549 
550 
551 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
#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:241
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:257
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
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:234
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
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.
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:227
static const char nl
Definition: Ostream.H:266
faceListList boundary(nPatches)