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