redistributePar.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-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2024 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Application
28  redistributePar
29 
30 Group
31  grpParallelUtilities
32 
33 Description
34  Redistributes existing decomposed mesh and fields according to the current
35  settings in the decomposeParDict file.
36 
37  Must be run on maximum number of source and destination processors.
38  Balances mesh and writes new mesh to new time directory.
39 
40  Can optionally run in decompose/reconstruct mode to decompose/reconstruct
41  mesh and fields.
42 
43 Usage
44  \b redistributePar [OPTION]
45 
46  Options:
47  - \par -decompose
48  Remove any existing \a processor subdirectories and decomposes the
49  mesh. Equivalent to running without processor subdirectories.
50 
51  - \par -reconstruct
52  Reconstruct mesh and fields (like reconstructParMesh+reconstructPar).
53 
54  - \par -newTimes
55  (in combination with -reconstruct) reconstruct only new times.
56 
57  - \par -dry-run
58  (not in combination with -reconstruct) Test without actually
59  decomposing.
60 
61  - \par -cellDist
62  not in combination with -reconstruct) Write the cell distribution
63  as a labelList, for use with 'manual'
64  decomposition method and as a volScalarField for visualization.
65 
66  - \par -region <regionName>
67  Distribute named region.
68 
69  - \par -allRegions
70  Distribute all regions in regionProperties. Does not check for
71  existence of processor*.
72 
73 \*---------------------------------------------------------------------------*/
74 
75 #include "argList.H"
76 #include "sigFpe.H"
77 #include "Time.H"
78 #include "fvMesh.H"
79 #include "fvMeshTools.H"
80 #include "fvMeshDistribute.H"
81 #include "fieldsDistributor.H"
82 #include "decompositionMethod.H"
83 #include "decompositionModel.H"
84 #include "timeSelector.H"
85 #include "PstreamReduceOps.H"
86 #include "volFields.H"
87 #include "surfaceFields.H"
89 #include "IOobjectList.H"
90 #include "globalIndex.H"
91 #include "loadOrCreateMesh.H"
92 #include "processorFvPatchField.H"
93 #include "topoSet.H"
94 #include "regionProperties.H"
95 
96 #include "parFvFieldDistributor.H"
98 #include "hexRef8Data.H"
99 #include "meshRefinement.H"
100 #include "pointFields.H"
101 
102 #include "faMeshSubset.H"
103 #include "faMeshTools.H"
104 #include "faMeshDistributor.H"
105 #include "faMeshesRegistry.H"
107 
108 #include "redistributeLagrangian.H"
109 
110 using namespace Foam;
111 
112 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
113 
114 // Use -verbose -verbose to switch on debug info. TBD.
115 int debug(::Foam::debug::debugSwitch("redistributePar", 0));
116 #define InfoOrPout (::debug ? Pout : Info.stream())
117 
118 
119 // Allocate a new file handler on valid processors only
120 // retaining the original IO ranks if possible
122 getNewHandler(const boolUList& useProc, const bool verbose = true)
123 {
124  autoPtr<fileOperation> handler
125  (
126  fileOperation::New(fileHandler(), useProc, verbose)
127  );
128 
129  if (::debug && handler)
130  {
131  Pout<< "Allocated " << handler().info()
132  << " myProcNo:" << UPstream::myProcNo(handler().comm())
133  << " ptr:" << Foam::name(handler.get()) << endl;
134  }
135 
136  return handler;
137 }
138 
139 
140 // Allocate a new file handler on valid processors only
141 // retaining the original IO ranks if possible
142 void newHandler(const boolUList& useProc, refPtr<fileOperation>& handler)
143 {
144  if (!handler)
145  {
146  handler = getNewHandler(useProc);
147  }
148 }
149 
150 
151 void createTimeDirs(const fileName& path)
152 {
153  // Get current set of local processor's time directories. Uses
154  // fileHandler
155  instantList localTimeDirs(Time::findTimes(path, "constant"));
156 
157  instantList masterTimeDirs;
158  if (Pstream::master())
159  {
160  masterTimeDirs = localTimeDirs;
161  }
162  Pstream::broadcast(masterTimeDirs);
163 
164  // Sync any cached times (e.g. masterUncollatedFileOperation::times_)
165  // since only master would have done the findTimes
166  for (const instant& t : masterTimeDirs)
167  {
168  if (!localTimeDirs.contains(t))
169  {
170  const fileName timePath(path/t.name());
171 
172  //Pout<< "Time:" << t << nl
173  // << " raw :" << timePath << nl
174  // << endl;
175  // Bypass fileHandler
176  Foam::mkDir(timePath);
177  }
178  }
179 
180  // Just to make sure remove all state and re-scan
181  fileHandler().flush();
182  (void)Time::findTimes(path, "constant");
183 }
184 
185 
186 void copyUniform
187 (
188  refPtr<fileOperation>& readHandler,
189  refPtr<fileOperation>& writeHandler,
190 
191  const bool reconstruct,
192  const bool decompose,
193 
194  const word& readTimeName,
195  const fileName& readCaseName,
196 
197  const objectRegistry& readDb,
198  const objectRegistry& writeDb
199 )
200 {
201  // 3 modes: reconstruct, decompose, redistribute
202 
203  // In reconstruct mode (separate reconstructed mesh):
204  // - read using readDb + readHandler
205  // - write using writeDb + writeHandler
206 
207  // In decompose mode (since re-using processor0 mesh):
208  // - read using readDb + readCaseName + readHandler
209  // - write using writeDb + writeHandler
210 
211  // In redistribute mode:
212  // - read using readDb + readHandler
213  // - write using writeDb + writeHandler
214 
215  fileName readPath;
216 
217  if (readHandler)
218  {
219  const label oldComm = UPstream::commWorld(readHandler().comm());
220 
221  Time& readTime = const_cast<Time&>(readDb.time());
222  bool oldProcCase = readTime.processorCase();
223  string oldCaseName;
224  if (decompose)
225  {
226  //Pout<< "***Setting caseName to " << readCaseName
227  // << " to read undecomposed uniform" << endl;
228  oldCaseName = readTime.caseName();
229  readTime.caseName() = readCaseName;
230  oldProcCase = readTime.processorCase(false);
231  }
232 
233  // Detect uniform/ at original database + time
234  readPath = readHandler().dirPath
235  (
236  false, // local directory
237  IOobject("uniform", readTimeName, readDb),
238  false // do not search in time
239  );
240 
241 
242  UPstream::commWorld(oldComm);
243 
244  if (decompose)
245  {
246  // Reset caseName on master
247  //Pout<< "***Restoring caseName to " << oldCaseName << endl;
248  readTime.caseName() = oldCaseName;
249  readTime.processorCase(oldProcCase);
250  }
251  }
253 
254  if (!readPath.empty())
255  {
256  InfoOrPout
257  << "Detected additional non-decomposed files in "
258  << readPath << endl;
259 
260  // readPath: searching is the same for all file handlers. Typical:
261  // <case>/0.1/uniform (parent dir, decompose mode)
262  // <case>/processor1/0.1/uniform (redistribute/reconstruct mode)
263  // <case>/processors2/0.1/uniform ,,
264  // writePath:
265  // uncollated : <case>/0.1/uniform (reconstruct mode). Should only
266  // be done by master
267  // uncollated : <case>/processorXXX/0.1/uniform. Should be done by all.
268  // collated : <case>/processors2/0.1/uniform. Should be done by
269  // local master only.
270 
271  const IOobject writeIO
272  (
273  "uniform",
274  writeDb.time().timeName(),
275  writeDb
276  );
277 
278  // Switch to writeHandler
279  if (writeHandler)
280  {
281  auto oldHandler = fileOperation::fileHandler(writeHandler);
282 
283  // Check: fileHandler.comm() is size 1 for uncollated
284  const label writeComm = fileHandler().comm();
285 
286  if (reconstruct)
287  {
288  const bool oldParRun = UPstream::parRun(false);
289  const label oldNumProcs(fileHandler().nProcs());
290  const fileName writePath
291  (
292  fileHandler().objectPath
293  (
294  writeIO,
295  word::null
296  )
297  );
298  fileHandler().cp(readPath, writePath);
299  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
300  UPstream::parRun(oldParRun);
301  }
302  else
303  {
304  const fileName writePath
305  (
306  fileHandler().objectPath
307  (
308  writeIO,
309  word::null
310  )
311  );
312 
313  if (::debug)
314  {
315  Pout<< " readPath :" << readPath << endl;
316  Pout<< " writePath :" << writePath << endl;
317  }
318 
319  fileHandler().broadcastCopy
320  (
321  writeComm, // send to all in writeComm
322  UPstream::master(writeComm), // to use ioranks. Check!
323  readPath,
324  writePath
325  );
326  }
327  writeHandler = fileOperation::fileHandler(oldHandler);
328  }
329  }
330 }
331 
332 
333 void printMeshData(const polyMesh& mesh)
334 {
335  // Collect all data on master
336 
337  labelListList patchNeiProcNo(Pstream::nProcs());
338  labelListList patchSize(Pstream::nProcs());
339  const labelList& pPatches = mesh.globalData().processorPatches();
340  patchNeiProcNo[Pstream::myProcNo()].setSize(pPatches.size());
341  patchSize[Pstream::myProcNo()].setSize(pPatches.size());
342  forAll(pPatches, i)
343  {
344  const processorPolyPatch& ppp = refCast<const processorPolyPatch>
345  (
346  mesh.boundaryMesh()[pPatches[i]]
347  );
348  patchNeiProcNo[Pstream::myProcNo()][i] = ppp.neighbProcNo();
349  patchSize[Pstream::myProcNo()][i] = ppp.size();
350  }
351  Pstream::gatherList(patchNeiProcNo);
352  Pstream::gatherList(patchSize);
353 
354 
355  // Print stats
356 
357  const globalIndex globalCells(mesh.nCells());
358  const globalIndex globalBoundaryFaces(mesh.nBoundaryFaces());
359 
360  label maxProcCells = 0;
361  label maxProcFaces = 0;
362  label totProcFaces = 0;
363  label maxProcPatches = 0;
364  label totProcPatches = 0;
365 
366  for (const int proci : Pstream::allProcs())
367  {
368  const label nLocalCells = globalCells.localSize(proci);
369  const label nBndFaces = globalBoundaryFaces.localSize(proci);
370 
371  InfoOrPout<< nl
372  << "Processor " << proci;
373 
374  if (!nLocalCells)
375  {
376  InfoOrPout<< " (empty)" << endl;
377  continue;
378  }
379  else
380  {
381  InfoOrPout<< nl
382  << " Number of cells = " << nLocalCells << endl;
383  }
384 
385  label nProcFaces = 0;
386  const labelList& nei = patchNeiProcNo[proci];
387 
388  forAll(patchNeiProcNo[proci], i)
389  {
390  InfoOrPout
391  << " Number of faces shared with processor "
392  << patchNeiProcNo[proci][i] << " = "
393  << patchSize[proci][i] << nl;
394 
395  nProcFaces += patchSize[proci][i];
396  }
397 
398  {
399  InfoOrPout
400  << " Number of processor patches = " << nei.size() << nl
401  << " Number of processor faces = " << nProcFaces << nl
402  << " Number of boundary faces = "
403  << nBndFaces-nProcFaces << endl;
404  }
405 
406  maxProcCells = max(maxProcCells, nLocalCells);
407  totProcFaces += nProcFaces;
408  totProcPatches += nei.size();
409  maxProcFaces = max(maxProcFaces, nProcFaces);
410  maxProcPatches = max(maxProcPatches, nei.size());
411  }
412 
413  // Summary stats
414 
415  InfoOrPout
416  << nl
417  << "Number of processor faces = " << (totProcFaces/2) << nl
418  << "Max number of cells = " << maxProcCells;
419 
420  if (maxProcCells != globalCells.totalSize())
421  {
422  scalar avgValue = scalar(globalCells.totalSize())/Pstream::nProcs();
423 
424  InfoOrPout
425  << " (" << 100.0*(maxProcCells-avgValue)/avgValue
426  << "% above average " << avgValue << ')';
427  }
428  InfoOrPout<< nl;
429 
430  InfoOrPout<< "Max number of processor patches = " << maxProcPatches;
431  if (totProcPatches)
432  {
433  scalar avgValue = scalar(totProcPatches)/Pstream::nProcs();
434 
435  InfoOrPout
436  << " (" << 100.0*(maxProcPatches-avgValue)/avgValue
437  << "% above average " << avgValue << ')';
438  }
439  InfoOrPout<< nl;
440 
441  InfoOrPout<< "Max number of faces between processors = " << maxProcFaces;
442  if (totProcFaces)
443  {
444  scalar avgValue = scalar(totProcFaces)/Pstream::nProcs();
445 
446  InfoOrPout
447  << " (" << 100.0*(maxProcFaces-avgValue)/avgValue
448  << "% above average " << avgValue << ')';
449  }
450  InfoOrPout<< nl << endl;
451 }
452 
453 
454 // Debugging: write volScalarField with decomposition for post processing.
455 void writeDecomposition
456 (
457  const word& name,
458  const fvMesh& mesh,
459  const labelUList& decomp
460 )
461 {
462  // Write the decomposition as labelList for use with 'manual'
463  // decomposition method.
465  (
466  IOobject
467  (
468  "cellDecomposition",
469  mesh.facesInstance(), // mesh read from facesInstance
470  mesh,
474  ),
475  decomp
476  ).write();
477 
478  InfoOrPout
479  << "Writing wanted cell distribution to volScalarField " << name
480  << " for postprocessing purposes." << nl << endl;
481 
482  volScalarField procCells
483  (
484  IOobject
485  (
486  name,
487  mesh.time().timeName(),
488  mesh,
492  ),
493  mesh,
494  dimensionedScalar("", dimless, -1),
496  );
497 
498  forAll(procCells, celli)
499  {
500  procCells[celli] = decomp[celli];
501  }
502 
503  procCells.correctBoundaryConditions();
504  procCells.write();
505 }
506 
507 
508 void determineDecomposition
509 (
510  refPtr<fileOperation>& readHandler,
511  const Time& baseRunTime,
512  const fileName& decompDictFile, // optional location for decomposeParDict
513  const bool decompose, // decompose, i.e. read from undecomposed case
514  const fileName& proc0CaseName,
515  const fvMesh& mesh,
516  const bool writeCellDist,
517 
518  label& nDestProcs,
519  labelList& decomp
520 )
521 {
522  // Switch to readHandler since decomposition method might do IO
523  // (e.g. read decomposeParDict)
524  auto oldHandler = fileOperation::fileHandler(readHandler);
525 
526  // Read decomposeParDict (on all processors)
528  (
529  mesh,
530  decompDictFile
531  );
532 
533  decompositionMethod& decomposer = method.decomposer();
534 
535  if (!decomposer.parallelAware())
536  {
538  << "You have selected decomposition method \""
539  << decomposer.type() << "\n"
540  << " which does not synchronise decomposition across"
541  " processor patches.\n"
542  " You might want to select a decomposition method"
543  " that is aware of this. Continuing...." << endl;
544  }
545 
546  Time& tm = const_cast<Time&>(mesh.time());
547 
548  const bool oldProcCase = tm.processorCase();
549  if (decompose)
550  {
551  InfoOrPout
552  << "Setting caseName to " << baseRunTime.caseName()
553  << " to read decomposeParDict" << endl;
554  tm.caseName() = baseRunTime.caseName();
555  tm.processorCase(false);
556  }
557 
558  scalarField cellWeights;
559  if (method.found("weightField"))
560  {
561  word weightName = method.get<word>("weightField");
562 
563  volScalarField weights
564  (
565  IOobject
566  (
567  weightName,
568  tm.timeName(),
569  mesh,
573  ),
574  mesh
575  );
576  cellWeights = weights.internalField();
577  }
578 
579  nDestProcs = decomposer.nDomains();
580  decomp = decomposer.decompose(mesh, cellWeights);
581 
582  readHandler = fileOperation::fileHandler(oldHandler);
583 
584 
585  if (decompose)
586  {
587  InfoOrPout
588  << "Restoring caseName" << endl;
589  tm.caseName() = proc0CaseName;
590  tm.processorCase(oldProcCase);
591  }
592 
593  // Dump decomposition to volScalarField
594  if (writeCellDist)
595  {
596  const label oldNumProcs =
597  const_cast<fileOperation&>(fileHandler()).nProcs(nDestProcs);
598 
599  // Note: on master make sure to write to processor0
600  if (decompose)
601  {
602  if (UPstream::master())
603  {
604  const bool oldParRun = UPstream::parRun(false);
605 
606  InfoOrPout
607  << "Setting caseName to " << baseRunTime.caseName()
608  << " to write undecomposed cellDist" << endl;
609 
610  tm.caseName() = baseRunTime.caseName();
611  tm.processorCase(false);
612  writeDecomposition("cellDist", mesh, decomp);
613  InfoOrPout<< "Restoring caseName" << endl;
614  tm.caseName() = proc0CaseName;
615  tm.processorCase(oldProcCase);
616 
617  UPstream::parRun(oldParRun);
618  }
619  }
620  else
621  {
622  writeDecomposition("cellDist", mesh, decomp);
623  }
624 
625  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
626  }
627 }
628 
629 
630 // Variant of GeometricField::correctBoundaryConditions that only
631 // evaluates selected patch fields
632 template<class CoupledPatchType, class GeoField>
633 void correctCoupledBoundaryConditions(fvMesh& mesh)
634 {
635  for (GeoField& fld : mesh.sorted<GeoField>())
636  {
637  fld.boundaryFieldRef().template evaluateCoupled<CoupledPatchType>();
638  }
639 }
640 
641 
642 // Inplace redistribute mesh and any fields
643 autoPtr<mapDistributePolyMesh> redistributeAndWrite
644 (
645  refPtr<fileOperation>& readHandler,
646  refPtr<fileOperation>& writeHandler,
647  const Time& baseRunTime,
648  const fileName& proc0CaseName,
649 
650  // Controls
651  const bool doReadFields,
652  const bool decompose, // decompose, i.e. read from undecomposed case
653  const bool reconstruct,
654  const bool overwrite,
655 
656  // Decomposition information
657  const label nDestProcs,
658  const labelList& decomp,
659 
660  // Mesh information
661  const boolList& volMeshOnProc,
662  const fileName& volMeshInstance,
663  fvMesh& mesh
664 )
665 {
666  Time& runTime = const_cast<Time&>(mesh.time());
667  const bool oldProcCase = runTime.processorCase();
668 
670  //Pout<< "Before distribution:" << endl;
671  //printMeshData(mesh);
672 
673 
674  // Storage of fields
675 
676  PtrList<volScalarField> volScalarFields;
677  PtrList<volVectorField> volVectorFields;
678  PtrList<volSphericalTensorField> volSphereTensorFields;
679  PtrList<volSymmTensorField> volSymmTensorFields;
680  PtrList<volTensorField> volTensorFields;
681 
682  PtrList<surfaceScalarField> surfScalarFields;
683  PtrList<surfaceVectorField> surfVectorFields;
684  PtrList<surfaceSphericalTensorField> surfSphereTensorFields;
685  PtrList<surfaceSymmTensorField> surfSymmTensorFields;
686  PtrList<surfaceTensorField> surfTensorFields;
687 
693 
694  PtrList<pointScalarField> pointScalarFields;
695  PtrList<pointVectorField> pointVectorFields;
696  PtrList<pointTensorField> pointTensorFields;
697  PtrList<pointSphericalTensorField> pointSphTensorFields;
698  PtrList<pointSymmTensorField> pointSymmTensorFields;
699 
700  // Self-contained pointMesh for reading pointFields
701  const pointMesh oldPointMesh(mesh);
702 
703  // Track how many (if any) pointFields are read/mapped
704  label nPointFields = 0;
705 
706  refPtr<fileOperation> noWriteHandler;
707 
708  parPointFieldDistributor pointDistributor
709  (
710  oldPointMesh, // source mesh
711  false, // savePoints=false (ie, delay until later)
712  //false // Do not write
713  noWriteHandler // Do not write
714  );
715 
716 
717  if (doReadFields)
718  {
719  // Create 0 sized mesh to do all the generation of zero sized
720  // fields on processors that have zero sized meshes. Note that this is
721  // only necessary on master but since polyMesh construction with
722  // Pstream::parRun does parallel comms we have to do it on all
723  // processors
724  autoPtr<fvMeshSubset> subsetterPtr;
725 
726  // Missing a volume mesh somewhere?
727  if (volMeshOnProc.found(false))
728  {
729  // A zero-sized mesh with boundaries.
730  // This is used to create zero-sized fields.
731  subsetterPtr.reset(new fvMeshSubset(mesh, zero{}));
732  subsetterPtr().subMesh().init(true);
733  subsetterPtr().subMesh().globalData();
734  subsetterPtr().subMesh().tetBasePtIs();
735  subsetterPtr().subMesh().geometricD();
736  }
737 
738 
739  // Get original objects (before incrementing time!)
740  if (decompose)
741  {
742  InfoOrPout
743  << "Setting caseName to " << baseRunTime.caseName()
744  << " to read IOobjects" << endl;
745  runTime.caseName() = baseRunTime.caseName();
746  runTime.processorCase(false);
747  }
748 
749  //IOobjectList objects(mesh, runTime.timeName());
750  // Swap to reading fileHandler and read IOobjects
751  IOobjectList objects;
752  if (readHandler)
753  {
754  auto oldHandler = fileOperation::fileHandler(readHandler);
755  const label oldComm = UPstream::commWorld(fileHandler().comm());
756 
757  objects = IOobjectList(mesh, runTime.timeName());
758  readHandler = fileOperation::fileHandler(oldHandler);
759  UPstream::commWorld(oldComm);
760  }
761 
762  if (decompose)
763  {
764  InfoOrPout
765  << "Restoring caseName" << endl;
766  runTime.caseName() = proc0CaseName;
767  runTime.processorCase(oldProcCase);
768  }
769 
770  InfoOrPout
771  << "From time " << runTime.timeName()
772  << " mesh:" << mesh.objectRegistry::objectRelPath()
773  << " have objects:" << objects.names() << endl;
774 
775  // We don't want to map the decomposition (mapping already tested when
776  // mapping the cell centre field)
777  (void)objects.erase("cellDist");
778 
779 
780  if (decompose)
781  {
782  runTime.caseName() = baseRunTime.caseName();
783  runTime.processorCase(false);
784  }
785 
786  // Field reading
787 
788  #undef doFieldReading
789  #define doFieldReading(Storage) \
790  { \
791  fieldsDistributor::readFields \
792  ( \
793  volMeshOnProc, readHandler, mesh, subsetterPtr, \
794  objects, Storage \
795  ); \
796  }
797 
798  // volField
799  doFieldReading(volScalarFields);
800  doFieldReading(volVectorFields);
801  doFieldReading(volSphereTensorFields);
802  doFieldReading(volSymmTensorFields);
803  doFieldReading(volTensorFields);
804 
805  // surfaceField
806  doFieldReading(surfScalarFields);
807  doFieldReading(surfVectorFields);
808  doFieldReading(surfSphereTensorFields);
809  doFieldReading(surfSymmTensorFields);
810  doFieldReading(surfTensorFields);
811 
812  // Dimensioned internal fields
813  doFieldReading(dimScalarFields);
814  doFieldReading(dimVectorFields);
815  doFieldReading(dimSphereTensorFields);
816  doFieldReading(dimSymmTensorFields);
817  doFieldReading(dimTensorFields);
818 
819  // pointFields
820  nPointFields = 0;
821 
822  #undef doFieldReading
823  #define doFieldReading(Storage) \
824  { \
825  fieldsDistributor::readFields \
826  ( \
827  volMeshOnProc, readHandler, oldPointMesh, \
828  subsetterPtr, objects, Storage, \
829  true /* (deregister field) */ \
830  ); \
831  nPointFields += Storage.size(); \
832  }
833 
834  doFieldReading(pointScalarFields);
835  doFieldReading(pointVectorFields);
836  doFieldReading(pointSphTensorFields);
837  doFieldReading(pointSymmTensorFields);
838  doFieldReading(pointTensorFields);
839  #undef doFieldReading
840 
841 
842  // Done reading
843 
844  if (decompose)
845  {
846  runTime.caseName() = proc0CaseName;
847  runTime.processorCase(oldProcCase);
848  }
849  }
850 
851  // Save pointMesh information before any topology changes occur!
852  if (nPointFields)
853  {
854  pointDistributor.saveMeshPoints();
855  }
856 
857 
858  // Read refinement data
859  autoPtr<hexRef8Data> refDataPtr;
860  {
861  // Read refinement data
862  if (decompose)
863  {
864  runTime.caseName() = baseRunTime.caseName();
865  runTime.processorCase(false);
866  }
867  IOobject io
868  (
869  "dummy",
870  volMeshInstance, //mesh.facesInstance(),
872  mesh,
876  );
877 
878  if (readHandler)
879  {
880  auto oldHandler = fileOperation::fileHandler(readHandler);
881  const label oldComm = UPstream::commWorld(fileHandler().comm());
882 
883  // Read
884  refDataPtr.reset(new hexRef8Data(io));
885 
886  UPstream::commWorld(oldComm);
887  readHandler = fileOperation::fileHandler(oldHandler);
888  }
889  else
890  {
892  refDataPtr.reset(new hexRef8Data(io));
893  }
894 
895  if (decompose)
896  {
897  runTime.caseName() = proc0CaseName;
898  runTime.processorCase(oldProcCase);
899  }
900 
901  // Make sure all processors have valid data (since only some will
902  // read)
903  refDataPtr().sync(io);
904 
905  // Now we've read refinement data we can remove it
907  }
908 
909 
910  // If faMeshesRegistry exists, it is also owned by the polyMesh and will
911  // be destroyed by clearGeom() in fvMeshDistribute::distribute()
912  //
913  // Rescue faMeshesRegistry from destruction by temporarily moving
914  // it to be locally owned.
915  std::unique_ptr<faMeshesRegistry> faMeshesRegistry_saved
916  (
918  );
919 
920  // Mesh distribution engine
921  fvMeshDistribute distributor(mesh);
922 
923  // Do all the distribution of mesh and fields
924  autoPtr<mapDistributePolyMesh> distMap = distributor.distribute(decomp);
925 
926  // Restore ownership onto the polyMesh
927  faMeshesRegistry::Store(std::move(faMeshesRegistry_saved));
928 
929 
930  // Print some statistics
931  InfoOrPout<< "After distribution:" << endl;
932  printMeshData(mesh);
933 
934  // Get other side of processor boundaries
935  do
936  {
937  #undef doCorrectCoupled
938  #define doCorrectCoupled(FieldType) \
939  correctCoupledBoundaryConditions<processorFvPatch, FieldType>(mesh);
940 
941  doCorrectCoupled(volScalarField);
942  doCorrectCoupled(volVectorField);
943  doCorrectCoupled(volSphericalTensorField);
944  doCorrectCoupled(volSymmTensorField);
945  doCorrectCoupled(volTensorField);
946  #undef doCorrectCoupled
947  }
948  while (false);
949 
950  // No update surface fields
951 
952 
953  // Map pointFields
954  if (nPointFields)
955  {
956  // Construct new pointMesh from distributed mesh
957  const pointMesh& newPointMesh = pointMesh::New(mesh);
958 
959  pointDistributor.resetTarget(newPointMesh, distMap());
960 
961  pointDistributor.distributeAndStore(pointScalarFields);
962  pointDistributor.distributeAndStore(pointVectorFields);
963  pointDistributor.distributeAndStore(pointSphTensorFields);
964  pointDistributor.distributeAndStore(pointSymmTensorFields);
965  pointDistributor.distributeAndStore(pointTensorFields);
966  }
967 
968 
969  // More precision (for points data)
971 
972 
973  if (!overwrite)
974  {
975  ++runTime;
977  }
978  else
979  {
980  mesh.setInstance(volMeshInstance);
981  }
982 
983 
984  // Register mapDistributePolyMesh for automatic writing...
985  IOmapDistributePolyMeshRef distMapRef
986  (
987  IOobject
988  (
989  "procAddressing",
992  mesh.thisDb(),
995  ),
996  distMap()
997  );
998 
999 
1000  if (reconstruct)
1001  {
1002  auto oldHandler = fileOperation::fileHandler(writeHandler);
1003 
1004  if (UPstream::master())
1005  {
1006  InfoOrPout
1007  << "Setting caseName to " << baseRunTime.caseName()
1008  << " to write reconstructed mesh (and fields)." << endl;
1009  runTime.caseName() = baseRunTime.caseName();
1010  const bool oldProcCase(runTime.processorCase(false));
1011  const label oldNumProcs
1012  (
1013  const_cast<fileOperation&>(fileHandler()).nProcs(nDestProcs)
1014  );
1015  const bool oldParRun = UPstream::parRun(false);
1016 
1017  mesh.write();
1019 
1020  // Now we've written all. Reset caseName on master
1021  InfoOrPout<< "Restoring caseName" << endl;
1022  UPstream::parRun(oldParRun);
1023  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
1024  runTime.caseName() = proc0CaseName;
1025  runTime.processorCase(oldProcCase);
1026  }
1027 
1028  writeHandler = fileOperation::fileHandler(oldHandler);
1029  }
1030  else
1031  {
1032  auto oldHandler = fileOperation::fileHandler(writeHandler);
1033 
1034  const label oldNumProcs
1035  (
1036  const_cast<fileOperation&>(fileHandler()).nProcs(nDestProcs)
1037  );
1038  mesh.write();
1039  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
1040 
1041  writeHandler = fileOperation::fileHandler(oldHandler);
1042 
1044  }
1045  InfoOrPout
1046  << "Written redistributed mesh to "
1047  << mesh.facesInstance() << nl << endl;
1048 
1049 
1050  if (decompose)
1051  {
1052  // Decompose (1 -> N)
1053  // so {boundary,cell,face,point}ProcAddressing have meaning
1055  (
1056  mesh,
1057  distMap(),
1058  decompose,
1059  mesh.facesInstance(), //oldFacesInstance,
1060  writeHandler // to write *ProcAddressing
1061  );
1062  }
1063  else if (reconstruct)
1064  {
1065  // Reconstruct (N -> 1)
1066  // so {boundary,cell,face,point}ProcAddressing have meaning. Make sure
1067  // to write these to meshes containing the source meshes (i.e. using
1068  // the read handler)
1070  (
1071  mesh,
1072  distMap(),
1073  decompose,
1074  volMeshInstance, //oldFacesInstance,
1075  readHandler //writeHandler
1076  );
1077  }
1078  else
1079  {
1080  // Redistribute (N -> M)
1081  // {boundary,cell,face,point}ProcAddressing would be incorrect
1082  // - can either remove or redistribute previous
1084  }
1085 
1086 
1087  // Refinement data
1088  if (refDataPtr)
1089  {
1090  auto& refData = refDataPtr();
1091 
1092  // Set instance
1093  IOobject io
1094  (
1095  "dummy",
1096  mesh.facesInstance(),
1098  mesh,
1102  );
1103  refData.sync(io);
1104 
1105 
1106  // Distribute
1107  refData.distribute(distMap());
1108 
1109 
1110  auto oldHandler = fileOperation::fileHandler(writeHandler);
1111 
1112  if (reconstruct)
1113  {
1114  if (UPstream::master())
1115  {
1116  const bool oldParRun = UPstream::parRun(false);
1117  const label oldNumProcs
1118  (
1119  const_cast<fileOperation&>(fileHandler()).nProcs(nDestProcs)
1120  );
1121 
1122  InfoOrPout
1123  << "Setting caseName to " << baseRunTime.caseName()
1124  << " to write reconstructed refinement data." << endl;
1125  runTime.caseName() = baseRunTime.caseName();
1126  const bool oldProcCase(runTime.processorCase(false));
1127 
1128  refData.write();
1129 
1130  // Now we've written all. Reset caseName on master
1131  InfoOrPout<< "Restoring caseName" << endl;
1132  runTime.caseName() = proc0CaseName;
1133  runTime.processorCase(oldProcCase);
1134 
1135  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
1136  UPstream::parRun(oldParRun);
1137  }
1138  }
1139  else
1140  {
1141  const label oldNumProcs
1142  (
1143  const_cast<fileOperation&>(fileHandler()).nProcs(nDestProcs)
1144  );
1145  refData.write();
1146  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
1147  }
1148 
1149  writeHandler = fileOperation::fileHandler(oldHandler);
1150  }
1151 
1153  //{
1154  // // Read sets
1155  // if (decompose)
1156  // {
1157  // runTime.caseName() = baseRunTime.caseName();
1158  // runTime.processorCase(false);
1159  // }
1160  // IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
1161  //
1162  // PtrList<cellSet> cellSets;
1163  // ReadFields(objects, cellSets);
1164  //
1165  // if (decompose)
1166  // {
1167  // runTime.caseName() = proc0CaseName;
1168  // runTime.processorCase(oldProcCase);
1169  // }
1170  //
1171  // forAll(cellSets, i)
1172  // {
1173  // cellSets[i].distribute(distMap());
1174  // }
1175  //
1176  // if (reconstruct)
1177  // {
1178  // if (Pstream::master())
1179  // {
1180  // Pout<< "Setting caseName to " << baseRunTime.caseName()
1181  // << " to write reconstructed refinement data." << endl;
1182  // runTime.caseName() = baseRunTime.caseName();
1183  // const bool oldProcCase(runTime.processorCase(false));
1184  //
1185  // forAll(cellSets, i)
1186  // {
1187  // cellSets[i].distribute(distMap());
1188  // }
1189  //
1190  // // Now we've written all. Reset caseName on master
1191  // Pout<< "Restoring caseName" << endl;
1192  // runTime.caseName() = proc0CaseName;
1193  // runTime.processorCase(oldProcCase);
1194  // }
1195  // }
1196  // else
1197  // {
1198  // forAll(cellSets, i)
1199  // {
1200  // cellSets[i].distribute(distMap());
1201  // }
1202  // }
1203  //}
1204 
1205 
1206  return distMap;
1207 }
1208 
1209 
1210 /*---------------------------------------------------------------------------*\
1211  main
1212 \*---------------------------------------------------------------------------*/
1213 
1214 int main(int argc, char *argv[])
1215 {
1217  (
1218  "Redistribute decomposed mesh and fields according"
1219  " to the decomposeParDict settings.\n"
1220  "Optionally run in decompose/reconstruct mode"
1221  );
1222 
1223  argList::noFunctionObjects(); // Never use function objects
1224 
1225  // enable -constant ... if someone really wants it
1226  // enable -zeroTime to prevent accidentally trashing the initial fields
1227  timeSelector::addOptions(true, true);
1228 
1229  #include "addAllRegionOptions.H"
1230 
1231  #include "addOverwriteOption.H"
1232  argList::addBoolOption("decompose", "Decompose case");
1233  argList::addBoolOption("reconstruct", "Reconstruct case");
1235  (
1236  "Additional verbosity. (Can be used multiple times for debugging)"
1237  );
1239  (
1240  "Test without writing the decomposition. "
1241  "Changes -cellDist to only write volScalarField."
1242  );
1243  argList::addVerboseOption("Additional verbosity");
1245  (
1246  "cellDist",
1247  "Write cell distribution as a labelList - for use with 'manual' "
1248  "decomposition method or as a volScalarField for post-processing."
1249  );
1251  (
1252  "newTimes",
1253  "Only reconstruct new times (i.e. that do not exist already)"
1254  );
1256  (
1257  "Additional verbosity. (Can be used multiple times)"
1258  );
1260  (
1261  "no-finite-area",
1262  "Suppress finiteArea mesh/field handling",
1263  true // Advanced option
1264  );
1265 
1266 
1267  //- Disable caching of times/processor dirs etc. Cause massive parallel
1268  // problems when e.g decomposing.
1270 
1271 
1272  // Handle arguments
1273  // ~~~~~~~~~~~~~~~~
1274  // (replacement for setRootCase that does not abort)
1275 
1276  argList args(argc, argv);
1277 
1278 
1279  // As much as possible avoid synchronised operation. To be looked at more
1280  // closely for the three scenarios:
1281  // - decompose - reads on master (and from parent directory) and sends
1282  // dictionary to slaves
1283  // - distribute - reads on potentially a different number of processors
1284  // than it writes to
1285  // - reconstruct - reads parallel, write on master only and to parent
1286  // directory
1287 
1288  // Running data-distributed?
1289  // (processors cannot see all other processors' files)
1290  const bool hasDistributedFiles(fileHandler().distributed());
1291 
1292 
1293  // Set up loose processorsXXX directory matching (for collated) so e.g.
1294  // when checking for -latestTime we don't miss anything. Once we know
1295  // the time, actual number of processors etc we switch back to strict
1296  // matching.
1298 
1299  // Need this line since we don't include "setRootCase.H"
1300  #include "foamDlOpenLibs.H"
1301 
1302  const bool reconstruct = args.found("reconstruct");
1303  const bool writeCellDist = args.found("cellDist");
1304  const bool dryrun = args.dryRun();
1305  const bool newTimes = args.found("newTimes");
1306  const int optVerbose = args.verbose();
1307 
1308  const bool doFiniteArea = !args.found("no-finite-area");
1309  bool decompose = args.found("decompose");
1310  bool overwrite = args.found("overwrite");
1311 
1312  // Field restrictions...
1313  const wordRes selectedFields;
1314  const wordRes selectedLagrangianFields;
1315 
1316 
1317  if (!UPstream::parRun())
1318  {
1320  << ": This utility can only be run parallel"
1321  << exit(FatalError);
1322  }
1323 
1324  if (decompose && reconstruct)
1325  {
1327  << "Cannot specify both -decompose and -reconstruct"
1328  << exit(FatalError);
1329  }
1330 
1331  if (optVerbose)
1332  {
1333  // Report on output
1336 
1337  if (optVerbose > 1)
1338  {
1339  Info<< "Additional debugging enabled" << nl << endl;
1340  ::debug = 1;
1341  }
1342  }
1343 
1344  // Disable NaN setting and floating point error trapping. This is to avoid
1345  // any issues inside the field redistribution inside fvMeshDistribute
1346  // which temporarily moves processor faces into existing patches. These
1347  // will now not have correct values. After all bits have been assembled
1348  // the processor fields will be restored but until then there might
1349  // be uninitialised values which might upset some patch field constructors.
1350  // Workaround by disabling floating point error trapping. TBD: have
1351  // actual field redistribution instead of subsetting inside
1352  // fvMeshDistribute.
1353  Foam::sigFpe::unset(true);
1354 
1355 
1356  // File handlers (read/write)
1357  // ==========================
1358 
1359  // Read handler on processors with a volMesh
1360  refPtr<fileOperation> volMeshReadHandler;
1361 
1362  // Read handler on processors with an areaMesh
1363  refPtr<fileOperation> areaMeshReadHandler;
1364 
1365  // Handler for master-only operation (read/writing from/to undecomposed)
1366  // - only the 'real' master, not io-rank masters
1367  refPtr<fileOperation> masterOnlyHandler;
1368 
1370  {
1371  const bool oldParRun = UPstream::parRun(false);
1372 
1373  masterOnlyHandler = fileOperation::NewUncollated();
1374 
1375  UPstream::parRun(oldParRun);
1376  }
1377 
1378  if (decompose)
1379  {
1380  InfoOrPout<< "Decomposing case (like decomposePar)"
1381  << nl << endl;
1382  }
1383  else if (reconstruct)
1384  {
1385  InfoOrPout<< "Reconstructing case (like reconstructParMesh)"
1386  << nl << endl;
1387  }
1388 
1389  if (decompose || reconstruct)
1390  {
1391  // The UPstream::nProcs is either the source or destination procs
1393  InfoOrPout<< "Switching to exact matching for "
1395  << " processor directories"
1396  << nl << endl;
1397  }
1398  else
1399  {
1400  // Redistribute mode. Accept any processorsXXX naming since we don't
1401  // know yet what the source/target number of processors is
1403  InfoOrPout<< "Switching to matching any "
1404  << fileOperation::processorsBaseDir << " directory" << nl << endl;
1405  }
1406 
1407 
1408  if ((decompose || reconstruct) && !overwrite)
1409  {
1410  overwrite = true;
1411 
1412  Warning
1413  << nl << " "
1414  << "Added implicit -overwrite for decompose/reconstruct modes"
1415  << nl << endl;
1416  }
1417 
1418  if
1419  (
1420  fileHandler().ioRanks().contains(UPstream::myProcNo())
1421  && !Foam::isDir(args.rootPath())
1422  )
1423  {
1424  //FatalErrorInFunction
1426  << ": cannot open root directory " << args.rootPath()
1427  << endl;
1428  //<< exit(FatalError);
1429  }
1430 
1431 
1432  if (hasDistributedFiles)
1433  {
1434  InfoOrPout<< "Detected multiple roots i.e. non-nfs running"
1435  << nl << endl;
1436 
1437  fileHandler().mkDir(args.globalPath());
1438  }
1439 
1440 
1441  // Check if we have processor directories. Ideally would like to
1442  // use fileHandler().dirPath here but we don't have runTime yet and
1443  // want to delay constructing runTime until we've synced all time
1444  // directories...
1445  const fileName procDir(fileHandler().filePath(args.path()));
1446  if (Foam::isDir(procDir))
1447  {
1448  if (decompose)
1449  {
1450  InfoOrPout<< "Removing existing processor directory:"
1451  << args.relativePath(procDir) << endl;
1452  fileHandler().rmDir(procDir);
1453  }
1454  }
1455  else
1456  {
1457  // Directory does not exist. If this happens on master -> decompose mode
1458  if (UPstream::master() && !reconstruct && !decompose)
1459  {
1460  decompose = true;
1461  InfoOrPout
1462  << "No processor directories; switching on decompose mode"
1463  << nl << endl;
1464  }
1465  }
1466  // If master changed to decompose mode make sure all nodes know about it
1467  Pstream::broadcast(decompose);
1468  if (decompose)
1469  {
1470  // The UPstream::nProcs is either the source or destination procs
1472  InfoOrPout
1473  << "Switching to exact matching for "
1475  << " processor directories"
1476  << nl << endl;
1477  }
1478 
1479 
1480 
1481  // If running distributed we have problem of new processors not finding
1482  // a system/controlDict. However if we switch on the master-only reading
1483  // the problem becomes that the time directories are differing sizes and
1484  // e.g. latestTime will pick up a different time (which causes createTime.H
1485  // to abort). So for now make sure to have master times on all
1486  // processors
1487  if (!reconstruct)
1488  {
1489  InfoOrPout<< "Creating time directories on all processors"
1490  << nl << endl;
1491  createTimeDirs(args.path());
1492  }
1493 
1494  // Construct time
1495  // ~~~~~~~~~~~~~~
1496 
1497  // Replace #include "createTime.H" with our own version
1498  // that has MUST_READ instead of READ_MODIFIED
1499 
1500  Info<< "Create time\n" << endl;
1501  Time runTime
1502  (
1504  args,
1505  false, // no enableFunctionObjects
1506  true, // permit enableLibs
1507  IOobjectOption::MUST_READ // Without watching
1508  );
1509 
1510 
1511  refPtr<fileOperation> writeHandler;
1512 
1513 
1514  runTime.functionObjects().off(); // Extra safety?
1515  // Make sure that no runTime checking is done since fileOperation::addWatch
1516  // etc. does broadcast over world, even if constructed only on a subset
1517  // of procs
1518  runTime.runTimeModifiable(false);
1519 
1520  // Save local processor0 casename
1521  const fileName proc0CaseName = runTime.caseName();
1522  const bool oldProcCase = runTime.processorCase();
1523 
1524 
1525  // Construct undecomposed Time
1526  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1527  // This will read the same controlDict but might have a different
1528  // set of times so enforce same times
1529 
1530  if (hasDistributedFiles)
1531  {
1532  InfoOrPout<< "Creating time directories for undecomposed Time"
1533  << " on all processors" << nl << endl;
1534  createTimeDirs(args.globalPath());
1535  }
1536 
1537 
1538  InfoOrPout<< "Create undecomposed database" << nl << endl;
1539  Time baseRunTime
1540  (
1541  runTime.controlDict(),
1542  runTime.rootPath(),
1544  runTime.system(),
1545  runTime.constant(),
1546  false, // No function objects
1547  false, // No extra controlDict libs
1548  IOobjectOption::MUST_READ // Without watching
1549  );
1550  // Make sure that no runTime checking is done since fileOperation::addWatch
1551  // etc. does broadcast over world, even if constructed only on a subset
1552  // of procs
1553  baseRunTime.runTimeModifiable(false);
1554 
1555 
1556  wordHashSet masterTimeDirSet;
1557  if (newTimes)
1558  {
1559  instantList baseTimeDirs(baseRunTime.times());
1560  for (const instant& t : baseTimeDirs)
1561  {
1562  masterTimeDirSet.insert(t.name());
1563  }
1564  }
1565 
1566 
1567  // Allow override of decomposeParDict location
1568  const fileName decompDictFile =
1569  args.getOrDefault<fileName>("decomposeParDict", "");
1570 
1571  // Get region names
1572  #include "getAllRegionOptions.H"
1573 
1575  {
1576  InfoOrPout<< "Using region: " << regionNames[0] << nl << endl;
1577  }
1578 
1579 
1580  // Demand driven lagrangian mapper
1581  autoPtr<parLagrangianDistributor> lagrangianDistributorPtr;
1582 
1583  if (reconstruct)
1584  {
1585  // use the times list from the master processor
1586  // and select a subset based on the command-line options
1588  Pstream::broadcast(timeDirs);
1589 
1590  if (timeDirs.empty())
1591  {
1593  << "No times selected"
1594  << exit(FatalError);
1595  }
1596 
1597 
1598  // Pass1 : reconstruct mesh and addressing
1599  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1600 
1601 
1602  InfoOrPout
1603  << nl
1604  << "Reconstructing mesh and addressing" << nl << endl;
1605 
1606  forAll(regionNames, regioni)
1607  {
1608  const word& regionName = regionNames[regioni];
1609 
1610  const fileName volMeshSubDir
1611  (
1613  );
1614  const fileName areaMeshSubDir
1615  (
1616  // Assume single-region area mesh
1618  );
1619 
1620  InfoOrPout
1621  << nl
1622  << "Reconstructing mesh:"
1624 
1625  bool areaMeshDetected = false;
1626 
1627  // Loop over all times
1628  forAll(timeDirs, timeI)
1629  {
1630  // Set time for global database
1631  runTime.setTime(timeDirs[timeI], timeI);
1632  baseRunTime.setTime(timeDirs[timeI], timeI);
1633 
1634  InfoOrPout<< "Time = " << runTime.timeName() << endl << endl;
1635 
1636  // Where meshes are
1637  fileName volMeshInstance;
1638  fileName areaMeshInstance;
1639 
1640  volMeshInstance = runTime.findInstance
1641  (
1642  volMeshSubDir,
1643  "faces",
1645  );
1646 
1647  if (doFiniteArea)
1648  {
1649  areaMeshInstance = runTime.findInstance
1650  (
1651  areaMeshSubDir,
1652  "faceLabels",
1654  );
1655  }
1656 
1658  (
1660  volMeshInstance,
1661  areaMeshInstance
1662  );
1663 
1664 
1665  // Check processors have meshes
1666  // - check for 'faces' file (polyMesh)
1667  // - check for 'faceLabels' file (faMesh)
1668  boolList volMeshOnProc;
1669  boolList areaMeshOnProc(UPstream::nProcs(), false);
1670 
1671  volMeshOnProc = haveMeshFile
1672  (
1673  runTime,
1674  volMeshInstance/volMeshSubDir,
1675  "faces"
1676  );
1677 
1678  // Create handler for reading
1679  newHandler(volMeshOnProc, volMeshReadHandler);
1680 
1681  if (doFiniteArea)
1682  {
1683  areaMeshOnProc = haveMeshFile
1684  (
1685  runTime,
1686  areaMeshInstance/areaMeshSubDir,
1687  "faceLabels"
1688  );
1689  areaMeshDetected = areaMeshOnProc.found(true);
1690 
1691  if (areaMeshOnProc == volMeshOnProc)
1692  {
1693  if (volMeshReadHandler)
1694  {
1695  // Use same reader for faMesh as for fvMesh
1696  areaMeshReadHandler.ref(volMeshReadHandler.ref());
1697  }
1698  }
1699  else
1700  {
1701  newHandler(areaMeshOnProc, areaMeshReadHandler);
1702  }
1703  }
1704 
1705 
1706  // Addressing back to reconstructed mesh as xxxProcAddressing.
1707  // - all processors have consistent faceProcAddressing
1708  // - processors without a mesh don't need faceProcAddressing
1709 
1710 
1711  // Note: filePath searches up on processors that don't have
1712  // processor if instance = constant so explicitly check
1713  // found filename.
1714  bool haveVolAddressing = false;
1715  if (volMeshOnProc[Pstream::myProcNo()])
1716  {
1717  // Read faces (just to know their size)
1718  faceCompactIOList faces
1719  (
1720  IOobject
1721  (
1722  "faces",
1723  volMeshInstance,
1724  volMeshSubDir,
1725  runTime,
1727  )
1728  );
1729 
1730  // Check faceProcAddressing
1731  labelIOList faceProcAddressing
1732  (
1733  IOobject
1734  (
1735  "faceProcAddressing",
1736  volMeshInstance,
1737  volMeshSubDir,
1738  runTime,
1740  )
1741  );
1742 
1743  haveVolAddressing =
1744  (
1745  faceProcAddressing.headerOk()
1746  && faceProcAddressing.size() == faces.size()
1747  );
1748  }
1749  else
1750  {
1751  // Have no mesh. Don't need addressing
1752  haveVolAddressing = true;
1753  }
1754 
1755  bool haveAreaAddressing = false;
1756  if (areaMeshOnProc[Pstream::myProcNo()])
1757  {
1758  // Read faces (just to know their size)
1760  (
1761  IOobject
1762  (
1763  "faceLabels",
1764  areaMeshInstance,
1765  areaMeshSubDir,
1766  runTime,
1768  )
1769  );
1770 
1771  // Check faceProcAddressing
1772  labelIOList faceProcAddressing
1773  (
1774  IOobject
1775  (
1776  "faceProcAddressing",
1777  areaMeshInstance,
1778  areaMeshSubDir,
1779  runTime,
1781  )
1782  );
1783 
1784  haveAreaAddressing =
1785  (
1786  faceProcAddressing.headerOk()
1787  && faceProcAddressing.size() == faceLabels.size()
1788  );
1789  }
1790  else if (areaMeshDetected)
1791  {
1792  // Have no mesh. Don't need addressing
1793  haveAreaAddressing = true;
1794  }
1795 
1796 
1797  // Additionally check for master faces being readable. Could
1798  // do even more checks, e.g. global number of cells same
1799  // as cellProcAddressing
1800 
1801  bool volMeshHaveUndecomposed = false;
1802  bool areaMeshHaveUndecomposed = false;
1803 
1804  if (Pstream::master())
1805  {
1806  InfoOrPout
1807  << "Checking " << baseRunTime.caseName()
1808  << " for undecomposed volume and area meshes..."
1809  << endl;
1810 
1811  const bool oldParRun = Pstream::parRun(false);
1812  const label oldNumProcs(fileHandler().nProcs());
1813 
1814  // Volume
1815  {
1816  faceCompactIOList facesIO
1817  (
1818  IOobject
1819  (
1820  "faces",
1821  volMeshInstance,
1822  volMeshSubDir,
1823  baseRunTime,
1825  ),
1826  label(0)
1827  );
1828  volMeshHaveUndecomposed = facesIO.headerOk();
1829  }
1830 
1831  // Area
1832  if (doFiniteArea)
1833  {
1834  labelIOList labelsIO
1835  (
1836  IOobject
1837  (
1838  "faceLabels",
1839  areaMeshInstance,
1840  areaMeshSubDir,
1841  baseRunTime,
1843  )
1844  );
1845  areaMeshHaveUndecomposed = labelsIO.headerOk();
1846  }
1847 
1848  const_cast<fileOperation&>
1849  (
1850  fileHandler()
1851  ).nProcs(oldNumProcs);
1852  Pstream::parRun(oldParRun); // Restore parallel state
1853  }
1854 
1856  (
1858  volMeshHaveUndecomposed,
1859  areaMeshHaveUndecomposed
1860  );
1861 
1862  // Report
1863  {
1864  InfoOrPout
1865  << " volume mesh ["
1866  << volMeshHaveUndecomposed << "] : "
1867  << volMeshInstance << nl
1868  << " area mesh ["
1869  << areaMeshHaveUndecomposed << "] : "
1870  << areaMeshInstance << nl
1871  << endl;
1872  }
1873 
1874 
1875  if
1876  (
1877  !volMeshHaveUndecomposed
1878  || !returnReduceAnd(haveVolAddressing)
1879  )
1880  {
1881  InfoOrPout
1882  << "No undecomposed mesh. Creating from: "
1883  << volMeshInstance << endl;
1884 
1885  if (areaMeshHaveUndecomposed)
1886  {
1887  areaMeshHaveUndecomposed = false;
1888  InfoOrPout
1889  << "Also ignore any undecomposed area mesh"
1890  << endl;
1891  }
1892 
1894  (
1895  IOobject
1896  (
1897  regionName,
1898  volMeshInstance,
1899  runTime,
1901  ),
1902  volMeshReadHandler
1903  );
1904  fvMeshTools::setBasicGeometry(volMeshPtr());
1905  fvMesh& mesh = volMeshPtr();
1906 
1907 
1908  InfoOrPout<< nl << "Reconstructing mesh" << nl << endl;
1909 
1910  // Reconstruct (1 processor)
1911  const label nDestProcs(1);
1912  const labelList finalDecomp(mesh.nCells(), Zero);
1913 
1914  redistributeAndWrite
1915  (
1916  volMeshReadHandler,
1917  masterOnlyHandler, //writeHandler,
1918  baseRunTime,
1919  proc0CaseName,
1920 
1921  // Controls
1922  false, // do not read fields
1923  false, // do not read undecomposed case on proc0
1924  true, // write redistributed files to proc0
1925  overwrite,
1926 
1927  // Decomposition information
1928  nDestProcs,
1929  finalDecomp,
1930 
1931  // For finite-volume
1932  volMeshOnProc,
1933  volMeshInstance,
1934  mesh
1935  );
1936  }
1937 
1938 
1939  // Similarly for finiteArea
1940  // - may or may not have undecomposed mesh
1941  // - may or may not have decomposed meshes
1942 
1943  if
1944  (
1945  areaMeshOnProc.found(true) // ie, areaMeshDetected
1946  &&
1947  (
1948  !areaMeshHaveUndecomposed
1949  || !returnReduceAnd(haveAreaAddressing)
1950  )
1951  )
1952  {
1953  InfoOrPout
1954  << "Loading area mesh from "
1955  << areaMeshInstance << endl;
1956 
1957  InfoOrPout<< " getting volume mesh support" << endl;
1958 
1960  (
1961  IOobject
1962  (
1963  regionName,
1964  baseRunTime.timeName(),
1965  baseRunTime,
1967  ),
1968  true // read on master only
1969  );
1970  fvMeshTools::setBasicGeometry(baseMeshPtr());
1971 
1973  (
1974  IOobject
1975  (
1976  regionName,
1977  baseMeshPtr().facesInstance(),
1978  runTime,
1980  ),
1981  volMeshReadHandler
1982  );
1983  fvMesh& mesh = volMeshPtr();
1984 
1985  // Read volume proc addressing back to base mesh
1987  (
1989  );
1990 
1991 
1992  //autoPtr<faMesh> areaMeshPtr =
1993  // faMeshTools::loadOrCreateMesh
1994  //(
1995  // IOobject
1996  // (
1997  // regionName,
1998  // areaMeshInstance,
1999  // runTime,
2000  // IOobjectOption::MUST_READ
2001  // ),
2002  // mesh, // <- The referenced polyMesh (from above)
2003  // decompose
2004  //);
2006  (
2007  IOobject
2008  (
2009  regionName,
2010  areaMeshInstance,
2011  runTime,
2013  ),
2014  mesh, // <- The referenced polyMesh (from above)
2015  areaMeshReadHandler
2016  );
2017  faMesh& areaMesh = areaMeshPtr();
2018 
2021 
2022  autoPtr<faMesh> areaBaseMeshPtr;
2023 
2024  // Reconstruct using polyMesh distribute map
2025  mapDistributePolyMesh faDistMap
2026  (
2028  (
2029  areaMesh,
2030  distMap(), // The polyMesh distMap
2031  baseMeshPtr(), // Target polyMesh
2032  areaBaseMeshPtr
2033  )
2034  );
2035 
2036  faMeshTools::forceDemandDriven(areaBaseMeshPtr());
2037  faMeshTools::unregisterMesh(areaBaseMeshPtr());
2038 
2039 
2040  if (Pstream::master())
2041  {
2042  InfoOrPout
2043  << "Setting caseName to " << baseRunTime.caseName()
2044  << " to write reconstructed area mesh." << endl;
2045  runTime.caseName() = baseRunTime.caseName();
2046  const bool oldProcCase(runTime.processorCase(false));
2047  const bool oldParRun(Pstream::parRun(false));
2048  const label oldNumProcs(fileHandler().nProcs());
2049 
2050  areaBaseMeshPtr().write();
2051 
2052  // Now we've written all. Reset caseName on master
2053  InfoOrPout<< "Restoring caseName" << endl;
2054  const_cast<fileOperation&>
2055  (
2056  fileHandler()
2057  ).nProcs(oldNumProcs);
2058  Pstream::parRun(oldParRun);
2059  runTime.caseName() = proc0CaseName;
2060  runTime.processorCase(oldProcCase);
2061  }
2062 
2063  // Update for the reconstructed procAddressing
2065  (
2066  areaBaseMeshPtr(), // Reconstruct location
2067  faDistMap,
2068  false, // decompose=false
2069  writeHandler, //writeHandler,
2070  areaMeshPtr.get() // procMesh
2071  );
2072  }
2073  }
2074 
2075  // Make sure all is finished writing until re-reading in pass2
2076  // below
2077  fileHandler().flush();
2078 
2079 
2080  // Pass2 : read mesh and addressing and reconstruct fields
2081  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2082 
2083  InfoOrPout
2084  << nl
2085  << "Reconstructing fields" << nl << endl;
2086 
2087  runTime.setTime(timeDirs[0], 0);
2088  baseRunTime.setTime(timeDirs[0], 0);
2089  InfoOrPout<< "Time = " << runTime.timeName() << endl << endl;
2090 
2091 
2092  // Read undecomposed mesh on master and 'empty' mesh
2093  // (zero faces, point, cells but valid patches and zones) on slaves.
2094  // This is a bit of tricky code and hidden inside fvMeshTools for
2095  // now.
2096  InfoOrPout<< "Reading undecomposed mesh (on master)" << endl;
2097  //autoPtr<fvMesh> baseMeshPtr = fvMeshTools::newMesh
2098  //(
2099  // IOobject
2100  // (
2101  // regionName,
2102  // baseRunTime.timeName(),
2103  // baseRunTime,
2104  // IOobjectOption::MUST_READ
2105  // ),
2106  // true // read on master only
2107  //);
2108  fileName facesInstance;
2109  fileName pointsInstance;
2111  (
2112  IOobject
2113  (
2114  regionName,
2115  baseRunTime.timeName(),
2116  baseRunTime,
2118  ),
2119  facesInstance,
2120  pointsInstance
2121  );
2122 
2124  (
2125  IOobject
2126  (
2127  regionName,
2128  facesInstance, //baseRunTime.timeName(),
2129  baseRunTime,
2131  ),
2132  masterOnlyHandler // read on master only
2133  );
2134 
2135  if (::debug)
2136  {
2137  Pout<< "Undecomposed mesh :"
2138  << " instance:" << baseMeshPtr().facesInstance()
2139  << " nCells:" << baseMeshPtr().nCells()
2140  << " nFaces:" << baseMeshPtr().nFaces()
2141  << " nPoints:" << baseMeshPtr().nPoints()
2142  << endl;
2143  }
2144 
2145  InfoOrPout<< "Reading local, decomposed mesh" << endl;
2147  (
2148  IOobject
2149  (
2150  regionName,
2151  baseMeshPtr().facesInstance(),
2152  runTime,
2154  ),
2155  volMeshReadHandler // read on fvMesh processors
2156  );
2157  fvMesh& mesh = volMeshPtr();
2158 
2159 
2160  // Similarly for finiteArea
2161  autoPtr<faMesh> areaBaseMeshPtr;
2162  autoPtr<faMesh> areaMeshPtr;
2163  autoPtr<faMeshDistributor> faDistributor;
2164  mapDistributePolyMesh areaDistMap;
2165 
2166  if (areaMeshDetected)
2167  {
2168  //areaBaseMeshPtr = faMeshTools::newMesh
2169  //(
2170  // IOobject
2171  // (
2172  // regionName,
2173  // baseRunTime.timeName(),
2174  // baseRunTime,
2175  // IOobjectOption::MUST_READ
2176  // ),
2177  // baseMeshPtr(),
2178  // true // read on master only
2179  //);
2180  areaBaseMeshPtr = faMeshTools::loadOrCreateMesh
2181  (
2182  IOobject
2183  (
2184  regionName,
2185  baseMeshPtr().facesInstance(),
2186  baseRunTime,
2188  ),
2189  baseMeshPtr(),
2190  masterOnlyHandler
2191  );
2192 
2193  //areaMeshPtr = faMeshTools::loadOrCreateMesh
2194  //(
2195  // IOobject
2196  // (
2197  // regionName,
2198  // areaBaseMeshPtr().facesInstance(),
2199  // runTime,
2200  // IOobjectOption::MUST_READ
2201  // ),
2202  // mesh,
2203  // decompose
2204  //);
2205  areaMeshPtr = faMeshTools::loadOrCreateMesh
2206  (
2207  IOobject
2208  (
2209  regionName,
2210  areaBaseMeshPtr().facesInstance(),
2211  runTime,
2213  ),
2214  mesh,
2215  areaMeshReadHandler
2216  );
2217 
2218  areaDistMap =
2220  (
2221  areaMeshPtr(),
2222  areaBaseMeshPtr
2223  );
2224 
2225  faMeshTools::forceDemandDriven(areaMeshPtr());
2226 
2227  // Create an appropriate field distributor
2228  faDistributor.reset
2229  (
2230  new faMeshDistributor
2231  (
2232  areaMeshPtr(), // source
2233  areaBaseMeshPtr(), // target
2234  areaDistMap,
2235  masterOnlyHandler // only write on master
2236  )
2237  );
2238  // Report some messages. Tbd.
2240  }
2241 
2242 
2243  // Read addressing back to base mesh
2245  distMap = fvMeshTools::readProcAddressing(mesh, baseMeshPtr);
2246 
2247  // Construct field mapper
2248  auto fvDistributorPtr =
2250  (
2251  mesh, // source
2252  baseMeshPtr(), // target
2253  distMap(),
2254  masterOnlyHandler // Write on master only
2255  );
2256 
2257  // Construct point field mapper
2258  const auto& basePointMesh = pointMesh::New(baseMeshPtr());
2259  const auto& procPointMesh = pointMesh::New(mesh);
2260 
2261  auto pointFieldDistributorPtr =
2263  (
2264  procPointMesh, // source
2265  basePointMesh, // target
2266  distMap(),
2267  false, // delay
2268  //UPstream::master() // Write reconstructed on master
2269  masterOnlyHandler // Write on master only
2270  );
2271 
2272 
2273  // Since we start from Times[0] and not runTime.timeName() we
2274  // might overlook point motion in the first timestep
2275  // (since mesh.readUpdate() below will not be triggered). Instead
2276  // detect points by hand
2278  {
2279  InfoOrPout
2280  << " Detected initial mesh motion;"
2281  << " reconstructing points" << nl
2282  << endl;
2283  fvDistributorPtr().reconstructPoints();
2284  }
2285 
2286 
2287  // Loop over all times
2288  forAll(timeDirs, timeI)
2289  {
2290  if (newTimes && masterTimeDirSet.found(timeDirs[timeI].name()))
2291  {
2292  InfoOrPout
2293  << "Skipping time " << timeDirs[timeI].name()
2294  << nl << endl;
2295  continue;
2296  }
2297 
2298  // Set time for global database
2299  runTime.setTime(timeDirs[timeI], timeI);
2300  baseRunTime.setTime(timeDirs[timeI], timeI);
2301 
2302  InfoOrPout<< "Time = " << runTime.timeName() << endl << endl;
2303 
2304 
2305  // Check if any new meshes need to be read.
2307 
2308  if (procStat == polyMesh::POINTS_MOVED)
2309  {
2310  InfoOrPout
2311  << " Detected mesh motion; reconstructing points"
2312  << nl << endl;
2313  fvDistributorPtr().reconstructPoints();
2314  }
2315  else if
2316  (
2317  procStat == polyMesh::TOPO_CHANGE
2318  || procStat == polyMesh::TOPO_PATCH_CHANGE
2319  )
2320  {
2321  InfoOrPout
2322  << " Detected topology change;"
2323  << " reconstructing addressing" << nl << endl;
2324 
2325  if (baseMeshPtr)
2326  {
2327  // Cannot do a baseMesh::readUpdate() since not all
2328  // processors will have mesh files. So instead just
2329  // recreate baseMesh
2330  baseMeshPtr.clear();
2331  //baseMeshPtr = fvMeshTools::newMesh
2332  //(
2333  // IOobject
2334  // (
2335  // regionName,
2336  // baseRunTime.timeName(),
2337  // baseRunTime,
2338  // IOobjectOption::MUST_READ
2339  // ),
2340  // true // read on master only
2341  //);
2342  baseMeshPtr = fvMeshTools::loadOrCreateMesh
2343  (
2344  IOobject
2345  (
2346  regionName,
2347  baseRunTime.timeName(),
2348  baseRunTime,
2350  ),
2351  masterOnlyHandler // read on master only
2352  );
2353  if (::debug)
2354  {
2355  Pout<< "Undecomposed mesh :"
2356  << " nCells:" << baseMeshPtr().nCells()
2357  << " nFaces:" << baseMeshPtr().nFaces()
2358  << " nPoints:" << baseMeshPtr().nPoints()
2359  << endl;
2360  }
2361  }
2362 
2363  // Re-read procAddressing
2364  distMap =
2365  fvMeshTools::readProcAddressing(mesh, baseMeshPtr);
2366 
2367  // Reset field mappers
2368 
2369  fvDistributorPtr.reset
2370  (
2372  (
2373  mesh, // source
2374  baseMeshPtr(), // target
2375  distMap(),
2376  masterOnlyHandler // Write on master only
2377  )
2378  );
2379 
2380  // Construct point field mapper
2381  const auto& basePointMesh = pointMesh::New(baseMeshPtr());
2382  const auto& procPointMesh = pointMesh::New(mesh);
2383 
2384  pointFieldDistributorPtr.reset
2385  (
2387  (
2388  procPointMesh, // source
2389  basePointMesh, // target
2390  distMap(),
2391  false, // delay until later
2392  masterOnlyHandler // Write on master only
2393  )
2394  );
2395 
2396  lagrangianDistributorPtr.reset();
2397 
2398  if (areaMeshPtr)
2399  {
2400  InfoOrPout
2401  << " Discarding finite-area addressing"
2402  << " (TODO)" << nl << endl;
2403 
2404  areaBaseMeshPtr.reset();
2405  areaMeshPtr.reset();
2406  faDistributor.reset();
2407  areaDistMap.clear();
2408  }
2409  }
2410 
2411 
2412  // Get list of objects
2413  IOobjectList objects(mesh, runTime.timeName());
2414 
2415  // Mesh fields (vol, surface, volInternal)
2416  fvDistributorPtr()
2417  .distributeAllFields(objects, selectedFields);
2418 
2419  // pointfields
2420  // - distribute and write (verbose)
2421  pointFieldDistributorPtr()
2422  .distributeAllFields(objects, selectedFields);
2423 
2424 
2425  // Clouds (note: might not be present on all processors)
2427  (
2428  lagrangianDistributorPtr,
2429  baseMeshPtr(),
2430  mesh,
2431  distMap(),
2432  selectedLagrangianFields
2433  //masterOnlyHandler
2434  );
2435 
2436  if (faDistributor)
2437  {
2438  faDistributor()
2439  .distributeAllFields(objects, selectedFields);
2440  }
2441 
2442 
2443  // If there are any "uniform" directories copy them from
2444  // the master processor
2445 
2446  copyUniform
2447  (
2448  volMeshReadHandler, //masterOnlyHandler, // readHandler
2449  masterOnlyHandler, // writeHandler
2450 
2451  true, // reconstruct
2452  false, // decompose
2453 
2454  mesh.time().timeName(),
2455  word::null, // optional caseName for reading
2456  mesh,
2457  baseMeshPtr()
2458  );
2459  // Non-region specific. Note: should do outside region loop
2460  // but would then have to replicate the whole time loop ...
2461  copyUniform
2462  (
2463  volMeshReadHandler, //masterOnlyHandler, // readHandler,
2464  masterOnlyHandler, // writeHandler
2465 
2466  true, // reconstruct
2467  false, // decompose
2468 
2469  mesh.time().timeName(),
2470  word::null, // optional caseName for reading
2471  mesh.time(), // runTime
2472  baseMeshPtr().time() // baseRunTime
2473  );
2474  }
2475  }
2476  }
2477  else
2478  {
2479  // decompose or redistribution mode.
2480  // decompose : master : read from parent dir
2481  // slave : dummy mesh
2482  // redistribute : all read mesh or dummy mesh
2483 
2484  Time& readRunTime =
2485  (
2486  (decompose)
2487  ? baseRunTime
2488  : runTime
2489  );
2490 
2491  // Time coming from processor0 (or undecomposed if no processor0)
2492  scalar masterTime = timeSelector::selectIfPresent
2493  (
2494  readRunTime,
2495  args
2496  )[0].value();
2497  Pstream::broadcast(masterTime);
2498  InfoOrPout
2499  << "Setting time to that of master or undecomposed case : "
2500  << masterTime << endl;
2501  runTime.setTime(masterTime, 0);
2502  baseRunTime.setTime(masterTime, 0);
2503 
2504 
2505 
2506 
2507  // Save old time name (since might be incremented)
2508  const word oldTimeName(runTime.timeName());
2509 
2510  forAll(regionNames, regioni)
2511  {
2512  const word& regionName = regionNames[regioni];
2513 
2514  const fileName volMeshSubDir
2515  (
2517  );
2518  const fileName areaMeshSubDir
2519  (
2520  // Assume single-region area mesh
2522  );
2523 
2524  InfoOrPout
2525  << nl << nl
2526  << (decompose ? "Decomposing" : "Redistributing")
2527  << " mesh:" << polyMesh::regionName(regionName) << nl << endl;
2528 
2529 
2530  // Get time instance directory
2531  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
2532  // At this point we should be able to read at least a mesh on
2533  // processor0. Note the changing of the processor0 casename to
2534  // enforce it to read/write from the undecomposed case
2535 
2536  fileName volMeshMasterInstance;
2537  fileName areaMeshMasterInstance;
2538 
2539  // Assume to be true
2540  bool volMeshHaveUndecomposed = true;
2541  bool areaMeshHaveUndecomposed = doFiniteArea;
2542 
2543  if (Pstream::master())
2544  {
2545  if (decompose)
2546  {
2547  InfoOrPout
2548  << "Checking undecomposed mesh in case: "
2549  << baseRunTime.caseName() << endl;
2550  runTime.caseName() = baseRunTime.caseName();
2551  runTime.processorCase(false);
2552  }
2553 
2554  const bool oldParRun = Pstream::parRun(false);
2555  const label oldNumProcs(fileHandler().nProcs());
2556  volMeshMasterInstance = readRunTime.findInstance
2557  (
2558  volMeshSubDir,
2559  "faces",
2561  );
2562 
2563  if (doFiniteArea)
2564  {
2565  areaMeshMasterInstance = readRunTime.findInstance
2566  (
2567  areaMeshSubDir,
2568  "faceLabels",
2570  );
2571 
2572  // Note: findInstance returns "constant" even if not found,
2573  // so recheck now for a false positive.
2574 
2575  if ("constant" == areaMeshMasterInstance)
2576  {
2577  const boolList areaMeshOnProc
2578  (
2579  haveMeshFile
2580  (
2581  readRunTime,
2582  areaMeshMasterInstance/areaMeshSubDir,
2583  "faceLabels",
2584  false // verbose=false
2585  )
2586  );
2587 
2588  if (areaMeshOnProc.empty() || !areaMeshOnProc[0])
2589  {
2590  areaMeshHaveUndecomposed = false;
2591  }
2592  }
2593  }
2594 
2595  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
2596  Pstream::parRun(oldParRun); // Restore parallel state
2597 
2598  if (decompose)
2599  {
2600  InfoOrPout
2601  << " volume mesh ["
2602  << volMeshHaveUndecomposed << "] : "
2603  << volMeshMasterInstance << nl
2604  << " area mesh ["
2605  << areaMeshHaveUndecomposed << "] : "
2606  << areaMeshMasterInstance << nl
2607  << nl << nl;
2608 
2609  // Restoring caseName
2610  InfoOrPout<< "Restoring caseName" << endl;
2611  runTime.caseName() = proc0CaseName;
2612  runTime.processorCase(oldProcCase);
2613  }
2614  }
2615 
2617  (
2619  volMeshHaveUndecomposed,
2620  areaMeshHaveUndecomposed,
2621  volMeshMasterInstance,
2622  areaMeshMasterInstance
2623  );
2624 
2625  // Check processors have meshes
2626  // - check for 'faces' file (polyMesh)
2627  // - check for 'faceLabels' file (faMesh)
2628  boolList volMeshOnProc;
2629  boolList areaMeshOnProc;
2630 
2631  if (decompose)
2632  {
2633  // Already determined above that master can read 'faces' file.
2634  // This avoids doing all the casename setting/restoring again.
2635  volMeshOnProc.setSize(UPstream::nProcs(), false);
2636  volMeshOnProc[UPstream::masterNo()] = volMeshHaveUndecomposed;
2637  }
2638  else
2639  {
2640  // All check if can read 'faces' file
2641  volMeshOnProc = haveMeshFile
2642  (
2643  runTime,
2644  volMeshMasterInstance/volMeshSubDir,
2645  "faces"
2646  );
2647  }
2648 
2649  // Create handler for reading
2650  newHandler(volMeshOnProc, volMeshReadHandler);
2651 
2652 
2653  // Now we've determined which processors are reading switch back
2654  // to exact matching of 'processorsXXX' directory names.
2655  // - this determines the processorsXXX fileNames
2656  // - the XXX comes from the number of read processors
2657  // - also adapt the masterOnlyReader (used in copyUniform)
2658 
2660  (
2661  findIndices(volMeshOnProc, true).size()
2662  );
2663 
2664 
2665  if (doFiniteArea)
2666  {
2667  if (decompose)
2668  {
2669  // Already determined above that master can read
2670  // 'faceLabels' file.
2671  areaMeshOnProc.setSize(UPstream::nProcs(), false);
2672  areaMeshOnProc[UPstream::masterNo()] =
2673  areaMeshHaveUndecomposed;
2674  }
2675  else
2676  {
2677  areaMeshOnProc = haveMeshFile
2678  (
2679  runTime,
2680  areaMeshMasterInstance/areaMeshSubDir,
2681  "faceLabels"
2682  );
2683  }
2684 
2685  // Create handler for reading
2686  if (areaMeshOnProc == volMeshOnProc)
2687  {
2688  if (volMeshReadHandler)
2689  {
2690  // Use same reader for faMesh as for fvMesh
2691  areaMeshReadHandler.ref(volMeshReadHandler.ref());
2692  }
2693  }
2694  else
2695  {
2696  newHandler(areaMeshOnProc, areaMeshReadHandler);
2697  }
2698  }
2699 
2700 
2701  // Prior to loadOrCreateMesh, note which meshes already exist
2702  // for the current file handler.
2703  // - where mesh would be written if it didn't exist already.
2704  fileNameList volMeshDir(Pstream::nProcs());
2705  {
2706  volMeshDir[Pstream::myProcNo()] =
2707  (
2708  fileHandler().objectPath
2709  (
2710  IOobject
2711  (
2712  "faces",
2713  volMeshMasterInstance/volMeshSubDir,
2714  runTime
2715  ),
2716  word::null
2717  ).path()
2718  );
2719 
2720  Pstream::allGatherList(volMeshDir);
2721 
2722  if (optVerbose && Pstream::master())
2723  {
2724  Info<< "Per processor faces dirs:" << nl
2725  << '(' << nl;
2726 
2727  for (const int proci : Pstream::allProcs())
2728  {
2729  Info<< " "
2730  << runTime.relativePath(volMeshDir[proci]);
2731 
2732  if (!volMeshOnProc[proci])
2733  {
2734  Info<< " [missing]";
2735  }
2736  Info<< nl;
2737  }
2738  Info<< ')' << nl << endl;
2739  }
2740  }
2741 
2742  fileNameList areaMeshDir(Pstream::nProcs());
2743  if (doFiniteArea)
2744  {
2745  areaMeshDir[Pstream::myProcNo()] =
2746  (
2747  fileHandler().objectPath
2748  (
2749  IOobject
2750  (
2751  "faceLabels",
2752  areaMeshMasterInstance/areaMeshSubDir,
2753  runTime
2754  ),
2755  word::null
2756  ).path()
2757  );
2758 
2759  Pstream::allGatherList(areaMeshDir);
2760 
2761  if (optVerbose && Pstream::master())
2762  {
2763  Info<< "Per processor faceLabels dirs:" << nl
2764  << '(' << nl;
2765 
2766  for (const int proci : Pstream::allProcs())
2767  {
2768  Info<< " "
2769  << runTime.relativePath(areaMeshDir[proci]);
2770 
2771  if (!areaMeshOnProc[proci])
2772  {
2773  Info<< " [missing]";
2774  }
2775  Info<< nl;
2776  }
2777  Info<< ')' << nl << endl;
2778  }
2779  }
2780 
2781 
2782  // Load mesh (or create dummy one)
2783  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2784 
2785  if (decompose)
2786  {
2787  InfoOrPout
2788  << "Setting caseName to " << baseRunTime.caseName()
2789  << " to read undecomposed mesh" << endl;
2790  runTime.caseName() = baseRunTime.caseName();
2791  runTime.processorCase(false);
2792  }
2793 
2795  (
2796  IOobject
2797  (
2798  regionName,
2799  volMeshMasterInstance,
2800  runTime,
2802  ),
2803  volMeshReadHandler
2804  );
2805  fvMesh& mesh = volMeshPtr();
2806 
2807 
2808  // Area mesh
2809 
2810  autoPtr<faMesh> areaMeshPtr;
2811 
2812  // Decomposing: must have an undecomposed mesh
2813  // Redistributing: have any proc mesh
2814  if
2815  (
2816  doFiniteArea
2817  &&
2818  (
2819  decompose
2820  ? areaMeshHaveUndecomposed
2821  : areaMeshOnProc.found(true)
2822  )
2823  )
2824  {
2825  areaMeshPtr = faMeshTools::loadOrCreateMesh
2826  (
2827  IOobject
2828  (
2829  regionName,
2830  areaMeshMasterInstance,
2831  runTime,
2833  ),
2834  mesh, // <- The referenced polyMesh (from above)
2835  areaMeshReadHandler
2836  );
2837 
2838  faMeshTools::forceDemandDriven(*areaMeshPtr);
2839  faMeshTools::unregisterMesh(*areaMeshPtr);
2840  }
2841 
2842 
2843  if (decompose)
2844  {
2845  InfoOrPout<< "Restoring caseName" << endl;
2846  runTime.caseName() = proc0CaseName;
2847  runTime.processorCase(oldProcCase);
2848  }
2849 
2850  const label nOldCells = mesh.nCells();
2851 
2852 
2853  // Determine decomposition
2854  // ~~~~~~~~~~~~~~~~~~~~~~~
2855 
2856  label nDestProcs;
2857  labelList finalDecomp;
2858  determineDecomposition
2859  (
2860  volMeshReadHandler, // how to read decomposeParDict
2861  baseRunTime,
2862  decompDictFile,
2863  decompose,
2864  proc0CaseName,
2865  mesh,
2866  writeCellDist,
2867 
2868  nDestProcs,
2869  finalDecomp
2870  );
2871 
2872  if (dryrun)
2873  {
2874  continue;
2875  }
2876 
2877  if (!writeHandler && nDestProcs < fileHandler().nProcs())
2878  {
2879  boolList isWriteProc(UPstream::nProcs(), false);
2880  isWriteProc.slice(0, nDestProcs) = true;
2881  InfoOrPout
2882  << " dest procs ["
2883  << isWriteProc << "]" << nl
2884  << endl;
2885  newHandler(isWriteProc, writeHandler);
2886  }
2887 
2888  // Area fields first. Read and deregister
2890  if (areaMeshPtr)
2891  {
2892  areaFields.read
2893  (
2894  baseRunTime,
2895  proc0CaseName,
2896  decompose,
2897 
2898  areaMeshOnProc,
2899  areaMeshReadHandler,
2900  areaMeshMasterInstance,
2901  (*areaMeshPtr)
2902  );
2903  }
2904 
2905 
2906  // Detect lagrangian fields
2907  if (decompose)
2908  {
2909  InfoOrPout
2910  << "Setting caseName to " << baseRunTime.caseName()
2911  << " to read lagrangian" << endl;
2912  if (UPstream::master())
2913  {
2914  // Change case name but only on the master - this will
2915  // hopefully cause the slaves to not read.
2916  runTime.caseName() = baseRunTime.caseName();
2917  }
2918  else
2919  {
2920  // Explicitly make sure that casename is not recognised as
2921  // a processor case since that has special handling for
2922  // caching processor directories etc.
2923  runTime.caseName() = "#invalid-name#";
2924  }
2925  runTime.processorCase(false);
2926  }
2927 
2928  // Read lagrangian fields and store on cloud (objectRegistry)
2930  (
2932  (
2933  mesh,
2934  selectedLagrangianFields
2935  )
2936  );
2937 
2938  if (decompose)
2939  {
2940  InfoOrPout<< "Restoring caseName" << endl;
2941  runTime.caseName() = proc0CaseName;
2942  runTime.processorCase(oldProcCase);
2943  }
2944 
2945 
2946  // Load fields, do all distribution (mesh and fields)
2947  // - but not lagrangian fields; these are done later
2948  autoPtr<mapDistributePolyMesh> distMap = redistributeAndWrite
2949  (
2950  volMeshReadHandler, // readHandler
2951  writeHandler, // writeHandler,
2952  baseRunTime,
2953  proc0CaseName,
2954 
2955  // Controls
2956  true, // read fields
2957  decompose, // decompose, i.e. read from undecomposed case
2958  false, // no reconstruction
2959  overwrite,
2960 
2961  // Decomposition information
2962  nDestProcs,
2963  finalDecomp,
2964 
2965  // For finite volume
2966  volMeshOnProc,
2967  volMeshMasterInstance,
2968  mesh
2969  );
2970 
2971  // Redistribute any clouds
2973  (
2974  lagrangianDistributorPtr,
2975  mesh,
2976  nOldCells,
2977  distMap(),
2978  clouds
2979  );
2980 
2981 
2982  // Redistribute area fields
2983 
2984  mapDistributePolyMesh faDistMap;
2985  autoPtr<faMesh> areaProcMeshPtr;
2986 
2987  if (areaMeshPtr)
2988  {
2989  faDistMap = faMeshDistributor::distribute
2990  (
2991  areaMeshPtr(),
2992  distMap(),
2993  areaProcMeshPtr
2994  );
2995 
2996  // Force recreation of everything that might vaguely
2997  // be used by patches:
2998 
2999  faMeshTools::forceDemandDriven(areaProcMeshPtr());
3000 
3001 
3002  if (reconstruct)
3003  {
3004  if (Pstream::master())
3005  {
3006  InfoOrPout
3007  << "Setting caseName to " << baseRunTime.caseName()
3008  << " to write reconstructed mesh (and fields)."
3009  << endl;
3010  runTime.caseName() = baseRunTime.caseName();
3011  const bool oldProcCase(runTime.processorCase(false));
3012  const bool oldParRun = UPstream::parRun(false);
3013  const label oldNumProcs(fileHandler().nProcs());
3014 
3015  areaProcMeshPtr->write();
3016 
3017  // Now we've written all. Reset caseName on master
3018  InfoOrPout<< "Restoring caseName" << endl;
3019  const_cast<fileOperation&>
3020  (
3021  fileHandler()
3022  ).nProcs(oldNumProcs);
3023  UPstream::parRun(oldParRun);
3024  runTime.caseName() = proc0CaseName;
3025  runTime.processorCase(oldProcCase);
3026  }
3027  }
3028  else
3029  {
3030  auto oldHandler = fileOperation::fileHandler(writeHandler);
3031 
3033  (
3034  IOobject
3035  (
3036  "procAddressing",
3037  areaProcMeshPtr->facesInstance(),
3039  areaProcMeshPtr->thisDb(),
3043  ),
3044  faDistMap
3045  ).write();
3046 
3047  areaProcMeshPtr->write();
3048 
3049  writeHandler = fileOperation::fileHandler(oldHandler);
3050 
3051  if (decompose)
3052  {
3054  (
3055  areaProcMeshPtr(),
3056  faDistMap,
3057  decompose,
3058  writeHandler
3059  );
3060  }
3061  }
3062 
3063  InfoOrPout
3064  << "Written redistributed mesh to "
3065  << areaProcMeshPtr->facesInstance() << nl << endl;
3066 
3067  faMeshDistributor distributor
3068  (
3069  areaMeshPtr(), // source
3070  areaProcMeshPtr(), // target
3071  faDistMap,
3072  writeHandler
3073  );
3074 
3075  areaFields.redistributeAndWrite(distributor, true);
3076  }
3077 
3078 
3079  // Get reference to standard write handler
3080  refPtr<fileOperation> defaultHandler;
3081  if (writeHandler)
3082  {
3083  defaultHandler.ref(writeHandler.ref());
3084  }
3085  else
3086  {
3087  defaultHandler.ref(const_cast<fileOperation&>(fileHandler()));
3088  }
3089 
3090 
3091  copyUniform
3092  (
3093  volMeshReadHandler, // read handler
3094  defaultHandler, //TBD: should be all IOranks
3095 
3096  reconstruct, // reconstruct
3097  decompose, // decompose
3098 
3099  oldTimeName,
3100  (decompose ? baseRunTime.caseName() : proc0CaseName),
3101  mesh, // read location is mesh (but oldTimeName)
3102  mesh // write location is mesh
3103  );
3104  }
3105 
3106 
3107  // Get reference to standard write handler
3108  refPtr<fileOperation> defaultHandler;
3109  if (writeHandler)
3110  {
3111  defaultHandler.ref(writeHandler.ref());
3112  }
3113  else
3114  {
3115  defaultHandler.ref(const_cast<fileOperation&>(fileHandler()));
3116  }
3117 
3118  copyUniform
3119  (
3120  volMeshReadHandler, // read handler
3121  defaultHandler, //TBD: should be all IOranks
3122 
3123  reconstruct, // reconstruct (=false)
3124  decompose, // decompose
3125 
3126  oldTimeName, // provided read time
3127  (decompose ? baseRunTime.caseName() : proc0CaseName),
3128  readRunTime,
3129  runTime // writing location
3130  );
3131  }
3132 
3133 
3134  InfoOrPout<< "End\n" << endl;
3135 
3136  return 0;
3137 }
3138 
3139 
3140 // ************************************************************************* //
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
Definition: fvPatchField.H:221
Foam::surfaceFields.
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:133
Holds a reference to the original mesh (the baseMesh) and optionally to a subset of that mesh (the su...
static void noFunctionObjects(bool addWithOption=false)
Remove &#39;-noFunctionObjects&#39; option and ignore any occurrences.
Definition: argList.C:547
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
boolList haveMeshFile(const Time &runTime, const fileName &meshPath, const word &meshFile="faces", const bool verbose=true)
Check for availability of specified mesh file (default: "faces")
A class for handling file names.
Definition: fileName.H:72
readOption readOpt() const noexcept
Get the read option.
Inter-processor communication reduction functions.
virtual bool parallelAware() const =0
Is method parallel aware?
List of IOobjects with searching and retrieving facilities. Implemented as a HashTable, so the various sorted methods should be used if traversing in parallel.
Definition: IOobjectList.H:55
static int nProcsFilter() noexcept
Return collated &#39;processorsDDD&#39; filtering.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:859
void off()
Switch the function objects off.
static void writeProcAddressing(const faMesh &mesh, const mapDistributePolyMesh &faDistMap, const bool decompose, refPtr< fileOperation > &writeHandler, const faMesh *procMesh=nullptr)
Write decompose/reconstruct addressing.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
static void removeFiles(const polyMesh &)
Helper: remove all relevant files from mesh instance.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
bool found(const Key &key) const
Same as contains()
Definition: HashTable.H:1370
static void unset(bool verbose=false)
Deactivate SIGFPE handler and NaN memory initialisation.
Definition: sigFpe.C:208
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:847
static void writeProcAddressing(const fvMesh &procMesh, const mapDistributePolyMesh &map, const bool decompose, const fileName &writeHandlerInstance, refPtr< fileOperation > &writeHandler)
Write addressing if decomposing (1 to many) or reconstructing (many to 1)
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create MeshObject registered with typeName.
Definition: MeshObject.C:53
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:1188
const fileName & caseName() const noexcept
Return case name.
Definition: TimePathsI.H:78
const labelList & processorPatches() const noexcept
Return list of processor patch labels.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
int debugSwitch(const char *name, const int deflt=0)
Lookup debug switch or add default value.
Definition: debug.C:222
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:675
static label nDomains(const dictionary &decompDict, const word &regionName="")
Return region-specific or top-level numberOfSubdomains entry.
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:411
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
bool found(const T &val, label pos=0) const
Same as contains()
Definition: UList.H:888
static void gatherList(const UList< commsStruct > &comms, UList< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
wordList names() const
The unsorted names of the IOobjects.
Definition: IOobjectList.C:218
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
void clear() noexcept
Same as reset(nullptr)
Definition: autoPtr.H:255
bool erase(iterator &iter)
Erase entry specified by given iterator and delete the allocated pointer.
Definition: HashPtrTable.C:109
fileName relativePath(const fileName &input, const bool caseTag=false) const
Return the input relative to the globalPath by stripping off a leading value of the globalPath...
Definition: TimePathsI.H:103
static bool Store(std::unique_ptr< faMeshesRegistry > &&ptr)
Transfer ownership of meshObject to registry.
Definition: MeshObject.C:196
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:374
const fileName & rootPath() const noexcept
Return the rootPath.
Definition: TimePathsI.H:66
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
labelList findIndices(const ListType &input, typename ListType::const_reference val, label start=0)
Linear search to find all occurrences of given element.
wordList regionNames
void clear()
Reset to zero size, only retaining communicator(s)
Ignore writing from objectRegistry::writeObject()
Reading, reconstruct, redistribution of lagrangian fields.
const dimensionSet dimless
Dimensionless.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1086
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:300
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 Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:421
A IOmapDistributePolyMesh wrapper for using referenced external data.
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:232
labelList faceLabels(nFaceLabels)
Distributor/redistributor for point fields, uses a two (or three) stage construction.
static word processorsBaseDir
Return the processors directory name (usually "processors")
decompositionMethod & decomposer() const
Return demand-driven decomposition method.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
A class for managing references or pointers (no reference counting)
Definition: HashPtrTable.H:49
instantList select(const instantList &times) const
Select a list of Time values that are within the ranges.
Definition: timeSelector.C:88
bool processorCase() const noexcept
True if this is a processor case.
Definition: TimePathsI.H:52
An encapsulation of filesystem-related operations.
static mapDistributePolyMesh readProcAddressing(const faMesh &mesh, const autoPtr< faMesh > &baseMeshPtr)
Read decompose/reconstruct addressing.
UPtrList< Type > sorted()
Return sorted list of objects with a class satisfying isA<Type> or isType<Type> (with Strict) ...
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:104
virtual const objectRegistry & thisDb() const
Return the object registry - resolve conflict polyMesh/lduMesh.
Definition: fvMesh.H:376
Neighbour processor patch.
virtual const objectRegistry & thisDb() const
Reference to the mesh database.
Definition: faMesh.H:1203
Mesh representing a set of points created from polyMesh.
Definition: pointMesh.H:45
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1077
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
static void removeFiles(const polyMesh &)
Helper: remove all sets files from mesh instance.
Definition: topoSet.C:693
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:853
void setSize(const label n)
Alias for resize()
Definition: List.H:320
static int verbose_
Output verbosity when writing.
dynamicFvMesh & mesh
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
virtual readUpdateState readUpdate()
Update the mesh based on the mesh files saved in time.
Definition: fvMesh.C:715
void masterMeshInstance(const IOobject &io, fileName &facesInstance, fileName &pointsInstance)
Determine master faces instance.
word findInstance(const fileName &directory, const word &name=word::null, IOobjectOption::readOption rOpt=IOobjectOption::MUST_READ, const word &stopInstance=word::null, const bool constant_fallback=true) const
Return time instance (location) of directory containing the file name (eg, used in reading mesh data)...
Definition: Time.C:725
Finite volume reconstructor for volume and surface fields.
void redistributeLagrangian(autoPtr< parLagrangianDistributor > &distributorPtr, const fvMesh &mesh, const label nOldCells, const mapDistributePolyMesh &distMap, PtrList< unmappedPassivePositionParticleCloud > &clouds)
const functionObjectList & functionObjects() const noexcept
Return the list of function objects.
Definition: Time.H:714
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
A class for handling words, derived from Foam::string.
Definition: word.H:63
static void addDryRunOption(const string &usage, bool advanced=false)
Enable a &#39;dry-run&#39; bool option, with usage information.
Definition: argList.C:504
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir)
Definition: faMesh.C:1016
const Time & time() const noexcept
Return time registry.
int dryRun() const noexcept
Return the dry-run flag.
Definition: argListI.H:109
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:406
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1071
const word & system() const noexcept
Return system name.
Definition: TimePathsI.H:118
static int verbose_
Output verbosity when writing.
Reading is optional [identical to LAZY_READ].
Simple container to manage read/write, redistribute finiteArea fields.
const fileName & globalCaseName() const noexcept
Return global case name.
Definition: TimePathsI.H:72
static autoPtr< fvMesh > newMesh(const IOobject &io, const bool masterOnlyReading, const bool verbose=false)
Read mesh or create dummy mesh (0 cells, >0 patches).
Definition: fvMeshTools.C:446
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
Miscellaneous file handling for meshes.
static const word null
An empty word.
Definition: word.H:84
A List of wordRe with additional matching capabilities.
Definition: wordRes.H:53
Finite area area (element) fields.
const globalMeshData & globalData() const
Return parallel info (demand-driven)
Definition: polyMesh.C:1311
label localSize(const label proci) const
Size of proci data.
Definition: globalIndexI.H:257
static instantList selectIfPresent(Time &runTime, const argList &args)
If any time option provided return the set of times - as per select0() - otherwise return just the cu...
Definition: timeSelector.C:291
virtual void setTime(const Time &t)
Reset the time and time-index to those of the given time.
Definition: Time.C:902
Abstract base class for domain decomposition.
MeshObject wrapper of decompositionMethod.
static unsigned int minPrecision(unsigned int prec) noexcept
Set the minimum default precision.
Definition: IOstream.H:440
static word controlDictName
The default control dictionary name (normally "controlDict")
Definition: Time.H:268
const dictionary & controlDict() const noexcept
Return read access to the controlDict dictionary.
Definition: Time.H:539
static autoPtr< fvMesh > loadOrCreateMesh(const IOobject &io, const bool decompose, const bool verbose=false)
Read mesh if available, or create empty mesh with non-proc as per proc0 mesh.
Definition: fvMeshTools.C:1177
fileName relativePath(const fileName &input, const bool caseTag=false) const
Return the input relative to the globalPath by stripping off a leading value of the globalPath...
Definition: argListI.H:87
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
virtual bool write(const bool writeOnProc=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1113
void reconstructLagrangian(autoPtr< parLagrangianDistributor > &distributorPtr, const fvMesh &baseMesh, const fvMesh &mesh, const mapDistributePolyMesh &distMap, const wordRes &selectedFields)
static void addVerboseOption(const string &usage="", bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:520
virtual bool write(const bool writeOnProc=true) const
Write mesh.
Definition: faMesh.C:1363
static int cacheLevel() noexcept
Return cache level.
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
T * get() noexcept
Return pointer without nullptr checking.
Definition: refPtr.H:249
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:192
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:112
int debug
Static debugging option.
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
Definition: refPtrI.H:230
const fileName & rootPath() const noexcept
Return root path.
Definition: argListI.H:56
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
Holds a reference to the original mesh (the baseMesh) and optionally to a subset of that mesh (the su...
Definition: fvMeshSubset.H:75
static autoPtr< fileOperation > New(const word &handlerType, bool verbose=false)
Select fileHandler-type. Uses defaultFileHandler if the handlerType is empty.
static label commWorld() noexcept
Communicator for all ranks (respecting any local worlds)
Definition: UPstream.H:441
static std::unique_ptr< faMeshesRegistry > Release(const word &objName, const polyMesh &mesh, const bool checkout=false)
Release ownership of meshObject (with given registration name) from registry. Returns nullptr if not ...
Definition: MeshObject.C:146
static autoPtr< faMesh > loadOrCreateMesh(const IOobject &io, const polyMesh &pMesh, const bool decompose, const bool verbose=false)
Definition: faMeshTools.C:576
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional &#39;FOAM Warning&#39; header text...
static void broadcasts(const label comm, Type &arg1, Args &&... args)
Broadcast multiple items to all communicator ranks. Does nothing in non-parallel. ...
static instantList findTimes(const fileName &directory, const word &constantDirName="constant")
Search a given directory for valid time directories.
Definition: TimePaths.C:109
fileName path() const
Return the full path to the (processor local) case.
Definition: argListI.H:74
int neighbProcNo() const noexcept
Return neighbour processor number.
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual linear/tree communicat...
An instant of time. Contains the time value and name. Uses Foam::Time when formatting the name...
Definition: instant.H:53
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:750
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: faMesh.C:1034
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> reconstruct(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
static void unregisterMesh(const faMesh &mesh)
Unregister the faMesh from its associated polyMesh to prevent triggering on polyMesh changes etc...
Definition: faMeshTools.C:33
instantList times() const
Search the case for valid time directories.
Definition: TimePaths.C:118
void setInstance(const fileName &instance, const IOobjectOption::writeOption wOpt=IOobject::AUTO_WRITE)
Set the instance for mesh files.
Definition: polyMeshIO.C:29
#define WarningInFunction
Report a warning using Foam::Warning.
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
label nCells() const noexcept
Number of mesh cells.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir)
Definition: polyMesh.C:841
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
Mesh data needed to do the Finite Area discretisation.
Definition: areaFaMesh.H:47
label nPointFields
Required Classes.
Nothing to be read.
Automatically write from objectRegistry::writeObject()
messageStream Info
Information stream (stdout output on master, null elsewhere)
void removeProcAddressing(const faMesh &mesh)
Remove procAddressing.
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
Reading is optional [identical to READ_IF_PRESENT].
Various for reading/decomposing/reconstructing/distributing refinement data.
Definition: hexRef8Data.H:56
T * get() noexcept
Return pointer to managed object without nullptr checking.
Definition: autoPtr.H:216
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
readUpdateState
Enumeration defining the state of the mesh after a read update.
Definition: polyMesh.H:91
static const fileOperation & fileHandler()
Return the current file handler. Will create the default file handler if necessary.
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
Registry of regIOobjects.
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
Switch runTimeModifiable() const noexcept
Supports re-reading.
Definition: Time.H:585
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
Foam::argList args(argc, argv)
A IOList wrapper for writing external data.
Definition: IOList.H:151
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
static autoPtr< mapDistributePolyMesh > readProcAddressing(const fvMesh &procMesh, const autoPtr< fvMesh > &baseMeshPtr)
Read procAddressing components (reconstructing)
static void forceDemandDriven(faMesh &mesh)
Force creation of everything that might vaguely be used by patches.
Definition: faMeshTools.C:45
static void setBasicGeometry(fvMesh &mesh)
Set the fvGeometryScheme to basic (to avoid parallel communication)
Definition: fvMeshTools.C:425
int verbose() const noexcept
Return the verbose flag.
Definition: argListI.H:121
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Do not request registration (bool: false)
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
PtrList< unmappedPassivePositionParticleCloud > readLagrangian(const fvMesh &mesh, const wordList &cloudNames, const boolUList &haveClouds, const wordRes &selectedFields)
static mapDistributePolyMesh distribute(const faMesh &oldMesh, const mapDistributePolyMesh &distMap, const polyMesh &tgtPolyMesh, autoPtr< faMesh > &newMeshPtr)
Distribute mesh according to the given (volume) mesh distribution.
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:101
Namespace for OpenFOAM.
fileName globalPath() const
Return the full path to the global case.
Definition: argListI.H:80
virtual labelList decompose(const pointField &points, const scalarField &pointWeights=scalarField::null()) const
Return the wanted processor number for every coordinate, using uniform or specified point weights...
static autoPtr< fileOperation > NewUncollated()
The commonly used uncollatedFileOperation.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127