1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "SortableList.H"
28 #include "addToRunTimeSelectionTable.H"
29 #include "volFields.H"
30 #include "polyTopoChange.H"
31 #include "surfaceFields.H"
33 #include "syncTools.H"
34 #include "ListListOps.H"
35 #include "pointFields.H"
36 #include "directTopoChange.H"
38 #include "pistonRefine.H"
39 #include "engineTime.H"
40 #include "layerAdditionRemoval.H"
41 #include "mapPolyMesh.H"
42 #include "GeometricField.H"
44 #include "fvPatchField.H"
45 #include "volPointInterpolation.H"
46 #include "fvcMeshPhi.H"
47 #include "fvcVolumeIntegrate.H"
48 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
52 defineTypeNameAndDebug(pistonRefine, 0);
53 addToRunTimeSelectionTable(engineTopoChangerMesh, pistonRefine, IOobject);
56 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
58 label pistonRefine::count(const PackedList<1>& l, const unsigned int val)
72 void pistonRefine::calculateProtectedCells
74 PackedList<1>& unrefineableCell
77 if (protectedCell_.size() == 0)
79 unrefineableCell.clear();
83 const labelList& cellLevel = meshCutter_.cellLevel();
85 unrefineableCell = protectedCell_;
87 // Get neighbouring cell level
88 labelList neiLevel(nFaces()-nInternalFaces());
90 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
92 neiLevel[faceI-nInternalFaces()] = cellLevel[faceOwner()[faceI]];
94 syncTools::swapBoundaryFaceList(*this, neiLevel, false);
99 // Pick up faces on border of protected cells
100 boolList seedFace(nFaces(), false);
102 forAll(faceNeighbour(), faceI)
104 label own = faceOwner()[faceI];
105 bool ownProtected = (unrefineableCell.get(own) == 1);
106 label nei = faceNeighbour()[faceI];
107 bool neiProtected = (unrefineableCell.get(nei) == 1);
109 if (ownProtected && (cellLevel[nei] > cellLevel[own]))
111 seedFace[faceI] = true;
113 else if (neiProtected && (cellLevel[own] > cellLevel[nei]))
115 seedFace[faceI] = true;
118 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
120 label own = faceOwner()[faceI];
121 bool ownProtected = (unrefineableCell.get(own) == 1);
125 && (neiLevel[faceI-nInternalFaces()] > cellLevel[own])
128 seedFace[faceI] = true;
132 syncTools::syncFaceList(*this, seedFace, orEqOp<bool>(), false);
135 // Extend unrefineableCell
136 bool hasExtended = false;
138 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
142 label own = faceOwner()[faceI];
143 if (unrefineableCell.get(own) == 0)
145 unrefineableCell.set(own, 1);
149 label nei = faceNeighbour()[faceI];
150 if (unrefineableCell.get(nei) == 0)
152 unrefineableCell.set(nei, 1);
157 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
161 label own = faceOwner()[faceI];
162 if (unrefineableCell.get(own) == 0)
164 unrefineableCell.set(own, 1);
170 if (!returnReduce(hasExtended, orOp<bool>()))
178 void pistonRefine::readDict()
180 dictionary refineDict
193 ).subDict(typeName + "Coeffs")
196 correctFluxes_ = List<Pair<word> >(refineDict.lookup("correctFluxes"));
198 dumpLevel_ = Switch(refineDict.lookup("dumpLevel"));
202 // Refines cells, maps fields and recalculates (an approximate) flux
203 autoPtr<mapPolyMesh> pistonRefine::refine
205 const labelList& cellsToRefine
208 // Mesh changing engine.
209 directTopoChange meshMod(*this);
211 // Play refinement commands into mesh changer.
212 meshCutter_.setRefinement(cellsToRefine, meshMod);
214 // Create mesh (with inflation), return map from old to new mesh.
215 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
216 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
218 Info<< "Refined from "
219 << returnReduce(map().nOldCells(), sumOp<label>())
220 << " to " << globalData().nTotalCells() << " cells." << endl;
225 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
227 label oldFaceI = map().faceMap()[faceI];
229 if (oldFaceI >= nInternalFaces())
231 FatalErrorIn("pistonRefine::refine")
232 << "New internal face:" << faceI
233 << " fc:" << faceCentres()[faceI]
234 << " originates from boundary oldFace:" << oldFaceI
235 << abort(FatalError);
245 pointField newPoints;
246 if (map().hasMotionPoints())
248 newPoints = map().preMotionPoints();
252 newPoints = points();
254 movePoints(newPoints);
258 // Correct the flux for modified/added faces. All the faces which only
259 // have been renumbered will already have been handled by the mapping.
261 const labelList& faceMap = map().faceMap();
262 const labelList& reverseFaceMap = map().reverseFaceMap();
264 // Storage for any master faces. These will be the original faces
265 // on the coarse cell that get split into four (or rather the
266 // master face gets modified and three faces get added from the master)
267 labelHashSet masterFaces(4*cellsToRefine.size());
269 forAll(faceMap, faceI)
271 label oldFaceI = faceMap[faceI];
275 label masterFaceI = reverseFaceMap[oldFaceI];
281 "pistonRefine::refine(const labelList&)"
282 ) << "Problem: should not have removed faces"
284 << nl << "face:" << faceI << abort(FatalError);
286 else if (masterFaceI != faceI)
288 masterFaces.insert(masterFaceI);
294 Info<< "Found " << returnReduce(masterFaces.size(), sumOp<label>())
295 << " split faces " << endl;
298 forAll(correctFluxes_, i)
302 Info<< "Mapping flux " << correctFluxes_[i][0]
303 << " using interpolated flux " << correctFluxes_[i][1]
306 surfaceScalarField& phi = const_cast<surfaceScalarField&>
308 lookupObject<surfaceScalarField>(correctFluxes_[i][0])
310 surfaceScalarField phiU =
313 lookupObject<volVectorField>(correctFluxes_[i][1])
317 // Recalculate new internal faces.
318 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
320 label oldFaceI = faceMap[faceI];
325 phi[faceI] = phiU[faceI];
327 else if (reverseFaceMap[oldFaceI] != faceI)
329 // face-from-masterface
330 phi[faceI] = phiU[faceI];
334 // Recalculate new boundary faces.
335 forAll(phi.boundaryField(), patchI)
337 fvsPatchScalarField& patchPhi = phi.boundaryField()[patchI];
338 const fvsPatchScalarField& patchPhiU =
339 phiU.boundaryField()[patchI];
341 label faceI = patchPhi.patch().patch().start();
345 label oldFaceI = faceMap[faceI];
350 patchPhi[i] = patchPhiU[i];
352 else if (reverseFaceMap[oldFaceI] != faceI)
354 // face-from-masterface
355 patchPhi[i] = patchPhiU[i];
362 // Update master faces
363 forAllConstIter(labelHashSet, masterFaces, iter)
365 label faceI = iter.key();
367 if (isInternalFace(faceI))
369 phi[faceI] = phiU[faceI];
373 label patchI = boundaryMesh().whichPatch(faceI);
374 label i = faceI - boundaryMesh()[patchI].start();
376 const fvsPatchScalarField& patchPhiU =
377 phiU.boundaryField()[patchI];
379 fvsPatchScalarField& patchPhi =
380 phi.boundaryField()[patchI];
382 patchPhi[i] = patchPhiU[i];
390 // Update numbering of cells/vertices.
391 meshCutter_.updateMesh(map);
393 // Update numbering of protectedCell_
394 if (protectedCell_.size() > 0)
396 PackedList<1> newProtectedCell(nCells(), 0);
398 forAll(newProtectedCell, cellI)
400 label oldCellI = map().cellMap()[cellI];
401 newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
403 protectedCell_.transfer(newProtectedCell);
406 // Debug: Check refinement levels (across faces only)
407 meshCutter_.checkRefinementLevels(-1, labelList(0));
413 // Combines previously split cells, maps fields and recalculates
414 // (an approximate) flux
415 autoPtr<mapPolyMesh> pistonRefine::unrefine
417 const labelList& splitPoints
420 directTopoChange meshMod(*this);
422 // Play refinement commands into mesh changer.
423 meshCutter_.setUnrefinement(splitPoints, meshMod);
426 // Save information on faces that will be combined
427 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
429 // Find the faceMidPoints on cells to be combined.
430 // for each face resulting of split of face into four store the
432 Map<label> faceToSplitPoint(3*splitPoints.size());
435 forAll(splitPoints, i)
437 label pointI = splitPoints[i];
439 const labelList& pEdges = pointEdges()[pointI];
443 label otherPointI = edges()[pEdges[j]].otherVertex(pointI);
445 const labelList& pFaces = pointFaces()[otherPointI];
447 forAll(pFaces, pFaceI)
449 faceToSplitPoint.insert(pFaces[pFaceI], otherPointI);
456 // Change mesh and generate mesh.
457 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
458 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
460 Info<< "Unrefined from "
461 << returnReduce(map().nOldCells(), sumOp<label>())
462 << " to " << globalData().nTotalCells() << " cells."
471 pointField newPoints;
472 if (map().hasMotionPoints())
474 newPoints = map().preMotionPoints();
478 newPoints = points();
480 movePoints(newPoints);
483 // Correct the flux for modified faces.
485 const labelList& reversePointMap = map().reversePointMap();
486 const labelList& reverseFaceMap = map().reverseFaceMap();
488 forAll(correctFluxes_, i)
492 Info<< "Mapping flux " << correctFluxes_[i][0]
493 << " using interpolated flux " << correctFluxes_[i][1]
496 surfaceScalarField& phi = const_cast<surfaceScalarField&>
498 lookupObject<surfaceScalarField>(correctFluxes_[i][0])
500 surfaceScalarField phiU =
503 lookupObject<volVectorField>(correctFluxes_[i][1])
507 forAllConstIter(Map<label>, faceToSplitPoint, iter)
509 label oldFaceI = iter.key();
510 label oldPointI = iter();
512 if (reversePointMap[oldPointI] < 0)
514 // midpoint was removed. See if face still exists.
515 label faceI = reverseFaceMap[oldFaceI];
519 if (isInternalFace(faceI))
521 phi[faceI] = phiU[faceI];
525 label patchI = boundaryMesh().whichPatch(faceI);
526 label i = faceI - boundaryMesh()[patchI].start();
528 const fvsPatchScalarField& patchPhiU =
529 phiU.boundaryField()[patchI];
531 fvsPatchScalarField& patchPhi =
532 phi.boundaryField()[patchI];
534 patchPhi[i] = patchPhiU[i];
543 // Update numbering of cells/vertices.
544 meshCutter_.updateMesh(map);
546 // Update numbering of protectedCell_
547 if (protectedCell_.size() > 0)
549 PackedList<1> newProtectedCell(nCells(), 0);
551 forAll(newProtectedCell, cellI)
553 label oldCellI = map().cellMap()[cellI];
556 newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
559 protectedCell_.transfer(newProtectedCell);
562 // Debug: Check refinement levels (across faces only)
563 meshCutter_.checkRefinementLevels(-1, labelList(0));
569 // Get max of connected point
570 scalarField pistonRefine::maxPointField(const scalarField& pFld) const
572 scalarField vFld(nCells(), -GREAT);
574 forAll(pointCells(), pointI)
576 const labelList& pCells = pointCells()[pointI];
580 vFld[pCells[i]] = max(vFld[pCells[i]], pFld[pointI]);
587 // Get min of connected cell
588 scalarField pistonRefine::minCellField(const volScalarField& vFld) const
590 scalarField pFld(nPoints(), GREAT);
592 forAll(pointCells(), pointI)
594 const labelList& pCells = pointCells()[pointI];
598 pFld[pointI] = min(pFld[pointI], vFld[pCells[i]]);
605 // Simple (non-parallel) interpolation by averaging.
606 scalarField pistonRefine::cellToPoint(const scalarField& vFld) const
608 scalarField pFld(nPoints());
610 forAll(pointCells(), pointI)
612 const labelList& pCells = pointCells()[pointI];
617 sum += vFld[pCells[i]];
619 pFld[pointI] = sum/pCells.size();
625 // Calculate error. Is < 0 or distance from inbetween levels
626 scalarField pistonRefine::error
628 const scalarField& fld,
629 const scalar minLevel,
630 const scalar maxLevel
633 const scalar halfLevel = 0.5*(minLevel + maxLevel);
635 scalarField c(fld.size(), -1);
639 if (fld[i] >= minLevel && fld[i] < maxLevel)
641 c[i] = mag(fld[i] - halfLevel);
648 void pistonRefine::selectRefineCandidates
650 const scalar lowerRefineLevel,
651 const scalar upperRefineLevel,
652 const scalarField& vFld,
653 PackedList<1>& candidateCell
656 // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
657 // higher more desirable to be refined).
658 scalarField cellError
671 // Mark cells that are candidates for refinement.
672 forAll(cellError, cellI)
674 if (cellError[cellI] > 0)
676 candidateCell.set(cellI, 1);
682 labelList pistonRefine::selectRefineCells
684 const label maxCells,
685 const label maxRefinement,
686 const PackedList<1>& candidateCell
689 // Every refined cell causes 7 extra cells
690 label nTotToRefine = (maxCells - globalData().nTotalCells()) / 7;
692 const labelList& cellLevel = meshCutter_.cellLevel();
694 // Mark cells that cannot be refined since they would trigger refinement
695 // of protected cells (since 2:1 cascade)
696 PackedList<1> unrefineableCell;
697 calculateProtectedCells(unrefineableCell);
699 // Count current selection
700 label nCandidates = returnReduce(count(candidateCell, 1), sumOp<label>());
703 DynamicList<label> candidates(nCells());
705 if (nCandidates < nTotToRefine)
707 forAll(candidateCell, cellI)
711 cellLevel[cellI] < maxRefinement
712 && candidateCell.get(cellI) == 1
714 unrefineableCell.size() == 0
715 || unrefineableCell.get(cellI) == 0
719 candidates.append(cellI);
725 // Sort by error? For now just truncate.
726 for (label level = 0; level < maxRefinement; level++)
728 forAll(candidateCell, cellI)
732 cellLevel[cellI] == level
733 && candidateCell.get(cellI) == 1
735 unrefineableCell.size() == 0
736 || unrefineableCell.get(cellI) == 0
740 candidates.append(cellI);
744 if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
751 // Guarantee 2:1 refinement after refinement
752 labelList consistentSet
754 meshCutter_.consistentRefinement
757 true // Add to set to guarantee 2:1
761 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
762 << " cells for refinement out of " << globalData().nTotalCells()
765 return consistentSet;
769 labelList pistonRefine::selectUnrefinePoints
771 const scalar unrefineLevel,
772 const PackedList<1>& markedCell,
773 const scalarField& pFld
776 // All points that can be unrefined
777 const labelList splitPoints(meshCutter_.getSplitPoints());
779 DynamicList<label> newSplitPoints(splitPoints.size());
781 forAll(splitPoints, i)
783 label pointI = splitPoints[i];
785 if (pFld[pointI] < unrefineLevel)
787 // Check that all cells are not marked
788 const labelList& pCells = pointCells()[pointI];
790 bool hasMarked = false;
792 forAll(pCells, pCellI)
794 if (markedCell.get(pCells[pCellI]) == 1)
803 newSplitPoints.append(pointI);
809 newSplitPoints.shrink();
811 // Guarantee 2:1 refinement after unrefinement
812 labelList consistentSet
814 meshCutter_.consistentUnrefinement
820 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
821 << " split points out of a possible "
822 << returnReduce(splitPoints.size(), sumOp<label>())
825 return consistentSet;
829 void pistonRefine::extendMarkedCells(PackedList<1>& markedCell) const
831 // Mark faces using any marked cell
832 boolList markedFace(nFaces(), false);
834 forAll(markedCell, cellI)
836 if (markedCell.get(cellI) == 1)
838 const cell& cFaces = cells()[cellI];
842 markedFace[cFaces[i]] = true;
847 syncTools::syncFaceList(*this, markedFace, orEqOp<bool>(), false);
849 // Update cells using any markedFace
850 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
852 if (markedFace[faceI])
854 markedCell.set(faceOwner()[faceI], 1);
855 markedCell.set(faceNeighbour()[faceI], 1);
858 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
860 if (markedFace[faceI])
862 markedCell.set(faceOwner()[faceI], 1);
867 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
870 void Foam::pistonRefine::checkAndCalculate()
873 label pistonIndex = -1;
874 bool foundPiston = false;
876 label linerIndex = -1;
877 bool foundLiner = false;
879 label cylinderHeadIndex = -1;
880 bool foundCylinderHead = false;
883 forAll(boundary(), i)
885 Info << boundary()[i].name() << endl;
886 if (boundary()[i].name() == "piston")
891 else if (boundary()[i].name() == "liner")
896 else if (boundary()[i].name() == "cylinderHead")
898 cylinderHeadIndex = i;
899 foundCylinderHead = true;
903 reduce(foundPiston, orOp<bool>());
904 reduce(foundLiner, orOp<bool>());
905 reduce(foundCylinderHead, orOp<bool>());
909 FatalErrorIn("Foam::pistonRefine::checkAndCalculate()")
910 << " : cannot find piston patch"
911 << abort(FatalError);
916 FatalErrorIn("Foam::pistonRefine::checkAndCalculate()")
917 << " : cannot find liner patch"
918 << abort(FatalError);
921 if (!foundCylinderHead)
923 FatalErrorIn("Foam::pistonRefine::checkAndCalculate()")
924 << " : cannot find cylinderHead patch"
929 if (linerIndex != -1)
932 max(boundary()[pistonIndex].patch().localPoints()).z();
934 reduce(pistonPosition(), minOp<scalar>());
936 if (cylinderHeadIndex != -1)
940 boundary()[cylinderHeadIndex].patch().localPoints()
943 reduce(deckHeight(), minOp<scalar>());
945 Info<< "deckHeight: " << deckHeight() << nl
946 << "piston position: " << pistonPosition() << endl;
953 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
955 // Construct from components
956 Foam::pistonRefine::pistonRefine
961 engineTopoChangerMesh(io),
962 piston_(*this, engTime().engineDict().subDict("piston")),
963 pistonPosition_(-GREAT),
967 nRefinementIterations_(0),
968 protectedCell_(nCells(), 0)
970 const labelList& cellLevel = meshCutter_.cellLevel();
971 const labelList& pointLevel = meshCutter_.pointLevel();
973 // Set cells that should not be refined.
974 // This is currently any cell which does not have 8 anchor points or
975 // uses any face which does not have 4 anchor points.
976 // Note: do not use cellPoint addressing
978 // Count number of points <= cellLevel
979 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
981 labelList nAnchors(nCells(), 0);
983 label nProtected = 0;
985 forAll(pointCells(), pointI)
987 const labelList& pCells = pointCells()[pointI];
991 label cellI = pCells[i];
993 if (protectedCell_.get(cellI) == 0)
995 if (pointLevel[pointI] <= cellLevel[cellI])
999 if (nAnchors[cellI] > 8)
1001 protectedCell_.set(cellI, 1);
1010 // Count number of points <= faceLevel
1011 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1012 // Bit tricky since proc face might be one more refined than the owner since
1013 // the coupled one is refined.
1016 labelList neiLevel(nFaces());
1018 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
1020 neiLevel[faceI] = cellLevel[faceOwner()[faceI]];
1022 syncTools::swapFaceList(*this, neiLevel, false);
1025 boolList protectedFace(nFaces(), false);
1027 forAll(faceOwner(), faceI)
1029 label faceLevel = max
1031 cellLevel[faceOwner()[faceI]],
1035 const face& f = faces()[faceI];
1041 if (pointLevel[f[fp]] <= faceLevel)
1047 protectedFace[faceI] = true;
1054 syncTools::syncFaceList
1062 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
1064 if (protectedFace[faceI])
1066 protectedCell_.set(faceOwner()[faceI], 1);
1068 protectedCell_.set(faceNeighbour()[faceI], 1);
1072 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
1074 if (protectedFace[faceI])
1076 protectedCell_.set(faceOwner()[faceI], 1);
1082 if (returnReduce(nProtected, sumOp<label>()) == 0)
1084 protectedCell_.clear();
1088 checkAndCalculate();
1092 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1094 Foam::pistonRefine::~pistonRefine()
1099 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1101 bool Foam::pistonRefine::update()
1103 // Re-read dictionary. Choosen since usually -small so trivial amount
1104 // of time compared to actual refinement. Also very useful to be able
1105 // to modify on-the-fly.
1106 dictionary refineDict
1115 IOobject::MUST_READ,
1119 ).subDict(typeName + "Coeffs")
1122 label refineInterval = readLabel(refineDict.lookup("refineInterval"));
1124 bool hasChanged = false;
1126 if (refineInterval == 0)
1128 changing(hasChanged);
1132 else if (refineInterval < 0)
1134 FatalErrorIn("dynamicRefineFvMesh::update()")
1135 << "Illegal refineInterval " << refineInterval << nl
1136 << "The refineInterval setting in the dynamicMeshDict should"
1137 << " be >= 1." << nl
1138 << exit(FatalError);
1141 // autoPtr<mapPolyMesh> topoChangeMap = topoChanger_.changeMesh();
1143 // pointField newPoints = points();
1145 // Note: cannot refine at time 0 since no V0 present since mesh not
1148 if (time().timeIndex() > 0 && time().timeIndex() % refineInterval == 0)
1150 label maxCells = readLabel(refineDict.lookup("maxCells"));
1154 FatalErrorIn("dynamicRefineFvMesh::update()")
1155 << "Illegal maximum number of cells " << maxCells << nl
1156 << "The maxCells setting in the dynamicMeshDict should"
1158 << exit(FatalError);
1161 label maxRefinement = readLabel(refineDict.lookup("maxRefinement"));
1163 if (maxRefinement <= 0)
1165 FatalErrorIn("dynamicRefineFvMesh::update()")
1166 << "Illegal maximum refinement level " << maxRefinement << nl
1167 << "The maxCells setting in the dynamicMeshDict should"
1169 << exit(FatalError);
1172 word field(refineDict.lookup("field"));
1174 const volScalarField& vFld = lookupObject<volScalarField>(field);
1176 const scalar lowerRefineLevel =
1177 readScalar(refineDict.lookup("lowerRefineLevel"));
1178 const scalar upperRefineLevel =
1179 readScalar(refineDict.lookup("upperRefineLevel"));
1180 const scalar unrefineLevel =
1181 readScalar(refineDict.lookup("unrefineLevel"));
1182 const label nBufferLayers =
1183 readLabel(refineDict.lookup("nBufferLayers"));
1185 // Cells marked for refinement or otherwise protected from unrefinement.
1186 PackedList<1> refineCell(nCells(), 0);
1188 if (globalData().nTotalCells() < maxCells)
1190 // Determine candidates for refinement (looking at field only)
1191 selectRefineCandidates
1199 // Select subset of candidates. Take into account max allowable
1200 // cells, refinement level, protected cells.
1201 labelList cellsToRefine
1211 label nCellsToRefine = returnReduce
1213 cellsToRefine.size(), sumOp<label>()
1216 if (nCellsToRefine > 0)
1218 // Refine/update mesh and map fields
1219 autoPtr<mapPolyMesh> map = refine(cellsToRefine);
1221 // Update refineCell. Note that some of the marked ones have
1222 // not been refined due to constraints.
1224 const labelList& cellMap = map().cellMap();
1225 const labelList& reverseCellMap = map().reverseCellMap();
1227 PackedList<1> newRefineCell(cellMap.size());
1229 forAll(cellMap, cellI)
1231 label oldCellI = cellMap[cellI];
1235 newRefineCell.set(cellI, 1);
1237 else if (reverseCellMap[oldCellI] != cellI)
1239 newRefineCell.set(cellI, 1);
1243 newRefineCell.set(cellI, refineCell.get(oldCellI));
1246 refineCell.transfer(newRefineCell);
1249 // Extend with a buffer layer to prevent neighbouring points
1251 for (label i = 0; i < nBufferLayers; i++)
1253 extendMarkedCells(refineCell);
1262 // Select unrefineable points that are not marked in refineCell
1263 labelList pointsToUnrefine
1265 selectUnrefinePoints
1273 label nSplitPoints = returnReduce
1275 pointsToUnrefine.size(),
1279 if (nSplitPoints > 0)
1281 // Refine/update mesh
1282 unrefine(pointsToUnrefine);
1289 if ((nRefinementIterations_ % 10) == 0)
1291 // Compact refinement history occassionally (how often?).
1292 // Unrefinement causes holes in the refinementHistory.
1293 const_cast<refinementHistory&>(meshCutter().history()).compact();
1295 nRefinementIterations_++;
1298 changing(hasChanged);
1300 // pointField newPoints = allPoints();
1301 pointField newPoints = points();
1305 // if (topoChangeMap().hasMotionPoints())
1307 // movePoints(topoChangeMap().preMotionPoints());
1308 // newPoints = topoChangeMap().preMotionPoints();
1315 scalar deltaZ = engTime().pistonDisplacement().value();
1316 Info<< "deltaZ = " << deltaZ << endl;
1318 Info << "pistonPosition = " << pistonPosition_ << endl;
1319 Info << "deckHeight = " << deckHeight_ << endl;
1322 // Position of the top of the static mesh layers above the piston
1323 scalar pistonPlusLayers = pistonPosition_; //+ pistonLayers_.value();
1325 newPoints = points();
1327 forAll (newPoints, pointi)
1329 point& p = newPoints[pointi];
1331 if (p.z() < pistonPlusLayers) // In piston bowl
1335 else if (p.z() < deckHeight_) // In liner region
1339 *(deckHeight_ - p.z())
1340 /(deckHeight_ - pistonPlusLayers);
1345 movePoints(newPoints);
1348 pistonPosition_ += deltaZ;
1349 scalar pistonSpeed = deltaZ/engTime().deltaT().value();
1351 Info<< "clearance: " << deckHeight_ - pistonPosition_ << nl
1352 << "Piston speed = " << pistonSpeed << " m/s" << endl;
1355 // return hasChanged;
1360 void Foam::pistonRefine::setBoundaryVelocity(volVectorField& U)
1362 // Does nothing, using the movingWallVelocity boundary condition for U in the piston patch...
1366 // vector pistonVel = piston().cs().axis()*engTime().pistonSpeed().value();
1368 //mean piston velocityy
1370 vector pistonVel = 0.5 * piston().cs().axis()*
1375 2.0*engTime().stroke().value()*engTime().rpm().value()/60.0
1379 // U.boundaryField()[piston().patchID().index()] = pistonVel;
1382 bool pistonRefine::writeObject
1384 IOstream::streamFormat fmt,
1385 IOstream::versionNumber ver,
1386 IOstream::compressionType cmp
1389 // Force refinement data to go to the current time directory.
1390 const_cast<hexRef8&>(meshCutter_).setInstance(time().timeName());
1393 pistonRefine::writeObjects(fmt, ver, cmp)
1394 && meshCutter_.write();
1398 volScalarField scalarCellLevel
1406 IOobject::AUTO_WRITE,
1410 dimensionedScalar("level", dimless, 0)
1413 const labelList& cellLevel = meshCutter_.cellLevel();
1415 forAll(cellLevel, cellI)
1417 scalarCellLevel[cellI] = cellLevel[cellI];
1420 writeOk = writeOk && scalarCellLevel.write();
1427 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //