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

meshRefinementRefine.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 \*----------------------------------------------------------------------------*/
00025 
00026 #include "meshRefinement.H"
00027 #include <autoMesh/trackedParticle.H>
00028 #include <OpenFOAM/syncTools.H>
00029 #include <OpenFOAM/Time.H>
00030 #include <autoMesh/refinementSurfaces.H>
00031 #include <autoMesh/shellSurfaces.H>
00032 #include <meshTools/faceSet.H>
00033 #include <decompositionMethods/decompositionMethod.H>
00034 #include <dynamicMesh/fvMeshDistribute.H>
00035 #include <dynamicMesh/polyTopoChange.H>
00036 #include <OpenFOAM/mapDistributePolyMesh.H>
00037 #include <edgeMesh/featureEdgeMesh.H>
00038 #include <lagrangian/Cloud.H>
00039 //#include <OpenFOAM/globalIndex.H>
00040 
00041 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00042 
00043 // Get faces (on the new mesh) that have in some way been affected by the
00044 // mesh change. Picks up all faces but those that are between two
00045 // unrefined faces. (Note that of an unchanged face the edge still might be
00046 // split but that does not change any face centre or cell centre.
00047 Foam::labelList Foam::meshRefinement::getChangedFaces
00048 (
00049     const mapPolyMesh& map,
00050     const labelList& oldCellsToRefine
00051 )
00052 {
00053     const polyMesh& mesh = map.mesh();
00054 
00055     labelList changedFaces;
00056     {
00057         // Mark any face on a cell which has been added or changed
00058         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00059         // Note that refining a face changes the face centre (for a warped face)
00060         // which changes the cell centre. This again changes the cellcentre-
00061         // cellcentre edge across all faces of the cell.
00062         // Note: this does not happen for unwarped faces but unfortunately
00063         // we don't have this information.
00064 
00065         const labelList& faceOwner = mesh.faceOwner();
00066         const labelList& faceNeighbour = mesh.faceNeighbour();
00067         const cellList& cells = mesh.cells();
00068         const label nInternalFaces = mesh.nInternalFaces();
00069 
00070         // Mark refined cells on old mesh
00071         PackedBoolList oldRefineCell(map.nOldCells());
00072 
00073         forAll(oldCellsToRefine, i)
00074         {
00075             oldRefineCell.set(oldCellsToRefine[i], 1u);
00076         }
00077 
00078         // Mark refined faces
00079         PackedBoolList refinedInternalFace(nInternalFaces);
00080 
00081         // 1. Internal faces
00082 
00083         for (label faceI = 0; faceI < nInternalFaces; faceI++)
00084         {
00085             label oldOwn = map.cellMap()[faceOwner[faceI]];
00086             label oldNei = map.cellMap()[faceNeighbour[faceI]];
00087 
00088             if
00089             (
00090                 oldOwn >= 0
00091              && oldRefineCell.get(oldOwn) == 0u
00092              && oldNei >= 0
00093              && oldRefineCell.get(oldNei) == 0u
00094             )
00095             {
00096                 // Unaffected face since both neighbours were not refined.
00097             }
00098             else
00099             {
00100                 refinedInternalFace.set(faceI, 1u);
00101             }
00102         }
00103 
00104 
00105         // 2. Boundary faces
00106 
00107         boolList refinedBoundaryFace(mesh.nFaces()-nInternalFaces, false);
00108 
00109         forAll(mesh.boundaryMesh(), patchI)
00110         {
00111             const polyPatch& pp = mesh.boundaryMesh()[patchI];
00112 
00113             label faceI = pp.start();
00114 
00115             forAll(pp, i)
00116             {
00117                 label oldOwn = map.cellMap()[faceOwner[faceI]];
00118 
00119                 if (oldOwn >= 0 && oldRefineCell.get(oldOwn) == 0u)
00120                 {
00121                     // owner did exist and wasn't refined.
00122                 }
00123                 else
00124                 {
00125                     refinedBoundaryFace[faceI-nInternalFaces] = true;
00126                 }
00127                 faceI++;
00128             }
00129         }
00130 
00131         // Synchronise refined face status
00132         syncTools::syncBoundaryFaceList
00133         (
00134             mesh,
00135             refinedBoundaryFace,
00136             orEqOp<bool>(),
00137             false
00138         );
00139 
00140 
00141         // 3. Mark all faces affected by refinement. Refined faces are in
00142         //    - refinedInternalFace
00143         //    - refinedBoundaryFace
00144         boolList changedFace(mesh.nFaces(), false);
00145 
00146         forAll(refinedInternalFace, faceI)
00147         {
00148             if (refinedInternalFace.get(faceI) == 1u)
00149             {
00150                 const cell& ownFaces = cells[faceOwner[faceI]];
00151                 forAll(ownFaces, ownI)
00152                 {
00153                     changedFace[ownFaces[ownI]] = true;
00154                 }
00155                 const cell& neiFaces = cells[faceNeighbour[faceI]];
00156                 forAll(neiFaces, neiI)
00157                 {
00158                     changedFace[neiFaces[neiI]] = true;
00159                 }
00160             }
00161         }
00162 
00163         forAll(refinedBoundaryFace, i)
00164         {
00165             if (refinedBoundaryFace[i])
00166             {
00167                 const cell& ownFaces = cells[faceOwner[i+nInternalFaces]];
00168                 forAll(ownFaces, ownI)
00169                 {
00170                     changedFace[ownFaces[ownI]] = true;
00171                 }
00172             }
00173         }
00174 
00175         syncTools::syncFaceList
00176         (
00177             mesh,
00178             changedFace,
00179             orEqOp<bool>(),
00180             false
00181         );
00182 
00183 
00184         // Now we have in changedFace marked all affected faces. Pack.
00185         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00186 
00187         label nChanged = 0;
00188 
00189         forAll(changedFace, faceI)
00190         {
00191             if (changedFace[faceI])
00192             {
00193                 nChanged++;
00194             }
00195         }
00196 
00197         changedFaces.setSize(nChanged);
00198         nChanged = 0;
00199 
00200         forAll(changedFace, faceI)
00201         {
00202             if (changedFace[faceI])
00203             {
00204                 changedFaces[nChanged++] = faceI;
00205             }
00206         }
00207     }
00208 
00209     label nChangedFaces = changedFaces.size();
00210     reduce(nChangedFaces, sumOp<label>());
00211 
00212     if (debug)
00213     {
00214         Pout<< "getChangedFaces : Detected "
00215             << " local:" << changedFaces.size()
00216             << " global:" << nChangedFaces
00217             << " changed faces out of " << mesh.globalData().nTotalFaces()
00218             << endl;
00219 
00220         faceSet changedFacesSet(mesh, "changedFaces", changedFaces);
00221         Pout<< "getChangedFaces : Writing " << changedFaces.size()
00222             << " changed faces to faceSet " << changedFacesSet.name()
00223             << endl;
00224         changedFacesSet.write();
00225     }
00226 
00227     return changedFaces;
00228 }
00229 
00230 
00231 // Mark cell for refinement (if not already marked). Return false if
00232 // refinelimit hit. Keeps running count (in nRefine) of cells marked for
00233 // refinement
00234 bool Foam::meshRefinement::markForRefine
00235 (
00236     const label markValue,
00237     const label nAllowRefine,
00238 
00239     label& cellValue,
00240     label& nRefine
00241 )
00242 {
00243     if (cellValue == -1)
00244     {
00245         cellValue = markValue;
00246         nRefine++;
00247     }
00248 
00249     return nRefine <= nAllowRefine;
00250 }
00251 
00252 
00253 // Calculates list of cells to refine based on intersection with feature edge.
00254 Foam::label Foam::meshRefinement::markFeatureRefinement
00255 (
00256     const point& keepPoint,
00257     const PtrList<featureEdgeMesh>& featureMeshes,
00258     const labelList& featureLevels,
00259     const label nAllowRefine,
00260 
00261     labelList& refineCell,
00262     label& nRefine
00263 ) const
00264 {
00265     // We want to refine all cells containing a feature edge.
00266     // - don't want to search over whole mesh
00267     // - don't want to build octree for whole mesh
00268     // - so use tracking to follow the feature edges
00269     //
00270     // 1. find non-manifold points on feature edges (i.e. start of feature edge
00271     //    or 'knot')
00272     // 2. seed particle starting at keepPoint going to this non-manifold point
00273     // 3. track particles to their non-manifold point
00274     //
00275     // 4. track particles across their connected feature edges, marking all
00276     //    visited cells with their level (through trackingData)
00277     // 5. do 4 until all edges have been visited.
00278 
00279 
00280     // Find all start cells of features. Is done by tracking from keepPoint.
00281     Cloud<trackedParticle> cloud(mesh_, IDLList<trackedParticle>());
00282 
00283     // Create particles on whichever processor holds the keepPoint.
00284     label cellI = mesh_.findCell(keepPoint);
00285 
00286     if (cellI != -1)
00287     {
00288         forAll(featureMeshes, featI)
00289         {
00290             const featureEdgeMesh& featureMesh = featureMeshes[featI];
00291             const labelListList& pointEdges = featureMesh.pointEdges();
00292 
00293             forAll(pointEdges, pointI)
00294             {
00295                 if (pointEdges[pointI].size() != 2)
00296                 {
00297                     if (debug)
00298                     {
00299                         Pout<< "Adding particle from point:" << pointI
00300                             << " coord:" << featureMesh.points()[pointI]
00301                             << " pEdges:" << pointEdges[pointI]
00302                             << endl;
00303                     }
00304 
00305                     // Non-manifold point. Create particle.
00306                     cloud.addParticle
00307                     (
00308                         new trackedParticle
00309                         (
00310                             cloud,
00311                             keepPoint,
00312                             cellI,
00313                             featureMesh.points()[pointI],   // endpos
00314                             featureLevels[featI],           // level
00315                             featI,                          // featureMesh
00316                             pointI                          // end point
00317                         )
00318                     );
00319                 }
00320             }
00321         }
00322     }
00323 
00324 
00325     // Largest refinement level of any feature passed through
00326     labelList maxFeatureLevel(mesh_.nCells(), -1);
00327 
00328     // Database to pass into trackedParticle::move
00329     trackedParticle::trackData td(cloud, maxFeatureLevel);
00330 
00331     // Track all particles to their end position (= starting feature point)
00332     cloud.move(td);
00333 
00334     // Reset level
00335     maxFeatureLevel = -1;
00336 
00337     // Whether edge has been visited.
00338     List<PackedBoolList> featureEdgeVisited(featureMeshes.size());
00339 
00340     forAll(featureMeshes, featI)
00341     {
00342         featureEdgeVisited[featI].setSize(featureMeshes[featI].edges().size());
00343         featureEdgeVisited[featI] = 0u;
00344     }
00345 
00346     while (true)
00347     {
00348         label nParticles = 0;
00349 
00350         // Make particle follow edge.
00351         forAllIter(Cloud<trackedParticle>, cloud, iter)
00352         {
00353             trackedParticle& tp = iter();
00354 
00355             label featI = tp.i();
00356             label pointI = tp.j();
00357 
00358             const featureEdgeMesh& featureMesh = featureMeshes[featI];
00359             const labelList& pEdges = featureMesh.pointEdges()[pointI];
00360 
00361             // Particle now at pointI. Check connected edges to see which one
00362             // we have to visit now.
00363 
00364             bool keepParticle = false;
00365 
00366             forAll(pEdges, i)
00367             {
00368                 label edgeI = pEdges[i];
00369 
00370                 if (featureEdgeVisited[featI].set(edgeI, 1u))
00371                 {
00372                     // Unvisited edge. Make the particle go to the other point
00373                     // on the edge.
00374 
00375                     const edge& e = featureMesh.edges()[edgeI];
00376                     label otherPointI = e.otherVertex(pointI);
00377 
00378                     tp.end() = featureMesh.points()[otherPointI];
00379                     tp.j() = otherPointI;
00380                     keepParticle = true;
00381                     break;
00382                 }
00383             }
00384 
00385             if (!keepParticle)
00386             {
00387                 // Particle at 'knot' where another particle already has been
00388                 // seeded. Delete particle.
00389                 cloud.deleteParticle(tp);
00390             }
00391             else
00392             {
00393                 // Keep particle
00394                 nParticles++;
00395             }
00396         }
00397 
00398         reduce(nParticles, sumOp<label>());
00399         if (nParticles == 0)
00400         {
00401             break;
00402         }
00403 
00404         // Track all particles to their end position.
00405         cloud.move(td);
00406     }
00407 
00408 
00409     // See which cells to refine. maxFeatureLevel will hold highest level
00410     // of any feature edge that passed through.
00411 
00412     const labelList& cellLevel = meshCutter_.cellLevel();
00413 
00414     label oldNRefine = nRefine;
00415 
00416     forAll(maxFeatureLevel, cellI)
00417     {
00418         if (maxFeatureLevel[cellI] > cellLevel[cellI])
00419         {
00420             // Mark
00421             if
00422             (
00423                !markForRefine
00424                 (
00425                     0,                      // surface (n/a)
00426                     nAllowRefine,
00427                     refineCell[cellI],
00428                     nRefine
00429                 )
00430             )
00431             {
00432                 // Reached limit
00433                 break;
00434             }
00435         }
00436     }
00437 
00438     if
00439     (
00440         returnReduce(nRefine, sumOp<label>())
00441       > returnReduce(nAllowRefine, sumOp<label>())
00442     )
00443     {
00444         Info<< "Reached refinement limit." << endl;
00445     }
00446 
00447     return returnReduce(nRefine-oldNRefine,  sumOp<label>());
00448 }
00449 
00450 
00451 // Mark cells for non-surface intersection based refinement.
00452 Foam::label Foam::meshRefinement::markInternalRefinement
00453 (
00454     const label nAllowRefine,
00455 
00456     labelList& refineCell,
00457     label& nRefine
00458 ) const
00459 {
00460     const labelList& cellLevel = meshCutter_.cellLevel();
00461     const pointField& cellCentres = mesh_.cellCentres();
00462 
00463     label oldNRefine = nRefine;
00464 
00465     // Collect cells to test
00466     pointField testCc(cellLevel.size()-nRefine);
00467     labelList testLevels(cellLevel.size()-nRefine);
00468     label testI = 0;
00469 
00470     forAll(cellLevel, cellI)
00471     {
00472         if (refineCell[cellI] == -1)
00473         {
00474             testCc[testI] = cellCentres[cellI];
00475             testLevels[testI] = cellLevel[cellI];
00476             testI++;
00477         }
00478     }
00479 
00480     // Do test to see whether cells is inside/outside shell with higher level
00481     labelList maxLevel;
00482     shells_.findHigherLevel(testCc, testLevels, maxLevel);
00483 
00484     // Mark for refinement. Note that we didn't store the original cellID so
00485     // now just reloop in same order.
00486     testI = 0;
00487     forAll(cellLevel, cellI)
00488     {
00489         if (refineCell[cellI] == -1)
00490         {
00491             if (maxLevel[testI] > testLevels[testI])
00492             {
00493                 bool reachedLimit = !markForRefine
00494                 (
00495                     maxLevel[testI],    // mark with any positive value
00496                     nAllowRefine,
00497                     refineCell[cellI],
00498                     nRefine
00499                 );
00500 
00501                 if (reachedLimit)
00502                 {
00503                     if (debug)
00504                     {
00505                         Pout<< "Stopped refining internal cells"
00506                             << " since reaching my cell limit of "
00507                             << mesh_.nCells()+7*nRefine << endl;
00508                     }
00509                     break;
00510                 }
00511             }
00512             testI++;
00513         }
00514     }
00515 
00516     if
00517     (
00518         returnReduce(nRefine, sumOp<label>())
00519       > returnReduce(nAllowRefine, sumOp<label>())
00520     )
00521     {
00522         Info<< "Reached refinement limit." << endl;
00523     }
00524 
00525     return returnReduce(nRefine-oldNRefine, sumOp<label>());
00526 }
00527 
00528 
00529 // Collect faces that are intersected and whose neighbours aren't yet marked
00530 // for refinement.
00531 Foam::labelList Foam::meshRefinement::getRefineCandidateFaces
00532 (
00533     const labelList& refineCell
00534 ) const
00535 {
00536     labelList testFaces(mesh_.nFaces());
00537 
00538     label nTest = 0;
00539 
00540     forAll(surfaceIndex_, faceI)
00541     {
00542         if (surfaceIndex_[faceI] != -1)
00543         {
00544             label own = mesh_.faceOwner()[faceI];
00545 
00546             if (mesh_.isInternalFace(faceI))
00547             {
00548                 label nei = mesh_.faceNeighbour()[faceI];
00549 
00550                 if (refineCell[own] == -1 || refineCell[nei] == -1)
00551                 {
00552                     testFaces[nTest++] = faceI;
00553                 }
00554             }
00555             else
00556             {
00557                 if (refineCell[own] == -1)
00558                 {
00559                     testFaces[nTest++] = faceI;
00560                 }
00561             }
00562         }
00563     }
00564     testFaces.setSize(nTest);
00565 
00566     return testFaces;
00567 }
00568 
00569 
00570 // Mark cells for surface intersection based refinement.
00571 Foam::label Foam::meshRefinement::markSurfaceRefinement
00572 (
00573     const label nAllowRefine,
00574     const labelList& neiLevel,
00575     const pointField& neiCc,
00576 
00577     labelList& refineCell,
00578     label& nRefine
00579 ) const
00580 {
00581     const labelList& cellLevel = meshCutter_.cellLevel();
00582     const pointField& cellCentres = mesh_.cellCentres();
00583 
00584     label oldNRefine = nRefine;
00585 
00586     // Use cached surfaceIndex_ to detect if any intersection. If so
00587     // re-intersect to determine level wanted.
00588 
00589     // Collect candidate faces
00590     // ~~~~~~~~~~~~~~~~~~~~~~~
00591 
00592     labelList testFaces(getRefineCandidateFaces(refineCell));
00593 
00594     // Collect segments
00595     // ~~~~~~~~~~~~~~~~
00596 
00597     pointField start(testFaces.size());
00598     pointField end(testFaces.size());
00599     labelList minLevel(testFaces.size());
00600 
00601     forAll(testFaces, i)
00602     {
00603         label faceI = testFaces[i];
00604 
00605         label own = mesh_.faceOwner()[faceI];
00606 
00607         if (mesh_.isInternalFace(faceI))
00608         {
00609             label nei = mesh_.faceNeighbour()[faceI];
00610 
00611             start[i] = cellCentres[own];
00612             end[i] = cellCentres[nei];
00613             minLevel[i] = min(cellLevel[own], cellLevel[nei]);
00614         }
00615         else
00616         {
00617             label bFaceI = faceI - mesh_.nInternalFaces();
00618 
00619             start[i] = cellCentres[own];
00620             end[i] = neiCc[bFaceI];
00621             minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
00622         }
00623     }
00624 
00625 
00626     // Do test for higher intersections
00627     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00628 
00629     labelList surfaceHit;
00630     labelList surfaceMinLevel;
00631     surfaces_.findHigherIntersection
00632     (
00633         start,
00634         end,
00635         minLevel,
00636 
00637         surfaceHit,
00638         surfaceMinLevel
00639     );
00640 
00641 
00642     // Mark cells for refinement
00643     // ~~~~~~~~~~~~~~~~~~~~~~~~~
00644 
00645     forAll(testFaces, i)
00646     {
00647         label faceI = testFaces[i];
00648 
00649         label surfI = surfaceHit[i];
00650 
00651         if (surfI != -1)
00652         {
00653             // Found intersection with surface with higher wanted
00654             // refinement. Check if the level field on that surface
00655             // specifies an even higher level. Note:this is weird. Should
00656             // do the check with the surfaceMinLevel whilst intersecting the
00657             // surfaces?
00658 
00659             label own = mesh_.faceOwner()[faceI];
00660 
00661             if (surfaceMinLevel[i] > cellLevel[own])
00662             {
00663                 // Owner needs refining
00664                 if
00665                 (
00666                    !markForRefine
00667                     (
00668                         surfI,
00669                         nAllowRefine,
00670                         refineCell[own],
00671                         nRefine
00672                     )
00673                 )
00674                 {
00675                     break;
00676                 }
00677             }
00678 
00679             if (mesh_.isInternalFace(faceI))
00680             {
00681                 label nei = mesh_.faceNeighbour()[faceI];
00682                 if (surfaceMinLevel[i] > cellLevel[nei])
00683                 {
00684                     // Neighbour needs refining
00685                     if
00686                     (
00687                        !markForRefine
00688                         (
00689                             surfI,
00690                             nAllowRefine,
00691                             refineCell[nei],
00692                             nRefine
00693                         )
00694                     )
00695                     {
00696                         break;
00697                     }
00698                 }
00699             }
00700         }
00701     }
00702 
00703     if
00704     (
00705         returnReduce(nRefine, sumOp<label>())
00706       > returnReduce(nAllowRefine, sumOp<label>())
00707     )
00708     {
00709         Info<< "Reached refinement limit." << endl;
00710     }
00711 
00712     return returnReduce(nRefine-oldNRefine, sumOp<label>());
00713 }
00714 
00715 
00716 // Checks if multiple intersections of a cell (by a surface with a higher
00717 // max than the cell level) and if so if the normals at these intersections
00718 // make a large angle.
00719 // Returns false if the nRefine limit has been reached, true otherwise.
00720 bool Foam::meshRefinement::checkCurvature
00721 (
00722     const scalar curvature,
00723     const label nAllowRefine,
00724 
00725     const label surfaceLevel,   // current intersection max level
00726     const vector& surfaceNormal,// current intersection normal
00727 
00728     const label cellI,
00729 
00730     label& cellMaxLevel,        // cached max surface level for this cell
00731     vector& cellMaxNormal,      // cached surface normal for this cell
00732 
00733     labelList& refineCell,
00734     label& nRefine
00735 ) const
00736 {
00737     const labelList& cellLevel = meshCutter_.cellLevel();
00738 
00739     // Test if surface applicable
00740     if (surfaceLevel > cellLevel[cellI])
00741     {
00742         if (cellMaxLevel == -1)
00743         {
00744             // First visit of cell. Store
00745             cellMaxLevel = surfaceLevel;
00746             cellMaxNormal = surfaceNormal;
00747         }
00748         else
00749         {
00750             // Second or more visit. Check curvature.
00751             if ((cellMaxNormal & surfaceNormal) < curvature)
00752             {
00753                 return markForRefine
00754                 (
00755                     surfaceLevel,   // mark with any non-neg number.
00756                     nAllowRefine,
00757                     refineCell[cellI],
00758                     nRefine
00759                 );
00760             }
00761 
00762             // Set normal to that of highest surface. Not really necessary
00763             // over here but we reuse cellMax info when doing coupled faces.
00764             if (surfaceLevel > cellMaxLevel)
00765             {
00766                 cellMaxLevel = surfaceLevel;
00767                 cellMaxNormal = surfaceNormal;
00768             }
00769         }
00770     }
00771 
00772     // Did not reach refinement limit.
00773     return true;
00774 }
00775 
00776 
00777 // Mark cells for surface curvature based refinement.
00778 Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
00779 (
00780     const scalar curvature,
00781     const label nAllowRefine,
00782     const labelList& neiLevel,
00783     const pointField& neiCc,
00784 
00785     labelList& refineCell,
00786     label& nRefine
00787 ) const
00788 {
00789     const labelList& cellLevel = meshCutter_.cellLevel();
00790     const pointField& cellCentres = mesh_.cellCentres();
00791 
00792     label oldNRefine = nRefine;
00793 
00794     // 1. local test: any cell on more than one surface gets refined
00795     // (if its current level is < max of the surface max level)
00796 
00797     // 2. 'global' test: any cell on only one surface with a neighbour
00798     // on a different surface gets refined (if its current level etc.)
00799 
00800 
00801     // Collect candidate faces (i.e. intersecting any surface and
00802     // owner/neighbour not yet refined.
00803     labelList testFaces(getRefineCandidateFaces(refineCell));
00804 
00805     // Collect segments
00806     pointField start(testFaces.size());
00807     pointField end(testFaces.size());
00808     labelList minLevel(testFaces.size());
00809 
00810     forAll(testFaces, i)
00811     {
00812         label faceI = testFaces[i];
00813 
00814         label own = mesh_.faceOwner()[faceI];
00815 
00816         if (mesh_.isInternalFace(faceI))
00817         {
00818             label nei = mesh_.faceNeighbour()[faceI];
00819 
00820             start[i] = cellCentres[own];
00821             end[i] = cellCentres[nei];
00822             minLevel[i] = min(cellLevel[own], cellLevel[nei]);
00823         }
00824         else
00825         {
00826             label bFaceI = faceI - mesh_.nInternalFaces();
00827 
00828             start[i] = cellCentres[own];
00829             end[i] = neiCc[bFaceI];
00830             minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
00831         }
00832     }
00833 
00834     // Test for all intersections (with surfaces of higher max level than
00835     // minLevel) and cache per cell the max surface level and the local normal
00836     // on that surface.
00837     labelList cellMaxLevel(mesh_.nCells(), -1);
00838     vectorField cellMaxNormal(mesh_.nCells(), vector::zero);
00839 
00840     {
00841         // Per segment the normals of the surfaces
00842         List<vectorList> surfaceNormal;
00843         // Per segment the list of levels of the surfaces
00844         labelListList surfaceLevel;
00845 
00846         surfaces_.findAllHigherIntersections
00847         (
00848             start,
00849             end,
00850             minLevel,           // max level of surface has to be bigger
00851                                 // than min level of neighbouring cells
00852             surfaceNormal,
00853             surfaceLevel
00854         );
00855         // Clear out unnecessary data
00856         start.clear();
00857         end.clear();
00858         minLevel.clear();
00859 
00860         // Extract per cell information on the surface with the highest max
00861         forAll(testFaces, i)
00862         {
00863             label faceI = testFaces[i];
00864             label own = mesh_.faceOwner()[faceI];
00865 
00866             const vectorList& fNormals = surfaceNormal[i];
00867             const labelList& fLevels = surfaceLevel[i];
00868 
00869             forAll(fLevels, hitI)
00870             {
00871                 checkCurvature
00872                 (
00873                     curvature,
00874                     nAllowRefine,
00875 
00876                     fLevels[hitI],
00877                     fNormals[hitI],
00878 
00879                     own,
00880                     cellMaxLevel[own],
00881                     cellMaxNormal[own],
00882 
00883                     refineCell,
00884                     nRefine
00885                 );
00886             }
00887 
00888             if (mesh_.isInternalFace(faceI))
00889             {
00890                 label nei = mesh_.faceNeighbour()[faceI];
00891 
00892                 forAll(fLevels, hitI)
00893                 {
00894                     checkCurvature
00895                     (
00896                         curvature,
00897                         nAllowRefine,
00898 
00899                         fLevels[hitI],
00900                         fNormals[hitI],
00901 
00902                         nei,
00903                         cellMaxLevel[nei],
00904                         cellMaxNormal[nei],
00905 
00906                         refineCell,
00907                         nRefine
00908                     );
00909                 }
00910             }
00911         }
00912     }
00913 
00914     // 2. Find out a measure of surface curvature and region edges.
00915     // Send over surface region and surface normal to neighbour cell.
00916 
00917     labelList neiBndMaxLevel(mesh_.nFaces()-mesh_.nInternalFaces());
00918     vectorField neiBndMaxNormal(mesh_.nFaces()-mesh_.nInternalFaces());
00919 
00920     for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
00921     {
00922         label bFaceI = faceI-mesh_.nInternalFaces();
00923         label own = mesh_.faceOwner()[faceI];
00924 
00925         neiBndMaxLevel[bFaceI] = cellMaxLevel[own];
00926         neiBndMaxNormal[bFaceI] = cellMaxNormal[own];
00927     }
00928     syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel, false);
00929     syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal, false);
00930 
00931     // Loop over all faces. Could only be checkFaces.. except if they're coupled
00932 
00933     // Internal faces
00934     for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
00935     {
00936         label own = mesh_.faceOwner()[faceI];
00937         label nei = mesh_.faceNeighbour()[faceI];
00938 
00939         if (cellMaxLevel[own] != -1 && cellMaxLevel[nei] != -1)
00940         {
00941             // Have valid data on both sides. Check curvature.
00942             if ((cellMaxNormal[own] & cellMaxNormal[nei]) < curvature)
00943             {
00944                 // See which side to refine
00945                 if (cellLevel[own] < cellMaxLevel[own])
00946                 {
00947                     if
00948                     (
00949                         !markForRefine
00950                         (
00951                             cellMaxLevel[own],
00952                             nAllowRefine,
00953                             refineCell[own],
00954                             nRefine
00955                         )
00956                     )
00957                     {
00958                         if (debug)
00959                         {
00960                             Pout<< "Stopped refining since reaching my cell"
00961                                 << " limit of " << mesh_.nCells()+7*nRefine
00962                                 << endl;
00963                         }
00964                         break;
00965                     }
00966                 }
00967 
00968                 if (cellLevel[nei] < cellMaxLevel[nei])
00969                 {
00970                     if
00971                     (
00972                         !markForRefine
00973                         (
00974                             cellMaxLevel[nei],
00975                             nAllowRefine,
00976                             refineCell[nei],
00977                             nRefine
00978                         )
00979                     )
00980                     {
00981                         if (debug)
00982                         {
00983                             Pout<< "Stopped refining since reaching my cell"
00984                                 << " limit of " << mesh_.nCells()+7*nRefine
00985                                 << endl;
00986                         }
00987                         break;
00988                     }
00989                 }
00990             }
00991         }
00992     }
00993     // Boundary faces
00994     for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
00995     {
00996         label own = mesh_.faceOwner()[faceI];
00997         label bFaceI = faceI - mesh_.nInternalFaces();
00998 
00999         if (cellLevel[own] < cellMaxLevel[own] && neiBndMaxLevel[bFaceI] != -1)
01000         {
01001             // Have valid data on both sides. Check curvature.
01002             if ((cellMaxNormal[own] & neiBndMaxNormal[bFaceI]) < curvature)
01003             {
01004                 if
01005                 (
01006                     !markForRefine
01007                     (
01008                         cellMaxLevel[own],
01009                         nAllowRefine,
01010                         refineCell[own],
01011                         nRefine
01012                     )
01013                 )
01014                 {
01015                     if (debug)
01016                     {
01017                         Pout<< "Stopped refining since reaching my cell"
01018                             << " limit of " << mesh_.nCells()+7*nRefine
01019                             << endl;
01020                     }
01021                     break;
01022                 }
01023             }
01024         }
01025     }
01026 
01027     if
01028     (
01029         returnReduce(nRefine, sumOp<label>())
01030       > returnReduce(nAllowRefine, sumOp<label>())
01031     )
01032     {
01033         Info<< "Reached refinement limit." << endl;
01034     }
01035 
01036     return returnReduce(nRefine-oldNRefine, sumOp<label>());
01037 }
01038 
01039 
01040 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
01041 
01042 // Calculate list of cells to refine. Gets for any edge (start - end)
01043 // whether it intersects the surface. Does more accurate test and checks
01044 // the wanted level on the surface intersected.
01045 // Does approximate precalculation of how many cells can be refined before
01046 // hitting overall limit maxGlobalCells.
01047 Foam::labelList Foam::meshRefinement::refineCandidates
01048 (
01049     const point& keepPoint,
01050     const scalar curvature,
01051 
01052     const PtrList<featureEdgeMesh>& featureMeshes,
01053     const labelList& featureLevels,
01054 
01055     const bool featureRefinement,
01056     const bool internalRefinement,
01057     const bool surfaceRefinement,
01058     const bool curvatureRefinement,
01059     const label maxGlobalCells,
01060     const label maxLocalCells
01061 ) const
01062 {
01063     label totNCells = mesh_.globalData().nTotalCells();
01064 
01065     labelList cellsToRefine;
01066 
01067     if (totNCells >= maxGlobalCells)
01068     {
01069         Info<< "No cells marked for refinement since reached limit "
01070             << maxGlobalCells << '.' << endl;
01071     }
01072     else
01073     {
01074         // Every cell I refine adds 7 cells. Estimate the number of cells
01075         // I am allowed to refine.
01076         // Assume perfect distribution so can only refine as much the fraction
01077         // of the mesh I hold. This prediction step prevents us having to do
01078         // lots of reduces to keep count of the total number of cells selected
01079         // for refinement.
01080 
01081         //scalar fraction = scalar(mesh_.nCells())/totNCells;
01082         //label myMaxCells = label(maxGlobalCells*fraction);
01083         //label nAllowRefine = (myMaxCells - mesh_.nCells())/7;
01085         //
01086         //Pout<< "refineCandidates:" << nl
01087         //    << "    total cells:" << totNCells << nl
01088         //    << "    local cells:" << mesh_.nCells() << nl
01089         //    << "    local fraction:" << fraction << nl
01090         //    << "    local allowable cells:" << myMaxCells << nl
01091         //    << "    local allowable refinement:" << nAllowRefine << nl
01092         //    << endl;
01093 
01094         //- Disable refinement shortcut. nAllowRefine is per processor limit.
01095         label nAllowRefine = labelMax / Pstream::nProcs();
01096 
01097         // Marked for refinement (>= 0) or not (-1). Actual value is the
01098         // index of the surface it intersects.
01099         labelList refineCell(mesh_.nCells(), -1);
01100         label nRefine = 0;
01101 
01102 
01103         // Swap neighbouring cell centres and cell level
01104         labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
01105         pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
01106         calcNeighbourData(neiLevel, neiCc);
01107 
01108 
01109 
01110         // Cells pierced by feature lines
01111         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01112 
01113         if (featureRefinement)
01114         {
01115             label nFeatures = markFeatureRefinement
01116             (
01117                 keepPoint,
01118                 featureMeshes,
01119                 featureLevels,
01120                 nAllowRefine,
01121 
01122                 refineCell,
01123                 nRefine
01124             );
01125 
01126             Info<< "Marked for refinement due to explicit features    : "
01127                 << nFeatures << " cells."  << endl;
01128         }
01129 
01130         // Inside refinement shells
01131         // ~~~~~~~~~~~~~~~~~~~~~~~~
01132 
01133         if (internalRefinement)
01134         {
01135             label nShell = markInternalRefinement
01136             (
01137                 nAllowRefine,
01138 
01139                 refineCell,
01140                 nRefine
01141             );
01142             Info<< "Marked for refinement due to refinement shells    : "
01143                 << nShell << " cells."  << endl;
01144         }
01145 
01146         // Refinement based on intersection of surface
01147         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01148 
01149         if (surfaceRefinement)
01150         {
01151             label nSurf = markSurfaceRefinement
01152             (
01153                 nAllowRefine,
01154                 neiLevel,
01155                 neiCc,
01156 
01157                 refineCell,
01158                 nRefine
01159             );
01160             Info<< "Marked for refinement due to surface intersection : "
01161                 << nSurf << " cells."  << endl;
01162         }
01163 
01164         // Refinement based on curvature of surface
01165         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01166 
01167         if
01168         (
01169             curvatureRefinement
01170          && (curvature >= -1 && curvature <= 1)
01171          && (surfaces_.minLevel() != surfaces_.maxLevel())
01172         )
01173         {
01174             label nCurv = markSurfaceCurvatureRefinement
01175             (
01176                 curvature,
01177                 nAllowRefine,
01178                 neiLevel,
01179                 neiCc,
01180 
01181                 refineCell,
01182                 nRefine
01183             );
01184             Info<< "Marked for refinement due to curvature/regions    : "
01185                 << nCurv << " cells."  << endl;
01186         }
01187 
01188         // Pack cells-to-refine
01189         // ~~~~~~~~~~~~~~~~~~~~
01190 
01191         cellsToRefine.setSize(nRefine);
01192         nRefine = 0;
01193 
01194         forAll(refineCell, cellI)
01195         {
01196             if (refineCell[cellI] != -1)
01197             {
01198                 cellsToRefine[nRefine++] = cellI;
01199             }
01200         }
01201     }
01202 
01203     return cellsToRefine;
01204 }
01205 
01206 
01207 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::refine
01208 (
01209     const labelList& cellsToRefine
01210 )
01211 {
01212     // Mesh changing engine.
01213     polyTopoChange meshMod(mesh_);
01214 
01215     // Play refinement commands into mesh changer.
01216     meshCutter_.setRefinement(cellsToRefine, meshMod);
01217 
01218     // Create mesh (no inflation), return map from old to new mesh.
01219     autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false);
01220 
01221     // Update fields
01222     mesh_.updateMesh(map);
01223 
01224     // Optionally inflate mesh
01225     if (map().hasMotionPoints())
01226     {
01227         mesh_.movePoints(map().preMotionPoints());
01228     }
01229     else
01230     {
01231         // Delete mesh volumes.
01232         mesh_.clearOut();
01233     }
01234 
01235     if (overwrite())
01236     {
01237         mesh_.setInstance(oldInstance());
01238     }
01239 
01240     // Update intersection info
01241     updateMesh(map, getChangedFaces(map, cellsToRefine));
01242 
01243     return map;
01244 }
01245 
01246 
01247 // Do refinement of consistent set of cells followed by truncation and
01248 // load balancing.
01249 Foam::autoPtr<Foam::mapDistributePolyMesh>
01250 Foam::meshRefinement::refineAndBalance
01251 (
01252     const string& msg,
01253     decompositionMethod& decomposer,
01254     fvMeshDistribute& distributor,
01255     const labelList& cellsToRefine,
01256     const scalar maxLoadUnbalance
01257 )
01258 {
01259     // Do all refinement
01260     refine(cellsToRefine);
01261 
01262     if (debug)
01263     {
01264         Pout<< "Writing refined but unbalanced " << msg
01265             << " mesh to time " << timeName() << endl;
01266         write
01267         (
01268             debug,
01269             mesh_.time().path()
01270            /timeName()
01271         );
01272         Pout<< "Dumped debug data in = "
01273             << mesh_.time().cpuTimeIncrement() << " s" << endl;
01274 
01275         // test all is still synced across proc patches
01276         checkData();
01277     }
01278 
01279     Info<< "Refined mesh in = "
01280         << mesh_.time().cpuTimeIncrement() << " s" << endl;
01281     printMeshInfo(debug, "After refinement " + msg);
01282 
01283 
01284     // Load balancing
01285     // ~~~~~~~~~~~~~~
01286 
01287     autoPtr<mapDistributePolyMesh> distMap;
01288 
01289     if (Pstream::nProcs() > 1)
01290     {
01291         scalar nIdealCells =
01292             mesh_.globalData().nTotalCells()
01293           / Pstream::nProcs();
01294 
01295         scalar unbalance = returnReduce
01296         (
01297             mag(1.0-mesh_.nCells()/nIdealCells),
01298             maxOp<scalar>()
01299         );
01300 
01301         if (unbalance <= maxLoadUnbalance)
01302         {
01303             Info<< "Skipping balancing since max unbalance " << unbalance
01304                 << " is less than allowable " << maxLoadUnbalance
01305                 << endl;
01306         }
01307         else
01308         {
01309             scalarField cellWeights(mesh_.nCells(), 1);
01310 
01311             distMap = balance
01312             (
01313                 false,  //keepZoneFaces
01314                 false,  //keepBaffles
01315                 cellWeights,
01316                 decomposer,
01317                 distributor
01318             );
01319 
01320             Info<< "Balanced mesh in = "
01321                 << mesh_.time().cpuTimeIncrement() << " s" << endl;
01322 
01323             printMeshInfo(debug, "After balancing " + msg);
01324 
01325 
01326             if (debug)
01327             {
01328                 Pout<< "Writing balanced " << msg
01329                     << " mesh to time " << timeName() << endl;
01330                 write
01331                 (
01332                     debug,
01333                     mesh_.time().path()/timeName()
01334                 );
01335                 Pout<< "Dumped debug data in = "
01336                     << mesh_.time().cpuTimeIncrement() << " s" << endl;
01337 
01338                 // test all is still synced across proc patches
01339                 checkData();
01340             }
01341         }
01342     }
01343 
01344     return distMap;
01345 }
01346 
01347 
01348 // Do load balancing followed by refinement of consistent set of cells.
01349 Foam::autoPtr<Foam::mapDistributePolyMesh>
01350 Foam::meshRefinement::balanceAndRefine
01351 (
01352     const string& msg,
01353     decompositionMethod& decomposer,
01354     fvMeshDistribute& distributor,
01355     const labelList& initCellsToRefine,
01356     const scalar maxLoadUnbalance
01357 )
01358 {
01359     labelList cellsToRefine(initCellsToRefine);
01360 
01361     //{
01362     //    globalIndex globalCells(mesh_.nCells());
01363     //
01364     //    Info<< "** Distribution before balancing/refining:" << endl;
01365     //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
01366     //    {
01367     //        Info<< "    " << procI << '\t'
01368     //            << globalCells.localSize(procI) << endl;
01369     //    }
01370     //    Info<< endl;
01371     //}
01372     //{
01373     //    globalIndex globalCells(cellsToRefine.size());
01374     //
01375     //    Info<< "** Cells to be refined:" << endl;
01376     //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
01377     //    {
01378     //        Info<< "    " << procI << '\t'
01379     //            << globalCells.localSize(procI) << endl;
01380     //    }
01381     //    Info<< endl;
01382     //}
01383 
01384 
01385     // Load balancing
01386     // ~~~~~~~~~~~~~~
01387 
01388     autoPtr<mapDistributePolyMesh> distMap;
01389 
01390     if (Pstream::nProcs() > 1)
01391     {
01392         // First check if we need to balance at all. Precalculate number of
01393         // cells after refinement and see what maximum difference is.
01394         scalar nNewCells = scalar(mesh_.nCells() + 7*cellsToRefine.size());
01395         scalar nIdealNewCells =
01396             returnReduce(nNewCells, sumOp<scalar>())
01397           / Pstream::nProcs();
01398         scalar unbalance = returnReduce
01399         (
01400             mag(1.0-nNewCells/nIdealNewCells),
01401             maxOp<scalar>()
01402         );
01403 
01404         if (unbalance <= maxLoadUnbalance)
01405         {
01406             Info<< "Skipping balancing since max unbalance " << unbalance
01407                 << " is less than allowable " << maxLoadUnbalance
01408                 << endl;
01409         }
01410         else
01411         {
01412             scalarField cellWeights(mesh_.nCells(), 1);
01413             forAll(cellsToRefine, i)
01414             {
01415                 cellWeights[cellsToRefine[i]] += 7;
01416             }
01417 
01418             distMap = balance
01419             (
01420                 false,  //keepZoneFaces
01421                 false,  //keepBaffles
01422                 cellWeights,
01423                 decomposer,
01424                 distributor
01425             );
01426 
01427             // Update cells to refine
01428             distMap().distributeCellIndices(cellsToRefine);
01429 
01430             Info<< "Balanced mesh in = "
01431                 << mesh_.time().cpuTimeIncrement() << " s" << endl;
01432         }
01433 
01434         //{
01435         //    globalIndex globalCells(mesh_.nCells());
01436         //
01437         //    Info<< "** Distribution after balancing:" << endl;
01438         //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
01439         //    {
01440         //        Info<< "    " << procI << '\t'
01441         //            << globalCells.localSize(procI) << endl;
01442         //    }
01443         //    Info<< endl;
01444         //}
01445 
01446         printMeshInfo(debug, "After balancing " + msg);
01447 
01448         if (debug)
01449         {
01450             Pout<< "Writing balanced " << msg
01451                 << " mesh to time " << timeName() << endl;
01452             write
01453             (
01454                 debug,
01455                 mesh_.time().path()/timeName()
01456             );
01457             Pout<< "Dumped debug data in = "
01458                 << mesh_.time().cpuTimeIncrement() << " s" << endl;
01459 
01460             // test all is still synced across proc patches
01461             checkData();
01462         }
01463     }
01464 
01465 
01466     // Refinement
01467     // ~~~~~~~~~~
01468 
01469     refine(cellsToRefine);
01470 
01471     if (debug)
01472     {
01473         Pout<< "Writing refined " << msg
01474             << " mesh to time " << timeName() << endl;
01475         write
01476         (
01477             debug,
01478             mesh_.time().path()
01479            /timeName()
01480         );
01481         Pout<< "Dumped debug data in = "
01482             << mesh_.time().cpuTimeIncrement() << " s" << endl;
01483 
01484         // test all is still synced across proc patches
01485         checkData();
01486     }
01487 
01488     Info<< "Refined mesh in = "
01489         << mesh_.time().cpuTimeIncrement() << " s" << endl;
01490 
01491     //{
01492     //    globalIndex globalCells(mesh_.nCells());
01493     //
01494     //    Info<< "** After refinement distribution:" << endl;
01495     //    for (label procI = 0; procI < Pstream::nProcs(); procI++)
01496     //    {
01497     //        Info<< "    " << procI << '\t'
01498     //            << globalCells.localSize(procI) << endl;
01499     //    }
01500     //    Info<< endl;
01501     //}
01502 
01503     printMeshInfo(debug, "After refinement " + msg);
01504 
01505     return distMap;
01506 }
01507 
01508 
01509 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines