1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
28 #include "objectMap.H"
29 #include "changeMap.H"
30 #include "multiThreader.H"
31 #include "dynamicTopoFvMesh.H"
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
40 // Method for the collapse of a quad-face in 2D
41 // - Returns a changeMap with a type specifying:
42 // -1: Collapse failed since max number of topo-changes was reached.
43 // 0: Collapse could not be performed.
44 // 1: Collapsed to first node.
45 // 2: Collapsed to second node.
46 // - overRideCase is used to force a certain collapse configuration.
47 // -1: Use this value to let collapseQuadFace decide a case.
48 // 1: Force collapse to first node.
49 // 2: Force collapse to second node.
50 // - checkOnly performs a feasibility check and returns without modifications.
51 const changeMap dynamicTopoFvMesh::collapseQuadFace
59 // Figure out which thread this is...
60 label tIndex = self();
62 // Prepare the changeMap
67 (statistics_[0] > maxModifications_)
68 && (maxModifications_ > -1)
71 // Reached the max allowable topo-changes.
72 stack(tIndex).clear();
77 // Check if edgeRefinements are to be avoided on patch.
78 if (lengthEstimator().checkRefinementPatch(whichPatch(fIndex)))
83 // Sanity check: Is the index legitimate?
90 "dynamicTopoFvMesh::collapseQuadFace\n"
92 " const label fIndex,\n"
93 " label overRideCase,\n"
97 << " Invalid index: " << fIndex
101 // Define the edges on the face to be collapsed
102 FixedList<edge,4> checkEdge(edge(-1,-1));
103 FixedList<label,4> checkEdgeIndex(-1);
106 checkEdgeIndex[0] = getTriBoundaryEdge(fIndex);
107 checkEdge[0] = edges_[checkEdgeIndex[0]];
109 const labelList& fEdges = faceEdges_[fIndex];
111 forAll(fEdges, edgeI)
113 if (checkEdgeIndex[0] != fEdges[edgeI])
115 const edge& thisEdge = edges_[fEdges[edgeI]];
119 checkEdge[0].start() == thisEdge[0] ||
120 checkEdge[0].start() == thisEdge[1]
123 checkEdgeIndex[1] = fEdges[edgeI];
124 checkEdge[1] = thisEdge;
127 map.firstEdge() = checkEdgeIndex[1];
132 checkEdge[0].end() == thisEdge[0] ||
133 checkEdge[0].end() == thisEdge[1]
136 checkEdgeIndex[2] = fEdges[edgeI];
137 checkEdge[2] = thisEdge;
140 map.secondEdge() = checkEdgeIndex[2];
144 checkEdgeIndex[3] = fEdges[edgeI];
145 checkEdge[3] = thisEdge;
150 // Build a hull of cells and tri-faces that are connected to each edge
151 FixedList<labelList, 2> hullCells;
152 FixedList<labelList, 2> hullTriFaces;
154 meshOps::constructPrismHull
166 meshOps::constructPrismHull
178 // Determine the neighbouring cells
179 label c0 = owner_[fIndex], c1 = neighbour_[fIndex];
181 // Define variables for the prism-face calculation
182 FixedList<face,2> c0BdyFace, c0IntFace, c1BdyFace, c1IntFace;
183 FixedList<label,2> c0BdyIndex, c0IntIndex, c1BdyIndex, c1IntIndex;
185 // Find the prism-faces
186 meshOps::findPrismFaces
201 meshOps::findPrismFaces
215 // Determine if either edge belongs to a boundary
216 FixedList<bool, 2> nBoundCurves(false), edgeBoundary(false);
218 edgeBoundary[0] = (whichEdgePatch(checkEdgeIndex[1]) > -1);
219 edgeBoundary[1] = (whichEdgePatch(checkEdgeIndex[2]) > -1);
221 // Decide on collapseCase
222 label collapseCase = -1;
224 if (edgeBoundary[0] && !edgeBoundary[1])
229 if (!edgeBoundary[0] && edgeBoundary[1])
234 if (edgeBoundary[0] && edgeBoundary[1])
244 "dynamicTopoFvMesh::collapseQuadFace\n"
246 " const label fIndex,\n"
247 " label overRideCase,\n"
250 ) << "Collapsing an internal face that "
251 << "lies on two boundary patches. "
252 << "Face: " << fIndex << ": " << faces_[fIndex]
256 // Bail out for now. If proximity based refinement is
257 // switched on, mesh may be sliced at this point.
261 // Check if either edge lies on a bounding curve.
262 if (checkBoundingCurve(checkEdgeIndex[1]))
264 nBoundCurves[0] = true;
267 if (checkBoundingCurve(checkEdgeIndex[2]))
269 nBoundCurves[1] = true;
272 // Collapse towards a bounding curve
273 if (nBoundCurves[0] && !nBoundCurves[1])
278 if (!nBoundCurves[0] && nBoundCurves[1])
283 if (!nBoundCurves[0] && !nBoundCurves[1])
285 // No bounding curves. Collapse to mid-point.
290 // Two bounding curves? This might cause pinching.
297 // Looks like this is an interior face.
298 // Collapse case [3] by default
302 // Perform an override if requested.
303 if (overRideCase != -1)
305 collapseCase = overRideCase;
308 // Configure the new point-positions
309 FixedList<bool, 2> check(false);
310 FixedList<FixedList<label, 2>, 2> checkPoints(FixedList<label, 2>(-1));
311 FixedList<point, 2> newPoint(vector::zero);
312 FixedList<point, 2> oldPoint(vector::zero);
314 // Determine the common vertices for the first and second edges
315 label cv0 = checkEdge[1].commonVertex(checkEdge[0]);
316 label cv1 = checkEdge[1].commonVertex(checkEdge[3]);
317 label cv2 = checkEdge[2].commonVertex(checkEdge[0]);
318 label cv3 = checkEdge[2].commonVertex(checkEdge[3]);
320 // Replacement check points
321 FixedList<label,2> original(-1), replacement(-1);
323 switch (collapseCase)
327 // Collapse to the first node
328 original[0] = cv2; original[1] = cv3;
329 replacement[0] = cv0; replacement[1] = cv1;
331 newPoint[0] = points_[replacement[0]];
332 newPoint[1] = points_[replacement[1]];
334 oldPoint[0] = oldPoints_[replacement[0]];
335 oldPoint[1] = oldPoints_[replacement[1]];
337 // Define check-points
339 checkPoints[1][0] = original[0];
340 checkPoints[1][1] = original[1];
347 // Collapse to the second node
348 original[0] = cv0; original[1] = cv1;
349 replacement[0] = cv2; replacement[1] = cv3;
351 newPoint[0] = points_[replacement[0]];
352 newPoint[1] = points_[replacement[1]];
354 oldPoint[0] = oldPoints_[replacement[0]];
355 oldPoint[1] = oldPoints_[replacement[1]];
357 // Define check-points
359 checkPoints[0][0] = original[0];
360 checkPoints[0][1] = original[1];
367 // Collapse to the mid-point
368 original[0] = cv0; original[1] = cv1;
369 replacement[0] = cv2; replacement[1] = cv3;
371 // Define new point-positions
377 + points_[replacement[0]]
386 + points_[replacement[1]]
390 // Specify off-centering
391 scalar offCentre = (c1 == -1) ? 0.0 : 1.0;
393 FixedList<vector,2> te(vector::zero), xf(vector::zero);
394 FixedList<vector,2> ne(vector::zero), nf(vector::zero);
396 // Compute tangent-to-edge
397 te[0] = (oldPoints_[replacement[0]] - oldPoints_[original[0]]);
398 te[1] = (oldPoints_[replacement[1]] - oldPoints_[original[1]]);
400 // Compute face position / normal
401 if (c0BdyFace[0].which(original[0]) > -1)
403 xf[0] = c0BdyFace[0].centre(oldPoints_);
404 nf[0] = c0BdyFace[0].normal(oldPoints_);
406 xf[1] = c0BdyFace[1].centre(oldPoints_);
407 nf[1] = c0BdyFace[1].normal(oldPoints_);
410 if (c0BdyFace[1].which(original[0]) > -1)
412 xf[0] = c0BdyFace[1].centre(oldPoints_);
413 nf[0] = c0BdyFace[1].normal(oldPoints_);
415 xf[1] = c0BdyFace[0].centre(oldPoints_);
416 nf[1] = c0BdyFace[0].normal(oldPoints_);
424 "dynamicTopoFvMesh::collapseQuadFace\n"
426 " const label fIndex,\n"
427 " label overRideCase,\n"
430 ) << "Could not find point in face."
434 // Compute edge-normals
435 ne[0] = (te[0] ^ nf[0]);
436 ne[1] = (te[1] ^ nf[1]);
438 ne[0] /= mag(ne[0]) + VSMALL;
439 ne[1] /= mag(ne[1]) + VSMALL;
441 // Reverse the vector, if necessary
442 if ((ne[0] & ne[1]) < 0.0)
447 // Define modified old point-positions,
448 // with off-centering, if necessary
451 oldPoints_[original[0]]
453 + (((0.05 * mag(te[0])) * ne[0]) * offCentre)
458 oldPoints_[original[1]]
460 + (((0.05 * mag(te[1])) * ne[1]) * offCentre)
463 // Define check-points
465 checkPoints[0][0] = original[0];
466 checkPoints[0][1] = original[1];
469 checkPoints[1][0] = replacement[0];
470 checkPoints[1][1] = replacement[1];
477 // Don't think this will ever happen.
482 "dynamicTopoFvMesh::collapseQuadFace\n"
484 " const label fIndex,\n"
485 " label overRideCase,\n"
489 << "Edge: " << fIndex << ": " << faces_[fIndex]
490 << ". Couldn't decide on collapseCase."
491 << abort(FatalError);
497 // Keep track of resulting cell quality,
498 // if collapse is indeed feasible
499 scalar collapseQuality(GREAT);
501 // Check collapsibility of cells around edges
502 // with the re-configured point
503 forAll(check, indexI)
510 // Check whether the collapse is possible.
515 hullTriFaces[indexI],
532 // Are we only performing checks?
535 map.type() = collapseCase;
539 Info << "Face: " << fIndex
540 << ":: " << faces_[fIndex] << nl
541 << " collapseCase determined to be: "
542 << collapseCase << nl
543 << " Resulting quality: "
553 const labelList& fE = faceEdges_[fIndex];
556 << "Face: " << fIndex << ": " << faces_[fIndex] << nl
557 << "faceEdges: " << fE
558 << " is to be collapsed. " << endl;
560 label epIndex = whichPatch(fIndex);
566 Info << "Internal" << endl;
570 Info << boundaryMesh()[epIndex].name() << endl;
576 Info << "~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
577 Info << "Hulls before modification" << endl;
578 Info << "~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
580 Info << nl << "Cells belonging to first Edge Hull: "
581 << hullCells[0] << endl;
583 forAll(hullCells[0],cellI)
585 const cell& firstCurCell = cells_[hullCells[0][cellI]];
587 Info << "Cell: " << hullCells[0][cellI]
588 << ": " << firstCurCell << endl;
590 forAll(firstCurCell,faceI)
592 Info << firstCurCell[faceI]
593 << ": " << faces_[firstCurCell[faceI]] << endl;
597 const labelList& firstEdgeFaces = edgeFaces_[checkEdgeIndex[1]];
599 Info << nl << "First Edge Face Hull: "
600 << firstEdgeFaces << endl;
602 forAll(firstEdgeFaces,indexI)
604 Info << firstEdgeFaces[indexI]
605 << ": " << faces_[firstEdgeFaces[indexI]] << endl;
608 Info << nl << "Cells belonging to second Edge Hull: "
609 << hullCells[1] << endl;
611 forAll(hullCells[1], cellI)
613 const cell& secondCurCell = cells_[hullCells[1][cellI]];
615 Info << "Cell: " << hullCells[1][cellI]
616 << ": " << secondCurCell << endl;
618 forAll(secondCurCell, faceI)
620 Info << secondCurCell[faceI]
621 << ": " << faces_[secondCurCell[faceI]] << endl;
625 const labelList& secondEdgeFaces = edgeFaces_[checkEdgeIndex[2]];
627 Info << nl << "Second Edge Face Hull: "
628 << secondEdgeFaces << endl;
630 forAll(secondEdgeFaces, indexI)
632 Info << secondEdgeFaces[indexI]
633 << ": " << faces_[secondEdgeFaces[indexI]] << endl;
636 // Write out VTK files prior to change
639 labelHashSet vtkCells;
641 forAll(hullCells[0], cellI)
643 if (!vtkCells.found(hullCells[0][cellI]))
645 vtkCells.insert(hullCells[0][cellI]);
649 forAll(hullCells[1], cellI)
651 if (!vtkCells.found(hullCells[1][cellI]))
653 vtkCells.insert(hullCells[1][cellI]);
667 // Edges / Quad-faces to throw or keep during collapse
668 FixedList<label,2> ends(-1);
669 FixedList<label,2> faceToKeep(-1), faceToThrow(-1);
670 FixedList<label,4> edgeToKeep(-1), edgeToThrow(-1);
672 // Maintain a list of modified faces for mapping
673 labelHashSet modifiedFaces;
675 // Case 2 & 3 use identical connectivity,
676 // but different point locations
677 if (collapseCase == 2 || collapseCase == 3)
679 const labelList& firstEdgeFaces = edgeFaces_[checkEdgeIndex[1]];
681 // Collapse to the second node...
682 forAll(firstEdgeFaces,faceI)
684 // Replace point indices on faces.
685 meshOps::replaceLabel
689 faces_[firstEdgeFaces[faceI]]
692 meshOps::replaceLabel
696 faces_[firstEdgeFaces[faceI]]
699 // Add an entry for mapping
700 if (!modifiedFaces.found(firstEdgeFaces[faceI]))
702 modifiedFaces.insert(firstEdgeFaces[faceI]);
705 // Determine the quad-face in cell[0] & cell[1]
706 // that belongs to firstEdgeFaces
707 if (firstEdgeFaces[faceI] == c0IntIndex[0])
709 faceToKeep[0] = c0IntIndex[1];
710 faceToThrow[0] = c0IntIndex[0];
713 if (firstEdgeFaces[faceI] == c0IntIndex[1])
715 faceToKeep[0] = c0IntIndex[0];
716 faceToThrow[0] = c0IntIndex[1];
721 if (firstEdgeFaces[faceI] == c1IntIndex[0])
723 faceToKeep[1] = c1IntIndex[1];
724 faceToThrow[1] = c1IntIndex[0];
727 if (firstEdgeFaces[faceI] == c1IntIndex[1])
729 faceToKeep[1] = c1IntIndex[0];
730 faceToThrow[1] = c1IntIndex[1];
735 // Find common edges between quad / tri faces...
736 meshOps::findCommonEdge
744 meshOps::findCommonEdge
752 meshOps::findCommonEdge
760 meshOps::findCommonEdge
768 // Size down edgeFaces for the ends.
769 meshOps::findCommonEdge
777 meshOps::sizeDownList
785 meshOps::findCommonEdge
793 meshOps::findCommonEdge
801 meshOps::findCommonEdge
809 meshOps::findCommonEdge
817 // Size down edgeFaces for the ends.
818 meshOps::findCommonEdge
826 meshOps::sizeDownList
833 // Correct edgeFaces for triangular faces...
834 forAll(edgeToThrow, indexI)
836 if (edgeToThrow[indexI] == -1)
841 const labelList& eF = edgeFaces_[edgeToThrow[indexI]];
843 label origTriFace = -1, retTriFace = -1;
845 // Find the original triangular face index
848 if (eF[faceI] == c0BdyIndex[0])
850 origTriFace = c0BdyIndex[0];
854 if (eF[faceI] == c0BdyIndex[1])
856 origTriFace = c0BdyIndex[1];
860 if (eF[faceI] == c1BdyIndex[0])
862 origTriFace = c1BdyIndex[0];
866 if (eF[faceI] == c1BdyIndex[1])
868 origTriFace = c1BdyIndex[1];
873 // Find the retained triangular face index
878 (eF[faceI] != origTriFace) &&
879 (eF[faceI] != faceToThrow[0]) &&
880 (eF[faceI] != faceToThrow[1])
883 retTriFace = eF[faceI];
888 // Finally replace the face index
889 if (retTriFace == -1)
891 // Couldn't find a retained face.
892 // This must be a boundary edge, so size-down instead.
893 meshOps::sizeDownList
896 edgeFaces_[edgeToKeep[indexI]]
901 meshOps::replaceLabel
905 edgeFaces_[edgeToKeep[indexI]]
908 meshOps::replaceLabel
912 faceEdges_[retTriFace]
917 // Correct faceEdges / edgeFaces for quad-faces...
918 forAll(firstEdgeFaces,faceI)
920 meshOps::replaceLabel
924 faceEdges_[firstEdgeFaces[faceI]]
927 // Renumber the edges on this face
928 const labelList& fE = faceEdges_[firstEdgeFaces[faceI]];
932 if (edges_[fE[edgeI]].start() == cv0)
934 edges_[fE[edgeI]].start() = cv2;
937 if (edges_[fE[edgeI]].end() == cv0)
939 edges_[fE[edgeI]].end() = cv2;
942 if (edges_[fE[edgeI]].start() == cv1)
944 edges_[fE[edgeI]].start() = cv3;
947 if (edges_[fE[edgeI]].end() == cv1)
949 edges_[fE[edgeI]].end() = cv3;
953 // Size-up edgeFaces for the replacement
956 (firstEdgeFaces[faceI] != faceToThrow[0]) &&
957 (firstEdgeFaces[faceI] != faceToThrow[1]) &&
958 (firstEdgeFaces[faceI] != fIndex)
963 firstEdgeFaces[faceI],
964 edgeFaces_[checkEdgeIndex[2]]
969 // Remove the current face from the replacement edge
970 meshOps::sizeDownList
973 edgeFaces_[checkEdgeIndex[2]]
976 // Replace point labels on all triangular boundary faces.
977 forAll(hullCells[0],cellI)
979 const cell& cellToCheck = cells_[hullCells[0][cellI]];
981 forAll(cellToCheck,faceI)
983 face& faceToCheck = faces_[cellToCheck[faceI]];
985 if (faceToCheck.size() == 3)
987 forAll(faceToCheck,pointI)
989 if (faceToCheck[pointI] == cv0)
991 faceToCheck[pointI] = cv2;
994 if (faceToCheck[pointI] == cv1)
996 faceToCheck[pointI] = cv3;
1003 // Now that we're done with all edges, remove them.
1004 removeEdge(checkEdgeIndex[0]);
1005 removeEdge(checkEdgeIndex[1]);
1006 removeEdge(checkEdgeIndex[3]);
1008 forAll(edgeToThrow, indexI)
1010 if (edgeToThrow[indexI] == -1)
1015 removeEdge(edgeToThrow[indexI]);
1018 // Delete the two points...
1024 const labelList& secondEdgeFaces = edgeFaces_[checkEdgeIndex[2]];
1026 // Collapse to the first node
1027 forAll(secondEdgeFaces,faceI)
1029 // Replace point indices on faces.
1030 meshOps::replaceLabel
1034 faces_[secondEdgeFaces[faceI]]
1037 meshOps::replaceLabel
1041 faces_[secondEdgeFaces[faceI]]
1044 // Add an entry for mapping
1045 if (!modifiedFaces.found(secondEdgeFaces[faceI]))
1047 modifiedFaces.insert(secondEdgeFaces[faceI]);
1050 // Determine the quad-face(s) in cell[0] & cell[1]
1051 // that belongs to secondEdgeFaces
1052 if (secondEdgeFaces[faceI] == c0IntIndex[0])
1054 faceToKeep[0] = c0IntIndex[1];
1055 faceToThrow[0] = c0IntIndex[0];
1058 if (secondEdgeFaces[faceI] == c0IntIndex[1])
1060 faceToKeep[0] = c0IntIndex[0];
1061 faceToThrow[0] = c0IntIndex[1];
1066 if (secondEdgeFaces[faceI] == c1IntIndex[0])
1068 faceToKeep[1] = c1IntIndex[1];
1069 faceToThrow[1] = c1IntIndex[0];
1072 if (secondEdgeFaces[faceI] == c1IntIndex[1])
1074 faceToKeep[1] = c1IntIndex[0];
1075 faceToThrow[1] = c1IntIndex[1];
1080 // Find common edges between quad / tri faces...
1081 meshOps::findCommonEdge
1089 meshOps::findCommonEdge
1097 meshOps::findCommonEdge
1105 meshOps::findCommonEdge
1113 // Size down edgeFaces for the ends.
1114 meshOps::findCommonEdge
1122 meshOps::sizeDownList
1130 meshOps::findCommonEdge
1138 meshOps::findCommonEdge
1146 meshOps::findCommonEdge
1154 meshOps::findCommonEdge
1162 // Size down edgeFaces for the ends.
1163 meshOps::findCommonEdge
1171 meshOps::sizeDownList
1178 // Correct edgeFaces for triangular faces...
1179 forAll(edgeToThrow, indexI)
1181 if (edgeToThrow[indexI] == -1)
1186 const labelList& eF = edgeFaces_[edgeToThrow[indexI]];
1188 label origTriFace = -1, retTriFace = -1;
1190 // Find the original triangular face index
1193 if (eF[faceI] == c0BdyIndex[0])
1195 origTriFace = c0BdyIndex[0];
1199 if (eF[faceI] == c0BdyIndex[1])
1201 origTriFace = c0BdyIndex[1];
1205 if (eF[faceI] == c1BdyIndex[0])
1207 origTriFace = c1BdyIndex[0];
1211 if (eF[faceI] == c1BdyIndex[1])
1213 origTriFace = c1BdyIndex[1];
1218 // Find the retained triangular face index
1223 (eF[faceI] != origTriFace) &&
1224 (eF[faceI] != faceToThrow[0]) &&
1225 (eF[faceI] != faceToThrow[1])
1228 retTriFace = eF[faceI];
1233 // Finally replace the face/edge indices
1234 if (retTriFace == -1)
1236 // Couldn't find a retained face.
1237 // This must be a boundary edge, so size-down instead.
1238 meshOps::sizeDownList
1241 edgeFaces_[edgeToKeep[indexI]]
1246 meshOps::replaceLabel
1250 edgeFaces_[edgeToKeep[indexI]]
1253 meshOps::replaceLabel
1255 edgeToThrow[indexI],
1257 faceEdges_[retTriFace]
1262 // Correct faceEdges / edgeFaces for quad-faces...
1263 forAll(secondEdgeFaces,faceI)
1265 meshOps::replaceLabel
1269 faceEdges_[secondEdgeFaces[faceI]]
1272 // Renumber the edges on this face
1273 const labelList& fE = faceEdges_[secondEdgeFaces[faceI]];
1277 if (edges_[fE[edgeI]].start() == cv2)
1279 edges_[fE[edgeI]].start() = cv0;
1282 if (edges_[fE[edgeI]].end() == cv2)
1284 edges_[fE[edgeI]].end() = cv0;
1287 if (edges_[fE[edgeI]].start() == cv3)
1289 edges_[fE[edgeI]].start() = cv1;
1292 if (edges_[fE[edgeI]].end() == cv3)
1294 edges_[fE[edgeI]].end() = cv1;
1298 // Size-up edgeFaces for the replacement
1301 (secondEdgeFaces[faceI] != faceToThrow[0]) &&
1302 (secondEdgeFaces[faceI] != faceToThrow[1]) &&
1303 (secondEdgeFaces[faceI] != fIndex)
1308 secondEdgeFaces[faceI],
1309 edgeFaces_[checkEdgeIndex[1]]
1314 // Remove the current face from the replacement edge
1315 meshOps::sizeDownList
1318 edgeFaces_[checkEdgeIndex[1]]
1321 // Replace point labels on all triangular boundary faces.
1322 forAll(hullCells[1], cellI)
1324 const cell& cellToCheck = cells_[hullCells[1][cellI]];
1326 forAll(cellToCheck, faceI)
1328 face& faceToCheck = faces_[cellToCheck[faceI]];
1330 if (faceToCheck.size() == 3)
1332 forAll(faceToCheck, pointI)
1334 if (faceToCheck[pointI] == cv2)
1336 faceToCheck[pointI] = cv0;
1339 if (faceToCheck[pointI] == cv3)
1341 faceToCheck[pointI] = cv1;
1348 // Now that we're done with all edges, remove them.
1349 removeEdge(checkEdgeIndex[0]);
1350 removeEdge(checkEdgeIndex[2]);
1351 removeEdge(checkEdgeIndex[3]);
1353 forAll(edgeToThrow, indexI)
1355 if (edgeToThrow[indexI] == -1)
1360 removeEdge(edgeToThrow[indexI]);
1363 // Delete the two points...
1371 Info << "~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
1372 Info << "Hulls after modification" << endl;
1373 Info << "~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
1375 Info << nl << "Cells belonging to first Edge Hull: "
1376 << hullCells[0] << endl;
1378 forAll(hullCells[0], cellI)
1380 const cell& firstCurCell = cells_[hullCells[0][cellI]];
1382 Info << "Cell: " << hullCells[0][cellI]
1383 << ": " << firstCurCell << endl;
1385 forAll(firstCurCell, faceI)
1387 Info << firstCurCell[faceI]
1388 << ": " << faces_[firstCurCell[faceI]] << endl;
1392 const labelList& firstEdgeFaces = edgeFaces_[checkEdgeIndex[1]];
1394 Info << nl << "First Edge Face Hull: " << firstEdgeFaces << endl;
1396 forAll(firstEdgeFaces, indexI)
1398 Info << firstEdgeFaces[indexI]
1399 << ": " << faces_[firstEdgeFaces[indexI]] << endl;
1402 Info << nl << "Cells belonging to second Edge Hull: "
1403 << hullCells[1] << endl;
1405 forAll(hullCells[1], cellI)
1407 const cell& secondCurCell = cells_[hullCells[1][cellI]];
1409 Info << "Cell: " << hullCells[1][cellI]
1410 << ": " << secondCurCell << endl;
1412 forAll(secondCurCell, faceI)
1414 Info << secondCurCell[faceI]
1415 << ": " << faces_[secondCurCell[faceI]] << endl;
1419 const labelList& secondEdgeFaces = edgeFaces_[checkEdgeIndex[2]];
1421 Info << nl << "Second Edge Face Hull: " << secondEdgeFaces << endl;
1423 forAll(secondEdgeFaces, indexI)
1425 Info << secondEdgeFaces[indexI]
1426 << ": " << faces_[secondEdgeFaces[indexI]] << endl;
1431 Info << "Retained face: "
1432 << faceToKeep[0] << ": "
1433 << " owner: " << owner_[faceToKeep[0]]
1434 << " neighbour: " << neighbour_[faceToKeep[0]]
1437 Info << "Discarded face: "
1438 << faceToThrow[0] << ": "
1439 << " owner: " << owner_[faceToThrow[0]]
1440 << " neighbour: " << neighbour_[faceToThrow[0]]
1445 Info << "Retained face: "
1446 << faceToKeep[1] << ": "
1447 << " owner: " << owner_[faceToKeep[1]]
1448 << " neighbour: " << neighbour_[faceToKeep[1]]
1451 Info << "Discarded face: "
1452 << faceToThrow[1] << ": "
1453 << " owner: " << owner_[faceToThrow[1]]
1454 << " neighbour: " << neighbour_[faceToThrow[1]]
1459 // Ensure proper orientation for the two retained faces
1460 FixedList<label,2> cellCheck(0);
1462 if (owner_[faceToThrow[0]] == c0)
1464 cellCheck[0] = neighbour_[faceToThrow[0]];
1466 if (owner_[faceToKeep[0]] == c0)
1470 (neighbour_[faceToThrow[0]] > neighbour_[faceToKeep[0]])
1471 && (neighbour_[faceToKeep[0]] != -1)
1474 // This face is to be flipped
1475 faces_[faceToKeep[0]] =
1477 faces_[faceToKeep[0]].reverseFace()
1480 owner_[faceToKeep[0]] = neighbour_[faceToKeep[0]];
1481 neighbour_[faceToKeep[0]] = neighbour_[faceToThrow[0]];
1483 setFlip(faceToKeep[0]);
1487 if (neighbour_[faceToThrow[0]] != -1)
1489 // Keep orientation intact, and update the owner
1490 owner_[faceToKeep[0]] = neighbour_[faceToThrow[0]];
1494 // This face will need to be flipped and converted
1495 // to a boundary face. Flip it now, so that conversion
1497 faces_[faceToKeep[0]] =
1499 faces_[faceToKeep[0]].reverseFace()
1502 owner_[faceToKeep[0]] = neighbour_[faceToKeep[0]];
1503 neighbour_[faceToKeep[0]] = -1;
1505 setFlip(faceToKeep[0]);
1511 // Keep orientation intact, and update the neighbour
1512 neighbour_[faceToKeep[0]] = neighbour_[faceToThrow[0]];
1517 cellCheck[0] = owner_[faceToThrow[0]];
1519 if (neighbour_[faceToKeep[0]] == c0)
1521 if (owner_[faceToThrow[0]] < owner_[faceToKeep[0]])
1523 // This face is to be flipped
1524 faces_[faceToKeep[0]] =
1526 faces_[faceToKeep[0]].reverseFace()
1529 neighbour_[faceToKeep[0]] = owner_[faceToKeep[0]];
1530 owner_[faceToKeep[0]] = owner_[faceToThrow[0]];
1532 setFlip(faceToKeep[0]);
1536 // Keep orientation intact, and update the neighbour
1537 neighbour_[faceToKeep[0]] = owner_[faceToThrow[0]];
1542 // Keep orientation intact, and update the owner
1543 owner_[faceToKeep[0]] = owner_[faceToThrow[0]];
1549 if (owner_[faceToThrow[1]] == c1)
1551 cellCheck[1] = neighbour_[faceToThrow[1]];
1553 if (owner_[faceToKeep[1]] == c1)
1557 (neighbour_[faceToThrow[1]] > neighbour_[faceToKeep[1]])
1558 && (neighbour_[faceToKeep[1]] != -1)
1561 // This face is to be flipped
1562 faces_[faceToKeep[1]] =
1564 faces_[faceToKeep[1]].reverseFace()
1567 owner_[faceToKeep[1]] = neighbour_[faceToKeep[1]];
1568 neighbour_[faceToKeep[1]] = neighbour_[faceToThrow[1]];
1570 setFlip(faceToKeep[1]);
1574 if (neighbour_[faceToThrow[1]] != -1)
1576 // Keep orientation intact, and update the owner
1577 owner_[faceToKeep[1]] = neighbour_[faceToThrow[1]];
1581 // This face will need to be flipped and converted
1582 // to a boundary face. Flip it now, so that conversion
1584 faces_[faceToKeep[1]] =
1586 faces_[faceToKeep[1]].reverseFace()
1589 owner_[faceToKeep[1]] = neighbour_[faceToKeep[1]];
1590 neighbour_[faceToKeep[1]] = -1;
1592 setFlip(faceToKeep[1]);
1598 // Keep orientation intact, and update the neighbour
1599 neighbour_[faceToKeep[1]] = neighbour_[faceToThrow[1]];
1604 cellCheck[1] = owner_[faceToThrow[1]];
1606 if (neighbour_[faceToKeep[1]] == c1)
1608 if (owner_[faceToThrow[1]] < owner_[faceToKeep[1]])
1610 // This face is to be flipped
1611 faces_[faceToKeep[1]] =
1613 faces_[faceToKeep[1]].reverseFace()
1616 neighbour_[faceToKeep[1]] = owner_[faceToKeep[1]];
1617 owner_[faceToKeep[1]] = owner_[faceToThrow[1]];
1619 setFlip(faceToKeep[1]);
1623 // Keep orientation intact, and update the neighbour
1624 neighbour_[faceToKeep[1]] = owner_[faceToThrow[1]];
1629 // Keep orientation intact, and update the owner
1630 owner_[faceToKeep[1]] = owner_[faceToThrow[1]];
1635 // Remove orphaned faces
1636 if (owner_[faceToKeep[0]] == -1)
1638 removeFace(faceToKeep[0]);
1643 (neighbour_[faceToKeep[0]] == -1)
1644 && (whichPatch(faceToKeep[0]) < 0)
1647 // Obtain a copy before adding the new face,
1648 // since the reference might become invalid during list resizing.
1649 face newFace = faces_[faceToKeep[0]];
1650 label newOwn = owner_[faceToKeep[0]];
1651 labelList newFaceEdges = faceEdges_[faceToKeep[0]];
1653 // This face is being converted from interior to boundary. Remove
1654 // from the interior list and add as a boundary face to the end.
1655 label newFaceIndex =
1659 whichPatch(faceToThrow[0]),
1666 // Add an entry for mapping
1667 if (!modifiedFaces.found(newFaceIndex))
1669 modifiedFaces.insert(newFaceIndex);
1672 // Add a faceEdges entry as well.
1673 // Edges don't have to change, since they're
1674 // all on the boundary anyway.
1675 faceEdges_.append(newFaceEdges);
1677 meshOps::replaceLabel
1684 // Correct edgeFaces with the new face label.
1685 forAll(newFaceEdges, edgeI)
1687 meshOps::replaceLabel
1691 edgeFaces_[newFaceEdges[edgeI]]
1695 // Renumber the neighbour so that this face is removed correctly.
1696 neighbour_[faceToKeep[0]] = 0;
1697 removeFace(faceToKeep[0]);
1700 // Remove the unwanted faces in the cell(s) adjacent to this face,
1701 // and correct the cells that contain discarded faces
1702 const cell& cell_0 = cells_[c0];
1704 forAll(cell_0,faceI)
1706 if (cell_0[faceI] != fIndex && cell_0[faceI] != faceToKeep[0])
1708 removeFace(cell_0[faceI]);
1712 if (cellCheck[0] != -1)
1714 meshOps::replaceLabel
1718 cells_[cellCheck[0]]
1727 // Increment the surface-collapse counter
1732 // Remove orphaned faces
1733 if (owner_[faceToKeep[1]] == -1)
1735 removeFace(faceToKeep[1]);
1740 (neighbour_[faceToKeep[1]] == -1)
1741 && (whichPatch(faceToKeep[1]) < 0)
1744 // Obtain a copy before adding the new face,
1745 // since the reference might become invalid during list resizing.
1746 face newFace = faces_[faceToKeep[1]];
1747 label newOwn = owner_[faceToKeep[1]];
1748 labelList newFaceEdges = faceEdges_[faceToKeep[1]];
1750 // This face is being converted from interior to boundary. Remove
1751 // from the interior list and add as a boundary face to the end.
1752 label newFaceIndex =
1756 whichPatch(faceToThrow[1]),
1763 // Add an entry for mapping
1764 if (!modifiedFaces.found(newFaceIndex))
1766 modifiedFaces.insert(newFaceIndex);
1769 // Add a faceEdges entry as well.
1770 // Edges don't have to change, since they're
1771 // all on the boundary anyway.
1772 faceEdges_.append(newFaceEdges);
1774 meshOps::replaceLabel
1781 // Correct edgeFaces with the new face label.
1782 forAll(newFaceEdges, edgeI)
1784 meshOps::replaceLabel
1788 edgeFaces_[newFaceEdges[edgeI]]
1792 // Renumber the neighbour so that this face is removed correctly.
1793 neighbour_[faceToKeep[1]] = 0;
1794 removeFace(faceToKeep[1]);
1797 const cell& cell_1 = cells_[c1];
1799 forAll(cell_1, faceI)
1801 if (cell_1[faceI] != fIndex && cell_1[faceI] != faceToKeep[1])
1803 removeFace(cell_1[faceI]);
1807 if (cellCheck[1] != -1)
1809 meshOps::replaceLabel
1813 cells_[cellCheck[1]]
1821 // Move old / new points
1822 oldPoints_[replacement[0]] = oldPoint[0];
1823 oldPoints_[replacement[1]] = oldPoint[1];
1825 points_[replacement[0]] = newPoint[0];
1826 points_[replacement[1]] = newPoint[1];
1828 // Finally remove the face
1831 // Write out VTK files after change
1834 labelHashSet vtkCells;
1836 forAll(hullCells[0], cellI)
1838 if (hullCells[0][cellI] == c0 || hullCells[0][cellI] == c1)
1843 if (!vtkCells.found(hullCells[0][cellI]))
1845 vtkCells.insert(hullCells[0][cellI]);
1849 forAll(hullCells[1], cellI)
1851 if (hullCells[1][cellI] == c0 || hullCells[1][cellI] == c1)
1856 if (!vtkCells.found(hullCells[1][cellI]))
1858 vtkCells.insert(hullCells[1][cellI]);
1870 // Specify that an old point-position
1871 // has been modified, if necessary
1872 if (collapseCase == 3 && c1 > -1)
1874 labelList mP(2, -1);
1876 mP[0] = original[0];
1877 mP[1] = replacement[0];
1879 modPoints_.set(replacement[0], mP);
1881 mP[0] = original[1];
1882 mP[1] = replacement[1];
1884 modPoints_.set(replacement[1], mP);
1887 // Fill-in candidate mapping information
1888 labelList mC(2, -1);
1889 mC[0] = c0, mC[1] = c1;
1891 // Now that all old / new cells possess correct connectivity,
1892 // compute mapping information.
1893 forAll(hullCells, indexI)
1895 forAll(hullCells[indexI], cellI)
1897 label mcIndex = hullCells[indexI][cellI];
1899 // Skip collapsed cells
1900 if (mcIndex == c0 || mcIndex == c1)
1905 // Set the mapping for this cell
1906 setCellMapping(mcIndex, mC);
1910 // Set face mapping information for modified faces
1911 forAllConstIter(labelHashSet, modifiedFaces, fIter)
1913 // Exclude deleted faces
1914 if (faces_[fIter.key()].empty())
1919 // Decide between default / weighted mapping
1920 // based on boundary information
1921 label fPatch = whichPatch(fIter.key());
1925 setFaceMapping(fIter.key());
1929 // Fill-in candidate mapping information
1930 labelList faceCandidates;
1932 const labelList& fEdges = faceEdges_[fIter.key()];
1934 forAll(fEdges, edgeI)
1936 if (whichEdgePatch(fEdges[edgeI]) == fPatch)
1938 // Loop through associated edgeFaces
1939 const labelList& eFaces = edgeFaces_[fEdges[edgeI]];
1941 forAll(eFaces, faceI)
1945 (eFaces[faceI] != fIter.key()) &&
1946 (whichPatch(eFaces[faceI]) == fPatch)
1949 faceCandidates.setSize
1951 faceCandidates.size() + 1,
1959 // Set the mapping for this face
1960 setFaceMapping(fIter.key(), faceCandidates);
1965 topoChangeFlag_ = true;
1967 // Increment the counter
1970 // Increment the number of modifications
1973 // Return a succesful collapse
1974 map.type() = collapseCase;
1980 // Method for the collapse of an edge in 3D
1981 // - Returns a changeMap with a type specifying:
1982 // -1: Collapse failed since max number of topo-changes was reached.
1983 // 0: Collapse could not be performed.
1984 // 1: Collapsed to first node.
1985 // 2: Collapsed to second node.
1986 // 3: Collapsed to mid-point (default)
1987 // - overRideCase is used to force a certain collapse configuration.
1988 // -1: Use this value to let collapseEdge decide a case.
1989 // 1: Force collapse to first node.
1990 // 2: Force collapse to second node.
1991 // 3: Force collapse to mid-point
1992 // - checkOnly performs a feasibility check and returns without modifications.
1993 // - forceOp to force the collapse.
1994 const changeMap dynamicTopoFvMesh::collapseEdge
2002 // Edge collapse performs the following operations:
2003 // [1] Checks if either vertex of the edge is on a boundary
2004 // [2] Checks whether cells attached to deleted vertices will be valid
2005 // after the edge-collapse operation
2006 // [3] Deletes all cells surrounding this edge
2007 // [4] Deletes all faces surrounding this edge
2008 // [5] Deletes all faces surrounding the deleted vertex attached
2009 // to the cells in [3]
2010 // [6] Checks the orientation of faces connected to the retained
2012 // [7] Remove one of the vertices of the edge
2013 // Update faceEdges, edgeFaces and edgePoints information
2015 // For 2D meshes, perform face-collapse
2018 return collapseQuadFace(eIndex, overRideCase, checkOnly);
2021 // Figure out which thread this is...
2022 label tIndex = self();
2024 // Prepare the changeMaps
2025 changeMap map, slaveMap;
2029 (statistics_[0] > maxModifications_)
2030 && (maxModifications_ > -1)
2033 // Reached the max allowable topo-changes.
2034 stack(tIndex).clear();
2039 // Check if edgeRefinements are to be avoided on patch.
2040 if (lengthEstimator().checkRefinementPatch(whichEdgePatch(eIndex)))
2045 // Sanity check: Is the index legitimate?
2051 "const changeMap dynamicTopoFvMesh::collapseEdge\n"
2053 " const label eIndex,\n"
2054 " label overRideCase,\n"
2055 " bool checkOnly,\n"
2059 << " Invalid index: " << eIndex
2060 << abort(FatalError);
2065 label replaceIndex = -1, m = edgePoints_[eIndex].size();
2067 // Size up the hull lists
2068 labelList cellHull(m, -1);
2069 labelList faceHull(m, -1);
2070 labelList edgeHull(m, -1);
2071 labelListList ringEntities(4, labelList(m, -1));
2073 // Construct a hull around this edge
2074 meshOps::constructHull
2091 // Check whether points of the edge lies on a boundary
2092 FixedList<label, 2> nBoundCurves(0), checkPoints(-1);
2093 const FixedList<bool,2> edgeBoundary = checkEdgeBoundary(eIndex);
2095 // Decide on collapseCase
2096 label collapseCase = -1;
2098 if (edgeBoundary[0] && !edgeBoundary[1])
2103 if (!edgeBoundary[0] && edgeBoundary[1])
2108 if (edgeBoundary[0] && edgeBoundary[1])
2110 // If this is an interior edge with two boundary points.
2111 // Bail out for now. If proximity based refinement is
2112 // switched on, mesh may be sliced at this point.
2113 if (whichEdgePatch(eIndex) == -1)
2118 // Check if either point lies on a bounding curve
2119 // Used to ensure that collapses happen towards bounding curves.
2120 // If the edge itself is on a bounding curve, collapse is valid.
2121 forAll(edges_[eIndex], pointI)
2123 const labelList& pEdges = pointEdges_[edges_[eIndex][pointI]];
2125 forAll(pEdges, edgeI)
2127 if (checkBoundingCurve(pEdges[edgeI]))
2129 nBoundCurves[pointI]++;
2134 // Pick the point which is connected to more bounding curves
2135 if (nBoundCurves[0] > nBoundCurves[1])
2140 if (nBoundCurves[1] > nBoundCurves[0])
2146 // Bounding edge: collapseEdge can collapse this edge
2152 // Looks like this is an interior edge.
2153 // Collapse case [3] by default
2157 // Perform an override if requested.
2158 if (overRideCase != -1)
2160 collapseCase = overRideCase;
2163 // Configure the new point-position
2164 point newPoint = vector::zero;
2165 point oldPoint = vector::zero;
2167 label collapsePoint = -1, replacePoint = -1;
2169 switch (collapseCase)
2173 // Collapse to the first node
2174 replacePoint = edges_[eIndex][0];
2175 collapsePoint = edges_[eIndex][1];
2177 newPoint = points_[replacePoint];
2178 oldPoint = oldPoints_[replacePoint];
2180 checkPoints[0] = collapsePoint;
2187 // Collapse to the second node
2188 replacePoint = edges_[eIndex][1];
2189 collapsePoint = edges_[eIndex][0];
2191 newPoint = points_[replacePoint];
2192 oldPoint = oldPoints_[replacePoint];
2194 checkPoints[0] = collapsePoint;
2201 // Collapse to the mid-point
2202 replacePoint = edges_[eIndex][1];
2203 collapsePoint = edges_[eIndex][0];
2209 points_[replacePoint]
2210 + points_[collapsePoint]
2218 oldPoints_[replacePoint]
2219 + oldPoints_[collapsePoint]
2223 checkPoints[0] = replacePoint;
2224 checkPoints[1] = collapsePoint;
2231 // Don't think this will ever happen.
2235 "const changeMap dynamicTopoFvMesh::collapseEdge\n"
2237 " const label eIndex,\n"
2238 " label overRideCase,\n"
2239 " bool checkOnly,\n"
2243 << "Edge: " << eIndex << ": " << edges_[eIndex]
2244 << ". Couldn't decide on collapseCase."
2245 << abort(FatalError);
2251 // Loop through edges and check for feasibility of collapse
2252 // Also, keep track of resulting cell quality,
2253 // if collapse is indeed feasible
2254 scalar collapseQuality(GREAT);
2255 labelHashSet cellsChecked;
2257 // Add all hull cells as 'checked',
2258 // and therefore, feasible
2259 forAll(cellHull, cellI)
2261 if (cellHull[cellI] == -1)
2266 cellsChecked.insert(cellHull[cellI]);
2269 // Check collapsibility of cells around edges
2270 // with the re-configured point
2271 forAll(checkPoints, pointI)
2273 if (checkPoints[pointI] == -1)
2278 const labelList& checkPointEdges = pointEdges_[checkPoints[pointI]];
2280 forAll(checkPointEdges, edgeI)
2282 const labelList& eFaces = edgeFaces_[checkPointEdges[edgeI]];
2284 // Build a list of cells to check
2285 forAll(eFaces, faceI)
2287 label own = owner_[eFaces[faceI]];
2288 label nei = neighbour_[eFaces[faceI]];
2291 if (!cellsChecked.found(own))
2293 // Check if a collapse is feasible
2300 checkPoints[pointI],
2313 // Check neighbour cell
2314 if (!cellsChecked.found(nei) && nei != -1)
2316 // Check if a collapse is feasible
2323 checkPoints[pointI],
2339 // Are we only performing checks?
2342 map.type() = collapseCase;
2346 Info << "Edge: " << eIndex
2347 << ":: " << edges_[eIndex] << nl
2348 << " collapseCase determined to be: "
2349 << collapseCase << nl
2350 << " Resulting quality: "
2358 // Update number of surface collapses, if necessary.
2359 if (whichEdgePatch(eIndex) > -1)
2364 // Define indices on the hull for removal / replacement
2365 label removeEdgeIndex = -1, replaceEdgeIndex = -1;
2366 label removeFaceIndex = -1, replaceFaceIndex = -1;
2368 if (replacePoint == edges_[eIndex][0])
2370 replaceEdgeIndex = 0;
2371 replaceFaceIndex = 1;
2372 removeEdgeIndex = 2;
2373 removeFaceIndex = 3;
2376 if (replacePoint == edges_[eIndex][1])
2378 removeEdgeIndex = 0;
2379 removeFaceIndex = 1;
2380 replaceEdgeIndex = 2;
2381 replaceFaceIndex = 3;
2385 // Don't think this will ever happen.
2389 "const changeMap dynamicTopoFvMesh::collapseEdge\n"
2391 " const label eIndex,\n"
2392 " label overRideCase,\n"
2393 " bool checkOnly,\n"
2397 << "Edge: " << eIndex << ": " << edges_[eIndex]
2398 << ". Couldn't decide on removal / replacement indices."
2399 << abort(FatalError);
2405 << "Edge: " << eIndex
2406 << ": " << edges_[eIndex]
2407 << " is to be collapsed. " << endl;
2409 label epIndex = whichEdgePatch(eIndex);
2415 Info << "Internal" << endl;
2419 Info << boundaryMesh()[epIndex].name() << endl;
2422 Info << " nBoundCurves: " << nBoundCurves << endl;
2423 Info << " collapseCase: " << collapseCase << endl;
2425 Info << " Resulting quality: " << collapseQuality << endl;
2429 Info << "Vertices: " << edgePoints_[eIndex] << endl;
2430 Info << "Edges: " << edgeHull << endl;
2431 Info << "Faces: " << faceHull << endl;
2432 Info << "Cells: " << cellHull << endl;
2433 Info << "replacePoint: " << replacePoint << endl;
2434 Info << "collapsePoint: " << collapsePoint << endl;
2435 Info << "checkPoints: " << checkPoints << endl;;
2436 Info << "ringEntities (removed faces): " << endl;
2438 forAll(ringEntities[removeFaceIndex], faceI)
2440 label fIndex = ringEntities[removeFaceIndex][faceI];
2447 Info << fIndex << ": " << faces_[fIndex] << endl;
2450 Info << "ringEntities (removed edges): " << endl;
2451 forAll(ringEntities[removeEdgeIndex], edgeI)
2453 label ieIndex = ringEntities[removeEdgeIndex][edgeI];
2460 Info << ieIndex << ": " << edges_[ieIndex] << endl;
2463 Info << "ringEntities (replacement faces): " << endl;
2464 forAll(ringEntities[replaceFaceIndex], faceI)
2466 label fIndex = ringEntities[replaceFaceIndex][faceI];
2473 Info << fIndex << ": " << faces_[fIndex] << endl;
2476 Info << "ringEntities (replacement edges): " << endl;
2477 forAll(ringEntities[replaceEdgeIndex], edgeI)
2479 label ieIndex = ringEntities[replaceEdgeIndex][edgeI];
2486 Info << ieIndex << ": " << edges_[ieIndex] << endl;
2489 labelList& collapsePointEdges = pointEdges_[collapsePoint];
2491 Info << "pointEdges (collapsePoint): ";
2493 forAll(collapsePointEdges, edgeI)
2495 Info << collapsePointEdges[edgeI] << " ";
2500 // Write out VTK files prior to change
2503 labelList vtkCells = cellsChecked.toc();
2508 + '(' + Foam::name(edges_[eIndex][0])
2509 + ',' + Foam::name(edges_[eIndex][1]) + ')'
2517 // Maintain a list of modified faces for mapping
2518 labelHashSet modifiedFaces;
2520 // Renumber all hull faces and edges
2521 forAll(faceHull, indexI)
2523 // Loop through all faces of the edge to be removed
2524 // and reassign them to the replacement edge
2525 label edgeToRemove = ringEntities[removeEdgeIndex][indexI];
2526 label faceToRemove = ringEntities[removeFaceIndex][indexI];
2527 label cellToRemove = cellHull[indexI];
2528 label replaceEdge = ringEntities[replaceEdgeIndex][indexI];
2529 label replaceFace = ringEntities[replaceFaceIndex][indexI];
2531 const labelList& rmvEdgeFaces = edgeFaces_[edgeToRemove];
2533 // Replace edgePoints for all edges emanating from hullVertices
2534 // except ring-edges; those are sized-down later
2535 const labelList& hullPointEdges =
2537 pointEdges_[edgePoints_[eIndex][indexI]]
2540 forAll(hullPointEdges, edgeI)
2546 edgePoints_[hullPointEdges[edgeI]],
2551 edgePoints_[hullPointEdges[edgeI]],
2556 meshOps::replaceLabel
2560 edgePoints_[hullPointEdges[edgeI]]
2565 forAll(rmvEdgeFaces, faceI)
2567 // Replace edge labels for faces
2568 meshOps::replaceLabel
2572 faceEdges_[rmvEdgeFaces[faceI]]
2575 // Loop through faces associated with this edge,
2576 // and renumber them as well.
2577 const face& faceToCheck = faces_[rmvEdgeFaces[faceI]];
2579 if ((replaceIndex = faceToCheck.which(collapsePoint)) > -1)
2583 Info << "Renumbering face: "
2584 << rmvEdgeFaces[faceI] << ": "
2585 << faceToCheck << endl;
2588 // Renumber the face...
2589 faces_[rmvEdgeFaces[faceI]][replaceIndex] = replacePoint;
2591 // Add an entry for mapping
2592 if (!modifiedFaces.found(rmvEdgeFaces[faceI]))
2594 modifiedFaces.insert(rmvEdgeFaces[faceI]);
2598 // Hull faces should be removed for the replacement edge
2599 if (rmvEdgeFaces[faceI] == faceHull[indexI])
2601 meshOps::sizeDownList
2604 edgeFaces_[replaceEdge]
2612 // Need to avoid ring faces as well.
2613 forAll(ringEntities[removeFaceIndex], faceII)
2618 == ringEntities[removeFaceIndex][faceII]
2626 // Size-up the replacement edge list if the face hasn't been found.
2627 // These faces are connected to the edge slated for
2628 // removal, but do not belong to the hull.
2633 rmvEdgeFaces[faceI],
2634 edgeFaces_[replaceEdge]
2639 if (cellToRemove == -1)
2644 // Size down edgeFaces for the ring edges
2645 meshOps::sizeDownList
2648 edgeFaces_[edgeHull[indexI]]
2651 // Size down edgePoints for the ring edges
2652 meshOps::sizeDownList
2655 edgePoints_[edgeHull[indexI]]
2658 // Ensure proper orientation of retained faces
2659 if (owner_[faceToRemove] == cellToRemove)
2661 if (owner_[replaceFace] == cellToRemove)
2665 (neighbour_[faceToRemove] > neighbour_[replaceFace])
2666 && (neighbour_[replaceFace] != -1)
2669 // This face is to be flipped
2670 faces_[replaceFace] = faces_[replaceFace].reverseFace();
2671 owner_[replaceFace] = neighbour_[replaceFace];
2672 neighbour_[replaceFace] = neighbour_[faceToRemove];
2674 setFlip(replaceFace);
2679 (neighbour_[faceToRemove] == -1) &&
2680 (neighbour_[replaceFace] != -1)
2683 // This interior face would need to be converted
2684 // to a boundary one, and flipped as well.
2685 face newFace = faces_[replaceFace].reverseFace();
2686 label newOwner = neighbour_[replaceFace];
2687 label newNeighbour = neighbour_[faceToRemove];
2688 labelList newFE = faceEdges_[replaceFace];
2690 label newFaceIndex =
2694 whichPatch(faceToRemove),
2701 // Set this face aside for mapping
2702 if (!modifiedFaces.found(newFaceIndex))
2704 modifiedFaces.insert(newFaceIndex);
2707 // Ensure that all edges of this face are
2709 forAll(newFE, edgeI)
2711 if (whichEdgePatch(newFE[edgeI]) == -1)
2713 edge newEdge = edges_[newFE[edgeI]];
2714 labelList newEF = edgeFaces_[newFE[edgeI]];
2715 labelList newEP = edgePoints_[newFE[edgeI]];
2717 // Need patch information for the new edge.
2718 // Find the corresponding edge in ringEntities.
2719 // Note that hullEdges doesn't need to be checked,
2720 // since they are common to both faces.
2725 ringEntities[replaceEdgeIndex],
2734 ringEntities[removeEdgeIndex][i]
2738 // Insert the new edge
2739 label newEdgeIndex =
2750 // Replace faceEdges for all
2752 forAll(newEF, faceI)
2754 meshOps::replaceLabel
2758 faceEdges_[newEF[faceI]]
2763 removeEdge(newFE[edgeI]);
2765 // Replace faceEdges with new edge index
2766 newFE[edgeI] = newEdgeIndex;
2768 // Modify ringEntities
2769 ringEntities[replaceEdgeIndex][i] = newEdgeIndex;
2773 // Add the new faceEdges
2774 faceEdges_.append(newFE);
2776 // Replace edgeFaces with the new face index
2777 const labelList& newFEdges = faceEdges_[newFaceIndex];
2779 forAll(newFEdges, edgeI)
2781 meshOps::replaceLabel
2785 edgeFaces_[newFEdges[edgeI]]
2790 removeFace(replaceFace);
2792 // Replace label for the new owner
2793 meshOps::replaceLabel
2800 // Modify ringEntities and replaceFace
2801 replaceFace = newFaceIndex;
2802 ringEntities[replaceFaceIndex][indexI] = newFaceIndex;
2807 (neighbour_[faceToRemove] == -1) &&
2808 (neighbour_[replaceFace] == -1)
2811 // Wierd overhanging cell. Since replaceFace
2812 // would be an orphan if this continued, remove
2813 // the face entirely.
2814 labelList rmFE = faceEdges_[replaceFace];
2820 (edgeFaces_[rmFE[edgeI]].size() == 1) &&
2821 (edgeFaces_[rmFE[edgeI]][0] == replaceFace)
2824 // This edge has to be removed entirely.
2825 removeEdge(rmFE[edgeI]);
2831 ringEntities[replaceEdgeIndex],
2836 // Modify ringEntities
2837 ringEntities[replaceEdgeIndex][i] = -1;
2841 // Size-down edgeFaces
2842 meshOps::sizeDownList
2845 edgeFaces_[rmFE[edgeI]]
2850 removeFace(replaceFace);
2852 // Modify ringEntities and replaceFace
2854 ringEntities[replaceFaceIndex][indexI] = -1;
2858 // Keep orientation intact, and update the owner
2859 owner_[replaceFace] = neighbour_[faceToRemove];
2863 if (neighbour_[faceToRemove] == -1)
2865 // This interior face would need to be converted
2866 // to a boundary one, but with orientation intact.
2867 face newFace = faces_[replaceFace];
2868 label newOwner = owner_[replaceFace];
2869 label newNeighbour = neighbour_[faceToRemove];
2870 labelList newFE = faceEdges_[replaceFace];
2872 label newFaceIndex =
2876 whichPatch(faceToRemove),
2883 // Set this face aside for mapping
2884 if (!modifiedFaces.found(newFaceIndex))
2886 modifiedFaces.insert(newFaceIndex);
2889 // Ensure that all edges of this face are
2891 forAll(newFE, edgeI)
2893 if (whichEdgePatch(newFE[edgeI]) == -1)
2895 edge newEdge = edges_[newFE[edgeI]];
2896 labelList newEF = edgeFaces_[newFE[edgeI]];
2897 labelList newEP = edgePoints_[newFE[edgeI]];
2899 // Need patch information for the new edge.
2900 // Find the corresponding edge in ringEntities.
2901 // Note that hullEdges doesn't need to be checked,
2902 // since they are common to both faces.
2907 ringEntities[replaceEdgeIndex],
2916 ringEntities[removeEdgeIndex][i]
2920 // Insert the new edge
2921 label newEdgeIndex =
2932 // Replace faceEdges for all
2934 forAll(newEF, faceI)
2936 meshOps::replaceLabel
2940 faceEdges_[newEF[faceI]]
2945 removeEdge(newFE[edgeI]);
2947 // Replace faceEdges with new edge index
2948 newFE[edgeI] = newEdgeIndex;
2950 // Modify ringEntities
2951 ringEntities[replaceEdgeIndex][i] = newEdgeIndex;
2955 // Add the new faceEdges
2956 faceEdges_.append(newFE);
2958 // Replace edgeFaces with the new face index
2959 const labelList& newFEdges = faceEdges_[newFaceIndex];
2961 forAll(newFEdges, edgeI)
2963 meshOps::replaceLabel
2967 edgeFaces_[newFEdges[edgeI]]
2972 removeFace(replaceFace);
2974 // Replace label for the new owner
2975 meshOps::replaceLabel
2982 // Modify ringEntities and replaceFace
2983 replaceFace = newFaceIndex;
2984 ringEntities[replaceFaceIndex][indexI] = newFaceIndex;
2988 // Keep orientation intact, and update the neighbour
2989 neighbour_[replaceFace] = neighbour_[faceToRemove];
2993 if (neighbour_[faceToRemove] != -1)
2995 meshOps::replaceLabel
2999 cells_[neighbour_[faceToRemove]]
3005 if (neighbour_[replaceFace] == cellToRemove)
3007 if (owner_[faceToRemove] < owner_[replaceFace])
3009 // This face is to be flipped
3010 faces_[replaceFace] = faces_[replaceFace].reverseFace();
3011 neighbour_[replaceFace] = owner_[replaceFace];
3012 owner_[replaceFace] = owner_[faceToRemove];
3014 setFlip(replaceFace);
3018 // Keep orientation intact, and update the neighbour
3019 neighbour_[replaceFace] = owner_[faceToRemove];
3024 // Keep orientation intact, and update the owner
3025 owner_[replaceFace] = owner_[faceToRemove];
3029 meshOps::replaceLabel
3033 cells_[owner_[faceToRemove]]
3038 // Remove all hull entities
3039 forAll(faceHull, indexI)
3041 label edgeToRemove = ringEntities[removeEdgeIndex][indexI];
3042 label faceToRemove = ringEntities[removeFaceIndex][indexI];
3043 label cellToRemove = cellHull[indexI];
3045 if (cellToRemove != -1)
3047 // Remove faceToRemove and associated faceEdges
3048 removeFace(faceToRemove);
3050 // Remove the hull cell
3051 removeCell(cellToRemove);
3054 // Remove the hull edge and associated edgeFaces
3055 removeEdge(edgeToRemove);
3057 // Remove the hull face
3058 removeFace(faceHull[indexI]);
3061 // Loop through pointEdges for the collapsePoint,
3062 // and replace all occurrences with replacePoint.
3063 // Size-up pointEdges for the replacePoint as well.
3064 const labelList& pEdges = pointEdges_[collapsePoint];
3066 forAll(pEdges, edgeI)
3069 label edgeIndex = pEdges[edgeI];
3071 if (edgeIndex != eIndex)
3075 Info << "Renumbering [edge]: "
3076 << edgeIndex << ": "
3077 << edges_[edgeIndex] << endl;
3080 if (edges_[edgeIndex][0] == collapsePoint)
3082 edges_[edgeIndex][0] = replacePoint;
3087 pointEdges_[replacePoint]
3091 if (edges_[edgeIndex][1] == collapsePoint)
3093 edges_[edgeIndex][1] = replacePoint;
3098 pointEdges_[replacePoint]
3103 // Looks like pointEdges is inconsistent
3107 "const changeMap dynamicTopoFvMesh::collapseEdge\n"
3109 " const label eIndex,\n"
3110 " label overRideCase,\n"
3111 " bool checkOnly,\n"
3115 << "pointEdges is inconsistent." << nl
3116 << "Point: " << collapsePoint << nl
3117 << "pointEdges: " << pEdges << nl
3118 << abort(FatalError);
3121 // Loop through faces associated with this edge,
3122 // and renumber them as well.
3123 const labelList& eFaces = edgeFaces_[edgeIndex];
3125 forAll(eFaces, faceI)
3127 const face& faceToCheck = faces_[eFaces[faceI]];
3129 if ((replaceIndex = faceToCheck.which(collapsePoint)) > -1)
3133 Info << "Renumbering face: "
3134 << eFaces[faceI] << ": "
3135 << faceToCheck << endl;
3138 // Renumber the face...
3139 faces_[eFaces[faceI]][replaceIndex] = replacePoint;
3141 // Set this face aside for mapping
3142 if (!modifiedFaces.found(eFaces[faceI]))
3144 modifiedFaces.insert(eFaces[faceI]);
3147 // Look for an edge on this face that doesn't
3148 // contain collapsePoint or replacePoint.
3149 label rplIndex = -1;
3150 const labelList& fEdges = faceEdges_[eFaces[faceI]];
3152 forAll(fEdges, edgeI)
3154 const edge& eCheck = edges_[fEdges[edgeI]];
3158 eCheck[0] != collapsePoint
3159 && eCheck[1] != collapsePoint
3160 && eCheck[0] != replacePoint
3161 && eCheck[1] != replacePoint
3164 rplIndex = fEdges[edgeI];
3169 // Modify edgePoints for this edge
3170 meshOps::replaceLabel
3174 edgePoints_[rplIndex]
3181 // At this point, edgePoints for the replacement edges are broken,
3182 // but edgeFaces are consistent. So use this information to re-build
3183 // edgePoints for all replacement edges.
3184 forAll(ringEntities[replaceEdgeIndex], edgeI)
3186 // If the ring edge was removed, don't bother.
3187 if (ringEntities[replaceEdgeIndex][edgeI] == -1)
3194 Info << "Building edgePoints for edge: "
3195 << ringEntities[replaceEdgeIndex][edgeI] << ": "
3196 << edges_[ringEntities[replaceEdgeIndex][edgeI]]
3200 buildEdgePoints(ringEntities[replaceEdgeIndex][edgeI]);
3203 // Move old / new points
3204 oldPoints_[replacePoint] = oldPoint;
3205 points_[replacePoint] = newPoint;
3207 // Remove the collapse point
3208 removePoint(collapsePoint);
3213 // For cell-mapping, exclude all hull-cells
3214 forAll(cellHull, indexI)
3216 if (cellsChecked.found(cellHull[indexI]))
3218 cellsChecked.erase(cellHull[indexI]);
3222 labelList mapCells = cellsChecked.toc();
3224 // Write out VTK files after change
3230 + '(' + Foam::name(edges_[eIndex][0])
3231 + ',' + Foam::name(edges_[eIndex][1]) + ')'
3237 // Specify that an old point-position
3238 // has been modified, if necessary
3239 if (collapseCase == 3)
3241 labelList mP(2, -1);
3243 mP[0] = collapsePoint;
3244 mP[1] = replacePoint;
3246 modPoints_.set(replacePoint, mP);
3249 // Now that all old / new cells possess correct connectivity,
3250 // compute mapping information.
3251 forAll(mapCells, cellI)
3253 // Fill-in candidate mapping information
3254 labelList mC(1, mapCells[cellI]);
3256 // Set the mapping for this cell
3257 setCellMapping(mapCells[cellI], mC);
3260 // Set face mapping information for modified faces
3261 forAllConstIter(labelHashSet, modifiedFaces, fIter)
3263 // Exclude deleted faces
3264 if (faces_[fIter.key()].empty())
3269 // Decide between default / weighted mapping
3270 // based on boundary information
3271 label fPatch = whichPatch(fIter.key());
3275 setFaceMapping(fIter.key());
3279 // Fill-in candidate mapping information
3280 labelList faceCandidates;
3282 const labelList& fEdges = faceEdges_[fIter.key()];
3284 forAll(fEdges, edgeI)
3286 if (whichEdgePatch(fEdges[edgeI]) == fPatch)
3288 // Loop through associated edgeFaces
3289 const labelList& eFaces = edgeFaces_[fEdges[edgeI]];
3291 forAll(eFaces, faceI)
3295 (eFaces[faceI] != fIter.key()) &&
3296 (whichPatch(eFaces[faceI]) == fPatch)
3299 faceCandidates.setSize
3301 faceCandidates.size() + 1,
3309 // Set the mapping for this face
3310 setFaceMapping(fIter.key(), faceCandidates);
3315 topoChangeFlag_ = true;
3317 // Increment the counter
3320 // Increment the number of modifications
3323 // Return a succesful collapse
3324 map.type() = collapseCase;
3330 // Remove the specified cells from the mesh,
3331 // and add internal faces/edges to the specified patch
3332 const changeMap dynamicTopoFvMesh::removeCells
3334 const labelList& cList,
3340 labelHashSet pointsToRemove, edgesToRemove, facesToRemove;
3341 Map<label> facesToConvert, edgesToConvert;
3343 // First loop through all cells and accumulate
3344 // a set of faces to be removed/converted.
3345 forAll(cList, cellI)
3347 const cell& cellToCheck = cells_[cList[cellI]];
3349 forAll(cellToCheck, faceI)
3351 label own = owner_[cellToCheck[faceI]];
3352 label nei = neighbour_[cellToCheck[faceI]];
3356 if (!facesToRemove.found(cellToCheck[faceI]))
3358 facesToRemove.insert(cellToCheck[faceI]);
3364 (findIndex(cList, own) != -1) &&
3365 (findIndex(cList, nei) != -1)
3368 if (!facesToRemove.found(cellToCheck[faceI]))
3370 facesToRemove.insert(cellToCheck[faceI]);
3375 facesToConvert.set(cellToCheck[faceI], -1);
3380 // Add all edges as candidates for conversion.
3381 // Some of these will be removed altogether.
3382 forAllConstIter(labelHashSet, facesToRemove, fIter)
3384 const labelList& fEdges = faceEdges_[fIter.key()];
3386 forAll(fEdges, edgeI)
3388 if (whichEdgePatch(fEdges[edgeI]) == patch)
3390 // Make an identical map
3391 edgesToConvert.set(fEdges[edgeI], fEdges[edgeI]);
3395 edgesToConvert.set(fEdges[edgeI], -1);
3400 forAllConstIter(Map<label>, facesToConvert, fIter)
3402 const labelList& fEdges = faceEdges_[fIter.key()];
3404 forAll(fEdges, edgeI)
3406 if (whichEdgePatch(fEdges[edgeI]) == patch)
3408 // Make an identical map
3409 edgesToConvert.set(fEdges[edgeI], fEdges[edgeI]);
3413 edgesToConvert.set(fEdges[edgeI], -1);
3418 // Build a list of edges to be removed.
3419 forAllConstIter(Map<label>, edgesToConvert, eIter)
3421 const labelList& eFaces = edgeFaces_[eIter.key()];
3423 bool allRemove = true;
3425 forAll(eFaces, faceI)
3427 if (facesToConvert.found(eFaces[faceI]))
3436 if (!edgesToRemove.found(eIter.key()))
3438 edgesToRemove.insert(eIter.key());
3443 // Weed-out the conversion list.
3444 forAllConstIter(labelHashSet, edgesToRemove, eIter)
3446 edgesToConvert.erase(eIter.key());
3449 // Build a set of points to be removed.
3452 forAllConstIter(labelHashSet, edgesToRemove, eIter)
3454 const edge& edgeToCheck = edges_[eIter.key()];
3456 forAll(edgeToCheck, pointI)
3458 const labelList& pEdges = pointEdges_[edgeToCheck[pointI]];
3460 bool allRemove = true;
3462 forAll(pEdges, edgeI)
3464 if (!edgesToRemove.found(pEdges[edgeI]))
3473 if (!pointsToRemove.found(edgeToCheck[pointI]))
3475 pointsToRemove.insert(edgeToCheck[pointI]);
3482 forAllIter(Map<label>, edgesToConvert, eIter)
3484 const labelList& eFaces = edgeFaces_[eIter.key()];
3486 label nConvFaces = 0;
3488 forAll(eFaces, faceI)
3490 if (facesToConvert.found(eFaces[faceI]))
3498 Info << "Invalid conversion. Bailing out." << endl;
3503 // Write out candidates for post-processing
3506 writeVTK("pointsToRemove", pointsToRemove.toc(), 0);
3507 writeVTK("edgesToRemove", edgesToRemove.toc(), 1);
3508 writeVTK("facesToRemove", facesToRemove.toc(), 2);
3509 writeVTK("cellsToRemove", cList, 3);
3510 writeVTK("edgesToConvert", edgesToConvert.toc(), 1);
3511 writeVTK("facesToConvert", facesToConvert.toc(), 2);
3514 // Loop through all faces for conversion, check orientation
3515 // and create new faces in their place.
3516 forAllIter(Map<label>, facesToConvert, fIter)
3518 // Check if this internal face is oriented properly.
3520 label newOwner = -1;
3521 labelList fEdges = faceEdges_[fIter.key()];
3523 if (findIndex(cList, neighbour_[fIter.key()]) != -1)
3525 // Orientation is correct
3526 newFace = faces_[fIter.key()];
3527 newOwner = owner_[fIter.key()];
3530 if (findIndex(cList, owner_[fIter.key()]) != -1)
3532 // Face is to be reversed.
3533 newFace = faces_[fIter.key()].reverseFace();
3534 newOwner = neighbour_[fIter.key()];
3536 setFlip(fIter.key());
3540 // Something's terribly wrong
3544 "const changeMap dynamicTopoFvMesh::removeCells\n"
3546 " const labelList& cList,\n"
3547 " const label patch\n"
3550 << nl << " Invalid mesh. "
3551 << abort(FatalError);
3554 // Insert the reconfigured face at the boundary.
3566 // Add the faceEdges entry.
3567 // Edges will be corrected later.
3568 faceEdges_.append(fEdges);
3570 // Add this face to the map.
3571 map.addFace(fIter());
3573 // Replace cell with the new face label
3574 meshOps::replaceLabel
3581 // Remove the internal face.
3582 removeFace(fIter.key());
3585 // Create a new edge for each converted edge
3586 forAllIter(Map<label>, edgesToConvert, eIter)
3590 // Create copies before appending.
3591 edge newEdge = edges_[eIter.key()];
3592 labelList eFaces = edgeFaces_[eIter.key()];
3593 labelList ePoints = edgePoints_[eIter.key()];
3606 // Add this edge to the map.
3607 map.addEdge(eIter());
3610 removeEdge(eIter.key());
3614 // Loop through all faces for conversion, and replace edgeFaces.
3615 forAllConstIter(Map<label>, facesToConvert, fIter)
3617 // Make a copy, because this list is going to
3618 // be modified within this loop.
3619 labelList fEdges = faceEdges_[fIter()];
3621 forAll(fEdges, edgeI)
3623 if (edgesToConvert.found(fEdges[edgeI]))
3625 meshOps::replaceLabel
3629 edgeFaces_[edgesToConvert[fEdges[edgeI]]]
3632 meshOps::replaceLabel
3635 edgesToConvert[fEdges[edgeI]],
3642 // Loop through all edges for conversion, and size-down edgeFaces.
3643 forAllConstIter(Map<label>, edgesToConvert, eIter)
3645 // Make a copy, because this list is going to
3646 // be modified within this loop.
3647 labelList eFaces = edgeFaces_[eIter()];
3649 forAll(eFaces, faceI)
3651 if (facesToRemove.found(eFaces[faceI]))
3653 meshOps::sizeDownList
3660 // Replace old edges with new ones.
3661 labelList& fEdges = faceEdges_[eFaces[faceI]];
3663 forAll(fEdges, edgeI)
3665 if (edgesToConvert.found(fEdges[edgeI]))
3667 fEdges[edgeI] = edgesToConvert[fEdges[edgeI]];
3673 // At this point, edgeFaces is consistent.
3674 // Correct edge-points for all converted edges
3677 forAllConstIter(Map<label>, edgesToConvert, eIter)
3679 buildEdgePoints(eIter());
3683 // Remove unwanted faces
3684 forAllConstIter(labelHashSet, facesToRemove, fIter)
3686 removeFace(fIter.key());
3689 // Remove unwanted edges
3690 forAllConstIter(labelHashSet, edgesToRemove, eIter)
3692 removeEdge(eIter.key());
3695 // Remove unwanted points
3696 forAllConstIter(labelHashSet, pointsToRemove, pIter)
3698 removePoint(pIter.key());
3702 forAll(cList, cellI)
3704 removeCell(cList[cellI]);
3708 topoChangeFlag_ = true;
3714 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3716 } // End namespace Foam
3718 // ************************************************************************* //