domainDecompositionDecompose.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 "decompositionMethod.H"
28 #include "IOobjectList.H"
29 #include "cyclicFvPatch.H"
30 #include "processorCyclicFvPatch.H"
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 void Foam::domainDecomposition::mark
37 (
38  const labelList& zoneElems,
39  const label zoneI,
40  labelList& elementToZone
41 )
42 {
43  forAll(zoneElems, i)
44  {
45  label pointi = zoneElems[i];
46 
47  if (elementToZone[pointi] == -1)
48  {
49  // First occurrence
50  elementToZone[pointi] = zoneI;
51  }
52  else if (elementToZone[pointi] >= 0)
53  {
54  // Multiple zones
55  elementToZone[pointi] = -2;
56  }
57  }
58 }
59 
60 
61 void Foam::domainDecomposition::addInterProcFace
62 (
63  const label facei,
64  const label ownerProc,
65  const label nbrProc,
66  const label subPatchID,
67  List<Map<label>>& nbrToInterPatch,
68  List<DynamicList<DynamicList<label>>>& interPatchFaces,
69  List<labelListList>& subPatchIDs,
70  List<labelListList>& subPatchStarts
71 ) const
72 {
73  // Create new interproc patches, if they do not already exist
74  label toNbrProcPatchi = -1, toOwnerProcPatchi = -1;
75  if (!nbrToInterPatch[ownerProc].found(nbrProc))
76  {
77  toNbrProcPatchi = nbrToInterPatch[ownerProc].size();
78  nbrToInterPatch[ownerProc].insert(nbrProc, toNbrProcPatchi);
79  interPatchFaces[ownerProc].append(DynamicList<label>());
80  subPatchIDs[ownerProc].append(labelList(1, subPatchID));
81  subPatchStarts[ownerProc].append(labelList(1, label(0)));
82 
83  if (facei != -1 && completeMesh().isInternalFace(facei))
84  {
85  toOwnerProcPatchi = nbrToInterPatch[nbrProc].size();
86  nbrToInterPatch[nbrProc].insert(ownerProc, toOwnerProcPatchi);
87  interPatchFaces[nbrProc].append(DynamicList<label>());
88  subPatchIDs[nbrProc].append(labelList(1, subPatchID));
89  subPatchStarts[nbrProc].append(labelList(1, label(0)));
90  }
91  }
92  else
93  {
94  toNbrProcPatchi = nbrToInterPatch[ownerProc][nbrProc];
95 
96  if (facei != -1 && completeMesh().isInternalFace(facei))
97  {
98  toOwnerProcPatchi = nbrToInterPatch[nbrProc][ownerProc];
99  }
100  }
101 
102  // If the sub patch has changed then add new sub-patch entries
103  if (subPatchIDs[ownerProc][toNbrProcPatchi].last() != subPatchID)
104  {
105  subPatchIDs[ownerProc][toNbrProcPatchi].append(subPatchID);
106  subPatchStarts[ownerProc][toNbrProcPatchi].append
107  (
108  interPatchFaces[ownerProc][toNbrProcPatchi].size()
109  );
110 
111  if (facei != -1 && completeMesh().isInternalFace(facei))
112  {
113  subPatchIDs[nbrProc][toOwnerProcPatchi].append(subPatchID);
114  subPatchStarts[nbrProc][toOwnerProcPatchi].append
115  (
116  interPatchFaces[nbrProc][toOwnerProcPatchi].size()
117  );
118  }
119  }
120 
121  // Add face to the inter-proc patches. Note use of turning index.
122  if (facei != -1)
123  {
124  interPatchFaces[ownerProc][toNbrProcPatchi].append(facei + 1);
125 
126  if (completeMesh().isInternalFace(facei))
127  {
128  interPatchFaces[nbrProc][toOwnerProcPatchi].append(- facei - 1);
129  }
130  }
131 }
132 
133 
134 Foam::labelList Foam::domainDecomposition::distributeCells()
135 {
136  Info<< "Calculating distribution of cells" << nl << endl;
137 
138  cpuTime decompositionTime;
139 
140  const dictionary decomposeParDict =
141  decompositionMethod::decomposeParDict(runTimes_.completeTime());
142 
143  scalarField cellWeights;
144  if (decomposeParDict.found("weightField"))
145  {
146  const word weightName = decomposeParDict.lookup("weightField");
147 
148  volScalarField weights
149  (
150  IOobject
151  (
152  weightName,
153  completeMesh().time().name(),
154  completeMesh(),
157  ),
158  completeMesh()
159  );
160  cellWeights = weights.primitiveField();
161  }
162 
163  const labelList result =
164  decompositionMethod::NewDecomposer(decomposeParDict)->decompose
165  (
166  completeMesh(),
167  cellWeights
168  );
169 
170  Info<< nl << "Finished decomposition in "
171  << decompositionTime.elapsedCpuTime()
172  << " s" << endl;
173 
174  return result;
175 }
176 
177 
178 void Foam::domainDecomposition::processInterCyclics
179 (
180  const labelList& cellProc,
181  const polyBoundaryMesh& patches,
182  List<DynamicList<DynamicList<label>>>& interPatchFaces,
183  List<Map<label>>& procNbrToInterPatch,
184  List<labelListList>& subPatchIDs,
185  List<labelListList>& subPatchStarts,
186  bool owner,
187  bool first
188 ) const
189 {
190  // Processor boundaries from split cyclics
192  {
193  if (isA<nonConformalCyclicPolyPatch>(patches[patchi]))
194  {
195  const nonConformalCyclicPolyPatch& nccPp =
196  refCast<const nonConformalCyclicPolyPatch>(patches[patchi]);
197 
198  if (nccPp.owner() != owner) continue;
199 
200  const polyPatch& origPp = nccPp.origPatch();
201  const polyPatch& nbrOrigPp = nccPp.nbrPatch().origPatch();
202 
203  const labelUList& origPatchFaceCells = origPp.faceCells();
204  const labelUList& nbrOrigPatchFaceCells = nbrOrigPp.faceCells();
205 
206  // Add all possible interfaces between processors that contain the
207  // original patches
208  forAll(origPatchFaceCells, origFacei)
209  {
210  const label ownerProc =
211  cellProc[origPatchFaceCells[origFacei]];
212 
213  forAll(nbrOrigPatchFaceCells, nbrOrigFacei)
214  {
215  const label nbrProc =
216  cellProc[nbrOrigPatchFaceCells[nbrOrigFacei]];
217 
218  if
219  (
220  (first && ownerProc < nbrProc)
221  || (!first && ownerProc > nbrProc)
222  )
223  {
224  addInterProcFace
225  (
226  -1,
227  ownerProc,
228  nbrProc,
229  patchi,
230  procNbrToInterPatch,
231  interPatchFaces,
232  subPatchIDs,
233  subPatchStarts
234  );
235  }
236  }
237  }
238  }
239  else if (isA<cyclicPolyPatch>(patches[patchi]))
240  {
241  const cyclicPolyPatch& cPp =
242  refCast<const cyclicPolyPatch>(patches[patchi]);
243 
244  if (cPp.owner() != owner) continue;
245 
246  const labelUList& patchFaceCells = cPp.faceCells();
247  const labelUList& nbrPatchFaceCells = cPp.nbrPatch().faceCells();
248 
249  // Add faces with different owner and neighbour processors
250  forAll(patchFaceCells, facei)
251  {
252  const label ownerProc = cellProc[patchFaceCells[facei]];
253  const label nbrProc = cellProc[nbrPatchFaceCells[facei]];
254 
255  if
256  (
257  (first && ownerProc < nbrProc)
258  || (!first && ownerProc > nbrProc)
259  )
260  {
261  addInterProcFace
262  (
263  cPp.start() + facei,
264  ownerProc,
265  nbrProc,
266  patchi,
267  procNbrToInterPatch,
268  interPatchFaces,
269  subPatchIDs,
270  subPatchStarts
271  );
272  }
273  }
274  }
275  }
276 }
277 
278 
279 void Foam::domainDecomposition::decompose()
280 {
281  // Decide which cell goes to which processor
282  cellProc_ = distributeCells();
283  Info<< nl;
284 
285  // Distribute the cells according to the given processor label
286 
287  // calculate the addressing information for the original mesh
288  Info<< "Calculating original mesh data" << nl << endl;
289 
290  // set references to the original mesh
291  const polyBoundaryMesh& patches = completeMesh().boundaryMesh();
292  const faceList& fcs = completeMesh().faces();
293  const labelList& owner = completeMesh().faceOwner();
294  const labelList& neighbour = completeMesh().faceNeighbour();
295 
296  // loop through the list of processor labels for the cell and add the
297  // cell shape to the list of cells for the appropriate processor
298 
299  Info<< "Distributing cells to processors" << nl << endl;
300 
301  // Cells per processor
302  procCellAddressing_ = invertOneToMany(nProcs(), cellProc_);
303 
304  Info<< "Distributing faces to processors" << nl << endl;
305 
306  // Loop through all internal faces and decide which processor they belong to
307  // First visit all internal faces. If cells at both sides belong to the
308  // same processor, the face is an internal face. If they are different,
309  // it belongs to both processors.
310  List<DynamicList<label>> dynProcFaceAddressing(nProcs());
311 
312  // Internal faces
313  forAll(neighbour, facei)
314  {
315  if (cellProc_[owner[facei]] == cellProc_[neighbour[facei]])
316  {
317  // Face internal to processor. Notice no turning index.
318  dynProcFaceAddressing[cellProc_[owner[facei]]].append(facei+1);
319  }
320  }
321 
322  // for all processors, set the size of start index and patch size
323  // lists to the number of patches in the mesh
324  labelListList procPatchSize(nProcs());
325  labelListList procPatchStartIndex(nProcs());
326  forAll(procPatchSize, proci)
327  {
328  procPatchSize[proci].setSize(patches.size());
329  procPatchStartIndex[proci].setSize(patches.size());
330  }
331 
332  // Patch faces
334  {
335  // Reset size and start index for all processors
336  forAll(procPatchSize, proci)
337  {
338  procPatchSize[proci][patchi] = 0;
339  procPatchStartIndex[proci][patchi] =
340  dynProcFaceAddressing[proci].size();
341  }
342 
343  const label patchStart = patches[patchi].start();
344 
345  if (!isA<cyclicPolyPatch>(patches[patchi]))
346  {
347  // Normal patch. Add faces to processor where the cell
348  // next to the face lives.
349 
350  const labelUList& patchFaceCells = patches[patchi].faceCells();
351 
352  forAll(patchFaceCells, facei)
353  {
354  const label curProc = cellProc_[patchFaceCells[facei]];
355 
356  // add the face without turning index
357  dynProcFaceAddressing[curProc].append(patchStart+facei+1);
358 
359  // increment the number of faces for this patch
360  procPatchSize[curProc][patchi]++;
361  }
362  }
363  else
364  {
365  // Cyclic patch. Add if the opposite sides are on the same
366  // processor.
367 
368  const cyclicPolyPatch& pp =
369  refCast<const cyclicPolyPatch>(patches[patchi]);
370 
371  const labelUList& patchFaceCells = pp.faceCells();
372  const labelUList& nbrPatchFaceCells = pp.nbrPatch().faceCells();
373 
374  forAll(patchFaceCells, facei)
375  {
376  const label curProc = cellProc_[patchFaceCells[facei]];
377  const label nbrProc = cellProc_[nbrPatchFaceCells[facei]];
378 
379  if (curProc == nbrProc)
380  {
381  // add the face without turning index
382  dynProcFaceAddressing[curProc].append(patchStart+facei+1);
383 
384  // increment the number of faces for this patch
385  procPatchSize[curProc][patchi]++;
386  }
387  }
388  }
389  }
390 
391  // Done internal bits of the new mesh and the ordinary patches.
392 
393  // Per processor, from neighbour processor to the inter-processor patch
394  // that communicates with that neighbour
395  List<Map<label>> procNbrToInterPatch(nProcs());
396 
397  // Per processor the faces per inter-processor patch
398  List<DynamicList<DynamicList<label>>> interPatchFaces(nProcs());
399 
400  // Sub-patch ID-s and starts for inter-processor patches
401  List<labelListList> subPatchIDs(nProcs());
402  List<labelListList> subPatchStarts(nProcs());
403 
404  // Processor boundaries from internal faces
405  forAll(neighbour, facei)
406  {
407  const label ownerProc = cellProc_[owner[facei]];
408  const label nbrProc = cellProc_[neighbour[facei]];
409 
410  if (ownerProc != nbrProc)
411  {
412  // inter - processor patch face found.
413  addInterProcFace
414  (
415  facei,
416  ownerProc,
417  nbrProc,
418  -1,
419  procNbrToInterPatch,
420  interPatchFaces,
421  subPatchIDs,
422  subPatchStarts
423  );
424  }
425  }
426 
427  // Special handling needed for the case that multiple processor cyclic
428  // patches are created on each local processor domain, e.g. if a 3x3 case
429  // is decomposed using the decomposition:
430  //
431  // | 1 | 0 | 2 |
432  // cyclic left | 2 | 0 | 1 | cyclic right
433  // | 2 | 0 | 1 |
434  //
435  // - processors 1 and 2 will both have pieces of both cyclic left- and
436  // right sub-patches present
437  // - the interface patch faces are stored in a single list, where each
438  // sub-patch is referenced into the list using a patch start index and
439  // size
440  // - if the patches are in order (in the boundary file) of left, right
441  // - processor 1 will send: left, right
442  // - processor 1 will need to receive in reverse order: right, left
443  // - similarly for processor 2
444  // - the sub-patches are therefore generated in 4 passes of the patch lists
445  // 1. add faces from owner patch where local proc i < nbr proc i
446  // 2. add faces from nbr patch where local proc i < nbr proc i
447  // 3. add faces from nbr patch where local proc i > nbr proc i
448  // 4. add faces from owner patch where local proc i > nbr proc i
449 
450  processInterCyclics
451  (
452  cellProc_,
453  patches,
454  interPatchFaces,
455  procNbrToInterPatch,
456  subPatchIDs,
457  subPatchStarts,
458  true,
459  true
460  );
461 
462  processInterCyclics
463  (
464  cellProc_,
465  patches,
466  interPatchFaces,
467  procNbrToInterPatch,
468  subPatchIDs,
469  subPatchStarts,
470  false,
471  true
472  );
473 
474  processInterCyclics
475  (
476  cellProc_,
477  patches,
478  interPatchFaces,
479  procNbrToInterPatch,
480  subPatchIDs,
481  subPatchStarts,
482  false,
483  false
484  );
485 
486  processInterCyclics
487  (
488  cellProc_,
489  patches,
490  interPatchFaces,
491  procNbrToInterPatch,
492  subPatchIDs,
493  subPatchStarts,
494  true,
495  false
496  );
497 
498  // Sort inter-proc patch by neighbour
499  labelListList procNeighbourProcessors(nProcs());
500  labelListList procProcessorPatchSize(nProcs());
501  labelListList procProcessorPatchStartIndex(nProcs());
502  List<labelListList> procProcessorPatchSubPatchIDs(nProcs());
503  List<labelListList> procProcessorPatchSubPatchStarts(nProcs());
505  forAll(procNbrToInterPatch, proci)
506  {
507  label nInterfaces = procNbrToInterPatch[proci].size();
508 
509  procNeighbourProcessors[proci].setSize(nInterfaces);
510  procProcessorPatchSize[proci].setSize(nInterfaces);
511  procProcessorPatchStartIndex[proci].setSize(nInterfaces);
512  procProcessorPatchSubPatchIDs[proci].setSize(nInterfaces);
513  procProcessorPatchSubPatchStarts[proci].setSize(nInterfaces);
514 
515  // Get sorted neighbour processors
516  const Map<label>& curNbrToInterPatch = procNbrToInterPatch[proci];
517  labelList nbrs = curNbrToInterPatch.toc();
518 
519  sortedOrder(nbrs, order);
520 
521  DynamicList<DynamicList<label>>& curInterPatchFaces =
522  interPatchFaces[proci];
523 
524  forAll(nbrs, i)
525  {
526  const label nbrProc = nbrs[i];
527  const label interPatch = curNbrToInterPatch[nbrProc];
528 
529  procNeighbourProcessors[proci][i] = nbrProc;
530  procProcessorPatchSize[proci][i] =
531  curInterPatchFaces[interPatch].size();
532  procProcessorPatchStartIndex[proci][i] =
533  dynProcFaceAddressing[proci].size();
534 
535  // Add size as last element to substarts and transfer
536  subPatchStarts[proci][interPatch].append
537  (
538  curInterPatchFaces[interPatch].size()
539  );
540  procProcessorPatchSubPatchIDs[proci][i].transfer
541  (
542  subPatchIDs[proci][interPatch]
543  );
544  procProcessorPatchSubPatchStarts[proci][i].transfer
545  (
546  subPatchStarts[proci][interPatch]
547  );
548 
549  // And add all the face labels for interPatch
550  DynamicList<label>& interPatchFaces =
551  curInterPatchFaces[interPatch];
552 
553  forAll(interPatchFaces, j)
554  {
555  dynProcFaceAddressing[proci].append(interPatchFaces[j]);
556  }
557 
558  interPatchFaces.clearStorage();
559  }
560 
561  curInterPatchFaces.clearStorage();
562  dynProcFaceAddressing[proci].shrink();
563  }
564 
565  // Transfer face addressing to non-dynamic member data
566  forAll(dynProcFaceAddressing, proci)
567  {
568  procFaceAddressing_[proci].transfer(dynProcFaceAddressing[proci]);
569  }
570 
571  if (debug)
572  {
573  forAll(procPatchStartIndex, proci)
574  {
575  Info<< "Processor:" << proci << endl;
576  Info<< " total faces:" << procFaceAddressing_[proci].size()
577  << endl;
578 
579  const labelList& curProcPatchStartIndex =
580  procPatchStartIndex[proci];
581 
582  forAll(curProcPatchStartIndex, patchi)
583  {
584  Info<< " patch:" << patchi
585  << "\tstart:" << curProcPatchStartIndex[patchi]
586  << "\tsize:" << procPatchSize[proci][patchi]
587  << endl;
588  }
589  }
590  Info<< endl;
591 
592  forAll(procNeighbourProcessors, proci)
593  {
594  Info<< "Processor " << proci << endl;
595  forAll(procNeighbourProcessors[proci], i)
596  {
597  Info<< " nbr:" << procNeighbourProcessors[proci][i] << endl;
598  Info<< " size:" << procProcessorPatchSize[proci][i] << endl;
599  Info<< " start:" << procProcessorPatchStartIndex[proci][i]
600  << endl;
601  }
602  }
603  Info<< endl;
604  }
605 
606  if (debug > 1)
607  {
608  forAll(procFaceAddressing_, proci)
609  {
610  Info<< "Processor:" << proci << endl;
611  Info<< " faces:" << procFaceAddressing_[proci] << endl;
612  }
613  }
614 
615  Info<< "Distributing points to processors" << nl << endl;
616 
617  // For every processor, loop through the list of faces for the processor.
618  // For every face, loop through the list of points and mark the point as
619  // used for the processor. Collect the list of used points for the
620  // processor.
621 
622  forAll(procPointAddressing_, proci)
623  {
624  boolList pointLabels(completeMesh().nPoints(), false);
625 
626  // Get reference to list of used faces
627  const labelList& procFaceLabels = procFaceAddressing_[proci];
628 
629  forAll(procFaceLabels, facei)
630  {
631  // Because of the turning index, some labels may be negative
632  const labelList& facePoints = fcs[mag(procFaceLabels[facei]) - 1];
633 
634  forAll(facePoints, pointi)
635  {
636  // Mark the point as used
637  pointLabels[facePoints[pointi]] = true;
638  }
639  }
640 
641  // Collect the used points
642  labelList& procPointLabels = procPointAddressing_[proci];
643 
644  procPointLabels.setSize(pointLabels.size());
645 
646  label nUsedPoints = 0;
647 
648  forAll(pointLabels, pointi)
649  {
650  if (pointLabels[pointi])
651  {
652  procPointLabels[nUsedPoints] = pointi;
653 
654  nUsedPoints++;
655  }
656  }
657 
658  // Reset the size of used points
659  procPointLabels.setSize(nUsedPoints);
660  }
661 
662  Info<< "Constructing processor meshes" << nl << endl;
663 
664  // Mark point/faces/cells that are in zones.
665  // -1 : not in zone
666  // -2 : in multiple zones
667  // >= 0 : in single given zone
668  // This will give direct lookup of elements that are in a single zone
669  // and we'll only have to revert back to searching through all zones
670  // for the duplicate elements
671 
672  // Point zones
673  labelList pointToZone(completeMesh().points().size(), -1);
674  forAll(completeMesh().pointZones(), zoneI)
675  {
676  mark(completeMesh().pointZones()[zoneI], zoneI, pointToZone);
677  }
678 
679  // Face zones
680  labelList faceToZone(completeMesh().faces().size(), -1);
681  forAll(completeMesh().faceZones(), zoneI)
682  {
683  mark(completeMesh().faceZones()[zoneI], zoneI, faceToZone);
684  }
685 
686  // Cell zones
687  labelList cellToZone(completeMesh().nCells(), -1);
688  forAll(completeMesh().cellZones(), zoneI)
689  {
690  mark(completeMesh().cellZones()[zoneI], zoneI, cellToZone);
691  }
692 
693  // Initialise information for reporting
694  label maxProcCells = 0;
695  label totProcFaces = 0;
696  label maxProcPatches = 0;
697  label totProcPatches = 0;
698  label maxProcFaces = 0;
699 
700  // Generate the meshes
701  for (label proci = 0; proci < nProcs(); proci++)
702  {
703  // Create processor points
704  const labelList& curPointLabels = procPointAddressing_[proci];
705  const pointField& meshPoints = completeMesh().points();
706  labelList pointLookup(completeMesh().nPoints(), -1);
707  pointField procPoints(curPointLabels.size());
708  forAll(curPointLabels, pointi)
709  {
710  procPoints[pointi] = meshPoints[curPointLabels[pointi]];
711  pointLookup[curPointLabels[pointi]] = pointi;
712  }
713 
714  // Create processor faces
715  const labelList& curFaceLabels = procFaceAddressing_[proci];
716  const faceList& meshFaces = completeMesh().faces();
717  labelList faceLookup(completeMesh().nFaces(), -1);
718  faceList procFaces(curFaceLabels.size());
719  forAll(curFaceLabels, facei)
720  {
721  // Mark the original face as used
722  // Remember to decrement the index by one (turning index)
723  label curF = mag(curFaceLabels[facei]) - 1;
724 
725  faceLookup[curF] = facei;
726 
727  // get the original face
728  labelList origFaceLabels;
729 
730  if (curFaceLabels[facei] >= 0)
731  {
732  // face not turned
733  origFaceLabels = meshFaces[curF];
734  }
735  else
736  {
737  origFaceLabels = meshFaces[curF].reverseFace();
738  }
739 
740  // translate face labels into local point list
741  face& procFaceLabels = procFaces[facei];
742 
743  procFaceLabels.setSize(origFaceLabels.size());
744 
745  forAll(origFaceLabels, pointi)
746  {
747  procFaceLabels[pointi] = pointLookup[origFaceLabels[pointi]];
748  }
749  }
750 
751  // Create processor cells
752  const labelList& curCellLabels = procCellAddressing_[proci];
753  const cellList& meshCells = completeMesh().cells();
754  cellList procCells(curCellLabels.size());
755  forAll(curCellLabels, celli)
756  {
757  const labelList& origCellLabels = meshCells[curCellLabels[celli]];
758  cell& curCell = procCells[celli];
759  curCell.setSize(origCellLabels.size());
760  forAll(origCellLabels, cellFacei)
761  {
762  curCell[cellFacei] = faceLookup[origCellLabels[cellFacei]];
763  }
764  }
765 
766  // Create a processor mesh without a boundary
767  procMeshes_.set
768  (
769  proci,
770  new fvMesh
771  (
772  IOobject
773  (
774  regionName_,
775  completeMesh().facesInstance(),
776  meshPath_,
777  runTimes_.procTimes()[proci]
778  ),
779  move(procPoints),
780  move(procFaces),
781  move(procCells)
782  )
783  );
784  fvMesh& procMesh = procMeshes_[proci];
785  procMesh.setPointsInstance(completeMesh().pointsInstance());
786 
787  // Create processor boundary patch information
788  const labelList& curPatchSizes = procPatchSize[proci];
789  const labelList& curPatchStarts = procPatchStartIndex[proci];
790  const labelList& curNeighbourProcessors =
791  procNeighbourProcessors[proci];
792  const labelList& curProcessorPatchSizes =
793  procProcessorPatchSize[proci];
794  const labelList& curProcessorPatchStarts =
795  procProcessorPatchStartIndex[proci];
796  const labelListList& curSubPatchIDs =
797  procProcessorPatchSubPatchIDs[proci];
798  const labelListList& curSubStarts =
799  procProcessorPatchSubPatchStarts[proci];
800  const polyPatchList& meshPatches = completeMesh().boundaryMesh();
801 
802  // Count the number of inter-proc patches
803  label nInterProcPatches = 0;
804  forAll(curSubPatchIDs, procPatchi)
805  {
806  nInterProcPatches += curSubPatchIDs[procPatchi].size();
807  }
808  List<polyPatch*> procPatches
809  (
810  curPatchSizes.size() + nInterProcPatches,
811  nullptr
812  );
813 
814  label nPatches = 0;
815 
816  // Copy existing non-proc patches
817  forAll(curPatchSizes, patchi)
818  {
819  const polyPatch& meshPatch = meshPatches[patchi];
820 
821  procPatches[nPatches] =
822  meshPatch.clone
823  (
824  procMesh.boundaryMesh(),
825  nPatches,
826  curPatchSizes[patchi],
827  curPatchStarts[patchi]
828  ).ptr();
829 
830  nPatches++;
831  }
832 
833  // Create new inter-proc patches
834  forAll(curProcessorPatchSizes, procPatchi)
835  {
836  const labelList& subPatchID = curSubPatchIDs[procPatchi];
837  const labelList& subStarts = curSubStarts[procPatchi];
838 
839  label curStart = curProcessorPatchStarts[procPatchi];
840 
841  forAll(subPatchID, i)
842  {
843  const label size =
844  i < subPatchID.size() - 1
845  ? subStarts[i+1] - subStarts[i]
846  : curProcessorPatchSizes[procPatchi] - subStarts[i];
847 
848  if (subPatchID[i] == -1)
849  {
850  // Processor patch from internal faces
851  procPatches[nPatches] =
852  new processorPolyPatch
853  (
854  size,
855  curStart,
856  nPatches,
857  procMesh.boundaryMesh(),
858  proci,
859  curNeighbourProcessors[procPatchi]
860  );
861  }
862  else if
863  (
864  isA<nonConformalCyclicPolyPatch>
865  (
866  completeMesh().boundaryMesh()[subPatchID[i]]
867  )
868  )
869  {
870  // Non-conformal processor cyclic patch from split
871  // non-conformal cyclic patch
872  const nonConformalCyclicPolyPatch& nccPp =
873  refCast<const nonConformalCyclicPolyPatch>
874  (
875  completeMesh().boundaryMesh()[subPatchID[i]]
876  );
877 
878  procPatches[nPatches] =
879  new nonConformalProcessorCyclicPolyPatch
880  (
881  size,
882  curStart,
883  nPatches,
884  procMesh.boundaryMesh(),
885  proci,
886  curNeighbourProcessors[procPatchi],
887  nccPp.name(),
888  nccPp.origPatch().name()
889  );
890  }
891  else if
892  (
893  isA<cyclicPolyPatch>
894  (
895  completeMesh().boundaryMesh()[subPatchID[i]]
896  )
897  )
898  {
899  // Processor cyclic patch from split cyclic faces
900  const cyclicPolyPatch& cPp =
901  refCast<const cyclicPolyPatch>
902  (
903  completeMesh().boundaryMesh()[subPatchID[i]]
904  );
905 
906  procPatches[nPatches] =
907  new processorCyclicPolyPatch
908  (
909  size,
910  curStart,
911  nPatches,
912  procMesh.boundaryMesh(),
913  proci,
914  curNeighbourProcessors[procPatchi],
915  cPp.name()
916  );
917  }
918  else
919  {
921  << "Sub patch ID set for non-cyclic patch type"
922  << exit(FatalError);
923  }
924 
925  curStart += size;
926 
927  nPatches++;
928  }
929  }
930 
931  // Add patches to the mesh
932  procMesh.addFvPatches(procPatches);
933 
934  // Allocate a stitcher, but do not stitch
935  procMesh.postConstruct(false, false, fvMesh::stitchType::none);
936 
937  // Create point zones
938  {
939  const pointZoneList& pz = completeMesh().pointZones();
940 
941  // Go through all the zoned points and find out if they
942  // belong to a zone. If so, add it to the zone as
943  // necessary
944  List<DynamicList<label>> zonePoints(pz.size());
945 
946  // Estimate size
947  forAll(zonePoints, zoneI)
948  {
949  zonePoints[zoneI].setCapacity(pz[zoneI].size()/nProcs());
950  }
951 
952  // Use the pointToZone map to find out the single zone (if any),
953  // use slow search only for shared points.
954  forAll(curPointLabels, pointi)
955  {
956  label curPoint = curPointLabels[pointi];
957 
958  label zoneI = pointToZone[curPoint];
959 
960  if (zoneI >= 0)
961  {
962  // Single zone.
963  zonePoints[zoneI].append(pointi);
964  }
965  else if (zoneI == -2)
966  {
967  // Multiple zones. Lookup.
968  forAll(pz, zoneI)
969  {
970  label index = pz[zoneI].localIndex(curPoint);
971 
972  if (index != -1)
973  {
974  zonePoints[zoneI].append(pointi);
975  }
976  }
977  }
978  }
979 
980  procMesh.pointZones().setSize(zonePoints.size());
981  forAll(zonePoints, zoneI)
982  {
983  procMesh.pointZones().set
984  (
985  zoneI,
986  pz[zoneI].clone
987  (
988  zonePoints[zoneI].shrink(),
989  procMesh.pointZones()
990  )
991  );
992  }
993 
994  if (pz.size())
995  {
996  // Force writing on all processors
997  procMesh.pointZones().writeOpt() = IOobject::AUTO_WRITE;
998  }
999  }
1000 
1001  // Create face zones
1002  {
1003  const faceZoneList& fz = completeMesh().faceZones();
1004 
1005  // Go through all the zoned face and find out if they
1006  // belong to a zone. If so, add it to the zone as
1007  // necessary
1008  List<DynamicList<label>> zoneFaces(fz.size());
1009  List<DynamicList<bool>> zoneFaceFlips(fz.size());
1010 
1011  // Estimate size
1012  forAll(zoneFaces, zoneI)
1013  {
1014  label procSize = fz[zoneI].size()/nProcs();
1015 
1016  zoneFaces[zoneI].setCapacity(procSize);
1017  zoneFaceFlips[zoneI].setCapacity(procSize);
1018  }
1019 
1020  // Go through all the zoned faces and find out if they
1021  // belong to a zone. If so, add it to the zone as
1022  // necessary
1023  forAll(curFaceLabels, facei)
1024  {
1025  // Remember to decrement the index by one (turning index)
1026  //
1027  label curF = mag(curFaceLabels[facei]) - 1;
1028 
1029  label zoneI = faceToZone[curF];
1030 
1031  if (zoneI >= 0)
1032  {
1033  // Single zone. Add the face
1034  zoneFaces[zoneI].append(facei);
1035 
1036  label index = fz[zoneI].localIndex(curF);
1037 
1038  if (fz[zoneI].oriented())
1039  {
1040  bool flip = fz[zoneI].flipMap()[index];
1041 
1042  if (curFaceLabels[facei] < 0)
1043  {
1044  flip = !flip;
1045  }
1046 
1047  zoneFaceFlips[zoneI].append(flip);
1048  }
1049  }
1050  else if (zoneI == -2)
1051  {
1052  // Multiple zones. Lookup.
1053  forAll(fz, zoneI)
1054  {
1055  label index = fz[zoneI].localIndex(curF);
1056 
1057  if (index != -1)
1058  {
1059  zoneFaces[zoneI].append(facei);
1060 
1061  if (fz[zoneI].oriented())
1062  {
1063  bool flip = fz[zoneI].flipMap()[index];
1064 
1065  if (curFaceLabels[facei] < 0)
1066  {
1067  flip = !flip;
1068  }
1069 
1070  zoneFaceFlips[zoneI].append(flip);
1071  }
1072  }
1073  }
1074  }
1075  }
1076 
1077  procMesh.faceZones().setSize(zoneFaces.size());
1078  forAll(zoneFaces, zoneI)
1079  {
1080  if (fz[zoneI].oriented())
1081  {
1082  procMesh.faceZones().set
1083  (
1084  zoneI,
1085  fz[zoneI].clone
1086  (
1087  zoneFaces[zoneI].shrink(), // addressing
1088  zoneFaceFlips[zoneI].shrink(), // flipmap
1089  procMesh.faceZones()
1090  )
1091  );
1092  }
1093  else
1094  {
1095  procMesh.faceZones().set
1096  (
1097  zoneI,
1098  fz[zoneI].clone
1099  (
1100  zoneFaces[zoneI].shrink(), // addressing
1101  procMesh.faceZones()
1102  )
1103  );
1104  }
1105  }
1106 
1107  if (fz.size())
1108  {
1109  // Force writing on all processors
1110  procMesh.faceZones().writeOpt() = IOobject::AUTO_WRITE;
1111  }
1112  }
1113 
1114  // Create cell zones
1115  {
1116  const cellZoneList& cz = completeMesh().cellZones();
1117 
1118  // Go through all the zoned cells and find out if they
1119  // belong to a zone. If so, add it to the zone as
1120  // necessary
1121  List<DynamicList<label>> zoneCells(cz.size());
1122 
1123  // Estimate size
1124  forAll(zoneCells, zoneI)
1125  {
1126  zoneCells[zoneI].setCapacity(cz[zoneI].size()/nProcs());
1127  }
1128 
1129  forAll(curCellLabels, celli)
1130  {
1131  label curCelli = curCellLabels[celli];
1132 
1133  label zoneI = cellToZone[curCelli];
1134 
1135  if (zoneI >= 0)
1136  {
1137  // Single zone.
1138  zoneCells[zoneI].append(celli);
1139  }
1140  else if (zoneI == -2)
1141  {
1142  // Multiple zones. Lookup.
1143  forAll(cz, zoneI)
1144  {
1145  label index = cz[zoneI].localIndex(curCelli);
1146 
1147  if (index != -1)
1148  {
1149  zoneCells[zoneI].append(celli);
1150  }
1151  }
1152  }
1153  }
1154 
1155  procMesh.cellZones().setSize(zoneCells.size());
1156  forAll(zoneCells, zoneI)
1157  {
1158  procMesh.cellZones().set
1159  (
1160  zoneI,
1161  cz[zoneI].clone
1162  (
1163  zoneCells[zoneI].shrink(),
1164  procMesh.cellZones()
1165  )
1166  );
1167  }
1168 
1169  if (cz.size())
1170  {
1171  // Force writing on all processors
1172  procMesh.cellZones().writeOpt() = IOobject::AUTO_WRITE;
1173  }
1174  }
1175 
1176  // Report processor and update global statistics
1177  {
1178  Info<< "Processor " << proci << nl
1179  << " Number of cells = " << procMesh.nCells()
1180  << endl;
1181 
1182  maxProcCells = max(maxProcCells, procMesh.nCells());
1183 
1184  label nBoundaryFaces = 0;
1185  label nProcPatches = 0;
1186  label nProcFaces = 0;
1187 
1188  forAll(procMesh.boundaryMesh(), patchi)
1189  {
1190  if (isA<processorPolyPatch>(procMesh.boundaryMesh()[patchi]))
1191  {
1192  const processorPolyPatch& ppp =
1193  refCast<const processorPolyPatch>
1194  (
1195  procMesh.boundaryMesh()[patchi]
1196  );
1197 
1198  Info<< " Number of faces shared with processor "
1199  << ppp.neighbProcNo() << " = " << ppp.size() << endl;
1200 
1201  nProcPatches++;
1202  nProcFaces += ppp.size();
1203  }
1204  else
1205  {
1206  nBoundaryFaces += procMesh.boundaryMesh()[patchi].size();
1207  }
1208  }
1209 
1210  Info<< " Number of processor patches = " << nProcPatches << nl
1211  << " Number of processor faces = " << nProcFaces << nl
1212  << " Number of boundary faces = " << nBoundaryFaces << nl
1213  << endl;
1214 
1215  totProcFaces += nProcFaces;
1216  totProcPatches += nProcPatches;
1217  maxProcPatches = max(maxProcPatches, nProcPatches);
1218  maxProcFaces = max(maxProcFaces, nProcFaces);
1219  }
1220  }
1221 
1222  // Determine the average number of processor elements
1223  scalar avgProcCells = scalar(completeMesh().nCells())/nProcs();
1224  scalar avgProcPatches = scalar(totProcPatches)/nProcs();
1225  scalar avgProcFaces = scalar(totProcFaces)/nProcs();
1226 
1227  // Prevent division by zero in the case of all faces on one processor
1228  if (totProcPatches == 0)
1229  {
1230  avgProcPatches = 1;
1231  }
1232  if (totProcFaces == 0)
1233  {
1234  avgProcFaces = 1;
1235  }
1236 
1237  Info<< "Number of processor faces = " << totProcFaces/2 << nl
1238  << "Max number of cells = " << maxProcCells
1239  << " (" << 100.0*(maxProcCells-avgProcCells)/avgProcCells
1240  << "% above average " << avgProcCells << ")" << nl
1241  << "Max number of processor patches = " << maxProcPatches
1242  << " (" << 100.0*(maxProcPatches-avgProcPatches)/avgProcPatches
1243  << "% above average " << avgProcPatches << ")" << nl
1244  << "Max number of faces between processors = " << maxProcFaces
1245  << " (" << 100.0*(maxProcFaces-avgProcFaces)/avgProcFaces
1246  << "% above average " << avgProcFaces << ")" << endl;
1247 
1248  // Clear (and thus trigger re-generation) of finite volume face addressing
1249  procFaceAddressingBf_.clear();
1250 }
1251 
1252 
1253 void Foam::domainDecomposition::decomposePoints()
1254 {
1255  for (label proci = 0; proci < nProcs(); proci++)
1256  {
1257  fvMesh& procMesh = procMeshes_[proci];
1258 
1259  const label pointsCompare =
1260  compareInstances
1261  (
1262  completeMesh().pointsInstance(),
1263  procMeshes_[proci].pointsInstance()
1264  );
1265 
1266  if (pointsCompare == -1)
1267  {
1268  procMesh.setPoints
1269  (
1270  pointField
1271  (
1272  completeMesh().points(),
1273  procPointAddressing_[proci]
1274  )
1275  );
1276  }
1277  }
1278 }
1279 
1280 
1281 // ************************************************************************* //
bool found
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static IOdictionary decomposeParDict(const Time &time)
Read and return the decomposeParDict.
static autoPtr< decompositionMethod > NewDecomposer(const dictionary &decompositionDict)
Return a reference to the selected decomposition method.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
const pointField & points
label nPoints
const fvPatchList & patches
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
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
int order(const scalar s)
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
labelListList invertOneToMany(const label len, const labelUList &)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:67
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
void mag(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
VolField< scalar > volScalarField
Definition: volFieldsFwd.H:62
T clone(const T &t)
Definition: List.H:55
PtrList< polyPatch > polyPatchList
container classes for polyPatch
Definition: polyPatchList.H:45
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
error FatalError
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
List< face > faceList
Definition: faceListFwd.H:41
UList< label > labelUList
Definition: UList.H:65
static const char nl
Definition: Ostream.H:267
labelList pointLabels(nPoints, -1)
label nPatches
Definition: readKivaGrid.H:396