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