faMeshDecomposition.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2016-2017 Wikki Ltd
9  Copyright (C) 2018-2025 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "faMeshDecomposition.H"
30 #include "Time.H"
31 #include "dictionary.H"
32 #include "labelIOList.H"
33 #include "processorFaPatch.H"
34 #include "faMesh.H"
35 #include "OSspecific.H"
36 #include "Map.H"
37 #include "SLList.H"
38 #include "ListOps.H"
39 #include "globalMeshData.H"
40 
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 
43 void Foam::faMeshDecomposition::distributeFaces()
44 {
45  const word& polyMeshRegionName = mesh().name();
46 
47  Info<< "\nCalculating distribution of finiteArea faces" << endl;
48 
49  cpuTime decompositionTime;
50 
51  for (label proci = 0; proci < nProcs(); ++proci)
52  {
53  Time processorDb
54  (
56  time().rootPath(),
57  time().caseName()/("processor" + Foam::name(proci)),
58  false, // No function objects
59  false // No extra controlDict libs
60  );
61 
62  polyMesh procFvMesh
63  (
64  IOobject
65  (
66  polyMeshRegionName,
67  processorDb.timeName(),
68  processorDb
69  )
70  );
71 
72  IOobject ioAddr
73  (
74  "procAddressing",
75  "constant",
77  procFvMesh,
81  );
82 
83 
84  // faceProcAddressing (polyMesh)
85  ioAddr.rename("faceProcAddressing");
86  labelIOList fvFaceProcAddressing(ioAddr);
87 
88  labelHashSet faceProcAddressingHash;
89  faceProcAddressingHash.reserve(fvFaceProcAddressing.size());
90 
91  // If faMesh's fvPatch is a part of the global face zones, faces of that
92  // patch will be present on all processors. Because of that, looping
93  // through faceProcAddressing will decompose global faMesh faces to the
94  // very last processor regardless of where fvPatch is really decomposed.
95  // Since global faces which do not belong to specific processor are
96  // located at the end of the faceProcAddressing, cutting it at
97  // i = owner.size() will correctly decompose faMesh faces.
98  // Vanja Skuric, 2016-04-21
99  if (hasGlobalFaceZones_)
100  {
101  // owner (polyMesh)
102  ioAddr.rename("owner");
103  const label ownerSize = labelIOList(ioAddr).size();
104 
105  for (int i = 0; i < ownerSize; ++i)
106  {
107  faceProcAddressingHash.insert(fvFaceProcAddressing[i]);
108  }
109  }
110  else
111  {
112  faceProcAddressingHash.insert
113  (
114  static_cast<labelList&>(fvFaceProcAddressing)
115  );
116  }
117 
118  forAll(faceLabels(), facei)
119  {
120  // With +1 for lookup in faceMap with flip encoding
121  const label index = (faceLabels()[facei] + 1);
122 
123  if (faceProcAddressingHash.found(index))
124  {
125  faceToProc_[facei] = proci;
126  }
127  }
128  }
129 
130  Info<< "\nFinished decomposition in "
131  << decompositionTime.elapsedCpuTime()
132  << " s" << endl;
133 }
134 
135 
136 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
137 
139 (
140  const polyMesh& mesh,
141  const label nProcessors,
142  const dictionary& params
143 )
144 :
145  faMesh(mesh),
146  nProcs_(nProcessors),
147  distributed_(false),
148  hasGlobalFaceZones_(false),
149  faceToProc_(nFaces()),
150  procFaceLabels_(nProcs_),
151  procMeshEdgesMap_(nProcs_),
152  procNInternalEdges_(nProcs_, Zero),
153  procPatchEdgeLabels_(nProcs_),
154  procPatchPointAddressing_(nProcs_),
155  procPatchEdgeAddressing_(nProcs_),
156  procEdgeAddressing_(nProcs_),
157  procFaceAddressing_(nProcs_),
158  procBoundaryAddressing_(nProcs_),
159  procPatchSize_(nProcs_),
160  procPatchStartIndex_(nProcs_),
161  procNeighbourProcessors_(nProcs_),
162  procProcessorPatchSize_(nProcs_),
163  procProcessorPatchStartIndex_(nProcs_),
164  globallySharedPoints_(),
165  cyclicParallel_(false)
166 {
168 }
169 
170 
171 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
172 
174 (
175  const dictionary& params
176 )
177 {
178  params.readIfPresent("distributed", distributed_);
179  if (params.found("globalFaceZones"))
180  {
181  hasGlobalFaceZones_ = true;
182  }
183 }
184 
185 
187 {
188  // Decide which cell goes to which processor
189  distributeFaces();
190 
191  const word& polyMeshRegionName = mesh().name();
192 
193  Info<< "\nDistributing faces to processors" << endl;
194 
195  labelList nLocalFaces(nProcs_, Zero);
196 
197  // Pass 1: determine local sizes, sanity check
198 
199  forAll(faceToProc_, facei)
200  {
201  const label proci = faceToProc_[facei];
202 
203  if (proci < 0 || proci >= nProcs_)
204  {
206  << "Invalid processor label " << proci
207  << " for face " << facei << nl
208  << abort(FatalError);
209  }
210  else
211  {
212  ++nLocalFaces[proci];
213  }
214  }
215 
216  // Adjust lengths
217  forAll(nLocalFaces, proci)
218  {
219  procFaceAddressing_[proci].resize(nLocalFaces[proci]);
220  nLocalFaces[proci] = 0; // restart list
221  }
222 
223  // Pass 2: fill in local lists
224  forAll(faceToProc_, facei)
225  {
226  const label proci = faceToProc_[facei];
227  const label localFacei = nLocalFaces[proci];
228  ++nLocalFaces[proci];
229 
230  procFaceAddressing_[proci][localFacei] = facei;
231  }
232 
233 
234  // Find processor mesh faceLabels and ...
235 
236  for (label procI = 0; procI < nProcs(); procI++)
237  {
238  Time processorDb
239  (
241  time().rootPath(),
242  time().caseName()/("processor" + Foam::name(procI)),
243  false, // No function objects
244  false // No extra controlDict libs
245  );
246 
247  polyMesh procFvMesh
248  (
249  IOobject
250  (
251  polyMeshRegionName,
252  processorDb.timeName(),
253  processorDb
254  )
255  );
256 
257  IOobject ioAddr
258  (
259  "procAddressing",
260  "constant",
262  procFvMesh,
266  );
267 
268 
269  // pointProcAddressing (polyMesh)
270  ioAddr.rename("pointProcAddressing");
271  labelIOList fvPointProcAddressing(ioAddr);
272 
273  Map<label> fvFaceProcAddressingHash;
274 
275  {
276  // faceProcAddressing (polyMesh)
277  ioAddr.rename("faceProcAddressing");
278  labelIOList fvFaceProcAddressing(ioAddr);
279 
280  fvFaceProcAddressingHash = invertToMap(fvFaceProcAddressing);
281  }
282 
283 
284  const labelList& curProcFaceAddressing = procFaceAddressing_[procI];
285 
286  labelList& curFaceLabels = procFaceLabels_[procI];
287 
288  curFaceLabels = labelList(curProcFaceAddressing.size(), -1);
289 
290  forAll(curProcFaceAddressing, faceI)
291  {
292  curFaceLabels[faceI] =
293  fvFaceProcAddressingHash.find
294  (
295  faceLabels()[curProcFaceAddressing[faceI]] + 1
296  ).val();
297  }
298 
299  // Create processor finite area mesh
300  faMesh procMesh
301  (
302  procFvMesh,
303  labelList(procFaceLabels_[procI])
304  );
305 
306  const uindirectPrimitivePatch& patch = this->patch();
307  const Map<label>& map = patch.meshPointMap();
308 
309  EdgeMap<label> edgesHash;
310 
311  const label nIntEdges = patch.nInternalEdges();
312 
313  for (label edgei = 0; edgei < nIntEdges; ++edgei)
314  {
315  edgesHash.insert(patch.edges()[edgei], edgesHash.size());
316  }
317 
318  forAll(boundary(), patchi)
319  {
320  // Include emptyFaPatch
321  const label size = boundary()[patchi].labelList::size();
322 
323  for (label edgei=0; edgei < size; ++edgei)
324  {
325  edgesHash.insert
326  (
327  patch.edges()[boundary()[patchi][edgei]],
328  edgesHash.size()
329  );
330  }
331  }
332 
333 
334  const uindirectPrimitivePatch& procPatch = procMesh.patch();
335  const labelList& procMeshPoints = procPatch.meshPoints();
336  const edgeList& procEdges = procPatch.edges();
337 
338  labelList& curPatchPointAddressing = procPatchPointAddressing_[procI];
339  curPatchPointAddressing.resize(procMeshPoints.size(), -1);
340 
341  forAll(procMeshPoints, pointi)
342  {
343  curPatchPointAddressing[pointi] =
344  map[fvPointProcAddressing[procMeshPoints[pointi]]];
345  }
346 
347  labelList& curPatchEdgeAddressing = procPatchEdgeAddressing_[procI];
348  curPatchEdgeAddressing.resize(procEdges.size(), -1);
349 
350  Map<label>& curMap = procMeshEdgesMap_[procI];
351  curMap.clear();
352  curMap.reserve(procEdges.size());
353 
354  forAll(procEdges, edgeI)
355  {
356  edge curGlobalEdge(curPatchPointAddressing, procEdges[edgeI]);
357  curPatchEdgeAddressing[edgeI] = edgesHash.find(curGlobalEdge).val();
358  }
359 
360  forAll(curPatchEdgeAddressing, edgeI)
361  {
362  curMap.insert(curPatchEdgeAddressing[edgeI], edgeI);
363  }
364 
365  procNInternalEdges_[procI] = procPatch.nInternalEdges();
366  }
367 
368 
369  Info << "\nDistributing edges to processors" << endl;
370 
371  // Loop through all internal edges and decide which processor they
372  // belong to. First visit all internal edges.
373 
374  // set references to the original mesh
375  const faBoundaryMesh& patches = boundary();
376  const edgeList& edges = this->edges();
377  const labelList& owner = edgeOwner();
378  const labelList& neighbour = edgeNeighbour();
379 
380  // Memory management
381  {
382  List<SLList<label>> procEdgeList(nProcs());
383 
384  forAll(procEdgeList, procI)
385  {
386  for(label i=0; i<procNInternalEdges_[procI]; i++)
387  {
388  procEdgeList[procI].append(procPatchEdgeAddressing_[procI][i]);
389  }
390  }
391 
392 
393  // Detect inter-processor boundaries
394 
395  // Neighbour processor for each subdomain
396  List<SLList<label>> interProcBoundaries(nProcs());
397 
398  // Edge labels belonging to each inter-processor boundary
399  List<SLList<SLList<label>>> interProcBEdges(nProcs());
400 
401  List<SLList<label>> procPatchIndex(nProcs());
402 
403  forAll(neighbour, edgeI)
404  {
405  if (faceToProc_[owner[edgeI]] != faceToProc_[neighbour[edgeI]])
406  {
407  // inter - processor patch edge found. Go through the list of
408  // inside boundaries for the owner processor and try to find
409  // this inter-processor patch.
410 
411  bool interProcBouFound = false;
412 
413  const label ownProc = faceToProc_[owner[edgeI]];
414  const label neiProc = faceToProc_[neighbour[edgeI]];
415 
416  auto curInterProcBdrsOwnIter =
417  interProcBoundaries[ownProc].cbegin();
418 
419  auto curInterProcBEdgesOwnIter =
420  interProcBEdges[ownProc].begin();
421 
422  // WARNING: Synchronous SLList iterators
423 
424  for
425  (
426  ;
427  curInterProcBdrsOwnIter.good()
428  && curInterProcBEdgesOwnIter.good();
429  ++curInterProcBdrsOwnIter,
430  ++curInterProcBEdgesOwnIter
431  )
432  {
433  if (curInterProcBdrsOwnIter() == neiProc)
434  {
435  // the inter - processor boundary exists. Add the face
436  interProcBouFound = true;
437 
438  bool neighbourFound = false;
439 
440  curInterProcBEdgesOwnIter().append(edgeI);
441 
442  auto curInterProcBdrsNeiIter =
443  interProcBoundaries[neiProc].cbegin();
444 
445  auto curInterProcBEdgesNeiIter =
446  interProcBEdges[neiProc].begin();
447 
448  // WARNING: Synchronous SLList iterators
449 
450  for
451  (
452  ;
453  curInterProcBdrsNeiIter.good()
454  && curInterProcBEdgesNeiIter.good();
455  ++curInterProcBdrsNeiIter,
456  ++curInterProcBEdgesNeiIter
457  )
458  {
459  if (curInterProcBdrsNeiIter() == ownProc)
460  {
461  // boundary found. Add the face
462  neighbourFound = true;
463 
464  curInterProcBEdgesNeiIter().append(edgeI);
465  }
466 
467  if (neighbourFound) break;
468  }
469 
470  if (interProcBouFound && !neighbourFound)
471  {
473  ("faDomainDecomposition::decomposeMesh()")
474  << "Inconsistency in inter - "
475  << "processor boundary lists for processors "
476  << ownProc << " and " << neiProc
477  << abort(FatalError);
478  }
479  }
480 
481  if (interProcBouFound) break;
482  }
483 
484  if (!interProcBouFound)
485  {
486  // inter - processor boundaries do not exist and need to
487  // be created
488 
489  // set the new addressing information
490 
491  // owner
492  interProcBoundaries[ownProc].append(neiProc);
493  interProcBEdges[ownProc].append(SLList<label>(edgeI));
494 
495  // neighbour
496  interProcBoundaries[neiProc].append(ownProc);
497  interProcBEdges[neiProc]
498  .append
499  (
500  SLList<label>(edgeI)
501  );
502  }
503  }
504  }
505 
506 
507  // Loop through patches. For cyclic boundaries detect inter-processor
508  // edges; for all other, add edges to the edge list and remember start
509  // and size of all patches.
510 
511  // for all processors, set the size of start index and patch size
512  // lists to the number of patches in the mesh
513  forAll(procPatchSize_, procI)
514  {
515  procPatchSize_[procI].setSize(patches.size());
516  procPatchStartIndex_[procI].setSize(patches.size());
517  }
518 
519  forAll(patches, patchI)
520  {
521  // Reset size and start index for all processors
522  forAll(procPatchSize_, procI)
523  {
524  procPatchSize_[procI][patchI] = 0;
525  procPatchStartIndex_[procI][patchI] =
526  procEdgeList[procI].size();
527  }
528 
529  const label patchStart = patches[patchI].start();
530 
531 // if (!isA<cyclicFaPatch>(patches[patchI]))
532  if (true)
533  {
534  // Normal patch. Add edges to processor where the face
535  // next to the edge lives
536 
537  const labelListList& eF = patch().edgeFaces();
538 
539  const label size = patches[patchI].labelList::size();
540 
541  labelList patchEdgeFaces(size, -1);
542 
543  for(int eI=0; eI<size; eI++)
544  {
545  patchEdgeFaces[eI] = eF[patches[patchI][eI]][0];
546  }
547 
548  forAll(patchEdgeFaces, edgeI)
549  {
550  const label curProc = faceToProc_[patchEdgeFaces[edgeI]];
551 
552  // add the face
553  procEdgeList[curProc].append(patchStart + edgeI);
554 
555  // increment the number of edges for this patch
556  procPatchSize_[curProc][patchI]++;
557  }
558  }
559  else
560  {
561  // Cyclic patch special treatment
562 
563  const faPatch& cPatch = patches[patchI];
564 
565  const label cycOffset = cPatch.size()/2;
566 
567  // Set reference to faceCells for both patches
568  const labelList::subList firstEdgeFaces
569  (
570  cPatch.edgeFaces(),
571  cycOffset
572  );
573 
574  const labelList::subList secondEdgeFaces
575  (
576  cPatch.edgeFaces(),
577  cycOffset,
578  cycOffset
579  );
580 
581  forAll(firstEdgeFaces, edgeI)
582  {
583  if
584  (
585  faceToProc_[firstEdgeFaces[edgeI]]
586  != faceToProc_[secondEdgeFaces[edgeI]]
587  )
588  {
589  // This edge becomes an inter-processor boundary edge
590  // inter - processor patch edge found. Go through
591  // the list of inside boundaries for the owner
592  // processor and try to find this inter-processor
593  // patch.
594 
595  cyclicParallel_ = true;
596 
597  bool interProcBouFound = false;
598 
599  const label ownProc =
600  faceToProc_[firstEdgeFaces[edgeI]];
601  const label neiProc =
602  faceToProc_[secondEdgeFaces[edgeI]];
603 
604  auto curInterProcBdrsOwnIter =
605  interProcBoundaries[ownProc].cbegin();
606 
607  auto curInterProcBEdgesOwnIter =
608  interProcBEdges[ownProc].begin();
609 
610  // WARNING: Synchronous SLList iterators
611 
612  for
613  (
614  ;
615  curInterProcBdrsOwnIter.good()
616  && curInterProcBEdgesOwnIter.good();
617  ++curInterProcBdrsOwnIter,
618  ++curInterProcBEdgesOwnIter
619  )
620  {
621  if (curInterProcBdrsOwnIter() == neiProc)
622  {
623  // the inter - processor boundary exists.
624  // Add the face
625  interProcBouFound = true;
626 
627  bool neighbourFound = false;
628 
629  curInterProcBEdgesOwnIter()
630  .append(patchStart + edgeI);
631 
632  auto curInterProcBdrsNeiIter
633  = interProcBoundaries[neiProc].cbegin();
634 
635  auto curInterProcBEdgesNeiIter =
636  interProcBEdges[neiProc].begin();
637 
638  // WARNING: Synchronous SLList iterators
639 
640  for
641  (
642  ;
643  curInterProcBdrsNeiIter.good()
644  && curInterProcBEdgesNeiIter.good();
645  ++curInterProcBdrsNeiIter,
646  ++curInterProcBEdgesNeiIter
647  )
648  {
649  if (curInterProcBdrsNeiIter() == ownProc)
650  {
651  // boundary found. Add the face
652  neighbourFound = true;
653 
654  curInterProcBEdgesNeiIter()
655  .append
656  (
657  patchStart
658  + cycOffset
659  + edgeI
660  );
661  }
662 
663  if (neighbourFound) break;
664  }
665 
666  if (interProcBouFound && !neighbourFound)
667  {
669  (
670  "faDomainDecomposition::decomposeMesh()"
671  ) << "Inconsistency in inter-processor "
672  << "boundary lists for processors "
673  << ownProc << " and " << neiProc
674  << " in cyclic boundary matching"
675  << abort(FatalError);
676  }
677  }
678 
679  if (interProcBouFound) break;
680  }
681 
682  if (!interProcBouFound)
683  {
684  // inter - processor boundaries do not exist
685  // and need to be created
686 
687  // set the new addressing information
688 
689  // owner
690  interProcBoundaries[ownProc].append(neiProc);
691  interProcBEdges[ownProc]
692  .append(SLList<label>(patchStart + edgeI));
693 
694  // neighbour
695  interProcBoundaries[neiProc].append(ownProc);
696  interProcBEdges[neiProc]
697  .append
698  (
699  SLList<label>
700  (
701  patchStart
702  + cycOffset
703  + edgeI
704  )
705  );
706  }
707  }
708  else
709  {
710  // This cyclic edge remains on the processor
711  label ownProc = faceToProc_[firstEdgeFaces[edgeI]];
712 
713  // add the edge
714  procEdgeList[ownProc].append(patchStart + edgeI);
715 
716  // increment the number of edges for this patch
717  procPatchSize_[ownProc][patchI]++;
718 
719  // Note: I cannot add the other side of the cyclic
720  // boundary here because this would violate the order.
721  // They will be added in a separate loop below
722  }
723  }
724 
725  // Ordering in cyclic boundaries is important.
726  // Add the other half of cyclic edges for cyclic boundaries
727  // that remain on the processor
728  forAll(secondEdgeFaces, edgeI)
729  {
730  if
731  (
732  faceToProc_[firstEdgeFaces[edgeI]]
733  == faceToProc_[secondEdgeFaces[edgeI]]
734  )
735  {
736  // This cyclic edge remains on the processor
737  label ownProc = faceToProc_[firstEdgeFaces[edgeI]];
738 
739  // add the second edge
740  procEdgeList[ownProc].append
741  (patchStart + cycOffset + edgeI);
742 
743  // increment the number of edges for this patch
744  procPatchSize_[ownProc][patchI]++;
745  }
746  }
747  }
748  }
749 
750  // Convert linked lists into normal lists
751  // Add inter-processor boundaries and remember start indices
752  forAll(procEdgeList, procI)
753  {
754  // Get internal and regular boundary processor faces
755  SLList<label>& curProcEdges = procEdgeList[procI];
756 
757  // Get reference to processor edge addressing
758  labelList& curProcEdgeAddressing = procEdgeAddressing_[procI];
759 
760  labelList& curProcNeighbourProcessors =
761  procNeighbourProcessors_[procI];
762 
763  labelList& curProcProcessorPatchSize =
764  procProcessorPatchSize_[procI];
765 
766  labelList& curProcProcessorPatchStartIndex =
767  procProcessorPatchStartIndex_[procI];
768 
769  // calculate the size
770  label nEdgesOnProcessor = curProcEdges.size();
771 
772  for (const auto& bedges : interProcBEdges[procI])
773  {
774  nEdgesOnProcessor += bedges.size();
775  }
776 
777  curProcEdgeAddressing.setSize(nEdgesOnProcessor);
778 
779  // Fill in the list. Calculate turning index.
780  // Turning index will be -1 only for some edges on processor
781  // boundaries, i.e. the ones where the current processor ID
782  // is in the face which is a edge neighbour.
783  // Turning index is stored as the sign of the edge addressing list
784 
785  label nEdges = 0;
786 
787  // Add internal and boundary edges
788  // Remember to increment the index by one such that the
789  // turning index works properly.
790  for (const label procEdgei : curProcEdges)
791  {
792  curProcEdgeAddressing[nEdges] = procEdgei;
793 // curProcEdgeAddressing[nEdges] = procEdgei + 1;
794  ++nEdges;
795  }
796 
797  // Add inter-processor boundary edges. At the beginning of each
798  // patch, grab the patch start index and size
799 
800  curProcNeighbourProcessors.setSize
801  (
802  interProcBoundaries[procI].size()
803  );
804 
805  curProcProcessorPatchSize.setSize
806  (
807  interProcBoundaries[procI].size()
808  );
809 
810  curProcProcessorPatchStartIndex.setSize
811  (
812  interProcBoundaries[procI].size()
813  );
814 
815  label nProcPatches = 0;
816 
817  auto curInterProcBdrsIter =
818  interProcBoundaries[procI].cbegin();
819 
820  auto curInterProcBEdgesIter =
821  interProcBEdges[procI].cbegin();
822 
823  for
824  (
825  ;
826  curInterProcBdrsIter.good()
827  && curInterProcBEdgesIter.good();
828  ++curInterProcBdrsIter,
829  ++curInterProcBEdgesIter
830  )
831  {
832  curProcNeighbourProcessors[nProcPatches] =
833  curInterProcBdrsIter();
834 
835  // Get start index for processor patch
836  curProcProcessorPatchStartIndex[nProcPatches] = nEdges;
837 
838  label& curSize =
839  curProcProcessorPatchSize[nProcPatches];
840 
841  curSize = 0;
842 
843  // add faces for this processor boundary
844 
845  for (const label edgei : *curInterProcBEdgesIter)
846  {
847  // add the edges
848 
849  // Remember to increment the index by one such that the
850  // turning index works properly.
851  if (faceToProc_[owner[edgei]] == procI)
852  {
853  curProcEdgeAddressing[nEdges] = edgei;
854 // curProcEdgeAddressing[nEdges] = edgei + 1;
855  }
856  else
857  {
858  // turning edge
859  curProcEdgeAddressing[nEdges] = edgei;
860 // curProcEdgeAddressing[nEdges] = -(edgei + 1);
861  }
862 
863  // increment the size
864  ++curSize;
865 
866  ++nEdges;
867  }
868 
869  ++nProcPatches;
870  }
871  }
872  }
873 
874  Info << "\nCalculating processor boundary addressing" << endl;
875  // For every patch of processor boundary, find the index of the original
876  // patch. Mis-alignment is caused by the fact that patches with zero size
877  // are omitted. For processor patches, set index to -1.
878  // At the same time, filter the procPatchSize_ and procPatchStartIndex_
879  // lists to exclude zero-size patches
880  forAll(procPatchSize_, procI)
881  {
882  // Make a local copy of old lists
883  const labelList oldPatchSizes = procPatchSize_[procI];
884 
885  const labelList oldPatchStarts = procPatchStartIndex_[procI];
886 
887  labelList& curPatchSizes = procPatchSize_[procI];
888 
889  labelList& curPatchStarts = procPatchStartIndex_[procI];
890 
891  const labelList& curProcessorPatchSizes =
892  procProcessorPatchSize_[procI];
893 
894  labelList& curBoundaryAddressing = procBoundaryAddressing_[procI];
895 
896  curBoundaryAddressing.setSize
897  (
898  oldPatchSizes.size()
899  + curProcessorPatchSizes.size()
900  );
901 
902  label nPatches = 0;
903 
904  forAll(oldPatchSizes, patchI)
905  {
906  //- Do not suppress zero sized patches since make parallel
907  // actions inside patches near impossible.
908  //if (oldPatchSizes[patchI] > 0)
909  {
910  curBoundaryAddressing[nPatches] = patchI;
911 
912  curPatchSizes[nPatches] = oldPatchSizes[patchI];
913 
914  curPatchStarts[nPatches] = oldPatchStarts[patchI];
915 
916  nPatches++;
917  }
918  }
919 
920  // reset to the size of live patches
921  curPatchSizes.setSize(nPatches);
922  curPatchStarts.setSize(nPatches);
923 
924  forAll(curProcessorPatchSizes, procPatchI)
925  {
926  curBoundaryAddressing[nPatches] = -1;
927 
928  nPatches++;
929  }
930 
931  curBoundaryAddressing.setSize(nPatches);
932  }
933 
934 
935  // Gather data about globally shared points
936 
937  labelList globallySharedPoints_(0);
938 
939  // Memory management
940  {
941  labelList pointsUsage(nPoints(), Zero);
942 
943  // Globally shared points are the ones used by more than 2 processors
944  // Size the list approximately and gather the points
945  labelHashSet gSharedPoints;
946  gSharedPoints.reserve(Foam::min(128, nPoints()/1000));
947 
948  // Loop through all the processors and mark up points used by
949  // processor boundaries. When a point is used twice, it is a
950  // globally shared point
951 
952  for (label procI = 0; procI < nProcs(); procI++)
953  {
954  // Get list of edge labels
955  const labelList& curEdgeLabels = procEdgeAddressing_[procI];
956 
957  // Get start of processor faces
958  const labelList& curProcessorPatchStarts =
959  procProcessorPatchStartIndex_[procI];
960 
961  const labelList& curProcessorPatchSizes =
962  procProcessorPatchSize_[procI];
963 
964  // Reset the lookup list
965  pointsUsage = 0;
966 
967  forAll(curProcessorPatchStarts, patchI)
968  {
969  const label curStart = curProcessorPatchStarts[patchI];
970  const label curEnd = curStart + curProcessorPatchSizes[patchI];
971 
972  for
973  (
974  label edgeI = curStart;
975  edgeI < curEnd;
976  edgeI++
977  )
978  {
979  // Mark the original edge as used
980  // Remember to decrement the index by one (turning index)
981  const label curE = curEdgeLabels[edgeI];
982 
983  const edge& e = edges[curE];
984 
985  forAll(e, pointI)
986  {
987  if (pointsUsage[e[pointI]] == 0)
988  {
989  // Point not previously used
990  pointsUsage[e[pointI]] = patchI + 1;
991  }
992  else if (pointsUsage[e[pointI]] != patchI + 1)
993  {
994  // Point used by some other patch = global point!
995  gSharedPoints.insert(e[pointI]);
996  }
997  }
998  }
999  }
1000  }
1001 
1002  // Grab the result from the hash list
1003  globallySharedPoints_ = gSharedPoints.sortedToc();
1004  }
1005 
1006 
1007  // Edge label for faPatches
1008 
1009  for (label procI = 0; procI < nProcs(); procI++)
1010  {
1011  // create a database
1012  Time processorDb
1013  (
1015  time().rootPath(),
1016  time().caseName()/("processor" + Foam::name(procI)),
1017  false, // No function objects
1018  false // No extra controlDict libs
1019  );
1020 
1021 
1022  // Read volume mesh
1023  polyMesh procFvMesh
1024  (
1025  IOobject
1026  (
1027  polyMeshRegionName,
1028  processorDb.timeName(),
1029  processorDb
1030  )
1031  );
1032 
1033  // create finite area mesh
1034  faMesh procMesh
1035  (
1036  procFvMesh,
1037  labelList(procFaceLabels_[procI])
1038  );
1039 
1040 
1041  const labelList& curEdgeAddressing = procEdgeAddressing_[procI];
1042 
1043  const labelList& curPatchStartIndex = procPatchStartIndex_[procI];
1044  const labelList& curPatchSize = procPatchSize_[procI];
1045 
1046  const labelList& curProcessorPatchStartIndex =
1047  procProcessorPatchStartIndex_[procI];
1048 
1049  const labelList& curProcessorPatchSize =
1050  procProcessorPatchSize_[procI];
1051 
1052  labelListList& curPatchEdgeLabels = procPatchEdgeLabels_[procI];
1053  curPatchEdgeLabels.resize
1054  (
1055  curPatchSize.size()
1056  + curProcessorPatchSize.size()
1057  );
1058 
1059  forAll(curPatchSize, patchI)
1060  {
1061  labelList& curEdgeLabels = curPatchEdgeLabels[patchI];
1062  curEdgeLabels.setSize(curPatchSize[patchI], -1);
1063 
1064  label edgeI = 0;
1065 
1066  for
1067  (
1068  int i=curPatchStartIndex[patchI];
1069  i<(curPatchStartIndex[patchI]+curPatchSize[patchI]);
1070  i++
1071  )
1072  {
1073  curEdgeLabels[edgeI] =
1074  procMeshEdgesMap_[procI][curEdgeAddressing[i]];
1075  edgeI++;
1076  }
1077  }
1078 
1079  forAll(curProcessorPatchSize, patchI)
1080  {
1081  labelList& curEdgeLabels =
1082  curPatchEdgeLabels[curPatchSize.size() + patchI];
1083  curEdgeLabels.setSize(curProcessorPatchSize[patchI], -1);
1084 
1085  label edgeI = 0;
1086 
1087  for
1088  (
1089  int i=curProcessorPatchStartIndex[patchI];
1090  i<(curProcessorPatchStartIndex[patchI]
1091  +curProcessorPatchSize[patchI]);
1092  i++
1093  )
1094  {
1095  curEdgeLabels[edgeI] =
1096  procMeshEdgesMap_[procI][curEdgeAddressing[i]];
1097  edgeI++;
1098  }
1099  }
1100  }
1101 }
1102 
1103 
1105 {
1106  const word& polyMeshRegionName = mesh().name();
1107 
1108  Info<< "\nConstructing processor FA meshes" << endl;
1109 
1110  // Make a lookup map for globally shared points
1111  Map<label> sharedPointLookup(invertToMap(globallySharedPoints_));
1112 
1113 
1114  label maxProcFaces = 0;
1115  label totProcFaces = 0;
1116  label maxProcEdges = 0;
1117  label totProcEdges = 0;
1118  label maxProcPatches = 0;
1119  label totProcPatches = 0;
1120 
1121  // Write out the meshes
1122  for (label procI = 0; procI < nProcs(); procI++)
1123  {
1124  // Create processor mesh without a boundary
1125 
1126  // create a database
1127  Time processorDb
1128  (
1130  time().rootPath(),
1131  time().caseName()/("processor" + Foam::name(procI)),
1132  false, // No function objects
1133  false // No extra controlDict libs
1134  );
1135 
1136  // Read volume mesh
1137  polyMesh procFvMesh
1138  (
1139  IOobject
1140  (
1141  polyMeshRegionName,
1142  processorDb.timeName(),
1143  processorDb
1144  )
1145  );
1146 
1147  labelIOList fvBoundaryProcAddressing
1148  (
1149  IOobject
1150  (
1151  "boundaryProcAddressing",
1152  "constant",
1154  procFvMesh,
1157  )
1158  );
1159 
1160 
1161  // Create finite area mesh
1162  faMesh procMesh
1163  (
1164  procFvMesh,
1165  labelList(procFaceLabels_[procI])
1166  );
1167 
1168  // Create processor boundary patches
1169  const labelList& curBoundaryAddressing =
1170  procBoundaryAddressing_[procI];
1171 
1172  const labelList& curPatchSizes = procPatchSize_[procI];
1173 
1174  const labelList& curNeighbourProcessors =
1175  procNeighbourProcessors_[procI];
1176 
1177  const labelList& curProcessorPatchSizes =
1178  procProcessorPatchSize_[procI];
1179 
1180  const labelListList& curPatchEdgeLabels =
1181  procPatchEdgeLabels_[procI];
1182 
1183  const faPatchList& meshPatches = boundary();
1184 
1185  faPatchList procPatches
1186  (
1187  curPatchSizes.size() + curProcessorPatchSizes.size()
1188  );
1189 
1190  label nPatches = 0;
1191 
1192  forAll(curPatchSizes, patchi)
1193  {
1194  const labelList& curEdgeLabels = curPatchEdgeLabels[nPatches];
1195 
1196  const label neiPolyPatchId =
1197  fvBoundaryProcAddressing.find
1198  (
1199  meshPatches[curBoundaryAddressing[patchi]]
1200  .ngbPolyPatchIndex()
1201  );
1202 
1203  procPatches.set
1204  (
1205  nPatches,
1206  meshPatches[curBoundaryAddressing[patchi]].clone
1207  (
1208  procMesh.boundary(),
1209  curEdgeLabels,
1210  nPatches,
1211  neiPolyPatchId
1212  )
1213  );
1214  ++nPatches;
1215  }
1216 
1217  forAll(curProcessorPatchSizes, procPatchI)
1218  {
1219  const labelList& curEdgeLabels = curPatchEdgeLabels[nPatches];
1220 
1221  procPatches.set
1222  (
1223  nPatches,
1224  new processorFaPatch
1225  (
1226  curEdgeLabels,
1227  nPatches,
1228  procMesh.boundary(),
1229  -1,
1230  procI,
1231  curNeighbourProcessors[procPatchI]
1232  )
1233  );
1234 
1235  ++nPatches;
1236  }
1237 
1238  // Add boundary patches
1239  procMesh.addFaPatches(procPatches);
1240 
1241  // More precision (for points data)
1243 
1244  procMesh.write();
1245 
1246  // Statistics
1247  Info<< nl << "Processor " << procI;
1248 
1249  if (procMesh.nFaces())
1250  {
1251  Info<< nl << " ";
1252  }
1253  else
1254  {
1255  Info<< ": ";
1256  }
1257 
1258  Info<< "Number of faces = " << procMesh.nFaces() << nl;
1259 
1260  if (procMesh.nFaces())
1261  {
1262  Info<< " Number of points = " << procMesh.nPoints() << nl;
1263  }
1264 
1265  totProcFaces += procMesh.nFaces();
1266  maxProcFaces = max(maxProcFaces, procMesh.nFaces());
1267 
1268  label nBoundaryEdges = 0;
1269  label nProcPatches = 0;
1270  label nProcEdges = 0;
1271 
1272  for (const faPatch& fap : procMesh.boundary())
1273  {
1274  const auto* ppp = isA<processorFaPatch>(fap);
1275 
1276  if (ppp)
1277  {
1278  const auto& procPatch = *ppp;
1279 
1280  Info<< " Number of edges shared with processor "
1281  << procPatch.neighbProcNo() << " = "
1282  << procPatch.size() << nl;
1283 
1284  nProcEdges += procPatch.size();
1285  ++nProcPatches;
1286  }
1287  else
1288  {
1289  nBoundaryEdges += fap.size();
1290  }
1291  }
1292 
1293  if (procMesh.nFaces() && (nBoundaryEdges || nProcEdges))
1294  {
1295  Info<< " Number of processor patches = " << nProcPatches << nl
1296  << " Number of processor edges = " << nProcEdges << nl
1297  << " Number of boundary edges = " << nBoundaryEdges << nl;
1298  }
1299 
1300  totProcEdges += nProcEdges;
1301  totProcPatches += nProcPatches;
1302  maxProcEdges = max(maxProcEdges, nProcEdges);
1303  maxProcPatches = max(maxProcPatches, nProcPatches);
1304 
1305  // Write the addressing information
1306 
1307  IOobject ioAddr
1308  (
1309  "procAddressing",
1310  "constant",
1312  procMesh.thisDb(),
1316  );
1317 
1318  // pointProcAddressing
1319  ioAddr.rename("pointProcAddressing");
1320  IOList<label>::writeContents(ioAddr, procPatchPointAddressing_[procI]);
1321 
1322  // edgeProcAddressing
1323  ioAddr.rename("edgeProcAddressing");
1324  IOList<label>::writeContents(ioAddr, procEdgeAddressing_[procI]);
1325 
1326  // faceProcAddressing
1327  ioAddr.rename("faceProcAddressing");
1328  IOList<label>::writeContents(ioAddr, procFaceAddressing_[procI]);
1329 
1330  // boundaryProcAddressing
1331  ioAddr.rename("boundaryProcAddressing");
1332  IOList<label>::writeContents(ioAddr, procBoundaryAddressing_[procI]);
1333  }
1334 
1335 
1336  // Summary stats
1337  Info<< nl
1338  << "Number of processor edges = " << (totProcEdges/2) << nl
1339  << "Max number of faces = " << maxProcFaces;
1340 
1341  if (maxProcFaces != totProcFaces)
1342  {
1343  scalar avgValue = scalar(totProcFaces)/nProcs_;
1344 
1345  Info<< " (" << 100.0*(maxProcFaces-avgValue)/avgValue
1346  << "% above average " << avgValue << ')';
1347  }
1348  Info<< nl;
1349 
1350  Info<< "Max number of processor patches = " << maxProcPatches;
1351  if (totProcPatches)
1352  {
1353  scalar avgValue = scalar(totProcPatches)/nProcs_;
1354 
1355  Info<< " (" << 100.0*(maxProcPatches-avgValue)/avgValue
1356  << "% above average " << avgValue << ')';
1357  }
1358  Info<< nl;
1359 
1360  Info<< "Max number of edges between processors = " << maxProcEdges;
1361  if (totProcEdges)
1362  {
1363  scalar avgValue = scalar(totProcEdges)/nProcs_;
1364 
1365  Info<< " (" << 100.0*(maxProcEdges-avgValue)/avgValue
1366  << "% above average " << avgValue << ')';
1367  }
1368  Info<< nl << endl;
1369 
1370  return true;
1371 }
1372 
1373 
1374 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:394
PtrList< faPatch > faPatchList
Store lists of faPatch as a PtrList.
Definition: faPatch.H:59
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:133
faceListList boundary
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:150
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
const Time & time() const
Return reference to time.
Definition: faMesh.C:1021
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
label start() const noexcept
The start label of boundary faces in the polyMesh face list.
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:411
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
SubList< label > subList
Declare type of subList.
Definition: List.H:149
Ignore writing from objectRegistry::writeObject()
static void writeContents(const IOobject &io, const UList< T > &content)
Write contents. The IOobject is never registered.
Definition: IOList.C:141
label nProcs() const noexcept
Number of processor in decomposition.
void updateParameters(const dictionary &params)
Update flags based on the decomposition model settings.
labelList faceLabels(nFaceLabels)
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Various functions to operate on Lists.
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:104
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
const fileName & caseName() const noexcept
Return the Time::caseName()
Definition: IOobject.C:468
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
IOList< label > labelIOList
IO for a List of label.
Definition: labelIOList.H:32
void setSize(const label n)
Alias for resize()
Definition: List.H:325
dynamicFvMesh & mesh
const labelList & faceLabels() const noexcept
Return the underlying polyMesh face labels.
Definition: faMeshI.H:96
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
label nPoints
bool writeDecomposition()
Write decomposition.
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
static unsigned int minPrecision(unsigned int prec) noexcept
Set the minimum default precision.
Definition: IOstream.H:440
static word controlDictName
The default control dictionary name (normally "controlDict")
Definition: Time.H:268
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
errorManip< error > abort(error &err)
Definition: errorManip.H:139
label find(const T &val) const
Find index of the first occurrence of the value.
Definition: UList.C:172
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
const polyMesh & mesh() const
Return access to polyMesh.
Definition: faMesh.C:1009
faMeshDecomposition(const polyMesh &mesh, const label nProcessors, const dictionary &params=dictionary::null)
Construct from components. Values will come from the volume decomposition.
const label nProcPatches
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:750
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
void decomposeMesh()
Decompose mesh.
const fileName & rootPath() const noexcept
Return the Time::rootPath()
Definition: IOobject.C:462
cpuTimePosix cpuTime
Selection of preferred clock mechanism for the elapsed cpu time.
Definition: cpuTimeFwd.H:36
const word & name() const
Return reference to name.
Definition: fvMesh.H:387
IOobject(const IOobject &)=default
Copy construct.
void reserve(label numEntries)
Reserve space for at least the specified number of elements (not the number of buckets) and regenerat...
Definition: HashTable.C:729
const polyBoundaryMesh & patches
Nothing to be read.
const std::string patch
OpenFOAM patch number as a std::string.
messageStream Info
Information stream (stdout output on master, null elsewhere)
std::enable_if_t< std::is_same_v< bool, TypeT >, bool > set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:498
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
List< label > labelList
A List of labels.
Definition: List.H:61
Non-intrusive singly-linked list.
Map< label > invertToMap(const labelUList &values)
Create inverse mapping, which is a lookup table into the given list.
Definition: ListOps.C:105
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:592
Do not request registration (bool: false)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127