domainDecomposition.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) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2019-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 "domainDecomposition.H"
30 #include "dictionary.H"
31 #include "labelIOList.H"
32 #include "processorPolyPatch.H"
34 #include "fvMesh.H"
35 #include "OSspecific.H"
36 #include "Map.H"
37 #include "DynamicList.H"
38 #include "fvFieldDecomposer.H"
39 #include "IOobjectList.H"
40 #include "PtrDynList.H"
41 #include "cellSet.H"
42 #include "faceSet.H"
43 #include "pointSet.H"
44 #include "decompositionModel.H"
45 #include "hexRef8Data.H"
46 
47 // For handling pointMeshes with additional patches
48 #include "pointMesh.H"
49 #include "meshPointPatch.H"
50 #include "processorPointPatch.H"
51 #include "DynamicField.H"
52 
53 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
54 
55 void Foam::domainDecomposition::mark
56 (
57  const labelList& zoneElems,
58  const label zoneI,
59  labelList& elementToZone
60 )
61 {
62  for (const label pointi : zoneElems)
63  {
64  if (elementToZone[pointi] == -1)
65  {
66  // First occurrence
67  elementToZone[pointi] = zoneI;
68  }
69  else if (elementToZone[pointi] >= 0)
70  {
71  // Multiple zones
72  elementToZone[pointi] = -2;
73  }
74  }
75 }
76 
77 
78 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
79 
81 (
82  const IOobject& io,
83  const fileName& decompDictFile
84 )
85 :
86  fvMesh(io),
87  facesInstancePointsPtr_
88  (
89  pointsInstance() != facesInstance()
90  ? new pointIOField
91  (
92  IOobject
93  (
94  "points",
95  facesInstance(),
96  polyMesh::meshSubDir,
97  *this,
98  IOobject::MUST_READ,
99  IOobject::NO_WRITE,
100  IOobject::NO_REGISTER
101  )
102  )
103  : nullptr
104  ),
105  decompDictFile_(decompDictFile),
106  nProcs_
107  (
108  decompositionMethod::nDomains
109  (
110  decompositionModel::New
111  (
112  *this,
113  decompDictFile
114  )
115  )
116  ),
117  distributed_(false),
118  cellToProc_(nCells()),
119  procPointAddressing_(nProcs_),
120  procFaceAddressing_(nProcs_),
121  procCellAddressing_(nProcs_),
122  procPatchSize_(nProcs_),
123  procPatchStartIndex_(nProcs_),
124  procNeighbourProcessors_(nProcs_),
125  procProcessorPatchSize_(nProcs_),
126  procProcessorPatchStartIndex_(nProcs_),
127  procProcessorPatchSubPatchIDs_(nProcs_),
128  procProcessorPatchSubPatchStarts_(nProcs_)
129 {
130  updateParameters(this->model());
131 }
132 
133 
134 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
135 
137 {
138  return decompositionModel::New(*this, decompDictFile_);
139 }
140 
141 
143 (
144  const dictionary& params
145 )
146 {
147  params.readIfPresent("distributed", distributed_);
148 }
149 
150 
151 bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets)
152 {
153  Info<< "\nConstructing processor meshes" << endl;
154 
155  // Mark point/faces/cells that are in zones.
156  // -1 : not in zone
157  // -2 : in multiple zones
158  // >= 0 : in single given zone
159  // This will give direct lookup of elements that are in a single zone
160  // and we'll only have to revert back to searching through all zones
161  // for the duplicate elements
162 
163  // Point zones
164  labelList pointToZone(points().size(), -1);
165 
166  forAll(pointZones(), zonei)
167  {
168  mark(pointZones()[zonei], zonei, pointToZone);
169  }
170 
171  // Face zones
172  labelList faceToZone(faces().size(), -1);
173 
174  forAll(faceZones(), zonei)
175  {
176  mark(faceZones()[zonei], zonei, faceToZone);
177  }
178 
179  // Cell zones
180  labelList cellToZone(nCells(), -1);
181 
182  forAll(cellZones(), zonei)
183  {
184  mark(cellZones()[zonei], zonei, cellToZone);
185  }
186 
187 
188  PtrDynList<const cellSet> cellSets;
189  PtrDynList<const faceSet> faceSets;
190  PtrDynList<const pointSet> pointSets;
191  if (decomposeSets)
192  {
193  // Read sets
194  IOobjectList objects(*this, facesInstance(), "polyMesh/sets");
195  for (const IOobject& io : objects.csorted<cellSet>())
196  {
197  cellSets.emplace_back(io);
198  }
199  for (const IOobject& io : objects.csorted<faceSet>())
200  {
201  faceSets.emplace_back(io);
202  }
203  for (const IOobject& io : objects.csorted<pointSet>())
204  {
205  pointSets.emplace_back(io);
206  }
207  }
208 
209 
210  // Load refinement data (if any)
211  hexRef8Data baseMeshData
212  (
213  IOobject
214  (
215  "dummy",
216  facesInstance(),
218  *this,
222  )
223  );
224 
225 
226  label maxProcCells = 0;
227  label maxProcFaces = 0;
228  label totProcFaces = 0;
229  label maxProcPatches = 0;
230  label totProcPatches = 0;
231 
232  // Write out the meshes
233  for (label proci = 0; proci < nProcs_; proci++)
234  {
235  // Create processor points
236  const labelList& curPointLabels = procPointAddressing_[proci];
237 
238  pointField procPoints(points(), curPointLabels);
239 
240  labelList pointLookup(nPoints(), -1);
241 
242  forAll(curPointLabels, pointi)
243  {
244  pointLookup[curPointLabels[pointi]] = pointi;
245  }
246 
247  // Create processor faces
248  const labelList& curFaceLabels = procFaceAddressing_[proci];
249 
250  const faceList& meshFaces = faces();
251 
252  labelList faceLookup(nFaces(), -1);
253 
254  faceList procFaces(curFaceLabels.size());
255 
256  forAll(curFaceLabels, facei)
257  {
258  // Mark the original face as used
259  // Remember to decrement the index by one (turning index)
260  label curF = mag(curFaceLabels[facei]) - 1;
261 
262  faceLookup[curF] = facei;
263 
264  // get the original face
265  labelList origFaceLabels;
266 
267  if (curFaceLabels[facei] >= 0)
268  {
269  // face not turned
270  origFaceLabels = meshFaces[curF];
271  }
272  else
273  {
274  origFaceLabels = meshFaces[curF].reverseFace();
275  }
276 
277  // translate face labels into local point list
278  face& procFaceLabels = procFaces[facei];
279 
280  procFaceLabels.setSize(origFaceLabels.size());
281 
282  forAll(origFaceLabels, pointi)
283  {
284  procFaceLabels[pointi] = pointLookup[origFaceLabels[pointi]];
285  }
286  }
287 
288  // Create processor cells
289  const labelList& curCellLabels = procCellAddressing_[proci];
290 
291  const cellList& meshCells = cells();
292 
293  cellList procCells(curCellLabels.size());
294 
295  forAll(curCellLabels, celli)
296  {
297  const labelList& origCellLabels = meshCells[curCellLabels[celli]];
298 
299  cell& curCell = procCells[celli];
300 
301  curCell.setSize(origCellLabels.size());
302 
303  forAll(origCellLabels, cellFacei)
304  {
305  curCell[cellFacei] = faceLookup[origCellLabels[cellFacei]];
306  }
307  }
308 
309  // Create processor mesh without a boundary
310 
311  // create a database
312  Time processorDb
313  (
315  time().rootPath(),
316  time().caseName()/("processor" + Foam::name(proci)),
317  false, // No function objects
318  false // No extra controlDict libs
319  );
320  processorDb.setTime(time());
321 
322  // create the mesh. Two situations:
323  // - points and faces come from the same time ('instance'). The mesh
324  // will get constructed in the same instance.
325  // - points come from a different time (moving mesh cases).
326  // It will read the points belonging to the faces instance and
327  // construct the procMesh with it which then gets handled as above.
328  // (so with 'old' geometry).
329  // Only at writing time will it additionally write the current
330  // points.
331 
332  autoPtr<polyMesh> procMeshPtr;
333 
334  if (facesInstancePointsPtr_)
335  {
336  // Construct mesh from facesInstance.
337  pointField facesInstancePoints
338  (
339  facesInstancePointsPtr_(),
340  curPointLabels
341  );
342 
343  procMeshPtr = autoPtr<polyMesh>::New
344  (
345  IOobject
346  (
347  this->polyMesh::name(), // region of undecomposed mesh
348  facesInstance(),
349  processorDb,
352  ),
353  std::move(facesInstancePoints),
354  std::move(procFaces),
355  std::move(procCells)
356  );
357  }
358  else
359  {
360  procMeshPtr = autoPtr<polyMesh>::New
361  (
362  IOobject
363  (
364  this->polyMesh::name(), // region of undecomposed mesh
365  facesInstance(),
366  processorDb,
369  ),
370  std::move(procPoints),
371  std::move(procFaces),
372  std::move(procCells)
373  );
374  }
375  polyMesh& procMesh = procMeshPtr();
376 
377 
378  // Create processor boundary patches
379  const labelList& curPatchSizes = procPatchSize_[proci];
380 
381  const labelList& curPatchStarts = procPatchStartIndex_[proci];
382 
383  const labelList& curNeighbourProcessors =
384  procNeighbourProcessors_[proci];
385 
386  const labelList& curProcessorPatchSizes =
387  procProcessorPatchSize_[proci];
388 
389  const labelList& curProcessorPatchStarts =
390  procProcessorPatchStartIndex_[proci];
391 
392  const labelListList& curSubPatchIDs =
393  procProcessorPatchSubPatchIDs_[proci];
394 
395  const labelListList& curSubStarts =
396  procProcessorPatchSubPatchStarts_[proci];
397 
398  const polyPatchList& meshPatches = boundaryMesh();
399 
400 
401  // Count the number of inter-proc patches
402  label nInterProcPatches = 0;
403  forAll(curSubPatchIDs, procPatchi)
404  {
405  nInterProcPatches += curSubPatchIDs[procPatchi].size();
406  }
407 
408  polyPatchList procPatches
409  (
410  curPatchSizes.size() + nInterProcPatches
411  );
412 
413  label nPatches = 0;
414 
415  forAll(curPatchSizes, patchi)
416  {
417  // Get the face labels consistent with the field mapping
418  // (reuse the patch field mappers)
419  const polyPatch& meshPatch = meshPatches[patchi];
420 
421  fvFieldDecomposer::patchFieldDecomposer patchMapper
422  (
423  SubList<label>
424  (
425  curFaceLabels,
426  curPatchSizes[patchi],
427  curPatchStarts[patchi]
428  ),
429  meshPatch.start()
430  );
431 
432  // Map existing patches
433  procPatches.set
434  (
435  nPatches,
436  meshPatch.clone
437  (
438  procMesh.boundaryMesh(),
439  nPatches,
440  patchMapper.directAddressing(),
441  curPatchStarts[patchi]
442  )
443  );
444 
445  nPatches++;
446  }
447 
448  forAll(curProcessorPatchSizes, procPatchi)
449  {
450  const labelList& subPatchID = curSubPatchIDs[procPatchi];
451  const labelList& subStarts = curSubStarts[procPatchi];
452 
453  label curStart = curProcessorPatchStarts[procPatchi];
454 
455  forAll(subPatchID, i)
456  {
457  label size =
458  (
459  i < subPatchID.size()-1
460  ? subStarts[i+1] - subStarts[i]
461  : curProcessorPatchSizes[procPatchi] - subStarts[i]
462  );
463 
464  if (subPatchID[i] == -1)
465  {
466  // From internal faces
467  procPatches.set
468  (
469  nPatches,
470  new processorPolyPatch
471  (
472  size,
473  curStart,
474  nPatches,
475  procMesh.boundaryMesh(),
476  proci,
477  curNeighbourProcessors[procPatchi]
478  )
479  );
480  }
481  else
482  {
483  const coupledPolyPatch& pcPatch
484  = refCast<const coupledPolyPatch>
485  (
486  boundaryMesh()[subPatchID[i]]
487  );
488 
489  procPatches.set
490  (
491  nPatches,
492  new processorCyclicPolyPatch
493  (
494  size,
495  curStart,
496  nPatches,
497  procMesh.boundaryMesh(),
498  proci,
499  curNeighbourProcessors[procPatchi],
500  pcPatch.name(),
501  pcPatch.transform()
502  )
503  );
504  }
505 
506  curStart += size;
507  ++nPatches;
508  }
509  }
510 
511  // Add boundary patches
512  procMesh.addPatches(procPatches);
513 
514  // Create and add zones
515 
516  // Point zones
517  {
518  const pointZoneMesh& pz = pointZones();
519 
520  // Go through all the zoned points and find out if they
521  // belong to a zone. If so, add it to the zone as
522  // necessary
523  List<DynamicList<label>> zonePoints(pz.size());
524 
525  // Estimate size
526  forAll(zonePoints, zonei)
527  {
528  zonePoints[zonei].setCapacity(pz[zonei].size()/nProcs_);
529  }
530 
531  // Use the pointToZone map to find out the single zone (if any),
532  // use slow search only for shared points.
533  forAll(curPointLabels, pointi)
534  {
535  label curPoint = curPointLabels[pointi];
536 
537  label zonei = pointToZone[curPoint];
538 
539  if (zonei >= 0)
540  {
541  // Single zone.
542  zonePoints[zonei].append(pointi);
543  }
544  else if (zonei == -2)
545  {
546  // Multiple zones. Lookup.
547  forAll(pz, zonei)
548  {
549  label index = pz[zonei].whichPoint(curPoint);
550 
551  if (index != -1)
552  {
553  zonePoints[zonei].append(pointi);
554  }
555  }
556  }
557  }
558 
559  procMesh.pointZones().clearAddressing();
560  procMesh.pointZones().setSize(zonePoints.size());
561  forAll(zonePoints, zonei)
562  {
563  procMesh.pointZones().set
564  (
565  zonei,
566  pz[zonei].clone
567  (
568  procMesh.pointZones(),
569  zonei,
570  zonePoints[zonei].shrink()
571  )
572  );
573  }
574 
575  if (pz.size())
576  {
577  // Force writing on all processors
578  procMesh.pointZones().writeOpt(IOobject::AUTO_WRITE);
579  }
580  }
581 
582  // Face zones
583  {
584  const faceZoneMesh& fz = faceZones();
585 
586  // Go through all the zoned face and find out if they
587  // belong to a zone. If so, add it to the zone as
588  // necessary
589  List<DynamicList<label>> zoneFaces(fz.size());
590  List<DynamicList<bool>> zoneFaceFlips(fz.size());
591 
592  // Estimate size
593  forAll(zoneFaces, zonei)
594  {
595  label procSize = fz[zonei].size() / nProcs_;
596 
597  zoneFaces[zonei].setCapacity(procSize);
598  zoneFaceFlips[zonei].setCapacity(procSize);
599  }
600 
601  // Go through all the zoned faces and find out if they
602  // belong to a zone. If so, add it to the zone as
603  // necessary
604  forAll(curFaceLabels, facei)
605  {
606  // Remember to decrement the index by one (turning index)
607  //
608  label curF = mag(curFaceLabels[facei]) - 1;
609 
610  label zonei = faceToZone[curF];
611 
612  if (zonei >= 0)
613  {
614  // Single zone. Add the face
615  zoneFaces[zonei].append(facei);
616 
617  label index = fz[zonei].whichFace(curF);
618 
619  bool flip = fz[zonei].flipMap()[index];
620 
621  if (curFaceLabels[facei] < 0)
622  {
623  flip = !flip;
624  }
625 
626  zoneFaceFlips[zonei].append(flip);
627  }
628  else if (zonei == -2)
629  {
630  // Multiple zones. Lookup.
631  forAll(fz, zonei)
632  {
633  label index = fz[zonei].whichFace(curF);
634 
635  if (index != -1)
636  {
637  zoneFaces[zonei].append(facei);
638 
639  bool flip = fz[zonei].flipMap()[index];
640 
641  if (curFaceLabels[facei] < 0)
642  {
643  flip = !flip;
644  }
645 
646  zoneFaceFlips[zonei].append(flip);
647  }
648  }
649  }
650  }
651 
652  procMesh.faceZones().clearAddressing();
653  procMesh.faceZones().setSize(zoneFaces.size());
654  forAll(zoneFaces, zonei)
655  {
656  procMesh.faceZones().set
657  (
658  zonei,
659  fz[zonei].clone
660  (
661  zoneFaces[zonei].shrink(), // addressing
662  zoneFaceFlips[zonei].shrink(), // flipmap
663  zonei,
664  procMesh.faceZones()
665  )
666  );
667  }
668 
669  if (fz.size())
670  {
671  // Force writing on all processors
672  procMesh.faceZones().writeOpt(IOobject::AUTO_WRITE);
673  }
674  }
675 
676  // Cell zones
677  {
678  const cellZoneMesh& cz = cellZones();
679 
680  // Go through all the zoned cells and find out if they
681  // belong to a zone. If so, add it to the zone as
682  // necessary
683  List<DynamicList<label>> zoneCells(cz.size());
684 
685  // Estimate size
686  forAll(zoneCells, zonei)
687  {
688  zoneCells[zonei].setCapacity(cz[zonei].size()/nProcs_);
689  }
690 
691  forAll(curCellLabels, celli)
692  {
693  label curCelli = curCellLabels[celli];
694 
695  label zonei = cellToZone[curCelli];
696 
697  if (zonei >= 0)
698  {
699  // Single zone.
700  zoneCells[zonei].append(celli);
701  }
702  else if (zonei == -2)
703  {
704  // Multiple zones. Lookup.
705  forAll(cz, zonei)
706  {
707  label index = cz[zonei].whichCell(curCelli);
708 
709  if (index != -1)
710  {
711  zoneCells[zonei].append(celli);
712  }
713  }
714  }
715  }
716 
717  procMesh.cellZones().clearAddressing();
718  procMesh.cellZones().setSize(zoneCells.size());
719  forAll(zoneCells, zonei)
720  {
721  procMesh.cellZones().set
722  (
723  zonei,
724  cz[zonei].clone
725  (
726  zoneCells[zonei].shrink(),
727  zonei,
728  procMesh.cellZones()
729  )
730  );
731  }
732 
733  if (cz.size())
734  {
735  // Force writing on all processors
736  procMesh.cellZones().writeOpt(IOobject::AUTO_WRITE);
737  }
738  }
739 
740  // More precision (for points data)
742 
743  procMesh.write();
744 
745  // Add pointMesh if it was available
746  const auto* pMeshPtr =
747  thisDb().cfindObject<pointMesh>(pointMesh::typeName);
748  if (pMeshPtr)
749  {
750  const auto& pMesh = *pMeshPtr;
751  const auto& pMeshBoundary = pMesh.boundary();
752 
753 
754  // 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring
755  // any additional patches
756  const auto& procPointMesh = pointMesh::New(procMesh);
757 
758  pointBoundaryMesh& procBoundary =
759  const_cast<pointBoundaryMesh&>(procPointMesh.boundary());
760 
761  // Keep track if it differs from the polyBoundaryMesh since then
762  // we need to write the boundary file.
763  bool differsFromPoly = false;
764 
765  // 2. Explicitly add subsetted meshPointPatches
766  forAll(pMeshBoundary, patchi)
767  {
768  const auto* mppPtr = isA<meshPointPatch>(pMeshBoundary[patchi]);
769  if (mppPtr && (procBoundary.findPatchID(mppPtr->name()) == -1))
770  {
771  const auto& mpp = *mppPtr;
772 
773  DynamicList<label> procMeshPoints(mpp.size());
774  DynamicField<vector> procNormals(mpp.size());
775  forAll(mpp.meshPoints(), i)
776  {
777  const label pointi = mpp.meshPoints()[i];
778  const label procPointi = pointLookup[pointi];
779  if (procPointi != -1)
780  {
781  procMeshPoints.append(procPointi);
782  procNormals.append(mpp.pointNormals()[i]);
783  }
784  }
785 
786  procBoundary.push_back
787  (
788  new meshPointPatch
789  (
790  mpp.name(),
791  procMeshPoints,
792  procNormals,
793  procBoundary.size(),
794  procBoundary,
795  meshPointPatch::typeName
796  )
797  );
798  differsFromPoly = true;
799  }
800  }
801 
802  // 3. Shuffle new patches before any processor patches
803  labelList oldToNew(procBoundary.size());
804  label newPatchi = 0;
805  forAll(procBoundary, patchi)
806  {
807  if (!isA<processorPointPatch>(procBoundary[patchi]))
808  {
809  oldToNew[patchi] = newPatchi;
810 
811  if (newPatchi != patchi)
812  {
813  differsFromPoly = true;
814  }
815 
816  newPatchi++;
817  }
818  }
819 
820  // decomposed-to-undecomposed patch numbering
821  labelList boundaryProcAddressing(identity(newPatchi));
822  boundaryProcAddressing.setSize(procBoundary.size(), -1);
823 
824  forAll(procBoundary, patchi)
825  {
826  if (isA<processorPointPatch>(procBoundary[patchi]))
827  {
828  oldToNew[patchi] = newPatchi++;
829  }
830  }
831  procBoundary.reorder(oldToNew, true);
832 
833 
834  if (differsFromPoly)
835  {
836  // Write pointMesh/boundary
837  procBoundary.write();
838 
839  // Write pointMesh/boundaryProcAddressing
840  IOobject ioAddr
841  (
842  "boundaryProcAddressing",
843  procMesh.facesInstance(),
845  procPointMesh.thisDb()
846  );
847  IOList<label>::writeContents(ioAddr, boundaryProcAddressing);
848  }
849  }
850 
851  // Write points if pointsInstance differing from facesInstance
852  if (facesInstancePointsPtr_)
853  {
854  pointIOField pointsInstancePoints
855  (
856  IOobject
857  (
858  "points",
859  pointsInstance(),
861  procMesh,
865  ),
866  std::move(procPoints)
867  );
868  pointsInstancePoints.write();
869  }
870 
871 
872  // Decompose any sets
873  if (decomposeSets)
874  {
875  forAll(cellSets, i)
876  {
877  const cellSet& cs = cellSets[i];
878  cellSet set(procMesh, cs.name(), cs.size()/nProcs_);
879  forAll(curCellLabels, i)
880  {
881  if (cs.found(curCellLabels[i]))
882  {
883  set.insert(i);
884  }
885  }
886  set.write();
887  }
888  forAll(faceSets, i)
889  {
890  const faceSet& cs = faceSets[i];
891  faceSet set(procMesh, cs.name(), cs.size()/nProcs_);
892  forAll(curFaceLabels, i)
893  {
894  if (cs.found(mag(curFaceLabels[i])-1))
895  {
896  set.insert(i);
897  }
898  }
899  set.write();
900  }
901  forAll(pointSets, i)
902  {
903  const pointSet& cs = pointSets[i];
904  pointSet set(procMesh, cs.name(), cs.size()/nProcs_);
905  forAll(curPointLabels, i)
906  {
907  if (cs.found(curPointLabels[i]))
908  {
909  set.insert(i);
910  }
911  }
912  set.write();
913  }
914  }
915 
916 
917  // Optional hexRef8 data
918  hexRef8Data
919  (
920  IOobject
921  (
922  "dummy",
923  facesInstance(),
925  procMesh,
929  ),
930  baseMeshData,
931  procCellAddressing_[proci],
932  procPointAddressing_[proci]
933  ).write();
934 
935 
936  // Statistics
937  Info<< nl << "Processor " << proci;
938 
939  if (procMesh.nCells())
940  {
941  Info<< nl << " ";
942  }
943  else
944  {
945  Info<< ": ";
946  }
947 
948  Info<< "Number of cells = " << procMesh.nCells() << nl;
949 
950  if (procMesh.nCells())
951  {
952  Info<< " Number of points = " << procMesh.nPoints() << nl;
953  }
954 
955  maxProcCells = max(maxProcCells, procMesh.nCells());
956 
957  label nBoundaryFaces = 0;
958  label nProcPatches = 0;
959  label nProcFaces = 0;
960 
961  for (const polyPatch& pp : procMesh.boundaryMesh())
962  {
963  const auto* cpp = isA<processorPolyPatch>(pp);
964 
965  if (cpp)
966  {
967  const auto& procPatch = *cpp;
968 
969  Info<< " Number of faces shared with processor "
970  << procPatch.neighbProcNo() << " = "
971  << procPatch.size() << nl;
972 
973  nProcFaces += procPatch.size();
974  ++nProcPatches;
975  }
976  else
977  {
978  nBoundaryFaces += pp.size();
979  }
980  }
981 
982  if (procMesh.nCells() && (nBoundaryFaces || nProcFaces))
983  {
984  Info<< " Number of processor patches = " << nProcPatches << nl
985  << " Number of processor faces = " << nProcFaces << nl
986  << " Number of boundary faces = " << nBoundaryFaces << nl;
987  }
988 
989  totProcFaces += nProcFaces;
990  totProcPatches += nProcPatches;
991  maxProcFaces = max(maxProcFaces, nProcFaces);
992  maxProcPatches = max(maxProcPatches, nProcPatches);
993 
994  // Write the addressing information
995 
996  IOobject ioAddr
997  (
998  "procAddressing",
999  procMesh.facesInstance(),
1001  procMesh.thisDb(),
1005  );
1006 
1007  // pointProcAddressing
1008  ioAddr.rename("pointProcAddressing");
1009  IOList<label>::writeContents(ioAddr, procPointAddressing_[proci]);
1010 
1011  // faceProcAddressing
1012  ioAddr.rename("faceProcAddressing");
1013  IOList<label>::writeContents(ioAddr, procFaceAddressing_[proci]);
1014 
1015  // cellProcAddressing
1016  ioAddr.rename("cellProcAddressing");
1017  IOList<label>::writeContents(ioAddr, procCellAddressing_[proci]);
1018 
1019  // Write patch map for backwards compatibility.
1020  // (= identity map for original patches, -1 for processor patches)
1021  label nMeshPatches = curPatchSizes.size();
1022  labelList procBoundaryAddr(identity(nMeshPatches));
1023  procBoundaryAddr.resize(nMeshPatches+nProcPatches, -1);
1024 
1025  // boundaryProcAddressing
1026  ioAddr.rename("boundaryProcAddressing");
1027  IOList<label>::writeContents(ioAddr, procBoundaryAddr);
1028  }
1029 
1030 
1031  // Summary stats
1032  Info<< nl
1033  << "Number of processor faces = " << (totProcFaces/2) << nl
1034  << "Max number of cells = " << maxProcCells;
1035 
1036  if (maxProcCells != nCells())
1037  {
1038  scalar avgValue = scalar(nCells())/nProcs_;
1039 
1040  Info<< " (" << 100.0*(maxProcCells-avgValue)/avgValue
1041  << "% above average " << avgValue << ')';
1042  }
1043  Info<< nl;
1044 
1045  Info<< "Max number of processor patches = " << maxProcPatches;
1046  if (totProcPatches)
1047  {
1048  scalar avgValue = scalar(totProcPatches)/nProcs_;
1049 
1050  Info<< " (" << 100.0*(maxProcPatches-avgValue)/avgValue
1051  << "% above average " << avgValue << ')';
1052  }
1053  Info<< nl;
1054 
1055  Info<< "Max number of faces between processors = " << maxProcFaces;
1056  if (totProcFaces)
1057  {
1058  scalar avgValue = scalar(totProcFaces)/nProcs_;
1059 
1060  Info<< " (" << 100.0*(maxProcFaces-avgValue)/avgValue
1061  << "% above average " << avgValue << ')';
1062  }
1063  Info<< nl << endl;
1064 
1065  return true;
1066 }
1067 
1068 
1069 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:394
bool writeDecomposition(const bool decomposeSets)
Write decomposition.
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with faceZone content on a polyMesh.
List< cell > cellList
List of cell.
Definition: cellListFwd.H:39
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:205
vectorIOField pointIOField
pointIOField is a vectorIOField.
Definition: pointIOField.H:38
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
static FOAM_NO_DANGLING_REFERENCE const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create MeshObject registered with typeName.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:412
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
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:194
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:400
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
PtrList< polyPatch > polyPatchList
Store lists of polyPatch as a PtrList.
Definition: polyPatch.H:56
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const cellShapeList & cells
const pointField & points
label nPoints
const auto & io
Reading is optional [identical to LAZY_READ].
ZoneMesh< pointZone, polyMesh > pointZoneMesh
A ZoneMesh with pointZone content on a polyMesh.
MeshObject wrapper of decompositionMethod.
static unsigned int minPrecision(unsigned int prec) noexcept
Set the minimum default precision.
Definition: IOstream.H:459
static word controlDictName
The default control dictionary name (normally "controlDict")
Definition: Time.H:267
void updateParameters(const dictionary &params)
Update flags based on the decomposition model settings.
static const decompositionModel & New(const polyMesh &mesh, const fileName &decompDictFile="", const dictionary *fallback=nullptr)
Read and register on mesh, optionally with alternative decomposeParDict path/name or with fallback co...
const label nProcPatches
static word meshSubDir
Return the mesh sub-directory name (usually "pointMesh")
Definition: pointMesh.H:107
decomposeUsingBbs false
Use bounding boxes (default) or unique decomposition of triangles (i.e. do not duplicate triangles) ...
Nothing to be read.
Automatically write from objectRegistry::writeObject()
messageStream Info
Information stream (stdout output on master, null elsewhere)
List< label > labelList
A List of labels.
Definition: List.H:61
domainDecomposition(const IOobject &io, const fileName &decompDictFile="")
Construct from components.
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
const decompositionModel & model() const
Return decomposition model used.
void setSize(label n)
Alias for resize()
Definition: List.H:535
Do not request registration (bool: false)
ZoneMesh< cellZone, polyMesh > cellZoneMesh
A ZoneMesh with cellZone content on a polyMesh.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...