decomposePar.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) 2016-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  decomposePar
29 
30 Group
31  grpParallelUtilities
32 
33 Description
34  Automatically decomposes a mesh and fields of a case for parallel
35  execution of OpenFOAM.
36 
37 Usage
38  \b decomposePar [OPTIONS]
39 
40  Options:
41  - \par -allRegions
42  Decompose all regions in regionProperties. Does not check for
43  existence of processor*.
44 
45  - \par -case <dir>
46  Specify case directory to use (instead of the cwd).
47 
48  - \par -cellDist
49  Write the cell distribution as a labelList, for use with 'manual'
50  decomposition method and as a VTK or volScalarField for visualization.
51 
52  - \par -constant
53  Include the 'constant/' dir in the times list.
54 
55  - \par -copyUniform
56  Copy any \a uniform directories too.
57 
58  - \par -copyZero
59  Copy \a 0 directory to processor* rather than decompose the fields.
60 
61  - \par -debug-switch <name=val>
62  Specify the value of a registered debug switch. Default is 1
63  if the value is omitted. (Can be used multiple times)
64 
65  - \par -decomposeParDict <file>
66  Use specified file for decomposePar dictionary.
67 
68  - \par -dry-run
69  Test without writing the decomposition. Changes -cellDist to
70  only write VTK output.
71 
72  - \par -fields
73  Use existing geometry decomposition and convert fields only.
74 
75  - \par fileHandler <handler>
76  Override the file handler type.
77 
78  - \par -force
79  Remove any existing \a processor subdirectories before decomposing the
80  geometry.
81 
82  - \par -ifRequired
83  Only decompose the geometry if the number of domains has changed from a
84  previous decomposition. No \a processor subdirectories will be removed
85  unless the \a -force option is also specified. This option can be used
86  to avoid redundant geometry decomposition (eg, in scripts), but should
87  be used with caution when the underlying (serial) geometry or the
88  decomposition method etc. have been changed between decompositions.
89 
90  - \par -info-switch <name=val>
91  Specify the value of a registered info switch. Default is 1
92  if the value is omitted. (Can be used multiple times)
93 
94  - \par -latestTime
95  Select the latest time.
96 
97  - \par -lib <name>
98  Additional library or library list to load (can be used multiple times).
99 
100  - \par -noFunctionObjects
101  Do not execute function objects.
102 
103  - \par -noSets
104  Skip decomposing cellSets, faceSets, pointSets.
105 
106  - \par -noZero
107  Exclude the \a 0 dir from the times list.
108 
109  - \par -opt-switch <name=val>
110  Specify the value of a registered optimisation switch (int/bool).
111  Default is 1 if the value is omitted. (Can be used multiple times)
112 
113  - \par -region <regionName>
114  Decompose named region. Does not check for existence of processor*.
115 
116  - \par -time <ranges>
117  Override controlDict settings and decompose selected times. Does not
118  re-decompose the mesh i.e. does not handle moving mesh or changing
119  mesh cases. Eg, ':10,20 40:70 1000:', 'none', etc.
120 
121  - \par -verbose
122  Additional verbosity.
123 
124  - \par -doc
125  Display documentation in browser.
126 
127  - \par -doc-source
128  Display source code in browser.
129 
130  - \par -help
131  Display short help and exit.
132 
133  - \par -help-man
134  Display full help (manpage format) and exit.
135 
136  - \par -help-notes
137  Display help notes (description) and exit.
138 
139  - \par -help-full
140  Display full help and exit.
141 
142 \*---------------------------------------------------------------------------*/
143 
144 #include "argList.H"
145 #include "timeSelector.H"
146 #include "OSspecific.H"
147 #include "IOobjectList.H"
148 
149 #include "decompositionModel.H"
150 #include "domainDecomposition.H"
152 
153 #include "regionProperties.H"
154 
155 #include "fieldsDistributor.H"
156 
157 #include "fvFieldDecomposer.H"
158 #include "pointFields.H"
159 #include "pointFieldDecomposer.H"
160 
162 
163 #include "emptyFaPatch.H"
164 #include "faFieldDecomposer.H"
165 #include "faMeshDecomposition.H"
166 
167 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
168 
169 namespace Foam
170 {
171 
172 // Read proc addressing at specific instance.
173 // Uses polyMesh/fvMesh meshSubDir by default
174 autoPtr<labelIOList> procAddressing
175 (
176  const fvMesh& procMesh,
177  const word& name,
178  const word& instance,
179  const word& local = fvMesh::meshSubDir
180 )
181 {
183  (
184  IOobject
185  (
186  name,
187  instance,
188  local,
189  procMesh,
192  false // do not register
193  )
194  );
195 }
196 
197 
198 // Read proc addressing at specific instance.
199 // Uses the finiteArea meshSubDir
200 autoPtr<labelIOList> faProcAddressing
201 (
202  const fvMesh& procMesh,
203  const word& name,
204  const word& instance,
205  const word& local = faMesh::meshSubDir
206 )
207 {
208  return procAddressing(procMesh, name, instance, local);
209 }
210 
211 
212 // Return cached or read proc addressing from facesInstance
213 const labelIOList& procAddressing
214 (
215  const PtrList<fvMesh>& procMeshList,
216  const label proci,
217  const word& name,
218  PtrList<labelIOList>& procAddressingList
219 )
220 {
221  const fvMesh& procMesh = procMeshList[proci];
222 
223  if (!procAddressingList.set(proci))
224  {
225  procAddressingList.set
226  (
227  proci,
228  procAddressing(procMesh, name, procMesh.facesInstance())
229  );
230  }
231  return procAddressingList[proci];
232 }
233 
234 
235 void decomposeUniform
236 (
237  const bool copyUniform,
238  const domainDecomposition& mesh,
239  const Time& processorDb,
240  const word& regionDir = word::null
241 )
242 {
243  const Time& runTime = mesh.time();
244 
245  // Any uniform data to copy/link?
246  const fileName uniformDir(regionDir/"uniform");
247 
248  if (fileHandler().isDir(runTime.timePath()/uniformDir))
249  {
250  Info<< "Detected additional non-decomposed files in "
251  << runTime.timePath()/uniformDir
252  << endl;
253 
254  // Bit of trickery to synthesise the correct directory base,
255  // e.g. processors4/0.01
256  const fileName timePath = fileHandler().objectPath
257  (
258  IOobject
259  (
260  "dummy",
261  runTime.timeName(),
262  processorDb
263  ),
264  word::null
265  ).path();
266 
267  // If no fields have been decomposed the destination
268  // directory will not have been created so make sure.
269  mkDir(timePath);
270 
271  if (copyUniform || mesh.distributed())
272  {
273  if (!fileHandler().exists(timePath/uniformDir))
274  {
275  fileHandler().cp
276  (
277  runTime.timePath()/uniformDir,
278  timePath/uniformDir
279  );
280  }
281  }
282  else
283  {
284  // Link with relative paths
285  string parentPath = string("..")/"..";
286 
287  if (!regionDir.empty())
288  {
289  parentPath = parentPath/"..";
290  }
291 
292  fileName currentDir(cwd());
293  chDir(timePath);
294 
295  if (!fileHandler().exists(uniformDir))
296  {
297  fileHandler().ln
298  (
299  parentPath/runTime.timeName()/uniformDir,
300  uniformDir
301  );
302  }
303  chDir(currentDir);
304  }
305  }
306 }
307 
308 } // End namespace Foam
309 
310 
311 using namespace Foam;
312 
313 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
314 
315 int main(int argc, char *argv[])
316 {
318  (
319  "Decompose a mesh and fields of a case for parallel execution"
320  );
321 
324  (
325  "decomposeParDict",
326  "file",
327  "Alternative decomposePar dictionary file"
328  );
329 
330  #include "addAllRegionOptions.H"
331 
333  (
334  "Test without writing the decomposition. "
335  "Changes -cellDist to only write VTK output."
336  );
337  argList::addVerboseOption("Additional verbosity");
339  (
340  "domains",
341  "N",
342  "Override numberOfSubdomains (-dry-run only)",
343  true // Advanced option
344  );
346  (
347  "method",
348  "name",
349  "Override decomposition method (-dry-run only)",
350  true // Advanced option
351  );
352 
354  (
355  "no-finite-area",
356  "Suppress finiteArea mesh/field decomposition",
357  true // Advanced option
358  );
359 
361  (
362  "no-lagrangian",
363  "Suppress lagrangian (cloud) decomposition",
364  true // Advanced option
365  );
366 
368  (
369  "cellDist",
370  "Write cell distribution as a labelList - for use with 'manual' "
371  "decomposition method and as a volScalarField for visualization."
372  );
374  (
375  "copyZero",
376  "Copy 0/ directory to processor*/ rather than decompose the fields"
377  );
379  (
380  "copyUniform",
381  "Copy any uniform/ directories too"
382  );
384  (
385  "fields",
386  "Use existing geometry decomposition and convert fields only"
387  );
389  (
390  "no-fields",
391  "Suppress conversion of fields (volume, finite-area, lagrangian)"
392  );
393 
395  (
396  "no-sets",
397  "Skip decomposing cellSets, faceSets, pointSets"
398  );
399  argList::addOptionCompat("no-sets", {"noSets", 2106});
400 
402  (
403  "force",
404  "Remove existing processor*/ subdirs before decomposing the geometry"
405  );
407  (
408  "ifRequired",
409  "Only decompose geometry if the number of domains has changed"
410  );
411 
412  // Allow explicit -constant, have zero from time range
413  timeSelector::addOptions(true, false); // constant(true), zero(false)
414 
415  #include "setRootCase.H"
416 
417  const bool writeCellDist = args.found("cellDist");
418 
419  // Most of these are ignored for dry-run (not triggered anywhere)
420  const bool copyZero = args.found("copyZero");
421  const bool copyUniform = args.found("copyUniform");
422  const bool decomposeSets = !args.found("no-sets");
423 
424  const bool decomposeIfRequired = args.found("ifRequired");
425 
426  const bool doDecompFields = !args.found("no-fields");
427  const bool doFiniteArea = !args.found("no-finite-area");
428  const bool doLagrangian = !args.found("no-lagrangian");
429 
430  bool decomposeFieldsOnly = args.found("fields");
431  bool forceOverwrite = args.found("force");
432 
433 
434  // Set time from database
435  #include "createTime.H"
436 
437  // Allow override of time (unless dry-run)
438  instantList times;
439  if (args.dryRun())
440  {
441  Info<< "\ndry-run: ignoring -copy*, -fields, -force, time selection"
442  << nl;
443  }
444  else
445  {
446  if (decomposeFieldsOnly && !doDecompFields)
447  {
449  << "Options -fields and -no-fields are mutually exclusive"
450  << " ... giving up" << nl
451  << exit(FatalError);
452  }
453 
454  if (!doDecompFields)
455  {
456  Info<< "Skip decompose of all fields" << nl;
457  }
458  if (!doFiniteArea)
459  {
460  Info<< "Skip decompose of finiteArea mesh/fields" << nl;
461  }
462  if (!doLagrangian)
463  {
464  Info<< "Skip decompose of lagrangian positions/fields" << nl;
465  }
466 
468  }
469 
470 
471  // Allow override of decomposeParDict location
472  fileName decompDictFile(args.get<fileName>("decomposeParDict", ""));
473  if (!decompDictFile.empty() && !decompDictFile.isAbsolute())
474  {
475  decompDictFile = runTime.globalPath()/decompDictFile;
476  }
477 
478  // Get region names
479  #include "getAllRegionOptions.H"
480 
481  const bool optRegions =
483 
485  {
486  Info<< "Using region: " << regionNames[0] << nl << endl;
487  }
488 
489  forAll(regionNames, regioni)
490  {
491  const word& regionName = regionNames[regioni];
493 
494  if (args.dryRun())
495  {
496  Info<< "dry-run: decomposing mesh " << regionName << nl << nl
497  << "Create mesh..." << flush;
498 
499  domainDecompositionDryRun decompTest
500  (
501  IOobject
502  (
503  regionName,
504  runTime.timeName(),
505  runTime,
508  false
509  ),
510  decompDictFile,
511  args.getOrDefault<label>("domains", 0),
512  args.getOrDefault<word>("method", word::null)
513  );
514 
515  decompTest.execute(writeCellDist, args.verbose());
516  continue;
517  }
518 
519  Info<< "\n\nDecomposing mesh";
520  if (!regionDir.empty())
521  {
522  Info<< ' ' << regionName;
523  }
524  Info<< nl << endl;
525 
526  // Determine the existing processor count directly
527  const label nProcsOld =
528  fileHandler().nProcs(runTime.path(), regionDir);
529 
530  // Get requested numberOfSubdomains directly from the dictionary.
531  // Note: have no mesh yet so cannot use decompositionModel::New
532  const label nDomains = decompositionMethod::nDomains
533  (
535  (
537  (
538  IOobject
539  (
541  runTime.time().system(),
542  regionDir, // region (if non-default)
543  runTime,
546  false // do not register
547  ),
548  decompDictFile
549  )
550  )
551  );
552 
553  // Give file handler a chance to determine the output directory
554  const_cast<fileOperation&>(fileHandler()).setNProcs(nDomains);
555 
556  if (decomposeFieldsOnly)
557  {
558  // Sanity check on previously decomposed case
559  if (nProcsOld != nDomains)
560  {
562  << "Specified -fields, but the case was decomposed with "
563  << nProcsOld << " domains"
564  << nl
565  << "instead of " << nDomains
566  << " domains as specified in decomposeParDict" << nl
567  << exit(FatalError);
568  }
569  }
570  else if (nProcsOld)
571  {
572  bool procDirsProblem = true;
573 
574  if (decomposeIfRequired && nProcsOld == nDomains)
575  {
576  // We can reuse the decomposition
577  decomposeFieldsOnly = true;
578  procDirsProblem = false;
579  forceOverwrite = false;
580 
581  Info<< "Using existing processor directories" << nl;
582  }
583 
584  if (optRegions)
585  {
586  procDirsProblem = false;
587  forceOverwrite = false;
588  }
589 
590  if (forceOverwrite)
591  {
592  Info<< "Removing " << nProcsOld
593  << " existing processor directories" << endl;
594 
595  // Remove existing processors directory
596  fileNameList dirs
597  (
599  (
600  runTime.path(),
601  fileName::Type::DIRECTORY
602  )
603  );
604  forAllReverse(dirs, diri)
605  {
606  const fileName& d = dirs[diri];
607 
608  label proci = -1;
609 
610  if
611  (
612  d.starts_with("processor")
613  &&
614  (
615  // Collated is "processors"
616  d[9] == 's'
617 
618  // Uncollated has integer(s) after 'processor'
619  || Foam::read(d.substr(9), proci)
620  )
621  )
622  {
623  if (fileHandler().exists(d))
624  {
625  fileHandler().rmDir(d);
626  }
627  }
628  }
629 
630  procDirsProblem = false;
631  }
632 
633  if (procDirsProblem)
634  {
636  << "Case is already decomposed with " << nProcsOld
637  << " domains, use the -force option or manually" << nl
638  << "remove processor directories before decomposing. e.g.,"
639  << nl
640  << " rm -rf " << runTime.path().c_str() << "/processor*"
641  << nl
642  << exit(FatalError);
643  }
644  }
645 
646  Info<< "Create mesh" << endl;
648  (
649  IOobject
650  (
651  regionName,
652  runTime.timeName(),
653  runTime,
656  false
657  ),
658  decompDictFile
659  );
660 
661  // Decompose the mesh
662  if (!decomposeFieldsOnly)
663  {
664  mesh.decomposeMesh();
665  mesh.writeDecomposition(decomposeSets);
666 
667  if (writeCellDist)
668  {
669  const labelList& procIds = mesh.cellToProc();
670 
671  // Write decomposition for visualization
672  mesh.writeVolField("cellDist");
673  //TBD: mesh.writeVTK("cellDist");
674 
675  // Write decomposition as labelList for use with 'manual'
676  // decomposition method.
677  labelIOList cellDecomposition
678  (
679  IOobject
680  (
681  "cellDecomposition",
683  mesh,
686  false
687  ),
688  procIds
689  );
690  cellDecomposition.write();
691 
692  Info<< nl << "Wrote decomposition to "
693  << cellDecomposition.objectRelPath()
694  << " for use in manual decomposition." << endl;
695  }
696 
697  fileHandler().flush();
698  }
699 
700 
701  if (copyZero)
702  {
703  // Copy the 0/ directory into each of the processor directories
704  // with fallback of 0.orig/ directory if necessary.
705 
706  fileName inputDir(runTime.path()/"0");
707 
708  bool canCopy = fileHandler().isDir(inputDir);
709  if (!canCopy)
710  {
711  // Try with "0.orig" instead
712  inputDir.ext("orig");
713  canCopy = fileHandler().isDir(inputDir);
714  }
715 
716  if (canCopy)
717  {
718  // Avoid copying into the same directory multiple times
719  // (collated format). Don't need a hash here.
720  fileName prevOutputDir;
721  for (label proci = 0; proci < mesh.nProcs(); ++proci)
722  {
723  Time processorDb
724  (
726  args.rootPath(),
727  args.caseName()/("processor" + Foam::name(proci))
728  );
729  // processorDb.setTime(runTime);
730 
731  // Get corresponding directory name
732  // (to handle processors/)
733  const fileName outputDir
734  (
735  fileHandler().objectPath
736  (
737  IOobject
738  (
739  word::null, // name
740  "0", // instance (time == 0)
741  processorDb
742  ),
743  word::null
744  )
745  );
746 
747  if (outputDir != prevOutputDir)
748  {
749  Info<< "Processor " << proci
750  << ": copying \""
751  << inputDir.name() << "/\" to "
752  << runTime.relativePath(outputDir)
753  << endl;
754 
755  fileHandler().cp(inputDir, outputDir);
756  prevOutputDir = outputDir;
757  }
758  }
759  }
760  else
761  {
762  Info<< "No 0/ or 0.orig/ directory to copy" << nl;
763  }
764  }
765  else
766  {
767  // Decompose field files, lagrangian, finite-area
768 
769  // Cached processor meshes and maps. These are only preserved if
770  // running with multiple times.
771  PtrList<Time> processorDbList(mesh.nProcs());
772  PtrList<fvMesh> procMeshList(mesh.nProcs());
773  PtrList<labelIOList> faceProcAddressingList(mesh.nProcs());
774  PtrList<labelIOList> cellProcAddressingList(mesh.nProcs());
775  PtrList<labelIOList> boundaryProcAddressingList(mesh.nProcs());
776  PtrList<labelIOList> pointProcAddressingList(mesh.nProcs());
777 
778  PtrList<fvFieldDecomposer> fieldDecomposerList(mesh.nProcs());
779  PtrList<pointFieldDecomposer> pointFieldDecomposerList
780  (
781  mesh.nProcs()
782  );
783 
784 
785  // Loop over all times
786  forAll(times, timei)
787  {
788  runTime.setTime(times[timei], timei);
789 
790  Info<< "Time = " << runTime.timeName() << endl;
791 
792  // Field objects at this time
793  IOobjectList objects;
794 
795  if (doDecompFields)
796  {
797  objects = IOobjectList(mesh, runTime.timeName());
798 
799  // Ignore generated fields: (cellDist)
800  objects.remove("cellDist");
801  }
802 
803  // Finite area handling
804  autoPtr<faMeshDecomposition> faMeshDecompPtr;
805  if (doFiniteArea)
806  {
807  IOobject io
808  (
809  "faBoundary",
811  (
813  "boundary"
814  ),
816  mesh,
819  false // not registered
820  );
821 
822  if (io.typeHeaderOk<faBoundaryMesh>(true))
823  {
824  // Always based on the volume decomposition!
825  faMeshDecompPtr.reset
826  (
828  (
829  mesh,
830  mesh.nProcs(),
831  mesh.model()
832  )
833  );
834  }
835  }
836 
837 
838  // Volume/surface/internal fields
839  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
840 
841  fvFieldDecomposer::fieldsCache volumeFieldCache;
842 
843  if (doDecompFields)
844  {
845  volumeFieldCache.readAllFields(mesh, objects);
846  }
847 
848 
849  // Point fields
850  // ~~~~~~~~~~~~
851  const pointMesh& pMesh = pointMesh::New(mesh);
852 
853  pointFieldDecomposer::fieldsCache pointFieldCache;
854 
855  if (doDecompFields)
856  {
857  pointFieldCache.readAllFields(pMesh, objects);
858  }
859 
860 
861  // Lagrangian fields
862  // ~~~~~~~~~~~~~~~~~
863 
864  fileNameList cloudDirs;
865 
866  if (doDecompFields && doLagrangian)
867  {
868  cloudDirs = fileHandler().readDir
869  (
872  );
873  }
874 
875  // Particles
876  PtrList<Cloud<indexedParticle>> lagrangianPositions
877  (
878  cloudDirs.size()
879  );
880  // Particles per cell
882  (
883  cloudDirs.size()
884  );
885 
886  lagrangianFieldDecomposer::fieldsCache lagrangianFieldCache
887  (
888  cloudDirs.size()
889  );
890 
891  label cloudI = 0;
892 
893  for (const fileName& cloudDir : cloudDirs)
894  {
895  IOobjectList cloudObjects
896  (
897  mesh,
898  runTime.timeName(),
899  cloud::prefix/cloudDir,
901  );
902 
903  // Note: look up "positions" for backwards compatibility
904  if
905  (
906  cloudObjects.found("coordinates")
907  || cloudObjects.found("positions")
908  )
909  {
910  // Read lagrangian particles
911  // ~~~~~~~~~~~~~~~~~~~~~~~~~
912 
913  Info<< "Identified lagrangian data set: "
914  << cloudDir << endl;
915 
916  lagrangianPositions.set
917  (
918  cloudI,
920  (
921  mesh,
922  cloudDir,
923  false
924  )
925  );
926 
927 
928  // Sort particles per cell
929  // ~~~~~~~~~~~~~~~~~~~~~~~
930 
931  cellParticles.set
932  (
933  cloudI,
935  (
936  mesh.nCells(),
937  static_cast<SLList<indexedParticle*>*>(nullptr)
938  )
939  );
940 
941  label i = 0;
942 
943  for (indexedParticle& p : lagrangianPositions[cloudI])
944  {
945  p.index() = i++;
946 
947  label celli = p.cell();
948 
949  // Check
950  if (celli < 0 || celli >= mesh.nCells())
951  {
953  << "Illegal cell number " << celli
954  << " for particle with index "
955  << p.index()
956  << " at position "
957  << p.position() << nl
958  << "Cell number should be between 0 and "
959  << mesh.nCells()-1 << nl
960  << "On this mesh the particle should"
961  << " be in cell "
962  << mesh.findCell(p.position())
963  << exit(FatalError);
964  }
965 
966  if (!cellParticles[cloudI][celli])
967  {
968  cellParticles[cloudI][celli] =
970  }
971 
972  cellParticles[cloudI][celli]->append(&p);
973  }
974 
975  // Read fields
976  // ~~~~~~~~~~~
977 
978  IOobjectList lagrangianObjects
979  (
980  mesh,
981  runTime.timeName(),
982  cloud::prefix/cloudDirs[cloudI],
984  );
985 
986  lagrangianFieldCache.readAllFields
987  (
988  cloudI,
989  lagrangianObjects
990  );
991 
992  ++cloudI;
993  }
994  }
995 
996  lagrangianPositions.resize(cloudI);
997  cellParticles.resize(cloudI);
998  lagrangianFieldCache.resize(cloudI);
999 
1000  Info<< endl;
1001 
1002  // split the fields over processors
1003  for
1004  (
1005  label proci = 0;
1006  doDecompFields && proci < mesh.nProcs();
1007  ++proci
1008  )
1009  {
1010  Info<< "Processor " << proci << ": field transfer" << endl;
1011 
1012  // open the database
1013  if (!processorDbList.set(proci))
1014  {
1015  processorDbList.set
1016  (
1017  proci,
1018  new Time
1019  (
1021  args.rootPath(),
1022  args.caseName()
1023  / ("processor" + Foam::name(proci)),
1025  args.allowLibs()
1026  )
1027  );
1028  }
1029  Time& processorDb = processorDbList[proci];
1030 
1031 
1032  processorDb.setTime(runTime);
1033 
1034  // read the mesh
1035  if (!procMeshList.set(proci))
1036  {
1037  procMeshList.set
1038  (
1039  proci,
1040  new fvMesh
1041  (
1042  IOobject
1043  (
1044  regionName,
1045  processorDb.timeName(),
1046  processorDb
1047  )
1048  )
1049  );
1050  }
1051  const fvMesh& procMesh = procMeshList[proci];
1052 
1053  const labelIOList& faceProcAddressing = procAddressing
1054  (
1055  procMeshList,
1056  proci,
1057  "faceProcAddressing",
1058  faceProcAddressingList
1059  );
1060 
1061  const labelIOList& cellProcAddressing = procAddressing
1062  (
1063  procMeshList,
1064  proci,
1065  "cellProcAddressing",
1066  cellProcAddressingList
1067  );
1068 
1069  const labelIOList& boundaryProcAddressing = procAddressing
1070  (
1071  procMeshList,
1072  proci,
1073  "boundaryProcAddressing",
1074  boundaryProcAddressingList
1075  );
1076 
1077 
1078  // FV fields: volume, surface, internal
1079  {
1080  if (!fieldDecomposerList.set(proci))
1081  {
1082  fieldDecomposerList.set
1083  (
1084  proci,
1085  new fvFieldDecomposer
1086  (
1087  mesh,
1088  procMesh,
1089  faceProcAddressing,
1090  cellProcAddressing,
1091  boundaryProcAddressing
1092  )
1093  );
1094  }
1095 
1096  volumeFieldCache.decomposeAllFields
1097  (
1098  fieldDecomposerList[proci]
1099  );
1100 
1101  if (times.size() == 1)
1102  {
1103  // Clear cached decomposer
1104  fieldDecomposerList.set(proci, nullptr);
1105  }
1106  }
1107 
1108 
1109  // Point fields
1110  if (!pointFieldCache.empty())
1111  {
1112  const labelIOList& pointProcAddressing = procAddressing
1113  (
1114  procMeshList,
1115  proci,
1116  "pointProcAddressing",
1117  pointProcAddressingList
1118  );
1119 
1120  const pointMesh& procPMesh = pointMesh::New(procMesh);
1121 
1122  if (!pointFieldDecomposerList.set(proci))
1123  {
1124  pointFieldDecomposerList.set
1125  (
1126  proci,
1128  (
1129  pMesh,
1130  procPMesh,
1131  pointProcAddressing,
1132  boundaryProcAddressing
1133  )
1134  );
1135  }
1136 
1137  pointFieldCache.decomposeAllFields
1138  (
1139  pointFieldDecomposerList[proci]
1140  );
1141 
1142  if (times.size() == 1)
1143  {
1144  pointProcAddressingList.set(proci, nullptr);
1145  pointFieldDecomposerList.set(proci, nullptr);
1146  }
1147  }
1148 
1149 
1150  // If there is lagrangian data write it out
1151  forAll(lagrangianPositions, cloudi)
1152  {
1153  if (lagrangianPositions[cloudi].size())
1154  {
1155  lagrangianFieldDecomposer fieldDecomposer
1156  (
1157  mesh,
1158  procMesh,
1159  faceProcAddressing,
1160  cellProcAddressing,
1161  cloudDirs[cloudi],
1162  lagrangianPositions[cloudi],
1163  cellParticles[cloudi]
1164  );
1165 
1166  // Lagrangian fields
1167  lagrangianFieldCache.decomposeAllFields
1168  (
1169  cloudi,
1170  cloudDirs[cloudi],
1171  fieldDecomposer
1172  );
1173  }
1174  }
1175 
1176  if (doDecompFields)
1177  {
1178  // Decompose "uniform" directory in the time region
1179  // directory
1180  decomposeUniform
1181  (
1182  copyUniform, mesh, processorDb, regionDir
1183  );
1184 
1185  // For a multi-region case, also decompose "uniform"
1186  // directory in the time directory
1187  if (regionNames.size() > 1 && regioni == 0)
1188  {
1189  decomposeUniform(copyUniform, mesh, processorDb);
1190  }
1191  }
1192 
1193 
1194  // We have cached all the constant mesh data for the current
1195  // processor. This is only important if running with
1196  // multiple times, otherwise it is just extra storage.
1197  if (times.size() == 1)
1198  {
1199  boundaryProcAddressingList.set(proci, nullptr);
1200  cellProcAddressingList.set(proci, nullptr);
1201  faceProcAddressingList.set(proci, nullptr);
1202  procMeshList.set(proci, nullptr);
1203  processorDbList.set(proci, nullptr);
1204  }
1205  }
1206 
1207 
1208  // Finite area mesh and field decomposition
1209  if (faMeshDecompPtr)
1210  {
1211  Info<< "\nFinite area mesh decomposition" << endl;
1212 
1213  faMeshDecomposition& aMesh = faMeshDecompPtr();
1214 
1215  aMesh.decomposeMesh();
1216  aMesh.writeDecomposition();
1217 
1218 
1219  // Area/edge fields
1220  // ~~~~~~~~~~~~~~~~
1221 
1222  faFieldDecomposer::fieldsCache areaFieldCache;
1223 
1224  if (doDecompFields)
1225  {
1226  areaFieldCache.readAllFields(aMesh, objects);
1227  }
1228 
1229  const label nAreaFields = areaFieldCache.size();
1230 
1231  Info<< endl;
1232  Info<< "Finite area field transfer: "
1233  << nAreaFields << " fields" << endl;
1234 
1235  // Split the fields over processors
1236  for
1237  (
1238  label proci = 0;
1239  nAreaFields && proci < mesh.nProcs();
1240  ++proci
1241  )
1242  {
1243  Info<< " Processor " << proci << endl;
1244 
1245  // open the database
1246  Time processorDb
1247  (
1249  args.rootPath(),
1250  args.caseName()
1251  / ("processor" + Foam::name(proci))
1252  );
1253 
1254  processorDb.setTime(runTime);
1255 
1256  // Read the mesh
1257  fvMesh procFvMesh
1258  (
1259  IOobject
1260  (
1261  regionName,
1262  processorDb.timeName(),
1263  processorDb
1264  )
1265  );
1266 
1267  faMesh procMesh(procFvMesh);
1268 
1269  // // Does not work. HJ, 15/Aug/2017
1270  // const labelIOList& faceProcAddressing =
1271  // procAddressing
1272  // (
1273  // procMeshList,
1274  // proci,
1275  // "faceProcAddressing",
1276  // faceProcAddressingList
1277  // );
1278 
1279  // const labelIOList& boundaryProcAddressing =
1280  // procAddressing
1281  // (
1282  // procMeshList,
1283  // proci,
1284  // "boundaryProcAddressing",
1285  // boundaryProcAddressingList
1286  // );
1287 
1288  // Addressing from faMesh (not polyMesh) meshSubDir
1289 
1290  autoPtr<labelIOList> tfaceProcAddr =
1291  faProcAddressing
1292  (
1293  procFvMesh,
1294  "faceProcAddressing",
1295  runTime.constant()
1296  );
1297  auto& faceProcAddressing = *tfaceProcAddr;
1298 
1299  autoPtr<labelIOList> tboundaryProcAddr =
1300  faProcAddressing
1301  (
1302  procFvMesh,
1303  "boundaryProcAddressing",
1304  runTime.constant()
1305  );
1306  auto& boundaryProcAddressing = *tboundaryProcAddr;
1307 
1308  autoPtr<labelIOList> tedgeProcAddr =
1309  faProcAddressing
1310  (
1311  procFvMesh,
1312  "edgeProcAddressing",
1313  runTime.constant()
1314  );
1315  const auto& edgeProcAddressing = *tedgeProcAddr;
1316 
1317  faFieldDecomposer fieldDecomposer
1318  (
1319  aMesh,
1320  procMesh,
1321  edgeProcAddressing,
1322  faceProcAddressing,
1323  boundaryProcAddressing
1324  );
1325 
1326  areaFieldCache.decomposeAllFields(fieldDecomposer);
1327  }
1328  }
1329  }
1330  }
1331  }
1332 
1333  Info<< "\nEnd\n" << endl;
1334 
1335  return 0;
1336 }
1337 
1338 
1339 // ************************************************************************* //
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 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
fileName path() const
Return path.
Definition: Time.H:449
A class for handling file names.
Definition: fileName.H:71
Finite Area area and edge field decomposer.
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 append(const T &elem)
Add copy at back of list.
Definition: LList.H:748
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...
fileName timePath() const
Return current time path.
Definition: Time.H:470
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:841
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create a new MeshObject.
Definition: MeshObject.C:41
void readAllFields(const faMesh &mesh, const IOobjectList &objects)
Read all fields given mesh and objects.
Template class for non-intrusive linked lists.
Definition: LList.H:50
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:402
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
bool chDir(const fileName &dir)
Change current directory to the one specified and return true on success.
Definition: POSIX.C:560
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 void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:365
static void noParallel()
Remove the parallel options.
Definition: argList.C:551
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Specify an alias for the option name.
Definition: argList.C:409
autoPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler.
virtual const fileName & dbDir() const
Override the objectRegistry dbDir for a single-region case.
Definition: polyMesh.C:824
wordList regionNames
Ignore writing from objectRegistry::writeObject()
void decomposeAllFields(const fvFieldDecomposer &decomposer, bool report=false) const
Decompose and write all fields.
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
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:361
Automatic domain decomposition class for finite-volume meshes.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
An encapsulation of filesystem-related operations.
Definition: fileOperation.H:63
bool allowFunctionObjects() const
The controlDict &#39;functions&#39; entry is allowed to be used.
Definition: argList.C:1817
void resize(const label sz)
Resize the hash table for efficiency.
Definition: HashTable.C:594
void readAllFields(const pointMesh &mesh, const IOobjectList &objects)
Read all fields given mesh and objects.
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:125
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
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 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
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::word regionName(Foam::polyMesh::defaultRegion)
bool allowLibs() const
The controlDict &#39;libs&#39; entry is allowed to be used. (eg, has not been disabled by the -no-libs option...
Definition: argList.C:1835
void readAllFields(const fvMesh &mesh, const IOobjectList &objects)
Read all fields given mesh and objects.
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
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
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.
const word & executable() const noexcept
Name of executable without the path.
Definition: argListI.H:44
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
const word & system() const noexcept
Return system name.
Definition: TimePathsI.H:95
static void addVerboseOption(const string &usage, bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:505
static const word null
An empty word.
Definition: word.H:84
bool exists(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition: POSIX.C:788
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:376
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
bool local
Definition: EEqn.H:20
static word controlDictName
The default control dictionary name (normally "controlDict")
Definition: Time.H:275
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: PtrList.H:163
const fileName & caseName() const noexcept
Return case name (parallel run) or global case (serial run)
Definition: argListI.H:62
label nDomains() const noexcept
Number of domains.
bool typeHeaderOk(const bool checkType=true, const bool search=true, const bool verbose=true)
Read header (uses typeFilePath to find file) and check its info.
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
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:89
Point field decomposer.
const fileName & rootPath() const noexcept
Return root path.
Definition: argListI.H:56
Finite Volume volume and surface field decomposer.
static const word canonicalName
The canonical name ("decomposeParDict") under which the MeshObject is registered. ...
void decomposeAllFields(const pointFieldDecomposer &decomposer, bool report=false) const
Decompose and write all fields.
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:698
bool starts_with(char c) const
True if string starts with given character (cf. C++20)
Definition: string.H:414
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:477
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:271
label nCells() const noexcept
Number of mesh cells.
autoPtr< IOobject > remove(const IOobject &io)
Remove object from the list by its IOobject::name().
Definition: IOobjectList.H:302
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
Nothing to be read.
fileName cwd()
The physical or logical current working directory path name.
Definition: POSIX.C:543
Finite area boundary mesh.
label findCell(const point &p, const cellDecomposition=CELL_TETS) const
Find cell enclosing this location and return index.
Definition: polyMesh.C:1505
messageStream Info
Information stream (stdout output on master, null elsewhere)
Automatic faMesh decomposition class.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:429
volScalarField & p
faMesh aMesh(mesh)
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
Testing of domain decomposition for finite-volume meshes.
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::Type::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition: POSIX.C:916
Foam::argList args(argc, argv)
label size() const
Number of fields.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
A class for handling character strings derived from std::string.
Definition: string.H:72
Adds label index to base particle.
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:570
int verbose() const noexcept
Return the verbose flag.
Definition: argListI.H:121
Do not request registration (bool: false)
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:101
bool set(const Key &key, const T &obj)
Copy assign a new entry, overwriting existing entries.
Definition: HashTableI.H:195
Namespace for OpenFOAM.
static IOobject selectIO(const IOobject &io, const fileName &altFile, const word &ioName="")
Return the IOobject, but also consider an alternative file name.
Definition: IOobject.C:231
fileName globalPath() const
Return global path for the case.
Definition: TimePathsI.H:73
void decomposeAllFields(const faFieldDecomposer &decomposer, bool report=false) const
Decompose and write all fields.
Lagrangian field decomposer.
static const word prefix
The prefix to local: lagrangian.
Definition: cloud.H:93