1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
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 \*---------------------------------------------------------------------------*/
30 #include "polyTopoChange.H"
31 #include "meshTools.H"
32 #include "polyAddFace.H"
33 #include "polyAddPoint.H"
34 #include "polyAddCell.H"
35 #include "polyModifyFace.H"
36 #include "syncTools.H"
42 #include "FaceCellWave.H"
43 #include "mapDistributePolyMesh.H"
44 #include "refinementData.H"
45 #include "refinementDistanceData.H"
47 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
51 defineTypeNameAndDebug(hexRef8, 0);
53 //- Reduction class. If x and y are not equal assign value.
58 void operator()( label& x, const label& y ) const
66 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
68 void Foam::hexRef8::reorder
76 labelList newElems(len, null);
84 FatalErrorIn("hexRef8::reorder(..)") << abort(FatalError);
89 newElems[newI] = elems[i];
93 elems.transfer(newElems);
97 void Foam::hexRef8::getFaceInfo
107 if (!mesh_.isInternalFace(faceI))
109 patchID = mesh_.boundaryMesh().whichPatch(faceI);
112 zoneID = mesh_.faceZones().whichZone(faceI);
118 const faceZone& fZone = mesh_.faceZones()[zoneID];
120 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
125 // Adds a face on top of existing faceI.
126 Foam::label Foam::hexRef8::addFace
128 polyTopoChange& meshMod,
135 label patchID, zoneID, zoneFlip;
137 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
141 if ((nei == -1) || (own < nei))
144 newFaceI = meshMod.setAction
153 faceI, // master face for addition
155 patchID, // patch for face
156 zoneID, // zone for face
157 zoneFlip // face zone flip
163 // Reverse owner/neighbour
164 newFaceI = meshMod.setAction
168 newFace.reverseFace(), // face
173 faceI, // master face for addition
175 patchID, // patch for face
176 zoneID, // zone for face
177 zoneFlip // face zone flip
185 // Adds an internal face from an edge. Assumes orientation correct.
186 // Problem is that the face is between four new vertices. So what do we provide
187 // as master? The only existing mesh item we have is the edge we have split.
188 // Have to be careful in only using it if it has internal faces since otherwise
189 // polyMeshMorph will complain (because it cannot generate a sensible mapping
191 Foam::label Foam::hexRef8::addInternalFace
193 polyTopoChange& meshMod,
194 const label meshFaceI,
195 const label meshPointI,
201 if (mesh_.isInternalFace(meshFaceI))
203 return meshMod.setAction
212 meshFaceI, // master face for addition
214 -1, // patch for face
216 false // face zone flip
223 // - append (i.e. create out of nothing - will not be mapped)
224 // problem: field does not get mapped.
225 // - inflate from point.
226 // problem: does interpolative mapping which constructs full
227 // volPointInterpolation!
229 // For now create out of nothing
231 return meshMod.setAction
240 -1, // master face for addition
242 -1, // patch for face
244 false // face zone flip
249 ////- Inflate-from-point:
250 //// Check if point has any internal faces we can use.
251 //label masterPointI = -1;
253 //const labelList& pFaces = mesh_.pointFaces()[meshPointI];
257 // if (mesh_.isInternalFace(pFaces[i]))
259 // // meshPoint uses internal faces so ok to inflate from it
260 // masterPointI = meshPointI;
266 //return meshMod.setAction
273 // masterPointI, // master point
274 // -1, // master edge
275 // -1, // master face for addition
276 // false, // flux flip
277 // -1, // patch for face
278 // -1, // zone for face
279 // false // face zone flip
286 // Modifies existing faceI for either new owner/neighbour or new face points.
287 void Foam::hexRef8::modFace
289 polyTopoChange& meshMod,
296 label patchID, zoneID, zoneFlip;
298 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
302 (own != mesh_.faceOwner()[faceI])
304 mesh_.isInternalFace(faceI)
305 && (nei != mesh_.faceNeighbour()[faceI])
307 || (newFace != mesh_.faces()[faceI])
310 if ((nei == -1) || (own < nei))
316 newFace, // modified face
317 faceI, // label of face being modified
321 patchID, // patch for face
322 false, // remove from zone
323 zoneID, // zone for face
324 zoneFlip // face flip in zone
334 newFace.reverseFace(), // modified face
335 faceI, // label of face being modified
339 patchID, // patch for face
340 false, // remove from zone
341 zoneID, // zone for face
342 zoneFlip // face flip in zone
350 // Bit complex way to determine the unrefined edge length.
351 Foam::scalar Foam::hexRef8::getLevel0EdgeLength() const
353 // Determine minimum edge length per refinement level
354 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
356 const scalar GREAT2 = sqr(GREAT);
358 label nLevels = gMax(cellLevel_)+1;
360 scalarField typEdgeLenSqr(nLevels, GREAT2);
363 // 1. Look only at edges surrounded by cellLevel cells only.
364 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
367 // Per edge the cellLevel of connected cells. -1 if not set,
368 // labelMax if different levels, otherwise levels of connected cells.
369 labelList edgeLevel(mesh_.nEdges(), -1);
371 forAll(cellLevel_, cellI)
373 const label cLevel = cellLevel_[cellI];
375 const labelList& cEdges = mesh_.cellEdges()[cellI];
379 label edgeI = cEdges[i];
381 if (edgeLevel[edgeI] == -1)
383 edgeLevel[edgeI] = cLevel;
385 else if (edgeLevel[edgeI] == labelMax)
387 // Already marked as on different cellLevels
389 else if (edgeLevel[edgeI] != cLevel)
391 edgeLevel[edgeI] = labelMax;
396 // Make sure that edges with different levels on different processors
397 // are also marked. Do the same test (edgeLevel != cLevel) on coupled
399 syncTools::syncEdgeList
403 ifEqEqOp<labelMax>(),
405 false // no separation
408 // Now use the edgeLevel with a valid value to determine the
410 forAll(edgeLevel, edgeI)
412 const label eLevel = edgeLevel[edgeI];
414 if (eLevel >= 0 && eLevel < labelMax)
416 const edge& e = mesh_.edges()[edgeI];
418 scalar edgeLenSqr = magSqr(e.vec(mesh_.points()));
420 typEdgeLenSqr[eLevel] = min(typEdgeLenSqr[eLevel], edgeLenSqr);
425 // Get the minimum per level over all processors. Note minimum so if
426 // cells are not cubic we use the smallest edge side.
427 Pstream::listCombineGather(typEdgeLenSqr, minEqOp<scalar>());
428 Pstream::listCombineScatter(typEdgeLenSqr);
432 Pout<< "hexRef8::getLevel0EdgeLength() :"
433 << " After phase1: Edgelengths (squared) per refinementlevel:"
434 << typEdgeLenSqr << endl;
438 // 2. For any levels where we haven't determined a valid length yet
439 // use any surrounding cell level. Here we use the max so we don't
440 // pick up levels between celllevel and higher celllevel (will have
441 // edges sized according to highest celllevel)
442 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
444 scalarField maxEdgeLenSqr(nLevels, -GREAT2);
446 forAll(cellLevel_, cellI)
448 const label cLevel = cellLevel_[cellI];
450 const labelList& cEdges = mesh_.cellEdges()[cellI];
454 const edge& e = mesh_.edges()[cEdges[i]];
456 scalar edgeLenSqr = magSqr(e.vec(mesh_.points()));
458 maxEdgeLenSqr[cLevel] = max(maxEdgeLenSqr[cLevel], edgeLenSqr);
462 Pstream::listCombineGather(maxEdgeLenSqr, maxEqOp<scalar>());
463 Pstream::listCombineScatter(maxEdgeLenSqr);
467 Pout<< "hexRef8::getLevel0EdgeLength() :"
468 << " Crappy Edgelengths (squared) per refinementlevel:"
469 << maxEdgeLenSqr << endl;
473 // 3. Combine the two sets of lengths
474 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
476 forAll(typEdgeLenSqr, levelI)
478 if (typEdgeLenSqr[levelI] == GREAT2 && maxEdgeLenSqr[levelI] >= 0)
480 typEdgeLenSqr[levelI] = maxEdgeLenSqr[levelI];
486 Pout<< "hexRef8::getLevel0EdgeLength() :"
487 << " Final Edgelengths (squared) per refinementlevel:"
488 << typEdgeLenSqr << endl;
491 // Find lowest level present
492 scalar level0Size = -1;
494 forAll(typEdgeLenSqr, levelI)
496 scalar lenSqr = typEdgeLenSqr[levelI];
500 level0Size = Foam::sqrt(lenSqr)*(1<<levelI);
504 Pout<< "hexRef8::getLevel0EdgeLength() :"
505 << " For level:" << levelI
506 << " have edgeLen:" << Foam::sqrt(lenSqr)
507 << " with equivalent level0 len:" << level0Size
514 if (level0Size == -1)
516 FatalErrorIn("hexRef8::getLevel0EdgeLength()")
517 << "Problem : typEdgeLenSqr:" << typEdgeLenSqr << abort(FatalError);
524 // Check whether pointI is an anchor on cellI.
525 // If it is not check whether any other point on the face is an anchor cell.
526 Foam::label Foam::hexRef8::getAnchorCell
528 const labelListList& cellAnchorPoints,
529 const labelListList& cellAddedCells,
535 if (cellAnchorPoints[cellI].size() > 0)
537 label index = findIndex(cellAnchorPoints[cellI], pointI);
541 return cellAddedCells[cellI][index];
545 // pointI is not an anchor cell.
546 // Maybe we are already a refined face so check all the face
548 const face& f = mesh_.faces()[faceI];
552 label index = findIndex(cellAnchorPoints[cellI], f[fp]);
556 return cellAddedCells[cellI][index];
562 // Pick up points of the cell
563 const labelList cPoints(cellPoints(cellI));
565 Perr<< "cell:" << cellI << " points:" << endl;
568 label pointI = cPoints[i];
570 Perr<< " " << pointI << " coord:" << mesh_.points()[pointI]
573 Perr<< "cell:" << cellI << " anchorPoints:" << cellAnchorPoints[cellI]
576 FatalErrorIn("hexRef8::getAnchorCell(..)")
577 << "Could not find point " << pointI
578 << " in the anchorPoints for cell " << cellI << endl
579 << "Does your original mesh obey the 2:1 constraint and"
580 << " did you use consistentRefinement to make your cells to refine"
581 << " obey this constraint as well?"
582 << abort(FatalError);
593 // Get new owner and neighbour
594 void Foam::hexRef8::getFaceNeighbours
596 const labelListList& cellAnchorPoints,
597 const labelListList& cellAddedCells,
610 mesh_.faceOwner()[faceI],
615 if (mesh_.isInternalFace(faceI))
621 mesh_.faceNeighbour()[faceI],
633 // Get point with the lowest pointLevel
634 Foam::label Foam::hexRef8::findMinLevel(const labelList& f) const
636 label minLevel = labelMax;
641 label level = pointLevel_[f[fp]];
643 if (level < minLevel)
654 // Get point with the highest pointLevel
655 Foam::label Foam::hexRef8::findMaxLevel(const labelList& f) const
657 label maxLevel = labelMin;
662 label level = pointLevel_[f[fp]];
664 if (level > maxLevel)
675 Foam::label Foam::hexRef8::countAnchors
678 const label anchorLevel
685 if (pointLevel_[f[fp]] <= anchorLevel)
694 // Find point with certain pointLevel. Skip any higher levels.
695 Foam::label Foam::hexRef8::findLevel
699 const bool searchForward,
700 const label wantedLevel
707 label pointI = f[fp];
709 if (pointLevel_[pointI] < wantedLevel)
711 FatalErrorIn("hexRef8::findLevel")
713 << " level:" << IndirectList<label>(pointLevel_, f)()
714 << " startFp:" << startFp
715 << " wantedLevel:" << wantedLevel
716 << abort(FatalError);
718 else if (pointLevel_[pointI] == wantedLevel)
733 FatalErrorIn("hexRef8::findLevel")
735 << " level:" << IndirectList<label>(pointLevel_, f)()
736 << " startFp:" << startFp
737 << " wantedLevel:" << wantedLevel
738 << abort(FatalError);
744 // Gets cell level such that the face has four points <= level.
745 Foam::label Foam::hexRef8::getAnchorLevel(const label faceI) const
747 const face& f = mesh_.faces()[faceI];
751 return pointLevel_[f[findMaxLevel(f)]];
755 label ownLevel = cellLevel_[mesh_.faceOwner()[faceI]];
757 if (countAnchors(f, ownLevel) == 4)
761 else if (countAnchors(f, ownLevel+1) == 4)
767 //FatalErrorIn("hexRef8::getAnchorLevel(const label) const")
768 // << "face:" << faceI
769 // << " centre:" << mesh_.faceCentres()[faceI]
771 // << " point levels:" << IndirectList<label>(pointLevel_, f)()
772 // << " own:" << mesh_.faceOwner()[faceI]
773 // << " ownLevel:" << cellLevel_[mesh_.faceOwner()[faceI]]
774 // << abort(FatalError);
782 void Foam::hexRef8::checkInternalOrientation
784 polyTopoChange& meshMod,
792 face compactFace(identity(newFace.size()));
793 pointField compactPoints(IndirectList<point>(meshMod.points(), newFace)());
795 vector n(compactFace.normal(compactPoints));
797 vector dir(neiPt - ownPt);
801 FatalErrorIn("checkInternalOrientation(..)")
802 << "cell:" << cellI << " old face:" << faceI
803 << " newFace:" << newFace << endl
804 << " coords:" << compactPoints
805 << " ownPt:" << ownPt
806 << " neiPt:" << neiPt
807 << abort(FatalError);
810 vector fcToOwn(compactFace.centre(compactPoints) - ownPt);
812 scalar s = (fcToOwn&n) / (dir&n);
814 if (s < 0.1 || s > 0.9)
816 FatalErrorIn("checkInternalOrientation(..)")
817 << "cell:" << cellI << " old face:" << faceI
818 << " newFace:" << newFace << endl
819 << " coords:" << compactPoints
820 << " ownPt:" << ownPt
821 << " neiPt:" << neiPt
823 << abort(FatalError);
828 void Foam::hexRef8::checkBoundaryOrientation
830 polyTopoChange& meshMod,
834 const point& boundaryPt,
838 face compactFace(identity(newFace.size()));
839 pointField compactPoints(IndirectList<point>(meshMod.points(), newFace)());
841 vector n(compactFace.normal(compactPoints));
843 vector dir(boundaryPt - ownPt);
847 FatalErrorIn("checkBoundaryOrientation(..)")
848 << "cell:" << cellI << " old face:" << faceI
849 << " newFace:" << newFace
850 << " coords:" << compactPoints
851 << " ownPt:" << ownPt
852 << " boundaryPt:" << boundaryPt
853 << abort(FatalError);
856 vector fcToOwn(compactFace.centre(compactPoints) - ownPt);
858 scalar s = (fcToOwn&dir) / magSqr(dir);
860 if (s < 0.7 || s > 1.3)
862 WarningIn("checkBoundaryOrientation(..)")
863 << "cell:" << cellI << " old face:" << faceI
864 << " newFace:" << newFace
865 << " coords:" << compactPoints
866 << " ownPt:" << ownPt
867 << " boundaryPt:" << boundaryPt
870 //<< abort(FatalError);
875 // If p0 and p1 are existing vertices check if edge is split and insert
877 void Foam::hexRef8::insertEdgeSplit
879 const labelList& edgeMidPoint,
882 DynamicList<label>& verts
885 if (p0 < mesh_.nPoints() && p1 < mesh_.nPoints())
887 label edgeI = meshTools::findEdge(mesh_, p0, p1);
889 if (edgeI != -1 && edgeMidPoint[edgeI] != -1)
891 verts.append(edgeMidPoint[edgeI]);
897 // Internal faces are one per edge between anchor points. So one per midPoint
898 // between the anchor points. Here we store the information on the midPoint
899 // and if we have enough information:
901 // - two face mid points
902 // we add the face. Note that this routine can get called anywhere from
903 // two times (two unrefined faces) to four times (two refined faces) so
904 // the first call that adds the information creates the face.
905 Foam::label Foam::hexRef8::storeMidPointInfo
907 const labelListList& cellAnchorPoints,
908 const labelListList& cellAddedCells,
909 const labelList& cellMidPoint,
910 const labelList& edgeMidPoint,
913 const bool faceOrder,
914 const label edgeMidPointI,
915 const label anchorPointI,
916 const label faceMidPointI,
918 Map<edge>& midPointToAnchors,
919 Map<edge>& midPointToFaceMids,
920 polyTopoChange& meshMod
923 // See if need to store anchors.
925 bool changed = false;
926 bool haveTwoAnchors = false;
928 Map<edge>::iterator edgeMidFnd = midPointToAnchors.find(edgeMidPointI);
930 if (edgeMidFnd == midPointToAnchors.end())
932 midPointToAnchors.insert(edgeMidPointI, edge(anchorPointI, -1));
936 edge& e = edgeMidFnd();
938 if (anchorPointI != e[0])
947 if (e[0] != -1 && e[1] != -1)
949 haveTwoAnchors = true;
953 bool haveTwoFaceMids = false;
955 Map<edge>::iterator faceMidFnd = midPointToFaceMids.find(edgeMidPointI);
957 if (faceMidFnd == midPointToFaceMids.end())
959 midPointToFaceMids.insert(edgeMidPointI, edge(faceMidPointI, -1));
963 edge& e = faceMidFnd();
965 if (faceMidPointI != e[0])
969 e[1] = faceMidPointI;
974 if (e[0] != -1 && e[1] != -1)
976 haveTwoFaceMids = true;
980 // Check if this call of storeMidPointInfo is the one that completed all
981 // the nessecary information.
983 if (changed && haveTwoAnchors && haveTwoFaceMids)
985 const edge& anchors = midPointToAnchors[edgeMidPointI];
986 const edge& faceMids = midPointToFaceMids[edgeMidPointI];
988 label otherFaceMidPointI = faceMids.otherVertex(faceMidPointI);
990 // Create face consistent with anchorI being the owner.
991 // Note that the edges between the edge mid point and the face mids
992 // might be marked for splitting. Note that these edge splits cannot
993 // be between cellMid and face mids.
995 DynamicList<label> newFaceVerts(4);
996 if (faceOrder == (mesh_.faceOwner()[faceI] == cellI))
998 newFaceVerts.append(faceMidPointI);
1000 // Check & insert edge split if any
1004 faceMidPointI, // edge between faceMid and
1005 edgeMidPointI, // edgeMid
1009 newFaceVerts.append(edgeMidPointI);
1019 newFaceVerts.append(otherFaceMidPointI);
1020 newFaceVerts.append(cellMidPoint[cellI]);
1024 newFaceVerts.append(otherFaceMidPointI);
1034 newFaceVerts.append(edgeMidPointI);
1044 newFaceVerts.append(faceMidPointI);
1045 newFaceVerts.append(cellMidPoint[cellI]);
1049 newFace.transfer(newFaceVerts.shrink());
1050 newFaceVerts.clear();
1052 label anchorCell0 = getAnchorCell
1060 label anchorCell1 = getAnchorCell
1066 anchors.otherVertex(anchorPointI)
1073 if (anchorCell0 < anchorCell1)
1078 ownPt = mesh_.points()[anchorPointI];
1079 neiPt = mesh_.points()[anchors.otherVertex(anchorPointI)];
1086 newFace = newFace.reverseFace();
1088 ownPt = mesh_.points()[anchors.otherVertex(anchorPointI)];
1089 neiPt = mesh_.points()[anchorPointI];
1096 if (anchorCell0 < anchorCell1)
1098 ownPt = mesh_.points()[anchorPointI];
1099 neiPt = mesh_.points()[anchors.otherVertex(anchorPointI)];
1103 ownPt = mesh_.points()[anchors.otherVertex(anchorPointI)];
1104 neiPt = mesh_.points()[anchorPointI];
1107 checkInternalOrientation
1118 return addInternalFace
1135 // Creates all the 12 internal faces for cellI.
1136 void Foam::hexRef8::createInternalFaces
1138 const labelListList& cellAnchorPoints,
1139 const labelListList& cellAddedCells,
1140 const labelList& cellMidPoint,
1141 const labelList& faceMidPoint,
1142 const labelList& faceAnchorLevel,
1143 const labelList& edgeMidPoint,
1146 polyTopoChange& meshMod
1149 // Find in every face the cellLevel+1 points (from edge subdivision)
1150 // and the anchor points.
1152 const cell& cFaces = mesh_.cells()[cellI];
1153 const label cLevel = cellLevel_[cellI];
1155 // From edge mid to anchor points
1156 Map<edge> midPointToAnchors(24);
1157 // From edge mid to face mids
1158 Map<edge> midPointToFaceMids(24);
1160 // Running count of number of internal faces added so far.
1161 label nFacesAdded = 0;
1165 label faceI = cFaces[i];
1167 const face& f = mesh_.faces()[faceI];
1168 const labelList& fEdges = mesh_.faceEdges()[faceI];
1170 // We are on the cellI side of face f. The face will have 1 or 4
1171 // cLevel points and lots of higher numbered ones.
1173 label faceMidPointI = -1;
1175 label nAnchors = countAnchors(f, cLevel);
1179 // Only one anchor point. So the other side of the face has already
1180 // been split using cLevel+1 and cLevel+2 points.
1182 // Find the one anchor.
1183 label anchorFp = -1;
1187 if (pointLevel_[f[fp]] <= cLevel)
1194 // Now the face mid point is the second cLevel+1 point
1195 label edgeMid = findLevel(f, f.fcIndex(anchorFp), true, cLevel+1);
1196 label faceMid = findLevel(f, f.fcIndex(edgeMid), true, cLevel+1);
1198 faceMidPointI = f[faceMid];
1200 else if (nAnchors == 4)
1202 // There is no face middle yet but the face will be marked for
1205 faceMidPointI = faceMidPoint[faceI];
1209 FatalErrorIn("createInternalFaces")
1210 << "nAnchors:" << nAnchors
1211 << " faceI:" << faceI
1212 << abort(FatalError);
1217 // Now loop over all the anchors (might be just one) and store
1218 // the edge mids connected to it. storeMidPointInfo will collect
1219 // all the info and combine it all.
1223 label point0 = f[fp0];
1225 if (pointLevel_[point0] <= cLevel)
1231 // to cLevel+1 or edgeMidPoint of this level.
1234 label edgeMidPointI = -1;
1236 label fp1 = f.fcIndex(fp0);
1238 if (pointLevel_[f[fp1]] <= cLevel)
1240 // Anchor. Edge will be split.
1241 label edgeI = fEdges[fp0];
1243 edgeMidPointI = edgeMidPoint[edgeI];
1245 if (edgeMidPointI == -1)
1247 const labelList cPoints(cellPoints(cellI));
1249 FatalErrorIn("createInternalFaces(..)")
1250 << "cell:" << cellI << " cLevel:" << cLevel
1251 << " cell points:" << cPoints
1253 << IndirectList<label>(pointLevel_, cPoints)()
1254 << " face:" << faceI
1257 << IndirectList<label>(pointLevel_, f)()
1258 << " faceAnchorLevel:" << faceAnchorLevel[faceI]
1259 << " faceMidPoint:" << faceMidPoint[faceI]
1260 << " faceMidPointI:" << faceMidPointI
1262 << abort(FatalError);
1267 // Search forward in face to clevel+1
1268 label edgeMid = findLevel(f, fp1, true, cLevel+1);
1270 edgeMidPointI = f[edgeMid];
1273 label newFaceI = storeMidPointInfo
1282 true, // mid point after anchor
1283 edgeMidPointI, // edgemid
1296 if (nFacesAdded == 12)
1307 label fpMin1 = f.rcIndex(fp0);
1309 if (pointLevel_[f[fpMin1]] <= cLevel)
1311 // Anchor. Edge will be split.
1312 label edgeI = fEdges[fpMin1];
1314 edgeMidPointI = edgeMidPoint[edgeI];
1316 if (edgeMidPointI == -1)
1318 const labelList cPoints(cellPoints(cellI));
1320 FatalErrorIn("createInternalFaces(..)")
1321 << "cell:" << cellI << " cLevel:" << cLevel
1322 << " cell points:" << cPoints
1324 << IndirectList<label>(pointLevel_, cPoints)()
1325 << " face:" << faceI
1328 << IndirectList<label>(pointLevel_, f)()
1329 << " faceAnchorLevel:" << faceAnchorLevel[faceI]
1330 << " faceMidPoint:" << faceMidPoint[faceI]
1331 << " faceMidPointI:" << faceMidPointI
1333 << abort(FatalError);
1338 // Search back to clevel+1
1339 label edgeMid = findLevel(f, fpMin1, false, cLevel+1);
1341 edgeMidPointI = f[edgeMid];
1344 newFaceI = storeMidPointInfo
1353 false, // mid point before anchor
1354 edgeMidPointI, // edgemid
1367 if (nFacesAdded == 12)
1375 if (nFacesAdded == 12)
1383 void Foam::hexRef8::walkFaceToMid
1385 const labelList& edgeMidPoint,
1388 const label startFp,
1389 DynamicList<label>& faceVerts
1392 const face& f = mesh_.faces()[faceI];
1393 const labelList& fEdges = mesh_.faceEdges()[faceI];
1397 // Starting from fp store all (1 or 2) vertices until where the face
1402 if (edgeMidPoint[fEdges[fp]] >= 0)
1404 faceVerts.append(edgeMidPoint[fEdges[fp]]);
1409 if (pointLevel_[f[fp]] <= cLevel)
1411 // Next anchor. Have already append split point on edge in code
1415 else if (pointLevel_[f[fp]] == cLevel+1)
1418 faceVerts.append(f[fp]);
1422 else if (pointLevel_[f[fp]] == cLevel+2)
1424 // Store and continue to cLevel+1.
1425 faceVerts.append(f[fp]);
1431 // Same as walkFaceToMid but now walk back.
1432 void Foam::hexRef8::walkFaceFromMid
1434 const labelList& edgeMidPoint,
1437 const label startFp,
1438 DynamicList<label>& faceVerts
1441 const face& f = mesh_.faces()[faceI];
1442 const labelList& fEdges = mesh_.faceEdges()[faceI];
1444 label fp = f.rcIndex(startFp);
1448 if (pointLevel_[f[fp]] <= cLevel)
1453 else if (pointLevel_[f[fp]] == cLevel+1)
1456 faceVerts.append(f[fp]);
1459 else if (pointLevel_[f[fp]] == cLevel+2)
1461 // Continue to cLevel+1.
1469 if (edgeMidPoint[fEdges[fp]] >= 0)
1471 faceVerts.append(edgeMidPoint[fEdges[fp]]);
1480 faceVerts.append(f[fp]);
1485 // Updates refineCell (cells marked for refinement) so across all faces
1486 // there will be 2:1 consistency after refinement.
1487 Foam::label Foam::hexRef8::faceConsistentRefinement
1490 PackedList<1>& refineCell
1496 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1498 label own = mesh_.faceOwner()[faceI];
1499 label ownLevel = cellLevel_[own] + refineCell.get(own);
1501 label nei = mesh_.faceNeighbour()[faceI];
1502 label neiLevel = cellLevel_[nei] + refineCell.get(nei);
1504 if (ownLevel > (neiLevel+1))
1508 refineCell.set(nei, 1);
1512 refineCell.set(own, 0);
1516 else if (neiLevel > (ownLevel+1))
1520 refineCell.set(own, 1);
1524 refineCell.set(nei, 0);
1531 // Coupled faces. Swap owner level to get neighbouring cell level.
1532 // (only boundary faces of neiLevel used)
1533 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1537 label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1539 neiLevel[i] = cellLevel_[own] + refineCell.get(own);
1542 // Swap to neighbour
1543 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
1545 // Now we have neighbour value see which cells need refinement
1548 label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1549 label ownLevel = cellLevel_[own] + refineCell.get(own);
1551 if (ownLevel > (neiLevel[i]+1))
1555 refineCell.set(own, 0);
1559 else if (neiLevel[i] > (ownLevel+1))
1563 refineCell.set(own, 1);
1573 // Debug: check if wanted refinement is compatible with 2:1
1574 void Foam::hexRef8::checkWantedRefinementLevels
1576 const labelList& cellsToRefine
1579 PackedList<1> refineCell(mesh_.nCells(), 0);
1580 forAll(cellsToRefine, i)
1582 refineCell.set(cellsToRefine[i], 1);
1585 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1587 label own = mesh_.faceOwner()[faceI];
1588 label ownLevel = cellLevel_[own] + refineCell.get(own);
1590 label nei = mesh_.faceNeighbour()[faceI];
1591 label neiLevel = cellLevel_[nei] + refineCell.get(nei);
1593 if (mag(ownLevel-neiLevel) > 1)
1597 "hexRef8::checkWantedRefinementLevels(const labelList&)"
1599 << " current level:" << cellLevel_[own]
1600 << " level after refinement:" << ownLevel
1602 << "neighbour cell:" << nei
1603 << " current level:" << cellLevel_[nei]
1604 << " level after refinement:" << neiLevel
1606 << "which does not satisfy 2:1 constraints anymore."
1607 << abort(FatalError);
1611 // Coupled faces. Swap owner level to get neighbouring cell level.
1612 // (only boundary faces of neiLevel used)
1613 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1617 label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
1619 neiLevel[i] = cellLevel_[own] + refineCell.get(own);
1622 // Swap to neighbour
1623 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
1625 // Now we have neighbour value see which cells need refinement
1628 label faceI = i + mesh_.nInternalFaces();
1630 label own = mesh_.faceOwner()[faceI];
1631 label ownLevel = cellLevel_[own] + refineCell.get(own);
1633 if (mag(ownLevel - neiLevel[i]) > 1)
1635 label patchI = mesh_.boundaryMesh().whichPatch(faceI);
1639 "hexRef8::checkWantedRefinementLevels(const labelList&)"
1640 ) << "Celllevel does not satisfy 2:1 constraint."
1641 << " On coupled face "
1643 << " on patch " << patchI << " "
1644 << mesh_.boundaryMesh()[patchI].name()
1645 << " owner cell " << own
1646 << " current level:" << cellLevel_[own]
1647 << " level after refinement:" << ownLevel
1649 << " (coupled) neighbour cell will get refinement "
1651 << abort(FatalError);
1657 // Set instance for mesh files
1658 void Foam::hexRef8::setInstance(const fileName& inst)
1662 Pout<< "hexRef8::setInstance(const fileName& inst) : "
1663 << "Resetting file instance to " << inst << endl;
1666 cellLevel_.instance() = inst;
1667 pointLevel_.instance() = inst;
1668 history_.instance() = inst;
1672 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1674 // Construct from mesh, read refinement data
1675 Foam::hexRef8::hexRef8(const polyMesh& mesh)
1683 mesh_.facesInstance(),
1684 polyMesh::meshSubDir,
1686 IOobject::READ_IF_PRESENT,
1687 IOobject::AUTO_WRITE
1689 labelList(mesh_.nCells(), 0)
1696 mesh_.facesInstance(),
1697 polyMesh::meshSubDir,
1699 IOobject::READ_IF_PRESENT,
1700 IOobject::AUTO_WRITE
1702 labelList(mesh_.nPoints(), 0)
1704 level0Edge_(getLevel0EdgeLength()),
1709 "refinementHistory",
1710 mesh_.facesInstance(),
1711 polyMesh::meshSubDir,
1713 IOobject::READ_IF_PRESENT,
1714 IOobject::AUTO_WRITE
1716 mesh_.nCells() // All cells visible if could not be read
1718 faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
1719 savedPointLevel_(0),
1722 if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
1726 "hexRef8::hexRef8(const polyMesh&)"
1727 ) << "History enabled but number of visible cells in it "
1728 << history_.visibleCells().size()
1729 << " is not equal to the number of cells in the mesh "
1731 << abort(FatalError);
1736 cellLevel_.size() != mesh_.nCells()
1737 || pointLevel_.size() != mesh_.nPoints()
1742 "hexRef8::hexRef8(const polyMesh&)"
1743 ) << "Restarted from inconsistent cellLevel or pointLevel files."
1745 << "Number of cells in mesh:" << mesh_.nCells()
1746 << " does not equal size of cellLevel:" << cellLevel_.size() << endl
1747 << "Number of points in mesh:" << mesh_.nPoints()
1748 << " does not equal size of pointLevel:" << pointLevel_.size()
1749 << abort(FatalError);
1753 // Check refinement levels for consistency
1754 checkRefinementLevels(-1, labelList(0));
1757 // Check initial mesh for consistency
1766 // Construct from components
1767 Foam::hexRef8::hexRef8
1769 const polyMesh& mesh,
1770 const labelList& cellLevel,
1771 const labelList& pointLevel,
1772 const refinementHistory& history
1781 mesh_.facesInstance(),
1782 polyMesh::meshSubDir,
1785 IOobject::AUTO_WRITE
1794 mesh_.facesInstance(),
1795 polyMesh::meshSubDir,
1798 IOobject::AUTO_WRITE
1802 level0Edge_(getLevel0EdgeLength()),
1807 "refinementHistory",
1808 mesh_.facesInstance(),
1809 polyMesh::meshSubDir,
1812 IOobject::AUTO_WRITE
1816 faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
1817 savedPointLevel_(0),
1820 if (history_.active() && history_.visibleCells().size() != mesh_.nCells())
1824 "hexRef8::hexRef8(const polyMesh&, const labelList&"
1825 ", const labelList&, const refinementHistory&)"
1826 ) << "History enabled but number of visible cells in it "
1827 << history_.visibleCells().size()
1828 << " is not equal to the number of cells in the mesh "
1829 << mesh_.nCells() << abort(FatalError);
1834 cellLevel_.size() != mesh_.nCells()
1835 || pointLevel_.size() != mesh_.nPoints()
1840 "hexRef8::hexRef8(const polyMesh&, const labelList&"
1841 ", const labelList&, const refinementHistory&)"
1842 ) << "Incorrect cellLevel or pointLevel size." << endl
1843 << "Number of cells in mesh:" << mesh_.nCells()
1844 << " does not equal size of cellLevel:" << cellLevel_.size() << endl
1845 << "Number of points in mesh:" << mesh_.nPoints()
1846 << " does not equal size of pointLevel:" << pointLevel_.size()
1847 << abort(FatalError);
1850 // Check refinement levels for consistency
1851 checkRefinementLevels(-1, labelList(0));
1854 // Check initial mesh for consistency
1863 // Construct from components
1864 Foam::hexRef8::hexRef8
1866 const polyMesh& mesh,
1867 const labelList& cellLevel,
1868 const labelList& pointLevel
1877 mesh_.facesInstance(),
1878 polyMesh::meshSubDir,
1881 IOobject::AUTO_WRITE
1890 mesh_.facesInstance(),
1891 polyMesh::meshSubDir,
1894 IOobject::AUTO_WRITE
1898 level0Edge_(getLevel0EdgeLength()),
1903 "refinementHistory",
1904 mesh_.facesInstance(),
1905 polyMesh::meshSubDir,
1908 IOobject::AUTO_WRITE
1910 List<refinementHistory::splitCell8>(0),
1913 faceRemover_(mesh_, GREAT), // merge boundary faces wherever possible
1914 savedPointLevel_(0),
1919 cellLevel_.size() != mesh_.nCells()
1920 || pointLevel_.size() != mesh_.nPoints()
1925 "hexRef8::hexRef8(const polyMesh&, const labelList&"
1926 ", const labelList&)"
1927 ) << "Incorrect cellLevel or pointLevel size." << endl
1928 << "Number of cells in mesh:" << mesh_.nCells()
1929 << " does not equal size of cellLevel:" << cellLevel_.size() << endl
1930 << "Number of points in mesh:" << mesh_.nPoints()
1931 << " does not equal size of pointLevel:" << pointLevel_.size()
1932 << abort(FatalError);
1935 // Check refinement levels for consistency
1936 checkRefinementLevels(-1, labelList(0));
1938 // Check initial mesh for consistency
1947 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1949 //- Get points of a cell (without using cellPoints addressing)
1950 Foam::labelList Foam::hexRef8::cellPoints(const label cellI) const
1952 // Pick up points of the cell
1953 const cell& cFaces = mesh_.cells()[cellI];
1955 labelHashSet cPoints(4*cFaces.size());
1959 const face& f = mesh_.faces()[cFaces[i]];
1963 cPoints.insert(f[fp]);
1966 return cPoints.toc();
1970 Foam::labelList Foam::hexRef8::consistentRefinement
1972 const labelList& cellsToRefine,
1976 // Loop, modifying cellsToRefine, until no more changes to due to 2:1
1978 // maxSet = false : unselect cells to refine
1979 // maxSet = true : select cells to refine
1981 // Go to straight boolList.
1982 PackedList<1> refineCell(mesh_.nCells(), 0);
1983 forAll(cellsToRefine, i)
1985 refineCell.set(cellsToRefine[i], 1);
1990 label nChanged = faceConsistentRefinement(maxSet, refineCell);
1992 reduce(nChanged, sumOp<label>());
1996 Pout<< "hexRef8::consistentRefinement : Changed " << nChanged
1997 << " refinement levels due to 2:1 conflicts."
2008 // Convert back to labelList.
2011 forAll(refineCell, cellI)
2013 if (refineCell.get(cellI) == 1)
2019 labelList newCellsToRefine(nRefined);
2022 forAll(refineCell, cellI)
2024 if (refineCell.get(cellI) == 1)
2026 newCellsToRefine[nRefined++] = cellI;
2032 checkWantedRefinementLevels(newCellsToRefine);
2035 return newCellsToRefine;
2039 // Given a list of cells to refine determine additional cells to refine
2040 // such that the overall refinement:
2041 // - satisfies maxFaceDiff (e.g. 2:1) across neighbouring faces
2042 // - satisfies maxPointDiff (e.g. 4:1) across selected point connected
2043 // cells. This is used to ensure that e.g. cells on the surface are not
2044 // point connected to cells which are 8 times smaller.
2045 Foam::labelList Foam::hexRef8::consistentSlowRefinement
2047 const label maxFaceDiff,
2048 const labelList& cellsToRefine,
2049 const labelList& facesToCheck,
2050 const label maxPointDiff,
2051 const labelList& pointsToCheck
2054 const labelList& faceOwner = mesh_.faceOwner();
2055 const labelList& faceNeighbour = mesh_.faceNeighbour();
2058 if (maxFaceDiff <= 0)
2062 "hexRef8::consistentSlowRefinement"
2063 "(const label, const labelList&, const labelList&"
2064 ", const label, const labelList&)"
2065 ) << "Illegal maxFaceDiff " << maxFaceDiff << nl
2066 << "Value should be >= 1" << exit(FatalError);
2070 // Bit tricky. Say we want a distance of three cells between two
2071 // consecutive refinement levels. This is done by using FaceCellWave to
2072 // transport out the new refinement level. It gets decremented by one
2073 // every cell it crosses so if we initialize it to maxFaceDiff
2074 // we will get a field everywhere that tells us whether an unselected cell
2075 // needs refining as well.
2078 // Initial information about (distance to) cellLevel on all cells
2079 List<refinementData> allCellInfo(mesh_.nCells());
2081 // Initial information about (distance to) cellLevel on all faces
2082 List<refinementData> allFaceInfo(mesh_.nFaces());
2084 forAll(allCellInfo, cellI)
2086 // maxFaceDiff since refinementData counts both
2088 allCellInfo[cellI] = refinementData
2090 maxFaceDiff*(cellLevel_[cellI]+1),// when cell is to be refined
2091 maxFaceDiff*cellLevel_[cellI] // current level
2095 // Cells to be refined will have cellLevel+1
2096 forAll(cellsToRefine, i)
2098 label cellI = cellsToRefine[i];
2100 allCellInfo[cellI].count() = allCellInfo[cellI].refinementCount();
2104 // Labels of seed faces
2105 DynamicList<label> seedFaces(mesh_.nFaces()/100);
2106 // refinementLevel data on seed faces
2107 DynamicList<refinementData> seedFacesInfo(mesh_.nFaces()/100);
2110 // Additional buffer layer thickness by changing initial count. Usually
2111 // this happens on boundary faces. Bit tricky. Use allFaceInfo to mark
2112 // off thus marked faces so they're skipped in the next loop.
2113 forAll(facesToCheck, i)
2115 label faceI = facesToCheck[i];
2117 if (allFaceInfo[faceI].valid())
2119 // Can only occur if face has already gone through loop below.
2122 "hexRef8::consistentSlowRefinement"
2123 "(const label, const labelList&, const labelList&"
2124 ", const label, const labelList&)"
2125 ) << "Argument facesToCheck seems to have duplicate entries!"
2127 << "face:" << faceI << " occurs at positions "
2128 << findIndices(facesToCheck, faceI)
2129 << abort(FatalError);
2133 const refinementData& ownData = allCellInfo[faceOwner[faceI]];
2135 if (mesh_.isInternalFace(faceI))
2137 // Seed face if neighbouring cell (after possible refinement)
2138 // will be refined one more than the current owner or neighbour.
2140 const refinementData& neiData = allCellInfo[faceNeighbour[faceI]];
2143 label faceRefineCount;
2144 if (neiData.count() > ownData.count())
2146 faceCount = neiData.count() + maxFaceDiff;
2147 faceRefineCount = faceCount + maxFaceDiff;
2151 faceCount = ownData.count() + maxFaceDiff;
2152 faceRefineCount = faceCount + maxFaceDiff;
2155 seedFaces.append(faceI);
2156 seedFacesInfo.append
2164 allFaceInfo[faceI] = seedFacesInfo[seedFacesInfo.size()-1];
2168 label faceCount = ownData.count() + maxFaceDiff;
2169 label faceRefineCount = faceCount + maxFaceDiff;
2171 seedFaces.append(faceI);
2172 seedFacesInfo.append
2180 allFaceInfo[faceI] = seedFacesInfo[seedFacesInfo.size()-1];
2185 // Just seed with all faces inbetween different refinement levels for now
2186 // (alternatively only seed faces on cellsToRefine but that gives problems
2187 // if no cells to refine)
2188 forAll(faceNeighbour, faceI)
2190 // Check if face already handled in loop above
2191 if (!allFaceInfo[faceI].valid())
2193 label own = faceOwner[faceI];
2194 label nei = faceNeighbour[faceI];
2196 // Seed face with transported data from highest cell.
2198 if (allCellInfo[own].count() > allCellInfo[nei].count())
2200 allFaceInfo[faceI].updateFace
2206 FaceCellWave<refinementData>::propagationTol()
2208 seedFaces.append(faceI);
2209 seedFacesInfo.append(allFaceInfo[faceI]);
2211 else if (allCellInfo[own].count() < allCellInfo[nei].count())
2213 allFaceInfo[faceI].updateFace
2219 FaceCellWave<refinementData>::propagationTol()
2221 seedFaces.append(faceI);
2222 seedFacesInfo.append(allFaceInfo[faceI]);
2227 // Seed all boundary faces with owner value. This is to make sure that
2228 // they are visited (probably only important for coupled faces since
2229 // these need to be visited from both sides)
2230 for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
2232 // Check if face already handled in loop above
2233 if (!allFaceInfo[faceI].valid())
2235 label own = faceOwner[faceI];
2237 // Seed face with transported data from owner.
2238 refinementData faceData;
2245 FaceCellWave<refinementData>::propagationTol()
2247 seedFaces.append(faceI);
2248 seedFacesInfo.append(faceData);
2253 // face-cell-face transport engine
2254 FaceCellWave<refinementData> levelCalc
2265 Pout<< "hexRef8::consistentSlowRefinement : Seeded "
2266 << seedFaces.size() << " faces between cells with different"
2267 << " refinement level." << endl;
2271 levelCalc.setFaceInfo(seedFaces.shrink(), seedFacesInfo.shrink());
2273 seedFacesInfo.clear();
2275 // Iterate until no change. Now 2:1 face difference should be satisfied
2276 levelCalc.iterate(mesh_.globalData().nTotalFaces());
2279 // Now check point-connected cells (face-connected cells already ok):
2280 // - get per point max of connected cells
2281 // - sync across coupled points
2282 // - check cells against above point max
2284 if (maxPointDiff == -1)
2286 // No need to do any point checking.
2290 // Determine per point the max cell level. (done as count, not
2291 // as cell level purely for ease)
2292 labelList maxPointCount(mesh_.nPoints(), 0);
2294 const labelListList& pointCells = mesh_.pointCells();
2296 forAll(pointCells, pointI)
2298 label& pLevel = maxPointCount[pointI];
2300 const labelList& pCells = pointCells[pointI];
2304 pLevel = max(pLevel, allCellInfo[pCells[i]].count());
2308 // Sync maxPointCount to neighbour
2309 syncTools::syncPointList
2314 labelMin, // null value
2315 false // no separation
2318 // Update allFaceInfo from maxPointCount for all points to check
2319 // (usually on boundary faces)
2321 // Per face the new refinement data
2322 Map<refinementData> changedFacesInfo(pointsToCheck.size());
2324 forAll(pointsToCheck, i)
2326 label pointI = pointsToCheck[i];
2328 // Loop over all cells using the point and check whether their
2329 // refinement level is much less than the maximum.
2331 const labelList& pCells = pointCells[pointI];
2333 forAll(pCells, pCellI)
2335 label cellI = pCells[pCellI];
2337 refinementData& cellInfo = allCellInfo[cellI];
2341 !cellInfo.isRefined()
2343 maxPointCount[pointI]
2344 > cellInfo.count() + maxFaceDiff*maxPointDiff
2348 // Mark cell for refinement
2349 cellInfo.count() = cellInfo.refinementCount();
2351 // Insert faces of cell as seed faces.
2352 const cell& cFaces = mesh_.cells()[cellI];
2354 forAll(cFaces, cFaceI)
2356 label faceI = cFaces[cFaceI];
2358 refinementData faceData;
2365 FaceCellWave<refinementData>::propagationTol()
2368 if (faceData.count() > allFaceInfo[faceI].count())
2370 changedFacesInfo.insert(faceI, faceData);
2377 label nChanged = changedFacesInfo.size();
2378 reduce(nChanged, sumOp<label>());
2386 // Transfer into seedFaces, seedFacesInfo
2387 seedFaces.setSize(changedFacesInfo.size());
2388 seedFacesInfo.setSize(changedFacesInfo.size());
2390 forAllConstIter(Map<refinementData>, changedFacesInfo, iter)
2392 seedFaces.append(iter.key());
2393 seedFacesInfo.append(iter());
2400 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
2402 label own = mesh_.faceOwner()[faceI];
2405 + (allCellInfo[own].isRefined() ? 1 : 0);
2407 label nei = mesh_.faceNeighbour()[faceI];
2410 + (allCellInfo[nei].isRefined() ? 1 : 0);
2412 if (mag(ownLevel-neiLevel) > 1)
2416 "hexRef8::consistentSlowRefinement"
2418 << " current level:" << cellLevel_[own]
2419 << " current refData:" << allCellInfo[own]
2420 << " level after refinement:" << ownLevel
2422 << "neighbour cell:" << nei
2423 << " current level:" << cellLevel_[nei]
2424 << " current refData:" << allCellInfo[nei]
2425 << " level after refinement:" << neiLevel
2427 << "which does not satisfy 2:1 constraints anymore." << nl
2428 << "face:" << faceI << " faceRefData:" << allFaceInfo[faceI]
2429 << abort(FatalError);
2434 // Coupled faces. Swap owner level to get neighbouring cell level.
2435 // (only boundary faces of neiLevel used)
2437 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2438 labelList neiCount(mesh_.nFaces()-mesh_.nInternalFaces());
2439 labelList neiRefCount(mesh_.nFaces()-mesh_.nInternalFaces());
2443 label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
2444 neiLevel[i] = cellLevel_[own];
2445 neiCount[i] = allCellInfo[own].count();
2446 neiRefCount[i] = allCellInfo[own].refinementCount();
2449 // Swap to neighbour
2450 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
2451 syncTools::swapBoundaryFaceList(mesh_, neiCount, false);
2452 syncTools::swapBoundaryFaceList(mesh_, neiRefCount, false);
2454 // Now we have neighbour value see which cells need refinement
2457 label faceI = i+mesh_.nInternalFaces();
2459 label own = mesh_.faceOwner()[faceI];
2462 + (allCellInfo[own].isRefined() ? 1 : 0);
2466 + ((neiCount[i] >= neiRefCount[i]) ? 1 : 0);
2468 if (mag(ownLevel - nbrLevel) > 1)
2470 label patchI = mesh_.boundaryMesh().whichPatch(faceI);
2474 "hexRef8::consistentSlowRefinement"
2475 "(const label, const labelList&, const labelList&"
2476 ", const label, const labelList&)"
2477 ) << "Celllevel does not satisfy 2:1 constraint."
2478 << " On coupled face "
2480 << " refData:" << allFaceInfo[faceI]
2481 << " on patch " << patchI << " "
2482 << mesh_.boundaryMesh()[patchI].name() << nl
2483 << "owner cell " << own
2484 << " current level:" << cellLevel_[own]
2485 << " current count:" << allCellInfo[own].count()
2486 << " current refCount:"
2487 << allCellInfo[own].refinementCount()
2488 << " level after refinement:" << ownLevel
2490 << "(coupled) neighbour cell"
2491 << " has current level:" << neiLevel[i]
2492 << " current count:" << neiCount[i]
2493 << " current refCount:" << neiRefCount[i]
2494 << " level after refinement:" << nbrLevel
2495 << abort(FatalError);
2500 // Convert back to labelList of cells to refine.
2504 forAll(allCellInfo, cellI)
2506 if (allCellInfo[cellI].isRefined())
2512 // Updated list of cells to refine
2513 labelList newCellsToRefine(nRefined);
2516 forAll(allCellInfo, cellI)
2518 if (allCellInfo[cellI].isRefined())
2520 newCellsToRefine[nRefined++] = cellI;
2526 Pout<< "hexRef8::consistentSlowRefinement : From "
2527 << cellsToRefine.size() << " to " << newCellsToRefine.size()
2528 << " cells to refine." << endl;
2531 return newCellsToRefine;
2535 Foam::labelList Foam::hexRef8::consistentSlowRefinement2
2537 const label maxFaceDiff,
2538 const labelList& cellsToRefine,
2539 const labelList& facesToCheck
2542 const labelList& faceOwner = mesh_.faceOwner();
2543 const labelList& faceNeighbour = mesh_.faceNeighbour();
2545 if (maxFaceDiff <= 0)
2549 "hexRef8::consistentSlowRefinement2"
2550 "(const label, const labelList&, const labelList&)"
2551 ) << "Illegal maxFaceDiff " << maxFaceDiff << nl
2552 << "Value should be >= 1" << exit(FatalError);
2555 const scalar level0Size = 2*maxFaceDiff*level0Edge_;
2558 // Bit tricky. Say we want a distance of three cells between two
2559 // consecutive refinement levels. This is done by using FaceCellWave to
2560 // transport out the 'refinement shell'. Anything inside the refinement
2561 // shell (given by a distance) gets marked for refinement.
2563 // Initial information about (distance to) cellLevel on all cells
2564 List<refinementDistanceData> allCellInfo(mesh_.nCells());
2566 // Initial information about (distance to) cellLevel on all faces
2567 List<refinementDistanceData> allFaceInfo(mesh_.nFaces());
2570 // Mark cells with wanted refinement level
2571 forAll(cellsToRefine, i)
2573 label cellI = cellsToRefine[i];
2575 allCellInfo[cellI] = refinementDistanceData
2578 mesh_.cellCentres()[cellI],
2579 cellLevel_[cellI]+1 // wanted refinement
2582 // Mark all others with existing refinement level
2583 forAll(allCellInfo, cellI)
2585 if (!allCellInfo[cellI].valid())
2587 allCellInfo[cellI] = refinementDistanceData
2590 mesh_.cellCentres()[cellI],
2591 cellLevel_[cellI] // wanted refinement
2597 // Labels of seed faces
2598 DynamicList<label> seedFaces(mesh_.nFaces()/100);
2599 // refinementLevel data on seed faces
2600 DynamicList<refinementDistanceData> seedFacesInfo(mesh_.nFaces()/100);
2603 const pointField& cc = mesh_.cellCentres();
2605 forAll(facesToCheck, i)
2607 label faceI = facesToCheck[i];
2609 if (allFaceInfo[faceI].valid())
2611 // Can only occur if face has already gone through loop below.
2614 "hexRef8::consistentSlowRefinement2"
2615 "(const label, const labelList&, const labelList&)"
2616 ) << "Argument facesToCheck seems to have duplicate entries!"
2618 << "face:" << faceI << " occurs at positions "
2619 << findIndices(facesToCheck, faceI)
2620 << abort(FatalError);
2623 label own = faceOwner[faceI];
2627 allCellInfo[own].valid()
2628 ? allCellInfo[own].originLevel()
2632 if (!mesh_.isInternalFace(faceI))
2634 // Do as if boundary face would have neighbour with one higher
2635 // refinement level.
2636 const point& fc = mesh_.faceCentres()[faceI];
2638 refinementDistanceData neiData
2641 2*fc - cc[own], // est'd cell centre
2645 allFaceInfo[faceI].updateFace
2649 own, // not used (should be nei)
2651 FaceCellWave<refinementDistanceData>::propagationTol()
2656 label nei = faceNeighbour[faceI];
2660 allCellInfo[nei].valid()
2661 ? allCellInfo[nei].originLevel()
2665 if (ownLevel == neiLevel)
2667 // Fake as if nei>own or own>nei (whichever one 'wins')
2668 allFaceInfo[faceI].updateFace
2673 refinementDistanceData(level0Size, cc[nei], neiLevel+1),
2674 FaceCellWave<refinementDistanceData>::propagationTol()
2676 allFaceInfo[faceI].updateFace
2681 refinementDistanceData(level0Size, cc[own], ownLevel+1),
2682 FaceCellWave<refinementDistanceData>::propagationTol()
2687 // Difference in level anyway.
2688 allFaceInfo[faceI].updateFace
2693 refinementDistanceData(level0Size, cc[nei], neiLevel),
2694 FaceCellWave<refinementDistanceData>::propagationTol()
2696 allFaceInfo[faceI].updateFace
2701 refinementDistanceData(level0Size, cc[own], ownLevel),
2702 FaceCellWave<refinementDistanceData>::propagationTol()
2706 seedFaces.append(faceI);
2707 seedFacesInfo.append(allFaceInfo[faceI]);
2711 // Create some initial seeds to start walking from. This is only if there
2712 // are no facesToCheck.
2713 // Just seed with all faces inbetween different refinement levels for now
2714 forAll(faceNeighbour, faceI)
2716 // Check if face already handled in loop above
2717 if (!allFaceInfo[faceI].valid())
2719 label own = faceOwner[faceI];
2723 allCellInfo[own].valid()
2724 ? allCellInfo[own].originLevel()
2728 label nei = faceNeighbour[faceI];
2732 allCellInfo[nei].valid()
2733 ? allCellInfo[nei].originLevel()
2737 if (ownLevel > neiLevel)
2739 // Set face to owner data. (since face not yet would be copy)
2740 seedFaces.append(faceI);
2741 allFaceInfo[faceI].updateFace
2746 refinementDistanceData(level0Size, cc[own], ownLevel),
2747 FaceCellWave<refinementDistanceData>::propagationTol()
2749 seedFacesInfo.append(allFaceInfo[faceI]);
2751 else if (neiLevel > ownLevel)
2753 seedFaces.append(faceI);
2754 allFaceInfo[faceI].updateFace
2759 refinementDistanceData(level0Size, cc[nei], neiLevel),
2760 FaceCellWave<refinementDistanceData>::propagationTol()
2762 seedFacesInfo.append(allFaceInfo[faceI]);
2768 seedFacesInfo.shrink();
2770 // face-cell-face transport engine
2771 FaceCellWave<refinementDistanceData> levelCalc
2778 mesh_.globalData().nTotalCells()
2784 // // Dump wanted level
2785 // volScalarField wantedLevel
2790 // fMesh.time().timeName(),
2792 // IOobject::NO_READ,
2793 // IOobject::AUTO_WRITE,
2797 // dimensionedScalar("zero", dimless, 0)
2800 // forAll(wantedLevel, cellI)
2802 // wantedLevel[cellI] = allCellInfo[cellI].wantedLevel(cc[cellI]);
2805 // Pout<< "Writing " << wantedLevel.objectPath() << endl;
2806 // wantedLevel.write();
2810 // Convert back to labelList of cells to refine.
2811 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2813 // 1. Force original refinement cells to be picked up by setting the
2814 // originLevel of input cells to be a very large level (but within range
2815 // of 1<< shift inside refinementDistanceData::wantedLevel)
2816 forAll(cellsToRefine, i)
2818 label cellI = cellsToRefine[i];
2820 allCellInfo[cellI].originLevel() = sizeof(label)*8-2;
2821 allCellInfo[cellI].origin() = cc[cellI];
2824 // 2. Extend to 2:1. For non-cube cells the scalar distance does not work
2825 // so make sure it at least provides 2:1.
2826 PackedList<1> refineCell(mesh_.nCells(), 0);
2827 forAll(allCellInfo, cellI)
2829 label wanted = allCellInfo[cellI].wantedLevel(cc[cellI]);
2831 if (wanted > cellLevel_[cellI]+1)
2833 refineCell.set(cellI, 1);
2839 label nChanged = faceConsistentRefinement(true, refineCell);
2841 reduce(nChanged, sumOp<label>());
2845 Pout<< "hexRef8::consistentSlowRefinement2 : Changed " << nChanged
2846 << " refinement levels due to 2:1 conflicts."
2856 // 3. Convert back to labelList.
2859 forAll(refineCell, cellI)
2861 if (refineCell.get(cellI) == 1)
2867 labelList newCellsToRefine(nRefined);
2870 forAll(refineCell, cellI)
2872 if (refineCell.get(cellI) == 1)
2874 newCellsToRefine[nRefined++] = cellI;
2880 Pout<< "hexRef8::consistentSlowRefinement2 : From "
2881 << cellsToRefine.size() << " to " << newCellsToRefine.size()
2882 << " cells to refine." << endl;
2884 // Check that newCellsToRefine obeys at least 2:1.
2887 cellSet cellsIn(mesh_, "cellsToRefineIn", cellsToRefine);
2888 Pout<< "hexRef8::consistentSlowRefinement2 : writing "
2889 << cellsIn.size() << " to cellSet "
2890 << cellsIn.objectPath() << endl;
2894 cellSet cellsOut(mesh_, "cellsToRefineOut", newCellsToRefine);
2895 Pout<< "hexRef8::consistentSlowRefinement2 : writing "
2896 << cellsOut.size() << " to cellSet "
2897 << cellsOut.objectPath() << endl;
2902 PackedList<1> refineCell(mesh_.nCells(), 0);
2903 forAll(newCellsToRefine, i)
2905 refineCell.set(newCellsToRefine[i], 1);
2907 const PackedList<1> savedRefineCell(refineCell);
2909 label nChanged = faceConsistentRefinement(true, refineCell);
2914 mesh_, "cellsToRefineOut2", newCellsToRefine.size()
2916 forAll(refineCell, cellI)
2918 if (refineCell.get(cellI) == 1)
2920 cellsOut2.insert(cellI);
2923 Pout<< "hexRef8::consistentSlowRefinement2 : writing "
2924 << cellsOut2.size() << " to cellSet "
2925 << cellsOut2.objectPath() << endl;
2931 forAll(refineCell, cellI)
2935 refineCell.get(cellI) == 1
2936 && savedRefineCell.get(cellI) == 0
2941 "hexRef8::consistentSlowRefinement2"
2942 "(const label, const labelList&, const labelList&)"
2943 ) << "Cell:" << cellI << " cc:"
2944 << mesh_.cellCentres()[cellI]
2945 << " was not marked for refinement but does not obey"
2946 << " 2:1 constraints."
2947 << abort(FatalError);
2953 return newCellsToRefine;
2957 // Top level driver to insert topo changes to do all refinement.
2958 Foam::labelListList Foam::hexRef8::setRefinement
2960 const labelList& cellLabels,
2961 polyTopoChange& meshMod
2966 Pout<< "hexRef8::setRefinement :"
2967 << " Checking initial mesh just to make sure" << endl;
2970 checkRefinementLevels(-1, labelList(0));
2973 // Clear any saved point/cell data.
2974 savedPointLevel_.clear();
2975 savedCellLevel_.clear();
2978 // New point/cell level. Copy of pointLevel for existing points.
2979 DynamicList<label> newCellLevel(cellLevel_.size());
2980 forAll(cellLevel_, cellI)
2982 newCellLevel.append(cellLevel_[cellI]);
2984 DynamicList<label> newPointLevel(pointLevel_.size());
2985 forAll(pointLevel_, pointI)
2987 newPointLevel.append(pointLevel_[pointI]);
2993 Pout<< "hexRef8::setRefinement :"
2994 << " Allocating " << cellLabels.size() << " cell midpoints."
2999 // Mid point per refined cell.
3001 // >=0: label of mid point.
3002 labelList cellMidPoint(mesh_.nCells(), -1);
3004 forAll(cellLabels, i)
3006 label cellI = cellLabels[i];
3008 label anchorPointI = mesh_.faces()[mesh_.cells()[cellI][0]][0];
3010 cellMidPoint[cellI] = meshMod.setAction
3014 mesh_.cellCentres()[cellI], // point
3015 anchorPointI, // master point
3016 -1, // zone for point
3017 true // supports a cell
3021 newPointLevel(cellMidPoint[cellI]) = cellLevel_[cellI]+1;
3027 cellSet splitCells(mesh_, "splitCells", cellLabels.size());
3029 forAll(cellMidPoint, cellI)
3031 if (cellMidPoint[cellI] >= 0)
3033 splitCells.insert(cellI);
3037 Pout<< "hexRef8::setRefinement : Dumping " << splitCells.size()
3038 << " cells to split to cellSet " << splitCells.objectPath()
3051 Pout<< "hexRef8::setRefinement :"
3052 << " Allocating edge midpoints."
3056 // Unrefined edges are ones between cellLevel or lower points.
3057 // If any cell using this edge gets split then the edge needs to be split.
3059 // -1 : no need to split edge
3060 // >=0 : label of introduced mid point
3061 labelList edgeMidPoint(mesh_.nEdges(), -1);
3063 // Note: Loop over cells to be refined or edges?
3064 forAll(cellMidPoint, cellI)
3066 if (cellMidPoint[cellI] >= 0)
3068 const labelList& cEdges = mesh_.cellEdges()[cellI];
3072 label edgeI = cEdges[i];
3074 const edge& e = mesh_.edges()[edgeI];
3078 pointLevel_[e[0]] <= cellLevel_[cellI]
3079 && pointLevel_[e[1]] <= cellLevel_[cellI]
3082 edgeMidPoint[edgeI] = 12345; // mark need for splitting
3088 // Synchronize edgeMidPoint across coupled patches. Take max so that
3089 // any split takes precedence.
3090 syncTools::syncEdgeList
3096 false // no separation
3100 // Introduce edge points
3101 // ~~~~~~~~~~~~~~~~~~~~~
3104 // Phase 1: calculate midpoints and sync.
3105 // This needs doing for if people do not write binary and we slowly
3108 pointField edgeMids(mesh_.nEdges(), point(-GREAT, -GREAT, -GREAT));
3110 forAll(edgeMidPoint, edgeI)
3112 if (edgeMidPoint[edgeI] >= 0)
3114 // Edge marked to be split.
3115 edgeMids[edgeI] = mesh_.edges()[edgeI].centre(mesh_.points());
3118 syncTools::syncEdgeList
3123 point(-GREAT, -GREAT, -GREAT),
3124 true // apply separation
3128 // Phase 2: introduce points at the synced locations.
3129 forAll(edgeMidPoint, edgeI)
3131 if (edgeMidPoint[edgeI] >= 0)
3133 // Edge marked to be split. Replace edgeMidPoint with actual
3136 const edge& e = mesh_.edges()[edgeI];
3138 edgeMidPoint[edgeI] = meshMod.setAction
3142 edgeMids[edgeI], // point
3143 e[0], // master point
3144 -1, // zone for point
3145 true // supports a cell
3149 newPointLevel(edgeMidPoint[edgeI]) =
3162 OFstream str(mesh_.time().path()/"edgeMidPoint.obj");
3164 forAll(edgeMidPoint, edgeI)
3166 if (edgeMidPoint[edgeI] >= 0)
3168 const edge& e = mesh_.edges()[edgeI];
3170 meshTools::writeOBJ(str, e.centre(mesh_.points()));
3174 Pout<< "hexRef8::setRefinement :"
3175 << " Dumping edge centres to split to file " << str.name() << endl;
3179 // Calculate face level
3180 // ~~~~~~~~~~~~~~~~~~~~
3181 // (after splitting)
3185 Pout<< "hexRef8::setRefinement :"
3186 << " Allocating face midpoints."
3190 // Face anchor level. There are guaranteed 4 points with level
3191 // <= anchorLevel. These are the corner points.
3192 labelList faceAnchorLevel(mesh_.nFaces());
3194 for (label faceI = 0; faceI < mesh_.nFaces(); faceI++)
3196 faceAnchorLevel[faceI] = getAnchorLevel(faceI);
3199 // -1 : no need to split face
3200 // >=0 : label of introduced mid point
3201 labelList faceMidPoint(mesh_.nFaces(), -1);
3204 // Internal faces: look at cells on both sides. Uniquely determined since
3205 // face itself guaranteed to be same level as most refined neighbour.
3206 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
3208 if (faceAnchorLevel[faceI] >= 0)
3210 label own = mesh_.faceOwner()[faceI];
3211 label ownLevel = cellLevel_[own];
3212 label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3214 label nei = mesh_.faceNeighbour()[faceI];
3215 label neiLevel = cellLevel_[nei];
3216 label newNeiLevel = neiLevel + (cellMidPoint[nei] >= 0 ? 1 : 0);
3220 newOwnLevel > faceAnchorLevel[faceI]
3221 || newNeiLevel > faceAnchorLevel[faceI]
3224 faceMidPoint[faceI] = 12345; // mark to be split
3229 // Coupled patches handled like internal faces except now all information
3230 // from neighbour comes from across processor.
3231 // Boundary faces are more complicated since the boundary face can
3232 // be more refined than its owner (or neighbour for coupled patches)
3233 // (does not happen if refining/unrefining only, but does e.g. when
3234 // refinining and subsetting)
3237 labelList newNeiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
3239 forAll(newNeiLevel, i)
3241 label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
3242 label ownLevel = cellLevel_[own];
3243 label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3245 newNeiLevel[i] = newOwnLevel;
3249 syncTools::swapBoundaryFaceList(mesh_, newNeiLevel, false);
3251 // So now we have information on the neighbour.
3253 forAll(newNeiLevel, i)
3255 label faceI = i+mesh_.nInternalFaces();
3257 if (faceAnchorLevel[faceI] >= 0)
3259 label own = mesh_.faceOwner()[faceI];
3260 label ownLevel = cellLevel_[own];
3261 label newOwnLevel = ownLevel + (cellMidPoint[own] >= 0 ? 1 : 0);
3265 newOwnLevel > faceAnchorLevel[faceI]
3266 || newNeiLevel[i] > faceAnchorLevel[faceI]
3269 faceMidPoint[faceI] = 12345; // mark to be split
3276 // Synchronize faceMidPoint across coupled patches. (logical or)
3277 syncTools::syncFaceList
3287 // Introduce face points
3288 // ~~~~~~~~~~~~~~~~~~~~~
3291 // Phase 1: determine mid points and sync. See comment for edgeMids
3293 pointField bFaceMids
3295 mesh_.nFaces()-mesh_.nInternalFaces(),
3296 point(-GREAT, -GREAT, -GREAT)
3299 forAll(bFaceMids, i)
3301 label faceI = i+mesh_.nInternalFaces();
3303 if (faceMidPoint[faceI] >= 0)
3305 bFaceMids[i] = mesh_.faceCentres()[faceI];
3308 syncTools::syncBoundaryFaceList
3313 true // apply separation
3316 forAll(faceMidPoint, faceI)
3318 if (faceMidPoint[faceI] >= 0)
3320 // Face marked to be split. Replace faceMidPoint with actual
3323 const face& f = mesh_.faces()[faceI];
3325 faceMidPoint[faceI] = meshMod.setAction
3330 faceI < mesh_.nInternalFaces()
3331 ? mesh_.faceCentres()[faceI]
3332 : bFaceMids[faceI-mesh_.nInternalFaces()]
3334 f[0], // master point
3335 -1, // zone for point
3336 true // supports a cell
3340 // Determine the level of the corner points and midpoint will
3342 newPointLevel(faceMidPoint[faceI]) = faceAnchorLevel[faceI]+1;
3349 faceSet splitFaces(mesh_, "splitFaces", cellLabels.size());
3351 forAll(faceMidPoint, faceI)
3353 if (faceMidPoint[faceI] >= 0)
3355 splitFaces.insert(faceI);
3359 Pout<< "hexRef8::setRefinement : Dumping " << splitFaces.size()
3360 << " faces to split to faceSet " << splitFaces.objectPath() << endl;
3366 // Information complete
3367 // ~~~~~~~~~~~~~~~~~~~~
3368 // At this point we have all the information we need. We should no
3369 // longer reference the cellLabels to refine. All the information is:
3370 // - cellMidPoint >= 0 : cell needs to be split
3371 // - faceMidPoint >= 0 : face needs to be split
3372 // - edgeMidPoint >= 0 : edge needs to be split
3376 // Get the corner/anchor points
3377 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3381 Pout<< "hexRef8::setRefinement :"
3382 << " Finding cell anchorPoints (8 per cell)"
3386 // There will always be 8 points on the hex that have were introduced
3387 // with the hex and will have the same or lower refinement level.
3389 // Per cell the 8 corner points.
3390 labelListList cellAnchorPoints(mesh_.nCells());
3393 labelList nAnchorPoints(mesh_.nCells(), 0);
3395 forAll(cellMidPoint, cellI)
3397 if (cellMidPoint[cellI] >= 0)
3399 cellAnchorPoints[cellI].setSize(8);
3403 forAll(pointLevel_, pointI)
3405 const labelList& pCells = mesh_.pointCells()[pointI];
3407 forAll(pCells, pCellI)
3409 label cellI = pCells[pCellI];
3413 cellMidPoint[cellI] >= 0
3414 && pointLevel_[pointI] <= cellLevel_[cellI]
3417 if (nAnchorPoints[cellI] == 8)
3421 "hexRef8::setRefinement(const labelList&"
3422 ", polyTopoChange&)"
3423 ) << "cell " << cellI
3424 << " of level " << cellLevel_[cellI]
3425 << " uses more than 8 points of equal or"
3426 << " lower level" << nl
3427 << "Points so far:" << cellAnchorPoints[cellI]
3428 << abort(FatalError);
3431 cellAnchorPoints[cellI][nAnchorPoints[cellI]++] = pointI;
3436 forAll(cellMidPoint, cellI)
3438 if (cellMidPoint[cellI] >= 0)
3440 if (nAnchorPoints[cellI] != 8)
3442 const labelList cPoints(cellPoints(cellI));
3446 "hexRef8::setRefinement(const labelList&"
3447 ", polyTopoChange&)"
3448 ) << "cell " << cellI
3449 << " of level " << cellLevel_[cellI]
3450 << " does not seem to have 8 points of equal or"
3451 << " lower level" << endl
3452 << "cellPoints:" << cPoints << endl
3454 << IndirectList<label>(pointLevel_, cPoints)() << endl
3455 << abort(FatalError);
3467 Pout<< "hexRef8::setRefinement :"
3468 << " Adding cells (1 per anchorPoint)"
3472 // Per cell the 7 added cells (+ original cell)
3473 labelListList cellAddedCells(mesh_.nCells());
3475 forAll(cellAnchorPoints, cellI)
3477 const labelList& cAnchors = cellAnchorPoints[cellI];
3479 if (cAnchors.size() == 8)
3481 labelList& cAdded = cellAddedCells[cellI];
3484 // Original cell at 0
3487 // Update cell level
3488 newCellLevel[cellI] = cellLevel_[cellI]+1;
3491 for (label i = 1; i < 8; i++)
3493 cAdded[i] = meshMod.setAction
3500 cellI, // master cell
3501 mesh_.cellZones().whichZone(cellI) // zone for cell
3505 newCellLevel(cAdded[i]) = cellLevel_[cellI]+1;
3513 // 1. existing faces that get split (into four always)
3514 // 2. existing faces that do not get split but only edges get split
3515 // 3. existing faces that do not get split but get new owner/neighbour
3516 // 4. new internal faces inside split cells.
3520 Pout<< "hexRef8::setRefinement :"
3521 << " Marking faces to be handled"
3525 // Get all affected faces.
3526 PackedList<1> affectedFace(mesh_.nFaces(), 0);
3529 forAll(cellMidPoint, cellI)
3531 if (cellMidPoint[cellI] >= 0)
3533 const cell& cFaces = mesh_.cells()[cellI];
3537 affectedFace.set(cFaces[i], 1);
3542 forAll(faceMidPoint, faceI)
3544 if (faceMidPoint[faceI] >= 0)
3546 affectedFace.set(faceI, 1);
3550 forAll(edgeMidPoint, edgeI)
3552 if (edgeMidPoint[edgeI] >= 0)
3554 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
3558 affectedFace.set(eFaces[i], 1);
3565 // 1. Faces that get split
3566 // ~~~~~~~~~~~~~~~~~~~~~~~
3570 Pout<< "hexRef8::setRefinement : Splitting faces" << endl;
3573 forAll(faceMidPoint, faceI)
3575 if (faceMidPoint[faceI] >= 0 && affectedFace.get(faceI) == 1)
3577 // Face needs to be split and hasn't yet been done in some way
3578 // (affectedFace - is impossible since this is first change but
3579 // just for completeness)
3581 const face& f = mesh_.faces()[faceI];
3583 // Has original faceI been used (three faces added, original gets
3585 bool modifiedFace = false;
3587 label anchorLevel = faceAnchorLevel[faceI];
3593 label pointI = f[fp];
3595 if (pointLevel_[pointI] <= anchorLevel)
3597 // point is anchor. Start collecting face.
3599 DynamicList<label> faceVerts(4);
3601 faceVerts.append(pointI);
3603 // Walk forward to mid point.
3604 // - if next is +2 midpoint is +1
3605 // - if next is +1 it is midpoint
3606 // - if next is +0 there has to be edgeMidPoint
3617 faceVerts.append(faceMidPoint[faceI]);
3628 // Convert dynamiclist to face.
3629 newFace.transfer(faceVerts.shrink());
3632 //Pout<< "Split face:" << faceI << " verts:" << f
3633 // << " into quad:" << newFace << endl;
3635 // Get new owner/neighbour
3642 pointI, // Anchor point
3651 if (mesh_.isInternalFace(faceI))
3653 label oldOwn = mesh_.faceOwner()[faceI];
3654 label oldNei = mesh_.faceNeighbour()[faceI];
3656 checkInternalOrientation
3661 mesh_.cellCentres()[oldOwn],
3662 mesh_.cellCentres()[oldNei],
3668 label oldOwn = mesh_.faceOwner()[faceI];
3670 checkBoundaryOrientation
3675 mesh_.cellCentres()[oldOwn],
3676 mesh_.faceCentres()[faceI],
3685 modifiedFace = true;
3687 modFace(meshMod, faceI, newFace, own, nei);
3691 addFace(meshMod, faceI, newFace, own, nei);
3696 // Mark face as having been handled
3697 affectedFace.set(faceI, 0);
3702 // 2. faces that do not get split but use edges that get split
3703 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3707 Pout<< "hexRef8::setRefinement :"
3708 << " Adding edge splits to unsplit faces"
3712 forAll(edgeMidPoint, edgeI)
3714 if (edgeMidPoint[edgeI] >= 0)
3716 // Split edge. Check that face not already handled above.
3718 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
3722 label faceI = eFaces[i];
3724 if (faceMidPoint[faceI] < 0 && affectedFace.get(faceI) == 1)
3726 // Unsplit face. Add edge splits to face.
3728 const face& f = mesh_.faces()[faceI];
3729 const labelList& fEdges = mesh_.faceEdges()[faceI];
3731 DynamicList<label> newFaceVerts(f.size());
3735 newFaceVerts.append(f[fp]);
3737 label edgeI = fEdges[fp];
3739 if (edgeMidPoint[edgeI] >= 0)
3741 newFaceVerts.append(edgeMidPoint[edgeI]);
3746 newFace.transfer(newFaceVerts.shrink());
3749 // The point with the lowest level should be an anchor
3750 // point of the neighbouring cells.
3751 label anchorFp = findMinLevel(f);
3759 f[anchorFp], // Anchor point
3768 if (mesh_.isInternalFace(faceI))
3770 label oldOwn = mesh_.faceOwner()[faceI];
3771 label oldNei = mesh_.faceNeighbour()[faceI];
3773 checkInternalOrientation
3778 mesh_.cellCentres()[oldOwn],
3779 mesh_.cellCentres()[oldNei],
3785 label oldOwn = mesh_.faceOwner()[faceI];
3787 checkBoundaryOrientation
3792 mesh_.cellCentres()[oldOwn],
3793 mesh_.faceCentres()[faceI],
3799 modFace(meshMod, faceI, newFace, own, nei);
3801 // Mark face as having been handled
3802 affectedFace.set(faceI, 0);
3809 // 3. faces that do not get split but whose owner/neighbour change
3810 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3814 Pout<< "hexRef8::setRefinement :"
3815 << " Changing owner/neighbour for otherwise unaffected faces"
3819 forAll(affectedFace, faceI)
3821 if (affectedFace.get(faceI) == 1)
3823 const face& f = mesh_.faces()[faceI];
3825 // The point with the lowest level should be an anchor
3826 // point of the neighbouring cells.
3827 label anchorFp = findMinLevel(f);
3835 f[anchorFp], // Anchor point
3841 modFace(meshMod, faceI, f, own, nei);
3843 // Mark face as having been handled
3844 affectedFace.set(faceI, 0);
3849 // 4. new internal faces inside split cells.
3850 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3853 // This is the hard one. We have to find the splitting points between
3854 // the anchor points. But the edges between the anchor points might have
3855 // been split (into two,three or four edges).
3859 Pout<< "hexRef8::setRefinement :"
3860 << " Create new internal faces for split cells"
3864 forAll(cellMidPoint, cellI)
3866 if (cellMidPoint[cellI] >= 0)
3882 // Extend pointLevels and cellLevels for the new cells. Could also be done
3883 // in updateMesh but saves passing cellAddedCells out of this routine.
3888 label minPointI = labelMax;
3889 label maxPointI = labelMin;
3891 forAll(cellMidPoint, cellI)
3893 if (cellMidPoint[cellI] >= 0)
3895 minPointI = min(minPointI, cellMidPoint[cellI]);
3896 maxPointI = max(maxPointI, cellMidPoint[cellI]);
3899 forAll(faceMidPoint, faceI)
3901 if (faceMidPoint[faceI] >= 0)
3903 minPointI = min(minPointI, faceMidPoint[faceI]);
3904 maxPointI = max(maxPointI, faceMidPoint[faceI]);
3907 forAll(edgeMidPoint, edgeI)
3909 if (edgeMidPoint[edgeI] >= 0)
3911 minPointI = min(minPointI, edgeMidPoint[edgeI]);
3912 maxPointI = max(maxPointI, edgeMidPoint[edgeI]);
3916 if (minPointI != labelMax && minPointI != mesh_.nPoints())
3918 FatalErrorIn("hexRef8::setRefinement(..)")
3919 << "Added point labels not consecutive to existing mesh points."
3921 << "mesh_.nPoints():" << mesh_.nPoints()
3922 << " minPointI:" << minPointI
3923 << " maxPointI:" << maxPointI
3924 << abort(FatalError);
3928 pointLevel_.transfer(newPointLevel.shrink());
3929 newPointLevel.clear();
3930 cellLevel_.transfer(newCellLevel.shrink());
3931 newCellLevel.clear();
3933 // Mark files as changed
3934 setInstance(mesh_.facesInstance());
3937 // Update the live split cells tree.
3938 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3940 // New unrefinement structure
3941 if (history_.active())
3945 Pout<< "hexRef8::setRefinement :"
3946 << " Updating refinement history to " << cellLevel_.size()
3947 << " cells" << endl;
3950 // Extend refinement history for new cells
3951 history_.resize(cellLevel_.size());
3953 forAll(cellAddedCells, cellI)
3955 const labelList& addedCells = cellAddedCells[cellI];
3957 if (addedCells.size() > 0)
3960 history_.storeSplit(cellI, addedCells);
3965 // Compact cellAddedCells.
3967 labelListList refinedCells(cellLabels.size());
3969 forAll(cellLabels, i)
3971 label cellI = cellLabels[i];
3973 refinedCells[i].transfer(cellAddedCells[cellI]);
3976 return refinedCells;
3980 void Foam::hexRef8::storeData
3982 const labelList& pointsToStore,
3983 const labelList& facesToStore,
3984 const labelList& cellsToStore
3987 savedPointLevel_.resize(2*pointsToStore.size());
3988 forAll(pointsToStore, i)
3990 label pointI = pointsToStore[i];
3991 savedPointLevel_.insert(pointI, pointLevel_[pointI]);
3994 savedCellLevel_.resize(2*cellsToStore.size());
3995 forAll(cellsToStore, i)
3997 label cellI = cellsToStore[i];
3998 savedCellLevel_.insert(cellI, cellLevel_[cellI]);
4003 // Gets called after the mesh change. setRefinement will already have made
4004 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4005 // only need to account for reordering.
4006 void Foam::hexRef8::updateMesh(const mapPolyMesh& map)
4008 Map<label> dummyMap(0);
4010 updateMesh(map, dummyMap, dummyMap, dummyMap);
4014 // Gets called after the mesh change. setRefinement will already have made
4015 // sure the pointLevel_ and cellLevel_ are the size of the new mesh so we
4016 // only need to account for reordering.
4017 void Foam::hexRef8::updateMesh
4019 const mapPolyMesh& map,
4020 const Map<label>& pointsToRestore,
4021 const Map<label>& facesToRestore,
4022 const Map<label>& cellsToRestore
4028 Pout<< "hexRef8::updateMesh :"
4029 << " Updating various lists"
4034 const labelList& reverseCellMap = map.reverseCellMap();
4038 Pout<< "hexRef8::updateMesh :"
4039 << " reverseCellMap:" << map.reverseCellMap().size()
4040 << " cellMap:" << map.cellMap().size()
4041 << " nCells:" << mesh_.nCells()
4042 << " nOldCells:" << map.nOldCells()
4043 << " cellLevel_:" << cellLevel_.size()
4044 << " reversePointMap:" << map.reversePointMap().size()
4045 << " pointMap:" << map.pointMap().size()
4046 << " nPoints:" << mesh_.nPoints()
4047 << " nOldPoints:" << map.nOldPoints()
4048 << " pointLevel_:" << pointLevel_.size()
4052 if (reverseCellMap.size() == cellLevel_.size())
4054 // Assume it is after hexRef8 that this routine is called.
4055 // Just account for reordering. We cannot use cellMap since
4056 // then cells created from cells would get cellLevel_ of
4057 // cell they were created from.
4058 reorder(reverseCellMap, mesh_.nCells(), -1, cellLevel_);
4063 const labelList& cellMap = map.cellMap();
4065 labelList newCellLevel(cellMap.size());
4066 forAll(cellMap, newCellI)
4068 label oldCellI = cellMap[newCellI];
4072 //FatalErrorIn("hexRef8::updateMesh(const mapPolyMesh&)")
4073 // << "Problem : cell " << newCellI
4074 // << " at " << mesh_.cellCentres()[newCellI]
4075 // << " does not originate from another cell"
4076 // << " (i.e. is inflated)." << nl
4077 // << "Hence we cannot determine the new cellLevel"
4078 // << " for it." << abort(FatalError);
4079 newCellLevel[newCellI] = -1;
4083 newCellLevel[newCellI] = cellLevel_[oldCellI];
4086 cellLevel_.transfer(newCellLevel);
4089 // See if any cells to restore. This will be for some new cells
4090 // the corresponding old cell.
4091 forAllConstIter(Map<label>, cellsToRestore, iter)
4093 label newCellI = iter.key();
4094 label storedCellI = iter();
4096 Map<label>::iterator fnd = savedCellLevel_.find(storedCellI);
4098 if (fnd == savedCellLevel_.end())
4100 FatalErrorIn("hexRef8::updateMesh(const mapPolyMesh&)")
4101 << "Problem : trying to restore old value for new cell "
4102 << newCellI << " but cannot find old cell " << storedCellI
4103 << " in map of stored values " << savedCellLevel_
4104 << abort(FatalError);
4106 cellLevel_[newCellI] = fnd();
4109 //if (findIndex(cellLevel_, -1) != -1)
4111 // WarningIn("hexRef8::updateMesh(const mapPolyMesh&)")
4113 // << "cellLevel_ contains illegal value -1 after mapping
4114 // << " at cell " << findIndex(cellLevel_, -1) << endl
4115 // << "This means that another program has inflated cells"
4116 // << " (created cells out-of-nothing) and hence we don't know"
4117 // << " their cell level. Continuing with illegal value."
4118 // << abort(FatalError);
4123 // Update pointlevel
4125 const labelList& reversePointMap = map.reversePointMap();
4127 if (reversePointMap.size() == pointLevel_.size())
4129 // Assume it is after hexRef8 that this routine is called.
4130 reorder(reversePointMap, mesh_.nPoints(), -1, pointLevel_);
4135 const labelList& pointMap = map.pointMap();
4137 labelList newPointLevel(pointMap.size());
4139 forAll(pointMap, newPointI)
4141 label oldPointI = pointMap[newPointI];
4143 if (oldPointI == -1)
4145 //FatalErrorIn("hexRef8::updateMesh(const mapPolyMesh&)")
4146 // << "Problem : point " << newPointI
4147 // << " at " << mesh_.points()[newPointI]
4148 // << " does not originate from another point"
4149 // << " (i.e. is inflated)." << nl
4150 // << "Hence we cannot determine the new pointLevel"
4151 // << " for it." << abort(FatalError);
4152 newPointLevel[newPointI] = -1;
4156 newPointLevel[newPointI] = pointLevel_[oldPointI];
4159 pointLevel_.transfer(newPointLevel);
4162 // See if any points to restore. This will be for some new points
4163 // the corresponding old point (the one from the call to storeData)
4164 forAllConstIter(Map<label>, pointsToRestore, iter)
4166 label newPointI = iter.key();
4167 label storedPointI = iter();
4169 Map<label>::iterator fnd = savedPointLevel_.find(storedPointI);
4171 if (fnd == savedPointLevel_.end())
4173 FatalErrorIn("hexRef8::updateMesh(const mapPolyMesh&)")
4174 << "Problem : trying to restore old value for new point "
4175 << newPointI << " but cannot find old point "
4177 << " in map of stored values " << savedPointLevel_
4178 << abort(FatalError);
4180 pointLevel_[newPointI] = fnd();
4183 //if (findIndex(pointLevel_, -1) != -1)
4185 // WarningIn("hexRef8::updateMesh(const mapPolyMesh&)")
4187 // << "pointLevel_ contains illegal value -1 after mapping"
4188 // << " at point" << findIndex(pointLevel_, -1) << endl
4189 // << "This means that another program has inflated points"
4190 // << " (created points out-of-nothing) and hence we don't know"
4191 // << " their point level. Continuing with illegal value."
4192 // //<< abort(FatalError);
4196 // Update refinement tree
4197 if (history_.active())
4199 history_.updateMesh(map);
4202 // Mark files as changed
4203 setInstance(mesh_.facesInstance());
4205 // Update face removal engine
4206 faceRemover_.updateMesh(map);
4210 // Gets called after mesh subsetting. Maps are from new back to old.
4211 void Foam::hexRef8::subset
4213 const labelList& pointMap,
4214 const labelList& faceMap,
4215 const labelList& cellMap
4221 Pout<< "hexRef8::subset :"
4222 << " Updating various lists"
4226 if (history_.active())
4230 "hexRef8::subset(const labelList&, const labelList&"
4231 ", const labelList&)"
4232 ) << "Subsetting will not work in combination with unrefinement."
4234 << "Proceed at your own risk." << endl;
4240 labelList newCellLevel(cellMap.size());
4242 forAll(cellMap, newCellI)
4244 newCellLevel[newCellI] = cellLevel_[cellMap[newCellI]];
4247 cellLevel_.transfer(newCellLevel);
4249 if (findIndex(cellLevel_, -1) != -1)
4251 FatalErrorIn("hexRef8::subset(..)")
4253 << "cellLevel_ contains illegal value -1 after mapping:"
4255 << abort(FatalError);
4259 // Update pointlevel
4261 labelList newPointLevel(pointMap.size());
4263 forAll(pointMap, newPointI)
4265 newPointLevel[newPointI] = pointLevel_[pointMap[newPointI]];
4268 pointLevel_.transfer(newPointLevel);
4270 if (findIndex(pointLevel_, -1) != -1)
4272 FatalErrorIn("hexRef8::subset(..)")
4274 << "pointLevel_ contains illegal value -1 after mapping:"
4276 << abort(FatalError);
4280 // Update refinement tree
4281 if (history_.active())
4283 history_.subset(pointMap, faceMap, cellMap);
4286 // Mark files as changed
4287 setInstance(mesh_.facesInstance());
4289 // Nothing needs doing to faceRemover.
4290 //faceRemover_.subset(pointMap, faceMap, cellMap);
4294 // Gets called after the mesh distribution
4295 void Foam::hexRef8::distribute(const mapDistributePolyMesh& map)
4299 Pout<< "hexRef8::distribute :"
4300 << " Updating various lists"
4305 map.distributeCellData(cellLevel_);
4306 // Update pointlevel
4307 map.distributePointData(pointLevel_);
4309 // Update refinement tree
4310 if (history_.active())
4312 history_.distribute(map);
4315 // Update face removal engine
4316 faceRemover_.distribute(map);
4320 void Foam::hexRef8::checkMesh() const
4322 const boundBox& meshBb = mesh_.globalData().bb();
4323 const scalar smallDim = 1E-6*mag(meshBb.max() - meshBb.min());
4327 Pout<< "hexRef8::checkMesh : Using matching tolerance smallDim:"
4328 << smallDim << endl;
4331 // Check owner on coupled faces.
4332 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4334 // There should be only one coupled face between two cells. Why? Since
4335 // otherwise mesh redistribution might cause multiple faces between two
4338 labelList nei(mesh_.nFaces()-mesh_.nInternalFaces());
4341 nei[i] = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4344 // Replace data on coupled patches with their neighbour ones.
4345 syncTools::swapBoundaryFaceList(mesh_, nei, false);
4347 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
4349 forAll(patches, patchI)
4351 const polyPatch& pp = patches[patchI];
4355 // Check how many faces between owner and neighbour. Should
4357 HashTable<label, labelPair, labelPair::Hash<> >
4358 cellToFace(2*pp.size());
4360 label faceI = pp.start();
4364 label own = mesh_.faceOwner()[faceI];
4365 label bFaceI = faceI-mesh_.nInternalFaces();
4367 if (!cellToFace.insert(labelPair(own, nei[bFaceI]), faceI))
4369 FatalErrorIn("hexRef8::checkMesh()")
4370 << "Faces do not seem to be correct across coupled"
4371 << " boundaries" << endl
4372 << "Coupled face " << faceI
4373 << " between owner " << own
4374 << " on patch " << pp.name()
4375 << " and coupled neighbour " << nei[bFaceI]
4376 << " has two faces connected to it:"
4378 << cellToFace[labelPair(own, nei[bFaceI])]
4379 << abort(FatalError);
4388 // Check face areas.
4389 // ~~~~~~~~~~~~~~~~~
4392 scalarField neiFaceAreas(mesh_.nFaces()-mesh_.nInternalFaces());
4393 forAll(neiFaceAreas, i)
4395 neiFaceAreas[i] = mag(mesh_.faceAreas()[i+mesh_.nInternalFaces()]);
4398 // Replace data on coupled patches with their neighbour ones.
4399 syncTools::swapBoundaryFaceList(mesh_, neiFaceAreas, false);
4401 forAll(neiFaceAreas, i)
4403 label faceI = i+mesh_.nInternalFaces();
4405 const scalar magArea = mag(mesh_.faceAreas()[faceI]);
4407 if (mag(magArea - neiFaceAreas[i]) > smallDim)
4409 const face& f = mesh_.faces()[faceI];
4410 label patchI = mesh_.boundaryMesh().whichPatch(faceI);
4412 FatalErrorIn("hexRef8::checkMesh()")
4413 << "Faces do not seem to be correct across coupled"
4414 << " boundaries" << endl
4415 << "Coupled face " << faceI
4416 << " on patch " << patchI
4417 << " " << mesh_.boundaryMesh()[patchI].name()
4418 << " coords:" << IndirectList<point>(mesh_.points(), f)()
4419 << " has face area:" << magArea
4420 << " (coupled) neighbour face area differs:"
4422 << " to within tolerance " << smallDim
4423 << abort(FatalError);
4429 // Check number of points on faces.
4430 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4432 labelList nVerts(mesh_.nFaces()-mesh_.nInternalFaces());
4436 nVerts[i] = mesh_.faces()[i+mesh_.nInternalFaces()].size();
4439 // Replace data on coupled patches with their neighbour ones.
4440 syncTools::swapBoundaryFaceList(mesh_, nVerts, false);
4444 label faceI = i+mesh_.nInternalFaces();
4446 const face& f = mesh_.faces()[faceI];
4448 if (f.size() != nVerts[i])
4450 label patchI = mesh_.boundaryMesh().whichPatch(faceI);
4452 FatalErrorIn("hexRef8::checkMesh()")
4453 << "Faces do not seem to be correct across coupled"
4454 << " boundaries" << endl
4455 << "Coupled face " << faceI
4456 << " on patch " << patchI
4457 << " " << mesh_.boundaryMesh()[patchI].name()
4458 << " coords:" << IndirectList<point>(mesh_.points(), f)()
4459 << " has size:" << f.size()
4460 << " (coupled) neighbour face has size:"
4462 << abort(FatalError);
4468 // Check points of face
4469 // ~~~~~~~~~~~~~~~~~~~~
4472 pointField anchorPoints(mesh_.nFaces()-mesh_.nInternalFaces());
4474 forAll(anchorPoints, i)
4476 label faceI = i+mesh_.nInternalFaces();
4477 const point& fc = mesh_.faceCentres()[faceI];
4478 const face& f = mesh_.faces()[faceI];
4479 const vector anchorVec(mesh_.points()[f[0]] - fc);
4481 anchorPoints[i] = anchorVec;
4484 // Replace data on coupled patches with their neighbour ones. Apply
4485 // rotation transformation (but not separation since is relative vector
4486 // to point on same face.
4487 syncTools::swapBoundaryFaceList(mesh_, anchorPoints, false);
4489 forAll(anchorPoints, i)
4491 label faceI = i+mesh_.nInternalFaces();
4492 const point& fc = mesh_.faceCentres()[faceI];
4493 const face& f = mesh_.faces()[faceI];
4494 const vector anchorVec(mesh_.points()[f[0]] - fc);
4496 if (mag(anchorVec - anchorPoints[i]) > smallDim)
4498 label patchI = mesh_.boundaryMesh().whichPatch(faceI);
4500 FatalErrorIn("hexRef8::checkMesh()")
4501 << "Faces do not seem to be correct across coupled"
4502 << " boundaries" << endl
4503 << "Coupled face " << faceI
4504 << " on patch " << patchI
4505 << " " << mesh_.boundaryMesh()[patchI].name()
4506 << " coords:" << IndirectList<point>(mesh_.points(), f)()
4507 << " has anchor vector:" << anchorVec
4508 << " (coupled) neighbour face anchor vector differs:"
4510 << " to within tolerance " << smallDim
4511 << abort(FatalError);
4518 Pout<< "hexRef8::checkMesh : Returning" << endl;
4523 void Foam::hexRef8::checkRefinementLevels
4525 const label maxPointDiff,
4526 const labelList& pointsToCheck
4531 Pout<< "hexRef8::checkRefinementLevels :"
4532 << " Checking 2:1 refinement level" << endl;
4537 cellLevel_.size() != mesh_.nCells()
4538 || pointLevel_.size() != mesh_.nPoints()
4541 FatalErrorIn("hexRef8::checkRefinementLevels(const label)")
4542 << "cellLevel size should be number of cells"
4543 << " and pointLevel size should be number of points."<< nl
4544 << "cellLevel:" << cellLevel_.size()
4545 << " mesh.nCells():" << mesh_.nCells() << nl
4546 << "pointLevel:" << pointLevel_.size()
4547 << " mesh.nPoints():" << mesh_.nPoints()
4548 << abort(FatalError);
4552 // Check 2:1 consistency.
4553 // ~~~~~~~~~~~~~~~~~~~~~~
4557 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
4559 label own = mesh_.faceOwner()[faceI];
4560 label nei = mesh_.faceNeighbour()[faceI];
4562 if (mag(cellLevel_[own] - cellLevel_[nei]) > 1)
4566 "hexRef8::checkRefinementLevels(const label)"
4567 ) << "Celllevel does not satisfy 2:1 constraint." << nl
4568 << "On face " << faceI << " owner cell " << own
4569 << " has refinement " << cellLevel_[own]
4570 << " neighbour cell " << nei << " has refinement "
4572 << abort(FatalError);
4576 // Coupled faces. Get neighbouring value
4577 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
4581 label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
4583 neiLevel[i] = cellLevel_[own];
4587 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
4591 label faceI = i+mesh_.nInternalFaces();
4593 label own = mesh_.faceOwner()[faceI];
4595 if (mag(cellLevel_[own] - neiLevel[i]) > 1)
4597 label patchI = mesh_.boundaryMesh().whichPatch(faceI);
4601 "hexRef8::checkRefinementLevels(const label)"
4602 ) << "Celllevel does not satisfy 2:1 constraint."
4603 << " On coupled face " << faceI
4604 << " on patch " << patchI << " "
4605 << mesh_.boundaryMesh()[patchI].name()
4606 << " owner cell " << own << " has refinement "
4608 << " (coupled) neighbour cell has refinement "
4610 << abort(FatalError);
4616 // Check pointLevel is synchronized
4617 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4619 labelList syncPointLevel(pointLevel_);
4622 syncTools::syncPointList
4628 false // no separation
4632 forAll(syncPointLevel, pointI)
4634 if (pointLevel_[pointI] != syncPointLevel[pointI])
4638 "hexRef8::checkRefinementLevels(const label)"
4639 ) << "PointLevel is not consistent across coupled patches."
4641 << "point:" << pointI << " coord:" << mesh_.points()[pointI]
4642 << " has level " << pointLevel_[pointI]
4643 << " whereas the coupled point has level "
4644 << syncPointLevel[pointI]
4645 << abort(FatalError);
4651 // Check 2:1 across points (instead of faces)
4652 if (maxPointDiff != -1)
4654 const labelListList& pointCells = mesh_.pointCells();
4656 // Determine per point the max cell level.
4657 labelList maxPointLevel(mesh_.nPoints(), 0);
4659 forAll(pointCells, pointI)
4661 const labelList& pCells = pointCells[pointI];
4663 label& pLevel = maxPointLevel[pointI];
4667 pLevel = max(pLevel, cellLevel_[pCells[i]]);
4671 // Sync maxPointLevel to neighbour
4672 syncTools::syncPointList
4677 labelMin, // null value
4678 false // no separation
4681 // Check 2:1 across boundary points
4682 forAll(pointsToCheck, i)
4684 label pointI = pointsToCheck[i];
4686 const labelList& pCells = pointCells[pointI];
4690 label cellI = pCells[i];
4694 mag(cellLevel_[cellI]-maxPointLevel[pointI])
4700 "hexRef8::checkRefinementLevels(const label)"
4701 ) << "Too big a difference between"
4702 << " point-connected cells." << nl
4704 << " cellLevel:" << cellLevel_[cellI]
4705 << " uses point:" << pointI
4706 << " coord:" << mesh_.points()[pointI]
4707 << " which is also used by a cell with level:"
4708 << maxPointLevel[pointI]
4709 << abort(FatalError);
4724 Foam::labelList Foam::hexRef8::getSplitPoints() const
4728 checkRefinementLevels(-1, labelList(0));
4733 Pout<< "hexRef8::getSplitPoints :"
4734 << " Calculating unrefineable points" << endl;
4738 if (!history_.active())
4740 FatalErrorIn("hexRef8::getSplitPoints()")
4741 << "Only call if constructed with history capability"
4742 << abort(FatalError);
4747 // -2 certainly not split point
4748 // >= label of master cell
4749 labelList splitMaster(mesh_.nPoints(), -1);
4750 labelList splitMasterLevel(mesh_.nPoints(), 0);
4752 // Unmark all with not 8 cells
4753 const labelListList& pointCells = mesh_.pointCells();
4755 forAll(pointCells, pointI)
4757 const labelList& pCells = pointCells[pointI];
4759 if (pCells.size() != 8)
4761 splitMaster[pointI] = -2;
4765 // Unmark all with different master cells
4766 const labelList& visibleCells = history_.visibleCells();
4768 forAll(visibleCells, cellI)
4770 //const labelList& cPoints = mesh_.cellPoints()[cellI];
4771 const labelList cPoints(cellPoints(cellI));
4773 if (visibleCells[cellI] != -1 && history_.parentIndex(cellI) >= 0)
4775 label parentIndex = history_.parentIndex(cellI);
4777 // Check same master.
4780 label pointI = cPoints[i];
4782 label masterCellI = splitMaster[pointI];
4784 if (masterCellI == -1)
4786 // First time visit of point. Store parent cell and
4787 // level of the parent cell (with respect to cellI). This
4788 // is additional guarantee that we're referring to the
4789 // same master at the same refinement level.
4791 splitMaster[pointI] = parentIndex;
4792 splitMasterLevel[pointI] = cellLevel_[cellI] - 1;
4794 else if (masterCellI == -2)
4796 // Already decided that point is not splitPoint
4800 (masterCellI != parentIndex)
4801 || (splitMasterLevel[pointI] != cellLevel_[cellI] - 1)
4804 // Different masters so point is on two refinement
4806 splitMaster[pointI] = -2;
4812 // Either not visible or is unrefined cell
4815 label pointI = cPoints[i];
4817 splitMaster[pointI] = -2;
4822 // Unmark boundary faces
4825 label faceI = mesh_.nInternalFaces();
4826 faceI < mesh_.nFaces();
4830 const face& f = mesh_.faces()[faceI];
4834 splitMaster[f[fp]] = -2;
4839 // Collect into labelList
4841 label nSplitPoints = 0;
4843 forAll(splitMaster, pointI)
4845 if (splitMaster[pointI] >= 0)
4851 labelList splitPoints(nSplitPoints);
4854 forAll(splitMaster, pointI)
4856 if (splitMaster[pointI] >= 0)
4858 splitPoints[nSplitPoints++] = pointI;
4866 //void Foam::hexRef8::markIndex
4868 // const label maxLevel,
4869 // const label level,
4870 // const label index,
4871 // const label markValue,
4872 // labelList& indexValues
4875 // if (level < maxLevel && indexValues[index] == -1)
4878 // indexValues[index] = markValue;
4881 // const splitCell8& split = history_.splitCells()[index];
4883 // if (split.parent_ >= 0)
4887 // maxLevel, level+1, split.parent_, markValue, indexValues);
4894 //// Get all cells which (down to level) originate from the same cell.
4895 //// level=0 returns cell only, level=1 returns the 8 cells this cell
4896 //// originates from, level=2 returns 64 cells etc.
4897 //// If the cell does not originate from refinement returns just itself.
4898 //void Foam::hexRef8::markCellClusters
4900 // const label maxLevel,
4901 // labelList& cluster
4904 // cluster.setSize(mesh_.nCells());
4907 // const DynamicList<splitCell8>& splitCells = history_.splitCells();
4909 // // Mark all splitCells down to level maxLevel with a cell originating from
4912 // labelList indexLevel(splitCells.size(), -1);
4914 // forAll(visibleCells, cellI)
4916 // label index = visibleCells[cellI];
4920 // markIndex(maxLevel, 0, index, cellI, indexLevel);
4924 // // Mark cells with splitCell
4928 Foam::labelList Foam::hexRef8::consistentUnrefinement
4930 const labelList& pointsToUnrefine,
4936 Pout<< "hexRef8::consistentUnrefinement :"
4937 << " Determining 2:1 consistent unrefinement" << endl;
4944 "hexRef8::consistentUnrefinement(const labelList&, const bool"
4945 ) << "maxSet not implemented yet."
4946 << abort(FatalError);
4949 // Loop, modifying pointsToUnrefine, until no more changes to due to 2:1
4951 // maxSet = false : unselect points to refine
4952 // maxSet = true: select points to refine
4954 // Maintain boolList for pointsToUnrefine and cellsToUnrefine
4955 PackedList<1> unrefinePoint(mesh_.nPoints(), 0);
4957 forAll(pointsToUnrefine, i)
4959 label pointI = pointsToUnrefine[i];
4961 unrefinePoint.set(pointI, 1);
4967 // Construct cells to unrefine
4968 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4970 PackedList<1> unrefineCell(mesh_.nCells(), 0);
4972 forAll(unrefinePoint, pointI)
4974 if (unrefinePoint.get(pointI) == 1)
4976 const labelList& pCells = mesh_.pointCells()[pointI];
4980 unrefineCell.set(pCells[j], 1);
4989 // Check 2:1 consistency taking refinement into account
4990 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4993 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
4995 label own = mesh_.faceOwner()[faceI];
4996 label ownLevel = cellLevel_[own] - unrefineCell.get(own);
4998 label nei = mesh_.faceNeighbour()[faceI];
4999 label neiLevel = cellLevel_[nei] - unrefineCell.get(nei);
5001 if (ownLevel < (neiLevel-1))
5003 // Since was 2:1 this can only occur if own is marked for
5008 unrefineCell.set(nei, 1);
5012 if (unrefineCell.get(own) == 0)
5014 FatalErrorIn("hexRef8::consistentUnrefinement(..)")
5015 << "problem" << abort(FatalError);
5018 unrefineCell.set(own, 0);
5022 else if (neiLevel < (ownLevel-1))
5026 unrefineCell.set(own, 1);
5030 if (unrefineCell.get(nei) == 0)
5032 FatalErrorIn("hexRef8::consistentUnrefinement(..)")
5033 << "problem" << abort(FatalError);
5036 unrefineCell.set(nei, 0);
5043 // Coupled faces. Swap owner level to get neighbouring cell level.
5044 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
5048 label own = mesh_.faceOwner()[i+mesh_.nInternalFaces()];
5050 neiLevel[i] = cellLevel_[own] - unrefineCell.get(own);
5053 // Swap to neighbour
5054 syncTools::swapBoundaryFaceList(mesh_, neiLevel, false);
5058 label faceI = i+mesh_.nInternalFaces();
5059 label own = mesh_.faceOwner()[faceI];
5060 label ownLevel = cellLevel_[own] - unrefineCell.get(own);
5062 if (ownLevel < (neiLevel[i]-1))
5066 if (unrefineCell.get(own) == 0)
5068 FatalErrorIn("hexRef8::consistentUnrefinement(..)")
5069 << "problem" << abort(FatalError);
5072 unrefineCell.set(own, 0);
5076 else if (neiLevel[i] < (ownLevel-1))
5080 if (unrefineCell.get(own) == 1)
5082 FatalErrorIn("hexRef8::consistentUnrefinement(..)")
5083 << "problem" << abort(FatalError);
5086 unrefineCell.set(own, 1);
5092 reduce(nChanged, sumOp<label>());
5096 Pout<< "hexRef8::consistentUnrefinement :"
5097 << " Changed " << nChanged
5098 << " refinement levels due to 2:1 conflicts."
5108 // Convert cellsToUnrefine back into points to unrefine
5109 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5111 // Knock out any point whose cell neighbour cannot be unrefined.
5112 forAll(unrefinePoint, pointI)
5114 if (unrefinePoint.get(pointI) == 1)
5116 const labelList& pCells = mesh_.pointCells()[pointI];
5120 if (unrefineCell.get(pCells[j]) == 0)
5122 unrefinePoint.set(pointI, 0);
5131 // Convert back to labelList.
5134 forAll(unrefinePoint, pointI)
5136 if (unrefinePoint.get(pointI) == 1)
5142 labelList newPointsToUnrefine(nSet);
5145 forAll(unrefinePoint, pointI)
5147 if (unrefinePoint.get(pointI) == 1)
5149 newPointsToUnrefine[nSet++] = pointI;
5153 return newPointsToUnrefine;
5157 void Foam::hexRef8::setUnrefinement
5159 const labelList& splitPointLabels,
5160 polyTopoChange& meshMod
5163 if (!history_.active())
5167 "hexRef8::setUnrefinement(const labelList&, polyTopoChange&)"
5168 ) << "Only call if constructed with history capability"
5169 << abort(FatalError);
5174 Pout<< "hexRef8::setUnrefinement :"
5175 << " Checking initial mesh just to make sure" << endl;
5179 forAll(cellLevel_, cellI)
5181 if (cellLevel_[cellI] < 0)
5185 "hexRef8::setUnrefinement(const labelList&, polyTopoChange&)"
5186 ) << "Illegal cell level " << cellLevel_[cellI]
5187 << " for cell " << cellI
5188 << abort(FatalError);
5194 pointSet pSet(mesh_, "splitPoints", splitPointLabels);
5197 cellSet cSet(mesh_, "splitPointCells", splitPointLabels.size());
5199 forAll(splitPointLabels, i)
5201 const labelList& pCells = mesh_.pointCells()[splitPointLabels[i]];
5205 cSet.insert(pCells[j]);
5210 Pout<< "hexRef8::setRefinement : Dumping " << pSet.size()
5212 << cSet.size() << " cells for unrefinement to" << nl
5213 << " pointSet " << pSet.objectPath() << nl
5214 << " cellSet " << cSet.objectPath()
5219 labelList cellRegion;
5220 labelList cellRegionMaster;
5221 labelList facesToRemove;
5224 labelHashSet splitFaces(12*splitPointLabels.size());
5226 forAll(splitPointLabels, i)
5228 const labelList& pFaces = mesh_.pointFaces()[splitPointLabels[i]];
5232 splitFaces.insert(pFaces[j]);
5236 // Check with faceRemover what faces will get removed. Note that this
5237 // can be more (but never less) than splitFaces provided.
5238 faceRemover_.compatibleRemoves
5240 splitFaces.toc(), // pierced faces
5241 cellRegion, // per cell -1 or region it is merged into
5242 cellRegionMaster, // per region the master cell
5243 facesToRemove // new faces to be removed.
5246 if (facesToRemove.size() != splitFaces.size())
5250 "hexRef8::setUnrefinement(const labelList&, polyTopoChange&)"
5251 ) << "Ininitial set of split points to unrefine does not"
5252 << " seem to be consistent or not mid points of refined cells"
5253 << abort(FatalError);
5257 // Redo the region master so it is consistent with our master.
5258 // This will guarantee that the new cell (for which faceRemover uses
5259 // the region master) is already compatible with our refinement structure.
5261 forAll(splitPointLabels, i)
5263 label pointI = splitPointLabels[i];
5265 // Get original cell label
5267 const labelList& pCells = mesh_.pointCells()[pointI];
5270 if (pCells.size() != 8)
5274 "hexRef8::setUnrefinement(const labelList&, polyTopoChange&)"
5275 ) << "splitPoint " << pointI
5276 << " should have 8 cells using it. It has " << pCells
5277 << abort(FatalError);
5281 // Check that the lowest numbered pCells is the master of the region
5282 // (should be guaranteed by directRemoveFaces)
5285 label masterCellI = min(pCells);
5289 label cellI = pCells[j];
5291 label region = cellRegion[cellI];
5295 FatalErrorIn("hexRef8::setUnrefinement(..)")
5296 << "Ininitial set of split points to unrefine does not"
5297 << " seem to be consistent or not mid points"
5298 << " of refined cells" << nl
5299 << "cell:" << cellI << " on splitPoint " << pointI
5300 << " has no region to be merged into"
5301 << abort(FatalError);
5304 if (masterCellI != cellRegionMaster[region])
5306 FatalErrorIn("hexRef8::setUnrefinement(..)")
5307 << "cell:" << cellI << " on splitPoint:" << pointI
5308 << " in region " << region
5309 << " has master:" << cellRegionMaster[region]
5310 << " which is not the lowest numbered cell"
5311 << " among the pointCells:" << pCells
5312 << abort(FatalError);
5318 // Insert all commands to combine cells. Never fails so don't have to
5319 // test for success.
5320 faceRemover_.setRefinement
5328 // Remove the 8 cells that originated from merging around the split point
5329 // and adapt cell levels (not that pointLevels stay the same since points
5330 // either get removed or stay at the same position.
5331 forAll(splitPointLabels, i)
5333 label pointI = splitPointLabels[i];
5335 const labelList& pCells = mesh_.pointCells()[pointI];
5337 label masterCellI = min(pCells);
5341 cellLevel_[pCells[j]]--;
5344 history_.combineCells(masterCellI, pCells);
5347 // Mark files as changed
5348 setInstance(mesh_.facesInstance());
5350 // history_.updateMesh will take care of truncating.
5354 // Write refinement to polyMesh directory.
5355 bool Foam::hexRef8::write() const
5357 bool writeOk = cellLevel_.write() && pointLevel_.write();
5359 if (history_.active())
5361 writeOk = writeOk && history_.write();
5368 // ************************************************************************* //