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
00076
00077
00078 #include <OpenFOAM/argList.H>
00079 #include <OpenFOAM/Time.H>
00080 #include <OpenFOAM/IOobjectList.H>
00081 #include <OpenFOAM/labelIOList.H>
00082 #include <OpenFOAM/processorPolyPatch.H>
00083 #include <OpenFOAM/mapAddedPolyMesh.H>
00084 #include <dynamicMesh/polyMeshAdder.H>
00085 #include <dynamicMesh/faceCoupleInfo.H>
00086 #include <dynamicMesh/fvMeshAdder.H>
00087 #include <dynamicMesh/polyTopoChange.H>
00088
00089 using namespace Foam;
00090
00091
00092
00093
00094
00095 static const scalar defaultMergeTol = 1E-7;
00096
00097
00098 static void renumber
00099 (
00100 const labelList& map,
00101 labelList& elems
00102 )
00103 {
00104 forAll(elems, i)
00105 {
00106 if (elems[i] >= 0)
00107 {
00108 elems[i] = map[elems[i]];
00109 }
00110 }
00111 }
00112
00113
00114
00115
00116
00117
00118 autoPtr<faceCoupleInfo> determineCoupledFaces
00119 (
00120 const bool fullMatch,
00121 const label procI,
00122 const polyMesh& masterMesh,
00123 const polyMesh& meshToAdd,
00124 const scalar mergeDist
00125 )
00126 {
00127 if (fullMatch || masterMesh.nCells() == 0)
00128 {
00129 return autoPtr<faceCoupleInfo>
00130 (
00131 new faceCoupleInfo
00132 (
00133 masterMesh,
00134 meshToAdd,
00135 mergeDist,
00136 true
00137 )
00138 );
00139 }
00140 else
00141 {
00142
00143
00144
00145 const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
00146
00147 const string toProcString("to" + name(procI));
00148
00149 DynamicList<label> masterFaces
00150 (
00151 masterMesh.nFaces()
00152 - masterMesh.nInternalFaces()
00153 );
00154
00155 forAll(masterPatches, patchI)
00156 {
00157 const polyPatch& pp = masterPatches[patchI];
00158
00159 if
00160 (
00161 isA<processorPolyPatch>(pp)
00162 && (
00163 pp.name().rfind(toProcString)
00164 == (pp.name().size()-toProcString.size())
00165 )
00166 )
00167 {
00168 label meshFaceI = pp.start();
00169 forAll(pp, i)
00170 {
00171 masterFaces.append(meshFaceI++);
00172 }
00173 }
00174 }
00175 masterFaces.shrink();
00176
00177
00178
00179
00180
00181 const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
00182
00183 DynamicList<label> addFaces
00184 (
00185 meshToAdd.nFaces()
00186 - meshToAdd.nInternalFaces()
00187 );
00188
00189 forAll(addPatches, patchI)
00190 {
00191 const polyPatch& pp = addPatches[patchI];
00192
00193 if (isA<processorPolyPatch>(pp))
00194 {
00195 bool isConnected = false;
00196
00197 for (label mergedProcI = 0; mergedProcI < procI; mergedProcI++)
00198 {
00199 const string fromProcString
00200 (
00201 "procBoundary"
00202 + name(procI)
00203 + "to"
00204 + name(mergedProcI)
00205 );
00206
00207 if (pp.name() == fromProcString)
00208 {
00209 isConnected = true;
00210 break;
00211 }
00212 }
00213
00214 if (isConnected)
00215 {
00216 label meshFaceI = pp.start();
00217 forAll(pp, i)
00218 {
00219 addFaces.append(meshFaceI++);
00220 }
00221 }
00222 }
00223 }
00224 addFaces.shrink();
00225
00226 return autoPtr<faceCoupleInfo>
00227 (
00228 new faceCoupleInfo
00229 (
00230 masterMesh,
00231 masterFaces,
00232 meshToAdd,
00233 addFaces,
00234 mergeDist,
00235 true,
00236 false,
00237
00238 false
00239 )
00240 );
00241 }
00242 }
00243
00244
00245 autoPtr<mapPolyMesh> mergeSharedPoints
00246 (
00247 const scalar mergeDist,
00248 polyMesh& mesh,
00249 labelListList& pointProcAddressing
00250 )
00251 {
00252
00253
00254 Map<label> pointToMaster
00255 (
00256 fvMeshAdder::findSharedPoints
00257 (
00258 mesh,
00259 mergeDist
00260 )
00261 );
00262
00263 Info<< "mergeSharedPoints : detected " << pointToMaster.size()
00264 << " points that are to be merged." << endl;
00265
00266 if (returnReduce(pointToMaster.size(), sumOp<label>()) == 0)
00267 {
00268 return autoPtr<mapPolyMesh>(NULL);
00269 }
00270
00271 polyTopoChange meshMod(mesh);
00272
00273 fvMeshAdder::mergePoints(mesh, pointToMaster, meshMod);
00274
00275
00276 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
00277
00278
00279 mesh.updateMesh(map);
00280
00281
00282
00283
00284
00285 forAll(pointProcAddressing, procI)
00286 {
00287 labelList& constructMap = pointProcAddressing[procI];
00288
00289 forAll(constructMap, i)
00290 {
00291 label oldPointI = constructMap[i];
00292
00293
00294 label newPointI = map().reversePointMap()[oldPointI];
00295
00296 if (newPointI < -1)
00297 {
00298 constructMap[i] = -newPointI-2;
00299 }
00300 else if (newPointI >= 0)
00301 {
00302 constructMap[i] = newPointI;
00303 }
00304 else
00305 {
00306 FatalErrorIn("fvMeshDistribute::mergeSharedPoints()")
00307 << "Problem. oldPointI:" << oldPointI
00308 << " newPointI:" << newPointI << abort(FatalError);
00309 }
00310 }
00311 }
00312
00313 return map;
00314 }
00315
00316
00317 int main(int argc, char *argv[])
00318 {
00319 argList::noParallel();
00320 argList::validOptions.insert("mergeTol", "relative merge distance");
00321 argList::validOptions.insert("fullMatch", "");
00322
00323 # include <OpenFOAM/addTimeOptions.H>
00324 # include <OpenFOAM/addRegionOption.H>
00325 # include <OpenFOAM/setRootCase.H>
00326 # include <OpenFOAM/createTime.H>
00327
00328 Info<< "This is an experimental tool which tries to merge"
00329 << " individual processor" << nl
00330 << "meshes back into one master mesh. Use it if the original"
00331 << " master mesh has" << nl
00332 << "been deleted or if the processor meshes have been modified"
00333 << " (topology change)." << nl
00334 << "This tool will write the resulting mesh to a new time step"
00335 << " and construct" << nl
00336 << "xxxxProcAddressing files in the processor meshes so"
00337 << " reconstructPar can be" << nl
00338 << "used to regenerate the fields on the master mesh." << nl
00339 << nl
00340 << "Not well tested & use at your own risk!" << nl
00341 << endl;
00342
00343
00344 word regionName = polyMesh::defaultRegion;
00345 fileName regionPrefix = "";
00346 if (args.optionFound("region"))
00347 {
00348 regionName = args.option("region");
00349 regionPrefix = regionName;
00350 Info<< "Operating on region " << regionName << nl << endl;
00351 }
00352
00353 scalar mergeTol = defaultMergeTol;
00354 args.optionReadIfPresent("mergeTol", mergeTol);
00355
00356 scalar writeTol = Foam::pow(10.0, -scalar(IOstream::defaultPrecision()));
00357
00358 Info<< "Merge tolerance : " << mergeTol << nl
00359 << "Write tolerance : " << writeTol << endl;
00360
00361 if (runTime.writeFormat() == IOstream::ASCII && mergeTol < writeTol)
00362 {
00363 FatalErrorIn(args.executable())
00364 << "Your current settings specify ASCII writing with "
00365 << IOstream::defaultPrecision() << " digits precision." << endl
00366 << "Your merging tolerance (" << mergeTol << ") is finer than this."
00367 << endl
00368 << "Please change your writeFormat to binary"
00369 << " or increase the writePrecision" << endl
00370 << "or adjust the merge tolerance (-mergeTol)."
00371 << exit(FatalError);
00372 }
00373
00374
00375 const bool fullMatch = args.optionFound("fullMatch");
00376
00377 if (fullMatch)
00378 {
00379 Info<< "Doing geometric matching on all boundary faces." << nl << endl;
00380 }
00381 else
00382 {
00383 Info<< "Doing geometric matching on correct procBoundaries only."
00384 << nl << "This assumes a correct decomposition." << endl;
00385 }
00386
00387
00388
00389 int nProcs = 0;
00390
00391 while
00392 (
00393 isDir
00394 (
00395 args.rootPath()
00396 / args.caseName()
00397 / fileName(word("processor") + name(nProcs))
00398 )
00399 )
00400 {
00401 nProcs++;
00402 }
00403
00404 Info<< "Found " << nProcs << " processor directories" << nl << endl;
00405
00406
00407
00408 PtrList<Time> databases(nProcs);
00409
00410 forAll (databases, procI)
00411 {
00412 Info<< "Reading database "
00413 << args.caseName()/fileName(word("processor") + name(procI))
00414 << endl;
00415
00416 databases.set
00417 (
00418 procI,
00419 new Time
00420 (
00421 Time::controlDictName,
00422 args.rootPath(),
00423 args.caseName()/fileName(word("processor") + name(procI))
00424 )
00425 );
00426
00427 Time& procTime = databases[procI];
00428
00429 instantList Times = procTime.times();
00430
00431
00432 # include <OpenFOAM/checkTimeOptions.H>
00433
00434 procTime.setTime(Times[startTime], startTime);
00435
00436 if (procI > 0 && databases[procI-1].value() != procTime.value())
00437 {
00438 FatalErrorIn(args.executable())
00439 << "Time not equal on processors." << nl
00440 << "Processor:" << procI-1
00441 << " time:" << databases[procI-1].value() << nl
00442 << "Processor:" << procI
00443 << " time:" << procTime.value()
00444 << exit(FatalError);
00445 }
00446 }
00447
00448
00449 Info<< "Setting master time to " << databases[0].timeName() << nl << endl;
00450 runTime.setTime(databases[0]);
00451
00452
00453
00454
00455
00456 boundBox bb = boundBox::invertedBox;
00457
00458 for (label procI = 0; procI < nProcs; procI++)
00459 {
00460 fileName pointsInstance
00461 (
00462 databases[procI].findInstance
00463 (
00464 regionPrefix/polyMesh::meshSubDir,
00465 "points"
00466 )
00467 );
00468
00469 if (pointsInstance != databases[procI].timeName())
00470 {
00471 FatalErrorIn(args.executable())
00472 << "Your time was specified as " << databases[procI].timeName()
00473 << " but there is no polyMesh/points in that time." << endl
00474 << "(there is a points file in " << pointsInstance
00475 << ")" << endl
00476 << "Please rerun with the correct time specified"
00477 << " (through the -constant, -time or -latestTime option)."
00478 << endl << exit(FatalError);
00479 }
00480
00481 Info<< "Reading points from "
00482 << databases[procI].caseName()
00483 << " for time = " << databases[procI].timeName()
00484 << nl << endl;
00485
00486 pointIOField points
00487 (
00488 IOobject
00489 (
00490 "points",
00491 databases[procI].findInstance
00492 (
00493 regionPrefix/polyMesh::meshSubDir,
00494 "points"
00495 ),
00496 regionPrefix/polyMesh::meshSubDir,
00497 databases[procI],
00498 IOobject::MUST_READ,
00499 IOobject::NO_WRITE,
00500 false
00501 )
00502 );
00503
00504 boundBox domainBb(points, false);
00505
00506 bb.min() = min(bb.min(), domainBb.min());
00507 bb.max() = max(bb.max(), domainBb.max());
00508 }
00509 const scalar mergeDist = mergeTol * bb.mag();
00510
00511 Info<< "Overall mesh bounding box : " << bb << nl
00512 << "Relative tolerance : " << mergeTol << nl
00513 << "Absolute matching distance : " << mergeDist << nl
00514 << endl;
00515
00516
00517
00518 labelListList cellProcAddressing(nProcs);
00519 labelListList faceProcAddressing(nProcs);
00520 labelListList pointProcAddressing(nProcs);
00521 labelListList boundaryProcAddressing(nProcs);
00522
00523
00524 label masterInternalFaces;
00525
00526 labelList masterOwner;
00527
00528 {
00529
00530 Info<< "Constructing empty mesh to add to." << nl << endl;
00531 polyMesh masterMesh
00532 (
00533 IOobject
00534 (
00535 regionName,
00536 runTime.timeName(),
00537 runTime,
00538 IOobject::NO_READ
00539 ),
00540 xferCopy(pointField()),
00541 xferCopy(faceList()),
00542 xferCopy(cellList())
00543 );
00544
00545 for (label procI = 0; procI < nProcs; procI++)
00546 {
00547 Info<< "Reading mesh to add from "
00548 << databases[procI].caseName()
00549 << " for time = " << databases[procI].timeName()
00550 << nl << endl;
00551
00552 polyMesh meshToAdd
00553 (
00554 IOobject
00555 (
00556 regionName,
00557 databases[procI].timeName(),
00558 databases[procI]
00559 )
00560 );
00561
00562
00563 cellProcAddressing[procI] = identity(meshToAdd.nCells());
00564 faceProcAddressing[procI] = identity(meshToAdd.nFaces());
00565 pointProcAddressing[procI] = identity(meshToAdd.nPoints());
00566 boundaryProcAddressing[procI] =
00567 identity(meshToAdd.boundaryMesh().size());
00568
00569
00570
00571 autoPtr<faceCoupleInfo> couples = determineCoupledFaces
00572 (
00573 fullMatch,
00574 procI,
00575 masterMesh,
00576 meshToAdd,
00577 mergeDist
00578 );
00579
00580
00581
00582 Info<< "Adding to master mesh" << nl << endl;
00583
00584 autoPtr<mapAddedPolyMesh> map = polyMeshAdder::add
00585 (
00586 masterMesh,
00587 meshToAdd,
00588 couples
00589 );
00590
00591
00592
00593
00594
00595 for (label mergedI = 0; mergedI < procI; mergedI++)
00596 {
00597 renumber(map().oldCellMap(), cellProcAddressing[mergedI]);
00598 renumber(map().oldFaceMap(), faceProcAddressing[mergedI]);
00599 renumber(map().oldPointMap(), pointProcAddressing[mergedI]);
00600
00601 renumber(map().oldPatchMap(), boundaryProcAddressing[mergedI]);
00602 }
00603
00604
00605 renumber(map().addedCellMap(), cellProcAddressing[procI]);
00606 renumber(map().addedFaceMap(), faceProcAddressing[procI]);
00607 renumber(map().addedPointMap(), pointProcAddressing[procI]);
00608 renumber(map().addedPatchMap(), boundaryProcAddressing[procI]);
00609
00610 Info<< endl;
00611 }
00612
00613
00614
00615 mergeSharedPoints(mergeDist, masterMesh, pointProcAddressing);
00616
00617
00618 masterInternalFaces = masterMesh.nInternalFaces();
00619 masterOwner = masterMesh.faceOwner();
00620
00621
00622 Info<< "\nWriting merged mesh to "
00623 << runTime.path()/runTime.timeName()
00624 << nl << endl;
00625
00626 if (!masterMesh.write())
00627 {
00628 FatalErrorIn(args.executable())
00629 << "Failed writing polyMesh."
00630 << exit(FatalError);
00631 }
00632 }
00633
00634
00635
00636
00637 Info<< "Reconstructing the addressing from the processor meshes"
00638 << " to the newly reconstructed mesh" << nl << endl;
00639
00640 forAll(databases, procI)
00641 {
00642 Info<< "Reading processor " << procI << " mesh from "
00643 << databases[procI].caseName() << endl;
00644
00645 polyMesh procMesh
00646 (
00647 IOobject
00648 (
00649 regionName,
00650 databases[procI].timeName(),
00651 databases[procI]
00652 )
00653 );
00654
00655
00656
00657
00658 Info<< "Writing pointProcAddressing to "
00659 << databases[procI].caseName()
00660 /procMesh.facesInstance()
00661 /polyMesh::meshSubDir
00662 << endl;
00663
00664 labelIOList
00665 (
00666 IOobject
00667 (
00668 "pointProcAddressing",
00669 procMesh.facesInstance(),
00670 polyMesh::meshSubDir,
00671 procMesh,
00672 IOobject::NO_READ,
00673 IOobject::NO_WRITE,
00674 false
00675 ),
00676 pointProcAddressing[procI]
00677 ).write();
00678
00679
00680
00681
00682 Info<< "Writing faceProcAddressing to "
00683 << databases[procI].caseName()
00684 /procMesh.facesInstance()
00685 /polyMesh::meshSubDir
00686 << endl;
00687
00688 labelIOList faceProcAddr
00689 (
00690 IOobject
00691 (
00692 "faceProcAddressing",
00693 procMesh.facesInstance(),
00694 polyMesh::meshSubDir,
00695 procMesh,
00696 IOobject::NO_READ,
00697 IOobject::NO_WRITE,
00698 false
00699 ),
00700 faceProcAddressing[procI]
00701 );
00702
00703
00704
00705 forAll(faceProcAddr, procFaceI)
00706 {
00707 label masterFaceI = faceProcAddr[procFaceI];
00708
00709 if
00710 (
00711 !procMesh.isInternalFace(procFaceI)
00712 && masterFaceI < masterInternalFaces
00713 )
00714 {
00715
00716
00717
00718 label procOwn = procMesh.faceOwner()[procFaceI];
00719 label masterOwn = masterOwner[masterFaceI];
00720
00721 if (cellProcAddressing[procI][procOwn] == masterOwn)
00722 {
00723
00724 faceProcAddr[procFaceI]++;
00725 }
00726 else
00727 {
00728
00729 faceProcAddr[procFaceI] =
00730 -1 - faceProcAddr[procFaceI];
00731 }
00732 }
00733 else
00734 {
00735
00736 faceProcAddr[procFaceI]++;
00737 }
00738 }
00739
00740 faceProcAddr.write();
00741
00742
00743
00744
00745 Info<< "Writing cellProcAddressing to "
00746 << databases[procI].caseName()
00747 /procMesh.facesInstance()
00748 /polyMesh::meshSubDir
00749 << endl;
00750
00751 labelIOList
00752 (
00753 IOobject
00754 (
00755 "cellProcAddressing",
00756 procMesh.facesInstance(),
00757 polyMesh::meshSubDir,
00758 procMesh,
00759 IOobject::NO_READ,
00760 IOobject::NO_WRITE,
00761 false
00762 ),
00763 cellProcAddressing[procI]
00764 ).write();
00765
00766
00767
00768
00769
00770 Info<< "Writing boundaryProcAddressing to "
00771 << databases[procI].caseName()
00772 /procMesh.facesInstance()
00773 /polyMesh::meshSubDir
00774 << endl;
00775
00776 labelIOList
00777 (
00778 IOobject
00779 (
00780 "boundaryProcAddressing",
00781 procMesh.facesInstance(),
00782 polyMesh::meshSubDir,
00783 procMesh,
00784 IOobject::NO_READ,
00785 IOobject::NO_WRITE,
00786 false
00787 ),
00788 boundaryProcAddressing[procI]
00789 ).write();
00790
00791 Info<< endl;
00792 }
00793
00794 Info<< "End.\n" << endl;
00795
00796 return 0;
00797 }
00798
00799
00800