1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 Automatically decomposes a mesh and fields of a case for parallel
30 execution of OpenFOAM.
34 - decomposePar [OPTION]
37 Write the cell distribution as a labelList for use with 'manual'
38 decomposition method and as a volScalarField for post-processing.
40 @param -region regionName \n
41 Decompose named region. Does not check for existence of processor*.
43 @param -copyUniform \n
44 Copy any @a uniform directories too.
47 Use existing geometry decomposition and convert fields only.
49 @param -filterPatches \n
50 Remove empty patches when decomposing the geometry.
53 Remove any existing @a processor subdirectories before decomposing the
57 Only decompose the geometry if the number of domains has changed from a
58 previous decomposition. No @a processor subdirectories will be removed
59 unless the @a -force option is also specified. This option can be used
60 to avoid redundant geometry decomposition (eg, in scripts), but should
61 be used with caution when the underlying (serial) geometry or the
62 decomposition method etc. have been changed between decompositions.
64 \*---------------------------------------------------------------------------*/
66 #include "OSspecific.H"
68 #include "IOobjectList.H"
69 #include "processorFvPatchFields.H"
70 #include "domainDecomposition.H"
71 #include "labelIOField.H"
72 #include "scalarIOField.H"
73 #include "vectorIOField.H"
74 #include "sphericalTensorIOField.H"
75 #include "symmTensorIOField.H"
76 #include "tensorIOField.H"
78 #include "tetPointFields.H"
79 #include "elementFields.H"
80 #include "tetFemMatrices.H"
81 #include "tetPointFieldDecomposer.H"
83 #include "pointFields.H"
85 #include "readFields.H"
86 #include "fvFieldDecomposer.H"
87 #include "pointFieldDecomposer.H"
88 #include "lagrangianFieldDecomposer.H"
91 #include "emptyFaPatch.H"
92 #include "faMeshDecomposition.H"
93 #include "faFieldDecomposer.H"
95 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
97 int main(int argc, char *argv[])
99 argList::noParallel();
100 # include "addRegionOption.H"
101 argList::validOptions.insert("cellDist", "");
102 argList::validOptions.insert("copyUniform", "");
103 argList::validOptions.insert("fields", "");
104 argList::validOptions.insert("filterPatches", "");
105 argList::validOptions.insert("force", "");
106 argList::validOptions.insert("ifRequired", "");
108 # include "setRootCase.H"
110 word regionName = fvMesh::defaultRegion;
111 word regionDir = word::null;
113 if (args.optionFound("region"))
115 regionName = args.option("region");
116 regionDir = regionName;
117 Info<< "Decomposing mesh " << regionName << nl << endl;
121 bool writeCellDist = args.optionFound("cellDist");
122 bool copyUniform = args.optionFound("copyUniform");
123 bool decomposeFieldsOnly = args.optionFound("fields");
124 bool filterPatches = args.optionFound("filterPatches");
125 bool forceOverwrite = args.optionFound("force");
126 bool ifRequiredDecomposition = args.optionFound("ifRequired");
128 # include "createTime.H"
130 Info<< "Time = " << runTime.timeName() << endl;
132 // Determine the existing processor count directly
139 /(word("processor") + name(nProcs))
142 /polyMesh::meshSubDir
149 // get requested numberOfSubdomains
152 IOdictionary decompDict
157 runTime.time().system(),
158 regionDir, // use region if non-standard
166 decompDict.lookup("numberOfSubdomains") >> nDomains;
169 if (decomposeFieldsOnly)
171 // Sanity check on previously decomposed case
172 if (nProcs != nDomains)
174 FatalErrorIn(args.executable())
175 << "Specified -fields, but the case was decomposed with "
176 << nProcs << " domains"
178 << "instead of " << nDomains
179 << " domains as specified in decomposeParDict"
186 bool procDirsProblem = true;
188 if (regionName != fvMesh::defaultRegion)
190 decomposeFieldsOnly = false;
191 procDirsProblem = false;
195 if (ifRequiredDecomposition && nProcs == nDomains)
197 // we can reuse the decomposition
198 decomposeFieldsOnly = true;
199 procDirsProblem = false;
200 forceOverwrite = false;
202 Info<< "Using existing processor directories" << nl;
207 Info<< "Removing " << nProcs
208 << " existing processor directories" << endl;
210 // remove existing processor dirs
211 // reverse order to avoid gaps if someone interrupts the process
212 for (label procI = nProcs-1; procI >= 0; --procI)
216 runTime.path()/(word("processor") + name(procI))
222 procDirsProblem = false;
227 FatalErrorIn(args.executable())
228 << "Case is already decomposed with " << nProcs
229 << " domains, use the -force option or manually" << nl
230 << "remove processor directories before decomposing. e.g.,"
232 << " rm -rf " << runTime.path().c_str() << "/processor*"
238 Info<< "Create mesh for region " << regionName << endl;
239 domainDecomposition mesh
249 // Decompose the mesh
250 if (!decomposeFieldsOnly)
252 mesh.decomposeMesh(filterPatches);
254 mesh.writeDecomposition();
258 const labelList& procIds = mesh.cellToProc();
260 // Write the decomposition as labelList for use with 'manual'
261 // decomposition method.
262 labelIOList cellDecomposition
267 mesh.facesInstance(),
275 cellDecomposition.write();
277 Info<< nl << "Wrote decomposition to "
278 << cellDecomposition.objectPath()
279 << " for use in manual decomposition." << endl;
281 // Write as volScalarField for post-processing
282 volScalarField cellDist
293 dimensionedScalar("cellDist", dimless, 0),
294 zeroGradientFvPatchScalarField::typeName
297 forAll(procIds, celli)
299 cellDist[celli] = procIds[celli];
304 Info<< nl << "Wrote decomposition as volScalarField to "
305 << cellDist.name() << " for use in post-processing."
311 // Search for list of objects for this time
312 IOobjectList objects(mesh, runTime.timeName());
314 // Construct the vol fields
315 // ~~~~~~~~~~~~~~~~~~~~~~~~
316 PtrList<volScalarField> volScalarFields;
317 readFields(mesh, objects, volScalarFields);
319 PtrList<volVectorField> volVectorFields;
320 readFields(mesh, objects, volVectorFields);
322 PtrList<volSphericalTensorField> volSphericalTensorFields;
323 readFields(mesh, objects, volSphericalTensorFields);
325 PtrList<volSymmTensorField> volSymmTensorFields;
326 readFields(mesh, objects, volSymmTensorFields);
328 PtrList<volTensorField> volTensorFields;
329 readFields(mesh, objects, volTensorFields);
332 // Construct the surface fields
333 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
334 PtrList<surfaceScalarField> surfaceScalarFields;
335 readFields(mesh, objects, surfaceScalarFields);
336 PtrList<surfaceVectorField> surfaceVectorFields;
337 readFields(mesh, objects, surfaceVectorFields);
338 PtrList<surfaceSphericalTensorField> surfaceSphericalTensorFields;
339 readFields(mesh, objects, surfaceSphericalTensorFields);
340 PtrList<surfaceSymmTensorField> surfaceSymmTensorFields;
341 readFields(mesh, objects, surfaceSymmTensorFields);
342 PtrList<surfaceTensorField> surfaceTensorFields;
343 readFields(mesh, objects, surfaceTensorFields);
346 // Construct the point fields
347 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
348 pointMesh pMesh(mesh);
350 PtrList<pointScalarField> pointScalarFields;
351 readFields(pMesh, objects, pointScalarFields);
353 PtrList<pointVectorField> pointVectorFields;
354 readFields(pMesh, objects, pointVectorFields);
356 PtrList<pointSphericalTensorField> pointSphericalTensorFields;
357 readFields(pMesh, objects, pointSphericalTensorFields);
359 PtrList<pointSymmTensorField> pointSymmTensorFields;
360 readFields(pMesh, objects, pointSymmTensorFields);
362 PtrList<pointTensorField> pointTensorFields;
363 readFields(pMesh, objects, pointTensorFields);
366 // Construct the tetPoint fields
367 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
368 tetPolyMesh* tetMeshPtr = NULL;
370 PtrList<tetPointScalarField> tetPointScalarFields;
371 PtrList<tetPointVectorField> tetPointVectorFields;
372 PtrList<tetPointSphericalTensorField> tetPointSphericalTensorFields;
373 PtrList<tetPointSymmTensorField> tetPointSymmTensorFields;
374 PtrList<tetPointTensorField> tetPointTensorFields;
376 PtrList<elementScalarField> elementScalarFields;
377 PtrList<elementVectorField> elementVectorFields;
381 objects.lookupClass("tetPointScalarField").size() > 0
382 || objects.lookupClass("tetPointVectorField").size() > 0
383 || objects.lookupClass("tetPointSphericalTensorField").size() > 0
384 || objects.lookupClass("tetPointSymmTensorField").size() > 0
385 || objects.lookupClass("tetPointTensorField").size() > 0
387 || objects.lookupClass("elementScalarField").size() > 0
388 || objects.lookupClass("elementVectorField").size() > 0
391 tetMeshPtr = new tetPolyMesh(mesh);
392 tetPolyMesh& tetMesh = *tetMeshPtr;
394 readFields(tetMesh, objects, tetPointScalarFields);
395 readFields(tetMesh, objects, tetPointVectorFields);
396 readFields(tetMesh, objects, tetPointSphericalTensorFields);
397 readFields(tetMesh, objects, tetPointSymmTensorFields);
398 readFields(tetMesh, objects, tetPointTensorFields);
400 readFields(tetMesh, objects, elementScalarFields);
401 readFields(tetMesh, objects, elementVectorFields);
405 // Construct the Lagrangian fields
406 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
408 fileNameList cloudDirs
410 readDir(runTime.timePath()/cloud::prefix, fileName::DIRECTORY)
414 PtrList<Cloud<indexedParticle> > lagrangianPositions(cloudDirs.size());
415 // Particles per cell
416 PtrList< List<SLList<indexedParticle*>*> > cellParticles(cloudDirs.size());
418 PtrList<PtrList<labelIOField> > lagrangianLabelFields(cloudDirs.size());
419 PtrList<PtrList<scalarIOField> > lagrangianScalarFields(cloudDirs.size());
420 PtrList<PtrList<vectorIOField> > lagrangianVectorFields(cloudDirs.size());
421 PtrList<PtrList<sphericalTensorIOField> > lagrangianSphericalTensorFields
425 PtrList<PtrList<symmTensorIOField> > lagrangianSymmTensorFields
429 PtrList<PtrList<tensorIOField> > lagrangianTensorFields
438 IOobjectList sprayObjs
442 cloud::prefix/cloudDirs[i]
445 IOobject* positionsPtr = sprayObjs.lookup("positions");
449 // Read lagrangian particles
450 // ~~~~~~~~~~~~~~~~~~~~~~~~~
452 Info<< "Identified lagrangian data set: " << cloudDirs[i] << endl;
454 lagrangianPositions.set
457 new Cloud<indexedParticle>
466 // Sort particles per cell
467 // ~~~~~~~~~~~~~~~~~~~~~~~
472 new List<SLList<indexedParticle*>*>
475 static_cast<SLList<indexedParticle*>*>(NULL)
483 Cloud<indexedParticle>,
484 lagrangianPositions[cloudI],
488 iter().index() = i++;
490 label celli = iter().cell();
493 if (celli < 0 || celli >= mesh.nCells())
495 FatalErrorIn(args.executable())
496 << "Illegal cell number " << celli
497 << " for particle with index " << iter().index()
498 << " at position " << iter().position() << nl
499 << "Cell number should be between 0 and "
500 << mesh.nCells()-1 << nl
501 << "On this mesh the particle should be in cell "
502 << mesh.findCell(iter().position())
506 if (!cellParticles[cloudI][celli])
508 cellParticles[cloudI][celli] =
509 new SLList<indexedParticle*>();
512 cellParticles[cloudI][celli]->append(&iter());
518 IOobjectList lagrangianObjects
522 cloud::prefix/cloudDirs[cloudI]
525 lagrangianFieldDecomposer::readFields
529 lagrangianLabelFields
532 lagrangianFieldDecomposer::readFields
536 lagrangianScalarFields
539 lagrangianFieldDecomposer::readFields
543 lagrangianVectorFields
546 lagrangianFieldDecomposer::readFields
550 lagrangianSphericalTensorFields
553 lagrangianFieldDecomposer::readFields
557 lagrangianSymmTensorFields
560 lagrangianFieldDecomposer::readFields
564 lagrangianTensorFields
571 lagrangianPositions.setSize(cloudI);
572 cellParticles.setSize(cloudI);
573 lagrangianLabelFields.setSize(cloudI);
574 lagrangianScalarFields.setSize(cloudI);
575 lagrangianVectorFields.setSize(cloudI);
576 lagrangianSphericalTensorFields.setSize(cloudI);
577 lagrangianSymmTensorFields.setSize(cloudI);
578 lagrangianTensorFields.setSize(cloudI);
581 // Any uniform data to copy/link?
582 fileName uniformDir("uniform");
584 if (isDir(runTime.timePath()/uniformDir))
586 Info<< "Detected additional non-decomposed files in "
587 << runTime.timePath()/uniformDir
597 // Split the fields over processors
598 for (label procI = 0; procI < mesh.nProcs(); procI++)
600 Info<< "Processor " << procI << ": field transfer" << endl;
605 Time::controlDictName,
607 args.caseName()/fileName(word("processor") + name(procI))
610 processorDb.setTime(runTime);
612 // Remove files remnants that can cause horrible problems
613 // - mut and nut are used to mark the new turbulence models,
614 // their existence prevents old models from being upgraded
615 // 1.6.x merge. HJ, 25/Aug/2010
617 fileName timeDir(processorDb.path()/processorDb.timeName());
621 rm(timeDir/"mut.gz");
622 rm(timeDir/"nut.gz");
631 processorDb.timeName(),
636 labelIOList cellProcAddressing
640 "cellProcAddressing",
641 procMesh.facesInstance(),
649 labelIOList boundaryProcAddressing
653 "boundaryProcAddressing",
654 procMesh.facesInstance(),
665 volScalarFields.size()
666 || volVectorFields.size()
667 || volSphericalTensorFields.size()
668 || volSymmTensorFields.size()
669 || volTensorFields.size()
670 || surfaceScalarFields.size()
671 || surfaceVectorFields.size()
672 || surfaceSphericalTensorFields.size()
673 || surfaceSymmTensorFields.size()
674 || surfaceTensorFields.size()
677 labelIOList faceProcAddressing
681 "faceProcAddressing",
682 procMesh.facesInstance(),
690 fvFieldDecomposer fieldDecomposer
696 boundaryProcAddressing
699 fieldDecomposer.decomposeFields(volScalarFields);
700 fieldDecomposer.decomposeFields(volVectorFields);
701 fieldDecomposer.decomposeFields(volSphericalTensorFields);
702 fieldDecomposer.decomposeFields(volSymmTensorFields);
703 fieldDecomposer.decomposeFields(volTensorFields);
705 fieldDecomposer.decomposeFields(surfaceScalarFields);
706 fieldDecomposer.decomposeFields(surfaceVectorFields);
707 fieldDecomposer.decomposeFields(surfaceSphericalTensorFields);
708 fieldDecomposer.decomposeFields(surfaceSymmTensorFields);
709 fieldDecomposer.decomposeFields(surfaceTensorFields);
716 pointScalarFields.size()
717 || pointVectorFields.size()
718 || pointSphericalTensorFields.size()
719 || pointSymmTensorFields.size()
720 || pointTensorFields.size()
723 labelIOList pointProcAddressing
727 "pointProcAddressing",
728 procMesh.facesInstance(),
736 pointMesh procPMesh(procMesh, true);
738 pointFieldDecomposer fieldDecomposer
743 boundaryProcAddressing
746 fieldDecomposer.decomposeFields(pointScalarFields);
747 fieldDecomposer.decomposeFields(pointVectorFields);
748 fieldDecomposer.decomposeFields(pointSphericalTensorFields);
749 fieldDecomposer.decomposeFields(pointSymmTensorFields);
750 fieldDecomposer.decomposeFields(pointTensorFields);
757 const tetPolyMesh& tetMesh = *tetMeshPtr;
758 tetPolyMesh procTetMesh(procMesh);
760 // Read the point addressing information
761 labelIOList pointProcAddressing
765 "pointProcAddressing",
766 procMesh.facesInstance(),
774 // Read the point addressing information
775 labelIOList faceProcAddressing
779 "faceProcAddressing",
780 procMesh.facesInstance(),
788 tetPointFieldDecomposer fieldDecomposer
795 boundaryProcAddressing
798 fieldDecomposer.decomposeFields(tetPointScalarFields);
799 fieldDecomposer.decomposeFields(tetPointVectorFields);
800 fieldDecomposer.decomposeFields(tetPointSphericalTensorFields);
801 fieldDecomposer.decomposeFields(tetPointSymmTensorFields);
802 fieldDecomposer.decomposeFields(tetPointTensorFields);
804 fieldDecomposer.decomposeFields(elementScalarFields);
805 fieldDecomposer.decomposeFields(elementVectorFields);
809 // If there is lagrangian data write it out
810 forAll(lagrangianPositions, cloudI)
812 if (lagrangianPositions[cloudI].size())
814 lagrangianFieldDecomposer fieldDecomposer
820 lagrangianPositions[cloudI],
821 cellParticles[cloudI]
827 lagrangianLabelFields[cloudI].size()
828 || lagrangianScalarFields[cloudI].size()
829 || lagrangianVectorFields[cloudI].size()
830 || lagrangianSphericalTensorFields[cloudI].size()
831 || lagrangianSymmTensorFields[cloudI].size()
832 || lagrangianTensorFields[cloudI].size()
835 fieldDecomposer.decomposeFields
838 lagrangianLabelFields[cloudI]
840 fieldDecomposer.decomposeFields
843 lagrangianScalarFields[cloudI]
845 fieldDecomposer.decomposeFields
848 lagrangianVectorFields[cloudI]
850 fieldDecomposer.decomposeFields
853 lagrangianSphericalTensorFields[cloudI]
855 fieldDecomposer.decomposeFields
858 lagrangianSymmTensorFields[cloudI]
860 fieldDecomposer.decomposeFields
863 lagrangianTensorFields[cloudI]
870 // Any non-decomposed data to copy?
871 if (uniformDir.size())
873 const fileName timePath = processorDb.timePath();
875 if (copyUniform || mesh.distributed())
879 runTime.timePath()/uniformDir,
885 // Link with relative paths
886 const string parentPath = string("..")/"..";
888 fileName currentDir(cwd());
890 if (!exists(uniformDir))
894 parentPath/runTime.timeName()/uniformDir,
911 // Finite area mesh and field decomposition
913 IOobject faMeshBoundaryIOobj
916 mesh.time().findInstance
918 mesh.dbDir()/polyMesh::meshSubDir,
923 IOobject::READ_IF_PRESENT,
928 if(faMeshBoundaryIOobj.headerOk())
930 Info << "\nFinite area mesh decomposition" << endl;
932 faMeshDecomposition aMesh(mesh);
934 aMesh.decomposeMesh(filterPatches);
936 aMesh.writeDecomposition();
939 // Construct the area fields
940 // ~~~~~~~~~~~~~~~~~~~~~~~~
941 PtrList<areaScalarField> areaScalarFields;
942 readFields(aMesh, objects, areaScalarFields);
944 PtrList<areaVectorField> areaVectorFields;
945 readFields(aMesh, objects, areaVectorFields);
947 PtrList<areaSphericalTensorField> areaSphericalTensorFields;
948 readFields(aMesh, objects, areaSphericalTensorFields);
950 PtrList<areaSymmTensorField> areaSymmTensorFields;
951 readFields(aMesh, objects, areaSymmTensorFields);
953 PtrList<areaTensorField> areaTensorFields;
954 readFields(aMesh, objects, areaTensorFields);
957 // Construct the edge fields
958 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
959 PtrList<edgeScalarField> edgeScalarFields;
960 readFields(aMesh, objects, edgeScalarFields);
964 // Split the fields over processors
965 for (label procI = 0; procI < mesh.nProcs(); procI++)
967 Info<< "Processor " << procI
968 << ": finite area field transfer" << endl;
973 Time::controlDictName,
975 args.caseName()/fileName(word("processor") + name(procI))
978 processorDb.setTime(runTime);
986 processorDb.timeName(),
991 faMesh procMesh(procFvMesh);
993 labelIOList faceProcAddressing
997 "faceProcAddressing",
1001 IOobject::MUST_READ,
1006 labelIOList boundaryProcAddressing
1010 "boundaryProcAddressing",
1012 procMesh.meshSubDir,
1014 IOobject::MUST_READ,
1022 areaScalarFields.size()
1023 || areaVectorFields.size()
1024 || areaSphericalTensorFields.size()
1025 || areaSymmTensorFields.size()
1026 || areaTensorFields.size()
1027 || edgeScalarFields.size()
1030 labelIOList edgeProcAddressing
1034 "edgeProcAddressing",
1036 procMesh.meshSubDir,
1038 IOobject::MUST_READ,
1043 faFieldDecomposer fieldDecomposer
1049 boundaryProcAddressing
1052 fieldDecomposer.decomposeFields(areaScalarFields);
1053 fieldDecomposer.decomposeFields(areaVectorFields);
1054 fieldDecomposer.decomposeFields(areaSphericalTensorFields);
1055 fieldDecomposer.decomposeFields(areaSymmTensorFields);
1056 fieldDecomposer.decomposeFields(areaTensorFields);
1058 fieldDecomposer.decomposeFields(edgeScalarFields);
1064 Info<< "\nEnd.\n" << endl;
1070 // ************************************************************************* //