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