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

dynamicRefineFvMesh.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 "dynamicRefineFvMesh.H"
00027 #include <OpenFOAM/addToRunTimeSelectionTable.H>
00028 #include <finiteVolume/volFields.H>
00029 #include <dynamicMesh/polyTopoChange.H>
00030 #include <finiteVolume/surfaceFields.H>
00031 #include <finiteVolume/fvCFD.H>
00032 #include <OpenFOAM/syncTools.H>
00033 #include <OpenFOAM/pointFields.H>
00034 
00035 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00036 
00037 namespace Foam
00038 {
00039 
00040 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00041 
00042 defineTypeNameAndDebug(dynamicRefineFvMesh, 0);
00043 
00044 addToRunTimeSelectionTable(dynamicFvMesh, dynamicRefineFvMesh, IOobject);
00045 
00046 
00047 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00048 
00049 label dynamicRefineFvMesh::count
00050 (
00051     const PackedBoolList& l,
00052     const unsigned int val
00053 )
00054 {
00055     label n = 0;
00056     forAll(l, i)
00057     {
00058         if (l.get(i) == val)
00059         {
00060             n++;
00061         }
00062     }
00063     return n;
00064 }
00065 
00066 
00067 void dynamicRefineFvMesh::calculateProtectedCells
00068 (
00069     PackedBoolList& unrefineableCell
00070 ) const
00071 {
00072     if (protectedCell_.empty())
00073     {
00074         unrefineableCell.clear();
00075         return;
00076     }
00077 
00078     const labelList& cellLevel = meshCutter_.cellLevel();
00079 
00080     unrefineableCell = protectedCell_;
00081 
00082     // Get neighbouring cell level
00083     labelList neiLevel(nFaces()-nInternalFaces());
00084 
00085     for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
00086     {
00087         neiLevel[faceI-nInternalFaces()] = cellLevel[faceOwner()[faceI]];
00088     }
00089     syncTools::swapBoundaryFaceList(*this, neiLevel, false);
00090 
00091 
00092     while (true)
00093     {
00094         // Pick up faces on border of protected cells
00095         boolList seedFace(nFaces(), false);
00096 
00097         forAll(faceNeighbour(), faceI)
00098         {
00099             label own = faceOwner()[faceI];
00100             bool ownProtected = (unrefineableCell.get(own) == 1);
00101             label nei = faceNeighbour()[faceI];
00102             bool neiProtected = (unrefineableCell.get(nei) == 1);
00103 
00104             if (ownProtected && (cellLevel[nei] > cellLevel[own]))
00105             {
00106                 seedFace[faceI] = true;
00107             }
00108             else if (neiProtected && (cellLevel[own] > cellLevel[nei]))
00109             {
00110                 seedFace[faceI] = true;
00111             }
00112         }
00113         for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
00114         {
00115             label own = faceOwner()[faceI];
00116             bool ownProtected = (unrefineableCell.get(own) == 1);
00117             if
00118             (
00119                 ownProtected
00120              && (neiLevel[faceI-nInternalFaces()] > cellLevel[own])
00121             )
00122             {
00123                 seedFace[faceI] = true;
00124             }
00125         }
00126 
00127         syncTools::syncFaceList(*this, seedFace, orEqOp<bool>(), false);
00128 
00129 
00130         // Extend unrefineableCell
00131         bool hasExtended = false;
00132 
00133         for (label faceI = 0; faceI < nInternalFaces(); faceI++)
00134         {
00135             if (seedFace[faceI])
00136             {
00137                 label own = faceOwner()[faceI];
00138                 if (unrefineableCell.get(own) == 0)
00139                 {
00140                     unrefineableCell.set(own, 1);
00141                     hasExtended = true;
00142                 }
00143 
00144                 label nei = faceNeighbour()[faceI];
00145                 if (unrefineableCell.get(nei) == 0)
00146                 {
00147                     unrefineableCell.set(nei, 1);
00148                     hasExtended = true;
00149                 }
00150             }
00151         }
00152         for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
00153         {
00154             if (seedFace[faceI])
00155             {
00156                 label own = faceOwner()[faceI];
00157                 if (unrefineableCell.get(own) == 0)
00158                 {
00159                     unrefineableCell.set(own, 1);
00160                     hasExtended = true;
00161                 }
00162             }
00163         }
00164 
00165         if (!returnReduce(hasExtended, orOp<bool>()))
00166         {
00167             break;
00168         }
00169     }
00170 }
00171 
00172 
00173 void dynamicRefineFvMesh::readDict()
00174 {
00175     dictionary refineDict
00176     (
00177         IOdictionary
00178         (
00179             IOobject
00180             (
00181                 "dynamicMeshDict",
00182                 time().constant(),
00183                 *this,
00184                 IOobject::MUST_READ,
00185                 IOobject::NO_WRITE,
00186                 false
00187             )
00188         ).subDict(typeName + "Coeffs")
00189     );
00190 
00191     correctFluxes_ = List<Pair<word> >(refineDict.lookup("correctFluxes"));
00192 
00193     dumpLevel_ = Switch(refineDict.lookup("dumpLevel"));
00194 }
00195 
00196 
00197 // Refines cells, maps fields and recalculates (an approximate) flux
00198 autoPtr<mapPolyMesh> dynamicRefineFvMesh::refine
00199 (
00200     const labelList& cellsToRefine
00201 )
00202 {
00203     // Mesh changing engine.
00204     polyTopoChange meshMod(*this);
00205 
00206     // Play refinement commands into mesh changer.
00207     meshCutter_.setRefinement(cellsToRefine, meshMod);
00208 
00209     // Create mesh (with inflation), return map from old to new mesh.
00210     //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
00211     autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
00212 
00213     Info<< "Refined from "
00214         << returnReduce(map().nOldCells(), sumOp<label>())
00215         << " to " << globalData().nTotalCells() << " cells." << endl;
00216 
00217     if (debug)
00218     {
00219         // Check map.
00220         for (label faceI = 0; faceI < nInternalFaces(); faceI++)
00221         {
00222             label oldFaceI = map().faceMap()[faceI];
00223 
00224             if (oldFaceI >= nInternalFaces())
00225             {
00226                 FatalErrorIn("dynamicRefineFvMesh::refine(const labelList&)")
00227                     << "New internal face:" << faceI
00228                     << " fc:" << faceCentres()[faceI]
00229                     << " originates from boundary oldFace:" << oldFaceI
00230                     << abort(FatalError);
00231             }
00232         }
00233     }
00234 
00235 
00236     // Update fields
00237     updateMesh(map);
00238 
00239     // Move mesh
00240     /*
00241     pointField newPoints;
00242     if (map().hasMotionPoints())
00243     {
00244         newPoints = map().preMotionPoints();
00245     }
00246     else
00247     {
00248         newPoints = points();
00249     }
00250     movePoints(newPoints);
00251     */
00252 
00253     // Correct the flux for modified/added faces. All the faces which only
00254     // have been renumbered will already have been handled by the mapping.
00255     {
00256         const labelList& faceMap = map().faceMap();
00257         const labelList& reverseFaceMap = map().reverseFaceMap();
00258 
00259         // Storage for any master faces. These will be the original faces
00260         // on the coarse cell that get split into four (or rather the
00261         // master face gets modified and three faces get added from the master)
00262         labelHashSet masterFaces(4*cellsToRefine.size());
00263 
00264         forAll(faceMap, faceI)
00265         {
00266             label oldFaceI = faceMap[faceI];
00267 
00268             if (oldFaceI >= 0)
00269             {
00270                 label masterFaceI = reverseFaceMap[oldFaceI];
00271 
00272                 if (masterFaceI < 0)
00273                 {
00274                     FatalErrorIn
00275                     (
00276                         "dynamicRefineFvMesh::refine(const labelList&)"
00277                     )   << "Problem: should not have removed faces"
00278                         << " when refining."
00279                         << nl << "face:" << faceI << abort(FatalError);
00280                 }
00281                 else if (masterFaceI != faceI)
00282                 {
00283                     masterFaces.insert(masterFaceI);
00284                 }
00285             }
00286         }
00287         if (debug)
00288         {
00289             Info<< "Found " << returnReduce(masterFaces.size(), sumOp<label>())
00290                 << " split faces " << endl;
00291         }
00292 
00293         forAll(correctFluxes_, i)
00294         {
00295             if (debug)
00296             {
00297                 Info<< "Mapping flux " << correctFluxes_[i][0]
00298                     << " using interpolated flux " << correctFluxes_[i][1]
00299                     << endl;
00300             }
00301             surfaceScalarField& phi = const_cast<surfaceScalarField&>
00302             (
00303                 lookupObject<surfaceScalarField>(correctFluxes_[i][0])
00304             );
00305             surfaceScalarField phiU =
00306                 fvc::interpolate
00307                 (
00308                     lookupObject<volVectorField>(correctFluxes_[i][1])
00309                 )
00310               & Sf();
00311 
00312             // Recalculate new internal faces.
00313             for (label faceI = 0; faceI < nInternalFaces(); faceI++)
00314             {
00315                 label oldFaceI = faceMap[faceI];
00316 
00317                 if (oldFaceI == -1)
00318                 {
00319                     // Inflated/appended
00320                     phi[faceI] = phiU[faceI];
00321                 }
00322                 else if (reverseFaceMap[oldFaceI] != faceI)
00323                 {
00324                     // face-from-masterface
00325                     phi[faceI] = phiU[faceI];
00326                 }
00327             }
00328 
00329             // Recalculate new boundary faces.
00330             forAll(phi.boundaryField(), patchI)
00331             {
00332                 fvsPatchScalarField& patchPhi = phi.boundaryField()[patchI];
00333                 const fvsPatchScalarField& patchPhiU =
00334                     phiU.boundaryField()[patchI];
00335 
00336                 label faceI = patchPhi.patch().patch().start();
00337 
00338                 forAll(patchPhi, i)
00339                 {
00340                     label oldFaceI = faceMap[faceI];
00341 
00342                     if (oldFaceI == -1)
00343                     {
00344                         // Inflated/appended
00345                         patchPhi[i] = patchPhiU[i];
00346                     }
00347                     else if (reverseFaceMap[oldFaceI] != faceI)
00348                     {
00349                         // face-from-masterface
00350                         patchPhi[i] = patchPhiU[i];
00351                     }
00352 
00353                     faceI++;
00354                 }
00355             }
00356 
00357             // Update master faces
00358             forAllConstIter(labelHashSet, masterFaces, iter)
00359             {
00360                 label faceI = iter.key();
00361 
00362                 if (isInternalFace(faceI))
00363                 {
00364                     phi[faceI] = phiU[faceI];
00365                 }
00366                 else
00367                 {
00368                     label patchI = boundaryMesh().whichPatch(faceI);
00369                     label i = faceI - boundaryMesh()[patchI].start();
00370 
00371                     const fvsPatchScalarField& patchPhiU =
00372                         phiU.boundaryField()[patchI];
00373 
00374                     fvsPatchScalarField& patchPhi =
00375                         phi.boundaryField()[patchI];
00376 
00377                     patchPhi[i] = patchPhiU[i];
00378                 }
00379             }
00380         }
00381     }
00382 
00383 
00384 
00385     // Update numbering of cells/vertices.
00386     meshCutter_.updateMesh(map);
00387 
00388     // Update numbering of protectedCell_
00389     if (protectedCell_.size())
00390     {
00391         PackedBoolList newProtectedCell(nCells());
00392 
00393         forAll(newProtectedCell, cellI)
00394         {
00395             label oldCellI = map().cellMap()[cellI];
00396             newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
00397         }
00398         protectedCell_.transfer(newProtectedCell);
00399     }
00400 
00401     // Debug: Check refinement levels (across faces only)
00402     meshCutter_.checkRefinementLevels(-1, labelList(0));
00403 
00404     return map;
00405 }
00406 
00407 
00408 // Combines previously split cells, maps fields and recalculates
00409 // (an approximate) flux
00410 autoPtr<mapPolyMesh> dynamicRefineFvMesh::unrefine
00411 (
00412     const labelList& splitPoints
00413 )
00414 {
00415     polyTopoChange meshMod(*this);
00416 
00417     // Play refinement commands into mesh changer.
00418     meshCutter_.setUnrefinement(splitPoints, meshMod);
00419 
00420 
00421     // Save information on faces that will be combined
00422     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00423 
00424     // Find the faceMidPoints on cells to be combined.
00425     // for each face resulting of split of face into four store the
00426     // midpoint
00427     Map<label> faceToSplitPoint(3*splitPoints.size());
00428 
00429     {
00430         forAll(splitPoints, i)
00431         {
00432             label pointI = splitPoints[i];
00433 
00434             const labelList& pEdges = pointEdges()[pointI];
00435 
00436             forAll(pEdges, j)
00437             {
00438                 label otherPointI = edges()[pEdges[j]].otherVertex(pointI);
00439 
00440                 const labelList& pFaces = pointFaces()[otherPointI];
00441 
00442                 forAll(pFaces, pFaceI)
00443                 {
00444                     faceToSplitPoint.insert(pFaces[pFaceI], otherPointI);
00445                 }
00446             }
00447         }
00448     }
00449 
00450 
00451     // Change mesh and generate map.
00452     //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
00453     autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
00454 
00455     Info<< "Unrefined from "
00456         << returnReduce(map().nOldCells(), sumOp<label>())
00457         << " to " << globalData().nTotalCells() << " cells."
00458         << endl;
00459 
00460     // Update fields
00461     updateMesh(map);
00462 
00463 
00464     // Move mesh
00465     /*
00466     pointField newPoints;
00467     if (map().hasMotionPoints())
00468     {
00469         newPoints = map().preMotionPoints();
00470     }
00471     else
00472     {
00473         newPoints = points();
00474     }
00475     movePoints(newPoints);
00476     */
00477 
00478     // Correct the flux for modified faces.
00479     {
00480         const labelList& reversePointMap = map().reversePointMap();
00481         const labelList& reverseFaceMap = map().reverseFaceMap();
00482 
00483         forAll(correctFluxes_, i)
00484         {
00485             if (debug)
00486             {
00487                 Info<< "Mapping flux " << correctFluxes_[i][0]
00488                     << " using interpolated flux " << correctFluxes_[i][1]
00489                     << endl;
00490             }
00491             surfaceScalarField& phi = const_cast<surfaceScalarField&>
00492             (
00493                 lookupObject<surfaceScalarField>(correctFluxes_[i][0])
00494             );
00495             surfaceScalarField phiU =
00496                 fvc::interpolate
00497                 (
00498                     lookupObject<volVectorField>(correctFluxes_[i][1])
00499                 )
00500               & Sf();
00501 
00502             forAllConstIter(Map<label>, faceToSplitPoint, iter)
00503             {
00504                 label oldFaceI = iter.key();
00505                 label oldPointI = iter();
00506 
00507                 if (reversePointMap[oldPointI] < 0)
00508                 {
00509                     // midpoint was removed. See if face still exists.
00510                     label faceI = reverseFaceMap[oldFaceI];
00511 
00512                     if (faceI >= 0)
00513                     {
00514                         if (isInternalFace(faceI))
00515                         {
00516                             phi[faceI] = phiU[faceI];
00517                         }
00518                         else
00519                         {
00520                             label patchI = boundaryMesh().whichPatch(faceI);
00521                             label i = faceI - boundaryMesh()[patchI].start();
00522 
00523                             const fvsPatchScalarField& patchPhiU =
00524                                 phiU.boundaryField()[patchI];
00525 
00526                             fvsPatchScalarField& patchPhi =
00527                                 phi.boundaryField()[patchI];
00528 
00529                             patchPhi[i] = patchPhiU[i];
00530                         }
00531                     }
00532                 }
00533             }
00534         }
00535     }
00536 
00537 
00538     // Update numbering of cells/vertices.
00539     meshCutter_.updateMesh(map);
00540 
00541     // Update numbering of protectedCell_
00542     if (protectedCell_.size())
00543     {
00544         PackedBoolList newProtectedCell(nCells());
00545 
00546         forAll(newProtectedCell, cellI)
00547         {
00548             label oldCellI = map().cellMap()[cellI];
00549             if (oldCellI >= 0)
00550             {
00551                 newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
00552             }
00553         }
00554         protectedCell_.transfer(newProtectedCell);
00555     }
00556 
00557     // Debug: Check refinement levels (across faces only)
00558     meshCutter_.checkRefinementLevels(-1, labelList(0));
00559 
00560     return map;
00561 }
00562 
00563 
00564 // Get max of connected point
00565 scalarField dynamicRefineFvMesh::maxPointField(const scalarField& pFld) const
00566 {
00567     scalarField vFld(nCells(), -GREAT);
00568 
00569     forAll(pointCells(), pointI)
00570     {
00571         const labelList& pCells = pointCells()[pointI];
00572 
00573         forAll(pCells, i)
00574         {
00575             vFld[pCells[i]] = max(vFld[pCells[i]], pFld[pointI]);
00576         }
00577     }
00578     return vFld;
00579 }
00580 
00581 
00582 // Get min of connected cell
00583 scalarField dynamicRefineFvMesh::minCellField(const volScalarField& vFld) const
00584 {
00585     scalarField pFld(nPoints(), GREAT);
00586 
00587     forAll(pointCells(), pointI)
00588     {
00589         const labelList& pCells = pointCells()[pointI];
00590 
00591         forAll(pCells, i)
00592         {
00593             pFld[pointI] = min(pFld[pointI], vFld[pCells[i]]);
00594         }
00595     }
00596     return pFld;
00597 }
00598 
00599 
00600 // Simple (non-parallel) interpolation by averaging.
00601 scalarField dynamicRefineFvMesh::cellToPoint(const scalarField& vFld) const
00602 {
00603     scalarField pFld(nPoints());
00604 
00605     forAll(pointCells(), pointI)
00606     {
00607         const labelList& pCells = pointCells()[pointI];
00608 
00609         scalar sum = 0.0;
00610         forAll(pCells, i)
00611         {
00612             sum += vFld[pCells[i]];
00613         }
00614         pFld[pointI] = sum/pCells.size();
00615     }
00616     return pFld;
00617 }
00618 
00619 
00620 // Calculate error. Is < 0 or distance to minLevel, maxLevel
00621 scalarField dynamicRefineFvMesh::error
00622 (
00623     const scalarField& fld,
00624     const scalar minLevel,
00625     const scalar maxLevel
00626 ) const
00627 {
00628     scalarField c(fld.size(), -1);
00629 
00630     forAll(fld, i)
00631     {
00632         scalar err = min(fld[i]-minLevel, maxLevel-fld[i]);
00633 
00634         if (err >= 0)
00635         {
00636             c[i] = err;
00637         }
00638     }
00639     return c;
00640 }
00641 
00642 
00643 void dynamicRefineFvMesh::selectRefineCandidates
00644 (
00645     const scalar lowerRefineLevel,
00646     const scalar upperRefineLevel,
00647     const scalarField& vFld,
00648     PackedBoolList& candidateCell
00649 ) const
00650 {
00651     // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
00652     // higher more desirable to be refined).
00653     scalarField cellError
00654     (
00655         maxPointField
00656         (
00657             error
00658             (
00659                 cellToPoint(vFld),
00660                 lowerRefineLevel,
00661                 upperRefineLevel
00662             )
00663         )
00664     );
00665 
00666     // Mark cells that are candidates for refinement.
00667     forAll(cellError, cellI)
00668     {
00669         if (cellError[cellI] > 0)
00670         {
00671             candidateCell.set(cellI, 1);
00672         }
00673     }
00674 }
00675 
00676 
00677 labelList dynamicRefineFvMesh::selectRefineCells
00678 (
00679     const label maxCells,
00680     const label maxRefinement,
00681     const PackedBoolList& candidateCell
00682 ) const
00683 {
00684     // Every refined cell causes 7 extra cells
00685     label nTotToRefine = (maxCells - globalData().nTotalCells()) / 7;
00686 
00687     const labelList& cellLevel = meshCutter_.cellLevel();
00688 
00689     // Mark cells that cannot be refined since they would trigger refinement
00690     // of protected cells (since 2:1 cascade)
00691     PackedBoolList unrefineableCell;
00692     calculateProtectedCells(unrefineableCell);
00693 
00694     // Count current selection
00695     label nCandidates = returnReduce(count(candidateCell, 1), sumOp<label>());
00696 
00697     // Collect all cells
00698     DynamicList<label> candidates(nCells());
00699 
00700     if (nCandidates < nTotToRefine)
00701     {
00702         forAll(candidateCell, cellI)
00703         {
00704             if
00705             (
00706                 cellLevel[cellI] < maxRefinement
00707              && candidateCell.get(cellI) == 1
00708              && (
00709                     unrefineableCell.empty()
00710                  || unrefineableCell.get(cellI) == 0
00711                 )
00712             )
00713             {
00714                 candidates.append(cellI);
00715             }
00716         }
00717     }
00718     else
00719     {
00720         // Sort by error? For now just truncate.
00721         for (label level = 0; level < maxRefinement; level++)
00722         {
00723             forAll(candidateCell, cellI)
00724             {
00725                 if
00726                 (
00727                     cellLevel[cellI] == level
00728                  && candidateCell.get(cellI) == 1
00729                  && (
00730                         unrefineableCell.empty()
00731                      || unrefineableCell.get(cellI) == 0
00732                     )
00733                 )
00734                 {
00735                     candidates.append(cellI);
00736                 }
00737             }
00738 
00739             if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
00740             {
00741                 break;
00742             }
00743         }
00744     }
00745 
00746     // Guarantee 2:1 refinement after refinement
00747     labelList consistentSet
00748     (
00749         meshCutter_.consistentRefinement
00750         (
00751             candidates.shrink(),
00752             true               // Add to set to guarantee 2:1
00753         )
00754     );
00755 
00756     Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
00757         << " cells for refinement out of " << globalData().nTotalCells()
00758         << "." << endl;
00759 
00760     return consistentSet;
00761 }
00762 
00763 
00764 labelList dynamicRefineFvMesh::selectUnrefinePoints
00765 (
00766     const scalar unrefineLevel,
00767     const PackedBoolList& markedCell,
00768     const scalarField& pFld
00769 ) const
00770 {
00771     // All points that can be unrefined
00772     const labelList splitPoints(meshCutter_.getSplitPoints());
00773 
00774     DynamicList<label> newSplitPoints(splitPoints.size());
00775 
00776     forAll(splitPoints, i)
00777     {
00778         label pointI = splitPoints[i];
00779 
00780         if (pFld[pointI] < unrefineLevel)
00781         {
00782             // Check that all cells are not marked
00783             const labelList& pCells = pointCells()[pointI];
00784 
00785             bool hasMarked = false;
00786 
00787             forAll(pCells, pCellI)
00788             {
00789                 if (markedCell.get(pCells[pCellI]) == 1)
00790                 {
00791                     hasMarked = true;
00792                     break;
00793                 }
00794             }
00795 
00796             if (!hasMarked)
00797             {
00798                 newSplitPoints.append(pointI);
00799             }
00800         }
00801     }
00802 
00803 
00804     newSplitPoints.shrink();
00805 
00806     // Guarantee 2:1 refinement after unrefinement
00807     labelList consistentSet
00808     (
00809         meshCutter_.consistentUnrefinement
00810         (
00811             newSplitPoints,
00812             false
00813         )
00814     );
00815     Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
00816         << " split points out of a possible "
00817         << returnReduce(splitPoints.size(), sumOp<label>())
00818         << "." << endl;
00819 
00820     return consistentSet;
00821 }
00822 
00823 
00824 void dynamicRefineFvMesh::extendMarkedCells(PackedBoolList& markedCell) const
00825 {
00826     // Mark faces using any marked cell
00827     boolList markedFace(nFaces(), false);
00828 
00829     forAll(markedCell, cellI)
00830     {
00831         if (markedCell.get(cellI) == 1)
00832         {
00833             const cell& cFaces = cells()[cellI];
00834 
00835             forAll(cFaces, i)
00836             {
00837                 markedFace[cFaces[i]] = true;
00838             }
00839         }
00840     }
00841 
00842     syncTools::syncFaceList(*this, markedFace, orEqOp<bool>(), false);
00843 
00844     // Update cells using any markedFace
00845     for (label faceI = 0; faceI < nInternalFaces(); faceI++)
00846     {
00847         if (markedFace[faceI])
00848         {
00849             markedCell.set(faceOwner()[faceI], 1);
00850             markedCell.set(faceNeighbour()[faceI], 1);
00851         }
00852     }
00853     for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
00854     {
00855         if (markedFace[faceI])
00856         {
00857             markedCell.set(faceOwner()[faceI], 1);
00858         }
00859     }
00860 }
00861 
00862 
00863 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00864 
00865 dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io)
00866 :
00867     dynamicFvMesh(io),
00868     meshCutter_(*this),
00869     dumpLevel_(false),
00870     nRefinementIterations_(0),
00871     protectedCell_(nCells(), 0)
00872 {
00873     // Read static part of dictionary
00874     readDict();
00875 
00876 
00877     const labelList& cellLevel = meshCutter_.cellLevel();
00878     const labelList& pointLevel = meshCutter_.pointLevel();
00879 
00880     // Set cells that should not be refined.
00881     // This is currently any cell which does not have 8 anchor points or
00882     // uses any face which does not have 4 anchor points.
00883     // Note: do not use cellPoint addressing
00884 
00885     // Count number of points <= cellLevel
00886     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00887 
00888     label nProtected = 0;
00889 
00890     forAll(cellLevel, cellI)
00891     {
00892         const labelList& cPoints = cellPoints(cellI);
00893 
00894         label nAnchors = 0;
00895         forAll(cPoints, cPointI)
00896         {
00897             label pointI = cPoints[cPointI];
00898             if (pointLevel[pointI] <= cellLevel[cellI])
00899             {
00900                 nAnchors++;
00901             }
00902         }
00903         if (nAnchors != 8)
00904         {
00905             protectedCell_.set(cellI, 1);
00906             nProtected++;
00907         }
00908     }
00909 
00910 
00911     // Count number of points <= faceLevel
00912     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00913     // Bit tricky since proc face might be one more refined than the owner since
00914     // the coupled one is refined.
00915 
00916     {
00917         labelList neiLevel(nFaces());
00918 
00919         for (label faceI = 0; faceI < nInternalFaces(); faceI++)
00920         {
00921             neiLevel[faceI] = cellLevel[faceNeighbour()[faceI]];
00922         }
00923         for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
00924         {
00925             neiLevel[faceI] = cellLevel[faceOwner()[faceI]];
00926         }
00927         syncTools::swapFaceList(*this, neiLevel, false);
00928 
00929 
00930         boolList protectedFace(nFaces(), false);
00931 
00932         forAll(faceOwner(), faceI)
00933         {
00934             label faceLevel = max
00935             (
00936                 cellLevel[faceOwner()[faceI]],
00937                 neiLevel[faceI]
00938             );
00939 
00940             const face& f = faces()[faceI];
00941 
00942             label nAnchors = 0;
00943 
00944             forAll(f, fp)
00945             {
00946                 if (pointLevel[f[fp]] <= faceLevel)
00947                 {
00948                     nAnchors++;
00949                 }
00950             }
00951 
00952             if (nAnchors != 4)
00953             {
00954                 protectedFace[faceI] = true;
00955             }
00956         }
00957 
00958         syncTools::syncFaceList
00959         (
00960             *this,
00961             protectedFace,
00962             orEqOp<bool>(),
00963             false
00964         );
00965 
00966         for (label faceI = 0; faceI < nInternalFaces(); faceI++)
00967         {
00968             if (protectedFace[faceI])
00969             {
00970                 if (protectedCell_.set(faceOwner()[faceI], 1))
00971                 {
00972                     nProtected++;
00973                 }
00974                 if (protectedCell_.set(faceNeighbour()[faceI], 1))
00975                 {
00976                     nProtected++;
00977                 }
00978             }
00979         }
00980         for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
00981         {
00982             if (protectedFace[faceI])
00983             {
00984                 if (protectedCell_.set(faceOwner()[faceI], 1))
00985                 {
00986                     nProtected++;
00987                 }
00988             }
00989         }
00990     }
00991 
00992     reduce(nProtected, sumOp<label>());
00993 
00994     //Info<< "Protecting " << nProtected << " out of "
00995     //    << returnReduce(nCells(), sumOp<label>())
00996     //    << endl;
00997 
00998 
00999 
01000     if (nProtected == 0)
01001     {
01002         protectedCell_.clear();
01003     }
01004 }
01005 
01006 
01007 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
01008 
01009 dynamicRefineFvMesh::~dynamicRefineFvMesh()
01010 {}
01011 
01012 
01013 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
01014 
01015 bool dynamicRefineFvMesh::update()
01016 {
01017     // Re-read dictionary. Choosen since usually -small so trivial amount
01018     // of time compared to actual refinement. Also very useful to be able
01019     // to modify on-the-fly.
01020     dictionary refineDict
01021     (
01022         IOdictionary
01023         (
01024             IOobject
01025             (
01026                 "dynamicMeshDict",
01027                 time().constant(),
01028                 *this,
01029                 IOobject::MUST_READ,
01030                 IOobject::NO_WRITE,
01031                 false
01032             )
01033         ).subDict(typeName + "Coeffs")
01034     );
01035 
01036     label refineInterval = readLabel(refineDict.lookup("refineInterval"));
01037 
01038     bool hasChanged = false;
01039 
01040     if (refineInterval == 0)
01041     {
01042         changing(hasChanged);
01043 
01044         return false;
01045     }
01046     else if (refineInterval < 0)
01047     {
01048         FatalErrorIn("dynamicRefineFvMesh::update()")
01049             << "Illegal refineInterval " << refineInterval << nl
01050             << "The refineInterval setting in the dynamicMeshDict should"
01051             << " be >= 1." << nl
01052             << exit(FatalError);
01053     }
01054 
01055 
01056 
01057 
01058     // Note: cannot refine at time 0 since no V0 present since mesh not
01059     //       moved yet.
01060 
01061     if (time().timeIndex() > 0 && time().timeIndex() % refineInterval == 0)
01062     {
01063         label maxCells = readLabel(refineDict.lookup("maxCells"));
01064 
01065         if (maxCells <= 0)
01066         {
01067             FatalErrorIn("dynamicRefineFvMesh::update()")
01068                 << "Illegal maximum number of cells " << maxCells << nl
01069                 << "The maxCells setting in the dynamicMeshDict should"
01070                 << " be > 0." << nl
01071                 << exit(FatalError);
01072         }
01073 
01074         label maxRefinement = readLabel(refineDict.lookup("maxRefinement"));
01075 
01076         if (maxRefinement <= 0)
01077         {
01078             FatalErrorIn("dynamicRefineFvMesh::update()")
01079                 << "Illegal maximum refinement level " << maxRefinement << nl
01080                 << "The maxCells setting in the dynamicMeshDict should"
01081                 << " be > 0." << nl
01082                 << exit(FatalError);
01083         }
01084 
01085         word field(refineDict.lookup("field"));
01086 
01087         const volScalarField& vFld = lookupObject<volScalarField>(field);
01088 
01089         const scalar lowerRefineLevel =
01090             readScalar(refineDict.lookup("lowerRefineLevel"));
01091         const scalar upperRefineLevel =
01092             readScalar(refineDict.lookup("upperRefineLevel"));
01093         const scalar unrefineLevel =
01094             readScalar(refineDict.lookup("unrefineLevel"));
01095         const label nBufferLayers =
01096             readLabel(refineDict.lookup("nBufferLayers"));
01097 
01098         // Cells marked for refinement or otherwise protected from unrefinement.
01099         PackedBoolList refineCell(nCells());
01100 
01101         if (globalData().nTotalCells() < maxCells)
01102         {
01103             // Determine candidates for refinement (looking at field only)
01104             selectRefineCandidates
01105             (
01106                 lowerRefineLevel,
01107                 upperRefineLevel,
01108                 vFld,
01109                 refineCell
01110             );
01111 
01112             // Select subset of candidates. Take into account max allowable
01113             // cells, refinement level, protected cells.
01114             labelList cellsToRefine
01115             (
01116                 selectRefineCells
01117                 (
01118                     maxCells,
01119                     maxRefinement,
01120                     refineCell
01121                 )
01122             );
01123 
01124             label nCellsToRefine = returnReduce
01125             (
01126                 cellsToRefine.size(), sumOp<label>()
01127             );
01128 
01129             if (nCellsToRefine > 0)
01130             {
01131                 // Refine/update mesh and map fields
01132                 autoPtr<mapPolyMesh> map = refine(cellsToRefine);
01133 
01134                 // Update refineCell. Note that some of the marked ones have
01135                 // not been refined due to constraints.
01136                 {
01137                     const labelList& cellMap = map().cellMap();
01138                     const labelList& reverseCellMap = map().reverseCellMap();
01139 
01140                     PackedBoolList newRefineCell(cellMap.size());
01141 
01142                     forAll(cellMap, cellI)
01143                     {
01144                         label oldCellI = cellMap[cellI];
01145 
01146                         if (oldCellI < 0)
01147                         {
01148                             newRefineCell.set(cellI, 1);
01149                         }
01150                         else if (reverseCellMap[oldCellI] != cellI)
01151                         {
01152                             newRefineCell.set(cellI, 1);
01153                         }
01154                         else
01155                         {
01156                             newRefineCell.set(cellI, refineCell.get(oldCellI));
01157                         }
01158                     }
01159                     refineCell.transfer(newRefineCell);
01160                 }
01161 
01162                 // Extend with a buffer layer to prevent neighbouring points
01163                 // being unrefined.
01164                 for (label i = 0; i < nBufferLayers; i++)
01165                 {
01166                     extendMarkedCells(refineCell);
01167                 }
01168 
01169                 hasChanged = true;
01170             }
01171         }
01172 
01173 
01174         {
01175             // Select unrefineable points that are not marked in refineCell
01176             labelList pointsToUnrefine
01177             (
01178                 selectUnrefinePoints
01179                 (
01180                     unrefineLevel,
01181                     refineCell,
01182                     minCellField(vFld)
01183                 )
01184             );
01185 
01186             label nSplitPoints = returnReduce
01187             (
01188                 pointsToUnrefine.size(),
01189                 sumOp<label>()
01190             );
01191 
01192             if (nSplitPoints > 0)
01193             {
01194                 // Refine/update mesh
01195                 unrefine(pointsToUnrefine);
01196 
01197                 hasChanged = true;
01198             }
01199         }
01200 
01201 
01202         if ((nRefinementIterations_ % 10) == 0)
01203         {
01204             // Compact refinement history occassionally (how often?).
01205             // Unrefinement causes holes in the refinementHistory.
01206             const_cast<refinementHistory&>(meshCutter().history()).compact();
01207         }
01208         nRefinementIterations_++;
01209     }
01210 
01211     changing(hasChanged);
01212 
01213     return hasChanged;
01214 }
01215 
01216 
01217 bool dynamicRefineFvMesh::writeObject
01218 (
01219     IOstream::streamFormat fmt,
01220     IOstream::versionNumber ver,
01221     IOstream::compressionType cmp
01222 ) const
01223 {
01224     // Force refinement data to go to the current time directory.
01225     const_cast<hexRef8&>(meshCutter_).setInstance(time().timeName());
01226 
01227     bool writeOk =
01228         dynamicFvMesh::writeObjects(fmt, ver, cmp)
01229      && meshCutter_.write();
01230 
01231     if (dumpLevel_)
01232     {
01233         volScalarField scalarCellLevel
01234         (
01235             IOobject
01236             (
01237                 "cellLevel",
01238                 time().timeName(),
01239                 *this,
01240                 IOobject::NO_READ,
01241                 IOobject::AUTO_WRITE,
01242                 false
01243             ),
01244             *this,
01245             dimensionedScalar("level", dimless, 0)
01246         );
01247 
01248         const labelList& cellLevel = meshCutter_.cellLevel();
01249 
01250         forAll(cellLevel, cellI)
01251         {
01252             scalarCellLevel[cellI] = cellLevel[cellI];
01253         }
01254 
01255         writeOk = writeOk && scalarCellLevel.write();
01256     }
01257 
01258     return writeOk;
01259 }
01260 
01261 
01262 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
01263 
01264 } // End namespace Foam
01265 
01266 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines