1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "dynamicRefineFvMesh.H"
27 #include "addToRunTimeSelectionTable.H"
28 #include "surfaceInterpolate.H"
29 #include "volFields.H"
30 #include "polyTopoChange.H"
31 #include "surfaceFields.H"
32 #include "syncTools.H"
33 #include "pointFields.H"
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(dynamicRefineFvMesh, 0);
40 addToRunTimeSelectionTable(dynamicFvMesh, dynamicRefineFvMesh, IOobject);
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 // the PackedBoolList::count method would probably be faster
46 // since we are only checking for 'true' anyhow
47 Foam::label Foam::dynamicRefineFvMesh::count
49 const PackedBoolList& l,
50 const unsigned int val
65 void Foam::dynamicRefineFvMesh::calculateProtectedCells
67 PackedBoolList& unrefineableCell
70 if (protectedCell_.empty())
72 unrefineableCell.clear();
76 const labelList& cellLevel = meshCutter_.cellLevel();
78 unrefineableCell = protectedCell_;
80 // Get neighbouring cell level
81 labelList neiLevel(nFaces()-nInternalFaces());
83 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
85 neiLevel[faceI-nInternalFaces()] = cellLevel[faceOwner()[faceI]];
87 syncTools::swapBoundaryFaceList(*this, neiLevel);
92 // Pick up faces on border of protected cells
93 boolList seedFace(nFaces(), false);
95 forAll(faceNeighbour(), faceI)
97 label own = faceOwner()[faceI];
98 bool ownProtected = unrefineableCell.get(own);
99 label nei = faceNeighbour()[faceI];
100 bool neiProtected = unrefineableCell.get(nei);
102 if (ownProtected && (cellLevel[nei] > cellLevel[own]))
104 seedFace[faceI] = true;
106 else if (neiProtected && (cellLevel[own] > cellLevel[nei]))
108 seedFace[faceI] = true;
111 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
113 label own = faceOwner()[faceI];
114 bool ownProtected = unrefineableCell.get(own);
118 && (neiLevel[faceI-nInternalFaces()] > cellLevel[own])
121 seedFace[faceI] = true;
125 syncTools::syncFaceList(*this, seedFace, orEqOp<bool>());
128 // Extend unrefineableCell
129 bool hasExtended = false;
131 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
135 label own = faceOwner()[faceI];
136 if (unrefineableCell.get(own) == 0)
138 unrefineableCell.set(own, 1);
142 label nei = faceNeighbour()[faceI];
143 if (unrefineableCell.get(nei) == 0)
145 unrefineableCell.set(nei, 1);
150 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
154 label own = faceOwner()[faceI];
155 if (unrefineableCell.get(own) == 0)
157 unrefineableCell.set(own, 1);
163 if (!returnReduce(hasExtended, orOp<bool>()))
171 void Foam::dynamicRefineFvMesh::readDict()
173 dictionary refineDict
182 IOobject::MUST_READ_IF_MODIFIED,
186 ).subDict(typeName + "Coeffs")
189 List<Pair<word> > fluxVelocities = List<Pair<word> >
191 refineDict.lookup("correctFluxes")
193 // Rework into hashtable.
194 correctFluxes_.resize(fluxVelocities.size());
195 forAll(fluxVelocities, i)
197 correctFluxes_.insert(fluxVelocities[i][0], fluxVelocities[i][1]);
200 dumpLevel_ = Switch(refineDict.lookup("dumpLevel"));
204 // Refines cells, maps fields and recalculates (an approximate) flux
205 Foam::autoPtr<Foam::mapPolyMesh>
206 Foam::dynamicRefineFvMesh::refine
208 const labelList& cellsToRefine
211 // Mesh changing engine.
212 polyTopoChange meshMod(*this);
214 // Play refinement commands into mesh changer.
215 meshCutter_.setRefinement(cellsToRefine, meshMod);
217 // Create mesh (with inflation), return map from old to new mesh.
218 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
219 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
221 Info<< "Refined from "
222 << returnReduce(map().nOldCells(), sumOp<label>())
223 << " to " << globalData().nTotalCells() << " cells." << endl;
228 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
230 label oldFaceI = map().faceMap()[faceI];
232 if (oldFaceI >= nInternalFaces())
234 FatalErrorIn("dynamicRefineFvMesh::refine(const labelList&)")
235 << "New internal face:" << faceI
236 << " fc:" << faceCentres()[faceI]
237 << " originates from boundary oldFace:" << oldFaceI
238 << abort(FatalError);
247 pointField newPoints;
248 if (map().hasMotionPoints())
250 newPoints = map().preMotionPoints();
254 newPoints = points();
256 movePoints(newPoints);
259 // Correct the flux for modified/added faces. All the faces which only
260 // have been renumbered will already have been handled by the mapping.
262 const labelList& faceMap = map().faceMap();
263 const labelList& reverseFaceMap = map().reverseFaceMap();
265 // Storage for any master faces. These will be the original faces
266 // on the coarse cell that get split into four (or rather the
267 // master face gets modified and three faces get added from the master)
268 labelHashSet masterFaces(4*cellsToRefine.size());
270 forAll(faceMap, faceI)
272 label oldFaceI = faceMap[faceI];
276 label masterFaceI = reverseFaceMap[oldFaceI];
282 "dynamicRefineFvMesh::refine(const labelList&)"
283 ) << "Problem: should not have removed faces"
285 << nl << "face:" << faceI << abort(FatalError);
287 else if (masterFaceI != faceI)
289 masterFaces.insert(masterFaceI);
295 Info<< "Found " << returnReduce(masterFaces.size(), sumOp<label>())
296 << " split faces " << endl;
299 HashTable<const surfaceScalarField*> fluxes
301 lookupClass<surfaceScalarField>()
303 forAllConstIter(HashTable<const surfaceScalarField*>, fluxes, iter)
305 if (!correctFluxes_.found(iter.key()))
307 WarningIn("dynamicRefineFvMesh::refine(const labelList&)")
308 << "Cannot find surfaceScalarField " << iter.key()
309 << " in user-provided flux mapping table "
310 << correctFluxes_ << endl
311 << " The flux mapping table is used to recreate the"
312 << " flux on newly created faces." << endl
313 << " Either add the entry if it is a flux or use ("
314 << iter.key() << " none) to suppress this warning."
319 const word& UName = correctFluxes_[iter.key()];
328 Info<< "Mapping flux " << iter.key()
329 << " using interpolated flux " << UName
333 surfaceScalarField& phi = const_cast<surfaceScalarField&>(*iter());
335 const surfaceScalarField phiU
339 lookupObject<volVectorField>(UName)
344 // Recalculate new internal faces.
345 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
347 label oldFaceI = faceMap[faceI];
352 phi[faceI] = phiU[faceI];
354 else if (reverseFaceMap[oldFaceI] != faceI)
356 // face-from-masterface
357 phi[faceI] = phiU[faceI];
361 // Recalculate new boundary faces.
362 forAll(phi.boundaryField(), patchI)
364 fvsPatchScalarField& patchPhi = phi.boundaryField()[patchI];
365 const fvsPatchScalarField& patchPhiU =
366 phiU.boundaryField()[patchI];
368 label faceI = patchPhi.patch().start();
372 label oldFaceI = faceMap[faceI];
377 patchPhi[i] = patchPhiU[i];
379 else if (reverseFaceMap[oldFaceI] != faceI)
381 // face-from-masterface
382 patchPhi[i] = patchPhiU[i];
389 // Update master faces
390 forAllConstIter(labelHashSet, masterFaces, iter)
392 label faceI = iter.key();
394 if (isInternalFace(faceI))
396 phi[faceI] = phiU[faceI];
400 label patchI = boundaryMesh().whichPatch(faceI);
401 label i = faceI - boundaryMesh()[patchI].start();
403 const fvsPatchScalarField& patchPhiU =
404 phiU.boundaryField()[patchI];
406 fvsPatchScalarField& patchPhi =
407 phi.boundaryField()[patchI];
409 if (patchPhi.size() > 0)
411 patchPhi[i] = patchPhiU[i];
418 // Update numbering of cells/vertices.
419 meshCutter_.updateMesh(map);
421 // Update numbering of protectedCell_
422 if (protectedCell_.size())
424 PackedBoolList newProtectedCell(nCells());
426 forAll(newProtectedCell, cellI)
428 label oldCellI = map().cellMap()[cellI];
429 newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
431 protectedCell_.transfer(newProtectedCell);
434 // Debug: Check refinement levels (across faces only)
435 meshCutter_.checkRefinementLevels(-1, labelList(0));
441 // Combines previously split cells, maps fields and recalculates
442 // (an approximate) flux
443 Foam::autoPtr<Foam::mapPolyMesh>
444 Foam::dynamicRefineFvMesh::unrefine
446 const labelList& splitPoints
449 polyTopoChange meshMod(*this);
451 // Play refinement commands into mesh changer.
452 meshCutter_.setUnrefinement(splitPoints, meshMod);
455 // Save information on faces that will be combined
456 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
458 // Find the faceMidPoints on cells to be combined.
459 // for each face resulting of split of face into four store the
461 Map<label> faceToSplitPoint(3*splitPoints.size());
464 forAll(splitPoints, i)
466 label pointI = splitPoints[i];
468 const labelList& pEdges = pointEdges()[pointI];
472 label otherPointI = edges()[pEdges[j]].otherVertex(pointI);
474 const labelList& pFaces = pointFaces()[otherPointI];
476 forAll(pFaces, pFaceI)
478 faceToSplitPoint.insert(pFaces[pFaceI], otherPointI);
485 // Change mesh and generate map.
486 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
487 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
489 Info<< "Unrefined from "
490 << returnReduce(map().nOldCells(), sumOp<label>())
491 << " to " << globalData().nTotalCells() << " cells."
500 pointField newPoints;
501 if (map().hasMotionPoints())
503 newPoints = map().preMotionPoints();
507 newPoints = points();
509 movePoints(newPoints);
512 // Correct the flux for modified faces.
514 const labelList& reversePointMap = map().reversePointMap();
515 const labelList& reverseFaceMap = map().reverseFaceMap();
517 HashTable<const surfaceScalarField*> fluxes
519 lookupClass<surfaceScalarField>()
521 forAllConstIter(HashTable<const surfaceScalarField*>, fluxes, iter)
523 if (!correctFluxes_.found(iter.key()))
525 WarningIn("dynamicRefineFvMesh::refine(const labelList&)")
526 << "Cannot find surfaceScalarField " << iter.key()
527 << " in user-provided flux mapping table "
528 << correctFluxes_ << endl
529 << " The flux mapping table is used to recreate the"
530 << " flux on newly created faces." << endl
531 << " Either add the entry if it is a flux or use ("
532 << iter.key() << " none) to suppress this warning."
537 const word& UName = correctFluxes_[iter.key()];
546 Info<< "Mapping flux " << iter.key()
547 << " using interpolated flux " << UName
551 surfaceScalarField& phi = const_cast<surfaceScalarField&>(*iter());
552 const surfaceScalarField phiU
556 lookupObject<volVectorField>(UName)
562 forAllConstIter(Map<label>, faceToSplitPoint, iter)
564 label oldFaceI = iter.key();
565 label oldPointI = iter();
567 if (reversePointMap[oldPointI] < 0)
569 // midpoint was removed. See if face still exists.
570 label faceI = reverseFaceMap[oldFaceI];
574 if (isInternalFace(faceI))
576 phi[faceI] = phiU[faceI];
580 label patchI = boundaryMesh().whichPatch(faceI);
581 label i = faceI - boundaryMesh()[patchI].start();
583 const fvsPatchScalarField& patchPhiU =
584 phiU.boundaryField()[patchI];
586 fvsPatchScalarField& patchPhi =
587 phi.boundaryField()[patchI];
589 patchPhi[i] = patchPhiU[i];
598 // Update numbering of cells/vertices.
599 meshCutter_.updateMesh(map);
601 // Update numbering of protectedCell_
602 if (protectedCell_.size())
604 PackedBoolList newProtectedCell(nCells());
606 forAll(newProtectedCell, cellI)
608 label oldCellI = map().cellMap()[cellI];
611 newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
614 protectedCell_.transfer(newProtectedCell);
617 // Debug: Check refinement levels (across faces only)
618 meshCutter_.checkRefinementLevels(-1, labelList(0));
624 // Get max of connected point
626 Foam::dynamicRefineFvMesh::maxPointField(const scalarField& pFld) const
628 scalarField vFld(nCells(), -GREAT);
630 forAll(pointCells(), pointI)
632 const labelList& pCells = pointCells()[pointI];
636 vFld[pCells[i]] = max(vFld[pCells[i]], pFld[pointI]);
643 // Get min of connected cell
645 Foam::dynamicRefineFvMesh::minCellField(const volScalarField& vFld) const
647 scalarField pFld(nPoints(), GREAT);
649 forAll(pointCells(), pointI)
651 const labelList& pCells = pointCells()[pointI];
655 pFld[pointI] = min(pFld[pointI], vFld[pCells[i]]);
662 // Simple (non-parallel) interpolation by averaging.
664 Foam::dynamicRefineFvMesh::cellToPoint(const scalarField& vFld) const
666 scalarField pFld(nPoints());
668 forAll(pointCells(), pointI)
670 const labelList& pCells = pointCells()[pointI];
675 sum += vFld[pCells[i]];
677 pFld[pointI] = sum/pCells.size();
683 // Calculate error. Is < 0 or distance to minLevel, maxLevel
684 Foam::scalarField Foam::dynamicRefineFvMesh::error
686 const scalarField& fld,
687 const scalar minLevel,
688 const scalar maxLevel
691 scalarField c(fld.size(), -1);
695 scalar err = min(fld[i]-minLevel, maxLevel-fld[i]);
706 void Foam::dynamicRefineFvMesh::selectRefineCandidates
708 const scalar lowerRefineLevel,
709 const scalar upperRefineLevel,
710 const scalarField& vFld,
711 PackedBoolList& candidateCell
714 // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
715 // higher more desirable to be refined).
716 scalarField cellError
729 // Mark cells that are candidates for refinement.
730 forAll(cellError, cellI)
732 if (cellError[cellI] > 0)
734 candidateCell.set(cellI, 1);
740 Foam::labelList Foam::dynamicRefineFvMesh::selectRefineCells
742 const label maxCells,
743 const label maxRefinement,
744 const PackedBoolList& candidateCell
747 // Every refined cell causes 7 extra cells
748 label nTotToRefine = (maxCells - globalData().nTotalCells()) / 7;
750 const labelList& cellLevel = meshCutter_.cellLevel();
752 // Mark cells that cannot be refined since they would trigger refinement
753 // of protected cells (since 2:1 cascade)
754 PackedBoolList unrefineableCell;
755 calculateProtectedCells(unrefineableCell);
757 // Count current selection
758 label nCandidates = returnReduce(count(candidateCell, 1), sumOp<label>());
761 DynamicList<label> candidates(nCells());
763 if (nCandidates < nTotToRefine)
765 forAll(candidateCell, cellI)
769 cellLevel[cellI] < maxRefinement
770 && candidateCell.get(cellI)
772 unrefineableCell.empty()
773 || !unrefineableCell.get(cellI)
777 candidates.append(cellI);
783 // Sort by error? For now just truncate.
784 for (label level = 0; level < maxRefinement; level++)
786 forAll(candidateCell, cellI)
790 cellLevel[cellI] == level
791 && candidateCell.get(cellI)
793 unrefineableCell.empty()
794 || !unrefineableCell.get(cellI)
798 candidates.append(cellI);
802 if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
809 // Guarantee 2:1 refinement after refinement
810 labelList consistentSet
812 meshCutter_.consistentRefinement
815 true // Add to set to guarantee 2:1
819 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
820 << " cells for refinement out of " << globalData().nTotalCells()
823 return consistentSet;
827 Foam::labelList Foam::dynamicRefineFvMesh::selectUnrefinePoints
829 const scalar unrefineLevel,
830 const PackedBoolList& markedCell,
831 const scalarField& pFld
834 // All points that can be unrefined
835 const labelList splitPoints(meshCutter_.getSplitPoints());
837 DynamicList<label> newSplitPoints(splitPoints.size());
839 forAll(splitPoints, i)
841 label pointI = splitPoints[i];
843 if (pFld[pointI] < unrefineLevel)
845 // Check that all cells are not marked
846 const labelList& pCells = pointCells()[pointI];
848 bool hasMarked = false;
850 forAll(pCells, pCellI)
852 if (markedCell.get(pCells[pCellI]))
861 newSplitPoints.append(pointI);
867 newSplitPoints.shrink();
869 // Guarantee 2:1 refinement after unrefinement
870 labelList consistentSet
872 meshCutter_.consistentUnrefinement
878 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
879 << " split points out of a possible "
880 << returnReduce(splitPoints.size(), sumOp<label>())
883 return consistentSet;
887 void Foam::dynamicRefineFvMesh::extendMarkedCells
889 PackedBoolList& markedCell
892 // Mark faces using any marked cell
893 boolList markedFace(nFaces(), false);
895 forAll(markedCell, cellI)
897 if (markedCell.get(cellI))
899 const cell& cFaces = cells()[cellI];
903 markedFace[cFaces[i]] = true;
908 syncTools::syncFaceList(*this, markedFace, orEqOp<bool>());
910 // Update cells using any markedFace
911 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
913 if (markedFace[faceI])
915 markedCell.set(faceOwner()[faceI], 1);
916 markedCell.set(faceNeighbour()[faceI], 1);
919 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
921 if (markedFace[faceI])
923 markedCell.set(faceOwner()[faceI], 1);
929 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
931 Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io)
936 nRefinementIterations_(0),
937 protectedCell_(nCells(), 0)
939 // Read static part of dictionary
943 const labelList& cellLevel = meshCutter_.cellLevel();
944 const labelList& pointLevel = meshCutter_.pointLevel();
946 // Set cells that should not be refined.
947 // This is currently any cell which does not have 8 anchor points or
948 // uses any face which does not have 4 anchor points.
949 // Note: do not use cellPoint addressing
951 // Count number of points <= cellLevel
952 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
954 labelList nAnchors(nCells(), 0);
956 label nProtected = 0;
958 forAll(pointCells(), pointI)
960 const labelList& pCells = pointCells()[pointI];
964 label cellI = pCells[i];
966 if (!protectedCell_.get(cellI))
968 if (pointLevel[pointI] <= cellLevel[cellI])
972 if (nAnchors[cellI] > 8)
974 protectedCell_.set(cellI, 1);
983 // Count number of points <= faceLevel
984 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
985 // Bit tricky since proc face might be one more refined than the owner since
986 // the coupled one is refined.
989 labelList neiLevel(nFaces());
991 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
993 neiLevel[faceI] = cellLevel[faceNeighbour()[faceI]];
995 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
997 neiLevel[faceI] = cellLevel[faceOwner()[faceI]];
999 syncTools::swapFaceList(*this, neiLevel);
1002 boolList protectedFace(nFaces(), false);
1004 forAll(faceOwner(), faceI)
1006 label faceLevel = max
1008 cellLevel[faceOwner()[faceI]],
1012 const face& f = faces()[faceI];
1018 if (pointLevel[f[fp]] <= faceLevel)
1024 protectedFace[faceI] = true;
1031 syncTools::syncFaceList(*this, protectedFace, orEqOp<bool>());
1033 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
1035 if (protectedFace[faceI])
1037 protectedCell_.set(faceOwner()[faceI], 1);
1039 protectedCell_.set(faceNeighbour()[faceI], 1);
1043 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
1045 if (protectedFace[faceI])
1047 protectedCell_.set(faceOwner()[faceI], 1);
1053 if (returnReduce(nProtected, sumOp<label>()) == 0)
1055 protectedCell_.clear();
1060 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1062 Foam::dynamicRefineFvMesh::~dynamicRefineFvMesh()
1066 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1068 bool Foam::dynamicRefineFvMesh::update()
1070 // Re-read dictionary. Choosen since usually -small so trivial amount
1071 // of time compared to actual refinement. Also very useful to be able
1072 // to modify on-the-fly.
1073 dictionary refineDict
1082 IOobject::MUST_READ_IF_MODIFIED,
1086 ).subDict(typeName + "Coeffs")
1089 label refineInterval = readLabel(refineDict.lookup("refineInterval"));
1091 bool hasChanged = false;
1093 if (refineInterval == 0)
1095 changing(hasChanged);
1099 else if (refineInterval < 0)
1101 FatalErrorIn("dynamicRefineFvMesh::update()")
1102 << "Illegal refineInterval " << refineInterval << nl
1103 << "The refineInterval setting in the dynamicMeshDict should"
1104 << " be >= 1." << nl
1105 << exit(FatalError);
1111 // Note: cannot refine at time 0 since no V0 present since mesh not
1114 if (time().timeIndex() > 0 && time().timeIndex() % refineInterval == 0)
1116 label maxCells = readLabel(refineDict.lookup("maxCells"));
1120 FatalErrorIn("dynamicRefineFvMesh::update()")
1121 << "Illegal maximum number of cells " << maxCells << nl
1122 << "The maxCells setting in the dynamicMeshDict should"
1124 << exit(FatalError);
1127 label maxRefinement = readLabel(refineDict.lookup("maxRefinement"));
1129 if (maxRefinement <= 0)
1131 FatalErrorIn("dynamicRefineFvMesh::update()")
1132 << "Illegal maximum refinement level " << maxRefinement << nl
1133 << "The maxCells setting in the dynamicMeshDict should"
1135 << exit(FatalError);
1138 const word fieldName(refineDict.lookup("field"));
1140 const volScalarField& vFld = lookupObject<volScalarField>(fieldName);
1142 const scalar lowerRefineLevel =
1143 readScalar(refineDict.lookup("lowerRefineLevel"));
1144 const scalar upperRefineLevel =
1145 readScalar(refineDict.lookup("upperRefineLevel"));
1146 const scalar unrefineLevel =
1147 readScalar(refineDict.lookup("unrefineLevel"));
1148 const label nBufferLayers =
1149 readLabel(refineDict.lookup("nBufferLayers"));
1151 // Cells marked for refinement or otherwise protected from unrefinement.
1152 PackedBoolList refineCell(nCells());
1154 if (globalData().nTotalCells() < maxCells)
1156 // Determine candidates for refinement (looking at field only)
1157 selectRefineCandidates
1165 // Select subset of candidates. Take into account max allowable
1166 // cells, refinement level, protected cells.
1167 labelList cellsToRefine
1177 label nCellsToRefine = returnReduce
1179 cellsToRefine.size(), sumOp<label>()
1182 if (nCellsToRefine > 0)
1184 // Refine/update mesh and map fields
1185 autoPtr<mapPolyMesh> map = refine(cellsToRefine);
1187 // Update refineCell. Note that some of the marked ones have
1188 // not been refined due to constraints.
1190 const labelList& cellMap = map().cellMap();
1191 const labelList& reverseCellMap = map().reverseCellMap();
1193 PackedBoolList newRefineCell(cellMap.size());
1195 forAll(cellMap, cellI)
1197 label oldCellI = cellMap[cellI];
1201 newRefineCell.set(cellI, 1);
1203 else if (reverseCellMap[oldCellI] != cellI)
1205 newRefineCell.set(cellI, 1);
1209 newRefineCell.set(cellI, refineCell.get(oldCellI));
1212 refineCell.transfer(newRefineCell);
1215 // Extend with a buffer layer to prevent neighbouring points
1217 for (label i = 0; i < nBufferLayers; i++)
1219 extendMarkedCells(refineCell);
1228 // Select unrefineable points that are not marked in refineCell
1229 labelList pointsToUnrefine
1231 selectUnrefinePoints
1239 label nSplitPoints = returnReduce
1241 pointsToUnrefine.size(),
1245 if (nSplitPoints > 0)
1247 // Refine/update mesh
1248 unrefine(pointsToUnrefine);
1255 if ((nRefinementIterations_ % 10) == 0)
1257 // Compact refinement history occassionally (how often?).
1258 // Unrefinement causes holes in the refinementHistory.
1259 const_cast<refinementHistory&>(meshCutter().history()).compact();
1261 nRefinementIterations_++;
1264 changing(hasChanged);
1270 bool Foam::dynamicRefineFvMesh::writeObject
1272 IOstream::streamFormat fmt,
1273 IOstream::versionNumber ver,
1274 IOstream::compressionType cmp
1277 // Force refinement data to go to the current time directory.
1278 const_cast<hexRef8&>(meshCutter_).setInstance(time().timeName());
1282 dynamicFvMesh::writeObjects(fmt, ver, cmp)
1283 && meshCutter_.write()
1288 volScalarField scalarCellLevel
1296 IOobject::AUTO_WRITE,
1300 dimensionedScalar("level", dimless, 0)
1303 const labelList& cellLevel = meshCutter_.cellLevel();
1305 forAll(cellLevel, cellI)
1307 scalarCellLevel[cellI] = cellLevel[cellI];
1310 writeOk = writeOk && scalarCellLevel.write();
1317 // ************************************************************************* //