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-2022 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"
94 #include "topoSet.H"
95 #include "regionProperties.H"
96 
97 #include "parFvFieldDistributor.H"
99 #include "hexRef8Data.H"
100 #include "meshRefinement.H"
101 #include "pointFields.H"
102 
103 #include "faMeshSubset.H"
104 #include "faMeshTools.H"
105 #include "faMeshDistributor.H"
107 
108 #include "redistributeLagrangian.H"
109 
110 #include "cyclicACMIFvPatch.H"
112 #include "uncollatedFileOperation.H"
113 #include "collatedFileOperation.H"
114 
115 using namespace Foam;
116 
117 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
118 
119 const int debug(::Foam::debug::debugSwitch("redistributePar", 0));
120 
121 void createTimeDirs(const fileName& path)
122 {
123  // Get current set of local processor's time directories. Uses
124  // fileHandler
125  const instantList localTimeDirs(Time::findTimes(path, "constant"));
126 
127  instantList masterTimeDirs;
128  if (Pstream::master())
129  {
130  //const bool oldParRun = Pstream::parRun(false);
131  //timeDirs = Time::findTimes(path, "constant");
132  //Pstream::parRun(oldParRun); // Restore parallel state
133  masterTimeDirs = localTimeDirs;
134  }
135  Pstream::broadcast(masterTimeDirs);
136  //DebugVar(masterTimeDirs);
137  //DebugVar(localTimeDirs);
138 
139  // Sync any cached times (e.g. masterUncollatedFileOperation::times_)
140  // since only master would have done the findTimes
141  for (const instant& t : masterTimeDirs)
142  {
143  if (!localTimeDirs.found(t))
144  {
145  const fileName timePath(path/t.name());
146 
147  //Pout<< "Time:" << t << nl
148  // << " raw :" << timePath << nl
149  // << endl;
150  Foam::mkDir(timePath);
151  }
152  }
153 
154  // Just to make sure remove all state and re-scan
155  fileHandler().flush();
156  (void)Time::findTimes(path, "constant");
157 }
158 
159 
160 void copyUniform
161 (
162  const fileOperation& fh,
163  const bool decompose,
164  const bool reconstruct,
165  const word& readTimeName,
166  const objectRegistry& readDb,
167  const objectRegistry& writeDb
168 )
169 {
170  // Detect uniform/ at original database + time
171  const IOobject readIO("uniform", readTimeName, readDb);
172  const fileName readPath
173  (
174  fh.dirPath
175  (
176  false, // local directory
177  readIO,
178  false // do not search in time
179  )
180  );
181  //if (Pstream::master() && !readPath.empty())
182  if (!readPath.empty())
183  {
184  Info<< "Detected additional non-decomposed files in "
185  << readPath << endl;
186 
187  // readPath: searching is the same for all file handlers. Typical:
188  // <case>/0.1/uniform (parent dir, decompose mode)
189  // <case>/processor1/0.1/uniform (redistribute/reconstruct mode)
190  // <case>/processors2/0.1/uniform ,,
191  // writePath:
192  // uncollated : <case>/0.1/uniform (reconstruct mode). Should only
193  // be done by master
194  // uncollated : <case>/processorXXX/0.1/uniform. Should be done by all.
195  // collated : <case>/processors2/0.1/uniform. Should be done by
196  // local master only.
197 
198  // See what local directory
199  const IOobject writeIO("uniform", writeDb.time().timeName(), writeDb);
200  const fileName writePath
201  (
202  fh.objectPath
203  (
204  writeIO,
205  word::null
206  )
207  );
208  // Do we already have this directory?
209  const fileName currentPath(fh.dirPath(false, writeIO, false));
210 
211  if (::debug)
212  {
213  Pout<< " readPath :" << readPath << endl;
214  Pout<< " writePath :" << writePath << endl;
215  Pout<< " currentPath:" << currentPath << endl;
216  }
217 
218  if (readPath == writePath)
219  {
220  return;
221  }
222 
223  if (currentPath.empty())
224  {
225  if (decompose)
226  {
227  // All processors copy to destination
228  fh.cp(readPath, writePath);
229  }
230  else if (reconstruct)
231  {
232  // Only master
233  if (Pstream::master())
234  {
235  const bool oldParRun = Pstream::parRun(false);
236  fh.cp(readPath, writePath);
237  Pstream::parRun(oldParRun);
238  }
239  }
240  else
241  {
242  // Redistribute. If same destination path do only on master,
243  // if different path do on all processors. For now check
244  // if collated file handler only. tbd.
245  if (isA<fileOperations::collatedFileOperation>(fh))
246  {
247  // Collated
248  if (Pstream::master())
249  {
250  const bool oldParRun = Pstream::parRun(false);
251  fh.cp(readPath, writePath);
252  Pstream::parRun(oldParRun);
253  }
254  }
255  else
256  {
257  // Assume uncollated
258  fh.cp(readPath, writePath);
259  }
260  }
261  }
262  }
263 }
264 
265 
266 void printMeshData(const polyMesh& mesh)
267 {
268  // Collect all data on master
269 
270  labelListList patchNeiProcNo(Pstream::nProcs());
271  labelListList patchSize(Pstream::nProcs());
272  const labelList& pPatches = mesh.globalData().processorPatches();
273  patchNeiProcNo[Pstream::myProcNo()].setSize(pPatches.size());
274  patchSize[Pstream::myProcNo()].setSize(pPatches.size());
275  forAll(pPatches, i)
276  {
277  const processorPolyPatch& ppp = refCast<const processorPolyPatch>
278  (
279  mesh.boundaryMesh()[pPatches[i]]
280  );
281  patchNeiProcNo[Pstream::myProcNo()][i] = ppp.neighbProcNo();
282  patchSize[Pstream::myProcNo()][i] = ppp.size();
283  }
284  Pstream::gatherList(patchNeiProcNo);
285  Pstream::gatherList(patchSize);
286 
287 
288  // Print stats
289 
290  const globalIndex globalCells(mesh.nCells());
291  const globalIndex globalBoundaryFaces(mesh.nBoundaryFaces());
292 
293  label maxProcCells = 0;
294  label maxProcFaces = 0;
295  label totProcFaces = 0;
296  label maxProcPatches = 0;
297  label totProcPatches = 0;
298 
299  for (const int proci : Pstream::allProcs())
300  {
301  const label nLocalCells = globalCells.localSize(proci);
302  const label nBndFaces = globalBoundaryFaces.localSize(proci);
303 
304  Info<< nl
305  << "Processor " << proci;
306 
307  if (!nLocalCells)
308  {
309  Info<< " (empty)" << endl;
310  continue;
311  }
312  else
313  {
314  Info<< nl
315  << " Number of cells = " << nLocalCells << endl;
316  }
317 
318  label nProcFaces = 0;
319  const labelList& nei = patchNeiProcNo[proci];
320 
321  forAll(patchNeiProcNo[proci], i)
322  {
323  Info<< " Number of faces shared with processor "
324  << patchNeiProcNo[proci][i] << " = "
325  << patchSize[proci][i] << nl;
326 
327  nProcFaces += patchSize[proci][i];
328  }
329 
330  {
331  Info<< " Number of processor patches = " << nei.size() << nl
332  << " Number of processor faces = " << nProcFaces << nl
333  << " Number of boundary faces = "
334  << nBndFaces-nProcFaces << endl;
335  }
336 
337  maxProcCells = max(maxProcCells, nLocalCells);
338  totProcFaces += nProcFaces;
339  totProcPatches += nei.size();
340  maxProcFaces = max(maxProcFaces, nProcFaces);
341  maxProcPatches = max(maxProcPatches, nei.size());
342  }
343 
344  // Summary stats
345 
346  Info<< nl
347  << "Number of processor faces = " << (totProcFaces/2) << nl
348  << "Max number of cells = " << maxProcCells;
349 
350  if (maxProcCells != globalCells.totalSize())
351  {
352  scalar avgValue = scalar(globalCells.totalSize())/Pstream::nProcs();
353 
354  Info<< " (" << 100.0*(maxProcCells-avgValue)/avgValue
355  << "% above average " << avgValue << ')';
356  }
357  Info<< nl;
358 
359  Info<< "Max number of processor patches = " << maxProcPatches;
360  if (totProcPatches)
361  {
362  scalar avgValue = scalar(totProcPatches)/Pstream::nProcs();
363 
364  Info<< " (" << 100.0*(maxProcPatches-avgValue)/avgValue
365  << "% above average " << avgValue << ')';
366  }
367  Info<< nl;
368 
369  Info<< "Max number of faces between processors = " << maxProcFaces;
370  if (totProcFaces)
371  {
372  scalar avgValue = scalar(totProcFaces)/Pstream::nProcs();
373 
374  Info<< " (" << 100.0*(maxProcFaces-avgValue)/avgValue
375  << "% above average " << avgValue << ')';
376  }
377  Info<< nl << endl;
378 }
379 
380 
381 // Debugging: write volScalarField with decomposition for post processing.
382 void writeDecomposition
383 (
384  const word& name,
385  const fvMesh& mesh,
386  const labelUList& decomp
387 )
388 {
389  // Write the decomposition as labelList for use with 'manual'
390  // decomposition method.
391  labelIOList cellDecomposition
392  (
393  IOobject
394  (
395  "cellDecomposition",
396  mesh.facesInstance(), // mesh read from facesInstance
397  mesh,
400  false
401  ),
402  decomp
403  );
404  cellDecomposition.write();
405 
406  Info<< "Writing wanted cell distribution to volScalarField " << name
407  << " for postprocessing purposes." << nl << endl;
408 
409  volScalarField procCells
410  (
411  IOobject
412  (
413  name,
414  mesh.time().timeName(),
415  mesh,
418  false // do not register
419  ),
420  mesh,
422  zeroGradientFvPatchScalarField::typeName
423  );
424 
425  forAll(procCells, celli)
426  {
427  procCells[celli] = decomp[celli];
428  }
429 
430  procCells.correctBoundaryConditions();
431  procCells.write();
432 }
433 
434 
435 void determineDecomposition
436 (
437  const Time& baseRunTime,
438  const fileName& decompDictFile, // optional location for decomposeParDict
439  const bool decompose, // decompose, i.e. read from undecomposed case
440  const fileName& proc0CaseName,
441  const fvMesh& mesh,
442  const bool writeCellDist,
443 
444  label& nDestProcs,
445  labelList& decomp
446 )
447 {
448  // Read decomposeParDict (on all processors)
450  (
451  mesh,
452  decompDictFile
453  );
454 
455  decompositionMethod& decomposer = method.decomposer();
456 
457  if (!decomposer.parallelAware())
458  {
460  << "You have selected decomposition method \""
461  << decomposer.type() << "\n"
462  << " which does not synchronise decomposition across"
463  " processor patches.\n"
464  " You might want to select a decomposition method"
465  " that is aware of this. Continuing...." << endl;
466  }
467 
468  Time& tm = const_cast<Time&>(mesh.time());
469 
470  const bool oldProcCase = tm.processorCase();
471  if (Pstream::master() && decompose)
472  {
473  Info<< "Setting caseName to " << baseRunTime.caseName()
474  << " to read decomposeParDict" << endl;
475  tm.caseName() = baseRunTime.caseName();
476  tm.processorCase(false);
477  }
478 
479  scalarField cellWeights;
480  if (method.found("weightField"))
481  {
482  word weightName = method.get<word>("weightField");
483 
484  volScalarField weights
485  (
486  IOobject
487  (
488  weightName,
489  tm.timeName(),
490  mesh,
493  ),
494  mesh
495  );
496  cellWeights = weights.internalField();
497  }
498 
499  nDestProcs = decomposer.nDomains();
500  decomp = decomposer.decompose(mesh, cellWeights);
501 
502  if (Pstream::master() && decompose)
503  {
504  Info<< "Restoring caseName" << endl;
505  tm.caseName() = proc0CaseName;
506  tm.processorCase(oldProcCase);
507  }
508 
509  // Dump decomposition to volScalarField
510  if (writeCellDist)
511  {
512  // Note: on master make sure to write to processor0
513  if (decompose)
514  {
515  if (Pstream::master())
516  {
517  const bool oldParRun = Pstream::parRun(false);
518 
519  Info<< "Setting caseName to " << baseRunTime.caseName()
520  << " to write undecomposed cellDist" << endl;
521 
522  tm.caseName() = baseRunTime.caseName();
523  tm.processorCase(false);
524  writeDecomposition("cellDist", mesh, decomp);
525  Info<< "Restoring caseName" << endl;
526  tm.caseName() = proc0CaseName;
527  tm.processorCase(oldProcCase);
528 
529  Pstream::parRun(oldParRun);
530  }
531  }
532  else
533  {
534  writeDecomposition("cellDist", mesh, decomp);
535  }
536  }
537 }
538 
539 
540 // Variant of GeometricField::correctBoundaryConditions that only
541 // evaluates selected patch fields
542 template<class CoupledPatchType, class GeoField>
543 void correctCoupledBoundaryConditions(fvMesh& mesh)
544 {
545  for (GeoField& fld : mesh.sorted<GeoField>())
546  {
547  fld.boundaryFieldRef().template evaluateCoupled<CoupledPatchType>();
548  }
549 }
550 
551 
552 // Inplace redistribute mesh and any fields
553 autoPtr<mapDistributePolyMesh> redistributeAndWrite
554 (
555  autoPtr<fileOperation>&& writeHandler,
556  const Time& baseRunTime,
557  const fileName& proc0CaseName,
558 
559  // Controls
560  const bool doReadFields,
561  const bool decompose, // decompose, i.e. read from undecomposed case
562  const bool reconstruct,
563  const bool overwrite,
564 
565  // Decomposition information
566  const label nDestProcs,
567  const labelList& decomp,
568 
569  // Mesh information
570  const boolList& volMeshOnProc,
571  const fileName& volMeshInstance,
572  fvMesh& mesh
573 )
574 {
575  Time& runTime = const_cast<Time&>(mesh.time());
576  const bool oldProcCase = runTime.processorCase();
577 
579  //Info<< "Before distribution:" << endl;
580  //printMeshData(mesh);
581 
582  // Storage of fields
583 
584  PtrList<volScalarField> volScalarFields;
585  PtrList<volVectorField> volVectorFields;
586  PtrList<volSphericalTensorField> volSphereTensorFields;
587  PtrList<volSymmTensorField> volSymmTensorFields;
588  PtrList<volTensorField> volTensorFields;
589 
590  PtrList<surfaceScalarField> surfScalarFields;
591  PtrList<surfaceVectorField> surfVectorFields;
592  PtrList<surfaceSphericalTensorField> surfSphereTensorFields;
593  PtrList<surfaceSymmTensorField> surfSymmTensorFields;
594  PtrList<surfaceTensorField> surfTensorFields;
595 
601 
602  PtrList<pointScalarField> pointScalarFields;
603  PtrList<pointVectorField> pointVectorFields;
604  PtrList<pointTensorField> pointTensorFields;
605  PtrList<pointSphericalTensorField> pointSphTensorFields;
606  PtrList<pointSymmTensorField> pointSymmTensorFields;
607 
608  // Self-contained pointMesh for reading pointFields
609  const pointMesh oldPointMesh(mesh);
610 
611  // Track how many (if any) pointFields are read/mapped
612  label nPointFields = 0;
613 
614  parPointFieldDistributor pointDistributor
615  (
616  oldPointMesh, // source mesh
617  false, // savePoints=false (ie, delay until later)
618  false // Do not write
619  );
620 
621 
622  if (doReadFields)
623  {
624  // Create 0 sized mesh to do all the generation of zero sized
625  // fields on processors that have zero sized meshes. Note that this is
626  // only necessary on master but since polyMesh construction with
627  // Pstream::parRun does parallel comms we have to do it on all
628  // processors
629  autoPtr<fvMeshSubset> subsetterPtr;
630 
631  // Missing a volume mesh somewhere?
632  if (volMeshOnProc.found(false))
633  {
634  // A zero-sized mesh with boundaries.
635  // This is used to create zero-sized fields.
636  subsetterPtr.reset(new fvMeshSubset(mesh, zero{}));
637  }
638 
639 
640  // Get original objects (before incrementing time!)
641  if (Pstream::master() && decompose)
642  {
643  runTime.caseName() = baseRunTime.caseName();
644  runTime.processorCase(false);
645  }
646  IOobjectList objects(mesh, runTime.timeName());
647  if (Pstream::master() && decompose)
648  {
649  runTime.caseName() = proc0CaseName;
650  runTime.processorCase(oldProcCase);
651  }
652 
653  Info<< "From time " << runTime.timeName()
654  << " mesh:" << mesh.objectRegistry::objectRelPath()
655  << " have objects:" << objects.names() << endl;
656 
657  // We don't want to map the decomposition (mapping already tested when
658  // mapping the cell centre field)
659  auto iter = objects.find("cellDist");
660  if (iter.found())
661  {
662  objects.erase(iter);
663  }
664 
665 
666  if (Pstream::master() && decompose)
667  {
668  runTime.caseName() = baseRunTime.caseName();
669  runTime.processorCase(false);
670  }
671 
672  // Field reading
673 
674  #undef doFieldReading
675  #define doFieldReading(Storage) \
676  { \
677  fieldsDistributor::readFields \
678  ( \
679  volMeshOnProc, mesh, subsetterPtr, objects, Storage \
680  ); \
681  }
682 
683  // volField
684  doFieldReading(volScalarFields);
685  doFieldReading(volVectorFields);
686  doFieldReading(volSphereTensorFields);
687  doFieldReading(volSymmTensorFields);
688  doFieldReading(volTensorFields);
689 
690  // surfaceField
691  doFieldReading(surfScalarFields);
692  doFieldReading(surfVectorFields);
693  doFieldReading(surfSphereTensorFields);
694  doFieldReading(surfSymmTensorFields);
695  doFieldReading(surfTensorFields);
696 
697  // Dimensioned internal fields
698  doFieldReading(dimScalarFields);
699  doFieldReading(dimVectorFields);
700  doFieldReading(dimSphereTensorFields);
701  doFieldReading(dimSymmTensorFields);
702  doFieldReading(dimTensorFields);
703 
704  // pointFields
705  nPointFields = 0;
706 
707  #undef doFieldReading
708  #define doFieldReading(Storage) \
709  { \
710  fieldsDistributor::readFields \
711  ( \
712  volMeshOnProc, oldPointMesh, subsetterPtr, objects, Storage, \
713  true /* (deregister field) */ \
714  ); \
715  nPointFields += Storage.size(); \
716  }
717 
718  doFieldReading(pointScalarFields);
719  doFieldReading(pointVectorFields);
720  doFieldReading(pointSphTensorFields);
721  doFieldReading(pointSymmTensorFields);
722  doFieldReading(pointTensorFields);
723  #undef doFieldReading
724 
725 
726  // Done reading
727 
728  if (Pstream::master() && decompose)
729  {
730  runTime.caseName() = proc0CaseName;
731  runTime.processorCase(oldProcCase);
732  }
733  }
734 
735  // Save pointMesh information before any topology changes occur!
736  if (nPointFields)
737  {
738  pointDistributor.saveMeshPoints();
739  }
740 
741 
742  // Mesh distribution engine
743  fvMeshDistribute distributor(mesh);
744 
745  // Do all the distribution of mesh and fields
746  autoPtr<mapDistributePolyMesh> distMap = distributor.distribute(decomp);
747 
748  // Print some statistics
749  Info<< "After distribution:" << endl;
750  printMeshData(mesh);
751 
752  // Get other side of processor boundaries
753  do
754  {
755  #undef doCorrectCoupled
756  #define doCorrectCoupled(FieldType) \
757  correctCoupledBoundaryConditions<processorFvPatch, FieldType>(mesh);
758 
759  doCorrectCoupled(volScalarField);
760  doCorrectCoupled(volVectorField);
761  doCorrectCoupled(volSphericalTensorField);
762  doCorrectCoupled(volSymmTensorField);
763  doCorrectCoupled(volTensorField);
764  #undef doCorrectCoupled
765  }
766  while (false);
767 
768  // No update surface fields
769 
770 
771  // Map pointFields
772  if (nPointFields)
773  {
774  // Construct new pointMesh from distributed mesh
775  const pointMesh& newPointMesh = pointMesh::New(mesh);
776 
777  pointDistributor.resetTarget(newPointMesh, distMap());
778 
779  pointDistributor.distributeAndStore(pointScalarFields);
780  pointDistributor.distributeAndStore(pointVectorFields);
781  pointDistributor.distributeAndStore(pointSphTensorFields);
782  pointDistributor.distributeAndStore(pointSymmTensorFields);
783  pointDistributor.distributeAndStore(pointTensorFields);
784  }
785 
786 
787  // Set the minimum write precision
789 
790 
791  if (!overwrite)
792  {
793  ++runTime;
795  }
796  else
797  {
798  mesh.setInstance(volMeshInstance);
799  }
800 
801 
802  // Register mapDistributePolyMesh for automatic writing...
803  IOmapDistributePolyMeshRef distMapRef
804  (
805  IOobject
806  (
807  "procAddressing",
810  mesh.thisDb(),
813  ),
814  distMap()
815  );
816 
817 
818  if (reconstruct)
819  {
820  if (Pstream::master())
821  {
822  Info<< "Setting caseName to " << baseRunTime.caseName()
823  << " to write reconstructed mesh (and fields)." << endl;
824  runTime.caseName() = baseRunTime.caseName();
825  const bool oldProcCase(runTime.processorCase(false));
826 
827  mesh.write();
829 
830  // Now we've written all. Reset caseName on master
831  Info<< "Restoring caseName" << endl;
832  runTime.caseName() = proc0CaseName;
833  runTime.processorCase(oldProcCase);
834  }
835  }
836  else
837  {
838  autoPtr<fileOperation> defaultHandler;
839  if (writeHandler)
840  {
841  defaultHandler = fileHandler(std::move(writeHandler));
842  }
843 
844  mesh.write();
845 
846  if (defaultHandler)
847  {
848  writeHandler = fileHandler(std::move(defaultHandler));
849  }
851  }
852  Info<< "Written redistributed mesh to "
853  << mesh.facesInstance() << nl << endl;
854 
855 
856  if (decompose || reconstruct)
857  {
858  // Decompose (1 -> N) or reconstruct (N -> 1)
859  // so {boundary,cell,face,point}ProcAddressing have meaning
861  (
862  mesh,
863  distMap(),
864  decompose,
865  std::move(writeHandler)
866  );
867  }
868  else
869  {
870  // Redistribute (N -> M)
871  // {boundary,cell,face,point}ProcAddressing would be incorrect
872  // - can either remove or redistribute previous
874  }
875 
876 
877  // Refinement data
878  {
879 
880  // Read refinement data
881  if (Pstream::master() && decompose)
882  {
883  runTime.caseName() = baseRunTime.caseName();
884  runTime.processorCase(false);
885  }
886  IOobject io
887  (
888  "dummy",
891  mesh,
894  false
895  );
896 
897  hexRef8Data refData(io);
898  if (Pstream::master() && decompose)
899  {
900  runTime.caseName() = proc0CaseName;
901  runTime.processorCase(oldProcCase);
902  }
903 
904  // Make sure all processors have valid data (since only some will
905  // read)
906  refData.sync(io);
907 
908  // Distribute
909  refData.distribute(distMap());
910 
911 
912  // Now we've read refinement data we can remove it
914 
915  if (reconstruct)
916  {
917  if (Pstream::master())
918  {
919  const bool oldParRun = Pstream::parRun(false);
920 
921  Info<< "Setting caseName to " << baseRunTime.caseName()
922  << " to write reconstructed refinement data." << endl;
923  runTime.caseName() = baseRunTime.caseName();
924  const bool oldProcCase(runTime.processorCase(false));
925 
926  refData.write();
927 
928  // Now we've written all. Reset caseName on master
929  Info<< "Restoring caseName" << endl;
930  runTime.caseName() = proc0CaseName;
931  runTime.processorCase(oldProcCase);
932 
933  Pstream::parRun(oldParRun);
934  }
935  }
936  else
937  {
938  refData.write();
939  }
940  }
941 
943  //{
944  // // Read sets
945  // if (Pstream::master() && decompose)
946  // {
947  // runTime.caseName() = baseRunTime.caseName();
948  // runTime.processorCase(false);
949  // }
950  // IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
951  //
952  // PtrList<cellSet> cellSets;
953  // ReadFields(objects, cellSets);
954  //
955  // if (Pstream::master() && decompose)
956  // {
957  // runTime.caseName() = proc0CaseName;
958  // runTime.processorCase(oldProcCase);
959  // }
960  //
961  // forAll(cellSets, i)
962  // {
963  // cellSets[i].distribute(distMap());
964  // }
965  //
966  // if (reconstruct)
967  // {
968  // if (Pstream::master())
969  // {
970  // Info<< "Setting caseName to " << baseRunTime.caseName()
971  // << " to write reconstructed refinement data." << endl;
972  // runTime.caseName() = baseRunTime.caseName();
973  // const bool oldProcCase(runTime.processorCase(false));
974  //
975  // forAll(cellSets, i)
976  // {
977  // cellSets[i].distribute(distMap());
978  // }
979  //
980  // // Now we've written all. Reset caseName on master
981  // Info<< "Restoring caseName" << endl;
982  // runTime.caseName() = proc0CaseName;
983  // runTime.processorCase(oldProcCase);
984  // }
985  // }
986  // else
987  // {
988  // forAll(cellSets, i)
989  // {
990  // cellSets[i].distribute(distMap());
991  // }
992  // }
993  //}
994 
995 
996  return distMap;
997 }
998 
999 
1000 /*---------------------------------------------------------------------------*\
1001  main
1002 \*---------------------------------------------------------------------------*/
1003 
1004 int main(int argc, char *argv[])
1005 {
1007  (
1008  "Redistribute decomposed mesh and fields according"
1009  " to the decomposeParDict settings.\n"
1010  "Optionally run in decompose/reconstruct mode"
1011  );
1012 
1013  argList::noFunctionObjects(); // Never use function objects
1014 
1015  // enable -constant ... if someone really wants it
1016  // enable -zeroTime to prevent accidentally trashing the initial fields
1017  timeSelector::addOptions(true, true);
1018 
1019  #include "addAllRegionOptions.H"
1020 
1021  #include "addOverwriteOption.H"
1022  argList::addBoolOption("decompose", "Decompose case");
1023  argList::addBoolOption("reconstruct", "Reconstruct case");
1024  argList::addVerboseOption("Additional verbosity");
1026  (
1027  "Test without writing the decomposition. "
1028  "Changes -cellDist to only write volScalarField."
1029  );
1030  argList::addVerboseOption("Additional verbosity");
1032  (
1033  "cellDist",
1034  "Write cell distribution as a labelList - for use with 'manual' "
1035  "decomposition method or as a volScalarField for post-processing."
1036  );
1038  (
1039  "newTimes",
1040  "Only reconstruct new times (i.e. that do not exist already)"
1041  );
1043  (
1044  "Additional verbosity. (Can be used multiple times)"
1045  );
1047  (
1048  "no-finite-area",
1049  "Suppress finiteArea mesh/field handling",
1050  true // Advanced option
1051  );
1052 
1053  // Handle arguments
1054  // ~~~~~~~~~~~~~~~~
1055  // (replacement for setRootCase that does not abort)
1056 
1057  argList args(argc, argv);
1058 
1059 
1060  // As much as possible avoid synchronised operation. To be looked at more
1061  // closely for the three scenarios:
1062  // - decompose - reads on master (and from parent directory) and sends
1063  // dictionary to slaves
1064  // - distribute - reads on potentially a different number of processors
1065  // than it writes to
1066  // - reconstruct - reads parallel, write on master only and to parent
1067  // directory
1068  autoPtr<fileOperation> writeHandler;
1069  if
1070  (
1071  fileHandler().type()
1072  != fileOperations::uncollatedFileOperation::typeName
1073  )
1074  {
1075  // Install 'uncollated' as fileHandler. Save old one in writeHandler.
1076  writeHandler = fileHandler(fileOperation::NewUncollated());
1077  }
1078 
1079  // Switch off parallel synchronisation of cached time directories
1080  fileHandler().distributed(true);
1081 
1082  // File handler to be used for writing
1083  const fileOperation& fh
1084  (
1085  writeHandler
1086  ? writeHandler()
1087  : fileHandler()
1088  );
1089 
1090  // Make sure to call findTimes on all processors to force caching of
1091  // time directories
1092  (void)fileHandler().findTimes(args.path(), "constant");
1093 
1094  // Need this line since we don't include "setRootCase.H"
1095  #include "foamDlOpenLibs.H"
1096 
1097  const bool reconstruct = args.found("reconstruct");
1098  const bool writeCellDist = args.found("cellDist");
1099  const bool dryrun = args.dryRun();
1100  const bool newTimes = args.found("newTimes");
1101  const int optVerbose = args.verbose();
1102 
1103  const bool doFiniteArea = !args.found("no-finite-area");
1104  bool decompose = args.found("decompose");
1105  bool overwrite = args.found("overwrite");
1106 
1107  if (optVerbose)
1108  {
1109  // Report on output
1112  }
1113 
1114  // Disable NaN setting and floating point error trapping. This is to avoid
1115  // any issues inside the field redistribution inside fvMeshDistribute
1116  // which temporarily moves processor faces into existing patches. These
1117  // will now not have correct values. After all bits have been assembled
1118  // the processor fields will be restored but until then there might
1119  // be uninitialised values which might upset some patch field constructors.
1120  // Workaround by disabling floating point error trapping. TBD: have
1121  // actual field redistribution instead of subsetting inside
1122  // fvMeshDistribute.
1123  Foam::sigFpe::unset(true);
1124 
1125  const wordRes selectedFields;
1126  const wordRes selectedLagrangianFields;
1127 
1128 
1129  if (decompose)
1130  {
1131  Info<< "Decomposing case (like decomposePar)" << nl << endl;
1132  if (reconstruct)
1133  {
1135  << "Cannot specify both -decompose and -reconstruct"
1136  << exit(FatalError);
1137  }
1138  }
1139  else if (reconstruct)
1140  {
1141  Info<< "Reconstructing case (like reconstructParMesh)" << nl << endl;
1142  }
1143 
1144  if ((decompose || reconstruct) && !overwrite)
1145  {
1146  overwrite = true;
1148  << "Working in -decompose or -reconstruct mode:"
1149  " automatically implies -overwrite" << nl << endl;
1150  }
1151 
1152  if (!Pstream::parRun())
1153  {
1155  << ": This utility can only be run parallel"
1156  << exit(FatalError);
1157  }
1158 
1159 
1160  if (!Foam::isDir(args.rootPath()))
1161  {
1163  << ": cannot open root directory " << args.rootPath()
1164  << exit(FatalError);
1165  }
1166 
1167  // Detect if running data-distributed (multiple roots)
1168  bool nfs = true;
1169  {
1170  List<fileName> roots(1, args.rootPath());
1172  nfs = (roots.size() == 1);
1173  }
1174 
1175  if (!nfs)
1176  {
1177  Info<< "Detected multiple roots i.e. non-nfs running"
1178  << nl << endl;
1179  }
1180 
1181  // Check if we have processor directories. Ideally would like to
1182  // use fileHandler().dirPath here but we don't have runTime yet and
1183  // want to delay constructing runTime until we've synced all time
1184  // directories...
1185  const fileName procDir(fileHandler().filePath(args.path()));
1186  if (Foam::isDir(procDir))
1187  {
1188  if (decompose)
1189  {
1190  Info<< "Removing existing processor directory:"
1191  << args.relativePath(procDir) << endl;
1192  fileHandler().rmDir(procDir);
1193  }
1194  }
1195  else
1196  {
1197  // Directory does not exist. If this happens on master -> decompose mode
1198  if (Pstream::master())
1199  {
1200  decompose = true;
1201  Info<< "No processor directories; switching on decompose mode"
1202  << nl << endl;
1203  }
1204  }
1205  // If master changed to decompose mode make sure all nodes know about it
1206  Pstream::broadcast(decompose);
1207 
1208 
1209  // If running distributed we have problem of new processors not finding
1210  // a system/controlDict. However if we switch on the master-only reading
1211  // the problem becomes that the time directories are differing sizes and
1212  // e.g. latestTime will pick up a different time (which causes createTime.H
1213  // to abort). So for now make sure to have master times on all
1214  // processors
1215  if (!reconstruct)
1216  {
1217  Info<< "Creating time directories on all processors" << nl << endl;
1218  createTimeDirs(args.path());
1219  }
1220 
1221  // Construct time
1222  // ~~~~~~~~~~~~~~
1223 
1224  #include "createTime.H"
1225  runTime.functionObjects().off(); // Extra safety?
1226 
1227 
1228  // Save local processor0 casename
1229  const fileName proc0CaseName = runTime.caseName();
1230  const bool oldProcCase = runTime.processorCase();
1231 
1232 
1233  // Construct undecomposed Time
1234  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1235  // This will read the same controlDict but might have a different
1236  // set of times so enforce same times
1237 
1238  if (!nfs)
1239  {
1240  Info<< "Creating time directories for undecomposed Time"
1241  << " on all processors" << nl << endl;
1242  createTimeDirs(args.globalPath());
1243  }
1244 
1245 
1246  Info<< "Create undecomposed database" << nl << endl;
1247  Time baseRunTime
1248  (
1249  runTime.controlDict(),
1250  runTime.rootPath(),
1252  runTime.system(),
1253  runTime.constant(),
1254  false // enableFunctionObjects
1255  );
1256 
1257 
1258  wordHashSet masterTimeDirSet;
1259  if (newTimes)
1260  {
1261  instantList baseTimeDirs(baseRunTime.times());
1262  for (const instant& t : baseTimeDirs)
1263  {
1264  masterTimeDirSet.insert(t.name());
1265  }
1266  }
1267 
1268 
1269  // Allow override of decomposeParDict location
1270  const fileName decompDictFile =
1271  args.getOrDefault<fileName>("decomposeParDict", "");
1272 
1273  // Get region names
1274  #include "getAllRegionOptions.H"
1275 
1277  {
1278  Info<< "Using region: " << regionNames[0] << nl << endl;
1279  }
1280 
1281 
1282  // Demand driven lagrangian mapper
1283  autoPtr<parLagrangianDistributor> lagrangianDistributorPtr;
1284 
1285 
1286  if (reconstruct)
1287  {
1288  // use the times list from the master processor
1289  // and select a subset based on the command-line options
1291  Pstream::broadcast(timeDirs);
1292 
1293  if (timeDirs.empty())
1294  {
1296  << "No times selected"
1297  << exit(FatalError);
1298  }
1299 
1300 
1301  // Pass1 : reconstruct mesh and addressing
1302  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1303 
1304 
1305  Info<< nl
1306  << "Reconstructing mesh and addressing" << nl << endl;
1307 
1308  forAll(regionNames, regioni)
1309  {
1310  const word& regionName = regionNames[regioni];
1312 
1313  const fileName volMeshSubDir(regionDir/polyMesh::meshSubDir);
1314  const fileName areaMeshSubDir(regionDir/faMesh::meshSubDir);
1315 
1316  Info<< nl
1317  << "Reconstructing mesh " << regionDir << nl << endl;
1318 
1319  bool areaMeshDetected = false;
1320 
1321  // Loop over all times
1322  forAll(timeDirs, timeI)
1323  {
1324  // Set time for global database
1325  runTime.setTime(timeDirs[timeI], timeI);
1326  baseRunTime.setTime(timeDirs[timeI], timeI);
1327 
1328  Info<< "Time = " << runTime.timeName() << endl << endl;
1329 
1330  // Where meshes are
1331  fileName volMeshInstance;
1332  fileName areaMeshInstance;
1333 
1334  volMeshInstance = runTime.findInstance
1335  (
1336  volMeshSubDir,
1337  "faces",
1339  );
1340 
1341  if (doFiniteArea)
1342  {
1343  areaMeshInstance = runTime.findInstance
1344  (
1345  areaMeshSubDir,
1346  "faceLabels",
1348  );
1349  }
1350 
1352  (
1354  volMeshInstance,
1355  areaMeshInstance
1356  );
1357 
1358 
1359  // Check processors have meshes
1360  // - check for 'faces' file (polyMesh)
1361  // - check for 'faceLabels' file (faMesh)
1362  boolList volMeshOnProc;
1363  boolList areaMeshOnProc;
1364 
1365  volMeshOnProc = haveMeshFile
1366  (
1367  runTime,
1368  volMeshInstance/volMeshSubDir,
1369  "faces"
1370  );
1371 
1372  if (doFiniteArea)
1373  {
1374  areaMeshOnProc = haveMeshFile
1375  (
1376  runTime,
1377  areaMeshInstance/areaMeshSubDir,
1378  "faceLabels"
1379  );
1380 
1381  areaMeshDetected = areaMeshOnProc.found(true);
1382  }
1383 
1384 
1385  // Addressing back to reconstructed mesh as xxxProcAddressing.
1386  // - all processors have consistent faceProcAddressing
1387  // - processors without a mesh don't need faceProcAddressing
1388 
1389 
1390  // Note: filePath searches up on processors that don't have
1391  // processor if instance = constant so explicitly check
1392  // found filename.
1393  bool haveVolAddressing = false;
1394  if (volMeshOnProc[Pstream::myProcNo()])
1395  {
1396  // Read faces (just to know their size)
1397  faceCompactIOList faces
1398  (
1399  IOobject
1400  (
1401  "faces",
1402  volMeshInstance,
1403  volMeshSubDir,
1404  runTime,
1406  )
1407  );
1408 
1409  // Check faceProcAddressing
1410  labelIOList faceProcAddressing
1411  (
1412  IOobject
1413  (
1414  "faceProcAddressing",
1415  volMeshInstance,
1416  volMeshSubDir,
1417  runTime,
1419  )
1420  );
1421 
1422  haveVolAddressing =
1423  (
1424  faceProcAddressing.headerOk()
1425  && faceProcAddressing.size() == faces.size()
1426  );
1427  }
1428  else
1429  {
1430  // Have no mesh. Don't need addressing
1431  haveVolAddressing = true;
1432  }
1433 
1434  bool haveAreaAddressing = false;
1435  if (areaMeshOnProc[Pstream::myProcNo()])
1436  {
1437  // Read faces (just to know their size)
1438  labelIOList faceLabels
1439  (
1440  IOobject
1441  (
1442  "faceLabels",
1443  areaMeshInstance,
1444  areaMeshSubDir,
1445  runTime,
1447  )
1448  );
1449 
1450  // Check faceProcAddressing
1451  labelIOList faceProcAddressing
1452  (
1453  IOobject
1454  (
1455  "faceProcAddressing",
1456  areaMeshInstance,
1457  areaMeshSubDir,
1458  runTime,
1460  )
1461  );
1462 
1463  haveAreaAddressing =
1464  (
1465  faceProcAddressing.headerOk()
1466  && faceProcAddressing.size() == faceLabels.size()
1467  );
1468  }
1469  else if (areaMeshDetected)
1470  {
1471  // Have no mesh. Don't need addressing
1472  haveAreaAddressing = true;
1473  }
1474 
1475 
1476  // Additionally check for master faces being readable. Could
1477  // do even more checks, e.g. global number of cells same
1478  // as cellProcAddressing
1479 
1480  bool volMeshHaveUndecomposed = false;
1481  bool areaMeshHaveUndecomposed = false;
1482 
1483  if (Pstream::master())
1484  {
1485  Info<< "Checking " << baseRunTime.caseName()
1486  << " for undecomposed volume and area meshes..."
1487  << endl;
1488 
1489  const bool oldParRun = Pstream::parRun(false);
1490 
1491  // Volume
1492  {
1493  faceCompactIOList facesIO
1494  (
1495  IOobject
1496  (
1497  "faces",
1498  volMeshInstance,
1499  volMeshSubDir,
1500  baseRunTime,
1502  ),
1503  label(0)
1504  );
1505  volMeshHaveUndecomposed = facesIO.headerOk();
1506  }
1507 
1508  // Area
1509  if (doFiniteArea)
1510  {
1511  labelIOList labelsIO
1512  (
1513  IOobject
1514  (
1515  "faceLabels",
1516  areaMeshInstance,
1517  areaMeshSubDir,
1518  baseRunTime,
1520  )
1521  );
1522  areaMeshHaveUndecomposed = labelsIO.headerOk();
1523  }
1524 
1525  Pstream::parRun(oldParRun); // Restore parallel state
1526  }
1527 
1529  (
1531  volMeshHaveUndecomposed,
1532  areaMeshHaveUndecomposed
1533  );
1534 
1535  // Report
1536  {
1537  Info<< " volume mesh ["
1538  << volMeshHaveUndecomposed << "] : "
1539  << volMeshInstance << nl
1540  << " area mesh ["
1541  << areaMeshHaveUndecomposed << "] : "
1542  << areaMeshInstance << nl
1543  << endl;
1544  }
1545 
1546 
1547  if
1548  (
1549  !volMeshHaveUndecomposed
1550  || !returnReduceAnd(haveVolAddressing)
1551  )
1552  {
1553  Info<< "No undecomposed mesh. Creating from: "
1554  << volMeshInstance << endl;
1555 
1556  if (areaMeshHaveUndecomposed)
1557  {
1558  areaMeshHaveUndecomposed = false;
1559  Info<< "Also ignore any undecomposed area mesh"
1560  << endl;
1561  }
1562 
1564  (
1565  IOobject
1566  (
1567  regionName,
1568  volMeshInstance,
1569  runTime,
1571  ),
1572  decompose
1573  );
1574  fvMeshTools::setBasicGeometry(volMeshPtr());
1575  fvMesh& mesh = volMeshPtr();
1576 
1577 
1578  Info<< nl << "Reconstructing mesh" << nl << endl;
1579 
1580  // Reconstruct (1 processor)
1581  const label nDestProcs(1);
1582  const labelList finalDecomp(mesh.nCells(), Zero);
1583 
1584  redistributeAndWrite
1585  (
1586  std::move(writeHandler),
1587  baseRunTime,
1588  proc0CaseName,
1589 
1590  // Controls
1591  false, // do not read fields
1592  false, // do not read undecomposed case on proc0
1593  true, // write redistributed files to proc0
1594  overwrite,
1595 
1596  // Decomposition information
1597  nDestProcs,
1598  finalDecomp,
1599 
1600  // For finite-volume
1601  volMeshOnProc,
1602  volMeshInstance,
1603  mesh
1604  );
1605  }
1606 
1607 
1608  // Similarly for finiteArea
1609  // - may or may not have undecomposed mesh
1610  // - may or may not have decomposed meshes
1611 
1612  if
1613  (
1614  areaMeshOnProc.found(true) // ie, areaMeshDetected
1615  &&
1616  (
1617  !areaMeshHaveUndecomposed
1618  || !returnReduceAnd(haveAreaAddressing)
1619  )
1620  )
1621  {
1622  Info<< "Loading area mesh from "
1623  << areaMeshInstance << endl;
1624 
1625  Info<< " getting volume mesh support" << endl;
1626 
1628  (
1629  IOobject
1630  (
1631  regionName,
1632  baseRunTime.timeName(),
1633  baseRunTime,
1635  ),
1636  true // read on master only
1637  );
1638  fvMeshTools::setBasicGeometry(baseMeshPtr());
1639 
1641  (
1642  IOobject
1643  (
1644  regionName,
1645  baseMeshPtr().facesInstance(),
1646  runTime,
1648  ),
1649  decompose
1650  );
1651  fvMeshTools::setBasicGeometry(volMeshPtr());
1652  fvMesh& mesh = volMeshPtr();
1653 
1654  // Read volume proc addressing back to base mesh
1656  (
1658  );
1659 
1660 
1662  (
1663  IOobject
1664  (
1665  regionName,
1666  areaMeshInstance,
1667  runTime,
1669  ),
1670  mesh, // <- The referenced polyMesh (from above)
1671  decompose
1672  );
1673  faMesh& areaMesh = areaMeshPtr();
1674 
1677 
1678  autoPtr<faMesh> areaBaseMeshPtr;
1679 
1680  // Reconstruct using polyMesh distribute map
1681  mapDistributePolyMesh faDistMap
1682  (
1684  (
1685  areaMesh,
1686  distMap(), // The polyMesh distMap
1687  baseMeshPtr(), // Target polyMesh
1688  areaBaseMeshPtr
1689  )
1690  );
1691 
1692  faMeshTools::forceDemandDriven(areaBaseMeshPtr());
1693  faMeshTools::unregisterMesh(areaBaseMeshPtr());
1694 
1695 
1696  if (Pstream::master())
1697  {
1698  Info<< "Setting caseName to " << baseRunTime.caseName()
1699  << " to write reconstructed area mesh." << endl;
1700  runTime.caseName() = baseRunTime.caseName();
1701  const bool oldProcCase(runTime.processorCase(false));
1702 
1703  areaBaseMeshPtr().write();
1704 
1705  // Now we've written all. Reset caseName on master
1706  Info<< "Restoring caseName" << endl;
1707  runTime.caseName() = proc0CaseName;
1708  runTime.processorCase(oldProcCase);
1709  }
1710 
1711  // Update for the reconstructed procAddressing
1713  (
1714  areaBaseMeshPtr(), // Reconstruct location
1715  faDistMap,
1716  false, // decompose=false
1717  std::move(writeHandler),
1718  areaMeshPtr.get() // procMesh
1719  );
1720  }
1721  }
1722 
1723  // Make sure all is finished writing until re-reading in pass2
1724  // below
1725  fileHandler().flush();
1726 
1727 
1728  // Pass2 : read mesh and addressing and reconstruct fields
1729  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1730 
1731  Info<< nl
1732  << "Reconstructing fields" << nl << endl;
1733 
1734  runTime.setTime(timeDirs[0], 0);
1735  baseRunTime.setTime(timeDirs[0], 0);
1736  Info<< "Time = " << runTime.timeName() << endl << endl;
1737 
1738 
1739  // Read undecomposed mesh on master and 'empty' mesh
1740  // (zero faces, point, cells but valid patches and zones) on slaves.
1741  // This is a bit of tricky code and hidden inside fvMeshTools for
1742  // now.
1743  Info<< "Reading undecomposed mesh (on master)" << endl;
1744 
1746  (
1747  IOobject
1748  (
1749  regionName,
1750  baseRunTime.timeName(),
1751  baseRunTime,
1753  ),
1754  true // read on master only
1755  );
1756 
1757  fvMeshTools::setBasicGeometry(baseMeshPtr());
1758 
1759  Info<< "Reading local, decomposed mesh" << endl;
1761  (
1762  IOobject
1763  (
1764  regionName,
1765  baseMeshPtr().facesInstance(),
1766  runTime,
1768  ),
1769  decompose
1770  );
1771  fvMesh& mesh = volMeshPtr();
1772 
1773 
1774  // Similarly for finiteArea
1775  autoPtr<faMesh> areaBaseMeshPtr;
1776  autoPtr<faMesh> areaMeshPtr;
1777  autoPtr<faMeshDistributor> faDistributor;
1778  mapDistributePolyMesh areaDistMap;
1779 
1780  if (areaMeshDetected)
1781  {
1782  areaBaseMeshPtr = faMeshTools::newMesh
1783  (
1784  IOobject
1785  (
1786  regionName,
1787  baseRunTime.timeName(),
1788  baseRunTime,
1790  ),
1791  baseMeshPtr(),
1792  true // read on master only
1793  );
1794 
1795  areaMeshPtr = faMeshTools::loadOrCreateMesh
1796  (
1797  IOobject
1798  (
1799  regionName,
1800  areaBaseMeshPtr().facesInstance(),
1801  runTime,
1803  ),
1804  mesh,
1805  decompose
1806  );
1807 
1808  areaDistMap =
1810  (
1811  areaMeshPtr(),
1812  areaBaseMeshPtr
1813  );
1814 
1815  faMeshTools::forceDemandDriven(areaMeshPtr());
1816 
1817  // Create an appropriate field distributor
1818  faDistributor.reset
1819  (
1820  new faMeshDistributor
1821  (
1822  areaMeshPtr(), // source
1823  areaBaseMeshPtr(), // target
1824  areaDistMap,
1825  Pstream::master() // only write on master
1826  )
1827  );
1828  // Report some messages. Tbd.
1830  }
1831 
1832 
1833  if (writeHandler && Pstream::master())
1834  {
1835  // Remove any left-over empty processor directories created
1836  // by loadOrCreateMesh to get around e.g. collated start-up
1837  // problems. Should not happen in reconstruct mode ...
1838  const bool oldParRun = Pstream::parRun(false);
1840  Pstream::parRun(oldParRun);
1841  }
1842 
1843 
1844  // Read addressing back to base mesh
1846  distMap = fvMeshTools::readProcAddressing(mesh, baseMeshPtr);
1847 
1848  // Construct field mapper
1849  auto fvDistributorPtr =
1851  (
1852  mesh, // source
1853  baseMeshPtr(), // target
1854  distMap(),
1855  UPstream::master() // Write reconstructed on master
1856  );
1857 
1858  // Construct point field mapper
1859  const auto& basePointMesh = pointMesh::New(baseMeshPtr());
1860  const auto& procPointMesh = pointMesh::New(mesh);
1861 
1862  auto pointFieldDistributorPtr =
1864  (
1865  procPointMesh, // source
1866  basePointMesh, // target
1867  distMap(),
1868  false, // delay
1869  UPstream::master() // Write reconstructed on master
1870  );
1871 
1872 
1873  // Since we start from Times[0] and not runTime.timeName() we
1874  // might overlook point motion in the first timestep
1875  // (since mesh.readUpdate() below will not be triggered). Instead
1876  // detect points by hand
1878  {
1879  Info<< " Detected initial mesh motion;"
1880  << " reconstructing points" << nl
1881  << endl;
1882  fvDistributorPtr().reconstructPoints();
1883  }
1884 
1885 
1886  // Loop over all times
1887  forAll(timeDirs, timeI)
1888  {
1889  if (newTimes && masterTimeDirSet.found(timeDirs[timeI].name()))
1890  {
1891  Info<< "Skipping time " << timeDirs[timeI].name()
1892  << nl << endl;
1893  continue;
1894  }
1895 
1896  // Set time for global database
1897  runTime.setTime(timeDirs[timeI], timeI);
1898  baseRunTime.setTime(timeDirs[timeI], timeI);
1899 
1900  Info<< "Time = " << runTime.timeName() << endl << endl;
1901 
1902 
1903  // Check if any new meshes need to be read.
1905 
1906  if (procStat == polyMesh::POINTS_MOVED)
1907  {
1908  Info<< " Detected mesh motion; reconstructing points"
1909  << nl << endl;
1910  fvDistributorPtr().reconstructPoints();
1911  }
1912  else if
1913  (
1914  procStat == polyMesh::TOPO_CHANGE
1915  || procStat == polyMesh::TOPO_PATCH_CHANGE
1916  )
1917  {
1918  Info<< " Detected topology change;"
1919  << " reconstructing addressing" << nl << endl;
1920 
1921  if (baseMeshPtr)
1922  {
1923  // Cannot do a baseMesh::readUpdate() since not all
1924  // processors will have mesh files. So instead just
1925  // recreate baseMesh
1926  baseMeshPtr.clear();
1927  baseMeshPtr = fvMeshTools::newMesh
1928  (
1929  IOobject
1930  (
1931  regionName,
1932  baseRunTime.timeName(),
1933  baseRunTime,
1935  ),
1936  true // read on master only
1937  );
1938  }
1939 
1940  // Re-read procAddressing
1941  distMap =
1942  fvMeshTools::readProcAddressing(mesh, baseMeshPtr);
1943 
1944  // Reset field mappers
1945 
1946  fvDistributorPtr.reset
1947  (
1949  (
1950  mesh, // source
1951  baseMeshPtr(), // target
1952  distMap(),
1953  UPstream::master() // Write reconstruct on master
1954  )
1955  );
1956 
1957  // Construct point field mapper
1958  const auto& basePointMesh = pointMesh::New(baseMeshPtr());
1959  const auto& procPointMesh = pointMesh::New(mesh);
1960 
1961  pointFieldDistributorPtr.reset
1962  (
1964  (
1965  procPointMesh, // source
1966  basePointMesh, // target
1967  distMap(),
1968  false, // delay until later
1969  UPstream::master() // Write reconstruct on master
1970  )
1971  );
1972 
1973  lagrangianDistributorPtr.reset();
1974 
1975  if (areaMeshPtr)
1976  {
1977  Info<< " Discarding finite-area addressing"
1978  << " (TODO)" << nl << endl;
1979 
1980  areaBaseMeshPtr.reset();
1981  areaMeshPtr.reset();
1982  faDistributor.reset();
1983  areaDistMap.clear();
1984  }
1985  }
1986 
1987 
1988  // Get list of objects
1989  IOobjectList objects(mesh, runTime.timeName());
1990 
1991 
1992  // Mesh fields (vol, surface, volInternal)
1993  fvDistributorPtr()
1994  .distributeAllFields(objects, selectedFields);
1995 
1996  // pointfields
1997  // - distribute and write (verbose)
1998  pointFieldDistributorPtr()
1999  .distributeAllFields(objects, selectedFields);
2000 
2001 
2002  // Clouds (note: might not be present on all processors)
2004  (
2005  lagrangianDistributorPtr,
2006  baseMeshPtr(),
2007  mesh,
2008  distMap(),
2009  selectedLagrangianFields
2010  );
2011 
2012  if (faDistributor)
2013  {
2014  faDistributor()
2015  .distributeAllFields(objects, selectedFields);
2016  }
2017 
2018  // If there are any "uniform" directories copy them from
2019  // the master processor
2020  copyUniform
2021  (
2022  fh,
2023  decompose,
2024  reconstruct,
2025  mesh.time().timeName(),
2026  mesh,
2027  baseMeshPtr()
2028  );
2029  // Non-region specific. Note: should do outside region loop
2030  // but would then have to replicate the whole time loop ...
2031  copyUniform
2032  (
2033  fh,
2034  decompose,
2035  reconstruct,
2036  mesh.time().timeName(),
2037  mesh.time(), // runTime
2038  baseMeshPtr().time() // baseRunTime
2039  );
2040  }
2041  }
2042  }
2043  else
2044  {
2045  // decompose or redistribution mode.
2046  // decompose : master : read from parent dir
2047  // slave : dummy mesh
2048  // redistribute : all read mesh or dummy mesh
2049 
2050  // Time coming from processor0 (or undecomposed if no processor0)
2051  scalar masterTime;
2052  if (decompose)
2053  {
2054  // Use base time. This is to handle e.g. startTime = latestTime
2055  // which will not do anything if there are no processor directories
2056  masterTime = timeSelector::selectIfPresent
2057  (
2058  baseRunTime,
2059  args
2060  )[0].value();
2061  }
2062  else
2063  {
2064  masterTime = timeSelector::selectIfPresent
2065  (
2066  runTime,
2067  args
2068  )[0].value();
2069  }
2070  Pstream::broadcast(masterTime);
2071  Info<< "Setting time to that of master or undecomposed case : "
2072  << masterTime << endl;
2073  runTime.setTime(masterTime, 0);
2074  baseRunTime.setTime(masterTime, 0);
2075 
2076  // Save old time name (since might be incremented)
2077  const word oldTimeName(runTime.timeName());
2078 
2079  forAll(regionNames, regioni)
2080  {
2081  const word& regionName = regionNames[regioni];
2083 
2084  const fileName volMeshSubDir(regionDir/polyMesh::meshSubDir);
2085  const fileName areaMeshSubDir(regionDir/faMesh::meshSubDir);
2086 
2087  Info<< nl << nl
2088  << (decompose ? "Decomposing" : "Redistributing")
2089  << " mesh " << regionDir << nl << endl;
2090 
2091 
2092  // Get time instance directory
2093  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
2094  // At this point we should be able to read at least a mesh on
2095  // processor0. Note the changing of the processor0 casename to
2096  // enforce it to read/write from the undecomposed case
2097 
2098  fileName volMeshMasterInstance;
2099  fileName areaMeshMasterInstance;
2100 
2101  // Assume to be true
2102  bool volMeshHaveUndecomposed = true;
2103  bool areaMeshHaveUndecomposed = doFiniteArea;
2104 
2105  if (Pstream::master())
2106  {
2107  if (decompose)
2108  {
2109  Info<< "Checking undecomposed mesh in case: "
2110  << baseRunTime.caseName() << endl;
2111  runTime.caseName() = baseRunTime.caseName();
2112  runTime.processorCase(false);
2113  }
2114 
2115  const bool oldParRun = Pstream::parRun(false);
2116  volMeshMasterInstance = runTime.findInstance
2117  (
2118  volMeshSubDir,
2119  "faces",
2121  );
2122 
2123  if (doFiniteArea)
2124  {
2125  areaMeshMasterInstance = runTime.findInstance
2126  (
2127  areaMeshSubDir,
2128  "faceLabels",
2130  );
2131 
2132  // Note: findInstance returns "constant" even if not found,
2133  // so recheck now for a false positive.
2134 
2135  if ("constant" == areaMeshMasterInstance)
2136  {
2137  const boolList areaMeshOnProc
2138  (
2139  haveMeshFile
2140  (
2141  runTime,
2142  areaMeshMasterInstance/areaMeshSubDir,
2143  "faceLabels",
2144  false // verbose=false
2145  )
2146  );
2147 
2148  if (areaMeshOnProc.empty() || !areaMeshOnProc[0])
2149  {
2150  areaMeshHaveUndecomposed = false;
2151  }
2152  }
2153  }
2154 
2155  Pstream::parRun(oldParRun); // Restore parallel state
2156 
2157  if (decompose)
2158  {
2159  Info<< " volume mesh ["
2160  << volMeshHaveUndecomposed << "] : "
2161  << volMeshMasterInstance << nl
2162  << " area mesh ["
2163  << areaMeshHaveUndecomposed << "] : "
2164  << areaMeshMasterInstance << nl
2165  << nl << nl;
2166 
2167  // Restoring caseName
2168  runTime.caseName() = proc0CaseName;
2169  runTime.processorCase(oldProcCase);
2170  }
2171  }
2172 
2174  (
2176  volMeshHaveUndecomposed,
2177  areaMeshHaveUndecomposed,
2178  volMeshMasterInstance,
2179  areaMeshMasterInstance
2180  );
2181 
2182  // Check processors have meshes
2183  // - check for 'faces' file (polyMesh)
2184  // - check for 'faceLabels' file (faMesh)
2185  boolList volMeshOnProc;
2186  boolList areaMeshOnProc;
2187 
2188  volMeshOnProc = haveMeshFile
2189  (
2190  runTime,
2191  volMeshMasterInstance/volMeshSubDir,
2192  "faces"
2193  );
2194 
2195  if (doFiniteArea)
2196  {
2197  areaMeshOnProc = haveMeshFile
2198  (
2199  runTime,
2200  areaMeshMasterInstance/areaMeshSubDir,
2201  "faceLabels"
2202  );
2203  }
2204 
2205  // Prior to loadOrCreateMesh, note which meshes already exist
2206  // for the current file handler.
2207  // - where mesh would be written if it didn't exist already.
2208  fileNameList volMeshDir(Pstream::nProcs());
2209  {
2210  volMeshDir[Pstream::myProcNo()] =
2211  (
2212  fileHandler().objectPath
2213  (
2214  IOobject
2215  (
2216  "faces",
2217  volMeshMasterInstance/volMeshSubDir,
2218  runTime
2219  ),
2220  word::null
2221  ).path()
2222  );
2223 
2224  Pstream::allGatherList(volMeshDir);
2225 
2226  if (optVerbose && Pstream::master())
2227  {
2228  Info<< "Per processor faces dirs:" << nl
2229  << '(' << nl;
2230 
2231  for (const int proci : Pstream::allProcs())
2232  {
2233  Info<< " "
2234  << runTime.relativePath(volMeshDir[proci]);
2235 
2236  if (!volMeshOnProc[proci])
2237  {
2238  Info<< " [missing]";
2239  }
2240  Info<< nl;
2241  }
2242  Info<< ')' << nl << endl;
2243  }
2244  }
2245 
2246  fileNameList areaMeshDir(Pstream::nProcs());
2247  if (doFiniteArea)
2248  {
2249  areaMeshDir[Pstream::myProcNo()] =
2250  (
2251  fileHandler().objectPath
2252  (
2253  IOobject
2254  (
2255  "faceLabels",
2256  areaMeshMasterInstance/areaMeshSubDir,
2257  runTime
2258  ),
2259  word::null
2260  ).path()
2261  );
2262 
2263  Pstream::allGatherList(areaMeshDir);
2264 
2265  if (optVerbose && Pstream::master())
2266  {
2267  Info<< "Per processor faceLabels dirs:" << nl
2268  << '(' << nl;
2269 
2270  for (const int proci : Pstream::allProcs())
2271  {
2272  Info<< " "
2273  << runTime.relativePath(areaMeshDir[proci]);
2274 
2275  if (!areaMeshOnProc[proci])
2276  {
2277  Info<< " [missing]";
2278  }
2279  Info<< nl;
2280  }
2281  Info<< ')' << nl << endl;
2282  }
2283  }
2284 
2285 
2286  // Load mesh (or create dummy one)
2287  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2288 
2289  if (Pstream::master() && decompose)
2290  {
2291  Info<< "Setting caseName to " << baseRunTime.caseName()
2292  << " to read undecomposed mesh" << endl;
2293  runTime.caseName() = baseRunTime.caseName();
2294  runTime.processorCase(false);
2295  }
2296 
2297  // Volume mesh
2299  (
2300  IOobject
2301  (
2302  regionName,
2303  volMeshMasterInstance,
2304  runTime,
2306  ),
2307  decompose
2308  );
2309  fvMesh& mesh = volMeshPtr();
2310 
2311 
2312  // Area mesh
2313 
2314  autoPtr<faMesh> areaMeshPtr;
2315 
2316  // Decomposing: must have an undecomposed mesh
2317  // Redistributing: have any proc mesh
2318  if
2319  (
2320  doFiniteArea
2321  &&
2322  (
2323  decompose
2324  ? areaMeshHaveUndecomposed
2325  : areaMeshOnProc.found(true)
2326  )
2327  )
2328  {
2329  areaMeshPtr = faMeshTools::loadOrCreateMesh
2330  (
2331  IOobject
2332  (
2333  regionName,
2334  areaMeshMasterInstance,
2335  runTime,
2337  ),
2338  mesh, // <- The referenced polyMesh (from above)
2339  decompose
2340  );
2341 
2342  faMeshTools::forceDemandDriven(*areaMeshPtr);
2343  faMeshTools::unregisterMesh(*areaMeshPtr);
2344  }
2345 
2346 
2347  if (writeHandler)
2348  {
2349  // Remove any left-over empty processor directories created
2350  // by loadOrCreateMesh to get around the collated start-up
2351  // problems
2352  Info<< "Removing left-over empty processor directories" << nl;
2353 
2354  if (Pstream::master()) //fileHandler().comm()))
2355  {
2356  const auto myProci = UPstream::myProcNo(); //comm()
2357  const auto& procs = UPstream::procID
2358  (
2360  );
2361  const bool oldParRun = Pstream::parRun(false);
2362  for (const auto proci : procs)
2363  {
2364  if
2365  (
2366  !volMeshOnProc[proci]
2367  && volMeshDir[proci] != volMeshDir[myProci]
2368  )
2369  {
2370  Foam::rmDir(volMeshDir[proci], true); // silent
2371  }
2372 
2373  if
2374  (
2375  !areaMeshOnProc[proci]
2376  && areaMeshDir[proci] != areaMeshDir[myProci]
2377  )
2378  {
2379  Foam::rmDir(areaMeshDir[proci], true); // silent
2380  }
2381 
2382  // Remove empty processor directories
2383  // Eg, <path-name>/processorN/constant/polyMesh
2384  // to <path-name>/processorN
2385  if (proci != myProci)
2386  {
2388  (
2389  volMeshDir[proci].path().path()
2390  );
2391  }
2392  }
2393 
2394  // Remove empty directory
2396 
2397  Pstream::parRun(oldParRun);
2398  }
2399  }
2400 
2401 
2402  if (Pstream::master() && decompose)
2403  {
2404  Info<< "Restoring caseName" << endl;
2405  runTime.caseName() = proc0CaseName;
2406  runTime.processorCase(oldProcCase);
2407  }
2408 
2409  const label nOldCells = mesh.nCells();
2410 
2411  // const label nOldAreaFaces =
2412  // (areaMeshPtr ? areaMeshPtr().nFaces() : 0);
2413  //
2414  //Pout<< "Loaded mesh : nCells:" << nOldCells
2415  // << " nPatches:" << mesh.boundaryMesh().size() << endl;
2416  //Pout<< "Loaded area mesh : nFaces:" << nOldAreaFaces << endl;
2417 
2418  // Determine decomposition
2419  // ~~~~~~~~~~~~~~~~~~~~~~~
2420 
2421  label nDestProcs;
2422  labelList finalDecomp;
2423  determineDecomposition
2424  (
2425  baseRunTime,
2426  decompDictFile,
2427  decompose,
2428  proc0CaseName,
2429  mesh,
2430  writeCellDist,
2431 
2432  nDestProcs,
2433  finalDecomp
2434  );
2435 
2436 
2437  if (dryrun)
2438  {
2439  if (!Pstream::master())
2440  {
2441  if (areaMeshPtr && !areaMeshOnProc[Pstream::myProcNo()])
2442  {
2443  // Remove dummy mesh created by loadOrCreateMesh
2444  const bool oldParRun = Pstream::parRun(false);
2445  areaMeshPtr->removeFiles();
2446  Pstream::parRun(oldParRun); // Restore parallel state
2447  }
2448 
2449  if (!volMeshOnProc[Pstream::myProcNo()])
2450  {
2451  // Remove dummy mesh created by loadOrCreateMesh
2452  const bool oldParRun = Pstream::parRun(false);
2453  mesh.removeFiles();
2454  // Silent rmdir
2455  Foam::rmDir(mesh.objectRegistry::objectPath(), true);
2456  Pstream::parRun(oldParRun); // Restore parallel state
2457  }
2458  }
2459  continue;
2460  }
2461 
2462  // Area fields first. Read and deregister
2464  if (areaMeshPtr)
2465  {
2466  areaFields.read
2467  (
2468  baseRunTime,
2469  proc0CaseName,
2470  decompose,
2471 
2472  areaMeshOnProc,
2473  areaMeshMasterInstance,
2474  (*areaMeshPtr)
2475  );
2476  }
2477 
2478 
2479  // Detect lagrangian fields
2480  if (Pstream::master() && decompose)
2481  {
2482  runTime.caseName() = baseRunTime.caseName();
2483  runTime.processorCase(false);
2484  }
2485 
2486  // Read lagrangian fields and store on cloud (objectRegistry)
2488  (
2490  (
2491  mesh,
2492  selectedLagrangianFields
2493  )
2494  );
2495 
2496  if (Pstream::master() && decompose)
2497  {
2498  runTime.caseName() = proc0CaseName;
2499  runTime.processorCase(oldProcCase);
2500  }
2501 
2502  // Load fields, do all distribution (mesh and fields)
2503  // - but not lagrangian fields; these are done later
2504  autoPtr<mapDistributePolyMesh> distMap = redistributeAndWrite
2505  (
2506  std::move(writeHandler),
2507  baseRunTime,
2508  proc0CaseName,
2509 
2510  // Controls
2511  true, // read fields
2512  decompose, // decompose, i.e. read from undecomposed case
2513  false, // no reconstruction
2514  overwrite,
2515 
2516  // Decomposition information
2517  nDestProcs,
2518  finalDecomp,
2519 
2520  // For finite volume
2521  volMeshOnProc,
2522  volMeshMasterInstance,
2523  mesh
2524  );
2525 
2526 
2527  // Redistribute any clouds
2529  (
2530  lagrangianDistributorPtr,
2531  mesh,
2532  nOldCells,
2533  distMap(),
2534  clouds
2535  );
2536 
2537 
2538  // Redistribute area fields
2539 
2540  mapDistributePolyMesh faDistMap;
2541  autoPtr<faMesh> areaProcMeshPtr;
2542 
2543  if (areaMeshPtr)
2544  {
2545  faDistMap = faMeshDistributor::distribute
2546  (
2547  areaMeshPtr(),
2548  distMap(),
2549  areaProcMeshPtr
2550  );
2551 
2552  // Force recreation of everything that might vaguely
2553  // be used by patches:
2554 
2555  faMeshTools::forceDemandDriven(areaProcMeshPtr());
2556 
2557 
2558  if (reconstruct)
2559  {
2560  if (Pstream::master())
2561  {
2562  Info<< "Setting caseName to " << baseRunTime.caseName()
2563  << " to write reconstructed mesh (and fields)."
2564  << endl;
2565  runTime.caseName() = baseRunTime.caseName();
2566  const bool oldProcCase(runTime.processorCase(false));
2567  //const bool oldParRun = Pstream::parRun(false);
2568 
2569  areaProcMeshPtr->write();
2570 
2571  // Now we've written all. Reset caseName on master
2572  Info<< "Restoring caseName" << endl;
2573  runTime.caseName() = proc0CaseName;
2574  runTime.processorCase(oldProcCase);
2575  }
2576  }
2577  else
2578  {
2579  autoPtr<fileOperation> defaultHandler;
2580  if (writeHandler)
2581  {
2582  defaultHandler = fileHandler(std::move(writeHandler));
2583  }
2584 
2586  (
2587  IOobject
2588  (
2589  "procAddressing",
2590  areaProcMeshPtr->facesInstance(),
2592  areaProcMeshPtr->thisDb(),
2595  false
2596  ),
2597  faDistMap
2598  ).write();
2599 
2600  areaProcMeshPtr->write();
2601 
2602  if (defaultHandler)
2603  {
2604  writeHandler = fileHandler(std::move(defaultHandler));
2605  }
2606 
2607  if (decompose)
2608  {
2610  (
2611  areaProcMeshPtr(),
2612  faDistMap,
2613  decompose,
2614  std::move(writeHandler)
2615  );
2616  }
2617  }
2618 
2619  Info<< "Written redistributed mesh to "
2620  << areaProcMeshPtr->facesInstance() << nl << endl;
2621 
2622  faMeshDistributor distributor
2623  (
2624  areaMeshPtr(), // source
2625  areaProcMeshPtr(), // target
2626  faDistMap
2627  );
2628 
2629  areaFields.redistributeAndWrite(distributor, true);
2630  }
2631 
2632  // Copy region-specific uniform
2633  // (e.g. solid/uniform/cumulativeContErr)
2634  copyUniform
2635  (
2636  fh,
2637  decompose,
2638  reconstruct,
2639  oldTimeName, // provided read time
2640  mesh, // read location is mesh (but oldTimeName)
2641  mesh // write location is mesh
2642  );
2643  }
2644 
2645  // Copy non-region specific uniform (e.g. uniform/time)
2646  copyUniform
2647  (
2648  fh,
2649  decompose,
2650  reconstruct,
2651  oldTimeName, // provided read time
2652  ( // read location
2653  decompose
2654  ? baseRunTime
2655  : runTime
2656  ),
2657  runTime // writing location
2658  );
2659  }
2660 
2661 
2662  Info<< "End\n" << endl;
2663 
2664  return 0;
2665 }
2666 
2667 
2668 // ************************************************************************* //
Foam::surfaceFields.
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:584
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:88
static autoPtr< faMesh > newMesh(const IOobject &io, const polyMesh &pMesh, const bool masterOnlyReading, const bool verbose=false)
Read mesh or create dummy mesh (0 faces, >0 patches).
Definition: faMeshTools.C:61
Holds a reference to the original mesh (the baseMesh) and optionally to a subset of that mesh (the su...
virtual fileName dirPath(const bool checkGlobal, const IOobject &io, const bool search=true) const =0
Search for a directory. checkGlobal : also check undecomposed.
static void noFunctionObjects(bool addWithOption=false)
Remove &#39;-noFunctionObjects&#39; option and ignore any occurrences.
Definition: argList.C:514
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:453
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
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")
fileName path() const
Return path.
Definition: Time.H:449
A class for handling file names.
Definition: fileName.H:71
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
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:853
void off()
Switch the function objects off.
word findInstance(const fileName &dir, const word &name=word::null, IOobjectOption::readOption rOpt=IOobjectOption::MUST_READ, const word &stopInstance=word::null) const
Return time instance (location) of dir that contains the file name (eg, used in reading mesh data)...
Definition: Time.C:777
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:578
static void unset(bool verbose=false)
Deactivate SIGFPE signal handler and NaN memory initialisation.
Definition: sigFpe.C:234
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:841
virtual bool write(const bool valid=true) const
Write mesh.
Definition: faMesh.C:1029
virtual bool write(const bool valid=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1072
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create a new MeshObject.
Definition: MeshObject.C:41
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:748
const fileName & caseName() const noexcept
Return case name.
Definition: TimePathsI.H:55
const labelList & processorPatches() const noexcept
Return list of processor patch labels.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
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 the UList is empty (ie, size() is zero)
Definition: UListI.H:420
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:402
wordList names() const
The unsorted names of all objects.
virtual labelList decompose(const pointField &points, const scalarField &pointWeights) const
Return the wanted processor number for every coordinate.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
bool found(const T &val, label pos=0) const
True if the value if found in the list.
Definition: UListI.H:258
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
void clear() noexcept
Same as reset(nullptr)
Definition: autoPtr.H:255
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:80
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:416
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:365
const fileName & rootPath() const noexcept
Return root path.
Definition: TimePathsI.H:43
autoPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler.
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
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)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:688
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:361
static label worldComm
Default world communicator (all processors). May differ from globalComm if local worlds are in use...
Definition: UPstream.H:361
A IOmapDistributePolyMesh wrapper for using referenced external data.
Distributor/redistributor for point fields, uses a two (or three) stage construction.
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
instantList select(const instantList &times) const
Select a list of Time values that are within the ranges.
Definition: timeSelector.C:88
virtual const objectRegistry & thisDb() const
Return reference to the mesh database.
Definition: faMesh.C:708
bool processorCase() const noexcept
Return true if this is a processor case.
Definition: TimePathsI.H:29
An encapsulation of filesystem-related operations.
Definition: fileOperation.H:63
static mapDistributePolyMesh readProcAddressing(const faMesh &mesh, const autoPtr< faMesh > &baseMeshPtr)
Read decompose/reconstruct addressing.
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all processes in communicator.
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:100
virtual const objectRegistry & thisDb() const
Return the object registry - resolve conflict polyMesh/lduMesh.
Definition: fvMesh.H:377
Neighbour processor patch.
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:413
void removeEmptyDirs(const fileName &path)
Remove empty directories from bottom up.
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:813
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:752
Foam::word regionName(Foam::polyMesh::defaultRegion)
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator) is 1 for serial run.
Definition: UPstream.H:656
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:618
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
static void gatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:847
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
void setSize(const label n)
Alias for resize()
Definition: List.H:289
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:567
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
virtual readUpdateState readUpdate()
Update the mesh based on the mesh files saved in time.
Definition: fvMesh.C:668
void removeFiles(const fileName &instanceDir) const
Remove all files from mesh instance.
Definition: polyMesh.C:1323
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)
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:495
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:397
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
List helper to append y unique elements onto the end of x.
Definition: ListOps.H:689
const word & system() const noexcept
Return system name.
Definition: TimePathsI.H:95
static int verbose_
Output verbosity when writing.
static void addVerboseOption(const string &usage, bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:505
Simple container to manage read/write, redistribute finiteArea fields.
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:444
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:47
void removeEmptyDir(const fileName &path)
Remove empty directory.
Finite area area (element) fields.
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1293
static instantList selectIfPresent(Time &runTime, const argList &args)
If any time option provided return the set of times (as select0) otherwise return just the current ti...
Definition: timeSelector.C:265
virtual void setTime(const Time &t)
Reset the time and time-index to those of the given time.
Definition: Time.C:977
Abstract base class for domain decomposition.
int neighbProcNo() const
Return neighbour processor number.
MeshObject wrapper of decompositionMethod.
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:727
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
static void combineReduce(const List< commsStruct > &comms, T &value, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors...
bool rmDir(const fileName &directory, const bool silent=false, const bool emptyOnly=false)
Remove a directory and its contents recursively,.
Definition: POSIX.C:1386
virtual bool cp(const fileName &src, const fileName &dst, const bool followLink=true) const =0
Copy, recursively if necessary, the source to the destination.
void reconstructLagrangian(autoPtr< parLagrangianDistributor > &distributorPtr, const fvMesh &baseMesh, const fvMesh &mesh, const mapDistributePolyMesh &distMap, const wordRes &selectedFields)
static word timeName(const scalar t, const int precision=precision_)
Return time name of given scalar time formatted with the given precision.
Definition: Time.C:760
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:89
int debug
Static debugging option.
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 void writeProcAddressing(const faMesh &mesh, const mapDistributePolyMesh &faDistMap, const bool decompose, autoPtr< fileOperation > &&writeHandler, const faMesh *procMesh=nullptr)
Write decompose/reconstruct addressing.
static autoPtr< faMesh > loadOrCreateMesh(const IOobject &io, const polyMesh &pMesh, const bool decompose, const bool verbose=false)
Definition: faMeshTools.C:243
static void broadcasts(const label comm, Type &arg1, Args &&... args)
Broadcast multiple items to all processes in communicator.
fileName path() const
Return the full path to the (processor local) case.
Definition: argListI.H:74
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))
void removeFiles(const fileName &instanceDir) const
Remove all files from mesh instance.
Definition: faMesh.C:736
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:698
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: faMesh.C:696
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> reconstruct(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
static instantList findTimes(const fileName &directory, const word &constantName="constant")
Search a given directory for valid time directories.
Definition: TimePaths.C:133
static void unregisterMesh(const faMesh &mesh)
Unregister the faMesh from its associated polyMesh to prevent triggering on polyMesh changes etc...
Definition: faMeshTools.C:31
PtrList< unmappedPassivePositionParticleCloud > readLagrangian(const fvMesh &mesh, const wordList &cloudNames, const wordRes &selectedFields)
instantList times() const
Search the case for valid time directories.
Definition: TimePaths.C:142
void setInstance(const fileName &instance, const IOobjectOption::writeOption wOpt=IOobject::AUTO_WRITE)
Set the instance for mesh files.
Definition: polyMeshIO.C:29
const functionObjectList & functionObjects() const
Return the list of function objects.
Definition: Time.H:662
#define WarningInFunction
Report a warning using Foam::Warning.
const fileName & globalCaseName() const noexcept
Return global case name.
Definition: TimePathsI.H:49
static List< int > & procID(const label communicator)
Process IDs within a given communicator.
Definition: UPstream.H:704
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
label nCells() const noexcept
Number of mesh cells.
const word & regionDir
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:79
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
Mesh data needed to do the Finite Area discretisation.
Definition: areaFaMesh.H:47
label nPointFields
Nothing to be read.
Automatically write from objectRegistry::writeObject()
const dictionary & controlDict() const
Return read access to the controlDict dictionary.
Definition: Time.H:457
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:58
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:73
readUpdateState
Enumeration defining the state of the mesh after a read update.
Definition: polyMesh.H:89
Registry of regIOobjects.
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
UPtrList< const regIOobject > sorted() const
Return sorted list of objects.
virtual bool write(const bool valid=true) const
Write using setting from DB.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
Foam::argList args(argc, argv)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
static void writeProcAddressing(const fvMesh &procMesh, const mapDistributePolyMesh &map, const bool decompose, autoPtr< fileOperation > &&writeHandler)
Write addressing if decomposing (1 to many) or reconstructing (many to 1)
static autoPtr< mapDistributePolyMesh > readProcAddressing(const fvMesh &procMesh, const autoPtr< fvMesh > &baseMeshPtr)
Read procAddressing components (reconstructing)
virtual fileName objectPath(const IOobject &io, const word &typeName) const
Generate disk file name for object. Opposite of filePath.
static void forceDemandDriven(faMesh &mesh)
Force creation of everything that might vaguely be used by patches.
Definition: faMeshTools.C:43
static void setBasicGeometry(fvMesh &mesh)
Set the fvGeometryScheme to basic (to avoid parallel communication)
Definition: fvMeshTools.C:423
int verbose() const noexcept
Return the verbose flag.
Definition: argListI.H:121
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
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
static autoPtr< fileOperation > NewUncollated()
Static construct the commonly used uncollatedFileOperation.
label localSize() const
My local size.
Definition: globalIndexI.H:225
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:157