1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "SortableList.H"
27 #include "addToRunTimeSelectionTable.H"
28 #include "volFields.H"
29 #include "polyTopoChange.H"
30 #include "surfaceFields.H"
32 #include "syncTools.H"
33 #include "ListListOps.H"
34 #include "pointFields.H"
35 #include "directTopoChange.H"
37 #include "pistonRefine.H"
38 #include "engineTime.H"
39 #include "layerAdditionRemoval.H"
40 #include "mapPolyMesh.H"
41 #include "GeometricField.H"
43 #include "fvPatchField.H"
44 #include "volPointInterpolation.H"
45 #include "fvcMeshPhi.H"
46 #include "fvcVolumeIntegrate.H"
47 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
51 defineTypeNameAndDebug(pistonRefine, 0);
52 addToRunTimeSelectionTable(engineTopoChangerMesh, pistonRefine, IOobject);
55 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 label pistonRefine::count(const PackedList<1>& l, const unsigned int val)
71 void pistonRefine::calculateProtectedCells
73 PackedList<1>& unrefineableCell
76 if (protectedCell_.size() == 0)
78 unrefineableCell.clear();
82 const labelList& cellLevel = meshCutter_.cellLevel();
84 unrefineableCell = protectedCell_;
86 // Get neighbouring cell level
87 labelList neiLevel(nFaces()-nInternalFaces());
89 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
91 neiLevel[faceI-nInternalFaces()] = cellLevel[faceOwner()[faceI]];
93 syncTools::swapBoundaryFaceList(*this, neiLevel, false);
98 // Pick up faces on border of protected cells
99 boolList seedFace(nFaces(), false);
101 forAll(faceNeighbour(), faceI)
103 label own = faceOwner()[faceI];
104 bool ownProtected = (unrefineableCell.get(own) == 1);
105 label nei = faceNeighbour()[faceI];
106 bool neiProtected = (unrefineableCell.get(nei) == 1);
108 if (ownProtected && (cellLevel[nei] > cellLevel[own]))
110 seedFace[faceI] = true;
112 else if (neiProtected && (cellLevel[own] > cellLevel[nei]))
114 seedFace[faceI] = true;
117 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
119 label own = faceOwner()[faceI];
120 bool ownProtected = (unrefineableCell.get(own) == 1);
124 && (neiLevel[faceI-nInternalFaces()] > cellLevel[own])
127 seedFace[faceI] = true;
131 syncTools::syncFaceList(*this, seedFace, orEqOp<bool>(), false);
134 // Extend unrefineableCell
135 bool hasExtended = false;
137 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
141 label own = faceOwner()[faceI];
142 if (unrefineableCell.get(own) == 0)
144 unrefineableCell.set(own, 1);
148 label nei = faceNeighbour()[faceI];
149 if (unrefineableCell.get(nei) == 0)
151 unrefineableCell.set(nei, 1);
156 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
160 label own = faceOwner()[faceI];
161 if (unrefineableCell.get(own) == 0)
163 unrefineableCell.set(own, 1);
169 if (!returnReduce(hasExtended, orOp<bool>()))
177 void pistonRefine::readDict()
179 dictionary refineDict
192 ).subDict(typeName + "Coeffs")
195 correctFluxes_ = List<Pair<word> >(refineDict.lookup("correctFluxes"));
197 dumpLevel_ = Switch(refineDict.lookup("dumpLevel"));
201 // Refines cells, maps fields and recalculates (an approximate) flux
202 autoPtr<mapPolyMesh> pistonRefine::refine
204 const labelList& cellsToRefine
207 // Mesh changing engine.
208 directTopoChange meshMod(*this);
210 // Play refinement commands into mesh changer.
211 meshCutter_.setRefinement(cellsToRefine, meshMod);
213 // Create mesh (with inflation), return map from old to new mesh.
214 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
215 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
217 Info<< "Refined from "
218 << returnReduce(map().nOldCells(), sumOp<label>())
219 << " to " << globalData().nTotalCells() << " cells." << endl;
224 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
226 label oldFaceI = map().faceMap()[faceI];
228 if (oldFaceI >= nInternalFaces())
230 FatalErrorIn("pistonRefine::refine")
231 << "New internal face:" << faceI
232 << " fc:" << faceCentres()[faceI]
233 << " originates from boundary oldFace:" << oldFaceI
234 << abort(FatalError);
244 pointField newPoints;
245 if (map().hasMotionPoints())
247 newPoints = map().preMotionPoints();
251 newPoints = points();
253 movePoints(newPoints);
257 // Correct the flux for modified/added faces. All the faces which only
258 // have been renumbered will already have been handled by the mapping.
260 const labelList& faceMap = map().faceMap();
261 const labelList& reverseFaceMap = map().reverseFaceMap();
263 // Storage for any master faces. These will be the original faces
264 // on the coarse cell that get split into four (or rather the
265 // master face gets modified and three faces get added from the master)
266 labelHashSet masterFaces(4*cellsToRefine.size());
268 forAll(faceMap, faceI)
270 label oldFaceI = faceMap[faceI];
274 label masterFaceI = reverseFaceMap[oldFaceI];
280 "pistonRefine::refine(const labelList&)"
281 ) << "Problem: should not have removed faces"
283 << nl << "face:" << faceI << abort(FatalError);
285 else if (masterFaceI != faceI)
287 masterFaces.insert(masterFaceI);
293 Info<< "Found " << returnReduce(masterFaces.size(), sumOp<label>())
294 << " split faces " << endl;
297 forAll(correctFluxes_, i)
301 Info<< "Mapping flux " << correctFluxes_[i][0]
302 << " using interpolated flux " << correctFluxes_[i][1]
305 surfaceScalarField& phi = const_cast<surfaceScalarField&>
307 lookupObject<surfaceScalarField>(correctFluxes_[i][0])
309 surfaceScalarField phiU =
312 lookupObject<volVectorField>(correctFluxes_[i][1])
316 // Recalculate new internal faces.
317 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
319 label oldFaceI = faceMap[faceI];
324 phi[faceI] = phiU[faceI];
326 else if (reverseFaceMap[oldFaceI] != faceI)
328 // face-from-masterface
329 phi[faceI] = phiU[faceI];
333 // Recalculate new boundary faces.
334 forAll(phi.boundaryField(), patchI)
336 fvsPatchScalarField& patchPhi = phi.boundaryField()[patchI];
337 const fvsPatchScalarField& patchPhiU =
338 phiU.boundaryField()[patchI];
340 label faceI = patchPhi.patch().patch().start();
344 label oldFaceI = faceMap[faceI];
349 patchPhi[i] = patchPhiU[i];
351 else if (reverseFaceMap[oldFaceI] != faceI)
353 // face-from-masterface
354 patchPhi[i] = patchPhiU[i];
361 // Update master faces
362 forAllConstIter(labelHashSet, masterFaces, iter)
364 label faceI = iter.key();
366 if (isInternalFace(faceI))
368 phi[faceI] = phiU[faceI];
372 label patchI = boundaryMesh().whichPatch(faceI);
373 label i = faceI - boundaryMesh()[patchI].start();
375 const fvsPatchScalarField& patchPhiU =
376 phiU.boundaryField()[patchI];
378 fvsPatchScalarField& patchPhi =
379 phi.boundaryField()[patchI];
381 patchPhi[i] = patchPhiU[i];
389 // Update numbering of cells/vertices.
390 meshCutter_.updateMesh(map);
392 // Update numbering of protectedCell_
393 if (protectedCell_.size() > 0)
395 PackedList<1> newProtectedCell(nCells(), 0);
397 forAll(newProtectedCell, cellI)
399 label oldCellI = map().cellMap()[cellI];
400 newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
402 protectedCell_.transfer(newProtectedCell);
405 // Debug: Check refinement levels (across faces only)
406 meshCutter_.checkRefinementLevels(-1, labelList(0));
412 // Combines previously split cells, maps fields and recalculates
413 // (an approximate) flux
414 autoPtr<mapPolyMesh> pistonRefine::unrefine
416 const labelList& splitPoints
419 directTopoChange meshMod(*this);
421 // Play refinement commands into mesh changer.
422 meshCutter_.setUnrefinement(splitPoints, meshMod);
425 // Save information on faces that will be combined
426 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
428 // Find the faceMidPoints on cells to be combined.
429 // for each face resulting of split of face into four store the
431 Map<label> faceToSplitPoint(3*splitPoints.size());
434 forAll(splitPoints, i)
436 label pointI = splitPoints[i];
438 const labelList& pEdges = pointEdges()[pointI];
442 label otherPointI = edges()[pEdges[j]].otherVertex(pointI);
444 const labelList& pFaces = pointFaces()[otherPointI];
446 forAll(pFaces, pFaceI)
448 faceToSplitPoint.insert(pFaces[pFaceI], otherPointI);
455 // Change mesh and generate mesh.
456 //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
457 autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
459 Info<< "Unrefined from "
460 << returnReduce(map().nOldCells(), sumOp<label>())
461 << " to " << globalData().nTotalCells() << " cells."
470 pointField newPoints;
471 if (map().hasMotionPoints())
473 newPoints = map().preMotionPoints();
477 newPoints = points();
479 movePoints(newPoints);
482 // Correct the flux for modified faces.
484 const labelList& reversePointMap = map().reversePointMap();
485 const labelList& reverseFaceMap = map().reverseFaceMap();
487 forAll(correctFluxes_, i)
491 Info<< "Mapping flux " << correctFluxes_[i][0]
492 << " using interpolated flux " << correctFluxes_[i][1]
495 surfaceScalarField& phi = const_cast<surfaceScalarField&>
497 lookupObject<surfaceScalarField>(correctFluxes_[i][0])
499 surfaceScalarField phiU =
502 lookupObject<volVectorField>(correctFluxes_[i][1])
506 forAllConstIter(Map<label>, faceToSplitPoint, iter)
508 label oldFaceI = iter.key();
509 label oldPointI = iter();
511 if (reversePointMap[oldPointI] < 0)
513 // midpoint was removed. See if face still exists.
514 label faceI = reverseFaceMap[oldFaceI];
518 if (isInternalFace(faceI))
520 phi[faceI] = phiU[faceI];
524 label patchI = boundaryMesh().whichPatch(faceI);
525 label i = faceI - boundaryMesh()[patchI].start();
527 const fvsPatchScalarField& patchPhiU =
528 phiU.boundaryField()[patchI];
530 fvsPatchScalarField& patchPhi =
531 phi.boundaryField()[patchI];
533 patchPhi[i] = patchPhiU[i];
542 // Update numbering of cells/vertices.
543 meshCutter_.updateMesh(map);
545 // Update numbering of protectedCell_
546 if (protectedCell_.size() > 0)
548 PackedList<1> newProtectedCell(nCells(), 0);
550 forAll(newProtectedCell, cellI)
552 label oldCellI = map().cellMap()[cellI];
555 newProtectedCell.set(cellI, protectedCell_.get(oldCellI));
558 protectedCell_.transfer(newProtectedCell);
561 // Debug: Check refinement levels (across faces only)
562 meshCutter_.checkRefinementLevels(-1, labelList(0));
568 // Get max of connected point
569 scalarField pistonRefine::maxPointField(const scalarField& pFld) const
571 scalarField vFld(nCells(), -GREAT);
573 forAll(pointCells(), pointI)
575 const labelList& pCells = pointCells()[pointI];
579 vFld[pCells[i]] = max(vFld[pCells[i]], pFld[pointI]);
586 // Get min of connected cell
587 scalarField pistonRefine::minCellField(const volScalarField& vFld) const
589 scalarField pFld(nPoints(), GREAT);
591 forAll(pointCells(), pointI)
593 const labelList& pCells = pointCells()[pointI];
597 pFld[pointI] = min(pFld[pointI], vFld[pCells[i]]);
604 // Simple (non-parallel) interpolation by averaging.
605 scalarField pistonRefine::cellToPoint(const scalarField& vFld) const
607 scalarField pFld(nPoints());
609 forAll(pointCells(), pointI)
611 const labelList& pCells = pointCells()[pointI];
616 sum += vFld[pCells[i]];
618 pFld[pointI] = sum/pCells.size();
624 // Calculate error. Is < 0 or distance from inbetween levels
625 scalarField pistonRefine::error
627 const scalarField& fld,
628 const scalar minLevel,
629 const scalar maxLevel
632 const scalar halfLevel = 0.5*(minLevel + maxLevel);
634 scalarField c(fld.size(), -1);
638 if (fld[i] >= minLevel && fld[i] < maxLevel)
640 c[i] = mag(fld[i] - halfLevel);
647 void pistonRefine::selectRefineCandidates
649 const scalar lowerRefineLevel,
650 const scalar upperRefineLevel,
651 const scalarField& vFld,
652 PackedList<1>& candidateCell
655 // Get error per cell. Is -1 (not to be refined) to >0 (to be refined,
656 // higher more desirable to be refined).
657 scalarField cellError
670 // Mark cells that are candidates for refinement.
671 forAll(cellError, cellI)
673 if (cellError[cellI] > 0)
675 candidateCell.set(cellI, 1);
681 labelList pistonRefine::selectRefineCells
683 const label maxCells,
684 const label maxRefinement,
685 const PackedList<1>& candidateCell
688 // Every refined cell causes 7 extra cells
689 label nTotToRefine = (maxCells - globalData().nTotalCells()) / 7;
691 const labelList& cellLevel = meshCutter_.cellLevel();
693 // Mark cells that cannot be refined since they would trigger refinement
694 // of protected cells (since 2:1 cascade)
695 PackedList<1> unrefineableCell;
696 calculateProtectedCells(unrefineableCell);
698 // Count current selection
699 label nCandidates = returnReduce(count(candidateCell, 1), sumOp<label>());
702 DynamicList<label> candidates(nCells());
704 if (nCandidates < nTotToRefine)
706 forAll(candidateCell, cellI)
710 cellLevel[cellI] < maxRefinement
711 && candidateCell.get(cellI) == 1
713 unrefineableCell.size() == 0
714 || unrefineableCell.get(cellI) == 0
718 candidates.append(cellI);
724 // Sort by error? For now just truncate.
725 for (label level = 0; level < maxRefinement; level++)
727 forAll(candidateCell, cellI)
731 cellLevel[cellI] == level
732 && candidateCell.get(cellI) == 1
734 unrefineableCell.size() == 0
735 || unrefineableCell.get(cellI) == 0
739 candidates.append(cellI);
743 if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
750 // Guarantee 2:1 refinement after refinement
751 labelList consistentSet
753 meshCutter_.consistentRefinement
756 true // Add to set to guarantee 2:1
760 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
761 << " cells for refinement out of " << globalData().nTotalCells()
764 return consistentSet;
768 labelList pistonRefine::selectUnrefinePoints
770 const scalar unrefineLevel,
771 const PackedList<1>& markedCell,
772 const scalarField& pFld
775 // All points that can be unrefined
776 const labelList splitPoints(meshCutter_.getSplitPoints());
778 DynamicList<label> newSplitPoints(splitPoints.size());
780 forAll(splitPoints, i)
782 label pointI = splitPoints[i];
784 if (pFld[pointI] < unrefineLevel)
786 // Check that all cells are not marked
787 const labelList& pCells = pointCells()[pointI];
789 bool hasMarked = false;
791 forAll(pCells, pCellI)
793 if (markedCell.get(pCells[pCellI]) == 1)
802 newSplitPoints.append(pointI);
808 newSplitPoints.shrink();
810 // Guarantee 2:1 refinement after unrefinement
811 labelList consistentSet
813 meshCutter_.consistentUnrefinement
819 Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
820 << " split points out of a possible "
821 << returnReduce(splitPoints.size(), sumOp<label>())
824 return consistentSet;
828 void pistonRefine::extendMarkedCells(PackedList<1>& markedCell) const
830 // Mark faces using any marked cell
831 boolList markedFace(nFaces(), false);
833 forAll(markedCell, cellI)
835 if (markedCell.get(cellI) == 1)
837 const cell& cFaces = cells()[cellI];
841 markedFace[cFaces[i]] = true;
846 syncTools::syncFaceList(*this, markedFace, orEqOp<bool>(), false);
848 // Update cells using any markedFace
849 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
851 if (markedFace[faceI])
853 markedCell.set(faceOwner()[faceI], 1);
854 markedCell.set(faceNeighbour()[faceI], 1);
857 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
859 if (markedFace[faceI])
861 markedCell.set(faceOwner()[faceI], 1);
866 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
869 void Foam::pistonRefine::checkAndCalculate()
872 label pistonIndex = -1;
873 bool foundPiston = false;
875 label linerIndex = -1;
876 bool foundLiner = false;
878 label cylinderHeadIndex = -1;
879 bool foundCylinderHead = false;
882 forAll(boundary(), i)
884 Info << boundary()[i].name() << endl;
885 if (boundary()[i].name() == "piston")
890 else if (boundary()[i].name() == "liner")
895 else if (boundary()[i].name() == "cylinderHead")
897 cylinderHeadIndex = i;
898 foundCylinderHead = true;
902 reduce(foundPiston, orOp<bool>());
903 reduce(foundLiner, orOp<bool>());
904 reduce(foundCylinderHead, orOp<bool>());
908 FatalErrorIn("Foam::pistonRefine::checkAndCalculate()")
909 << " : cannot find piston patch"
910 << abort(FatalError);
915 FatalErrorIn("Foam::pistonRefine::checkAndCalculate()")
916 << " : cannot find liner patch"
917 << abort(FatalError);
920 if (!foundCylinderHead)
922 FatalErrorIn("Foam::pistonRefine::checkAndCalculate()")
923 << " : cannot find cylinderHead patch"
928 if (linerIndex != -1)
931 max(boundary()[pistonIndex].patch().localPoints()).z();
933 reduce(pistonPosition(), minOp<scalar>());
935 if (cylinderHeadIndex != -1)
939 boundary()[cylinderHeadIndex].patch().localPoints()
942 reduce(deckHeight(), minOp<scalar>());
944 Info<< "deckHeight: " << deckHeight() << nl
945 << "piston position: " << pistonPosition() << endl;
952 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
954 // Construct from components
955 Foam::pistonRefine::pistonRefine
960 engineTopoChangerMesh(io),
961 piston_(*this, engTime().engineDict().subDict("piston")),
962 pistonPosition_(-GREAT),
966 nRefinementIterations_(0),
967 protectedCell_(nCells(), 0)
969 const labelList& cellLevel = meshCutter_.cellLevel();
970 const labelList& pointLevel = meshCutter_.pointLevel();
972 // Set cells that should not be refined.
973 // This is currently any cell which does not have 8 anchor points or
974 // uses any face which does not have 4 anchor points.
975 // Note: do not use cellPoint addressing
977 // Count number of points <= cellLevel
978 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
980 labelList nAnchors(nCells(), 0);
982 label nProtected = 0;
984 forAll(pointCells(), pointI)
986 const labelList& pCells = pointCells()[pointI];
990 label cellI = pCells[i];
992 if (protectedCell_.get(cellI) == 0)
994 if (pointLevel[pointI] <= cellLevel[cellI])
998 if (nAnchors[cellI] > 8)
1000 protectedCell_.set(cellI, 1);
1009 // Count number of points <= faceLevel
1010 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1011 // Bit tricky since proc face might be one more refined than the owner since
1012 // the coupled one is refined.
1015 labelList neiLevel(nFaces());
1017 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
1019 neiLevel[faceI] = cellLevel[faceOwner()[faceI]];
1021 syncTools::swapFaceList(*this, neiLevel, false);
1024 boolList protectedFace(nFaces(), false);
1026 forAll(faceOwner(), faceI)
1028 label faceLevel = max
1030 cellLevel[faceOwner()[faceI]],
1034 const face& f = faces()[faceI];
1040 if (pointLevel[f[fp]] <= faceLevel)
1046 protectedFace[faceI] = true;
1053 syncTools::syncFaceList
1061 for (label faceI = 0; faceI < nInternalFaces(); faceI++)
1063 if (protectedFace[faceI])
1065 protectedCell_.set(faceOwner()[faceI], 1);
1067 protectedCell_.set(faceNeighbour()[faceI], 1);
1071 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
1073 if (protectedFace[faceI])
1075 protectedCell_.set(faceOwner()[faceI], 1);
1081 if (returnReduce(nProtected, sumOp<label>()) == 0)
1083 protectedCell_.clear();
1087 checkAndCalculate();
1091 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1093 Foam::pistonRefine::~pistonRefine()
1098 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1100 bool Foam::pistonRefine::update()
1102 // Re-read dictionary. Choosen since usually -small so trivial amount
1103 // of time compared to actual refinement. Also very useful to be able
1104 // to modify on-the-fly.
1105 dictionary refineDict
1114 IOobject::MUST_READ,
1118 ).subDict(typeName + "Coeffs")
1121 label refineInterval = readLabel(refineDict.lookup("refineInterval"));
1123 bool hasChanged = false;
1125 if (refineInterval == 0)
1127 changing(hasChanged);
1131 else if (refineInterval < 0)
1133 FatalErrorIn("dynamicRefineFvMesh::update()")
1134 << "Illegal refineInterval " << refineInterval << nl
1135 << "The refineInterval setting in the dynamicMeshDict should"
1136 << " be >= 1." << nl
1137 << exit(FatalError);
1140 // autoPtr<mapPolyMesh> topoChangeMap = topoChanger_.changeMesh();
1142 // pointField newPoints = points();
1144 // Note: cannot refine at time 0 since no V0 present since mesh not
1147 if (time().timeIndex() > 0 && time().timeIndex() % refineInterval == 0)
1149 label maxCells = readLabel(refineDict.lookup("maxCells"));
1153 FatalErrorIn("dynamicRefineFvMesh::update()")
1154 << "Illegal maximum number of cells " << maxCells << nl
1155 << "The maxCells setting in the dynamicMeshDict should"
1157 << exit(FatalError);
1160 label maxRefinement = readLabel(refineDict.lookup("maxRefinement"));
1162 if (maxRefinement <= 0)
1164 FatalErrorIn("dynamicRefineFvMesh::update()")
1165 << "Illegal maximum refinement level " << maxRefinement << nl
1166 << "The maxCells setting in the dynamicMeshDict should"
1168 << exit(FatalError);
1171 word field(refineDict.lookup("field"));
1173 const volScalarField& vFld = lookupObject<volScalarField>(field);
1175 const scalar lowerRefineLevel =
1176 readScalar(refineDict.lookup("lowerRefineLevel"));
1177 const scalar upperRefineLevel =
1178 readScalar(refineDict.lookup("upperRefineLevel"));
1179 const scalar unrefineLevel =
1180 readScalar(refineDict.lookup("unrefineLevel"));
1181 const label nBufferLayers =
1182 readLabel(refineDict.lookup("nBufferLayers"));
1184 // Cells marked for refinement or otherwise protected from unrefinement.
1185 PackedList<1> refineCell(nCells(), 0);
1187 if (globalData().nTotalCells() < maxCells)
1189 // Determine candidates for refinement (looking at field only)
1190 selectRefineCandidates
1198 // Select subset of candidates. Take into account max allowable
1199 // cells, refinement level, protected cells.
1200 labelList cellsToRefine
1210 label nCellsToRefine = returnReduce
1212 cellsToRefine.size(), sumOp<label>()
1215 if (nCellsToRefine > 0)
1217 // Refine/update mesh and map fields
1218 autoPtr<mapPolyMesh> map = refine(cellsToRefine);
1220 // Update refineCell. Note that some of the marked ones have
1221 // not been refined due to constraints.
1223 const labelList& cellMap = map().cellMap();
1224 const labelList& reverseCellMap = map().reverseCellMap();
1226 PackedList<1> newRefineCell(cellMap.size());
1228 forAll(cellMap, cellI)
1230 label oldCellI = cellMap[cellI];
1234 newRefineCell.set(cellI, 1);
1236 else if (reverseCellMap[oldCellI] != cellI)
1238 newRefineCell.set(cellI, 1);
1242 newRefineCell.set(cellI, refineCell.get(oldCellI));
1245 refineCell.transfer(newRefineCell);
1248 // Extend with a buffer layer to prevent neighbouring points
1250 for (label i = 0; i < nBufferLayers; i++)
1252 extendMarkedCells(refineCell);
1261 // Select unrefineable points that are not marked in refineCell
1262 labelList pointsToUnrefine
1264 selectUnrefinePoints
1272 label nSplitPoints = returnReduce
1274 pointsToUnrefine.size(),
1278 if (nSplitPoints > 0)
1280 // Refine/update mesh
1281 unrefine(pointsToUnrefine);
1288 if ((nRefinementIterations_ % 10) == 0)
1290 // Compact refinement history occassionally (how often?).
1291 // Unrefinement causes holes in the refinementHistory.
1292 const_cast<refinementHistory&>(meshCutter().history()).compact();
1294 nRefinementIterations_++;
1297 changing(hasChanged);
1299 // pointField newPoints = allPoints();
1300 pointField newPoints = points();
1304 // if (topoChangeMap().hasMotionPoints())
1306 // movePoints(topoChangeMap().preMotionPoints());
1307 // newPoints = topoChangeMap().preMotionPoints();
1314 scalar deltaZ = engTime().pistonDisplacement().value();
1315 Info<< "deltaZ = " << deltaZ << endl;
1317 Info << "pistonPosition = " << pistonPosition_ << endl;
1318 Info << "deckHeight = " << deckHeight_ << endl;
1321 // Position of the top of the static mesh layers above the piston
1322 scalar pistonPlusLayers = pistonPosition_; //+ pistonLayers_.value();
1324 newPoints = points();
1326 forAll (newPoints, pointi)
1328 point& p = newPoints[pointi];
1330 if (p.z() < pistonPlusLayers) // In piston bowl
1334 else if (p.z() < deckHeight_) // In liner region
1338 *(deckHeight_ - p.z())
1339 /(deckHeight_ - pistonPlusLayers);
1344 movePoints(newPoints);
1347 pistonPosition_ += deltaZ;
1348 scalar pistonSpeed = deltaZ/engTime().deltaT().value();
1350 Info<< "clearance: " << deckHeight_ - pistonPosition_ << nl
1351 << "Piston speed = " << pistonSpeed << " m/s" << endl;
1354 // return hasChanged;
1359 void Foam::pistonRefine::setBoundaryVelocity(volVectorField& U)
1361 // Does nothing, using the movingWallVelocity boundary condition for U in the piston patch...
1365 // vector pistonVel = piston().cs().axis()*engTime().pistonSpeed().value();
1367 //mean piston velocityy
1369 vector pistonVel = 0.5 * piston().cs().axis()*
1374 2.0*engTime().stroke().value()*engTime().rpm().value()/60.0
1378 // U.boundaryField()[piston().patchID().index()] = pistonVel;
1381 bool pistonRefine::writeObject
1383 IOstream::streamFormat fmt,
1384 IOstream::versionNumber ver,
1385 IOstream::compressionType cmp
1388 // Force refinement data to go to the current time directory.
1389 const_cast<hexRef8&>(meshCutter_).setInstance(time().timeName());
1392 pistonRefine::writeObjects(fmt, ver, cmp)
1393 && meshCutter_.write();
1397 volScalarField scalarCellLevel
1405 IOobject::AUTO_WRITE,
1409 dimensionedScalar("level", dimless, 0)
1412 const labelList& cellLevel = meshCutter_.cellLevel();
1414 forAll(cellLevel, cellI)
1416 scalarCellLevel[cellI] = cellLevel[cellI];
1419 writeOk = writeOk && scalarCellLevel.write();
1426 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //