63 static const scalar defaultMergeTol = 1
e-6;
67 scalar getMergeDistance
74 scalar mergeTol = defaultMergeTol;
75 args.optionReadIfPresent(
"mergeTol", mergeTol);
78 Foam::pow(scalar(10.0), -scalar(IOstream::defaultPrecision()));
80 Info<<
"Merge tolerance : " << mergeTol <<
nl 81 <<
"Write tolerance : " << writeTol <<
endl;
83 if (runTime.writeFormat() == IOstream::ASCII && mergeTol < writeTol)
86 <<
"Your current settings specify ASCII writing with " 87 << IOstream::defaultPrecision() <<
" digits precision." << endl
88 <<
"Your merging tolerance (" << mergeTol <<
") is finer than this." 90 <<
"Please change your writeFormat to binary" 91 <<
" or increase the writePrecision" << endl
92 <<
"or adjust the merge tolerance (-mergeTol)." 96 scalar mergeDist = mergeTol * bb.mag();
98 Info<<
"Overall meshes bounding box : " << bb <<
nl 99 <<
"Relative tolerance : " << mergeTol <<
nl 100 <<
"Absolute matching distance : " << mergeDist <<
nl 120 void printMeshData(
const polyMesh& mesh)
124 globalIndex globalCells(mesh.nCells());
127 const labelList& pPatches = mesh.globalData().processorPatches();
128 patchNeiProcNo[Pstream::myProcNo()].
setSize(pPatches.size());
129 patchSize[Pstream::myProcNo()].setSize(pPatches.size());
132 const processorPolyPatch& ppp = refCast<const processorPolyPatch>
134 mesh.boundaryMesh()[pPatches[i]]
136 patchNeiProcNo[Pstream::myProcNo()][i] = ppp.neighbProcNo();
137 patchSize[Pstream::myProcNo()][i] = ppp.size();
139 Pstream::gatherList(patchNeiProcNo);
140 Pstream::gatherList(patchSize);
145 globalIndex globalBoundaryFaces(mesh.nFaces()-mesh.nInternalFaces());
147 label maxProcCells = 0;
148 label totProcFaces = 0;
149 label maxProcPatches = 0;
150 label totProcPatches = 0;
151 label maxProcFaces = 0;
153 for (
label proci = 0; proci < Pstream::nProcs(); proci++)
156 <<
"Processor " << proci <<
nl 157 <<
" Number of cells = " << globalCells.localSize(proci)
160 label nProcFaces = 0;
162 const labelList& nei = patchNeiProcNo[proci];
164 forAll(patchNeiProcNo[proci], i)
166 Info<<
" Number of faces shared with processor " 167 << patchNeiProcNo[proci][i] <<
" = " << patchSize[proci][i]
170 nProcFaces += patchSize[proci][i];
173 Info<<
" Number of processor patches = " << nei.size() <<
nl 174 <<
" Number of processor faces = " << nProcFaces <<
nl 175 <<
" Number of boundary faces = " 176 << globalBoundaryFaces.localSize(proci) <<
endl;
178 maxProcCells =
max(maxProcCells, globalCells.localSize(proci));
179 totProcFaces += nProcFaces;
180 totProcPatches += nei.size();
181 maxProcPatches =
max(maxProcPatches, nei.size());
182 maxProcFaces =
max(maxProcFaces, nProcFaces);
187 scalar avgProcCells = scalar(globalCells.size())/Pstream::nProcs();
188 scalar avgProcPatches = scalar(totProcPatches)/Pstream::nProcs();
189 scalar avgProcFaces = scalar(totProcFaces)/Pstream::nProcs();
192 if (totProcPatches == 0)
196 if (totProcFaces == 0)
202 <<
"Number of processor faces = " << totProcFaces/2 <<
nl 203 <<
"Max number of cells = " << maxProcCells
204 <<
" (" << 100.0*(maxProcCells-avgProcCells)/avgProcCells
205 <<
"% above average " << avgProcCells <<
")" <<
nl 206 <<
"Max number of processor patches = " << maxProcPatches
207 <<
" (" << 100.0*(maxProcPatches-avgProcPatches)/avgProcPatches
208 <<
"% above average " << avgProcPatches <<
")" <<
nl 209 <<
"Max number of faces between processors = " << maxProcFaces
210 <<
" (" << 100.0*(maxProcFaces-avgProcFaces)/avgProcFaces
211 <<
"% above average " << avgProcFaces <<
")" <<
nl 217 void writeDecomposition
224 Info<<
"Writing wanted cell distribution to volScalarField " << name
225 <<
" for postprocessing purposes." <<
nl <<
endl;
232 mesh.time().timeName(),
235 IOobject::AUTO_WRITE,
240 extrapolatedCalculatedFvPatchScalarField::typeName
245 procCells[cI] = decomp[cI];
247 procCells.correctBoundaryConditions();
253 template<
class GeoField>
258 const autoPtr<fvMeshSubset>& subsetterPtr,
259 IOobjectList& allObjects,
260 PtrList<GeoField>& fields
264 IOobjectList objects(allObjects.lookupClass(GeoField::typeName));
267 wordList objectNames = objects.toc();
271 Pstream::scatter(masterNames);
273 if (haveMesh[Pstream::myProcNo()] && objectNames != masterNames)
276 <<
"differing fields of type " << GeoField::typeName
277 <<
" on processors." << endl
278 <<
"Master has:" << masterNames << endl
279 << Pstream::myProcNo() <<
" has:" << objectNames
283 fields.setSize(masterNames.size());
286 if (Pstream::master())
290 const word& name = masterNames[i];
291 IOobject& io = *objects[
name];
292 io.writeOpt() = IOobject::AUTO_WRITE;
295 fields.set(i,
new GeoField(io, mesh));
298 if (subsetterPtr.valid())
300 tmp<GeoField> tsubfld = subsetterPtr().interpolate(fields[i]);
303 for (
label proci = 1; proci < Pstream::nProcs(); proci++)
305 if (!haveMesh[proci])
307 OPstream toProc(Pstream::commsTypes::blocking, proci);
314 else if (!haveMesh[Pstream::myProcNo()])
320 const word& name = masterNames[i];
325 Pstream::commsTypes::blocking,
328 dictionary fieldDict(fromMaster);
338 mesh.time().timeName(),
357 const word& name = masterNames[i];
358 IOobject& io = *objects[
name];
359 io.writeOpt() = IOobject::AUTO_WRITE;
362 fields.set(i,
new GeoField(io, mesh));
378 if (
mag(b[celli] - a[celli]) > tolDim)
381 <<
"Did not map volVectorField correctly:" <<
nl 383 <<
" transfer b:" << b[celli]
384 <<
" real cc:" << a[celli]
394 a.boundaryField()[
patchi];
397 b.boundaryField()[
patchi];
399 if (!bBoundary.coupled())
403 if (
mag(aBoundary[i] - bBoundary[i]) > tolDim)
406 <<
"Did not map volVectorField correctly:" 408 <<
"patch:" <<
patchi <<
" patchFace:" << i
410 <<
" real :" << aBoundary[i] << endl
411 <<
" mapped :" << bBoundary[i] << endl
412 <<
"This might be just a precision entry" 413 <<
" on writing the mesh." <<
endl;
423 int main(
int argc,
char *argv[])
431 "specify the merge distance relative to the bounding box size " 435 timeSelector::addOptions();
439 if (
env(
"FOAM_SIGFPE"))
442 <<
"Detected floating point exception trapping (FOAM_SIGFPE)." 443 <<
" This might give" <<
nl 444 <<
" problems when mapping fields. Switch it off in case" 445 <<
" of problems." <<
endl;
450 if (!Pstream::master() && !
isDir(args.path()))
452 Pout<<
"Creating case directory " << args.path() <<
endl;
458 regIOobject::fileModificationChecking = regIOobject::timeStamp;
461 instantList times = timeSelector::selectIfPresent(runTime, args);
462 runTime.setTime(times[0], 0);
464 runTime.functionObjects().off();
466 word regionName = polyMesh::defaultRegion;
469 if (args.optionReadIfPresent(
"region", regionName))
471 meshSubDir = regionName/polyMesh::meshSubDir;
475 meshSubDir = polyMesh::meshSubDir;
477 Info<<
"Using mesh subdirectory " << meshSubDir <<
nl <<
endl;
479 const bool overwrite = args.optionFound(
"overwrite");
485 fileName masterInstDir;
486 if (Pstream::master())
488 masterInstDir = runTime.findInstance(meshSubDir,
"points");
490 Pstream::scatter(masterInstDir);
493 const fileName meshPath = runTime.path()/masterInstDir/meshSubDir;
495 Info<<
"Found points in " << meshPath <<
nl <<
endl;
498 boolList haveMesh(Pstream::nProcs(),
false);
499 haveMesh[Pstream::myProcNo()] =
isDir(meshPath);
500 Pstream::gatherList(haveMesh);
501 Pstream::scatterList(haveMesh);
502 Info<<
"Per processor mesh availability : " << haveMesh <<
endl;
503 const bool allHaveMesh = (
findIndex(haveMesh,
false) == -1);
519 Info<<
"Before distribution:" <<
endl;
524 IOdictionary decompositionDict
531 IOobject::MUST_READ_IF_MODIFIED,
540 autoPtr<decompositionMethod> decomposer
548 if (!decomposer().parallelAware())
551 <<
"You have selected decomposition method " 552 << decomposer().typeName
553 <<
" which does" << endl
554 <<
"not synchronise the decomposition across" 555 <<
" processor patches." << endl
556 <<
" You might want to select a decomposition method which" 557 <<
" is aware of this. Continuing." 561 finalDecomp = decomposer().decompose(mesh, mesh.cellCentres());
567 writeDecomposition(
"decomposition", mesh, finalDecomp);
576 autoPtr<fvMeshSubset> subsetterPtr;
581 const polyBoundaryMesh& patches = mesh.boundaryMesh();
587 if (isA<processorPolyPatch>(patches[
patchi]))
597 <<
"Cannot find non-processor patch on processor " 598 << Pstream::myProcNo() << endl
604 subsetterPtr.reset(
new fvMeshSubset(mesh));
605 subsetterPtr().setLargeCellSubset(
labelHashSet(0), nonProci,
false);
610 IOobjectList objects(mesh, runTime.timeName());
613 IOobjectList::iterator iter = objects.find(
"decomposition");
614 if (iter != objects.end())
622 PtrList<volScalarField> volScalarFields;
632 PtrList<volVectorField> volVectorFields;
642 PtrList<volSphericalTensorField> volSphereTensorFields;
649 volSphereTensorFields
652 PtrList<volSymmTensorField> volSymmTensorFields;
662 PtrList<volTensorField> volTensorFields;
675 PtrList<surfaceScalarField> surfScalarFields;
685 PtrList<surfaceVectorField> surfVectorFields;
695 PtrList<surfaceSphericalTensorField> surfSphereTensorFields;
702 surfSphereTensorFields
705 PtrList<surfaceSymmTensorField> surfSymmTensorFields;
715 PtrList<surfaceTensorField> surfTensorFields;
731 const scalar tolDim = getMergeDistance
739 fvMeshDistribute distributor(mesh, tolDim);
745 autoPtr<mapDistributePolyMesh> map = distributor.distribute(finalDecomp);
752 Info<<
"After distribution:" <<
endl;
762 mesh.setInstance(masterInstDir);
764 Info<<
"Writing redistributed mesh to " << runTime.timeName() <<
nl <<
endl;
776 nFaces[Pstream::myProcNo()] = mesh.nFaces();
777 Pstream::gatherList(nFaces);
778 Pstream::scatterList(nFaces);
781 <<
"You can pick up the redecomposed mesh from the polyMesh directory" 782 <<
" in " << runTime.timeName() <<
"." <<
nl 783 <<
"If you redecomposed the mesh to less processors you can delete" 785 <<
"the processor directories with 0 sized meshes in them." <<
nl 786 <<
"Below is a sample set of commands to do this." 787 <<
" Take care when issuing these" <<
nl 788 <<
"commands." <<
nl <<
endl;
792 fileName procDir =
"processor" +
name(proci);
794 if (nFaces[proci] == 0)
796 Info<<
" rm -r " << procDir.c_str() <<
nl;
800 fileName timeDir = procDir/runTime.timeName()/meshSubDir;
801 fileName constDir = procDir/runTime.constant()/meshSubDir;
803 Info<<
" rm -r " << constDir.c_str() <<
nl 804 <<
" mv " << timeDir.c_str()
805 <<
' ' << constDir.c_str() <<
nl;
List< instant > instantList
List of instants.
List< labelList > labelListList
A List of labelList.
#define forAll(list, i)
Loop across all elements in list.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Inter-processor communication reduction functions.
fvPatchField< vector > fvPatchVectorField
errorManipArg< error, int > exit(error &err, const int errNo=1)
void readFields(const typename GeoFieldType::Mesh &mesh, const IOobjectList &objects, const HashSet< word > &selectedFields, LIFOStack< regIOobject *> &storedObjects)
Read the selected GeometricFields of the specified type.
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Ostream & endl(Ostream &os)
Add newline and flush stream.
GeometricField< vector, fvPatchField, volMesh > volVectorField
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
List< bool > boolList
Bool container classes.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
const dimensionedScalar e
Elementary charge.
bool isDir(const fileName &, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Load or create (0 size) a mesh. Used in distributing meshes to a larger number of processors...
List< label > labelList
A List of labels.
errorManip< error > abort(error &err)
autoPtr< fvMesh > loadOrCreateMesh(const IOobject &io)
Load (if it exists) or create zero cell mesh given an IOobject:
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
word name(const complex &)
Return a string representation of a complex.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
List< word > wordList
A List of words.
void setSize(const label)
Reset size of List.
const dimensionSet dimless(0, 0, 0, 0, 0, 0, 0)
#define WarningInFunction
Report a warning using Foam::Warning.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
prefixOSstream Pout(cout, "Pout")
dimensioned< scalar > mag(const dimensioned< Type > &)
virtual Ostream & write(const token &)=0
Write next token to stream.
bool env(const word &)
Return true if environment variable of given name is defined.