FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

autoRefineMesh.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 Application
00025     autoRefineMesh
00026 
00027 Description
00028     Utility to refine cells near to a surface.
00029 
00030 Usage
00031 
00032     - autoRefineMesh [OPTIONS]
00033 
00034     @param -case <dir>\n
00035     Case directory.
00036 
00037     @param -help \n
00038     Display help message.
00039 
00040     @param -doc \n
00041     Display Doxygen API documentation page for this application.
00042 
00043     @param -srcDoc \n
00044     Display Doxygen source documentation page for this application.
00045 
00046 \*---------------------------------------------------------------------------*/
00047 
00048 #include <OpenFOAM/argList.H>
00049 #include <OpenFOAM/Time.H>
00050 #include <OpenFOAM/polyMesh.H>
00051 #include <meshTools/twoDPointCorrector.H>
00052 #include <OpenFOAM/OFstream.H>
00053 #include <dynamicMesh/multiDirRefinement.H>
00054 
00055 #include <triSurface/triSurface.H>
00056 #include <meshTools/triSurfaceSearch.H>
00057 
00058 #include <meshTools/cellSet.H>
00059 #include <meshTools/pointSet.H>
00060 #include <meshTools/surfaceToCell.H>
00061 #include <meshTools/surfaceToPoint.H>
00062 #include <meshTools/cellToPoint.H>
00063 #include <meshTools/pointToCell.H>
00064 #include <meshTools/cellToCell.H>
00065 #include <meshTools/surfaceSets.H>
00066 #include <dynamicMesh/polyTopoChange.H>
00067 #include <dynamicMesh/polyTopoChanger.H>
00068 #include <OpenFOAM/mapPolyMesh.H>
00069 #include <OpenFOAM/labelIOList.H>
00070 #include <OpenFOAM/emptyPolyPatch.H>
00071 #include <dynamicMesh/removeCells.H>
00072 #include <meshTools/meshSearch.H>
00073 
00074 using namespace Foam;
00075 
00076 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00077 
00078 
00079 // Max cos angle for edges to be considered aligned with axis.
00080 static const scalar edgeTol = 1E-3;
00081 
00082 
00083 void writeSet(const cellSet& cells, const string& msg)
00084 {
00085     Info<< "Writing " << msg << " (" << cells.size() << ") to cellSet "
00086         << cells.instance()/cells.local()/cells.name()
00087         << endl;
00088     cells.write();
00089 }
00090 
00091 
00092 direction getNormalDir(const twoDPointCorrector* correct2DPtr)
00093 {
00094     direction dir = 3;
00095 
00096     if (correct2DPtr)
00097     {
00098         const vector& normal = correct2DPtr->planeNormal();
00099 
00100         if (mag(normal & vector(1, 0, 0)) > 1-edgeTol)
00101         {
00102             dir = 0;
00103         }
00104         else if (mag(normal & vector(0, 1, 0)) > 1-edgeTol)
00105         {
00106             dir = 1;
00107         }
00108         else if (mag(normal & vector(0, 0, 1)) > 1-edgeTol)
00109         {
00110             dir = 2;
00111         }
00112     }
00113     return dir;
00114 }
00115 
00116 
00117 
00118 // Calculate some edge statistics on mesh. Return min. edge length over all
00119 // directions but exclude component (0=x, 1=y, 2=z, other=none)
00120 scalar getEdgeStats(const primitiveMesh& mesh, const direction excludeCmpt)
00121 {
00122     label nX = 0;
00123     label nY = 0;
00124     label nZ = 0;
00125 
00126     scalar minX = GREAT;
00127     scalar maxX = -GREAT;
00128     vector x(1, 0, 0);
00129 
00130     scalar minY = GREAT;
00131     scalar maxY = -GREAT;
00132     vector y(0, 1, 0);
00133 
00134     scalar minZ = GREAT;
00135     scalar maxZ = -GREAT;
00136     vector z(0, 0, 1);
00137 
00138     scalar minOther = GREAT;
00139     scalar maxOther = -GREAT;
00140 
00141     const edgeList& edges = mesh.edges();
00142 
00143     forAll(edges, edgeI)
00144     {
00145         const edge& e = edges[edgeI];
00146 
00147         vector eVec(e.vec(mesh.points()));
00148 
00149         scalar eMag = mag(eVec);
00150 
00151         eVec /= eMag;
00152 
00153         if (mag(eVec & x) > 1-edgeTol)
00154         {
00155             minX = min(minX, eMag);
00156             maxX = max(maxX, eMag);
00157             nX++;
00158         }
00159         else if (mag(eVec & y) > 1-edgeTol)
00160         {
00161             minY = min(minY, eMag);
00162             maxY = max(maxY, eMag);
00163             nY++;
00164         }
00165         else if (mag(eVec & z) > 1-edgeTol)
00166         {
00167             minZ = min(minZ, eMag);
00168             maxZ = max(maxZ, eMag);
00169             nZ++;
00170         }
00171         else
00172         {
00173             minOther = min(minOther, eMag);
00174             maxOther = max(maxOther, eMag);
00175         }
00176     }
00177 
00178     Info<< "Mesh bounding box:" << boundBox(mesh.points()) << nl << nl
00179         << "Mesh edge statistics:" << nl
00180         << "    x aligned :  number:" << nX << "\tminLen:" << minX
00181         << "\tmaxLen:" << maxX << nl
00182         << "    y aligned :  number:" << nY << "\tminLen:" << minY
00183         << "\tmaxLen:" << maxY << nl
00184         << "    z aligned :  number:" << nZ << "\tminLen:" << minZ
00185         << "\tmaxLen:" << maxZ << nl
00186         << "    other     :  number:" << mesh.nEdges() - nX - nY - nZ
00187         << "\tminLen:" << minOther
00188         << "\tmaxLen:" << maxOther << nl << endl;
00189 
00190     if (excludeCmpt == 0)
00191     {
00192         return min(minY, min(minZ, minOther));
00193     }
00194     else if (excludeCmpt == 1)
00195     {
00196         return min(minX, min(minZ, minOther));
00197     }
00198     else if (excludeCmpt == 2)
00199     {
00200         return min(minX, min(minY, minOther));
00201     }
00202     else
00203     {
00204         return min(minX, min(minY, min(minZ, minOther)));
00205     }
00206 }
00207 
00208 
00209 // Adds empty patch if not yet there. Returns patchID.
00210 label addPatch(polyMesh& mesh, const word& patchName)
00211 {
00212     label patchI = mesh.boundaryMesh().findPatchID(patchName);
00213 
00214     if (patchI == -1)
00215     {
00216         const polyBoundaryMesh& patches = mesh.boundaryMesh();
00217 
00218         List<polyPatch*> newPatches(patches.size() + 1);
00219 
00220         // Add empty patch as 0th entry (Note: only since subsetMesh wants this)
00221         patchI = 0;
00222 
00223         newPatches[patchI] =
00224             new emptyPolyPatch
00225             (
00226                 Foam::word(patchName),
00227                 0,
00228                 mesh.nInternalFaces(),
00229                 patchI,
00230                 patches
00231             );
00232 
00233         forAll(patches, i)
00234         {
00235             const polyPatch& pp = patches[i];
00236 
00237             newPatches[i+1] =
00238                 pp.clone
00239                 (
00240                     patches,
00241                     i+1,
00242                     pp.size(),
00243                     pp.start()
00244                 ).ptr();
00245         }
00246 
00247         mesh.removeBoundary();
00248         mesh.addPatches(newPatches);
00249 
00250         Info<< "Created patch oldInternalFaces at " << patchI << endl;
00251     }
00252     else
00253     {
00254         Info<< "Reusing patch oldInternalFaces at " << patchI << endl;
00255     }
00256 
00257 
00258     return patchI;
00259 }
00260 
00261 
00262 // Take surface and select cells based on surface curvature.
00263 void selectCurvatureCells
00264 (
00265     const polyMesh& mesh,
00266     const fileName& surfName,
00267     const triSurfaceSearch& querySurf,
00268     const scalar nearDist,
00269     const scalar curvature,
00270     cellSet& cells
00271 )
00272 {
00273     // Use surfaceToCell to do actual calculation.
00274 
00275     // Since we're adding make sure set is on disk.
00276     cells.write();
00277 
00278     // Take centre of cell 0 as outside point since info not used.
00279 
00280     surfaceToCell cutSource
00281     (
00282         mesh,
00283         surfName,
00284         querySurf.surface(),
00285         querySurf,
00286         pointField(1, mesh.cellCentres()[0]),
00287         false,
00288         false,
00289         false,
00290         nearDist,
00291         curvature
00292     );
00293 
00294     cutSource.applyToSet(topoSetSource::ADD, cells);
00295 }
00296 
00297 
00298 // cutCells contains currently selected cells to be refined. Add neighbours
00299 // on the inside or outside to them.
00300 void addCutNeighbours
00301 (
00302     const polyMesh& mesh,
00303     const bool selectInside,
00304     const bool selectOutside,
00305     const labelHashSet& inside,
00306     const labelHashSet& outside,
00307     labelHashSet& cutCells
00308 )
00309 {
00310     // Pick up face neighbours of cutCells
00311 
00312     labelHashSet addCutFaces(cutCells.size());
00313 
00314     for
00315     (
00316         labelHashSet::const_iterator iter = cutCells.begin();
00317         iter != cutCells.end();
00318         ++iter
00319     )
00320     {
00321         label cellI = iter.key();
00322 
00323         const labelList& cFaces = mesh.cells()[cellI];
00324 
00325         forAll(cFaces, i)
00326         {
00327             label faceI = cFaces[i];
00328 
00329             if (mesh.isInternalFace(faceI))
00330             {
00331                 label nbr = mesh.faceOwner()[faceI];
00332 
00333                 if (nbr == cellI)
00334                 {
00335                     nbr = mesh.faceNeighbour()[faceI];
00336                 }
00337 
00338                 if (selectInside && inside.found(nbr))
00339                 {
00340                     addCutFaces.insert(nbr);
00341                 }
00342                 else if (selectOutside && outside.found(nbr))
00343                 {
00344                     addCutFaces.insert(nbr);
00345                 }
00346             }
00347         }
00348     }
00349 
00350     Info<< "    Selected an additional " << addCutFaces.size()
00351         << " neighbours of cutCells to refine" << endl;
00352 
00353     for
00354     (
00355         labelHashSet::const_iterator iter = addCutFaces.begin();
00356         iter != addCutFaces.end();
00357         ++iter
00358     )
00359     {
00360         cutCells.insert(iter.key());
00361     }
00362 }
00363 
00364 
00365 // Return true if any cells had to be split to keep a difference between
00366 // neighbouring refinement levels < limitDiff.
00367 // Gets cells which will be refined (so increase the refinement level) and
00368 // updates it.
00369 bool limitRefinementLevel
00370 (
00371     const primitiveMesh& mesh,
00372     const label limitDiff,
00373     const labelHashSet& excludeCells,
00374     const labelList& refLevel,
00375     labelHashSet& cutCells
00376 )
00377 {
00378     // Do simple check on validity of refinement level.
00379     forAll(refLevel, cellI)
00380     {
00381         if (!excludeCells.found(cellI))
00382         {
00383             const labelList& cCells = mesh.cellCells()[cellI];
00384 
00385             forAll(cCells, i)
00386             {
00387                 label nbr = cCells[i];
00388 
00389                 if (!excludeCells.found(nbr))
00390                 {
00391                     if (refLevel[cellI] - refLevel[nbr] >= limitDiff)
00392                     {
00393                         FatalErrorIn("limitRefinementLevel")
00394                             << "Level difference between neighbouring cells "
00395                             << cellI << " and " << nbr
00396                             << " greater than or equal to " << limitDiff << endl
00397                             << "refLevels:" << refLevel[cellI] << ' '
00398                             <<  refLevel[nbr] << abort(FatalError);
00399                     }
00400                 }
00401             }
00402         }
00403     }
00404 
00405 
00406     labelHashSet addCutCells(cutCells.size());
00407 
00408     for
00409     (
00410         labelHashSet::const_iterator iter = cutCells.begin();
00411         iter != cutCells.end();
00412         ++iter
00413     )
00414     {
00415         // cellI will be refined.
00416         label cellI = iter.key();
00417 
00418         const labelList& cCells = mesh.cellCells()[cellI];
00419 
00420         forAll(cCells, i)
00421         {
00422             label nbr = cCells[i];
00423 
00424             if (!excludeCells.found(nbr) && !cutCells.found(nbr))
00425             {
00426                 if (refLevel[cellI] + 1 - refLevel[nbr] >= limitDiff)
00427                 {
00428                     addCutCells.insert(nbr);
00429                 }
00430             }
00431         }
00432     }
00433 
00434     if (addCutCells.size())
00435     {
00436         // Add cells to cutCells.
00437 
00438         Info<< "Added an additional " << addCutCells.size() << " cells"
00439             << " to satisfy 1:" << limitDiff << " refinement level"
00440             << endl;
00441         for
00442         (
00443             labelHashSet::const_iterator iter = addCutCells.begin();
00444             iter != addCutCells.end();
00445             ++iter
00446         )
00447         {
00448             cutCells.insert(iter.key());
00449         }
00450         return true;
00451     }
00452     else
00453     {
00454         Info<< "Added no additional cells"
00455             << " to satisfy 1:" << limitDiff << " refinement level"
00456             << endl;
00457 
00458         return false;
00459     }
00460 }
00461 
00462 
00463 // Do all refinement (i.e. refCells) according to refineDict and update
00464 // refLevel afterwards for added cells
00465 void doRefinement
00466 (
00467     polyMesh& mesh,
00468     const dictionary& refineDict,
00469     const labelHashSet& refCells,
00470     labelList& refLevel
00471 )
00472 {
00473     label oldCells = mesh.nCells();
00474 
00475     // Multi-iteration, multi-direction topology modifier.
00476     multiDirRefinement multiRef
00477     (
00478         mesh,
00479         refCells.toc(),
00480         refineDict
00481     );
00482 
00483     //
00484     // Update refLevel for split cells
00485     //
00486 
00487     refLevel.setSize(mesh.nCells());
00488 
00489     for (label cellI = oldCells; cellI < mesh.nCells(); cellI++)
00490     {
00491         refLevel[cellI] = 0;
00492     }
00493 
00494     const labelListList& addedCells = multiRef.addedCells();
00495 
00496     forAll(addedCells, oldCellI)
00497     {
00498         const labelList& added = addedCells[oldCellI];
00499 
00500         if (added.size())
00501         {
00502             // Give all cells resulting from split the refinement level
00503             // of the master.
00504             label masterLevel = ++refLevel[oldCellI];
00505 
00506             forAll(added, i)
00507             {
00508                 refLevel[added[i]] = masterLevel;
00509             }
00510         }
00511     }
00512 }
00513 
00514 
00515 // Subset mesh and update refLevel and cutCells
00516 void subsetMesh
00517 (
00518     polyMesh& mesh,
00519     const label writeMesh,
00520     const label patchI,                 // patchID for exposed faces
00521     const labelHashSet& cellsToRemove,
00522     cellSet& cutCells,
00523     labelIOList& refLevel
00524 )
00525 {
00526     removeCells cellRemover(mesh);
00527 
00528     labelList cellLabels(cellsToRemove.toc());
00529 
00530     Info<< "Mesh has:" << mesh.nCells() << " cells."
00531         << " Removing:" << cellLabels.size() << " cells" << endl;
00532 
00533     // exposed faces
00534     labelList exposedFaces(cellRemover.getExposedFaces(cellLabels));
00535 
00536     polyTopoChange meshMod(mesh);
00537     cellRemover.setRefinement
00538     (
00539         cellLabels,
00540         exposedFaces,
00541         labelList(exposedFaces.size(), patchI),
00542         meshMod
00543     );
00544 
00545     // Do all changes
00546     Info<< "Morphing ..." << endl;
00547 
00548     const Time& runTime = mesh.time();
00549 
00550     autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
00551 
00552     if (morphMap().hasMotionPoints())
00553     {
00554         mesh.movePoints(morphMap().preMotionPoints());
00555     }
00556 
00557     // Update topology on cellRemover
00558     cellRemover.updateMesh(morphMap());
00559 
00560     // Update refLevel for removed cells.
00561     const labelList& cellMap = morphMap().cellMap();
00562 
00563     labelList newRefLevel(cellMap.size());
00564 
00565     forAll(cellMap, i)
00566     {
00567         newRefLevel[i] = refLevel[cellMap[i]];
00568     }
00569 
00570     // Transfer back to refLevel
00571     refLevel.transfer(newRefLevel);
00572 
00573     if (writeMesh)
00574     {
00575         Info<< "Writing refined mesh to time " << runTime.timeName() << nl
00576             << endl;
00577 
00578         IOstream::defaultPrecision(10);
00579         mesh.write();
00580         refLevel.write();
00581     }
00582 
00583     // Update cutCells for removed cells.
00584     cutCells.updateMesh(morphMap());
00585 }
00586 
00587 
00588 // Divide the cells according to status compared to surface. Constructs sets:
00589 // - cutCells : all cells cut by surface
00590 // - inside   : all cells inside surface
00591 // - outside  :   ,,      outside ,,
00592 // and a combined set:
00593 // - selected : sum of above according to selectCut/Inside/Outside flags.
00594 void classifyCells
00595 (
00596     const polyMesh& mesh,
00597     const fileName& surfName,
00598     const triSurfaceSearch& querySurf,
00599     const pointField& outsidePts,
00600 
00601     const bool selectCut,
00602     const bool selectInside,
00603     const bool selectOutside,
00604 
00605     const label nCutLayers,
00606 
00607     cellSet& inside,
00608     cellSet& outside,
00609     cellSet& cutCells,
00610     cellSet& selected
00611 )
00612 {
00613     // Cut faces with surface and classify cells
00614     surfaceSets::getSurfaceSets
00615     (
00616         mesh,
00617         surfName,
00618         querySurf.surface(),
00619         querySurf,
00620         outsidePts,
00621 
00622         nCutLayers,
00623 
00624         inside,
00625         outside,
00626         cutCells
00627     );
00628 
00629     // Combine wanted parts into selected
00630     if (selectCut)
00631     {
00632         selected.addSet(cutCells);
00633     }
00634     if (selectInside)
00635     {
00636         selected.addSet(inside);
00637     }
00638     if (selectOutside)
00639     {
00640         selected.addSet(outside);
00641     }
00642 
00643     Info<< "Determined cell status:" << endl
00644         << "    inside  :" << inside.size() << endl
00645         << "    outside :" << outside.size() << endl
00646         << "    cutCells:" << cutCells.size() << endl
00647         << "    selected:" << selected.size() << endl
00648         << endl;
00649 
00650     writeSet(inside, "inside cells");
00651     writeSet(outside, "outside cells");
00652     writeSet(cutCells, "cut cells");
00653     writeSet(selected, "selected cells");
00654 }
00655 
00656 
00657 // Main program:
00658 
00659 int main(int argc, char *argv[])
00660 {
00661     argList::noParallel();
00662 
00663 #   include <OpenFOAM/setRootCase.H>
00664 #   include <OpenFOAM/createTime.H>
00665 #   include <OpenFOAM/createPolyMesh.H>
00666 
00667     // If nessecary add oldInternalFaces patch
00668     label newPatchI = addPatch(mesh, "oldInternalFaces");
00669 
00670 
00671     //
00672     // Read motionProperties dictionary
00673     //
00674 
00675     Info<< "Checking for motionProperties\n" << endl;
00676 
00677     IOobject motionObj
00678     (
00679         "motionProperties",
00680         runTime.constant(),
00681         mesh,
00682         IOobject::MUST_READ,
00683         IOobject::NO_WRITE
00684     );
00685 
00686     // corrector for mesh motion
00687     twoDPointCorrector* correct2DPtr = NULL;
00688 
00689     if (motionObj.headerOk())
00690     {
00691         Info<< "Reading " << runTime.constant() / "motionProperties"
00692             << endl << endl;
00693 
00694         IOdictionary motionProperties(motionObj);
00695 
00696         Switch twoDMotion(motionProperties.lookup("twoDMotion"));
00697 
00698         if (twoDMotion)
00699         {
00700             Info<< "Correcting for 2D motion" << endl << endl;
00701             correct2DPtr = new twoDPointCorrector(mesh);
00702         }
00703     }
00704 
00705     IOdictionary refineDict
00706     (
00707         IOobject
00708         (
00709             "autoRefineMeshDict",
00710             runTime.system(),
00711             mesh,
00712             IOobject::MUST_READ,
00713             IOobject::NO_WRITE
00714         )
00715     );
00716 
00717     fileName surfName(refineDict.lookup("surface"));
00718     surfName.expand();
00719     label nCutLayers(readLabel(refineDict.lookup("nCutLayers")));
00720     label cellLimit(readLabel(refineDict.lookup("cellLimit")));
00721     bool selectCut(readBool(refineDict.lookup("selectCut")));
00722     bool selectInside(readBool(refineDict.lookup("selectInside")));
00723     bool selectOutside(readBool(refineDict.lookup("selectOutside")));
00724     bool selectHanging(readBool(refineDict.lookup("selectHanging")));
00725 
00726     scalar minEdgeLen(readScalar(refineDict.lookup("minEdgeLen")));
00727     scalar maxEdgeLen(readScalar(refineDict.lookup("maxEdgeLen")));
00728     scalar curvature(readScalar(refineDict.lookup("curvature")));
00729     scalar curvDist(readScalar(refineDict.lookup("curvatureDistance")));
00730     pointField outsidePts(refineDict.lookup("outsidePoints"));
00731     label refinementLimit(readLabel(refineDict.lookup("splitLevel")));
00732     bool writeMesh(readBool(refineDict.lookup("writeMesh")));
00733 
00734     Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
00735         << "    cells cut by surface            : " << selectCut << nl
00736         << "    cells inside of surface         : " << selectInside << nl
00737         << "    cells outside of surface        : " << selectOutside << nl
00738         << "    hanging cells                   : " << selectHanging << nl
00739         << endl;
00740 
00741 
00742     if (nCutLayers > 0 && selectInside)
00743     {
00744         WarningIn(args.executable())
00745             << "Illogical settings : Both nCutLayers>0 and selectInside true."
00746             << endl
00747             << "This would mean that inside cells get removed but should be"
00748             << " included in final mesh" << endl;
00749     }
00750 
00751     // Surface.
00752     triSurface surf(surfName);
00753 
00754     // Search engine on surface
00755     triSurfaceSearch querySurf(surf);
00756 
00757     // Search engine on mesh. No face decomposition since mesh unwarped.
00758     meshSearch queryMesh(mesh, false);
00759 
00760     // Check all 'outside' points
00761     forAll(outsidePts, outsideI)
00762     {
00763         const point& outsidePoint = outsidePts[outsideI];
00764 
00765         if (queryMesh.findCell(outsidePoint, -1, false) == -1)
00766         {
00767             FatalErrorIn(args.executable())
00768                 << "outsidePoint " << outsidePoint
00769                 << " is not inside any cell"
00770                 << exit(FatalError);
00771         }
00772     }
00773 
00774 
00775 
00776     // Current refinement level. Read if present.
00777     labelIOList refLevel
00778     (
00779         IOobject
00780         (
00781             "refinementLevel",
00782             runTime.timeName(),
00783             polyMesh::defaultRegion,
00784             mesh,
00785             IOobject::READ_IF_PRESENT,
00786             IOobject::AUTO_WRITE
00787         ),
00788         labelList(mesh.nCells(), 0)
00789     );
00790 
00791     label maxLevel = max(refLevel);
00792 
00793     if (maxLevel > 0)
00794     {
00795         Info<< "Read existing refinement level from file "
00796             << refLevel.objectPath() << nl
00797             << "   min level : " << min(refLevel) << nl
00798             << "   max level : " << maxLevel << nl
00799             << endl;
00800     }
00801     else
00802     {
00803         Info<< "Created zero refinement level in file "
00804             << refLevel.objectPath() << nl
00805             << endl;
00806     }
00807 
00808 
00809 
00810 
00811     // Print edge stats on original mesh. Leave out 2d-normal direction
00812     direction normalDir(getNormalDir(correct2DPtr));
00813     scalar meshMinEdgeLen = getEdgeStats(mesh, normalDir);
00814 
00815     while (meshMinEdgeLen > minEdgeLen)
00816     {
00817         // Get inside/outside/cutCells cellSets.
00818         cellSet inside(mesh, "inside", mesh.nCells()/10);
00819         cellSet outside(mesh, "outside", mesh.nCells()/10);
00820         cellSet cutCells(mesh, "cutCells", mesh.nCells()/10);
00821         cellSet selected(mesh, "selected", mesh.nCells()/10);
00822 
00823         classifyCells
00824         (
00825             mesh,
00826             surfName,
00827             querySurf,
00828             outsidePts,
00829 
00830             selectCut,      // for determination of selected
00831             selectInside,   // for determination of selected
00832             selectOutside,  // for determination of selected
00833 
00834             nCutLayers,     // How many layers of cutCells to include
00835 
00836             inside,
00837             outside,
00838             cutCells,
00839             selected        // not used but determined anyway.
00840         );
00841 
00842         Info<< "    Selected " << cutCells.name() << " with "
00843             << cutCells.size() << " cells" << endl;
00844 
00845         if ((curvDist > 0) && (meshMinEdgeLen < maxEdgeLen))
00846         {
00847             // Done refining enough close to surface. Now switch to more
00848             // intelligent refinement where only cutCells on surface curvature
00849             // are refined.
00850             cellSet curveCells(mesh, "curveCells", mesh.nCells()/10);
00851 
00852             selectCurvatureCells
00853             (
00854                 mesh,
00855                 surfName,
00856                 querySurf,
00857                 maxEdgeLen,
00858                 curvature,
00859                 curveCells
00860             );
00861 
00862             Info<< "    Selected " << curveCells.name() << " with "
00863                 << curveCells.size() << " cells" << endl;
00864 
00865             // Add neighbours to cutCells. This is if selectCut is not
00866             // true and so outside and/or inside cells get exposed there is
00867             // also refinement in them.
00868             if (!selectCut)
00869             {
00870                 addCutNeighbours
00871                 (
00872                     mesh,
00873                     selectInside,
00874                     selectOutside,
00875                     inside,
00876                     outside,
00877                     cutCells
00878                 );
00879             }
00880 
00881             // Subset cutCells to only curveCells
00882             cutCells.subset(curveCells);
00883 
00884             Info<< "    Removed cells not on surface curvature. Selected "
00885                 << cutCells.size() << endl;
00886         }
00887 
00888 
00889         if (nCutLayers > 0)
00890         {
00891             // Subset mesh to remove inside cells altogether. Updates cutCells,
00892             // refLevel.
00893             subsetMesh(mesh, writeMesh, newPatchI, inside, cutCells, refLevel);
00894         }
00895 
00896 
00897         // Added cells from 2:1 refinement level restriction.
00898         while
00899         (
00900             limitRefinementLevel
00901             (
00902                 mesh,
00903                 refinementLimit,
00904                 labelHashSet(),
00905                 refLevel,
00906                 cutCells
00907             )
00908         )
00909         {}
00910 
00911 
00912         Info<< "    Current cells           : " << mesh.nCells() << nl
00913             << "    Selected for refinement :" << cutCells.size() << nl
00914             << endl;
00915 
00916         if (cutCells.empty())
00917         {
00918             Info<< "Stopping refining since 0 cells selected to be refined ..."
00919                 << nl << endl;
00920             break;
00921         }
00922 
00923         if ((mesh.nCells() + 8*cutCells.size()) > cellLimit)
00924         {
00925             Info<< "Stopping refining since cell limit reached ..." << nl
00926                 << "Would refine from " << mesh.nCells()
00927                 << " to " << mesh.nCells() + 8*cutCells.size() << " cells."
00928                 << nl << endl;
00929             break;
00930         }
00931 
00932         doRefinement
00933         (
00934             mesh,
00935             refineDict,
00936             cutCells,
00937             refLevel
00938         );
00939 
00940         Info<< "    After refinement:" << mesh.nCells() << nl
00941             << endl;
00942 
00943         if (writeMesh)
00944         {
00945             Info<< "    Writing refined mesh to time " << runTime.timeName()
00946                 << nl << endl;
00947 
00948             IOstream::defaultPrecision(10);
00949             mesh.write();
00950             refLevel.write();
00951         }
00952 
00953         // Update mesh edge stats.
00954         meshMinEdgeLen = getEdgeStats(mesh, normalDir);
00955     }
00956 
00957 
00958     if (selectHanging)
00959     {
00960         // Get inside/outside/cutCells cellSets.
00961         cellSet inside(mesh, "inside", mesh.nCells()/10);
00962         cellSet outside(mesh, "outside", mesh.nCells()/10);
00963         cellSet cutCells(mesh, "cutCells", mesh.nCells()/10);
00964         cellSet selected(mesh, "selected", mesh.nCells()/10);
00965 
00966         classifyCells
00967         (
00968             mesh,
00969             surfName,
00970             querySurf,
00971             outsidePts,
00972 
00973             selectCut,
00974             selectInside,
00975             selectOutside,
00976 
00977             nCutLayers,
00978 
00979             inside,
00980             outside,
00981             cutCells,
00982             selected
00983         );
00984 
00985 
00986         // Find any cells which have all their points on the outside of the
00987         // selected set and refine them
00988         labelHashSet hanging = surfaceSets::getHangingCells(mesh, selected);
00989 
00990         Info<< "Detected " << hanging.size() << " hanging cells"
00991             << " (cells with all points on"
00992             << " outside of cellSet 'selected').\nThese would probably result"
00993             << " in flattened cells when snapping the mesh to the surface"
00994             << endl;
00995 
00996         Info<< "Refining " << hanging.size() << " hanging cells" << nl
00997             << endl;
00998 
00999         // Added cells from 2:1 refinement level restriction.
01000         while
01001         (
01002             limitRefinementLevel
01003             (
01004                 mesh,
01005                 refinementLimit,
01006                 labelHashSet(),
01007                 refLevel,
01008                 hanging
01009             )
01010         )
01011         {}
01012 
01013         doRefinement(mesh, refineDict, hanging, refLevel);
01014 
01015         Info<< "Writing refined mesh to time " << runTime.timeName() << nl
01016             << endl;
01017 
01018         // Write final mesh
01019         IOstream::defaultPrecision(10);
01020         mesh.write();
01021         refLevel.write();
01022 
01023     }
01024     else if (!writeMesh)
01025     {
01026         Info<< "Writing refined mesh to time " << runTime.timeName() << nl
01027             << endl;
01028 
01029         // Write final mesh. (will have been written already if writeMesh=true)
01030         IOstream::defaultPrecision(10);
01031         mesh.write();
01032         refLevel.write();
01033     }
01034 
01035 
01036     Info << "End\n" << endl;
01037 
01038     return 0;
01039 }
01040 
01041 
01042 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines