1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
30 #include "cellLooper.H"
31 #include "refineCell.H"
32 #include "meshTools.H"
33 #include "geomCellLooper.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(Foam::cellCuts, 0);
42 // * * * * * * * * * * * * * Private Static Functions * * * * * * * * * * * //
44 // Find val in first nElems elements of list.
45 Foam::label Foam::cellCuts::findPartIndex
47 const labelList& elems,
52 for (label i = 0; i < nElems; i++)
63 Foam::boolList Foam::cellCuts::expand
66 const labelList& labels
69 boolList result(size, false);
71 forAll(labels, labelI)
73 result[labels[labelI]] = true;
79 Foam::scalarField Foam::cellCuts::expand
82 const labelList& labels,
83 const scalarField& weights
86 scalarField result(size, -GREAT);
88 forAll(labels, labelI)
90 result[labels[labelI]] = weights[labelI];
96 // Find first point in lst not in map.
97 Foam::label Foam::cellCuts::firstUnique
100 const Map<label>& map
105 if (!map.found(lst[i]))
114 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
116 // Write cell and raw cuts on any of the elements
117 void Foam::cellCuts::writeUncutOBJ
124 OFstream cutsStream(dir / "cell_" + name(cellI) + ".obj");
126 Pout<< "Writing cell for time " << mesh().time().timeName()
127 << " to " << cutsStream.name() << nl;
138 //- Loop cutting cell in two
139 OFstream cutStream(dir / "cellCuts_" + name(cellI) + ".obj");
141 Pout<< "Writing raw cuts on cell for time " << mesh().time().timeName()
142 << " to " << cutStream.name() << nl;
144 const labelList& cPoints = mesh().cellPoints()[cellI];
148 label pointI = cPoints[i];
149 if (pointIsCut_[pointI])
151 meshTools::writeOBJ(cutStream, mesh().points()[pointI]);
155 const pointField& pts = mesh().points();
157 const labelList& cEdges = mesh().cellEdges()[cellI];
161 label edgeI = cEdges[i];
163 if (edgeIsCut_[edgeI])
165 const edge& e = mesh().edges()[edgeI];
167 const scalar w = edgeWeight_[edgeI];
169 meshTools::writeOBJ(cutStream, w*pts[e[1]] + (1-w)*pts[e[0]]);
175 void Foam::cellCuts::writeOBJ
179 const pointField& loopPoints,
180 const labelList& anchors
184 OFstream cutsStream(dir / "cell_" + name(cellI) + ".obj");
186 Pout<< "Writing cell for time " << mesh().time().timeName()
187 << " to " << cutsStream.name() << nl;
199 //- Loop cutting cell in two
200 OFstream loopStream(dir / "cellLoop_" + name(cellI) + ".obj");
202 Pout<< "Writing loop for time " << mesh().time().timeName()
203 << " to " << loopStream.name() << nl;
207 writeOBJ(loopStream, loopPoints, vertI);
211 OFstream anchorStream(dir / "anchors_" + name(cellI) + ".obj");
213 Pout<< "Writing anchors for time " << mesh().time().timeName()
214 << " to " << anchorStream.name() << endl;
218 meshTools::writeOBJ(anchorStream, mesh().points()[anchors[i]]);
223 // Find face on cell using the two edges.
224 Foam::label Foam::cellCuts::edgeEdgeToFace
231 const labelList& cFaces = mesh().cells()[cellI];
233 forAll(cFaces, cFaceI)
235 label faceI = cFaces[cFaceI];
237 const labelList& fEdges = mesh().faceEdges()[faceI];
241 findIndex(fEdges, edgeA) != -1
242 && findIndex(fEdges, edgeB) != -1
249 // Coming here means the loop is illegal since the two edges
250 // are not shared by a face. We just mark loop as invalid and continue.
254 "Foam::cellCuts::edgeEdgeToFace"
255 "(const label cellI, const label edgeA,"
256 "const label edgeB) const"
257 ) << "cellCuts : Cannot find face on cell "
258 << cellI << " that has both edges " << edgeA << ' ' << edgeB << endl
259 << "faces : " << cFaces << endl
260 << "edgeA : " << mesh().edges()[edgeA] << endl
261 << "edgeB : " << mesh().edges()[edgeB] << endl
262 << "Marking the loop across this cell as invalid" << endl;
268 // Find face on cell using an edge and a vertex.
269 Foam::label Foam::cellCuts::edgeVertexToFace
276 const labelList& cFaces = mesh().cells()[cellI];
278 forAll(cFaces, cFaceI)
280 label faceI = cFaces[cFaceI];
282 const face& f = mesh().faces()[faceI];
284 const labelList& fEdges = mesh().faceEdges()[faceI];
288 findIndex(fEdges, edgeI) != -1
289 && findIndex(f, vertI) != -1
298 "Foam::cellCuts::edgeVertexToFace"
299 "(const label cellI, const label edgeI, "
300 "const label vertI) const"
301 ) << "cellCuts : Cannot find face on cell "
302 << cellI << " that has both edge " << edgeI << " and vertex "
304 << "faces : " << cFaces << endl
305 << "edge : " << mesh().edges()[edgeI] << endl
306 << "Marking the loop across this cell as invalid" << endl;
312 // Find face using two vertices (guaranteed not to be along edge)
313 Foam::label Foam::cellCuts::vertexVertexToFace
320 const labelList& cFaces = mesh().cells()[cellI];
322 forAll(cFaces, cFaceI)
324 label faceI = cFaces[cFaceI];
326 const face& f = mesh().faces()[faceI];
330 findIndex(f, vertA) != -1
331 && findIndex(f, vertB) != -1
338 WarningIn("Foam::cellCuts::vertexVertexToFace")
339 << "cellCuts : Cannot find face on cell "
340 << cellI << " that has vertex " << vertA << " and vertex "
342 << "faces : " << cFaces << endl
343 << "Marking the loop across this cell as invalid" << endl;
349 void Foam::cellCuts::calcFaceCuts() const
353 FatalErrorIn("cellCuts::calcFaceCuts()")
354 << "faceCuts already calculated" << abort(FatalError);
357 const faceList& faces = mesh().faces();
360 faceCutsPtr_ = new labelListList(mesh().nFaces());
361 labelListList& faceCuts = *faceCutsPtr_;
363 for (label faceI = 0; faceI < mesh().nFaces(); faceI++)
365 const face& f = faces[faceI];
367 // Big enough storage (possibly all points and all edges cut). Shrink
369 labelList& cuts = faceCuts[faceI];
371 cuts.setSize(2*f.size());
375 // Do point-edge-point walk over face and collect all cuts.
376 // Problem is that we want to start from one of the endpoints of a
377 // string of connected cuts; we don't want to start somewhere in the
380 // Pass1: find first point cut not preceeded by a cut.
389 label vMin1 = f[f.rcIndex(fp)];
394 && !edgeIsCut_[findEdge(faceI, v0, vMin1)]
397 cuts[cutI++] = vertToEVert(v0);
398 startFp = f.fcIndex(fp);
404 // Pass2: first edge cut not preceeded by point cut
409 label fp1 = f.fcIndex(fp);
414 label edgeI = findEdge(faceI, v0, v1);
416 if (edgeIsCut_[edgeI] && !pointIsCut_[v0])
418 cuts[cutI++] = edgeToEVert(edgeI);
425 // Pass3: nothing found so far. Either face is not cut at all or all
426 // vertices are cut. Start from 0.
432 // Store all cuts starting from startFp;
435 bool allVerticesCut = true;
439 label fp1 = f.fcIndex(fp);
441 // Get the three items: current vertex, next vertex and edge
445 label edgeI = findEdge(faceI, v0, v1);
449 cuts[cutI++] = vertToEVert(v0);
453 // For check if all vertices have been cut (= illegal)
454 allVerticesCut = false;
457 if (edgeIsCut_[edgeI])
459 cuts[cutI++] = edgeToEVert(edgeI);
468 WarningIn("Foam::cellCuts::calcFaceCuts() const")
469 << "Face " << faceI << " vertices " << f
470 << " has all its vertices cut. Not cutting face." << endl;
475 // Remove duplicate starting point
476 if (cutI > 1 && cuts[cutI-1] == cuts[0])
485 // Find edge on face using two vertices
486 Foam::label Foam::cellCuts::findEdge
493 const edgeList& edges = mesh().edges();
495 const labelList& fEdges = mesh().faceEdges()[faceI];
499 const edge& e = edges[fEdges[i]];
503 (e[0] == v0 && e[1] == v1)
504 || (e[0] == v1 && e[1] == v0)
515 // Check if there is a face on the cell on which all cuts are.
516 Foam::label Foam::cellCuts::loopFace
519 const labelList& loop
522 const cell& cFaces = mesh().cells()[cellI];
524 forAll(cFaces, cFaceI)
526 label faceI = cFaces[cFaceI];
528 const labelList& fEdges = mesh().faceEdges()[faceI];
529 const face& f = mesh().faces()[faceI];
531 bool allOnFace = true;
539 if (findIndex(fEdges, getEdge(cut)) == -1)
541 // Edge not on face. Skip face.
548 if (findIndex(f, getVertex(cut)) == -1)
550 // Vertex not on face. Skip face.
559 // Found face where all elements of loop are on the face.
567 // From point go into connected face
568 bool Foam::cellCuts::walkPoint
571 const label startCut,
573 const label exclude0,
574 const label exclude1,
576 const label otherCut,
582 label vertI = getVertex(otherCut);
584 const labelList& pFaces = mesh().pointFaces()[vertI];
586 forAll(pFaces, pFaceI)
588 label otherFaceI = pFaces[pFaceI];
592 otherFaceI != exclude0
593 && otherFaceI != exclude1
594 && meshTools::faceOnCell(mesh(), cellI, otherFaceI)
597 label oldNVisited = nVisited;
615 // No success. Restore state and continue
616 nVisited = oldNVisited;
623 // Cross cut (which is edge on faceI) onto next face
624 bool Foam::cellCuts::crossEdge
627 const label startCut,
629 const label otherCut,
635 // Cross edge to other face
636 label edgeI = getEdge(otherCut);
638 label otherFaceI = meshTools::otherFace(mesh(), cellI, faceI, edgeI);
641 label oldNVisited = nVisited;
643 // Recurse to otherCut
661 // No success. Restore state (i.e. backtrack)
662 nVisited = oldNVisited;
669 bool Foam::cellCuts::addCut
677 // Check for duplicate cuts.
678 if (findPartIndex(visited, nVisited, cut) != -1)
680 // Truncate (copy of) visited for ease of printing.
681 labelList truncVisited(visited);
682 truncVisited.setSize(nVisited);
684 Pout<< "For cell " << cellI << " : trying to add duplicate cut " << cut;
685 labelList cuts(1, cut);
686 writeCuts(Pout, cuts, loopWeights(cuts));
689 writeCuts(Pout, truncVisited, loopWeights(truncVisited));
696 visited[nVisited++] = cut;
703 // Walk across faceI, storing cuts as you go. Returns last two cuts visisted.
704 // Returns true if valid walk.
705 bool Foam::cellCuts::walkFace
708 const label startCut,
713 label& beforeLastCut,
718 const labelList& fCuts = faceCuts()[faceI];
720 if (fCuts.size() < 2)
725 // Easy case : two cuts.
726 if (fCuts.size() == 2)
730 if (!addCut(cellI, cut, nVisited, visited))
742 if (!addCut(cellI, cut, nVisited, visited))
754 // Harder case: more than 2 cuts on face.
755 // Should be start or end of string of cuts. Store all but last cut.
759 for (label i = 0; i < fCuts.size()-1; i++)
761 if (!addCut(cellI, fCuts[i], nVisited, visited))
766 beforeLastCut = fCuts[fCuts.size()-2];
767 lastCut = fCuts[fCuts.size()-1];
769 else if (fCuts[fCuts.size()-1] == cut)
771 for (label i = fCuts.size()-1; i >= 1; --i)
773 if (!addCut(cellI, fCuts[i], nVisited, visited))
778 beforeLastCut = fCuts[1];
783 WarningIn("Foam::cellCuts::walkFace")
784 << "In middle of cut. cell:" << cellI << " face:" << faceI
785 << " cuts:" << fCuts << " current cut:" << cut << endl;
795 // Walk across cuts (cut edges or cut vertices) of cell. Stops when hit cut
796 // already visited. Returns true when loop of 3 or more vertices found.
797 bool Foam::cellCuts::walkCell
800 const label startCut,
808 // Walk across face, storing cuts. Return last two cuts visited.
810 label beforeLastCut = -1;
815 Pout<< "For cell:" << cellI << " walked across face " << faceI
817 labelList cuts(1, cut);
818 writeCuts(Pout, cuts, loopWeights(cuts));
822 bool validWalk = walkFace
842 Pout<< " to last cut ";
843 labelList cuts(1, lastCut);
844 writeCuts(Pout, cuts, loopWeights(cuts));
848 // Check if starting point reached.
849 if (lastCut == startCut)
855 // Truncate (copy of) visited for ease of printing.
856 labelList truncVisited(visited);
857 truncVisited.setSize(nVisited);
859 Pout<< "For cell " << cellI << " : found closed path:";
860 writeCuts(Pout, truncVisited, loopWeights(truncVisited));
861 Pout<< " closed by " << lastCut << endl;
868 // Loop but too short. Probably folded back on itself.
874 // Check last cut and one before that to determine type.
876 // From beforeLastCut to lastCut:
877 // - from edge to edge
878 // (- always not along existing edge)
879 // - from edge to vertex
880 // - not along existing edge
881 // - along existing edge: not allowed?
882 // - from vertex to edge
883 // - not along existing edge
884 // - along existing edge. Not allowed. See above.
885 // - from vertex to vertex
886 // - not along existing edge
887 // - along existing edge
889 if (isEdge(beforeLastCut))
893 // beforeLastCut=edge, lastCut=edge.
895 // Cross lastCut (=edge) into face not faceI
908 // beforeLastCut=edge, lastCut=vertex.
910 // Go from lastCut to all connected faces (except faceI)
915 faceI, // exclude0: don't cross back on current face
927 // beforeLastCut=vertex, lastCut=edge.
940 // beforeLastCut=vertex, lastCut=vertex. Check if along existing
946 getVertex(beforeLastCut),
952 // Cut along existing edge. So is in fact on two faces.
953 // Get faces on both sides of the edge to make
954 // sure we dont fold back on to those.
957 meshTools::getEdgeFaces(mesh(), cellI, edgeI, f0, f1);
973 // Cross cut across face.
978 faceI, // face to exclude
979 -1, // face to exclude
990 // Determine for every cut cell the loop (= face) it is cut by. Done by starting
991 // from a cut edge or cut vertex and walking across faces, from cut to cut,
992 // until starting cut hit.
993 // If multiple loops are possible across a cell circumference takes the first
995 void Foam::cellCuts::calcCellLoops(const labelList& cutCells)
997 // Calculate cuts per face.
998 const labelListList& allFaceCuts = faceCuts();
1000 // Per cell the number of faces with valid cuts. Is used as quick
1001 // rejection to see if cell can be cut.
1002 labelList nCutFaces(mesh().nCells(), 0);
1004 forAll(allFaceCuts, faceI)
1006 const labelList& fCuts = allFaceCuts[faceI];
1008 if (fCuts.size() == mesh().faces()[faceI].size())
1010 // Too many cuts on face. WalkCell would get very upset so disable.
1011 nCutFaces[mesh().faceOwner()[faceI]] = labelMin;
1013 if (mesh().isInternalFace(faceI))
1015 nCutFaces[mesh().faceNeighbour()[faceI]] = labelMin;
1018 else if (fCuts.size() >= 2)
1020 // Could be valid cut. Update count for owner and neighbour.
1021 nCutFaces[mesh().faceOwner()[faceI]]++;
1023 if (mesh().isInternalFace(faceI))
1025 nCutFaces[mesh().faceNeighbour()[faceI]]++;
1031 // Stack of visited cuts (nVisited used as stack pointer)
1033 labelList visited(mesh().nPoints());
1037 label cellI = cutCells[i];
1039 bool validLoop = false;
1041 // Quick rejection: has enough faces that are cut?
1042 if (nCutFaces[cellI] >= 3)
1044 const labelList& cFaces = mesh().cells()[cellI];
1048 Pout<< "cell:" << cellI << " cut faces:" << endl;
1051 label faceI = cFaces[i];
1052 const labelList& fCuts = allFaceCuts[faceI];
1054 Pout<< " face:" << faceI << " cuts:";
1055 writeCuts(Pout, fCuts, loopWeights(fCuts));
1062 // Determine the first cut face to start walking from.
1063 forAll(cFaces, cFaceI)
1065 label faceI = cFaces[cFaceI];
1067 const labelList& fCuts = allFaceCuts[faceI];
1069 // Take first or last cut of multiple on face.
1070 // Note that in calcFaceCuts
1071 // we have already made sure this is the start or end of a
1073 if (fCuts.size() >= 2)
1075 // Try walking from start of fCuts.
1080 Pout<< "cell:" << cellI
1081 << " start walk at face:" << faceI
1083 labelList cuts(1, fCuts[0]);
1084 writeCuts(Pout, cuts, loopWeights(cuts));
1105 // No need to try and walk from end of cuts since
1106 // all paths already tried by walkCell.
1112 // Copy nVisited elements out of visited (since visited is
1113 // never truncated for efficiency reasons)
1115 labelList& loop = cellLoops_[cellI];
1117 loop.setSize(nVisited);
1119 for (label i = 0; i < nVisited; i++)
1121 loop[i] = visited[i];
1126 // Invalid loop. Leave cellLoops_[cellI] zero size which
1128 Pout<< "calcCellLoops(const labelList&) : did not find valid"
1129 << " loop for cell " << cellI << endl;
1130 // Dump cell and cuts on cell.
1131 writeUncutOBJ(".", cellI);
1133 cellLoops_[cellI].setSize(0);
1138 //Pout<< "calcCellLoops(const labelList&) : did not find valid"
1139 // << " loop for cell " << cellI << " since not enough cut faces"
1141 cellLoops_[cellI].setSize(0);
1147 // Walk unset edges of single cell from starting point and marks visited
1148 // edges and vertices with status.
1149 void Foam::cellCuts::walkEdges
1155 Map<label>& edgeStatus,
1156 Map<label>& pointStatus
1159 if (pointStatus.insert(pointI, status))
1161 // First visit to pointI
1163 const labelList& pEdges = mesh().pointEdges()[pointI];
1165 forAll(pEdges, pEdgeI)
1167 label edgeI = pEdges[pEdgeI];
1171 meshTools::edgeOnCell(mesh(), cellI, edgeI)
1172 && edgeStatus.insert(edgeI, status)
1175 // First visit to edgeI so recurse.
1177 label v2 = mesh().edges()[edgeI].otherVertex(pointI);
1179 walkEdges(cellI, v2, status, edgeStatus, pointStatus);
1186 // Invert anchor point selection.
1187 Foam::labelList Foam::cellCuts::nonAnchorPoints
1189 const labelList& cellPoints,
1190 const labelList& anchorPoints,
1191 const labelList& loop
1194 labelList newElems(cellPoints.size());
1197 forAll(cellPoints, i)
1199 label pointI = cellPoints[i];
1203 findIndex(anchorPoints, pointI) == -1
1204 && findIndex(loop, vertToEVert(pointI)) == -1
1207 newElems[newElemI++] = pointI;
1211 newElems.setSize(newElemI);
1217 //- Check anchor points on 'outside' of loop
1218 bool Foam::cellCuts::loopAnchorConsistent
1221 const pointField& loopPts,
1222 const labelList& anchorPoints
1225 // Create identity face for ease of calculation of normal etc.
1226 face f(identity(loopPts.size()));
1228 vector normal = f.normal(loopPts);
1229 point ctr = f.centre(loopPts);
1232 // Get average position of anchor points.
1233 vector avg(vector::zero);
1235 forAll(anchorPoints, ptI)
1237 avg += mesh().points()[anchorPoints[ptI]];
1239 avg /= anchorPoints.size();
1242 if (((avg - ctr) & normal) > 0)
1253 // Determines set of anchor points given a loop. The loop should split the
1254 // cell into (one or) two sets of vertices. The set of vertices that is
1255 // on the 'normal' side of the loop is the anchor set.
1256 // Returns true if valid set, false otherwise.
1257 bool Foam::cellCuts::calcAnchors
1260 const labelList& loop,
1261 const pointField& loopPts,
1263 labelList& anchorPoints
1266 const edgeList& edges = mesh().edges();
1268 const labelList& cPoints = mesh().cellPoints()[cellI];
1269 const labelList& cEdges = mesh().cellEdges()[cellI];
1270 const cell& cFaces = mesh().cells()[cellI];
1278 Map<label> pointStatus(2*cPoints.size());
1279 Map<label> edgeStatus(2*cEdges.size());
1281 // Mark loop vertices
1284 label cut = loop[i];
1288 edgeStatus.insert(getEdge(cut), 0);
1292 pointStatus.insert(getVertex(cut), 0);
1295 // Since edges between two cut vertices have not been marked, mark them
1299 label edgeI = cEdges[i];
1300 const edge& e = edges[edgeI];
1302 if (pointStatus.found(e[0]) && pointStatus.found(e[1]))
1304 edgeStatus.insert(edgeI, 0);
1309 // Find uncut starting vertex
1310 label uncutIndex = firstUnique(cPoints, pointStatus);
1312 if (uncutIndex == -1)
1314 WarningIn("Foam::cellCuts::calcAnchors")
1315 << "Invalid loop " << loop << " for cell " << cellI << endl
1316 << "Can not find point on cell which is not cut by loop."
1319 writeOBJ(".", cellI, loopPts, labelList(0));
1324 // Walk unset vertices and edges and mark with 1 in pointStatus, edgeStatus
1325 walkEdges(cellI, cPoints[uncutIndex], 1, edgeStatus, pointStatus);
1327 // Find new uncut starting vertex
1328 uncutIndex = firstUnique(cPoints, pointStatus);
1330 if (uncutIndex == -1)
1332 // All vertices either in loop or in anchor. So split is along single
1334 WarningIn("Foam::cellCuts::calcAnchors")
1335 << "Invalid loop " << loop << " for cell " << cellI << endl
1336 << "All vertices of cell are either in loop or in anchor set"
1339 writeOBJ(".", cellI, loopPts, labelList(0));
1344 // Walk unset vertices and edges and mark with 2. These are the
1346 walkEdges(cellI, cPoints[uncutIndex], 2, edgeStatus, pointStatus);
1348 // Collect both sets in lists.
1349 DynamicList<label> connectedPoints(cPoints.size());
1350 DynamicList<label> otherPoints(cPoints.size());
1352 forAllConstIter(Map<label>, pointStatus, iter)
1356 connectedPoints.append(iter.key());
1358 else if (iter() == 2)
1360 otherPoints.append(iter.key());
1363 connectedPoints.shrink();
1364 otherPoints.shrink();
1366 // Check that all points have been used.
1367 uncutIndex = firstUnique(cPoints, pointStatus);
1369 if (uncutIndex != -1)
1371 WarningIn("Foam::cellCuts::calcAnchors")
1372 << "Invalid loop " << loop << " for cell " << cellI
1373 << " since it splits the cell into more than two cells" << endl;
1375 writeOBJ(".", cellI, loopPts, connectedPoints);
1381 // Check that both parts (connectedPoints, otherPoints) have enough faces.
1382 labelHashSet connectedFaces(2*cFaces.size());
1383 labelHashSet otherFaces(2*cFaces.size());
1385 forAllConstIter(Map<label>, pointStatus, iter)
1387 label pointI = iter.key();
1389 const labelList& pFaces = mesh().pointFaces()[pointI];
1393 forAll(pFaces, pFaceI)
1395 if (meshTools::faceOnCell(mesh(), cellI, pFaces[pFaceI]))
1397 connectedFaces.insert(pFaces[pFaceI]);
1401 else if (iter() == 2)
1403 forAll(pFaces, pFaceI)
1405 if (meshTools::faceOnCell(mesh(), cellI, pFaces[pFaceI]))
1407 otherFaces.insert(pFaces[pFaceI]);
1413 if (connectedFaces.size() < 3)
1415 WarningIn("Foam::cellCuts::calcAnchors")
1416 << "Invalid loop " << loop << " for cell " << cellI
1417 << " since would have too few faces on one side." << nl
1418 << "All faces:" << cFaces << endl;
1420 writeOBJ(".", cellI, loopPts, connectedPoints);
1425 if (otherFaces.size() < 3)
1427 WarningIn("Foam::cellCuts::calcAnchors")
1428 << "Invalid loop " << loop << " for cell " << cellI
1429 << " since would have too few faces on one side." << nl
1430 << "All faces:" << cFaces << endl;
1432 writeOBJ(".", cellI, loopPts, otherPoints);
1438 // Check that faces are split into two regions and not more.
1439 // When walking across the face the only transition of pointStatus is
1440 // from set1 to loop to set2 or back. Not allowed is from set1 to loop to
1445 label faceI = cFaces[i];
1447 const face& f = mesh().faces()[faceI];
1449 bool hasSet1 = false;
1450 bool hasSet2 = false;
1452 label prevStat = pointStatus[f[0]];
1457 label pStat = pointStatus[v0];
1459 if (pStat == prevStat)
1462 else if (pStat == 0)
1466 else if (pStat == 1)
1470 // Second occurence of set1.
1471 WarningIn("Foam::cellCuts::calcAnchors")
1472 << "Invalid loop " << loop << " for cell " << cellI
1473 << " since face " << f << " would be split into"
1474 << " more than two faces" << endl;
1476 writeOBJ(".", cellI, loopPts, otherPoints);
1483 else if (pStat == 2)
1487 // Second occurence of set1.
1488 WarningIn("Foam::cellCuts::calcAnchors")
1489 << "Invalid loop " << loop << " for cell " << cellI
1490 << " since face " << f << " would be split into"
1491 << " more than two faces" << endl;
1493 writeOBJ(".", cellI, loopPts, otherPoints);
1502 FatalErrorIn("Foam::cellCuts::calcAnchors")
1503 << abort(FatalError);
1509 label v1 = f.nextLabel(fp);
1510 label edgeI = findEdge(faceI, v0, v1);
1512 label eStat = edgeStatus[edgeI];
1514 if (eStat == prevStat)
1517 else if (eStat == 0)
1521 else if (eStat == 1)
1525 // Second occurence of set1.
1526 WarningIn("Foam::cellCuts::calcAnchors")
1527 << "Invalid loop " << loop << " for cell " << cellI
1528 << " since face " << f << " would be split into"
1529 << " more than two faces" << endl;
1531 writeOBJ(".", cellI, loopPts, otherPoints);
1538 else if (eStat == 2)
1542 // Second occurence of set1.
1543 WarningIn("Foam::cellCuts::calcAnchors")
1544 << "Invalid loop " << loop << " for cell " << cellI
1545 << " since face " << f << " would be split into"
1546 << " more than two faces" << endl;
1548 writeOBJ(".", cellI, loopPts, otherPoints);
1563 // Check which one of point sets to use.
1564 bool loopOk = loopAnchorConsistent(cellI, loopPts, connectedPoints);
1568 // Additional check: are non-anchor points on other side?
1569 bool otherLoopOk = loopAnchorConsistent(cellI, loopPts, otherPoints);
1571 if (loopOk == otherLoopOk)
1573 // Both sets of points are supposedly on the same side as the
1574 // loop normal. Oops.
1576 WarningIn("Foam::cellCuts::calcAnchors")
1577 << " For cell:" << cellI
1578 << " achorpoints and nonanchorpoints are geometrically"
1579 << " on same side!" << endl
1580 << "cellPoints:" << cPoints << endl
1581 << "loop:" << loop << endl
1582 << "anchors:" << connectedPoints << endl
1583 << "otherPoints:" << otherPoints << endl;
1585 writeOBJ(".", cellI, loopPts, connectedPoints);
1591 // connectedPoints on 'outside' of loop so these are anchor points
1592 anchorPoints.transfer(connectedPoints);
1593 connectedPoints.clear();
1597 anchorPoints.transfer(otherPoints);
1598 otherPoints.clear();
1604 Foam::pointField Foam::cellCuts::loopPoints
1606 const labelList& loop,
1607 const scalarField& loopWeights
1610 pointField loopPts(loop.size());
1614 loopPts[fp] = coord(loop[fp], loopWeights[fp]);
1620 // Returns weights of loop. Inverse of loopPoints.
1621 Foam::scalarField Foam::cellCuts::loopWeights(const labelList& loop) const
1623 scalarField weights(loop.size());
1627 label cut = loop[fp];
1631 label edgeI = getEdge(cut);
1633 weights[fp] = edgeWeight_[edgeI];
1637 weights[fp] = -GREAT;
1644 // Check if cut edges in loop are compatible with ones in edgeIsCut_
1645 bool Foam::cellCuts::validEdgeLoop
1647 const labelList& loop,
1648 const scalarField& loopWeights
1653 label cut = loop[fp];
1657 label edgeI = getEdge(cut);
1659 // Check: cut compatible only if can be snapped to existing one.
1660 if (edgeIsCut_[edgeI])
1662 scalar edgeLen = mesh().edges()[edgeI].mag(mesh().points());
1666 mag(loopWeights[fp] - edgeWeight_[edgeI])
1667 > geomCellLooper::snapTol()*edgeLen
1670 // Positions differ too much->would create two cuts.
1680 // Counts cuts on face. Includes cuts through vertices and through edges.
1681 // Assumes that if edge is cut both in edgeIsCut and in loop that the position
1682 // of the cut is the same.
1683 Foam::label Foam::cellCuts::countFaceCuts
1686 const labelList& loop
1691 // Count cut vertices
1692 const face& f = mesh().faces()[faceI];
1696 label vertI = f[fp];
1698 // Vertex already cut or mentioned in current loop.
1702 || (findIndex(loop, vertToEVert(vertI)) != -1)
1710 const labelList& fEdges = mesh().faceEdges()[faceI];
1712 forAll(fEdges, fEdgeI)
1714 label edgeI = fEdges[fEdgeI];
1716 // Edge already cut or mentioned in current loop.
1720 || (findIndex(loop, edgeToEVert(edgeI)) != -1)
1731 // Determine compatibility of loop with existing cut pattern. Does not use
1732 // cut-addressing (faceCuts_, cutCuts_)
1733 bool Foam::cellCuts::conservativeValidLoop
1736 const labelList& loop
1740 if (loop.size() < 2)
1747 if (isEdge(loop[cutI]))
1749 label edgeI = getEdge(loop[cutI]);
1751 if (edgeIsCut_[edgeI])
1753 // edge compatibility already checked.
1757 // Quick rejection: vertices of edge itself cannot be cut.
1758 const edge& e = mesh().edges()[edgeI];
1760 if (pointIsCut_[e.start()] || pointIsCut_[e.end()])
1766 // Check faces using this edge
1767 const labelList& eFaces = mesh().edgeFaces()[edgeI];
1769 forAll(eFaces, eFaceI)
1771 label nCuts = countFaceCuts(eFaces[eFaceI], loop);
1784 label vertI = getVertex(loop[cutI]);
1786 if (!pointIsCut_[vertI])
1788 // New cut through vertex.
1790 // Check edges using vertex.
1791 const labelList& pEdges = mesh().pointEdges()[vertI];
1793 forAll(pEdges, pEdgeI)
1795 label edgeI = pEdges[pEdgeI];
1797 if (edgeIsCut_[edgeI])
1803 // Check faces using vertex.
1804 const labelList& pFaces = mesh().pointFaces()[vertI];
1806 forAll(pFaces, pFaceI)
1808 label nCuts = countFaceCuts(pFaces[pFaceI], loop);
1824 // Determine compatibility of loop with existing cut pattern. Does not use
1825 // derived cut-addressing (faceCuts), only pointIsCut, edgeIsCut.
1826 // Adds any cross-cuts found to newFaceSplitCut and sets cell points on
1827 // one side of the loop in anchorPoints.
1828 bool Foam::cellCuts::validLoop
1831 const labelList& loop,
1832 const scalarField& loopWeights,
1834 Map<edge>& newFaceSplitCut,
1835 labelList& anchorPoints
1838 if (loop.size() < 2)
1845 // Allow as fallback the 'old' loop checking where only a single
1846 // cut per face is allowed.
1847 if (!conservativeValidLoop(cellI, loop))
1855 label cut = loop[fp];
1856 label nextCut = loop[(fp+1) % loop.size()];
1858 // Label (if any) of face cut (so cut not along existing edge)
1859 label meshFaceI = -1;
1863 label edgeI = getEdge(cut);
1865 // Look one cut ahead to find if it is along existing edge.
1867 if (isEdge(nextCut))
1869 // From edge to edge -> cross cut
1870 label nextEdgeI = getEdge(nextCut);
1872 // Find face and mark as to be split.
1873 meshFaceI = edgeEdgeToFace(cellI, edgeI, nextEdgeI);
1875 if (meshFaceI == -1)
1877 // Can't find face using both cut edges.
1883 // From edge to vertex -> cross cut only if no existing edge.
1885 label nextVertI = getVertex(nextCut);
1886 const edge& e = mesh().edges()[edgeI];
1888 if (e.start() != nextVertI && e.end() != nextVertI)
1890 // New edge. Find face and mark as to be split.
1891 meshFaceI = edgeVertexToFace(cellI, edgeI, nextVertI);
1893 if (meshFaceI == -1)
1895 // Can't find face. Ilegal.
1904 label vertI = getVertex(cut);
1906 if (isEdge(nextCut))
1908 // From vertex to edge -> cross cut only if no existing edge.
1909 label nextEdgeI = getEdge(nextCut);
1911 const edge& nextE = mesh().edges()[nextEdgeI];
1913 if (nextE.start() != vertI && nextE.end() != vertI)
1915 // Should be cross cut. Find face.
1916 meshFaceI = edgeVertexToFace(cellI, nextEdgeI, vertI);
1918 if (meshFaceI == -1)
1926 // From vertex to vertex -> cross cut only if no existing edge.
1927 label nextVertI = getVertex(nextCut);
1929 if (meshTools::findEdge(mesh(), vertI, nextVertI) == -1)
1931 // New edge. Find face.
1932 meshFaceI = vertexVertexToFace(cellI, vertI, nextVertI);
1934 if (meshFaceI == -1)
1942 if (meshFaceI != -1)
1944 // meshFaceI is cut across along cut-nextCut (so not along existing
1945 // edge). Check if this is compatible with existing pattern.
1946 edge cutEdge(cut, nextCut);
1948 Map<edge>::const_iterator iter = faceSplitCut_.find(meshFaceI);
1950 if (iter == faceSplitCut_.end())
1952 // Face not yet cut so insert.
1953 newFaceSplitCut.insert(meshFaceI, cutEdge);
1957 // Face already cut. Ok if same edge.
1958 if (iter() != cutEdge)
1966 // Is there a face on which all cuts are?
1967 label faceContainingLoop = loopFace(cellI, loop);
1969 if (faceContainingLoop != -1)
1971 WarningIn("Foam::cellCuts::validLoop")
1972 << "Found loop on cell " << cellI << " with all points"
1973 << " on face " << faceContainingLoop << endl;
1975 //writeOBJ(".", cellI, loopPoints(loop, loopWeights), labelList(0));
1980 // Calculate anchor points
1981 // Final success is determined by whether anchor points can be determined.
1986 loopPoints(loop, loopWeights),
1992 // Update basic cut information (pointIsCut, edgeIsCut) from cellLoops.
1993 // Assumes cellLoops_ and edgeWeight_ already set and consistent.
1994 // Does not use any other information.
1995 void Foam::cellCuts::setFromCellLoops()
1997 // 'Uncut' edges/vertices that are not used in loops.
1998 pointIsCut_ = false;
2002 faceSplitCut_.clear();
2004 forAll(cellLoops_, cellI)
2006 const labelList& loop = cellLoops_[cellI];
2010 // Storage for cross-face cuts
2011 Map<edge> faceSplitCuts(loop.size());
2012 // Storage for points on one side of cell.
2013 labelList anchorPoints;
2027 //writeOBJ(".", cellI, loopPoints(cellI), anchorPoints);
2029 //FatalErrorIn("cellCuts::setFromCellLoops()")
2030 WarningIn("cellCuts::setFromCellLoops")
2031 << "Illegal loop " << loop
2032 << " when recreating cut-addressing"
2033 << " from existing cellLoops for cell " << cellI
2035 //<< abort(FatalError);
2037 cellLoops_[cellI].setSize(0);
2038 cellAnchorPoints_[cellI].setSize(0);
2042 // Copy anchor points.
2043 cellAnchorPoints_[cellI].transfer(anchorPoints);
2045 // Copy faceSplitCuts into overall faceSplit info.
2046 forAllConstIter(Map<edge>, faceSplitCuts, iter)
2048 faceSplitCut_.insert(iter.key(), iter());
2051 // Update edgeIsCut, pointIsCut information
2054 label cut = loop[cutI];
2058 edgeIsCut_[getEdge(cut)] = true;
2062 pointIsCut_[getVertex(cut)] = true;
2069 // Reset edge weights
2070 forAll(edgeIsCut_, edgeI)
2072 if (!edgeIsCut_[edgeI])
2074 // Weight not used. Set to illegal value to make any use fall over.
2075 edgeWeight_[edgeI] = -GREAT;
2081 // Upate basic cut information from single cellLoop. Returns true if loop
2083 bool Foam::cellCuts::setFromCellLoop
2086 const labelList& loop,
2087 const scalarField& loopWeights
2090 // Dump loop for debugging.
2093 OFstream str("last_cell.obj");
2095 str<< "# edges of cell " << cellI << nl;
2107 OFstream loopStr("last_loop.obj");
2109 loopStr<< "# looppoints for cell " << cellI << nl;
2111 pointField pointsOfLoop = loopPoints(loop, loopWeights);
2113 forAll(pointsOfLoop, i)
2115 meshTools::writeOBJ(loopStr, pointsOfLoop[i]);
2120 forAll(pointsOfLoop, i)
2122 str << ' ' << i + 1;
2124 str << ' ' << 1 << nl;
2127 bool okLoop = false;
2129 if (validEdgeLoop(loop, loopWeights))
2131 // Storage for cuts across face
2132 Map<edge> faceSplitCuts(loop.size());
2133 // Storage for points on one side of cell
2134 labelList anchorPoints;
2137 validLoop(cellI, loop, loopWeights, faceSplitCuts, anchorPoints);
2141 // Valid loop. Copy cellLoops and anchorPoints
2142 cellLoops_[cellI] = loop;
2143 cellAnchorPoints_[cellI].transfer(anchorPoints);
2146 forAllConstIter(Map<edge>, faceSplitCuts, iter)
2148 faceSplitCut_.insert(iter.key(), iter());
2152 // Update edgeIsCut, pointIsCut information
2155 label cut = loop[cutI];
2159 label edgeI = getEdge(cut);
2161 edgeIsCut_[edgeI] = true;
2163 edgeWeight_[edgeI] = loopWeights[cutI];
2167 label vertI = getVertex(cut);
2169 pointIsCut_[vertI] = true;
2179 // Update basic cut information from cellLoops. Checks for consistency with
2180 // existing cut pattern.
2181 void Foam::cellCuts::setFromCellLoops
2183 const labelList& cellLabels,
2184 const labelListList& cellLoops,
2185 const List<scalarField>& cellLoopWeights
2188 // 'Uncut' edges/vertices that are not used in loops.
2189 pointIsCut_ = false;
2193 forAll(cellLabels, cellLabelI)
2195 label cellI = cellLabels[cellLabelI];
2197 const labelList& loop = cellLoops[cellLabelI];
2201 const scalarField& loopWeights = cellLoopWeights[cellLabelI];
2203 if (setFromCellLoop(cellI, loop, loopWeights))
2205 // Valid loop. Call above will have upated all already.
2210 cellLoops_[cellI].setSize(0);
2217 // Cut cells and update basic cut information from cellLoops. Checks each loop
2218 // for consistency with existing cut pattern.
2219 void Foam::cellCuts::setFromCellCutter
2221 const cellLooper& cellCutter,
2222 const List<refineCell>& refCells
2225 // 'Uncut' edges/vertices that are not used in loops.
2226 pointIsCut_ = false;
2230 // storage for loop of cuts (cut vertices and/or cut edges)
2232 scalarField cellLoopWeights;
2234 // For debugging purposes
2235 DynamicList<label> invalidCutCells(2);
2236 DynamicList<labelList> invalidCutLoops(2);
2237 DynamicList<scalarField> invalidCutLoopWeights(2);
2240 forAll(refCells, refCellI)
2242 const refineCell& refCell = refCells[refCellI];
2244 label cellI = refCell.cellNo();
2246 const vector& refDir = refCell.direction();
2249 // Cut cell. Determines cellLoop and cellLoopWeights
2264 // Check whether edge refinement is on a per face basis compatible with
2268 if (setFromCellLoop(cellI, cellLoop, cellLoopWeights))
2270 // Valid loop. Will have updated all info already.
2274 cellLoops_[cellI].setSize(0);
2276 // Discarded by validLoop
2279 invalidCutCells.append(cellI);
2280 invalidCutLoops.append(cellLoop);
2281 invalidCutLoopWeights.append(cellLoopWeights);
2288 cellLoops_[cellI].setSize(0);
2292 if (debug && invalidCutCells.size())
2294 invalidCutCells.shrink();
2295 invalidCutLoops.shrink();
2296 invalidCutLoopWeights.shrink();
2298 fileName cutsFile("invalidLoopCells.obj");
2300 Pout<< "cellCuts : writing inValidLoops cells to " << cutsFile << endl;
2302 OFstream cutsStream(cutsFile);
2313 fileName loopsFile("invalidLoops.obj");
2315 Pout<< "cellCuts : writing inValidLoops loops to " << loopsFile << endl;
2317 OFstream loopsStream(loopsFile);
2321 forAll(invalidCutLoops, i)
2326 loopPoints(invalidCutLoops[i], invalidCutLoopWeights[i]),
2334 // Same as one before but cut plane prescribed (instead of just normal)
2335 void Foam::cellCuts::setFromCellCutter
2337 const cellLooper& cellCutter,
2338 const labelList& cellLabels,
2339 const List<plane>& cellCutPlanes
2342 // 'Uncut' edges/vertices that are not used in loops.
2343 pointIsCut_ = false;
2347 // storage for loop of cuts (cut vertices and/or cut edges)
2349 scalarField cellLoopWeights;
2351 // For debugging purposes
2352 DynamicList<label> invalidCutCells(2);
2353 DynamicList<labelList> invalidCutLoops(2);
2354 DynamicList<scalarField> invalidCutLoopWeights(2);
2357 forAll(cellLabels, i)
2359 label cellI = cellLabels[i];
2361 // Cut cell. Determines cellLoop and cellLoopWeights
2376 // Check whether edge refinement is on a per face basis compatible with
2380 if (setFromCellLoop(cellI, cellLoop, cellLoopWeights))
2382 // Valid loop. Will have updated all info already.
2386 cellLoops_[cellI].setSize(0);
2388 // Discarded by validLoop
2391 invalidCutCells.append(cellI);
2392 invalidCutLoops.append(cellLoop);
2393 invalidCutLoopWeights.append(cellLoopWeights);
2400 cellLoops_[cellI].setSize(0);
2404 if (debug && invalidCutCells.size())
2406 invalidCutCells.shrink();
2407 invalidCutLoops.shrink();
2408 invalidCutLoopWeights.shrink();
2410 fileName cutsFile("invalidLoopCells.obj");
2412 Pout<< "cellCuts : writing inValidLoops cells to " << cutsFile << endl;
2414 OFstream cutsStream(cutsFile);
2425 fileName loopsFile("invalidLoops.obj");
2427 Pout<< "cellCuts : writing inValidLoops loops to " << loopsFile << endl;
2429 OFstream loopsStream(loopsFile);
2433 forAll(invalidCutLoops, i)
2438 loopPoints(invalidCutLoops[i], invalidCutLoopWeights[i]),
2446 // Set orientation of loops
2447 void Foam::cellCuts::orientPlanesAndLoops()
2449 // Determine anchorPoints if not yet done by validLoop.
2450 forAll(cellLoops_, cellI)
2452 const labelList& loop = cellLoops_[cellI];
2454 if (loop.size() && cellAnchorPoints_[cellI].empty())
2456 // Leave anchor points empty if illegal loop.
2462 cellAnchorPoints_[cellI]
2469 Pout<< "cellAnchorPoints:" << endl;
2471 forAll(cellAnchorPoints_, cellI)
2473 if (cellLoops_[cellI].size())
2475 if (cellAnchorPoints_[cellI].empty())
2477 FatalErrorIn("orientPlanesAndLoops()")
2478 << "No anchor points for cut cell " << cellI << endl
2479 << "cellLoop:" << cellLoops_[cellI] << abort(FatalError);
2484 Pout<< " cell:" << cellI << " anchored at "
2485 << cellAnchorPoints_[cellI] << endl;
2490 // Calculate number of valid cellLoops
2493 forAll(cellLoops_, cellI)
2495 if (cellLoops_[cellI].size())
2503 // Do all: calculate addressing, calculate loops splitting cells
2504 void Foam::cellCuts::calcLoopsAndAddressing(const labelList& cutCells)
2506 // Sanity check on weights
2507 forAll(edgeIsCut_, edgeI)
2509 if (edgeIsCut_[edgeI])
2511 scalar weight = edgeWeight_[edgeI];
2513 if (weight < 0 || weight > 1)
2517 "cellCuts::calcLoopsAndAddressing(const labelList&)"
2518 ) << "Weight out of range [0,1]. Edge " << edgeI
2519 << " verts:" << mesh().edges()[edgeI]
2520 << " weight:" << weight << abort(FatalError);
2525 // Weight not used. Set to illegal value to make any use fall over.
2526 edgeWeight_[edgeI] = -GREAT;
2531 // Calculate faces that split cells in two
2532 calcCellLoops(cutCells);
2536 Pout<< "-- cellLoops --" << endl;
2537 forAll(cellLoops_, cellI)
2539 const labelList& loop = cellLoops_[cellI];
2543 Pout<< "cell:" << cellI << " ";
2544 writeCuts(Pout, loop, loopWeights(loop));
2550 // Redo basic cut information (pointIsCut, edgeIsCut, faceSplitCut)
2551 // using cellLoop only.
2556 void Foam::cellCuts::check() const
2558 // Check weights for unsnapped values
2559 forAll(edgeIsCut_, edgeI)
2561 if (edgeIsCut_[edgeI])
2565 edgeWeight_[edgeI] < geomCellLooper::snapTol()
2566 || edgeWeight_[edgeI] > (1 - geomCellLooper::snapTol())
2569 // Should have been snapped.
2570 //FatalErrorIn("cellCuts::check()")
2571 WarningIn("cellCuts::check()")
2572 << "edge:" << edgeI << " vertices:"
2573 << mesh().edges()[edgeI]
2574 << " weight:" << edgeWeight_[edgeI] << " should have been"
2575 << " snapped to one of its endpoints"
2576 //<< abort(FatalError);
2582 if (edgeWeight_[edgeI] > - 1)
2584 FatalErrorIn("cellCuts::check()")
2585 << "edge:" << edgeI << " vertices:"
2586 << mesh().edges()[edgeI]
2587 << " weight:" << edgeWeight_[edgeI] << " is not cut but"
2588 << " its weight is not marked invalid"
2589 << abort(FatalError);
2594 // Check that all elements of cellloop are registered
2595 forAll(cellLoops_, cellI)
2597 const labelList& loop = cellLoops_[cellI];
2601 label cut = loop[i];
2605 (isEdge(cut) && !edgeIsCut_[getEdge(cut)])
2606 || (!isEdge(cut) && !pointIsCut_[getVertex(cut)])
2609 labelList cuts(1, cut);
2610 writeCuts(Pout, cuts, loopWeights(cuts));
2612 FatalErrorIn("cellCuts::check()")
2613 << "cell:" << cellI << " loop:"
2615 << " cut:" << cut << " is not marked as cut"
2616 << abort(FatalError);
2621 // Check that no elements of cell loop are anchor point.
2622 forAll(cellLoops_, cellI)
2624 const labelList& anchors = cellAnchorPoints_[cellI];
2626 const labelList& loop = cellLoops_[cellI];
2628 if (loop.size() && anchors.empty())
2630 FatalErrorIn("cellCuts::check()")
2631 << "cell:" << cellI << " loop:" << loop
2632 << " has no anchor points"
2633 << abort(FatalError);
2639 label cut = loop[i];
2644 && findIndex(anchors, getVertex(cut)) != -1
2647 FatalErrorIn("cellCuts::check()")
2648 << "cell:" << cellI << " loop:" << loop
2649 << " anchor points:" << anchors
2650 << " anchor:" << getVertex(cut) << " is part of loop"
2651 << abort(FatalError);
2657 // Check that cut faces have a neighbour that is cut.
2658 forAllConstIter(Map<edge>, faceSplitCut_, iter)
2660 label faceI = iter.key();
2662 if (mesh().isInternalFace(faceI))
2664 label own = mesh().faceOwner()[faceI];
2665 label nei = mesh().faceNeighbour()[faceI];
2667 if (cellLoops_[own].empty() && cellLoops_[nei].empty())
2669 FatalErrorIn("cellCuts::check()")
2670 << "Internal face:" << faceI << " cut by " << iter()
2671 << " has owner:" << own
2672 << " and neighbour:" << nei
2673 << " that are both uncut"
2674 << abort(FatalError);
2679 label own = mesh().faceOwner()[faceI];
2681 if (cellLoops_[own].empty())
2683 FatalErrorIn("cellCuts::check()")
2684 << "Boundary face:" << faceI << " cut by " << iter()
2685 << " has owner:" << own
2687 << abort(FatalError);
2694 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
2696 // Construct from cells to cut and pattern of cuts
2697 Foam::cellCuts::cellCuts
2699 const polyMesh& mesh,
2700 const labelList& cutCells,
2701 const labelList& meshVerts,
2702 const labelList& meshEdges,
2703 const scalarField& meshEdgeWeights
2707 pointIsCut_(expand(mesh.nPoints(), meshVerts)),
2708 edgeIsCut_(expand(mesh.nEdges(), meshEdges)),
2709 edgeWeight_(expand(mesh.nEdges(), meshEdges, meshEdgeWeights)),
2711 faceSplitCut_(cutCells.size()),
2712 cellLoops_(mesh.nCells()),
2714 cellAnchorPoints_(mesh.nCells())
2718 Pout<< "cellCuts : constructor from cut verts and edges" << endl;
2721 calcLoopsAndAddressing(cutCells);
2723 // Calculate planes and flip cellLoops if nessecary
2724 orientPlanesAndLoops();
2735 Pout<< "cellCuts : leaving constructor from cut verts and edges"
2741 // Construct from pattern of cuts. Finds out itself which cells are cut.
2742 // (can go wrong if e.g. all neighbours of cell are refined)
2743 Foam::cellCuts::cellCuts
2745 const polyMesh& mesh,
2746 const labelList& meshVerts,
2747 const labelList& meshEdges,
2748 const scalarField& meshEdgeWeights
2752 pointIsCut_(expand(mesh.nPoints(), meshVerts)),
2753 edgeIsCut_(expand(mesh.nEdges(), meshEdges)),
2754 edgeWeight_(expand(mesh.nEdges(), meshEdges, meshEdgeWeights)),
2756 faceSplitCut_(mesh.nFaces()/10 + 1),
2757 cellLoops_(mesh.nCells()),
2759 cellAnchorPoints_(mesh.nCells())
2763 Pout<< "cellCuts : constructor from cellLoops" << endl;
2766 calcLoopsAndAddressing(identity(mesh.nCells()));
2768 // Calculate planes and flip cellLoops if nessecary
2769 orientPlanesAndLoops();
2780 Pout<< "cellCuts : leaving constructor from cellLoops" << endl;
2785 // Construct from complete cellLoops. Assumes correct cut pattern.
2786 // Only constructs cut-cut addressing and cellAnchorPoints
2787 Foam::cellCuts::cellCuts
2789 const polyMesh& mesh,
2790 const labelList& cellLabels,
2791 const labelListList& cellLoops,
2792 const List<scalarField>& cellEdgeWeights
2796 pointIsCut_(mesh.nPoints(), false),
2797 edgeIsCut_(mesh.nEdges(), false),
2798 edgeWeight_(mesh.nEdges(), -GREAT),
2800 faceSplitCut_(cellLabels.size()),
2801 cellLoops_(mesh.nCells()),
2803 cellAnchorPoints_(mesh.nCells())
2807 Pout<< "cellCuts : constructor from cellLoops" << endl;
2810 // Update pointIsCut, edgeIsCut, faceSplitCut from cell loops.
2811 // Makes sure cuts are consistent
2812 setFromCellLoops(cellLabels, cellLoops, cellEdgeWeights);
2814 // Calculate planes and flip cellLoops if nessecary
2815 orientPlanesAndLoops();
2826 Pout<< "cellCuts : leaving constructor from cellLoops" << endl;
2831 // Construct from list of cells to cut and cell cutter.
2832 Foam::cellCuts::cellCuts
2834 const polyMesh& mesh,
2835 const cellLooper& cellCutter,
2836 const List<refineCell>& refCells
2840 pointIsCut_(mesh.nPoints(), false),
2841 edgeIsCut_(mesh.nEdges(), false),
2842 edgeWeight_(mesh.nEdges(), -GREAT),
2844 faceSplitCut_(refCells.size()),
2845 cellLoops_(mesh.nCells()),
2847 cellAnchorPoints_(mesh.nCells())
2851 Pout<< "cellCuts : constructor from cellCutter" << endl;
2854 // Update pointIsCut, edgeIsCut, faceSplitCut from cell loops.
2855 // Makes sure cuts are consistent
2856 setFromCellCutter(cellCutter, refCells);
2858 // Calculate planes and flip cellLoops if nessecary
2859 orientPlanesAndLoops();
2870 Pout<< "cellCuts : leaving constructor from cellCutter" << endl;
2875 // Construct from list of cells to cut, plane to cut with and cell cutter.
2876 Foam::cellCuts::cellCuts
2878 const polyMesh& mesh,
2879 const cellLooper& cellCutter,
2880 const labelList& cellLabels,
2881 const List<plane>& cutPlanes
2885 pointIsCut_(mesh.nPoints(), false),
2886 edgeIsCut_(mesh.nEdges(), false),
2887 edgeWeight_(mesh.nEdges(), -GREAT),
2889 faceSplitCut_(cellLabels.size()),
2890 cellLoops_(mesh.nCells()),
2892 cellAnchorPoints_(mesh.nCells())
2896 Pout<< "cellCuts : constructor from cellCutter with prescribed plane"
2900 // Update pointIsCut, edgeIsCut, faceSplitCut from cell loops.
2901 // Makes sure cuts are consistent
2902 setFromCellCutter(cellCutter, cellLabels, cutPlanes);
2904 // Calculate planes and flip cellLoops if nessecary
2905 orientPlanesAndLoops();
2916 Pout<< "cellCuts : leaving constructor from cellCutter with prescribed"
2917 << " plane" << endl;
2922 // Construct from components
2923 Foam::cellCuts::cellCuts
2925 const polyMesh& mesh,
2926 const boolList& pointIsCut,
2927 const boolList& edgeIsCut,
2928 const scalarField& edgeWeight,
2929 const Map<edge>& faceSplitCut,
2930 const labelListList& cellLoops,
2932 const labelListList& cellAnchorPoints
2936 pointIsCut_(pointIsCut),
2937 edgeIsCut_(edgeIsCut),
2938 edgeWeight_(edgeWeight),
2940 faceSplitCut_(faceSplitCut),
2941 cellLoops_(cellLoops),
2943 cellAnchorPoints_(cellAnchorPoints)
2947 Pout<< "cellCuts : constructor from components" << endl;
2948 Pout<< "cellCuts : leaving constructor from components" << endl;
2953 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
2955 Foam::cellCuts::~cellCuts()
2961 void Foam::cellCuts::clearOut()
2963 deleteDemandDrivenData(faceCutsPtr_);
2967 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2969 Foam::pointField Foam::cellCuts::loopPoints(const label cellI) const
2971 const labelList& loop = cellLoops_[cellI];
2973 pointField loopPts(loop.size());
2977 label cut = loop[fp];
2981 label edgeI = getEdge(cut);
2983 loopPts[fp] = coord(cut, edgeWeight_[edgeI]);
2987 loopPts[fp] = coord(cut, -GREAT);
2994 // Flip loop for cell
2995 void Foam::cellCuts::flip(const label cellI)
2997 labelList& loop = cellLoops_[cellI];
3001 // Reverse anchor point set.
3002 cellAnchorPoints_[cellI] =
3005 mesh().cellPoints()[cellI],
3006 cellAnchorPoints_[cellI],
3013 void Foam::cellCuts::flipLoopOnly(const label cellI)
3015 labelList& loop = cellLoops_[cellI];
3021 void Foam::cellCuts::writeOBJ
3024 const pointField& loopPts,
3028 label startVertI = vertI;
3032 const point& pt = loopPts[fp];
3034 os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
3042 os << ' ' << startVertI + fp + 1;
3048 void Foam::cellCuts::writeOBJ(Ostream& os) const
3052 forAll(cellLoops_, cellI)
3054 writeOBJ(os, loopPoints(cellI), vertI);
3059 void Foam::cellCuts::writeCellOBJ(const fileName& dir, const label cellI) const
3061 const labelList& anchors = cellAnchorPoints_[cellI];
3063 writeOBJ(dir, cellI, loopPoints(cellI), anchors);
3067 // ************************************************************************* //