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-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 "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  runTimes_.procTimes()[proci]
777  ),
778  move(procPoints),
779  move(procFaces),
780  move(procCells)
781  )
782  );
783  fvMesh& procMesh = procMeshes_[proci];
784  procMesh.setPointsInstance(completeMesh().pointsInstance());
785 
786  // Create processor boundary patch information
787  const labelList& curPatchSizes = procPatchSize[proci];
788  const labelList& curPatchStarts = procPatchStartIndex[proci];
789  const labelList& curNeighbourProcessors =
790  procNeighbourProcessors[proci];
791  const labelList& curProcessorPatchSizes =
792  procProcessorPatchSize[proci];
793  const labelList& curProcessorPatchStarts =
794  procProcessorPatchStartIndex[proci];
795  const labelListList& curSubPatchIDs =
796  procProcessorPatchSubPatchIDs[proci];
797  const labelListList& curSubStarts =
798  procProcessorPatchSubPatchStarts[proci];
799  const polyPatchList& meshPatches = completeMesh().boundaryMesh();
800 
801  // Count the number of inter-proc patches
802  label nInterProcPatches = 0;
803  forAll(curSubPatchIDs, procPatchi)
804  {
805  nInterProcPatches += curSubPatchIDs[procPatchi].size();
806  }
807  List<polyPatch*> procPatches
808  (
809  curPatchSizes.size() + nInterProcPatches,
810  nullptr
811  );
812 
813  label nPatches = 0;
814 
815  // Copy existing non-proc patches
816  forAll(curPatchSizes, patchi)
817  {
818  const polyPatch& meshPatch = meshPatches[patchi];
819 
820  procPatches[nPatches] =
821  meshPatch.clone
822  (
823  procMesh.boundaryMesh(),
824  nPatches,
825  curPatchSizes[patchi],
826  curPatchStarts[patchi]
827  ).ptr();
828 
829  nPatches++;
830  }
831 
832  // Create new inter-proc patches
833  forAll(curProcessorPatchSizes, procPatchi)
834  {
835  const labelList& subPatchID = curSubPatchIDs[procPatchi];
836  const labelList& subStarts = curSubStarts[procPatchi];
837 
838  label curStart = curProcessorPatchStarts[procPatchi];
839 
840  forAll(subPatchID, i)
841  {
842  const label size =
843  i < subPatchID.size() - 1
844  ? subStarts[i+1] - subStarts[i]
845  : curProcessorPatchSizes[procPatchi] - subStarts[i];
846 
847  if (subPatchID[i] == -1)
848  {
849  // Processor patch from internal faces
850  procPatches[nPatches] =
851  new processorPolyPatch
852  (
853  size,
854  curStart,
855  nPatches,
856  procMesh.boundaryMesh(),
857  proci,
858  curNeighbourProcessors[procPatchi]
859  );
860  }
861  else if
862  (
863  isA<nonConformalCyclicPolyPatch>
864  (
865  completeMesh().boundaryMesh()[subPatchID[i]]
866  )
867  )
868  {
869  // Non-conformal processor cyclic patch from split
870  // non-conformal cyclic patch
871  const nonConformalCyclicPolyPatch& nccPp =
872  refCast<const nonConformalCyclicPolyPatch>
873  (
874  completeMesh().boundaryMesh()[subPatchID[i]]
875  );
876 
877  procPatches[nPatches] =
878  new nonConformalProcessorCyclicPolyPatch
879  (
880  size,
881  curStart,
882  nPatches,
883  procMesh.boundaryMesh(),
884  proci,
885  curNeighbourProcessors[procPatchi],
886  nccPp.name(),
887  nccPp.origPatch().name()
888  );
889  }
890  else if
891  (
892  isA<cyclicPolyPatch>
893  (
894  completeMesh().boundaryMesh()[subPatchID[i]]
895  )
896  )
897  {
898  // Processor cyclic patch from split cyclic faces
899  const cyclicPolyPatch& cPp =
900  refCast<const cyclicPolyPatch>
901  (
902  completeMesh().boundaryMesh()[subPatchID[i]]
903  );
904 
905  procPatches[nPatches] =
906  new processorCyclicPolyPatch
907  (
908  size,
909  curStart,
910  nPatches,
911  procMesh.boundaryMesh(),
912  proci,
913  curNeighbourProcessors[procPatchi],
914  cPp.name()
915  );
916  }
917  else
918  {
920  << "Sub patch ID set for non-cyclic patch type"
921  << exit(FatalError);
922  }
923 
924  curStart += size;
925 
926  nPatches++;
927  }
928  }
929 
930  // Add patches to the mesh
931  procMesh.addFvPatches(procPatches);
932 
933  // Allocate a stitcher, but do not stitch
934  procMesh.postConstruct(false, fvMesh::stitchType::none);
935 
936  // Create point zones
937  {
938  const pointZoneList& pz = completeMesh().pointZones();
939 
940  // Go through all the zoned points and find out if they
941  // belong to a zone. If so, add it to the zone as
942  // necessary
943  List<DynamicList<label>> zonePoints(pz.size());
944 
945  // Estimate size
946  forAll(zonePoints, zoneI)
947  {
948  zonePoints[zoneI].setCapacity(pz[zoneI].size()/nProcs());
949  }
950 
951  // Use the pointToZone map to find out the single zone (if any),
952  // use slow search only for shared points.
953  forAll(curPointLabels, pointi)
954  {
955  label curPoint = curPointLabels[pointi];
956 
957  label zoneI = pointToZone[curPoint];
958 
959  if (zoneI >= 0)
960  {
961  // Single zone.
962  zonePoints[zoneI].append(pointi);
963  }
964  else if (zoneI == -2)
965  {
966  // Multiple zones. Lookup.
967  forAll(pz, zoneI)
968  {
969  label index = pz[zoneI].localIndex(curPoint);
970 
971  if (index != -1)
972  {
973  zonePoints[zoneI].append(pointi);
974  }
975  }
976  }
977  }
978 
979  procMesh.pointZones().setSize(zonePoints.size());
980  forAll(zonePoints, zoneI)
981  {
982  procMesh.pointZones().set
983  (
984  zoneI,
985  pz[zoneI].clone
986  (
987  zonePoints[zoneI].shrink(),
988  procMesh.pointZones()
989  )
990  );
991  }
992 
993  if (pz.size())
994  {
995  // Force writing on all processors
996  procMesh.pointZones().writeOpt() = IOobject::AUTO_WRITE;
997  }
998  }
999 
1000  // Create face zones
1001  {
1002  const faceZoneList& fz = completeMesh().faceZones();
1003 
1004  // Go through all the zoned face and find out if they
1005  // belong to a zone. If so, add it to the zone as
1006  // necessary
1007  List<DynamicList<label>> zoneFaces(fz.size());
1008  List<DynamicList<bool>> zoneFaceFlips(fz.size());
1009 
1010  // Estimate size
1011  forAll(zoneFaces, zoneI)
1012  {
1013  label procSize = fz[zoneI].size()/nProcs();
1014 
1015  zoneFaces[zoneI].setCapacity(procSize);
1016  zoneFaceFlips[zoneI].setCapacity(procSize);
1017  }
1018 
1019  // Go through all the zoned faces and find out if they
1020  // belong to a zone. If so, add it to the zone as
1021  // necessary
1022  forAll(curFaceLabels, facei)
1023  {
1024  // Remember to decrement the index by one (turning index)
1025  //
1026  label curF = mag(curFaceLabels[facei]) - 1;
1027 
1028  label zoneI = faceToZone[curF];
1029 
1030  if (zoneI >= 0)
1031  {
1032  // Single zone. Add the face
1033  zoneFaces[zoneI].append(facei);
1034 
1035  label index = fz[zoneI].localIndex(curF);
1036 
1037  bool flip = fz[zoneI].flipMap()[index];
1038 
1039  if (curFaceLabels[facei] < 0)
1040  {
1041  flip = !flip;
1042  }
1043 
1044  zoneFaceFlips[zoneI].append(flip);
1045  }
1046  else if (zoneI == -2)
1047  {
1048  // Multiple zones. Lookup.
1049  forAll(fz, zoneI)
1050  {
1051  label index = fz[zoneI].localIndex(curF);
1052 
1053  if (index != -1)
1054  {
1055  zoneFaces[zoneI].append(facei);
1056 
1057  bool flip = fz[zoneI].flipMap()[index];
1058 
1059  if (curFaceLabels[facei] < 0)
1060  {
1061  flip = !flip;
1062  }
1063 
1064  zoneFaceFlips[zoneI].append(flip);
1065  }
1066  }
1067  }
1068  }
1069 
1070  procMesh.faceZones().setSize(zoneFaces.size());
1071  forAll(zoneFaces, zoneI)
1072  {
1073  procMesh.faceZones().set
1074  (
1075  zoneI,
1076  fz[zoneI].clone
1077  (
1078  zoneFaces[zoneI].shrink(), // addressing
1079  zoneFaceFlips[zoneI].shrink(), // flipmap
1080  procMesh.faceZones()
1081  )
1082  );
1083  }
1084 
1085  if (fz.size())
1086  {
1087  // Force writing on all processors
1088  procMesh.faceZones().writeOpt() = IOobject::AUTO_WRITE;
1089  }
1090  }
1091 
1092  // Create cell zones
1093  {
1094  const cellZoneList& cz = completeMesh().cellZones();
1095 
1096  // Go through all the zoned cells and find out if they
1097  // belong to a zone. If so, add it to the zone as
1098  // necessary
1099  List<DynamicList<label>> zoneCells(cz.size());
1100 
1101  // Estimate size
1102  forAll(zoneCells, zoneI)
1103  {
1104  zoneCells[zoneI].setCapacity(cz[zoneI].size()/nProcs());
1105  }
1106 
1107  forAll(curCellLabels, celli)
1108  {
1109  label curCelli = curCellLabels[celli];
1110 
1111  label zoneI = cellToZone[curCelli];
1112 
1113  if (zoneI >= 0)
1114  {
1115  // Single zone.
1116  zoneCells[zoneI].append(celli);
1117  }
1118  else if (zoneI == -2)
1119  {
1120  // Multiple zones. Lookup.
1121  forAll(cz, zoneI)
1122  {
1123  label index = cz[zoneI].localIndex(curCelli);
1124 
1125  if (index != -1)
1126  {
1127  zoneCells[zoneI].append(celli);
1128  }
1129  }
1130  }
1131  }
1132 
1133  procMesh.cellZones().setSize(zoneCells.size());
1134  forAll(zoneCells, zoneI)
1135  {
1136  procMesh.cellZones().set
1137  (
1138  zoneI,
1139  cz[zoneI].clone
1140  (
1141  zoneCells[zoneI].shrink(),
1142  procMesh.cellZones()
1143  )
1144  );
1145  }
1146 
1147  if (cz.size())
1148  {
1149  // Force writing on all processors
1150  procMesh.cellZones().writeOpt() = IOobject::AUTO_WRITE;
1151  }
1152  }
1153 
1154  // Report processor and update global statistics
1155  {
1156  Info<< "Processor " << proci << nl
1157  << " Number of cells = " << procMesh.nCells()
1158  << endl;
1159 
1160  maxProcCells = max(maxProcCells, procMesh.nCells());
1161 
1162  label nBoundaryFaces = 0;
1163  label nProcPatches = 0;
1164  label nProcFaces = 0;
1165 
1166  forAll(procMesh.boundaryMesh(), patchi)
1167  {
1168  if (isA<processorPolyPatch>(procMesh.boundaryMesh()[patchi]))
1169  {
1170  const processorPolyPatch& ppp =
1171  refCast<const processorPolyPatch>
1172  (
1173  procMesh.boundaryMesh()[patchi]
1174  );
1175 
1176  Info<< " Number of faces shared with processor "
1177  << ppp.neighbProcNo() << " = " << ppp.size() << endl;
1178 
1179  nProcPatches++;
1180  nProcFaces += ppp.size();
1181  }
1182  else
1183  {
1184  nBoundaryFaces += procMesh.boundaryMesh()[patchi].size();
1185  }
1186  }
1187 
1188  Info<< " Number of processor patches = " << nProcPatches << nl
1189  << " Number of processor faces = " << nProcFaces << nl
1190  << " Number of boundary faces = " << nBoundaryFaces << nl
1191  << endl;
1192 
1193  totProcFaces += nProcFaces;
1194  totProcPatches += nProcPatches;
1195  maxProcPatches = max(maxProcPatches, nProcPatches);
1196  maxProcFaces = max(maxProcFaces, nProcFaces);
1197  }
1198  }
1199 
1200  // Determine the average number of processor elements
1201  scalar avgProcCells = scalar(completeMesh().nCells())/nProcs();
1202  scalar avgProcPatches = scalar(totProcPatches)/nProcs();
1203  scalar avgProcFaces = scalar(totProcFaces)/nProcs();
1204 
1205  // Prevent division by zero in the case of all faces on one processor
1206  if (totProcPatches == 0)
1207  {
1208  avgProcPatches = 1;
1209  }
1210  if (totProcFaces == 0)
1211  {
1212  avgProcFaces = 1;
1213  }
1214 
1215  Info<< "Number of processor faces = " << totProcFaces/2 << nl
1216  << "Max number of cells = " << maxProcCells
1217  << " (" << 100.0*(maxProcCells-avgProcCells)/avgProcCells
1218  << "% above average " << avgProcCells << ")" << nl
1219  << "Max number of processor patches = " << maxProcPatches
1220  << " (" << 100.0*(maxProcPatches-avgProcPatches)/avgProcPatches
1221  << "% above average " << avgProcPatches << ")" << nl
1222  << "Max number of faces between processors = " << maxProcFaces
1223  << " (" << 100.0*(maxProcFaces-avgProcFaces)/avgProcFaces
1224  << "% above average " << avgProcFaces << ")" << endl;
1225 
1226  // Clear (and thus trigger re-generation) of finite volume face addressing
1227  procFaceAddressingBf_.clear();
1228 }
1229 
1230 
1231 void Foam::domainDecomposition::decomposePoints()
1232 {
1233  for (label proci = 0; proci < nProcs(); proci++)
1234  {
1235  fvMesh& procMesh = procMeshes_[proci];
1236 
1237  const label pointsCompare =
1238  compareInstances
1239  (
1240  completeMesh().pointsInstance(),
1241  procMeshes_[proci].pointsInstance()
1242  );
1243 
1244  if (pointsCompare == -1)
1245  {
1246  procMesh.setPoints
1247  (
1248  pointField
1249  (
1250  completeMesh().points(),
1251  procPointAddressing_[proci]
1252  )
1253  );
1254  }
1255  }
1256 }
1257 
1258 
1259 // ************************************************************************* //
bool found
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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:257
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
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
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:64
dimensioned< scalar > mag(const dimensioned< Type > &)
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)
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:266
labelList pointLabels(nPoints, -1)
label nPatches
Definition: readKivaGrid.H:396