00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #include <finiteVolume/fvMesh.H>
00076 #include <decompositionMethods/decompositionMethod.H>
00077 #include <OpenFOAM/PstreamReduceOps.H>
00078 #include <finiteVolume/fvCFD.H>
00079 #include <dynamicMesh/fvMeshDistribute.H>
00080 #include <OpenFOAM/mapDistributePolyMesh.H>
00081 #include <OpenFOAM/IOobjectList.H>
00082
00083
00084
00085
00086
00087 static const scalar defaultMergeTol = 1E-6;
00088
00089
00090
00091
00092
00093 autoPtr<fvMesh> createMesh
00094 (
00095 const Time& runTime,
00096 const word& regionName,
00097 const fileName& instDir,
00098 const bool haveMesh
00099 )
00100 {
00101 Pout<< "Create mesh for time = "
00102 << runTime.timeName() << nl << endl;
00103
00104 IOobject io
00105 (
00106 regionName,
00107 instDir,
00108 runTime,
00109 IOobject::MUST_READ
00110 );
00111
00112 if (!haveMesh)
00113 {
00114
00115 fvMesh dummyMesh
00116 (
00117 io,
00118 xferCopy(pointField()),
00119 xferCopy(faceList()),
00120 xferCopy(labelList()),
00121 xferCopy(labelList()),
00122 false
00123 );
00124 Pout<< "Writing dummy mesh to " << dummyMesh.polyMesh::objectPath()
00125 << endl;
00126 dummyMesh.write();
00127 }
00128
00129 Pout<< "Reading mesh from " << io.objectPath() << endl;
00130 autoPtr<fvMesh> meshPtr(new fvMesh(io));
00131 fvMesh& mesh = meshPtr();
00132
00133
00134
00135 if (Pstream::master())
00136 {
00137
00138 for
00139 (
00140 int slave=Pstream::firstSlave();
00141 slave<=Pstream::lastSlave();
00142 slave++
00143 )
00144 {
00145 OPstream toSlave(Pstream::blocking, slave);
00146 toSlave << mesh.boundaryMesh();
00147 }
00148 }
00149 else
00150 {
00151
00152 IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
00153 PtrList<entry> patchEntries(fromMaster);
00154
00155 if (haveMesh)
00156 {
00157
00158
00159 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00160
00161 forAll(patchEntries, patchI)
00162 {
00163 const entry& e = patchEntries[patchI];
00164 const word type(e.dict().lookup("type"));
00165 const word& name = e.keyword();
00166
00167 if (type == processorPolyPatch::typeName)
00168 {
00169 break;
00170 }
00171
00172 if (patchI >= patches.size())
00173 {
00174 FatalErrorIn
00175 (
00176 "createMesh(const Time&, const fileName&, const bool)"
00177 ) << "Non-processor patches not synchronised."
00178 << endl
00179 << "Processor " << Pstream::myProcNo()
00180 << " has only " << patches.size()
00181 << " patches, master has "
00182 << patchI
00183 << exit(FatalError);
00184 }
00185
00186 if
00187 (
00188 type != patches[patchI].type()
00189 || name != patches[patchI].name()
00190 )
00191 {
00192 FatalErrorIn
00193 (
00194 "createMesh(const Time&, const fileName&, const bool)"
00195 ) << "Non-processor patches not synchronised."
00196 << endl
00197 << "Master patch " << patchI
00198 << " name:" << type
00199 << " type:" << type << endl
00200 << "Processor " << Pstream::myProcNo()
00201 << " patch " << patchI
00202 << " has name:" << patches[patchI].name()
00203 << " type:" << patches[patchI].type()
00204 << exit(FatalError);
00205 }
00206 }
00207 }
00208 else
00209 {
00210
00211 List<polyPatch*> patches(patchEntries.size());
00212 label nPatches = 0;
00213
00214 forAll(patchEntries, patchI)
00215 {
00216 const entry& e = patchEntries[patchI];
00217 const word type(e.dict().lookup("type"));
00218 const word& name = e.keyword();
00219
00220 if (type == processorPolyPatch::typeName)
00221 {
00222 break;
00223 }
00224
00225 Pout<< "Adding patch:" << nPatches
00226 << " name:" << name
00227 << " type:" << type << endl;
00228
00229 dictionary patchDict(e.dict());
00230 patchDict.remove("nFaces");
00231 patchDict.add("nFaces", 0);
00232 patchDict.remove("startFace");
00233 patchDict.add("startFace", 0);
00234
00235 patches[patchI] = polyPatch::New
00236 (
00237 name,
00238 patchDict,
00239 nPatches++,
00240 mesh.boundaryMesh()
00241 ).ptr();
00242 }
00243 patches.setSize(nPatches);
00244 mesh.addFvPatches(patches, false);
00245
00247
00248 }
00249 }
00250
00251 if (!haveMesh)
00252 {
00253
00254 Pout<< "Removing dummy mesh " << io.objectPath()
00255 << endl;
00256 rmDir(io.objectPath());
00257 }
00258
00259
00260 mesh.clearOut();
00261 mesh.globalData();
00262
00263 return meshPtr;
00264 }
00265
00266
00267
00268 scalar getMergeDistance
00269 (
00270 const argList& args,
00271 const Time& runTime,
00272 const boundBox& bb
00273 )
00274 {
00275 scalar mergeTol = defaultMergeTol;
00276 args.optionReadIfPresent("mergeTol", mergeTol);
00277
00278 scalar writeTol =
00279 Foam::pow(scalar(10.0), -scalar(IOstream::defaultPrecision()));
00280
00281 Info<< "Merge tolerance : " << mergeTol << nl
00282 << "Write tolerance : " << writeTol << endl;
00283
00284 if (runTime.writeFormat() == IOstream::ASCII && mergeTol < writeTol)
00285 {
00286 FatalErrorIn("getMergeDistance")
00287 << "Your current settings specify ASCII writing with "
00288 << IOstream::defaultPrecision() << " digits precision." << endl
00289 << "Your merging tolerance (" << mergeTol << ") is finer than this."
00290 << endl
00291 << "Please change your writeFormat to binary"
00292 << " or increase the writePrecision" << endl
00293 << "or adjust the merge tolerance (-mergeTol)."
00294 << exit(FatalError);
00295 }
00296
00297 scalar mergeDist = mergeTol * bb.mag();
00298
00299 Info<< "Overall meshes bounding box : " << bb << nl
00300 << "Relative tolerance : " << mergeTol << nl
00301 << "Absolute matching distance : " << mergeDist << nl
00302 << endl;
00303
00304 return mergeDist;
00305 }
00306
00307
00308 void printMeshData(Ostream& os, const polyMesh& mesh)
00309 {
00310 os << "Number of points: " << mesh.points().size() << nl
00311 << " faces: " << mesh.faces().size() << nl
00312 << " internal faces: " << mesh.faceNeighbour().size() << nl
00313 << " cells: " << mesh.cells().size() << nl
00314 << " boundary patches: " << mesh.boundaryMesh().size() << nl
00315 << " point zones: " << mesh.pointZones().size() << nl
00316 << " face zones: " << mesh.faceZones().size() << nl
00317 << " cell zones: " << mesh.cellZones().size() << nl;
00318 }
00319
00320
00321
00322 void writeDecomposition
00323 (
00324 const word& name,
00325 const fvMesh& mesh,
00326 const labelList& decomp
00327 )
00328 {
00329 Info<< "Writing wanted cell distribution to volScalarField " << name
00330 << " for postprocessing purposes." << nl << endl;
00331
00332 volScalarField procCells
00333 (
00334 IOobject
00335 (
00336 name,
00337 mesh.time().timeName(),
00338 mesh,
00339 IOobject::NO_READ,
00340 IOobject::AUTO_WRITE,
00341 false
00342 ),
00343 mesh,
00344 dimensionedScalar(name, dimless, -1),
00345 zeroGradientFvPatchScalarField::typeName
00346 );
00347
00348 forAll(procCells, cI)
00349 {
00350 procCells[cI] = decomp[cI];
00351 }
00352 procCells.write();
00353 }
00354
00355
00356
00357
00358 template<class GeoField>
00359 void readFields
00360 (
00361 const boolList& haveMesh,
00362 const fvMesh& mesh,
00363 const autoPtr<fvMeshSubset>& subsetterPtr,
00364 IOobjectList& allObjects,
00365 PtrList<GeoField>& fields
00366 )
00367 {
00368
00369
00370
00371 IOobjectList objects(allObjects.lookupClass(GeoField::typeName));
00372
00373 wordList objectNames = objects.toc();
00374
00375 wordList masterNames(objectNames);
00376 Pstream::scatter(masterNames);
00377
00378 if (haveMesh[Pstream::myProcNo()] && objectNames != masterNames)
00379 {
00380 FatalErrorIn("readFields()")
00381 << "differing fields of type " << GeoField::typeName
00382 << " on processors." << endl
00383 << "Master has:" << masterNames << endl
00384 << Pstream::myProcNo() << " has:" << objectNames
00385 << abort(FatalError);
00386 }
00387
00388 fields.setSize(masterNames.size());
00389
00390
00391 if (Pstream::master())
00392 {
00393 forAll(masterNames, i)
00394 {
00395 const word& name = masterNames[i];
00396 IOobject& io = *objects[name];
00397 io.writeOpt() = IOobject::AUTO_WRITE;
00398
00399
00400 fields.set(i, new GeoField(io, mesh));
00401
00402
00403 if (subsetterPtr.valid())
00404 {
00405 tmp<GeoField> tsubfld = subsetterPtr().interpolate(fields[i]);
00406
00407
00408 for (label procI = 1; procI < Pstream::nProcs(); procI++)
00409 {
00410 if (!haveMesh[procI])
00411 {
00412 OPstream toProc(Pstream::blocking, procI);
00413 toProc<< tsubfld();
00414 }
00415 }
00416 }
00417 }
00418 }
00419 else if (!haveMesh[Pstream::myProcNo()])
00420 {
00421
00422
00423 forAll(masterNames, i)
00424 {
00425 const word& name = masterNames[i];
00426
00427
00428 IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
00429
00430 fields.set
00431 (
00432 i,
00433 new GeoField
00434 (
00435 IOobject
00436 (
00437 name,
00438 mesh.time().timeName(),
00439 mesh,
00440 IOobject::NO_READ,
00441 IOobject::AUTO_WRITE
00442 ),
00443 mesh,
00444 fromMaster
00445 )
00446 );
00447
00449
00450 }
00451 }
00452 else
00453 {
00454
00455 forAll(masterNames, i)
00456 {
00457 const word& name = masterNames[i];
00458 IOobject& io = *objects[name];
00459 io.writeOpt() = IOobject::AUTO_WRITE;
00460
00461
00462 fields.set(i, new GeoField(io, mesh));
00463 }
00464 }
00465 }
00466
00467
00468
00469 void compareFields
00470 (
00471 const scalar tolDim,
00472 const volVectorField& a,
00473 const volVectorField& b
00474 )
00475 {
00476 forAll(a, cellI)
00477 {
00478 if (mag(b[cellI] - a[cellI]) > tolDim)
00479 {
00480 FatalErrorIn
00481 (
00482 "compareFields"
00483 "(const scalar, const volVectorField&, const volVectorField&)"
00484 ) << "Did not map volVectorField correctly:" << nl
00485 << "cell:" << cellI
00486 << " transfer b:" << b[cellI]
00487 << " real cc:" << a[cellI]
00488 << abort(FatalError);
00489 }
00490 }
00491 forAll(a.boundaryField(), patchI)
00492 {
00493
00494
00495
00496 const fvPatchVectorField& aBoundary =
00497 a.boundaryField()[patchI];
00498
00499 const fvPatchVectorField& bBoundary =
00500 b.boundaryField()[patchI];
00501
00502 if (!bBoundary.coupled())
00503 {
00504 forAll(aBoundary, i)
00505 {
00506 if (mag(aBoundary[i] - bBoundary[i]) > tolDim)
00507 {
00508 FatalErrorIn
00509 (
00510 "compareFields"
00511 "(const scalar, const volVectorField&"
00512 ", const volVectorField&)"
00513 ) << "Did not map volVectorField correctly:"
00514 << endl
00515 << "patch:" << patchI << " patchFace:" << i
00516 << " cc:" << endl
00517 << " real :" << aBoundary[i] << endl
00518 << " mapped :" << bBoundary[i] << endl
00519 << abort(FatalError);
00520 }
00521 }
00522 }
00523 }
00524 }
00525
00526
00527
00528
00529 int main(int argc, char *argv[])
00530 {
00531 # include <OpenFOAM/addRegionOption.H>
00532 argList::validOptions.insert("mergeTol", "relative merge distance");
00533
00534 # include <OpenFOAM/setRootCase.H>
00535
00536
00537 if (!Pstream::master() && !isDir(args.path()))
00538 {
00539 Pout<< "Creating case directory " << args.path() << endl;
00540 mkDir(args.path());
00541 }
00542
00543 # include <OpenFOAM/createTime.H>
00544
00545 word regionName = polyMesh::defaultRegion;
00546 fileName meshSubDir;
00547
00548 if (args.optionReadIfPresent("region", regionName))
00549 {
00550 meshSubDir = regionName/polyMesh::meshSubDir;
00551 }
00552 else
00553 {
00554 meshSubDir = polyMesh::meshSubDir;
00555 }
00556 Info<< "Using mesh subdirectory " << meshSubDir << nl << endl;
00557
00558
00559
00560
00561
00562 fileName masterInstDir;
00563 if (Pstream::master())
00564 {
00565 masterInstDir = runTime.findInstance(meshSubDir, "points");
00566 }
00567 Pstream::scatter(masterInstDir);
00568
00569
00570 const fileName meshPath = runTime.path()/masterInstDir/meshSubDir;
00571
00572 Info<< "Found points in " << meshPath << nl << endl;
00573
00574
00575 boolList haveMesh(Pstream::nProcs(), false);
00576 haveMesh[Pstream::myProcNo()] = isDir(meshPath);
00577 Pstream::gatherList(haveMesh);
00578 Pstream::scatterList(haveMesh);
00579 Info<< "Per processor mesh availability : " << haveMesh << endl;
00580 const bool allHaveMesh = (findIndex(haveMesh, false) == -1);
00581
00582
00583 autoPtr<fvMesh> meshPtr = createMesh
00584 (
00585 runTime,
00586 regionName,
00587 masterInstDir,
00588 haveMesh[Pstream::myProcNo()]
00589 );
00590 fvMesh& mesh = meshPtr();
00591
00592 Pout<< "Read mesh:" << endl;
00593 printMeshData(Pout, mesh);
00594 Pout<< endl;
00595
00596 IOdictionary decompositionDict
00597 (
00598 IOobject
00599 (
00600 "decomposeParDict",
00601 runTime.system(),
00602 mesh,
00603 IOobject::MUST_READ,
00604 IOobject::NO_WRITE
00605 )
00606 );
00607
00608 labelList finalDecomp;
00609
00610
00611 {
00612 autoPtr<decompositionMethod> decomposer
00613 (
00614 decompositionMethod::New
00615 (
00616 decompositionDict,
00617 mesh
00618 )
00619 );
00620
00621 if (!decomposer().parallelAware())
00622 {
00623 WarningIn(args.executable())
00624 << "You have selected decomposition method "
00625 << decomposer().typeName
00626 << " which does" << endl
00627 << "not synchronise the decomposition across"
00628 << " processor patches." << endl
00629 << " You might want to select a decomposition method which"
00630 << " is aware of this. Continuing."
00631 << endl;
00632 }
00633
00634 finalDecomp = decomposer().decompose(mesh.cellCentres());
00635 }
00636
00637
00638 writeDecomposition("decomposition", mesh, finalDecomp);
00639
00640
00641
00642
00643
00644
00645
00646 autoPtr<fvMeshSubset> subsetterPtr;
00647
00648 if (!allHaveMesh)
00649 {
00650
00651 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00652
00653 label nonProcI = -1;
00654
00655 forAll(patches, patchI)
00656 {
00657 if (isA<processorPolyPatch>(patches[patchI]))
00658 {
00659 break;
00660 }
00661 nonProcI++;
00662 }
00663
00664 if (nonProcI == -1)
00665 {
00666 FatalErrorIn(args.executable())
00667 << "Cannot find non-processor patch on processor "
00668 << Pstream::myProcNo() << endl
00669 << " Current patches:" << patches.names() << abort(FatalError);
00670 }
00671
00672
00673
00674 subsetterPtr.reset(new fvMeshSubset(mesh));
00675 subsetterPtr().setLargeCellSubset(labelHashSet(0), nonProcI, false);
00676 }
00677
00678
00679
00680 IOobjectList objects(mesh, runTime.timeName());
00681
00682
00683 IOobjectList::iterator iter = objects.find("decomposition");
00684 if (iter != objects.end())
00685 {
00686 objects.erase(iter);
00687 }
00688
00689 PtrList<volScalarField> volScalarFields;
00690 readFields
00691 (
00692 haveMesh,
00693 mesh,
00694 subsetterPtr,
00695 objects,
00696 volScalarFields
00697 );
00698
00699 PtrList<volVectorField> volVectorFields;
00700 readFields
00701 (
00702 haveMesh,
00703 mesh,
00704 subsetterPtr,
00705 objects,
00706 volVectorFields
00707 );
00708
00709 PtrList<volSphericalTensorField> volSphereTensorFields;
00710 readFields
00711 (
00712 haveMesh,
00713 mesh,
00714 subsetterPtr,
00715 objects,
00716 volSphereTensorFields
00717 );
00718
00719 PtrList<volSymmTensorField> volSymmTensorFields;
00720 readFields
00721 (
00722 haveMesh,
00723 mesh,
00724 subsetterPtr,
00725 objects,
00726 volSymmTensorFields
00727 );
00728
00729 PtrList<volTensorField> volTensorFields;
00730 readFields
00731 (
00732 haveMesh,
00733 mesh,
00734 subsetterPtr,
00735 objects,
00736 volTensorFields
00737 );
00738
00739 PtrList<surfaceScalarField> surfScalarFields;
00740 readFields
00741 (
00742 haveMesh,
00743 mesh,
00744 subsetterPtr,
00745 objects,
00746 surfScalarFields
00747 );
00748
00749 PtrList<surfaceVectorField> surfVectorFields;
00750 readFields
00751 (
00752 haveMesh,
00753 mesh,
00754 subsetterPtr,
00755 objects,
00756 surfVectorFields
00757 );
00758
00759 PtrList<surfaceSphericalTensorField> surfSphereTensorFields;
00760 readFields
00761 (
00762 haveMesh,
00763 mesh,
00764 subsetterPtr,
00765 objects,
00766 surfSphereTensorFields
00767 );
00768
00769 PtrList<surfaceSymmTensorField> surfSymmTensorFields;
00770 readFields
00771 (
00772 haveMesh,
00773 mesh,
00774 subsetterPtr,
00775 objects,
00776 surfSymmTensorFields
00777 );
00778
00779 PtrList<surfaceTensorField> surfTensorFields;
00780 readFields
00781 (
00782 haveMesh,
00783 mesh,
00784 subsetterPtr,
00785 objects,
00786 surfTensorFields
00787 );
00788
00789
00790
00791
00792 volVectorField mapCc("mapCc", 1*mesh.C());
00793
00794
00795 const scalar tolDim = getMergeDistance
00796 (
00797 args,
00798 runTime,
00799 mesh.globalData().bb()
00800 );
00801
00802
00803 fvMeshDistribute distributor(mesh, tolDim);
00804
00805 Pout<< "Wanted distribution:"
00806 << distributor.countCells(finalDecomp) << nl << endl;
00807
00808
00809 autoPtr<mapDistributePolyMesh> map = distributor.distribute(finalDecomp);
00810
00812
00813
00814
00815
00816 Pout<< "After distribution mesh:" << endl;
00817 printMeshData(Pout, mesh);
00818 Pout<< endl;
00819
00820 runTime++;
00821 Pout<< "Writing redistributed mesh to " << runTime.timeName() << nl << endl;
00822 mesh.write();
00823
00824
00825
00826 compareFields(tolDim, mesh.C(), mapCc);
00827
00828
00829
00830
00831
00832 labelList nFaces(Pstream::nProcs());
00833 nFaces[Pstream::myProcNo()] = mesh.nFaces();
00834 Pstream::gatherList(nFaces);
00835 Pstream::scatterList(nFaces);
00836
00837 Info<< nl
00838 << "You can pick up the redecomposed mesh from the polyMesh directory"
00839 << " in " << runTime.timeName() << "." << nl
00840 << "If you redecomposed the mesh to less processors you can delete"
00841 << nl
00842 << "the processor directories with 0 sized meshes in them." << nl
00843 << "Below is a sample set of commands to do this."
00844 << " Take care when issuing these" << nl
00845 << "commands." << nl << endl;
00846
00847 forAll(nFaces, procI)
00848 {
00849 fileName procDir = "processor" + name(procI);
00850
00851 if (nFaces[procI] == 0)
00852 {
00853 Info<< " rm -r " << procDir.c_str() << nl;
00854 }
00855 else
00856 {
00857 fileName timeDir = procDir/runTime.timeName()/meshSubDir;
00858 fileName constDir = procDir/runTime.constant()/meshSubDir;
00859
00860 Info<< " rm -r " << constDir.c_str() << nl
00861 << " mv " << timeDir.c_str()
00862 << ' ' << constDir.c_str() << nl;
00863 }
00864 }
00865 Info<< endl;
00866
00867
00868 Pout<< "End\n" << endl;
00869
00870 return 0;
00871 }
00872
00873
00874