domainDecomposition.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "domainDecomposition.H"
27 #include "decompositionMethod.H"
28 #include "IOobjectList.H"
29 #include "cellSet.H"
30 #include "faceSet.H"
31 #include "pointSet.H"
32 #include "hexRef8Data.H"
33 #include "cyclicFvPatch.H"
34 #include "processorCyclicFvPatch.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
44 }
45 
46 
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
48 
49 void Foam::domainDecomposition::decomposePoints()
50 {
51  for (label proci = 0; proci < nProcs(); proci++)
52  {
53  fvMesh& procMesh = procMeshes_[proci];
54 
55  const label pointsCompare =
56  compareInstances
57  (
58  completeMesh().pointsInstance(),
59  procMeshes_[proci].pointsInstance()
60  );
61 
62  if (pointsCompare == -1)
63  {
64  procMesh.setPoints
65  (
67  (
68  completeMesh().points(),
69  procPointAddressing_[proci]
70  )
71  );
72  }
73  }
74 }
75 
76 
77 void Foam::domainDecomposition::reconstructPoints()
78 {
79  const label pointsCompare =
80  compareInstances
81  (
82  completeMesh().pointsInstance(),
83  procMeshes_[0].pointsInstance()
84  );
85 
86  if (pointsCompare == 1)
87  {
88  pointField completePoints(completeMesh().nPoints());
89 
90  for (label proci = 0; proci < nProcs(); proci++)
91  {
92  const fvMesh& procMesh = procMeshes_[proci];
93 
94  completePoints.rmap(procMesh.points(), procPointAddressing_[proci]);
95  }
96 
97  completeMesh_->setPoints(completePoints);
98  }
99 }
100 
101 
102 bool Foam::domainDecomposition::completeConformal() const
103 {
104  return completeMesh().conformal();
105 }
106 
107 
108 bool Foam::domainDecomposition::procsConformal() const
109 {
110  forAll(procMeshes_, proci)
111  {
112  if (!procMeshes_[proci].conformal())
113  {
114  return false;
115  }
116  }
117 
118  return true;
119 }
120 
121 
122 void Foam::domainDecomposition::unconform()
123 {
124  // ...
125  auto checkNonConformalCoupledPatchOrdering = []
126  (
127  const labelPair& procs,
128  const fvPatch& fvp,
129  const fvPatch& nbrFvp,
130  const labelList& polyFacesPf,
131  const labelList& nbrPolyFacesPf
132  )
133  {
134  if (fvp.size() != nbrFvp.size())
135  {
137  << "Coupled patches " << fvp.name() << " and "
138  << nbrFvp.name() << " are not the same size"
139  << exit(FatalError);
140  }
141 
142  if (fvp.size())
143  {
144  for (label i = 1; i < fvp.size(); ++ i)
145  {
146  if
147  (
148  polyFacesPf[i - 1] > polyFacesPf[i]
149  ? true
150  : polyFacesPf[i - 1] == polyFacesPf[i]
151  ? nbrPolyFacesPf[i - 1] >= nbrPolyFacesPf[i]
152  : false
153  )
154  {
156  << "Coupled patches " << fvp.name()
157  << " and " << nbrFvp.name()
158  << " are not in order";
159 
160  if (procs[0] == procs[1])
161  {
163  << " on process #" << procs[0];
164  }
165 
167  << exit(FatalError);
168  }
169  }
170  }
171 
173  << "Coupled patches " << fvp.name()
174  << " and " << nbrFvp.name()
175  << " are in order" << endl;
176  };
177 
178  // ...
179  auto checkNonConformalErrorPatchOrdering = []
180  (
181  const label& proci,
182  const fvPatch& fvp,
183  const labelList& polyFacesPf
184  )
185  {
186  if (fvp.size())
187  {
188  for (label i = 1; i < fvp.size(); ++ i)
189  {
190  if (polyFacesPf[i - 1] > polyFacesPf[i])
191  {
193  << "Error patch " << fvp.name()
194  << " is not in order";
195 
196  if (proci > 0)
197  {
199  << " on process #" << proci;
200  }
201 
203  << exit(FatalError);
204  }
205  }
206  }
207 
209  << "Error patch " << fvp.name()
210  << " is in order" << endl;
211  };
212 
213  if (completeConformal() && procsConformal())
214  {
215  // Nothing to do
216  }
217  else if (!completeConformal() && procsConformal())
218  {
219  // Construct the reverse of proc-face-face addressing
220  labelList faceProcFace(completeMesh().nFaces(), -labelMax);
221  forAll(procMeshes_, proci)
222  {
223  forAll(procFaceAddressing()[proci], procFacei)
224  {
225  const label facei =
226  mag(procFaceAddressing()[proci][procFacei]) - 1;
227 
228  faceProcFace[facei] =
229  faceProcFace[facei] == -labelMax ? procFacei : -1;
230  }
231  }
232 
233  // Map the polyFacesBf from the complete to the processor meshes and
234  // unconform the processor meshes. Set dummy data for the face
235  // geometry. This should not be used during decomposition.
236  forAll(procMeshes_, proci)
237  {
238  fvMesh& procMesh = procMeshes_[proci];
239 
240  const surfaceLabelField::Boundary& faceAddressingBf =
241  procFaceAddressingBf()[proci];
242 
243  surfaceLabelField::Boundary polyFacesBf
244  (
246  procMesh.polyFacesBf()
247  );
248  surfaceVectorField Sf(procMesh.Sf().cloneUnSliced());
249  surfaceVectorField Cf(procMesh.Cf().cloneUnSliced());
250 
251  forAll(procMesh.boundary(), procNccPatchi)
252  {
253  const fvPatch& fvp = procMesh.boundary()[procNccPatchi];
254 
255  if (isA<nonConformalFvPatch>(fvp))
256  {
257  const label completeNccPatchi =
258  isA<processorCyclicFvPatch>(fvp)
259  ? refCast<const processorCyclicFvPatch>(fvp)
260  .referPatchID()
261  : procNccPatchi;
262 
263  polyFacesBf[procNccPatchi] =
264  labelField
265  (
266  faceProcFace,
267  labelField
268  (
269  completeMesh().polyFacesBf()[completeNccPatchi],
270  mag(faceAddressingBf[procNccPatchi]) - 1
271  )
272  );
273 
274  const label size = polyFacesBf[procNccPatchi].size();
275 
276  Sf.boundaryFieldRef()[procNccPatchi].resize(size, Zero);
277  Cf.boundaryFieldRef()[procNccPatchi].resize(size, Zero);
278  }
279  }
280 
281  procMesh.unconform
282  (
283  polyFacesBf,
284  Sf,
285  Cf,
286  NullObjectRef<surfaceScalarField>(),
287  false
288  );
289  }
290 
291  // Check ordering
292  if (debug)
293  {
294  forAll(procMeshes_, proci)
295  {
296  forAll(procMeshes_[proci].boundary(), patchi)
297  {
298  const fvPatch& fvp =
299  procMeshes_[proci].boundary()[patchi];
300 
301  // Coupled patches
302  if
303  (
304  isA<nonConformalCoupledFvPatch>(fvp)
305  && refCast<const nonConformalCoupledFvPatch>(fvp).owner()
306  )
307  {
308  const label nccPatchi = patchi;
309 
310  label nbrProci = -1, nbrNccPatchi = -1;
311  if (isA<cyclicFvPatch>(fvp))
312  {
313  nbrProci = proci;
314  nbrNccPatchi =
315  refCast<const cyclicFvPatch>(fvp).nbrPatchID();
316  }
317  else if (isA<processorCyclicFvPatch>(fvp))
318  {
319  typedef processorCyclicFvPatch PcFvp;
320 
321  const PcFvp& pcFvp = refCast<const PcFvp>(fvp);
322 
323  nbrProci = pcFvp.neighbProcNo();
324 
325  const fvBoundaryMesh& nbrFvPatches =
326  procMeshes_[nbrProci].boundary();
327 
328  forAll(nbrFvPatches, nbrNccPatchj)
329  {
330  const fvPatch& nbrFvp =
331  nbrFvPatches[nbrNccPatchj];
332 
333  if (isA<PcFvp>(nbrFvp))
334  {
335  const PcFvp& nbrPcFvp =
336  refCast<const PcFvp>(nbrFvp);
337 
338  if
339  (
340  nbrPcFvp.neighbProcNo()
341  == proci
342  && nbrPcFvp.referPatchID()
343  == pcFvp.referPatch().nbrPatchID()
344  )
345  {
346  nbrNccPatchi = nbrNccPatchj;
347  break;
348  }
349  }
350  }
351 
352  if (nbrNccPatchi == -1)
353  {
355  << "Opposite processor patch not found for "
356  << "patch " << fvp.name() << " on proc #"
357  << proci << exit(FatalError);
358  }
359  }
360  else
361  {
363  << "Non-conformal-coupled type not recognised "
364  << "for patch " << fvp.name() << " on proc #"
365  << proci << exit(FatalError);
366  }
367 
368  checkNonConformalCoupledPatchOrdering
369  (
370  {proci, nbrProci},
371  procMeshes_[proci].boundary()[nccPatchi],
372  procMeshes_[nbrProci].boundary()[nbrNccPatchi],
373  procMeshes_[proci].polyFacesBf()[nccPatchi],
374  procMeshes_[nbrProci].polyFacesBf()[nbrNccPatchi]
375  );
376  }
377 
378  // Error patches
379  if (isA<nonConformalErrorFvPatch>(fvp))
380  {
381  const label ncePatchi = patchi;
382 
383  checkNonConformalErrorPatchOrdering
384  (
385  proci,
386  procMeshes_[proci].boundary()[ncePatchi],
387  procMeshes_[proci].polyFacesBf()[ncePatchi]
388  );
389  }
390  }
391  }
392  }
393  }
394  else if (completeConformal() && !procsConformal())
395  {
396  // Map the polyFacesBf from the processor to the complete meshes and
397  // unconform the complete mesh. Set dummy data for the face
398  // geometry. This should not be used during decomposition.
399  surfaceLabelField::Boundary polyFacesBf
400  (
402  completeMesh().polyFacesBf()
403  );
404  surfaceVectorField Sf(completeMesh().Sf().cloneUnSliced());
405  surfaceVectorField Cf(completeMesh().Cf().cloneUnSliced());
406 
407  forAll(procMeshes_, proci)
408  {
409  const fvMesh& procMesh = procMeshes_[proci];
410 
411  const surfaceLabelField::Boundary& faceAddressingBf =
412  procFaceAddressingBf()[proci];
413 
414  forAll(procMesh.boundary(), procNccPatchi)
415  {
416  const fvPatch& fvp = procMesh.boundary()[procNccPatchi];
417 
418  if (isA<nonConformalFvPatch>(fvp))
419  {
420  const label completeNccPatchi =
421  isA<processorCyclicFvPatch>(fvp)
422  ? refCast<const processorCyclicFvPatch>(fvp)
423  .referPatchID()
424  : procNccPatchi;
425 
426  const label size =
427  max
428  (
429  max(mag(faceAddressingBf[procNccPatchi])),
430  polyFacesBf[completeNccPatchi].size()
431  );
432 
433  polyFacesBf[completeNccPatchi].resize(size, -1);
434  Sf.boundaryFieldRef()[completeNccPatchi].resize(size, Zero);
435  Cf.boundaryFieldRef()[completeNccPatchi].resize(size, Zero);
436 
437  polyFacesBf[completeNccPatchi].labelField::rmap
438  (
439  mag
440  (
441  labelField
442  (
443  procFaceAddressing_[proci],
444  procMesh.polyFacesBf()[procNccPatchi]
445  )
446  ) - 1,
447  mag(faceAddressingBf[procNccPatchi]) - 1
448  );
449  }
450  }
451  }
452 
453  completeMesh_->unconform
454  (
455  polyFacesBf,
456  Sf,
457  Cf,
458  NullObjectRef<surfaceScalarField>(),
459  false
460  );
461 
462  // Check ordering
463  if (debug)
464  {
465  forAll(completeMesh().boundary(), patchi)
466  {
467  const fvPatch& fvp = completeMesh().boundary()[patchi];
468 
469  // Coupled patches
470  if
471  (
472  isA<nonConformalCyclicFvPatch>(fvp)
473  && refCast<const nonConformalCoupledFvPatch>(fvp).owner()
474  )
475  {
476  const label nccPatchi = patchi;
477 
478  const label nbrNccPatchi =
479  refCast<const nonConformalCyclicFvPatch>(fvp)
480  .nbrPatchID();
481 
482  checkNonConformalCoupledPatchOrdering
483  (
484  {-labelMax, labelMax},
485  completeMesh().boundary()[nccPatchi],
486  completeMesh().boundary()[nbrNccPatchi],
487  completeMesh().polyFacesBf()[nccPatchi],
488  completeMesh().polyFacesBf()[nbrNccPatchi]
489  );
490  }
491 
492  // Error patches
493  if (isA<nonConformalErrorFvPatch>(fvp))
494  {
495  const label ncePatchi = patchi;
496 
497  checkNonConformalErrorPatchOrdering
498  (
499  -labelMax,
500  completeMesh().boundary()[ncePatchi],
501  completeMesh().polyFacesBf()[ncePatchi]
502  );
503  }
504  }
505  }
506  }
507  else // if (!completeConformal() && !procsConformal())
508  {
509  // Assume everything is consistent and do nothing
510  }
511 }
512 
513 
514 Foam::label Foam::domainDecomposition::compareInstances
515 (
516  const fileName& a,
517  const fileName& b
518 ) const
519 {
520  const word& constant = runTimes_.completeTime().constant();
521 
522  if (a == constant && b == constant) return 0;
523 
524  if (a == constant) return +1;
525 
526  if (b == constant) return -1;
527 
528  const scalar aValue = instant(a).value();
529  const scalar bValue = instant(b).value();
530 
531  if (aValue < bValue) return +1;
532 
533  if (aValue > bValue) return -1;
534 
535  return 0;
536 }
537 
538 
539 void Foam::domainDecomposition::validateComplete() const
540 {
541  if (!completeMesh_.valid())
542  {
544  << "Complete data requested but complete mesh has not been "
545  << "generated or read" << exit(FatalError);
546  }
547 }
548 
549 
550 void Foam::domainDecomposition::validateProcs() const
551 {
552  if (!procMeshes_.set(0))
553  {
555  << "Decomposed data requested but decomposed mesh has not been "
556  << "generated or read" << exit(FatalError);
557  }
558 }
559 
560 
561 void Foam::domainDecomposition::readComplete(const bool stitch)
562 {
563  completeMesh_.reset
564  (
565  new fvMesh
566  (
567  IOobject
568  (
569  regionName_,
570  runTimes_.completeTime().name(),
571  runTimes_.completeTime(),
574  false
575  ),
576  false,
577  stitch
580  )
581  );
582 }
583 
584 
585 void Foam::domainDecomposition::readProcs()
586 {
587  for (label proci = 0; proci < nProcs(); proci++)
588  {
589  procMeshes_.set
590  (
591  proci,
592  new fvMesh
593  (
594  IOobject
595  (
596  regionName_,
597  runTimes_.procTimes()[proci].name(),
598  runTimes_.procTimes()[proci],
601  false
602  ),
603  false
604  )
605  );
606  }
607 }
608 
609 
610 void Foam::domainDecomposition::readCompleteAddressing()
611 {
612  cellProc_ =
614  (
615  IOobject
616  (
617  "cellProc",
618  completeMesh().facesInstance(),
619  completeMesh().meshSubDir,
620  completeMesh(),
623  false
624  )
625  );
626 }
627 
628 
629 void Foam::domainDecomposition::readProcsAddressing()
630 {
631  for (label proci = 0; proci < nProcs(); proci++)
632  {
633  const fvMesh& procMesh = procMeshes_[proci];
634 
635  procPointAddressing_[proci] =
637  (
638  IOobject
639  (
640  "pointProcAddressing",
641  procMesh.facesInstance(),
642  procMesh.meshSubDir,
643  procMesh,
646  false
647  )
648  );
649 
650  procFaceAddressing_[proci] =
652  (
653  IOobject
654  (
655  "faceProcAddressing",
656  procMesh.facesInstance(),
657  procMesh.meshSubDir,
658  procMesh,
661  false
662  )
663  );
664 
665  procCellAddressing_[proci] =
667  (
668  IOobject
669  (
670  "cellProcAddressing",
671  procMesh.facesInstance(),
672  procMesh.meshSubDir,
673  procMesh,
676  false
677  )
678  );
679  }
680 }
681 
682 
683 void Foam::domainDecomposition::readAddressing()
684 {
685  readCompleteAddressing();
686  readProcsAddressing();
687 }
688 
689 
690 Foam::fvMesh::readUpdateState Foam::domainDecomposition::readUpdate()
691 {
692  validateComplete();
693  validateProcs();
694 
695  // Do read-update on all meshes
697  completeMesh_->readUpdate(fvMesh::stitchType::nonGeometric);
698  forAll(runTimes_.procTimes(), proci)
699  {
700  fvMesh::readUpdateState procStat =
701  procMeshes_[proci].readUpdate(fvMesh::stitchType::nonGeometric);
702  if (procStat > stat)
703  {
704  stat = procStat;
705  }
706  }
707 
708  return stat;
709 }
710 
711 
712 void Foam::domainDecomposition::writeCompleteAddressing() const
713 {
714  labelIOList cellProc
715  (
716  IOobject
717  (
718  "cellProc",
719  completeMesh().facesInstance(),
720  completeMesh().meshSubDir,
721  completeMesh(),
724  ),
725  cellProc_
726  );
727 
728  cellProc.write();
729 }
730 
731 
732 void Foam::domainDecomposition::writeProcsAddressing() const
733 {
734  for (label proci = 0; proci < nProcs(); proci++)
735  {
736  const fvMesh& procMesh = procMeshes_[proci];
737 
738  labelIOList pointProcAddressing
739  (
740  IOobject
741  (
742  "pointProcAddressing",
743  procMesh.facesInstance(),
744  procMesh.meshSubDir,
745  procMesh,
748  ),
749  procPointAddressing_[proci]
750  );
751  pointProcAddressing.write();
752 
753  labelIOList faceProcAddressing
754  (
755  IOobject
756  (
757  "faceProcAddressing",
758  procMesh.facesInstance(),
759  procMesh.meshSubDir,
760  procMesh,
763  ),
764  procFaceAddressing_[proci]
765  );
766  faceProcAddressing.write();
767 
768  labelIOList cellProcAddressing
769  (
770  IOobject
771  (
772  "cellProcAddressing",
773  procMesh.facesInstance(),
774  procMesh.meshSubDir,
775  procMesh,
778  ),
779  procCellAddressing_[proci]
780  );
781  cellProcAddressing.write();
782  }
783 }
784 
785 
786 void Foam::domainDecomposition::writeAddressing() const
787 {
788  writeCompleteAddressing();
789  writeProcsAddressing();
790 }
791 
792 
793 void Foam::domainDecomposition::writeProcPoints(const fileName& inst)
794 {
795  IOobject completePointsIo
796  (
797  "points",
798  inst,
800  completeMesh(),
803  false
804  );
805 
806  if (!completePointsIo.headerOk()) return;
807 
808  const pointIOField completePoints(completePointsIo);
809 
810  for (label proci = 0; proci < nProcs(); proci++)
811  {
812  pointIOField procPoints
813  (
814  IOobject
815  (
816  "points",
817  inst,
819  procMeshes()[proci],
822  false
823  ),
824  pointField
825  (
826  completePoints,
827  procPointAddressing_[proci]
828  )
829  );
830 
831  procPoints.write();
832  }
833 }
834 
835 
836 void Foam::domainDecomposition::writeCompletePoints(const fileName& inst)
837 {
838  pointIOField completePoints
839  (
840  IOobject
841  (
842  "points",
843  inst,
845  completeMesh(),
848  false
849  ),
850  pointField(completeMesh().nPoints())
851  );
852 
853  for (label proci = 0; proci < nProcs(); proci++)
854  {
855  IOobject procPointsIo
856  (
857  "points",
858  inst,
860  procMeshes()[proci],
863  false
864  );
865 
866  if (!procPointsIo.headerOk()) return;
867 
868  completePoints.rmap
869  (
870  pointIOField(procPointsIo),
871  procPointAddressing_[proci]
872  );
873  }
874 
875  completePoints.write();
876 }
877 
878 
879 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
880 
882 (
883  const processorRunTimes& runTimes,
884  const word& regionName
885 )
886 :
887  runTimes_(runTimes),
888  regionName_(regionName),
889  completeMesh_(nullptr),
890  procMeshes_(nProcs()),
891  cellProc_(),
892  procPointAddressing_(nProcs()),
893  procFaceAddressing_(nProcs()),
894  procCellAddressing_(nProcs()),
895  procFaceAddressingBf_()
896 {}
897 
898 
899 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
900 
902 {}
903 
904 
905 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
906 
908 {
909  readComplete();
910 
912  (
913  "cellProc",
914  completeMesh().facesInstance(),
916  completeMesh()
917  );
918  IOobject procFaceIo
919  (
920  "faces",
921  completeMesh().facesInstance(),
922  completeMesh().meshDir(),
923  runTimes_.procTimes()[0]
924  );
925  typeIOobject<labelIOList> procAddrIo
926  (
927  "cellProcAddressing",
928  completeMesh().facesInstance(),
929  completeMesh().meshDir(),
930  runTimes_.procTimes()[0]
931  );
932 
933  const bool load = addrIo.headerOk() && procFaceIo.headerOk();
934 
935  if (load)
936  {
937  readProcs();
938 
939  if (procAddrIo.headerOk())
940  {
941  readAddressing();
942  }
943  else
944  {
945  readCompleteAddressing();
946 
948  << nl << " Processor meshes exist but have no addressing."
949  << nl << nl << " This could be because the processor meshes "
950  << "have changed. Decomposing the" << nl << " mesh would "
951  << "overwrite that change. If you are sure that this is "
952  << "appropriate," << nl << " then delete the "
953  << fileName("processor*")/procFaceIo.relativePath().c_str()
954  << " directories and re-run this" << nl << " command."
955  << exit(FatalError);
956  }
957 
958  decomposePoints();
959  }
960  else
961  {
962  if
963  (
964  completeMesh().facesInstance()
965  != runTimes_.completeTime().name()
966  && completeMesh().facesInstance()
967  != runTimes_.completeTime().constant()
968  )
969  {
971  << "Cannot begin mesh decomposition at time "
972  << fileName(runTimes_.completeTime().name()) << nl
973  << "The mesh at this instant is that of an earlier"
974  << " time " << completeMesh().facesInstance() << nl
975  << "Decomposition must start from this earlier time"
976  << exit(FatalError);
977  }
978 
979  decompose();
980  }
981 
982  if (!completeConformal())
983  {
984  procFaceAddressingBf_.clear();
985  forAll(procMeshes_, proci) procMeshes_[proci].conform();
986  unconform();
987  }
988 
989  writeProcs(doSets);
990 
991  if (!load)
992  {
993  writeProcPoints(completeMesh().facesInstance());
994  }
995 
996  return !load;
997 }
998 
999 
1001 {
1002  readProcs();
1003 
1004  IOobject faceIo
1005  (
1006  "faces",
1007  procMeshes()[0].facesInstance(),
1008  procMeshes()[0].meshDir(),
1009  runTimes_.completeTime()
1010  );
1012  (
1013  "cellProc",
1014  procMeshes()[0].facesInstance(),
1015  procMeshes()[0].meshDir(),
1016  runTimes_.completeTime()
1017  );
1018  typeIOobject<labelIOList> procAddrIo
1019  (
1020  "cellProcAddressing",
1021  procMeshes()[0].facesInstance(),
1023  procMeshes()[0]
1024  );
1025 
1026  const bool load = faceIo.headerOk() && procAddrIo.headerOk();
1027 
1028  if (load)
1029  {
1030  typeIOobject<pointIOField> completePointsIo
1031  (
1032  "points",
1033  procMeshes()[0].pointsInstance(),
1034  procMeshes()[0].meshDir(),
1035  runTimes_.completeTime()
1036  );
1037 
1038  readComplete(completePointsIo.headerOk());
1039 
1040  if (addrIo.headerOk())
1041  {
1042  readAddressing();
1043  }
1044  else
1045  {
1046  readProcsAddressing();
1047 
1049  << nl << " A complete mesh exists but has no "
1050  << addrIo.name() << " addressing." << nl << nl << " This "
1051  << "could be because the complete mesh has changed. "
1052  << "Reconstructing the" << nl << " mesh would overwrite "
1053  << "that change. If you are sure that this is appropriate,"
1054  << nl << " then delete the " << faceIo.relativePath()
1055  << " directory and re-run this command." << nl << nl
1056  << " Or, it could be because the complete and processor "
1057  << "meshes were decomposed" << nl << " by a version of "
1058  << "OpenFOAM that pre-dates the automatic generation of "
1059  << nl << " " << addrIo.name() << " addressing. This will be "
1060  << "assumed and the " << addrIo.name() << " addressing will"
1061  << nl << " be re-built" << nl << endl;
1062 
1063  cellProc_ = labelList(completeMesh().nCells(), -1);
1064 
1065  for (label proci = 0; proci < nProcs(); proci++)
1066  {
1068  (
1069  cellProc_,
1070  procCellAddressing_[proci]
1071  ) = proci;
1072  }
1073 
1074  writeCompleteAddressing();
1075  }
1076 
1077  reconstructPoints();
1078  }
1079  else
1080  {
1081  if
1082  (
1083  procMeshes()[0].facesInstance()
1084  != runTimes_.procTimes()[0].name()
1085  && procMeshes()[0].facesInstance()
1086  != runTimes_.procTimes()[0].constant()
1087  )
1088  {
1090  << "Cannot begin mesh reconstruction at time "
1091  << fileName(runTimes_.procTimes()[0].name()) << nl
1092  << "The mesh at this instant is that of an earlier"
1093  << " time " << procMeshes()[0].facesInstance() << nl
1094  << "Reconstruction must start from this earlier time"
1095  << exit(FatalError);
1096  }
1097 
1098  reconstruct();
1099  }
1100 
1101  if (!procsConformal())
1102  {
1103  procFaceAddressingBf_.clear();
1104  completeMesh_->conform();
1105  unconform();
1106  }
1107 
1108  writeComplete(doSets);
1109 
1110  if (!load)
1111  {
1112  writeCompletePoints(procMeshes()[0].facesInstance());
1113  }
1114 
1115  return !load;
1116 }
1117 
1118 
1120 {
1121  const fvMesh::readUpdateState stat = readUpdate();
1122 
1123  // Topology changes
1124  {
1125  const label facesCompare =
1126  compareInstances
1127  (
1128  completeMesh().facesInstance(),
1129  procMeshes_[0].facesInstance()
1130  );
1131 
1132  // If the complete mesh has newer topology then we need to decompose
1133  if (facesCompare == -1)
1134  {
1135  decompose();
1136  }
1137 
1138  // If there has been matching topology change then reload the addressing
1139  if (facesCompare == 0 && stat >= fvMesh::TOPO_CHANGE)
1140  {
1141  procFaceAddressingBf_.clear();
1142  readAddressing();
1143  }
1144 
1145  // The processor meshes should not have newer topology when decomposing
1146  if (facesCompare == +1)
1147  {
1149  << "Cannot decompose at time "
1150  << procMeshes_[0].facesInstance()
1151  << " because the processor mesh topology has evolved further"
1152  << " than the complete mesh topology." << exit(FatalError);
1153  }
1154  }
1155 
1156  // Geometry changes
1157  {
1158  const label pointsCompare =
1159  compareInstances
1160  (
1161  completeMesh().pointsInstance(),
1162  procMeshes_[0].pointsInstance()
1163  );
1164 
1165  // If the complete mesh has newer geometry then we need to decompose
1166  // the points
1167  if (pointsCompare == -1)
1168  {
1169  decomposePoints();
1170  }
1171 
1172  // The processor meshes should not have newer geometry when decomposing
1173  if (pointsCompare == +1)
1174  {
1176  << "Cannot decompose at time "
1177  << procMeshes_[0].pointsInstance()
1178  << " because the processor mesh geometry has evolved further"
1179  << " than the complete mesh geometry." << exit(FatalError);
1180  }
1181  }
1182 
1183  // Non-conformal changes
1184  {
1185  // If the mesh has changed in any way, and the complete mesh is
1186  // non-conformal, then we need to re-unconform the processor meshes
1187  if (stat != fvMesh::UNCHANGED && !completeConformal())
1188  {
1189  procFaceAddressingBf_.clear();
1190  forAll(procMeshes_, proci) procMeshes_[proci].conform();
1191  unconform();
1192  }
1193  }
1194 
1195  return stat;
1196 }
1197 
1198 
1200 {
1201  const fvMesh::readUpdateState stat = readUpdate();
1202 
1203  // Topology changes
1204  {
1205  const label facesCompare =
1206  compareInstances
1207  (
1208  completeMesh().facesInstance(),
1209  procMeshes_[0].facesInstance()
1210  );
1211 
1212  // The complete mesh should not have newer topology when reconstructing
1213  if (facesCompare == -1)
1214  {
1216  << "Cannot reconstruct at time "
1217  << completeMesh().facesInstance()
1218  << " because the complete mesh topology has evolved further"
1219  << " than the processor mesh topology." << exit(FatalError);
1220  }
1221 
1222  // If there has been matching topology change then reload the addressing
1223  if (facesCompare == 0 && stat >= fvMesh::TOPO_CHANGE)
1224  {
1225  procFaceAddressingBf_.clear();
1226  readAddressing();
1227  }
1228 
1229  // If the processor meshes have newer topology then we need to
1230  // reconstruct
1231  if (facesCompare == +1)
1232  {
1233  reconstruct();
1234  }
1235  }
1236 
1237  // Geometry changes
1238  {
1239  const label pointsCompare =
1240  compareInstances
1241  (
1242  completeMesh().pointsInstance(),
1243  procMeshes_[0].pointsInstance()
1244  );
1245 
1246  // The complete mesh should not have newer geometry when reconstructing
1247  if (pointsCompare == -1)
1248  {
1250  << "Cannot reconstruct at time "
1251  << completeMesh().pointsInstance()
1252  << " because the complete mesh geometry has evolved further"
1253  << " than the processor mesh geometry." << exit(FatalError);
1254  }
1255 
1256  // If the processor meshes have newer geometry then we need to
1257  // reconstruct the points
1258  if (pointsCompare == +1)
1259  {
1260  reconstructPoints();
1261  }
1262  }
1263 
1264  // Non-conformal changes
1265  {
1266  // If the mesh has changed in any way, and the processor meshes are
1267  // non-conformal, then we need to re-unconform the complete mesh
1268  if (stat != fvMesh::UNCHANGED && !procsConformal())
1269  {
1270  procFaceAddressingBf_.clear();
1271  completeMesh_->conform();
1272  unconform();
1273  }
1274  }
1275 
1276  return stat;
1277 }
1278 
1279 
1282 {
1283  validateComplete();
1284  validateProcs();
1285 
1286  if (procFaceAddressingBf_.empty())
1287  {
1288  // Map from reference patch and processors to the interface patch
1289  typedef HashTable<label, labelPair, Hash<labelPair>> labelPairTable;
1290  List<labelPairTable> refPatchProcPatchTable
1291  (
1292  completeMesh().boundary().size()
1293  );
1294  forAll(procMeshes_, proci)
1295  {
1296  const fvMesh& procMesh = procMeshes_[proci];
1297 
1298  forAll(procMesh.boundary(), procPatchi)
1299  {
1300  const fvPatch& fvp = procMesh.boundary()[procPatchi];
1301 
1302  if (isA<cyclicFvPatch>(fvp))
1303  {
1304  refPatchProcPatchTable[procPatchi].insert
1305  (
1306  labelPair(proci, proci),
1307  procPatchi
1308  );
1309  }
1310  else if (isA<processorCyclicFvPatch>(fvp))
1311  {
1312  const processorCyclicFvPatch& pcFvp =
1313  refCast<const processorCyclicFvPatch>(fvp);
1314 
1315  refPatchProcPatchTable[pcFvp.referPatchID()].insert
1316  (
1317  labelPair(proci, pcFvp.neighbProcNo()),
1318  procPatchi
1319  );
1320  }
1321  }
1322  }
1323 
1324  // Build non-conformal finite volume face addressing for each processor
1326  nonConformalProcFaceAddressingBf(nProcs());
1327  forAll(nonConformalProcFaceAddressingBf, proci)
1328  {
1329  nonConformalProcFaceAddressingBf[proci].resize
1330  (
1331  procMeshes_[proci].boundary().size()
1332  );
1333  }
1334  if (completeMesh().conformal() && procMeshes_[0].conformal())
1335  {
1336  // Nothing to do
1337  }
1338  else if (!completeMesh().conformal())
1339  {
1340  // Decompose non-conformal addressing
1341  const surfaceLabelField::Boundary& polyFacesBf =
1342  completeMesh().polyFacesBf();
1343 
1344  // Cyclic patches
1345  forAll(completeMesh().boundary(), nccPatchi)
1346  {
1347  const fvPatch& fvp = completeMesh().boundary()[nccPatchi];
1348 
1349  if (!isA<nonConformalCyclicFvPatch>(fvp)) continue;
1350 
1351  const nonConformalCyclicFvPatch& nccFvp =
1352  refCast<const nonConformalCyclicFvPatch>(fvp);
1353 
1354  if (!nccFvp.owner()) continue;
1355 
1356  const label nccNbrPatchi = nccFvp.nbrPatchID();
1357 
1358  forAll(polyFacesBf[nccPatchi], nccPatchFacei)
1359  {
1360  const label facei = polyFacesBf[nccPatchi][nccPatchFacei];
1361  const label celli = completeMesh().faceOwner()[facei];
1362  const label proci = cellProc_[celli];
1363 
1364  const label nbrFacei =
1365  polyFacesBf[nccNbrPatchi][nccPatchFacei];
1366  const label nbrCelli =
1367  completeMesh().faceOwner()[nbrFacei];
1368  const label nbrProci = cellProc_[nbrCelli];
1369 
1370  const label procNccPatchi =
1371  refPatchProcPatchTable
1372  [nccPatchi][labelPair(proci, nbrProci)];
1373  const label nbrProcNccPatchi =
1374  refPatchProcPatchTable
1375  [nccNbrPatchi][labelPair(nbrProci, proci)];
1376 
1377  nonConformalProcFaceAddressingBf[proci][procNccPatchi]
1378  .append(nccPatchFacei + 1);
1379  nonConformalProcFaceAddressingBf[nbrProci][nbrProcNccPatchi]
1380  .append(nccPatchFacei + 1);
1381  }
1382  }
1383 
1384  // Error patches
1385  forAll(completeMesh().boundary(), ncePatchi)
1386  {
1387  const fvPatch& fvp = completeMesh().boundary()[ncePatchi];
1388 
1389  if (!isA<nonConformalErrorFvPatch>(fvp)) continue;
1390 
1391  forAll(polyFacesBf[ncePatchi], ncePatchFacei)
1392  {
1393  const label facei = polyFacesBf[ncePatchi][ncePatchFacei];
1394  const label celli = completeMesh().faceOwner()[facei];
1395  const label proci = cellProc_[celli];
1396 
1397  nonConformalProcFaceAddressingBf[proci][ncePatchi]
1398  .append(ncePatchFacei + 1);
1399  }
1400  }
1401  }
1402  else // if (!procMeshes_[0].conformal())
1403  {
1404  // Reconstruct non-conformal addressing
1405 
1406  // Cyclic patches
1407  forAll(completeMesh().boundary(), nccPatchi)
1408  {
1409  const fvPatch& fvp = completeMesh().boundary()[nccPatchi];
1410 
1411  if (!isA<nonConformalCyclicFvPatch>(fvp)) continue;
1412 
1413  const nonConformalCyclicFvPatch& nccFvp =
1414  refCast<const nonConformalCyclicFvPatch>(fvp);
1415 
1416  if (!nccFvp.owner()) continue;
1417 
1418  const label nccNbrPatchi = nccFvp.nbrPatchID();
1419 
1420  label count = 0;
1421  labelPairTable procCounts;
1423  (
1424  labelPairTable,
1425  refPatchProcPatchTable[nccPatchi],
1426  iter
1427  )
1428  {
1429  procCounts.insert(iter.key(), 0);
1430  }
1431 
1432  while (true)
1433  {
1434  labelPair procNbrProc(labelMax, labelMax);
1435  labelPair faceNbrFace(labelMax, labelMax);
1436 
1437  forAllConstIter(labelPairTable, procCounts, iter)
1438  {
1439  const label proci = iter.key().first();
1440  const label nbrProci = iter.key().second();
1441 
1442  const labelPair procNbrProcStar(proci, nbrProci);
1443  const labelPair nbrProcProcStar(nbrProci, proci);
1444 
1445  const label procNccPatchi =
1446  refPatchProcPatchTable
1447  [nccPatchi][procNbrProcStar];
1448  const label nbrProcNccPatchi =
1449  refPatchProcPatchTable
1450  [nccNbrPatchi][nbrProcProcStar];
1451 
1452  const label size =
1453  procMeshes_[proci]
1454  .polyFacesBf()[procNccPatchi]
1455  .size();
1456 
1457  if (iter() >= size) continue;
1458 
1459  const label procFacei =
1460  procMeshes_[proci].polyFacesBf()
1461  [procNccPatchi][iter()];
1462  const label nbrProcFacei =
1463  procMeshes_[nbrProci].polyFacesBf()
1464  [nbrProcNccPatchi][iter()];
1465 
1466  const labelPair faceNbrFaceStar
1467  (
1468  procFaceAddressing_[proci][procFacei] - 1,
1469  procFaceAddressing_[nbrProci][nbrProcFacei] - 1
1470  );
1471 
1472  if (faceNbrFace > faceNbrFaceStar)
1473  {
1474  procNbrProc = procNbrProcStar;
1475  faceNbrFace = faceNbrFaceStar;
1476  }
1477  }
1478 
1479  if (faceNbrFace == labelPair(labelMax, labelMax))
1480  {
1481  break;
1482  }
1483  else
1484  {
1485  const label proci = procNbrProc.first();
1486  const label nbrProci = procNbrProc.second();
1487 
1488  const labelPair nbrProcProc(nbrProci, proci);
1489 
1490  const label procNccPatchi =
1491  refPatchProcPatchTable[nccPatchi][procNbrProc];
1492  const label nbrProcNccPatchi =
1493  refPatchProcPatchTable[nccNbrPatchi][nbrProcProc];
1494 
1495  nonConformalProcFaceAddressingBf
1496  [proci][procNccPatchi].append(count + 1);
1497  nonConformalProcFaceAddressingBf
1498  [nbrProci][nbrProcNccPatchi].append(count + 1);
1499 
1500  count ++;
1501  procCounts[procNbrProc] ++;
1502  }
1503  }
1504  }
1505 
1506  // Error patches
1507  forAll(completeMesh().boundary(), ncePatchi)
1508  {
1509  const fvPatch& fvp = completeMesh().boundary()[ncePatchi];
1510 
1511  if (!isA<nonConformalErrorFvPatch>(fvp)) continue;
1512 
1513  label count = 0;
1514  labelList procCounts(nProcs(), 0);
1515 
1516  while (true)
1517  {
1518  label facei = labelMax, proci = labelMax;
1519 
1520  forAll(procCounts, procStari)
1521  {
1522  const label size =
1523  procMeshes_[procStari]
1524  .polyFacesBf()[ncePatchi]
1525  .size();
1526 
1527  if (procCounts[procStari] >= size) continue;
1528 
1529  const label procFacei =
1530  procMeshes_[procStari].polyFacesBf()
1531  [ncePatchi][procCounts[procStari]];
1532 
1533  const label faceStari =
1534  procFaceAddressing_[procStari][procFacei] - 1;
1535 
1536  if (facei > faceStari)
1537  {
1538  facei = faceStari;
1539  proci = procStari;
1540  }
1541  }
1542 
1543  if (facei == labelMax)
1544  {
1545  break;
1546  }
1547  else
1548  {
1549  nonConformalProcFaceAddressingBf
1550  [proci][ncePatchi].append(count + 1);
1551 
1552  count ++;
1553  procCounts[proci] ++;
1554  }
1555  }
1556  }
1557  }
1558 
1559  // Build finite volume face addressing boundary fields
1560  procFaceAddressingBf_.resize(nProcs());
1561  forAll(procMeshes_, proci)
1562  {
1563  const fvMesh& procMesh = procMeshes_[proci];
1564 
1565  procFaceAddressingBf_.set
1566  (
1567  proci,
1569  (
1570  procMesh.boundary(),
1572  calculatedFvsPatchLabelField::typeName
1573  )
1574  );
1575 
1576  forAll(procMesh.boundary(), procPatchi)
1577  {
1578  const fvPatch& fvp = procMesh.boundary()[procPatchi];
1579 
1580  if (isA<nonConformalFvPatch>(fvp))
1581  {
1582  procFaceAddressingBf_[proci][procPatchi] =
1583  nonConformalProcFaceAddressingBf[proci][procPatchi];
1584  }
1585  else if (isA<processorCyclicFvPatch>(fvp))
1586  {
1587  const label completePatchi =
1588  refCast<const processorCyclicFvPatch>(fvp)
1589  .referPatchID();
1590 
1591  procFaceAddressingBf_[proci][procPatchi] =
1592  mag(fvp.patchSlice(procFaceAddressing_[proci]))
1593  - completeMesh().boundaryMesh()[completePatchi].start();
1594  }
1595  else if (isA<processorFvPatch>(fvp))
1596  {
1597  procFaceAddressingBf_[proci][procPatchi] =
1598  fvp.patchSlice(procFaceAddressing_[proci]);
1599  }
1600  else
1601  {
1602  procFaceAddressingBf_[proci][procPatchi] =
1603  mag(fvp.patchSlice(procFaceAddressing_[proci]))
1604  - completeMesh().boundaryMesh()[procPatchi].start();
1605  }
1606  }
1607  }
1608  }
1609 
1610  return procFaceAddressingBf_;
1611 }
1612 
1613 
1614 void Foam::domainDecomposition::writeComplete(const bool doSets) const
1615 {
1616  const bool topologyWrite =
1617  static_cast<const faceCompactIOList&>(completeMesh().faces())
1618  .writeOpt() == IOobject::AUTO_WRITE;
1619 
1620  // Set the precision of the points data to be min 10
1622 
1623  // Write the complete mesh
1624  completeMesh().write();
1625 
1626  // Everything written below is topological data, so quit here if not
1627  // writing topology
1628  if (!topologyWrite) return;
1629 
1630  // Read, reconstruct and write sets
1631  if (doSets)
1632  {
1635  HashPtrTable<pointSet> pointSets;
1636 
1637  for (label proci = 0; proci < nProcs(); proci++)
1638  {
1639  const fvMesh& procMesh = procMeshes_[proci];
1640 
1641  const labelList& cellMap = procCellAddressing()[proci];
1642  const labelList& faceMap = procFaceAddressing()[proci];
1643  const labelList& pointMap = procPointAddressing()[proci];
1644 
1645  // Scan the contents of the sets directory
1646  IOobjectList setObjects
1647  (
1648  procMesh,
1649  runTimes_.procTimes()[proci].name(),
1650  polyMesh::meshSubDir/"sets"
1651  );
1652  IOobjectList cellSetObjects
1653  (
1654  setObjects.lookupClass(cellSet::typeName)
1655  );
1656  IOobjectList faceSetObjects
1657  (
1658  setObjects.lookupClass(faceSet::typeName)
1659  );
1660  IOobjectList pointSetObjects
1661  (
1662  setObjects.lookupClass(pointSet::typeName)
1663  );
1664 
1665  if
1666  (
1667  (cellSets.empty() && !cellSetObjects.empty())
1668  || (faceSets.empty() && !faceSetObjects.empty())
1669  || (pointSets.empty() && !pointSetObjects.empty())
1670  )
1671  {
1672  Info<< "Reconstructing sets" << incrIndent << nl << endl;
1673  }
1674 
1675  // Read and reconstruct the sets
1676  forAllConstIter(IOobjectList, cellSetObjects, iter)
1677  {
1678  const cellSet procSet(*iter());
1679 
1680  if (!cellSets.found(iter.key()))
1681  {
1682  Info<< indent << "cellSet " << iter.key() << endl;
1683 
1684  cellSets.insert
1685  (
1686  iter.key(),
1687  new cellSet
1688  (
1689  completeMesh(),
1690  iter.key(),
1691  procSet.size()
1692  )
1693  );
1694  }
1695 
1696  cellSet& cSet = *cellSets[iter.key()];
1697 
1698  cSet.instance() = runTimes_.completeTime().name();
1699 
1700  forAllConstIter(cellSet, procSet, iter)
1701  {
1702  cSet.insert(cellMap[iter.key()]);
1703  }
1704  }
1705  forAllConstIter(IOobjectList, faceSetObjects, iter)
1706  {
1707  const faceSet procSet(*iter());
1708 
1709  if (!faceSets.found(iter.key()))
1710  {
1711  Info<< indent << "faceSet " << iter.key() << endl;
1712 
1713  faceSets.insert
1714  (
1715  iter.key(),
1716  new faceSet
1717  (
1718  completeMesh(),
1719  iter.key(),
1720  procSet.size()
1721  )
1722  );
1723  }
1724 
1725  faceSet& cSet = *faceSets[iter.key()];
1726 
1727  cSet.instance() = runTimes_.completeTime().name();
1728 
1729  forAllConstIter(faceSet, procSet, iter)
1730  {
1731  cSet.insert(mag(faceMap[iter.key()]) - 1);
1732  }
1733  }
1734  forAllConstIter(IOobjectList, pointSetObjects, iter)
1735  {
1736  const pointSet procSet(*iter());
1737 
1738  if (!pointSets.found(iter.key()))
1739  {
1740  Info<< indent << "pointSet " << iter.key() << endl;
1741 
1742  pointSets.insert
1743  (
1744  iter.key(),
1745  new pointSet
1746  (
1747  completeMesh(),
1748  iter.key(),
1749  procSet.size()
1750  )
1751  );
1752  }
1753 
1754  pointSet& cSet = *pointSets[iter.key()];
1755 
1756  cSet.instance() = runTimes_.completeTime().name();
1757 
1758  forAllConstIter(pointSet, procSet, iter)
1759  {
1760  cSet.insert(pointMap[iter.key()]);
1761  }
1762  }
1763  }
1764 
1765  // Write the sets
1767  {
1768  iter()->write();
1769  }
1771  {
1772  iter()->write();
1773  }
1774  forAllConstIter(HashPtrTable<pointSet>, pointSets, iter)
1775  {
1776  iter()->write();
1777  }
1778 
1779  if (!cellSets.empty() || !faceSets.empty() || !pointSets.empty())
1780  {
1781  Info<< decrIndent << endl;
1782  }
1783  }
1784 
1785  // Read, decompose, and write refinement data (if any)
1786  UPtrList<const labelList> cellMaps(nProcs());
1787  UPtrList<const labelList> pointMaps(nProcs());
1788  PtrList<const hexRef8Data> refinementDatas(nProcs());
1789  for (label proci = 0; proci < nProcs(); proci++)
1790  {
1791  const fvMesh& procMesh = procMeshes_[proci];
1792 
1793  cellMaps.set(proci, &procCellAddressing_[proci]);
1794  pointMaps.set(proci, &procPointAddressing_[proci]);
1795  refinementDatas.set
1796  (
1797  proci,
1798  new hexRef8Data
1799  (
1800  IOobject
1801  (
1802  "dummy",
1803  completeMesh().facesInstance(),
1805  procMesh,
1808  false
1809  )
1810  )
1811  );
1812  }
1813  hexRef8Data
1814  (
1815  IOobject
1816  (
1817  "dummy",
1818  completeMesh().facesInstance(),
1820  completeMesh(),
1823  false
1824  ),
1825  cellMaps,
1826  pointMaps,
1827  refinementDatas
1828  ).write();
1829 
1830  // Write decomposition addressing
1831  writeAddressing();
1832 }
1833 
1834 
1835 void Foam::domainDecomposition::writeProcs(const bool doSets) const
1836 {
1837  const bool topologyWrite =
1838  static_cast<const faceCompactIOList&>(procMeshes()[0].faces())
1839  .writeOpt() == IOobject::AUTO_WRITE;
1840 
1841  // Write out the meshes
1842  for (label proci = 0; proci < nProcs(); proci++)
1843  {
1844  const fvMesh& procMesh = procMeshes_[proci];
1845 
1846  // Set the precision of the points data to be min 10
1848 
1849  // Write the processor mesh
1850  procMesh.write();
1851  }
1852 
1853  // Everything written below is topological data, so quit here if not
1854  // writing topology
1855  if (!topologyWrite) return;
1856 
1857  // Read, decompose, and write any sets
1858  if (doSets)
1859  {
1860  // Scan the contents of the sets directory
1861  IOobjectList setObjects
1862  (
1863  completeMesh(),
1864  completeMesh().facesInstance(),
1865  polyMesh::meshSubDir/"sets"
1866  );
1867  IOobjectList cellSetObjects
1868  (
1869  setObjects.lookupClass(cellSet::typeName)
1870  );
1871  IOobjectList faceSetObjects
1872  (
1873  setObjects.lookupClass(faceSet::typeName)
1874  );
1875  IOobjectList pointSetObjects
1876  (
1877  setObjects.lookupClass(pointSet::typeName)
1878  );
1879 
1880  // Read the sets
1882  forAllConstIter(IOobjectList, cellSetObjects, iter)
1883  {
1884  cellSets.append(new cellSet(*iter()));
1885  }
1887  forAllConstIter(IOobjectList, faceSetObjects, iter)
1888  {
1889  faceSets.append(new faceSet(*iter()));
1890  }
1891  PtrList<const pointSet> pointSets;
1892  forAllConstIter(IOobjectList, pointSetObjects, iter)
1893  {
1894  pointSets.append(new pointSet(*iter()));
1895  }
1896 
1897  // Decompose and write sets into the processor mesh directories
1898  for (label proci = 0; proci < nProcs(); proci++)
1899  {
1900  const fvMesh& procMesh = procMeshes_[proci];
1901 
1902  forAll(cellSets, i)
1903  {
1904  const cellSet& cs = cellSets[i];
1905  cellSet set(procMesh, cs.name(), cs.size()/nProcs());
1906  forAll(procCellAddressing_[proci], i)
1907  {
1908  if (cs.found(procCellAddressing_[proci][i]))
1909  {
1910  set.insert(i);
1911  }
1912  }
1913  set.write();
1914  }
1915  forAll(faceSets, i)
1916  {
1917  const faceSet& cs = faceSets[i];
1918  faceSet set(procMesh, cs.name(), cs.size()/nProcs());
1919  forAll(procFaceAddressing_[proci], i)
1920  {
1921  if (cs.found(mag(procFaceAddressing_[proci][i]) - 1))
1922  {
1923  set.insert(i);
1924  }
1925  }
1926  set.write();
1927  }
1928  forAll(pointSets, i)
1929  {
1930  const pointSet& cs = pointSets[i];
1931  pointSet set(procMesh, cs.name(), cs.size()/nProcs());
1932  forAll(procPointAddressing_[proci], i)
1933  {
1934  if (cs.found(procPointAddressing_[proci][i]))
1935  {
1936  set.insert(i);
1937  }
1938  }
1939  set.write();
1940  }
1941  }
1942  }
1943 
1944  // Read, decompose, and write refinement data (if any)
1946  (
1947  IOobject
1948  (
1949  "dummy",
1950  completeMesh().facesInstance(),
1952  completeMesh(),
1955  false
1956  )
1957  );
1958  for (label proci = 0; proci < nProcs(); proci++)
1959  {
1960  const fvMesh& procMesh = procMeshes_[proci];
1961 
1962  hexRef8Data
1963  (
1964  IOobject
1965  (
1966  "dummy",
1967  completeMesh().facesInstance(),
1969  procMesh,
1972  false
1973  ),
1975  procCellAddressing_[proci],
1976  procPointAddressing_[proci]
1977  ).write();
1978  }
1979 
1980  // Write decomposition addressing
1981  writeAddressing();
1982 }
1983 
1984 
1985 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
Generic GeometricBoundaryField class.
GeometricBoundaryField< Type, PatchField, GeoMesh > Boundary
Type of the boundary field.
static const GeometricField< Type, PatchField, GeoMesh > & null()
Return a null geometric field.
A HashTable specialisation for hashing pointers.
Definition: HashPtrTable.H:67
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:111
An STL-conforming hash table.
Definition: HashTable.H:127
bool set(const Key &, const T &newElmt)
Assign a new hashedEntry, overwriting existing entries.
Definition: HashTableI.H:91
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
bool empty() const
Return true if the hash table is empty.
Definition: HashTableI.H:72
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:113
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:53
IOobjectList lookupClass(const word &className) const
Return the list for all IOobjects of a given class.
Definition: IOobjectList.C:190
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
fileName relativePath() const
Return the path relative to the case directory.
Definition: IOobject.C:393
fileName & instance() const
Return the instance directory, constant, system, <time> etc.
Definition: IOobject.C:355
bool headerOk()
Read header of local object without type-checking.
const word & name() const
Return name.
Definition: IOobject.H:310
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:458
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void resize(const label)
Alias for setSize(const label)
Definition: ListI.H:138
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
const Type & second() const
Return second.
Definition: Pair.H:110
const Type & first() const
Return first.
Definition: Pair.H:98
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
bool set(const label) const
Is element set.
Definition: PtrListI.H:65
void append(T *)
Append an element at the end of the list.
Definition: PtrListI.H:39
A List with indirect addressing.
Definition: UIndirectList.H:60
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: UPtrList.H:66
bool set(const label) const
Is element set.
Definition: UPtrListI.H:78
A collection of cell labels.
Definition: cellSet.H:51
virtual label nbrPatchID() const
Return neighbour.
Definition: cyclicFvPatch.H:96
Automatic domain decomposition class for finite-volume meshes.
label nProcs() const
Return the number of processors in the decomposition.
void writeProcs(const bool doSets) const
Write the decomposed meshes and associated data.
bool readDecompose(const bool doSets)
Read in the complete mesh. Read the processor meshes if they are.
void writeComplete(const bool doSets) const
Write the decomposed meshes and associated data.
bool readReconstruct(const bool doSets)
Read in the processor meshes. Read the complete mesh if it is.
const PtrList< surfaceLabelField::Boundary > & procFaceAddressingBf() const
Access the labels of faces for each processor (see notes above)
const fvMesh & completeMesh() const
Access the global mesh.
domainDecomposition(const processorRunTimes &procRunTimes, const word &regionName)
Construct from processor run times and region name.
fvMesh::readUpdateState readUpdateReconstruct()
Read-update for reconstruction.
fvMesh::readUpdateState readUpdateDecompose()
Read-update for decomposition.
virtual ~domainDecomposition()
Destructor.
A list of face labels.
Definition: faceSet.H:51
A class for handling file names.
Definition: fileName.H:82
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:101
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:893
virtual bool write(const bool write=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1734
const word & name() const
Return reference to name.
Definition: fvMesh.H:420
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:64
const List< T >::subList patchSlice(const List< T > &l) const
Slice list to patch.
Definition: fvPatch.H:191
Various for reading/decomposing/reconstructing/distributing refinement data.
Definition: hexRef8Data.H:58
bool write() const
Write.
Definition: hexRef8Data.C:372
Non-conformal cyclic FV patch. As nonConformalCoupledFvPatch, but the neighbouring patch is local and...
virtual bool owner() const
...
A set of point labels.
Definition: pointSet.H:51
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:269
readUpdateState
Enumeration defining the state of the mesh after a read update.
Definition: polyMesh.H:91
label referPatchID() const
Return the referring patch ID.
virtual int neighbProcNo() const
Return neighbour processor number.
Transfers refinement levels such that slow transition between levels is maintained....
virtual bool write(const bool write=true) const
Write using setting from DB.
Templated form of IOobject providing type information for file reading and header type checking.
Definition: IOobject.H:531
bool headerOk()
Read header (uses typeGlobalFile to find file) and check.
A class for handling words, derived from string.
Definition: word.H:62
Foam::word regionName
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
label patchi
const pointField & points
label nPoints
volScalarField & b
Definition: createFields.H:27
#define WarningInFunction
Report a warning using Foam::Warning.
#define InfoInFunction
Report an information message using Foam::Info.
tmp< VolField< typename outerProduct< vector, Type >::type > > reconstruct(const SurfaceField< Type > &ssf)
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:235
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:228
dimensioned< scalar > mag(const dimensioned< Type > &)
vectorIOField pointIOField
pointIOField is a vectorIOField.
Definition: pointIOField.H:42
defineTypeNameAndDebug(combustionModel, 0)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
IOList< label > labelIOList
Label container classes.
Definition: labelIOList.H:42
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:49
error FatalError
label count(const ListType &l, typename ListType::const_reference x)
Count the number of occurrences of a value in a list.
static const label labelMax
Definition: label.H:62
SurfaceField< vector > surfaceVectorField
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:221
static const char nl
Definition: Ostream.H:260
faceListList boundary(nPatches)