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