1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "dynamicTopoFvMesh.H"
30 #include "objectMap.H"
31 #include "changeMap.H"
32 #include "triPointRef.H"
33 #include "linePointRef.H"
34 #include "multiThreader.H"
35 #include "coupledInfo.H"
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
44 // Perform a Delaunay test on an internal face
45 // - Returns 'true' if the test failed
46 bool dynamicTopoFvMesh::testDelaunay
51 bool failed = false, procCoupled = false;
52 label eIndex = -1, pointIndex = -1, fLabel = -1;
53 label sIndex = -1, pIndex = -1;
54 FixedList<triFace, 2> triFaces(triFace(-1, -1, -1));
55 FixedList<bool, 2> foundTriFace(false);
57 // If this entity was deleted, skip it.
58 if (faces_[fIndex].empty())
63 // If face is not shared by prism cells, skip it.
64 label own = owner_[fIndex], nei = neighbour_[fIndex];
66 if (cells_[own].size() != 5)
73 if (cells_[nei].size() != 5)
79 // Boundary faces are discarded.
80 if (whichPatch(fIndex) > -1)
82 procCoupled = processorCoupledEntity(fIndex);
90 const labelList& fEdges = faceEdges_[fIndex];
94 // Break out if both triangular faces are found
95 if (foundTriFace[0] && foundTriFace[1])
100 // Obtain edgeFaces for this edge
101 const labelList& eFaces = edgeFaces_[fEdges[edgeI]];
103 forAll(eFaces, faceI)
105 const face& thisFace = faces_[eFaces[faceI]];
107 if (thisFace.size() == 3)
111 // Update the second face.
112 triFaces[1][0] = thisFace[0];
113 triFaces[1][1] = thisFace[1];
114 triFaces[1][2] = thisFace[2];
116 foundTriFace[1] = true;
120 // Update the first face.
121 triFaces[0][0] = thisFace[0];
122 triFaces[0][1] = thisFace[1];
123 triFaces[0][2] = thisFace[2];
125 foundTriFace[0] = true;
126 fLabel = eFaces[faceI];
129 eIndex = fEdges[edgeI];
133 // Stop searching for processor boundary cases
134 foundTriFace[1] = true;
141 const edge& checkEdge = edges_[eIndex];
143 // Configure the comparison edge
148 // If this is a new entity, bail out for now.
149 // This will be handled at the next time-step.
150 if (fIndex >= nOldFaces_)
155 const label faceEnum = coupleMap::FACE;
156 const label pointEnum = coupleMap::POINT;
159 bool foundEdge = false;
161 forAll(procIndices_, pI)
163 // Fetch non-const reference to subMeshes
164 const coupledInfo& recvMesh = recvMeshes_[pI];
166 const coupleMap& cMap = recvMesh.map();
167 const dynamicTopoFvMesh& sMesh = recvMesh.subMesh();
169 if ((sIndex = cMap.findSlave(faceEnum, fIndex)) > -1)
171 // Find equivalent points on the slave
172 cEdge[0] = cMap.findSlave(pointEnum, checkEdge[0]);
173 cEdge[1] = cMap.findSlave(pointEnum, checkEdge[1]);
175 // Find a triangular face containing cEdge
176 const labelList& sfE = sMesh.faceEdges_[sIndex];
180 // Obtain edgeFaces for this edge
181 const labelList& seF = sMesh.edgeFaces_[sfE[edgeI]];
185 const face& tF = sMesh.faces_[seF[faceI]];
191 (findIndex(tF, cEdge[0]) > -1) &&
192 (findIndex(tF, cEdge[1]) > -1)
195 triFaces[1][0] = tF[0];
196 triFaces[1][1] = tF[1];
197 triFaces[1][2] = tF[2];
212 // Store patch index for later
219 if (sIndex == -1 || !foundEdge)
221 // Write out for post-processing
222 writeVTK("coupledDelaunayFace_" + Foam::name(fIndex), fIndex, 2);
226 "bool dynamicTopoFvMesh::testDelaunay"
227 "(const label fIndex) const"
229 << "Coupled maps were improperly specified." << nl
230 << " Slave index not found for: " << nl
231 << " Face: " << fIndex << nl
232 << " checkEdge: " << checkEdge << nl
233 << " cEdge: " << cEdge << nl
234 << abort(FatalError);
243 // Obtain point references for the first face
244 point a = points_[triFaces[0][0]];
246 const face& faceToCheck = faces_[fLabel];
252 points_[faceToCheck[0]],
253 points_[faceToCheck[1]],
254 points_[faceToCheck[2]]
258 scalar rSquared = (a - cCentre) & (a - cCentre);
260 // Find the isolated point on the second face
261 point otherPoint = vector::zero;
263 // Check the first point
264 if (triFaces[1][0] != cEdge[0] && triFaces[1][0] != cEdge[1])
266 pointIndex = triFaces[1][0];
269 // Check the second point
270 if (triFaces[1][1] != cEdge[0] && triFaces[1][1] != cEdge[1])
272 pointIndex = triFaces[1][1];
275 // Check the third point
276 if (triFaces[1][2] != cEdge[0] && triFaces[1][2] != cEdge[1])
278 pointIndex = triFaces[1][2];
283 otherPoint = recvMeshes_[pIndex].subMesh().points_[pointIndex];
287 otherPoint = points_[pointIndex];
290 // ...and determine whether it lies in this circle
291 if (((otherPoint - cCentre) & (otherPoint - cCentre)) < rSquared)
301 // Method for the swapping of a quad-face in 2D
302 // - Returns a changeMap with a type specifying:
303 // 1: Swap sequence was successful
304 // -1: Swap sequence failed
305 const changeMap dynamicTopoFvMesh::swapQuadFace
314 label commonIndex = -1;
315 FixedList<label,4> otherPointIndex(-1), nextToOtherPoint(-1);
316 FixedList<label,2> c0BdyIndex(-1), c0IntIndex(-1);
317 FixedList<label,2> c1BdyIndex(-1), c1IntIndex(-1);
318 FixedList<face,2> c0BdyFace(face(3)), c0IntFace(face(4));
319 FixedList<face,2> c1BdyFace(face(3)), c1IntFace(face(4));
320 FixedList<label,2> commonEdgeIndex(-1);
321 FixedList<edge,2> commonEdges(edge(-1, -1));
322 FixedList<label,4> otherEdgeIndex(-1);
323 FixedList<label,4> commonFaceIndex(-1), cornerEdgeIndex(-1);
324 FixedList<face,4> commonFaces(face(3)), commonIntFaces(face(4));
325 FixedList<label,4> commonIntFaceIndex(-1);
326 FixedList<bool,2> foundTriFace0(false), foundTriFace1(false);
327 FixedList<face,2> triFaces0(face(3)), triFaces1(face(3));
329 if (coupledModification_)
331 if (processorCoupledEntity(fIndex))
333 // When swapping across processors, we need to add the
334 // prism-cell from (as well as delete on) the patchSubMesh
335 const changeMap faceMap = insertCells(fIndex);
337 // Bail out if entity is handled elsewhere
338 if (faceMap.type() == -2)
343 if (faceMap.type() != 1)
347 "const changeMap dynamicTopoFvMesh::swapQuadFace"
348 "(const label fIndex)"
350 << " Could not insert cells around face: " << fIndex
351 << " :: " << faces_[fIndex] << nl
352 << abort(FatalError);
355 // Figure out the new internal face index.
356 // This should not be a coupled face anymore.
357 label newIndex = faceMap.index();
359 // Temporarily turn off coupledModification
360 unsetCoupledModification();
362 // Recursively call this function for the new face
363 map = swapQuadFace(newIndex);
366 setCoupledModification();
372 // Get the two cells on either side...
373 label c0 = owner_[fIndex];
374 label c1 = neighbour_[fIndex];
376 // Prepare two new cells
377 FixedList<cell, 2> newCell(cell(5));
379 // Need to find common faces and edges...
380 // At the end of this loop, commonFaces [0] & [1] share commonEdge[0]
381 // and commonFaces [2] & [3] share commonEdge[1]
382 // Also, commonFaces[0] & [2] are connected to cell[0],
383 // and commonFaces[1] & [3] are connected to cell[1]
384 const labelList& fEdges = faceEdges_[fIndex];
386 forAll(fEdges, edgeI)
388 // Break out if all triangular faces are found
391 foundTriFace0[0] && foundTriFace0[1] &&
392 foundTriFace1[0] && foundTriFace1[1]
398 // Obtain edgeFaces for this edge
399 const labelList& eFaces = edgeFaces_[fEdges[edgeI]];
401 forAll(eFaces, faceI)
403 const face& eFace = faces_[eFaces[faceI]];
405 if (eFace.size() == 3)
407 // Found a triangular face. Determine which cell it belongs to.
408 if (owner_[eFaces[faceI]] == c0)
410 if (foundTriFace0[0])
412 // Update the second face on cell[0].
414 foundTriFace0[1] = true;
416 if (foundTriFace1[1])
418 commonEdgeIndex[1] = fEdges[edgeI];
419 commonEdges[1] = edges_[fEdges[edgeI]];
424 // Update the first face on cell[0].
426 foundTriFace0[0] = true;
428 if (foundTriFace1[0])
430 commonEdgeIndex[0] = fEdges[edgeI];
431 commonEdges[0] = edges_[fEdges[edgeI]];
437 if (foundTriFace1[0])
439 // Update the second face on cell[1].
441 foundTriFace1[1] = true;
443 if (foundTriFace0[1])
445 commonEdgeIndex[1] = fEdges[edgeI];
446 commonEdges[1] = edges_[fEdges[edgeI]];
451 // Update the first face on cell[1].
453 foundTriFace1[0] = true;
455 if (foundTriFace0[0])
457 commonEdgeIndex[0] = fEdges[edgeI];
458 commonEdges[0] = edges_[fEdges[edgeI]];
463 // Store the face and index
464 commonFaces[commonIndex][0] = eFace[0];
465 commonFaces[commonIndex][1] = eFace[1];
466 commonFaces[commonIndex][2] = eFace[2];
468 commonFaceIndex[commonIndex] = eFaces[faceI];
473 // Find the interior/boundary faces.
474 meshOps::findPrismFaces
487 meshOps::findPrismFaces
500 // Find the points that don't lie on shared edges
501 // and the points next to them (for orientation)
502 meshOps::findIsolatedPoint
510 meshOps::findIsolatedPoint
518 meshOps::findIsolatedPoint
526 meshOps::findIsolatedPoint
534 // Ensure that the configuration will be valid
535 // using old point-positions. A simple area-based
536 // calculation should suffice.
537 FixedList<face, 2> triFaceOldPoints(face(3));
539 triFaceOldPoints[0][0] = otherPointIndex[0];
540 triFaceOldPoints[0][1] = nextToOtherPoint[0];
541 triFaceOldPoints[0][2] = otherPointIndex[1];
543 triFaceOldPoints[1][0] = otherPointIndex[1];
544 triFaceOldPoints[1][1] = nextToOtherPoint[1];
545 triFaceOldPoints[1][2] = otherPointIndex[0];
547 // Assume XY plane here
548 vector n = vector(0,0,1);
550 forAll(triFaceOldPoints, faceI)
552 // Assume that centre-plane passes through the origin.
555 xf = triFaceOldPoints[faceI].centre(oldPoints_);
556 nf = triFaceOldPoints[faceI].normal(oldPoints_);
558 if ((((xf & n) * n) & nf) < 0.0)
560 // This will yield an inverted cell. Bail out.
565 // Find the other two edges on the face being flipped
566 forAll(fEdges, edgeI)
570 fEdges[edgeI] != commonEdgeIndex[0] &&
571 fEdges[edgeI] != commonEdgeIndex[1]
574 // Obtain a reference to this edge
575 const edge& eThis = edges_[fEdges[edgeI]];
579 eThis[0] == nextToOtherPoint[0]
580 || eThis[1] == nextToOtherPoint[0]
583 otherEdgeIndex[0] = fEdges[edgeI];
587 otherEdgeIndex[1] = fEdges[edgeI];
592 // At the end of this loop, commonIntFaces [0] & [1] share otherEdges[0]
593 // and commonIntFaces [2] & [3] share the otherEdges[1],
594 // where [0],[2] lie on cell[0] and [1],[3] lie on cell[1]
597 const labelList& e1 = faceEdges_[c0IntIndex[0]];
601 if (e1[edgeI] == otherEdgeIndex[0])
603 commonIntFaces[0] = c0IntFace[0];
604 commonIntFaces[2] = c0IntFace[1];
605 commonIntFaceIndex[0] = c0IntIndex[0];
606 commonIntFaceIndex[2] = c0IntIndex[1];
613 // The edge was not found before
614 commonIntFaces[0] = c0IntFace[1];
615 commonIntFaces[2] = c0IntFace[0];
616 commonIntFaceIndex[0] = c0IntIndex[1];
617 commonIntFaceIndex[2] = c0IntIndex[0];
622 const labelList& e3 = faceEdges_[c1IntIndex[0]];
626 if (e3[edgeI] == otherEdgeIndex[0])
628 commonIntFaces[1] = c1IntFace[0];
629 commonIntFaces[3] = c1IntFace[1];
630 commonIntFaceIndex[1] = c1IntIndex[0];
631 commonIntFaceIndex[3] = c1IntIndex[1];
638 // The edge was not found before
639 commonIntFaces[1] = c1IntFace[1];
640 commonIntFaces[3] = c1IntFace[0];
641 commonIntFaceIndex[1] = c1IntIndex[1];
642 commonIntFaceIndex[3] = c1IntIndex[0];
645 // Find two common edges between quad/quad faces
646 meshOps::findCommonEdge
654 meshOps::findCommonEdge
662 // Find four common edges between quad/tri faces
663 meshOps::findCommonEdge
666 commonIntFaceIndex[1],
671 meshOps::findCommonEdge
674 commonIntFaceIndex[1],
679 meshOps::findCommonEdge
682 commonIntFaceIndex[2],
687 meshOps::findCommonEdge
690 commonIntFaceIndex[2],
695 // Perform a few debug calls before modifications
698 Pout<< nl << nl << "Face: " << fIndex
699 << " needs to be flipped. " << endl;
703 Pout<< " Cell[0]: " << c0 << ": " << cells_[c0] << nl
704 << " Cell[1]: " << c1 << ": " << cells_[c1] << nl;
706 Pout<< " Common Faces: Set 1: "
707 << commonFaceIndex[0] << ": " << commonFaces[0] << ", "
708 << commonFaceIndex[1] << ": " << commonFaces[1] << nl;
710 Pout<< " Common Faces: Set 2: "
711 << commonFaceIndex[2] << ": " << commonFaces[2] << ", "
712 << commonFaceIndex[3] << ": " << commonFaces[3] << nl;
714 Pout<< " Old face: " << faces_[fIndex] << nl
715 << " Old faceEdges: " << faceEdges_[fIndex] << endl;
718 // Write out VTK files before change
721 labelList cellHull(2, -1);
726 writeVTK(Foam::name(fIndex) + "_Swap_0", cellHull);
730 // Modify the five faces belonging to this hull
731 face newFace = faces_[fIndex];
732 labelList newFEdges = faceEdges_[fIndex];
733 FixedList<face, 4> newBdyFace(face(3));
734 FixedList<edge, 2> newEdges;
736 // Assign current faces
737 forAll(newBdyFace, faceI)
739 newBdyFace[faceI] = faces_[commonFaceIndex[faceI]];
742 label c0count=0, c1count=0;
744 // Size down edgeFaces for the original face
745 meshOps::sizeDownList
748 edgeFaces_[otherEdgeIndex[0]]
751 meshOps::sizeDownList
754 edgeFaces_[otherEdgeIndex[1]]
757 // Size up edgeFaces for the face after flipping
761 edgeFaces_[otherEdgeIndex[2]]
767 edgeFaces_[otherEdgeIndex[3]]
770 // Replace edgeFaces and faceEdges for the
771 // four (out of 8 total) corner edges of this hull.
772 meshOps::replaceLabel
776 faceEdges_[commonFaceIndex[1]]
779 meshOps::replaceLabel
783 edgeFaces_[cornerEdgeIndex[0]]
786 meshOps::replaceLabel
790 faceEdges_[commonFaceIndex[3]]
793 meshOps::replaceLabel
797 edgeFaces_[cornerEdgeIndex[1]]
800 meshOps::replaceLabel
804 faceEdges_[commonFaceIndex[0]]
807 meshOps::replaceLabel
811 edgeFaces_[cornerEdgeIndex[2]]
814 meshOps::replaceLabel
818 faceEdges_[commonFaceIndex[2]]
821 meshOps::replaceLabel
825 edgeFaces_[cornerEdgeIndex[3]]
828 // Define parameters for the new flipped face
829 newFace[0] = otherPointIndex[0];
830 newFace[1] = otherPointIndex[1];
831 newFace[2] = otherPointIndex[3];
832 newFace[3] = otherPointIndex[2];
834 newFEdges[0] = otherEdgeIndex[2];
835 newFEdges[1] = commonEdgeIndex[0];
836 newFEdges[2] = otherEdgeIndex[3];
837 newFEdges[3] = commonEdgeIndex[1];
839 newCell[0][c0count++] = fIndex;
840 newCell[1][c1count++] = fIndex;
843 neighbour_[fIndex] = c1;
845 // Both commonEdges need to be renumbered.
846 newEdges[0][0] = otherPointIndex[0];
847 newEdges[0][1] = otherPointIndex[1];
849 newEdges[1][0] = otherPointIndex[3];
850 newEdges[1][1] = otherPointIndex[2];
852 // Four modified boundary faces need to be constructed,
853 // but right-handedness is also important.
854 // Take a cue from the existing boundary-face orientation
856 // Zeroth boundary face - Owner c[0], Neighbour -1
857 newBdyFace[0][0] = otherPointIndex[0];
858 newBdyFace[0][1] = nextToOtherPoint[0];
859 newBdyFace[0][2] = otherPointIndex[1];
860 newCell[0][c0count++] = commonFaceIndex[0];
861 owner_[commonFaceIndex[0]] = c0;
862 neighbour_[commonFaceIndex[0]] = -1;
864 // First boundary face - Owner c[1], Neighbour -1
865 newBdyFace[1][0] = otherPointIndex[1];
866 newBdyFace[1][1] = nextToOtherPoint[1];
867 newBdyFace[1][2] = otherPointIndex[0];
868 newCell[1][c1count++] = commonFaceIndex[1];
869 owner_[commonFaceIndex[1]] = c1;
870 neighbour_[commonFaceIndex[1]] = -1;
872 // Second boundary face - Owner c[0], Neighbour -1
873 newBdyFace[2][0] = otherPointIndex[3];
874 newBdyFace[2][1] = nextToOtherPoint[3];
875 newBdyFace[2][2] = otherPointIndex[2];
876 newCell[0][c0count++] = commonFaceIndex[2];
877 owner_[commonFaceIndex[2]] = c0;
878 neighbour_[commonFaceIndex[2]] = -1;
880 // Third boundary face - Owner c[1], Neighbour -1
881 newBdyFace[3][0] = otherPointIndex[2];
882 newBdyFace[3][1] = nextToOtherPoint[2];
883 newBdyFace[3][2] = otherPointIndex[3];
884 newCell[1][c1count++] = commonFaceIndex[3];
885 owner_[commonFaceIndex[3]] = c1;
886 neighbour_[commonFaceIndex[3]] = -1;
890 Pout<< "New flipped face: " << newFace << nl;
894 forAll(newBdyFace, faceI)
896 Pout<< "New boundary face[" << faceI << "]: "
897 << commonFaceIndex[faceI]
898 << ": " << newBdyFace[faceI] << nl;
905 // Check the orientation of the two quad faces, and modify as necessary
906 label newOwn=0, newNei=0;
908 // The quad face belonging to cell[1] now becomes a part of cell[0]
909 if (neighbour_[commonIntFaceIndex[1]] == -1)
912 // Face doesn't need to be flipped, just update the owner
913 f = commonIntFaces[1];
918 if (owner_[commonIntFaceIndex[1]] == c1)
920 // This face is on the interior, check for previous owner
921 // Upper-triangular ordering has to be maintained, however...
922 if (c0 > neighbour_[commonIntFaceIndex[1]])
925 f = commonIntFaces[1].reverseFace();
926 newOwn = neighbour_[commonIntFaceIndex[1]];
929 setFlip(commonIntFaceIndex[1]);
933 // Flip isn't necessary, just change the owner
934 f = commonIntFaces[1];
936 newNei = neighbour_[commonIntFaceIndex[1]];
940 if (neighbour_[commonIntFaceIndex[1]] == c1)
942 // This face is on the interior, check for previous neighbour
943 // Upper-triangular ordering has to be maintained, however...
944 if (c0 < owner_[commonIntFaceIndex[1]])
947 f = commonIntFaces[1].reverseFace();
949 newNei = owner_[commonIntFaceIndex[1]];
951 setFlip(commonIntFaceIndex[1]);
955 // Flip isn't necessary, just change the neighbour
956 f = commonIntFaces[1];
957 newOwn = owner_[commonIntFaceIndex[1]];
962 faces_[commonIntFaceIndex[1]] = f;
963 newCell[0][c0count++] = commonIntFaceIndex[0];
964 newCell[0][c0count++] = commonIntFaceIndex[1];
965 owner_[commonIntFaceIndex[1]] = newOwn;
966 neighbour_[commonIntFaceIndex[1]] = newNei;
968 // The quad face belonging to cell[0] now becomes a part of cell[1]
969 if (neighbour_[commonIntFaceIndex[2]] == -1)
972 // Face doesn't need to be flipped, just update the owner
973 f = commonIntFaces[2];
978 if (owner_[commonIntFaceIndex[2]] == c0)
980 // This face is on the interior, check for previous owner
981 // Upper-triangular ordering has to be maintained, however...
982 if (c1 > neighbour_[commonIntFaceIndex[2]])
985 f = commonIntFaces[2].reverseFace();
986 newOwn = neighbour_[commonIntFaceIndex[2]];
989 setFlip(commonIntFaceIndex[2]);
993 // Flip isn't necessary, just change the owner
994 f = commonIntFaces[2];
996 newNei = neighbour_[commonIntFaceIndex[2]];
1000 if (neighbour_[commonIntFaceIndex[2]] == c0)
1002 // This face is on the interior, check for previous neighbour
1003 // Upper-triangular ordering has to be maintained, however...
1004 if (c1 < owner_[commonIntFaceIndex[2]])
1006 // Flip is necessary
1007 f = commonIntFaces[2].reverseFace();
1009 newNei = owner_[commonIntFaceIndex[2]];
1011 setFlip(commonIntFaceIndex[2]);
1015 // Flip isn't necessary, just change the neighbour
1016 f = commonIntFaces[2];
1017 newOwn = owner_[commonIntFaceIndex[2]];
1022 faces_[commonIntFaceIndex[2]] = f;
1023 newCell[1][c1count++] = commonIntFaceIndex[2];
1024 newCell[1][c1count++] = commonIntFaceIndex[3];
1025 owner_[commonIntFaceIndex[2]] = newOwn;
1026 neighbour_[commonIntFaceIndex[2]] = newNei;
1028 // Now that all entities are properly configured,
1029 // overwrite the entries in connectivity lists.
1030 cells_[c0] = newCell[0];
1031 cells_[c1] = newCell[1];
1033 faces_[fIndex] = newFace;
1034 faceEdges_[fIndex] = newFEdges;
1036 forAll(newBdyFace, faceI)
1038 faces_[commonFaceIndex[faceI]] = newBdyFace[faceI];
1041 edges_[commonEdgeIndex[0]] = newEdges[0];
1042 edges_[commonEdgeIndex[1]] = newEdges[1];
1044 // Fill-in mapping information
1045 labelList mC(2, -1);
1046 mC[0] = c0; mC[1] = c1;
1050 // Set the mapping for this cell
1051 setCellMapping(mC[cellI], mC);
1054 // Interpolate new fluxes for the flipped face.
1055 setFaceMapping(fIndex);
1057 // Write out VTK files after change
1060 labelList cellHull(2, -1);
1074 topoChangeFlag_ = true;
1076 // Increment the counter
1079 // Return a successful operation.
1086 // Allocate dynamic programming tables
1087 void dynamicTopoFvMesh::initTables
1090 PtrList<scalarListList>& Q,
1091 PtrList<labelListList>& K,
1092 PtrList<labelListList>& triangulations,
1093 const label checkIndex
1096 label mMax = maxTetsPerEdge_;
1098 // Check if resizing is necessary only for a particular index.
1099 if (checkIndex != -1)
1102 Q[checkIndex].setSize((mMax-2),scalarList(mMax,-1.0));
1103 K[checkIndex].setSize((mMax-2),labelList(mMax,-1));
1104 triangulations[checkIndex].setSize(3,labelList((mMax-2),-1));
1109 // Size all elements by default.
1110 label numIndices = coupledModification_ ? 2 : 1;
1112 m.setSize(numIndices, -1);
1113 Q.setSize(numIndices);
1114 K.setSize(numIndices);
1115 triangulations.setSize(numIndices);
1122 new scalarListList((mMax-2),scalarList(mMax,-1.0))
1128 new labelListList((mMax-2),labelList(mMax,-1))
1134 new labelListList(3,labelList((mMax-2),-1))
1140 // Utility method to fill the dynamic programming tables
1141 // - Returns true if the operation completed successfully.
1142 // - Returns false if tables could not be resized.
1143 bool dynamicTopoFvMesh::fillTables
1148 labelList& hullVertices,
1149 PtrList<scalarListList>& Q,
1150 PtrList<labelListList>& K,
1151 PtrList<labelListList>& triangulations,
1152 const label checkIndex
1155 // Obtain a reference to this edge
1156 const labelList& edgeFaces = edgeFaces_[eIndex];
1158 // If this entity was deleted, skip it.
1159 if (edgeFaces.empty())
1164 // Ensure that edge is surrounded by triangles
1165 forAll(edgeFaces, faceI)
1167 if (faces_[edgeFaces[faceI]].size() != 3)
1173 const edge& edgeToCheck = edges_[eIndex];
1175 if (coupledModification_)
1177 return coupledFillTables(eIndex, minQuality, m, Q, K, triangulations);
1181 m[checkIndex] = hullVertices.size();
1183 // Check if a table-resize is necessary
1184 if (m[checkIndex] > maxTetsPerEdge_)
1186 if (allowTableResize_)
1188 // Resize the tables to account for
1189 // more tets per edge
1190 label& mtpe = const_cast<label&>(maxTetsPerEdge_);
1192 mtpe = m[checkIndex];
1194 // Clear tables for this index.
1195 Q[checkIndex].clear();
1196 K[checkIndex].clear();
1197 triangulations[checkIndex].clear();
1199 // Resize for this index.
1200 initTables(m, Q, K, triangulations, checkIndex);
1204 // Can't resize. Bail out.
1209 // Fill dynamic programming tables
1219 triangulations[checkIndex]
1222 // Print out tables for debugging
1225 printTables(m, Q, K, checkIndex);
1232 // Fill tables given addressing
1233 void dynamicTopoFvMesh::fillTables
1235 const edge& edgeToCheck,
1236 const scalar minQuality,
1238 const labelList& hullVertices,
1239 const UList<point>& points,
1242 labelListList& triangulations
1245 for (label i = (m - 3); i >= 0; i--)
1247 for (label j = i + 2; j < m; j++)
1249 for (label k = i + 1; k < j; k++)
1251 scalar q = (*tetMetric_)
1253 points[hullVertices[i]],
1254 points[hullVertices[k]],
1255 points[hullVertices[j]],
1256 points[edgeToCheck[0]]
1259 // For efficiency, check the bottom triangulation
1260 // only when the top one if less than the hull quality.
1270 points[hullVertices[j]],
1271 points[hullVertices[k]],
1272 points[hullVertices[i]],
1273 points[edgeToCheck[1]]
1281 q = Foam::min(q, Q[k][j]);
1286 q = Foam::min(q, Q[i][k]);
1289 if ((k == i + 1) || (q > Q[i][j]))
1300 // Remove the edge according to the swap sequence.
1301 // - Returns a changeMap with a type specifying:
1302 // 1: Swap sequence was successful
1303 // -1: Swap sequence failed
1304 const changeMap dynamicTopoFvMesh::removeEdgeFlips
1307 const scalar minQuality,
1308 const labelList& vertexHull,
1309 PtrList<scalarListList>& Q,
1310 PtrList<labelListList>& K,
1311 PtrList<labelListList>& triangulations,
1312 const label checkIndex
1315 changeMap map, slaveMap;
1319 Pout<< nl << " Removing edge : " << eIndex << " by flipping."
1320 << " Edge: " << edges_[eIndex]
1321 << " minQuality: " << minQuality
1325 if (coupledModification_)
1327 if (processorCoupledEntity(eIndex))
1329 const changeMap edgeMap = insertCells(eIndex);
1331 // Bail out if entity is handled elsewhere
1332 if (edgeMap.type() == -2)
1337 if (edgeMap.type() != 1)
1342 "const changeMap dynamicTopoFvMesh::removeEdgeFlips\n"
1344 " const label eIndex,\n"
1345 " const scalar minQuality,\n"
1346 " const labelList& vertexHull,\n"
1347 " PtrList<scalarListList>& Q,\n"
1348 " PtrList<labelListList>& K,\n"
1349 " PtrList<labelListList>& triangulations,\n"
1350 " const label checkIndex\n"
1353 << " Could not insert cells around edge: " << eIndex
1354 << " :: " << edges_[eIndex] << nl
1355 << abort(FatalError);
1358 // Temporarily turn off coupledModification
1359 unsetCoupledModification();
1361 // Re-fill tables for the reconfigured edge.
1362 // This should not be a coupled edge anymore.
1363 label newIndex = edgeMap.index();
1365 if (processorCoupledEntity(newIndex))
1367 // Write out edge connectivity
1368 writeEdgeConnectivity(newIndex);
1373 "const changeMap dynamicTopoFvMesh::removeEdgeFlips\n"
1375 " const label eIndex,\n"
1376 " const scalar minQuality,\n"
1377 " const labelList& vertexHull,\n"
1378 " PtrList<scalarListList>& Q,\n"
1379 " PtrList<labelListList>& K,\n"
1380 " PtrList<labelListList>& triangulations,\n"
1381 " const label checkIndex\n"
1384 << " Edge: " << newIndex
1385 << " :: " << edges_[newIndex] << nl
1386 << " is still processor-coupled. "
1387 << abort(FatalError);
1390 const edge& newEdge = edges_[newIndex];
1392 // Build vertexHull for this edge
1393 labelList newVertexHull;
1394 buildVertexHull(newIndex, newVertexHull);
1400 newVertexHull.size(),
1408 // Recursively call this function for the new edge
1423 setCoupledModification();
1429 label m = vertexHull.size();
1430 labelList hullFaces(m, -1);
1431 labelList hullCells(m, -1);
1432 labelList hullEdges(m, -1);
1433 labelListList ringEntities(4, labelList(m, -1));
1435 // Construct the hull
1436 meshOps::constructHull
1453 label numTriangulations = 0, isolatedVertex = -1;
1455 // Extract the appropriate triangulations
1456 extractTriangulation
1462 triangulations[checkIndex]
1465 // Check old-volumes for the configuration.
1468 checkTriangulationVolumes
1472 triangulations[checkIndex]
1476 // Reset all triangulations and bail out
1477 triangulations[checkIndex][0] = -1;
1478 triangulations[checkIndex][1] = -1;
1479 triangulations[checkIndex][2] = -1;
1484 // Determine the final swap triangulation
1491 triangulations[checkIndex]
1495 // Check that the triangulation is valid
1500 const edge& edgeToCheck = edges_[eIndex];
1502 Pout<< " All triangulations: " << nl
1503 << ' ' << triangulations[checkIndex][0] << nl
1504 << ' ' << triangulations[checkIndex][1] << nl
1505 << ' ' << triangulations[checkIndex][2] << nl
1511 "const changeMap dynamicTopoFvMesh::removeEdgeFlips\n"
1513 " const label eIndex,\n"
1514 " const scalar minQuality,\n"
1515 " const labelList& vertexHull,\n"
1516 " PtrList<scalarListList>& Q,\n"
1517 " PtrList<labelListList>& K,\n"
1518 " PtrList<labelListList>& triangulations,\n"
1519 " const label checkIndex\n"
1522 << "Could not determine 3-2 swap triangulation." << nl
1523 << "Edge: " << edgeToCheck << nl
1525 << points_[edgeToCheck[0]] << ","
1526 << points_[edgeToCheck[1]] << nl
1527 << abort(FatalError);
1529 // Reset all triangulations and bail out
1530 triangulations[checkIndex][0] = -1;
1531 triangulations[checkIndex][1] = -1;
1532 triangulations[checkIndex][2] = -1;
1539 Pout<< " Identified tF as: " << tF << nl;
1541 Pout<< " Triangulation: "
1542 << triangulations[checkIndex][0][tF] << " "
1543 << triangulations[checkIndex][1][tF] << " "
1544 << triangulations[checkIndex][2][tF] << " "
1547 Pout<< " All triangulations: " << nl
1548 << ' ' << triangulations[checkIndex][0] << nl
1549 << ' ' << triangulations[checkIndex][1] << nl
1550 << ' ' << triangulations[checkIndex][2] << nl
1554 if (coupledModification_)
1556 if (locallyCoupledEntity(eIndex))
1558 // Flip the slave edge as well.
1561 // Determine the slave index.
1562 forAll(patchCoupling_, patchI)
1564 if (patchCoupling_(patchI))
1566 const label edgeEnum = coupleMap::EDGE;
1567 const coupleMap& cMap = patchCoupling_[patchI].map();
1569 if ((sIndex = cMap.findSlave(edgeEnum, eIndex)) > -1)
1581 "const changeMap dynamicTopoFvMesh::removeEdgeFlips\n"
1583 " const label eIndex,\n"
1584 " const scalar minQuality,\n"
1585 " const labelList& vertexHull,\n"
1586 " PtrList<scalarListList>& Q,\n"
1587 " PtrList<labelListList>& K,\n"
1588 " PtrList<labelListList>& triangulations,\n"
1589 " const label checkIndex\n"
1592 << "Coupled maps were improperly specified." << nl
1593 << " Slave index not found for: " << nl
1594 << " Edge: " << eIndex << nl
1595 << abort(FatalError);
1600 Pout<< nl << "Removing slave edge: " << sIndex
1601 << " for master edge: " << eIndex << endl;
1604 // Build vertexHull for this edge
1605 labelList slaveVertexHull;
1606 buildVertexHull(sIndex, slaveVertexHull);
1608 // Turn off switch temporarily.
1609 unsetCoupledModification();
1611 // Recursively call for the slave edge.
1627 setCoupledModification();
1629 // Bail out if the slave failed.
1630 if (slaveMap.type() == -1)
1632 // Reset all triangulations and bail out
1633 triangulations[checkIndex][0] = -1;
1634 triangulations[checkIndex][1] = -1;
1635 triangulations[checkIndex][2] = -1;
1642 // Perform a series of 2-3 swaps
1645 while (numSwaps < (m-3))
1647 for (label i = 0; i < (m-2); i++)
1649 if ( (i != tF) && (triangulations[checkIndex][0][i] != -1) )
1651 // Check if triangulation is on the boundary
1654 boundaryTriangulation
1658 triangulations[checkIndex]
1671 triangulations[checkIndex],
1678 // Done with this face, so reset it
1679 triangulations[checkIndex][0][i] = -1;
1680 triangulations[checkIndex][1][i] = -1;
1681 triangulations[checkIndex][2][i] = -1;
1690 Pout<< "Triangulations: " << nl;
1692 forAll(triangulations[checkIndex], row)
1694 Pout<< triangulations[checkIndex][row] << nl;
1699 // Should have performed at least one swap
1703 "const changeMap dynamicTopoFvMesh::removeEdgeFlips\n"
1705 " const label eIndex,\n"
1706 " const scalar minQuality,\n"
1707 " const labelList& vertexHull,\n"
1708 " PtrList<scalarListList>& Q,\n"
1709 " PtrList<labelListList>& K,\n"
1710 " PtrList<labelListList>& triangulations,\n"
1711 " const label checkIndex\n"
1714 << "Did not perform any 2-3 swaps" << nl
1715 << abort(FatalError);
1719 // Perform the final 3-2 / 2-2 swap
1727 triangulations[checkIndex],
1734 // Done with this face, so reset it
1735 triangulations[checkIndex][0][tF] = -1;
1736 triangulations[checkIndex][1][tF] = -1;
1737 triangulations[checkIndex][2][tF] = -1;
1739 // Update the coupled map
1740 if (coupledModification_)
1742 // Create a mapping entry for the new edge.
1743 const coupleMap& cMap = patchCoupling_[pIndex].map();
1745 if (locallyCoupledEntity(map.addedEdgeList()[0].index()))
1750 map.addedEdgeList()[0].index(),
1751 slaveMap.addedEdgeList()[0].index()
1757 slaveMap.addedEdgeList()[0].index(),
1758 map.addedEdgeList()[0].index()
1762 // Add a mapping entry for two new faces as well.
1765 const List<objectMap>& amfList = map.addedFaceList();
1766 const List<objectMap>& asfList = slaveMap.addedFaceList();
1768 forAll(amfList, mfI)
1770 // Configure a face for comparison.
1771 const face& mF = faces_[amfList[mfI].index()];
1775 cF[pointI] = cMap.entityMap(coupleMap::POINT)[mF[pointI]];
1778 bool matched = false;
1780 forAll(asfList, sfI)
1782 const face& sF = faces_[asfList[sfI].index()];
1784 if (triFace::compare(triFace(cF), triFace(sF)))
1789 amfList[mfI].index(),
1790 asfList[sfI].index()
1796 asfList[sfI].index(),
1797 amfList[mfI].index()
1808 Pout<< "masterFaces: " << nl
1811 Pout<< "slaveFaces: " << nl
1814 forAll(amfList, mfI)
1816 Pout<< amfList[mfI].index() << ": "
1817 << faces_[amfList[mfI].index()]
1821 forAll(asfList, sfI)
1823 Pout<< asfList[sfI].index() << ": "
1824 << faces_[asfList[sfI].index()]
1833 "const changeMap dynamicTopoFvMesh::removeEdgeFlips\n"
1835 " const label eIndex,\n"
1836 " const scalar minQuality,\n"
1837 " const labelList& vertexHull,\n"
1838 " PtrList<scalarListList>& Q,\n"
1839 " PtrList<labelListList>& K,\n"
1840 " PtrList<labelListList>& triangulations,\n"
1841 " const label checkIndex\n"
1844 << "Failed to build coupled face maps."
1845 << abort(FatalError);
1850 // Finally remove the edge
1854 map.removeEdge(eIndex);
1856 // Increment the counter
1860 topoChangeFlag_ = true;
1862 // Return a successful operation.
1867 // Extract triangulations from the programming table
1868 void dynamicTopoFvMesh::extractTriangulation
1872 const labelListList& K,
1873 label& numTriangulations,
1874 labelListList& triangulations
1881 // Fill in the triangulation list
1882 triangulations[0][numTriangulations] = i;
1883 triangulations[1][numTriangulations] = k;
1884 triangulations[2][numTriangulations] = j;
1886 // Increment triangulation count
1887 numTriangulations++;
1889 // Recursively call the function for the two sub-triangulations
1890 extractTriangulation(i,k,K,numTriangulations,triangulations);
1891 extractTriangulation(k,j,K,numTriangulations,triangulations);
1896 // Identify the 3-2 swap from the triangulation sequence
1897 // - Use an edge-plane intersection formula
1898 label dynamicTopoFvMesh::identify32Swap
1901 const labelList& hullVertices,
1902 const labelListList& triangulations,
1906 label m = hullVertices.size();
1907 const edge& edgeToCheck = edges_[eIndex];
1909 // Obtain intersection point.
1910 linePointRef segment
1912 points_[edgeToCheck.start()],
1913 points_[edgeToCheck.end()]
1916 vector intPt = vector::zero;
1918 // Configure a face with triangulation
1919 for (label i = 0; i < (m-2); i++)
1923 meshOps::segmentTriFaceIntersection
1927 points_[hullVertices[triangulations[0][i]]],
1928 points_[hullVertices[triangulations[1][i]]],
1929 points_[hullVertices[triangulations[2][i]]]
1942 if (debug > 1 || output)
1944 Pout<< nl << nl << "Hull Vertices: " << nl;
1946 forAll(hullVertices, vertexI)
1948 Pout<< hullVertices[vertexI] << ": "
1949 << points_[hullVertices[vertexI]]
1956 "label dynamicTopoFvMesh::identify32Swap\n"
1958 " const label eIndex,\n"
1959 " const labelList& hullVertices,\n"
1960 " const labelListList& triangulations,\n"
1964 << "Could not determine 3-2 swap triangulation." << nl
1965 << "Edge: " << edgeToCheck << nl
1967 << segment.start() << "," << segment.end() << nl
1971 // Could not find an intersecting triangulation.
1972 // - If this is a boundary edge, a curved surface-mesh
1973 // was probably the reason why this failed.
1974 // - If so, declare the nearest triangulation instead.
1975 vector eCentre = segment.centre();
1977 scalarField dist(m-2, 0.0);
1979 label mT = -1, ePatch = whichEdgePatch(eIndex);
1980 bool foundTriangulation = false;
1982 for (label i = 0; i < (m-2); i++)
1984 // Compute edge to face-centre distance.
1992 points_[hullVertices[triangulations[0][i]]],
1993 points_[hullVertices[triangulations[1][i]]],
1994 points_[hullVertices[triangulations[2][i]]]
2000 while (!foundTriangulation)
2004 // Check validity for boundary edges
2008 ((triangulations[0][mT] != 0) || (triangulations[2][mT] != m-1))
2011 // This is a 2-3 triangulation. Try again.
2016 foundTriangulation = true;
2020 if (debug > 1 || output)
2022 Pout<< " All distances :" << dist << nl
2023 << " Triangulation index: " << mT
2032 // Routine to check whether the triangulation at the
2033 // index lies on the boundary of the vertex ring.
2034 bool dynamicTopoFvMesh::boundaryTriangulation
2037 label& isolatedVertex,
2038 labelListList& triangulations
2041 label first = 0, second = 0, third = 0;
2043 // Count for occurrences
2044 forAll(triangulations, row)
2046 forAll(triangulations[row], col)
2048 if (triangulations[row][col] == triangulations[0][index])
2053 if (triangulations[row][col] == triangulations[1][index])
2058 if (triangulations[row][col] == triangulations[2][index])
2067 isolatedVertex = triangulations[0][index];
2073 isolatedVertex = triangulations[1][index];
2079 isolatedVertex = triangulations[2][index];
2083 // This isn't a boundary triangulation
2088 // Utility method to compute the minimum quality of a vertex hull
2089 scalar dynamicTopoFvMesh::computeMinQuality
2092 labelList& hullVertices
2095 scalar minQuality = GREAT;
2097 // Obtain a reference to this edge
2098 const edge& edgeToCheck = edges_[eIndex];
2099 const labelList& edgeFaces = edgeFaces_[eIndex];
2101 // If this entity was deleted, skip it.
2102 if (edgeFaces.empty())
2107 // Ensure that edge is surrounded by triangles
2108 forAll(edgeFaces, faceI)
2110 if (faces_[edgeFaces[faceI]].size() != 3)
2116 // Build vertexHull for this edge
2117 buildVertexHull(eIndex, hullVertices);
2119 if (coupledModification_)
2121 if (locallyCoupledEntity(eIndex))
2123 // Compute the minimum quality of the slave edge as well.
2126 // Determine the slave index.
2127 forAll(patchCoupling_, patchI)
2129 if (patchCoupling_(patchI))
2131 const label edgeEnum = coupleMap::EDGE;
2132 const coupleMap& cMap = patchCoupling_[patchI].map();
2134 if ((sIndex = cMap.findSlave(edgeEnum, eIndex)) > -1)
2145 "scalar dynamicTopoFvMesh::computeMinQuality"
2146 "(const label eIndex, labelList& hullVertices) const"
2148 << nl << "Coupled maps were improperly specified." << nl
2149 << " Slave index not found for: " << nl
2150 << " Edge: " << eIndex << nl
2151 << abort(FatalError);
2154 // Build vertexHull for this edge
2155 labelList slaveVertexHull;
2156 buildVertexHull(eIndex, slaveVertexHull);
2158 // Temporarily turn off coupledModification
2159 unsetCoupledModification();
2161 scalar slaveQuality = computeMinQuality(sIndex, slaveVertexHull);
2163 minQuality = Foam::min(slaveQuality, minQuality);
2166 setCoupledModification();
2169 if (processorCoupledEntity(eIndex))
2171 // Don't compute minQuality here, but do it in
2172 // fillTables instead, while calculating hullPoints
2177 // Compute minQuality
2187 (whichEdgePatch(eIndex) < 0)
2193 // Ensure that the mesh is valid
2194 if (minQuality < 0.0)
2196 // Write out faces and cells for post processing.
2197 labelHashSet iFaces, iCells, bFaces;
2199 const labelList& eFaces = edgeFaces_[eIndex];
2201 forAll(eFaces, faceI)
2203 iFaces.insert(eFaces[faceI]);
2205 if (!iCells.found(owner_[eFaces[faceI]]))
2207 iCells.insert(owner_[eFaces[faceI]]);
2210 if (!iCells.found(neighbour_[eFaces[faceI]]))
2212 iCells.insert(neighbour_[eFaces[faceI]]);
2216 writeVTK(Foam::name(eIndex) + "_iCells", iCells.toc());
2217 writeVTK(Foam::name(eIndex) + "_iFaces", iFaces.toc(), 2);
2219 // Write out the boundary patches (for post-processing reference)
2222 label faceI = nOldInternalFaces_;
2223 faceI < faces_.size();
2227 if (faces_[faceI].empty())
2232 label pIndex = whichPatch(faceI);
2236 bFaces.insert(faceI);
2240 writeVTK(Foam::name(eIndex) + "_bFaces", bFaces.toc(), 2);
2244 "scalar dynamicTopoFvMesh::computeMinQuality"
2245 "(const label eIndex, labelList& hullVertices) const"
2247 << "Encountered negative cell-quality!" << nl
2248 << "Edge: " << eIndex << ": " << edgeToCheck << nl
2249 << "vertexHull: " << hullVertices << nl
2250 << "Minimum Quality: " << minQuality
2251 << abort(FatalError);
2258 // Compute minQuality given addressing
2259 scalar dynamicTopoFvMesh::computeMinQuality
2261 const edge& edgeToCheck,
2262 const labelList& hullVertices,
2263 const UList<point>& points,
2267 scalar cQuality = 0.0;
2268 scalar minQuality = GREAT;
2270 // Obtain point references
2271 const point& a = points[edgeToCheck[0]];
2272 const point& c = points[edgeToCheck[1]];
2274 label start = (closedRing ? 0 : 1);
2276 for (label indexJ = start; indexJ < hullVertices.size(); indexJ++)
2278 label indexI = hullVertices.rcIndex(indexJ);
2280 // Pick vertices off the list
2281 const point& b = points[hullVertices[indexI]];
2282 const point& d = points[hullVertices[indexJ]];
2284 // Compute the quality
2285 cQuality = tetMetric_(a, b, c, d);
2287 // Check if the quality is worse
2288 minQuality = Foam::min(cQuality, minQuality);
2295 // Method used to perform a 2-3 swap in 3D
2296 // - Returns a changeMap with a type specifying:
2297 // 1: Swap was successful
2298 // - The index of the triangulated face in map.index()
2299 const changeMap dynamicTopoFvMesh::swap23
2301 const label isolatedVertex,
2303 const label triangulationIndex,
2304 const label numTriangulations,
2305 const labelListList& triangulations,
2306 const labelList& hullVertices,
2307 const labelList& hullFaces,
2308 const labelList& hullCells
2311 // A 2-3 swap performs the following operations:
2312 // [1] Remove face: [ edgeToCheck[0] edgeToCheck[1] isolatedVertex ]
2313 // [2] Remove two cells on either side of removed face
2315 // [4] Add three new faces
2316 // [5] Add three new cells
2317 // Update faceEdges and edgeFaces information
2321 // Obtain a copy of the edge
2322 edge edgeToCheck = edges_[eIndex];
2324 label faceForRemoval = hullFaces[isolatedVertex];
2325 label vertexForRemoval = hullVertices[isolatedVertex];
2327 // Determine the two cells to be removed
2328 FixedList<label,2> cellsForRemoval;
2329 cellsForRemoval[0] = owner_[faceForRemoval];
2330 cellsForRemoval[1] = neighbour_[faceForRemoval];
2334 // Print out arguments
2336 << "== Swapping 2-3 ==" << nl
2337 << "Edge: " << eIndex << ": " << edgeToCheck << endl;
2341 Pout<< " On SubMesh: " << Switch::asText(isSubMesh_) << nl;
2342 Pout<< " coupledModification: " << coupledModification_ << nl;
2344 label bPatch = whichEdgePatch(eIndex);
2346 const polyBoundaryMesh& boundary = boundaryMesh();
2350 Pout<< " Patch: Internal" << nl;
2353 if (bPatch < boundary.size())
2355 Pout<< " Patch: " << boundary[bPatch].name() << nl;
2359 Pout<< " New patch: " << bPatch << endl;
2362 Pout<< " Ring: " << hullVertices << nl
2363 << " Faces: " << hullFaces << nl
2364 << " Cells: " << hullCells << nl
2365 << " Triangulation: "
2366 << triangulations[0][triangulationIndex] << " "
2367 << triangulations[1][triangulationIndex] << " "
2368 << triangulations[2][triangulationIndex] << " "
2370 << " Isolated vertex: " << isolatedVertex << endl;
2378 + '(' + Foam::name(edgeToCheck[0])
2379 + ',' + Foam::name(edgeToCheck[1]) + ')'
2381 + Foam::name(numTriangulations) + "_"
2382 + Foam::name(triangulationIndex),
2389 // Check if this is an internal face
2390 if (cellsForRemoval[1] == -1)
2392 // Write out for post-processing
2393 Pout<< " isolatedVertex: " << isolatedVertex << nl
2394 << " triangulations: " << triangulations << nl
2395 << " numTriangulations: " << numTriangulations << nl
2396 << " triangulationIndex: " << triangulationIndex << endl;
2398 writeVTK("Edge23_" + Foam::name(eIndex), eIndex, 1);
2399 writeVTK("Cells23_" + Foam::name(eIndex), hullCells, 3);
2401 // Write out identify32Swap output for diagnostics
2402 identify32Swap(eIndex, hullVertices, triangulations, true);
2407 "const changeMap dynamicTopoFvMesh::swap23\n"
2409 " const label isolatedVertex,\n"
2410 " const label eIndex,\n"
2411 " const label triangulationIndex,\n"
2412 " const label numTriangulations,\n"
2413 " const labelListList& triangulations,\n"
2414 " const labelList& hullVertices,\n"
2415 " const labelList& hullFaces,\n"
2416 " const labelList& hullCells\n"
2419 << " Expected an internal face,"
2420 << " but found a boundary one instead." << nl
2421 << " Looks like identify32Swap couldn't correctly identify"
2422 << " the 2-2 swap triangulation." << nl
2423 << abort(FatalError);
2426 // Add three new cells to the end of the cell list
2427 FixedList<label,3> newCellIndex(-1);
2428 FixedList<cell, 3> newTetCell(cell(4));
2430 forAll(newCellIndex, cellI)
2432 scalar avgScale = -1.0;
2434 if (edgeRefinement_)
2440 lengthScale_[cellsForRemoval[0]]
2441 + lengthScale_[cellsForRemoval[1]]
2447 newCellIndex[cellI] = insertCell(newTetCell[cellI], avgScale);
2449 // Add this cell to the map.
2450 map.addCell(newCellIndex[cellI]);
2453 // Obtain point-ordering for the other vertices
2454 // otherVertices[0] is the point before isolatedVertex
2455 // otherVertices[1] is the point after isolatedVertex
2456 FixedList<label,2> otherVertices;
2458 if (triangulations[0][triangulationIndex] == isolatedVertex)
2460 otherVertices[0] = hullVertices[triangulations[2][triangulationIndex]];
2461 otherVertices[1] = hullVertices[triangulations[1][triangulationIndex]];
2464 if (triangulations[1][triangulationIndex] == isolatedVertex)
2466 otherVertices[0] = hullVertices[triangulations[0][triangulationIndex]];
2467 otherVertices[1] = hullVertices[triangulations[2][triangulationIndex]];
2471 otherVertices[0] = hullVertices[triangulations[1][triangulationIndex]];
2472 otherVertices[1] = hullVertices[triangulations[0][triangulationIndex]];
2475 // Insert three new internal faces
2476 FixedList<label,3> newFaceIndex;
2479 // First face: The actual triangulation
2480 tmpTriFace[0] = otherVertices[0];
2481 tmpTriFace[1] = vertexForRemoval;
2482 tmpTriFace[2] = otherVertices[1];
2495 // Add this face to the map.
2496 map.addFace(newFaceIndex[0]);
2498 // Note the triangulation face in index()
2499 map.index() = newFaceIndex[0];
2501 // Second face: Triangle involving edgeToCheck[0]
2502 tmpTriFace[0] = otherVertices[0];
2503 tmpTriFace[1] = edgeToCheck[0];
2504 tmpTriFace[2] = otherVertices[1];
2517 // Add this face to the map.
2518 map.addFace(newFaceIndex[1]);
2520 // Third face: Triangle involving edgeToCheck[1]
2521 tmpTriFace[0] = otherVertices[1];
2522 tmpTriFace[1] = edgeToCheck[1];
2523 tmpTriFace[2] = otherVertices[0];
2536 // Add this face to the map.
2537 map.addFace(newFaceIndex[2]);
2539 // Append three dummy faceEdges entries.
2540 for (label i = 0; i < 3; i++)
2542 faceEdges_.append(labelList(0));
2545 // Add an entry to edgeFaces
2546 labelList newEdgeFaces(3);
2547 newEdgeFaces[0] = newFaceIndex[0];
2548 newEdgeFaces[1] = newFaceIndex[1];
2549 newEdgeFaces[2] = newFaceIndex[2];
2551 // Add a new internal edge to the mesh
2552 label newEdgeIndex =
2566 // Add this edge to the map.
2567 map.addEdge(newEdgeIndex);
2569 // Define the six edges to check while building faceEdges:
2570 FixedList<edge,6> check;
2572 check[0][0] = vertexForRemoval; check[0][1] = otherVertices[0];
2573 check[1][0] = vertexForRemoval; check[1][1] = otherVertices[1];
2574 check[2][0] = edgeToCheck[0]; check[2][1] = otherVertices[0];
2575 check[3][0] = edgeToCheck[1]; check[3][1] = otherVertices[0];
2576 check[4][0] = edgeToCheck[0]; check[4][1] = otherVertices[1];
2577 check[5][0] = edgeToCheck[1]; check[5][1] = otherVertices[1];
2579 // Add three new entries to faceEdges
2580 label nE0 = 0, nE1 = 0, nE2 = 0;
2581 FixedList<labelList,3> newFaceEdges(labelList(3));
2583 newFaceEdges[0][nE0++] = newEdgeIndex;
2584 newFaceEdges[1][nE1++] = newEdgeIndex;
2585 newFaceEdges[2][nE2++] = newEdgeIndex;
2587 // Fill-in information for the three new cells,
2588 // and correct info on existing neighbouring cells
2589 label nF0 = 0, nF1 = 0, nF2 = 0;
2590 FixedList<bool,2> foundEdge;
2592 // Add the newly created faces to cells
2593 newTetCell[0][nF0++] = newFaceIndex[0];
2594 newTetCell[0][nF0++] = newFaceIndex[2];
2595 newTetCell[1][nF1++] = newFaceIndex[0];
2596 newTetCell[1][nF1++] = newFaceIndex[1];
2597 newTetCell[2][nF2++] = newFaceIndex[1];
2598 newTetCell[2][nF2++] = newFaceIndex[2];
2600 forAll(cellsForRemoval, cellI)
2602 label cellIndex = cellsForRemoval[cellI];
2604 forAll(cells_[cellIndex], faceI)
2606 label faceIndex = cells_[cellIndex][faceI];
2608 foundEdge[0] = false; foundEdge[1] = false;
2610 // Check if face contains edgeToCheck[0]
2613 (faces_[faceIndex][0] == edgeToCheck[0])
2614 || (faces_[faceIndex][1] == edgeToCheck[0])
2615 || (faces_[faceIndex][2] == edgeToCheck[0])
2618 foundEdge[0] = true;
2621 // Check if face contains edgeToCheck[1]
2624 (faces_[faceIndex][0] == edgeToCheck[1])
2625 || (faces_[faceIndex][1] == edgeToCheck[1])
2626 || (faces_[faceIndex][2] == edgeToCheck[1])
2629 foundEdge[1] = true;
2632 // Face is connected to edgeToCheck[0]
2633 if (foundEdge[0] && !foundEdge[1])
2635 // Check if a face-flip is necessary
2636 if (owner_[faceIndex] == cellIndex)
2638 if (neighbour_[faceIndex] == -1)
2641 owner_[faceIndex] = newCellIndex[1];
2646 faces_[faceIndex] = faces_[faceIndex].reverseFace();
2647 owner_[faceIndex] = neighbour_[faceIndex];
2648 neighbour_[faceIndex] = newCellIndex[1];
2655 // Flip is unnecessary. Just update neighbour
2656 neighbour_[faceIndex] = newCellIndex[1];
2659 // Add this face to the cell
2660 newTetCell[1][nF1++] = faceIndex;
2662 // Update faceEdges and edgeFaces
2663 forAll(faceEdges_[faceIndex], edgeI)
2665 if (edges_[faceEdges_[faceIndex][edgeI]] == check[0])
2667 newFaceEdges[0][nE0++] = faceEdges_[faceIndex][edgeI];
2672 edgeFaces_[faceEdges_[faceIndex][edgeI]]
2676 if (edges_[faceEdges_[faceIndex][edgeI]] == check[1])
2678 newFaceEdges[0][nE0++] = faceEdges_[faceIndex][edgeI];
2683 edgeFaces_[faceEdges_[faceIndex][edgeI]]
2687 if (edges_[faceEdges_[faceIndex][edgeI]] == check[2])
2689 newFaceEdges[1][nE1++] = faceEdges_[faceIndex][edgeI];
2694 edgeFaces_[faceEdges_[faceIndex][edgeI]]
2698 if (edges_[faceEdges_[faceIndex][edgeI]] == check[4])
2700 newFaceEdges[1][nE1++] = faceEdges_[faceIndex][edgeI];
2705 edgeFaces_[faceEdges_[faceIndex][edgeI]]
2711 // Face is connected to edgeToCheck[1]
2712 if (!foundEdge[0] && foundEdge[1])
2714 // Check if a face-flip is necessary
2715 if (owner_[faceIndex] == cellIndex)
2717 if (neighbour_[faceIndex] == -1)
2720 owner_[faceIndex] = newCellIndex[0];
2725 faces_[faceIndex] = faces_[faceIndex].reverseFace();
2726 owner_[faceIndex] = neighbour_[faceIndex];
2727 neighbour_[faceIndex] = newCellIndex[0];
2734 // Flip is unnecessary. Just update neighbour
2735 neighbour_[faceIndex] = newCellIndex[0];
2738 // Add this face to the cell
2739 newTetCell[0][nF0++] = faceIndex;
2741 // Update faceEdges and edgeFaces
2742 const labelList& fEdges = faceEdges_[faceIndex];
2744 forAll(fEdges, edgeI)
2746 if (edges_[fEdges[edgeI]] == check[3])
2748 newFaceEdges[2][nE2++] = fEdges[edgeI];
2753 edgeFaces_[fEdges[edgeI]]
2757 if (edges_[fEdges[edgeI]] == check[5])
2759 newFaceEdges[2][nE2++] = fEdges[edgeI];
2764 edgeFaces_[fEdges[edgeI]]
2770 // Face is connected to both edgeToCheck [0] and [1]
2773 (foundEdge[0] && foundEdge[1]) &&
2774 (faceIndex != faceForRemoval)
2777 // Check if a face-flip is necessary
2778 if (owner_[faceIndex] == cellIndex)
2780 if (neighbour_[faceIndex] == -1)
2783 owner_[faceIndex] = newCellIndex[2];
2788 faces_[faceIndex] = faces_[faceIndex].reverseFace();
2789 owner_[faceIndex] = neighbour_[faceIndex];
2790 neighbour_[faceIndex] = newCellIndex[2];
2797 // Flip is unnecessary. Just update neighbour
2798 neighbour_[faceIndex] = newCellIndex[2];
2801 // Add this face to the cell
2802 newTetCell[2][nF2++] = faceIndex;
2807 // Now update faceEdges for the three new faces
2808 forAll(newFaceEdges, faceI)
2810 faceEdges_[newFaceIndex[faceI]] = newFaceEdges[faceI];
2813 // Update edgeFaces for edges of the removed face
2814 forAll(faceEdges_[faceForRemoval], edgeI)
2816 label edgeIndex = faceEdges_[faceForRemoval][edgeI];
2818 meshOps::sizeDownList
2821 edgeFaces_[edgeIndex]
2826 removeFace(faceForRemoval);
2829 map.removeFace(faceForRemoval);
2831 forAll(cellsForRemoval, cellI)
2833 removeCell(cellsForRemoval[cellI]);
2836 map.removeCell(cellsForRemoval[cellI]);
2839 // Update the cell list with newly configured cells.
2840 forAll(newCellIndex, cellI)
2842 cells_[newCellIndex[cellI]] = newTetCell[cellI];
2846 // Skip mapping for the intermediate cell.
2847 setCellMapping(newCellIndex[cellI], hullCells, false);
2851 // Set the mapping for this cell
2852 setCellMapping(newCellIndex[cellI], hullCells);
2856 // Fill in mapping information for three new faces.
2857 // Since they're all internal, interpolate fluxes by default.
2858 forAll(newFaceIndex, faceI)
2860 setFaceMapping(newFaceIndex[faceI]);
2865 Pout<< "Added edge: " << nl;
2867 Pout<< newEdgeIndex << ":: "
2868 << edges_[newEdgeIndex]
2870 << edgeFaces_[newEdgeIndex]
2873 Pout<< "Added faces: " << nl;
2875 forAll(newFaceIndex, faceI)
2877 Pout<< newFaceIndex[faceI] << ":: "
2878 << faces_[newFaceIndex[faceI]]
2880 << faceEdges_[newFaceIndex[faceI]]
2884 Pout<< "Added cells: " << nl;
2886 forAll(newCellIndex, cellI)
2888 Pout<< newCellIndex[cellI] << ":: "
2889 << cells_[newCellIndex[cellI]]
2900 + '(' + Foam::name(edgeToCheck[0])
2901 + ',' + Foam::name(edgeToCheck[1]) + ')'
2903 + Foam::name(numTriangulations) + "_"
2904 + Foam::name(triangulationIndex),
2911 // Specify that the swap was successful
2914 // Return the changeMap
2919 // Method used to perform a 2-2 / 3-2 swap in 3D
2920 // - Returns a changeMap with a type specifying:
2921 // 1: Swap was successful
2922 // - The index of the triangulated face in map.index()
2923 const changeMap dynamicTopoFvMesh::swap32
2926 const label triangulationIndex,
2927 const label numTriangulations,
2928 const labelListList& triangulations,
2929 const labelList& hullVertices,
2930 const labelList& hullFaces,
2931 const labelList& hullCells
2934 // A 2-2 / 3-2 swap performs the following operations:
2935 // [1] Remove three faces surrounding edgeToCheck
2936 // [2] Remove two (2-2 swap) or three(3-2 swap)
2937 // cells surrounding edgeToCheck
2938 // [3] Add one internal face
2939 // [4] Add two new cells
2940 // [5] If edgeToCheck is on a boundary,
2941 // add two boundary faces and a boundary edge (2-2 swap)
2942 // eIndex is removed later by removeEdgeFlips
2943 // Update faceEdges and edgeFaces information
2947 // Obtain a copy of the edge
2948 edge edgeToCheck = edges_[eIndex];
2950 // Determine the patch this edge belongs to
2951 label edgePatch = whichEdgePatch(eIndex);
2953 // Determine the three faces to be removed
2954 FixedList<label,3> facesForRemoval;
2955 DynamicList<label> cellRemovalList(3);
2957 forAll(facesForRemoval, faceI)
2959 facesForRemoval[faceI] =
2961 hullFaces[triangulations[faceI][triangulationIndex]]
2964 label own = owner_[facesForRemoval[faceI]];
2965 label nei = neighbour_[facesForRemoval[faceI]];
2967 // Check and add cells as well
2968 if (findIndex(cellRemovalList, own) == -1)
2970 cellRemovalList.append(own);
2975 if (findIndex(cellRemovalList, nei) == -1)
2977 cellRemovalList.append(nei);
2984 // Print out arguments
2989 Pout<< "== Swapping 3-2 ==" << nl;
2993 Pout<< "== Swapping 2-2 ==" << nl;
2996 Pout<< " Edge: " << eIndex << ": " << edgeToCheck << endl;
3000 Pout<< " On SubMesh: " << Switch::asText(isSubMesh_) << nl;
3001 Pout<< " coupledModification: " << coupledModification_ << nl;
3003 label bPatch = whichEdgePatch(eIndex);
3005 const polyBoundaryMesh& boundary = boundaryMesh();
3009 Pout<< " Patch: Internal" << nl;
3012 if (bPatch < boundary.size())
3014 Pout<< " Patch: " << boundary[bPatch].name() << nl;
3018 Pout<< " New patch: " << bPatch << endl;
3021 Pout<< " Ring: " << hullVertices << nl
3022 << " Faces: " << hullFaces << nl
3023 << " Cells: " << hullCells << nl
3024 << " Triangulation: "
3025 << triangulations[0][triangulationIndex] << " "
3026 << triangulations[1][triangulationIndex] << " "
3027 << triangulations[2][triangulationIndex] << " "
3036 + '(' + Foam::name(edgeToCheck[0])
3037 + ',' + Foam::name(edgeToCheck[1]) + ')'
3039 + Foam::name(numTriangulations) + "_"
3040 + Foam::name(triangulationIndex),
3047 // Add two new cells to the end of the cell list
3048 FixedList<label,2> newCellIndex(-1);
3049 FixedList<cell, 2> newTetCell(cell(4));
3051 forAll(newCellIndex, cellI)
3053 scalar avgScale = 0.0;
3055 if (edgeRefinement_)
3057 forAll(cellRemovalList, indexI)
3059 avgScale += lengthScale_[cellRemovalList[indexI]];
3062 avgScale /= cellRemovalList.size();
3066 newCellIndex[cellI] = insertCell(newTetCell[cellI], avgScale);
3068 // Add this cell to the map.
3069 map.addCell(newCellIndex[cellI]);
3072 // Insert a new internal face
3075 newTriFace[0] = hullVertices[triangulations[0][triangulationIndex]];
3076 newTriFace[1] = hullVertices[triangulations[1][triangulationIndex]];
3077 newTriFace[2] = hullVertices[triangulations[2][triangulationIndex]];
3079 label newFaceIndex =
3090 // Add this face to the map.
3091 map.addFace(newFaceIndex);
3093 // Note the triangulation face in index()
3094 map.index() = newFaceIndex;
3096 // Add faceEdges for the new face as well.
3097 faceEdges_.append(labelList(3));
3099 // Define the three edges to check while building faceEdges:
3100 FixedList<edge,3> check;
3102 check[0][0] = newTriFace[0]; check[0][1] = newTriFace[1];
3103 check[1][0] = newTriFace[1]; check[1][1] = newTriFace[2];
3104 check[2][0] = newTriFace[2]; check[2][1] = newTriFace[0];
3106 // For 2-2 swaps, two faces are introduced
3107 label nE = 0, nBf = 0;
3108 FixedList<label,2> nBE(0);
3109 FixedList<labelList,2> bdyFaceEdges(labelList(3, -1));
3111 // Fill-in information for the two new cells,
3112 // and correct info on existing neighbouring cells
3113 label nF0 = 0, nF1 = 0;
3114 label otherPoint = -1, nextPoint = -1;
3115 FixedList<bool,2> foundEdge;
3117 // For a 2-2 swap on a boundary edge,
3118 // add two boundary faces and an edge
3119 label newEdgeIndex = -1;
3120 labelList oldBdyFaceIndex(2, -1), newBdyFaceIndex(2, -1);
3124 // Temporary local variables
3125 label facePatch = -1;
3126 edge newEdge(-1, -1);
3127 FixedList<label,2> nBEdge(0);
3128 FixedList<FixedList<label,2>,2> bdyEdges;
3129 FixedList<face,2> newBdyTriFace(face(3));
3131 // Get a cue for face orientation from existing faces
3132 forAll(facesForRemoval, faceI)
3134 if (neighbour_[facesForRemoval[faceI]] == -1)
3136 facePatch = whichPatch(facesForRemoval[faceI]);
3138 // Record this face-index for mapping.
3139 oldBdyFaceIndex[nBf++] = facesForRemoval[faceI];
3141 meshOps::findIsolatedPoint
3143 faces_[facesForRemoval[faceI]],
3149 if (nextPoint == edgeToCheck[0])
3151 newEdge[1] = otherPoint;
3152 newBdyTriFace[0][0] = otherPoint;
3153 newBdyTriFace[0][1] = edgeToCheck[0];
3154 newBdyTriFace[1][2] = otherPoint;
3158 newEdge[0] = otherPoint;
3159 newBdyTriFace[1][0] = otherPoint;
3160 newBdyTriFace[1][1] = edgeToCheck[1];
3161 newBdyTriFace[0][2] = otherPoint;
3164 // Also update faceEdges for the new boundary faces
3165 forAll(faceEdges_[facesForRemoval[faceI]], edgeI)
3169 edges_[faceEdges_[facesForRemoval[faceI]][edgeI]]
3170 == edge(edgeToCheck[0], otherPoint)
3173 bdyFaceEdges[0][nBE[0]++] =
3175 faceEdges_[facesForRemoval[faceI]][edgeI]
3178 bdyEdges[0][nBEdge[0]++] =
3180 faceEdges_[facesForRemoval[faceI]][edgeI]
3186 edges_[faceEdges_[facesForRemoval[faceI]][edgeI]]
3187 == edge(edgeToCheck[1], otherPoint)
3190 bdyFaceEdges[1][nBE[1]++] =
3192 faceEdges_[facesForRemoval[faceI]][edgeI]
3195 bdyEdges[1][nBEdge[1]++] =
3197 faceEdges_[facesForRemoval[faceI]][edgeI]
3204 // Insert the first of two new faces
3205 newBdyFaceIndex[0] =
3216 // Add this face to the map.
3217 map.addFace(newBdyFaceIndex[0]);
3219 // Insert the second of two new faces
3220 newBdyFaceIndex[1] =
3231 // Add this face to the map.
3232 map.addFace(newBdyFaceIndex[1]);
3234 // Update the new cells
3235 newTetCell[0][nF0++] = newBdyFaceIndex[1];
3236 newTetCell[1][nF1++] = newBdyFaceIndex[0];
3238 // Add an edgeFaces entry
3239 labelList newBdyEdgeFaces(3, -1);
3240 newBdyEdgeFaces[0] = newBdyFaceIndex[0];
3241 newBdyEdgeFaces[1] = newFaceIndex;
3242 newBdyEdgeFaces[2] = newBdyFaceIndex[1];
3244 // Find the point other than the new edge
3245 // on the new triangular face
3246 meshOps::findIsolatedPoint
3265 // Add this edge to the map.
3266 map.addEdge(newEdgeIndex);
3268 // Update faceEdges with the new edge
3269 faceEdges_[newFaceIndex][nE++] = newEdgeIndex;
3270 bdyFaceEdges[0][nBE[0]++] = newEdgeIndex;
3271 bdyFaceEdges[1][nBE[1]++] = newEdgeIndex;
3273 // Update edgeFaces with the two new faces
3274 forAll(bdyEdges[0], edgeI)
3279 edgeFaces_[bdyEdges[0][edgeI]]
3285 edgeFaces_[bdyEdges[1][edgeI]]
3289 // Add faceEdges for the two new boundary faces
3290 faceEdges_.append(bdyFaceEdges[0]);
3291 faceEdges_.append(bdyFaceEdges[1]);
3293 // Update the number of surface swaps.
3297 newTetCell[0][nF0++] = newFaceIndex;
3298 newTetCell[1][nF1++] = newFaceIndex;
3300 forAll(cellRemovalList, cellI)
3302 label cellIndex = cellRemovalList[cellI];
3304 forAll(cells_[cellIndex], faceI)
3306 label faceIndex = cells_[cellIndex][faceI];
3308 foundEdge[0] = false; foundEdge[1] = false;
3310 // Find the face that contains only
3311 // edgeToCheck[0] or edgeToCheck[1]
3312 forAll(faces_[faceIndex], pointI)
3314 if (faces_[faceIndex][pointI] == edgeToCheck[0])
3316 foundEdge[0] = true;
3319 if (faces_[faceIndex][pointI] == edgeToCheck[1])
3321 foundEdge[1] = true;
3325 // Face is connected to edgeToCheck[0]
3326 if (foundEdge[0] && !foundEdge[1])
3328 // Check if a face-flip is necessary
3329 if (owner_[faceIndex] == cellIndex)
3331 if (neighbour_[faceIndex] == -1)
3334 owner_[faceIndex] = newCellIndex[1];
3339 faces_[faceIndex] = faces_[faceIndex].reverseFace();
3340 owner_[faceIndex] = neighbour_[faceIndex];
3341 neighbour_[faceIndex] = newCellIndex[1];
3348 // Flip is unnecessary. Just update neighbour
3349 neighbour_[faceIndex] = newCellIndex[1];
3352 // Add this face to the cell
3353 newTetCell[1][nF1++] = faceIndex;
3355 // Update faceEdges and edgeFaces
3356 forAll(faceEdges_[faceIndex], edgeI)
3360 (edges_[faceEdges_[faceIndex][edgeI]] == check[0])
3361 || (edges_[faceEdges_[faceIndex][edgeI]] == check[1])
3362 || (edges_[faceEdges_[faceIndex][edgeI]] == check[2])
3365 faceEdges_[newFaceIndex][nE++] =
3367 faceEdges_[faceIndex][edgeI]
3373 edgeFaces_[faceEdges_[faceIndex][edgeI]]
3381 // Face is connected to edgeToCheck[1]
3382 if (!foundEdge[0] && foundEdge[1])
3384 // Check if a face-flip is necessary
3385 if (owner_[faceIndex] == cellIndex)
3387 if (neighbour_[faceIndex] == -1)
3390 owner_[faceIndex] = newCellIndex[0];
3395 faces_[faceIndex] = faces_[faceIndex].reverseFace();
3396 owner_[faceIndex] = neighbour_[faceIndex];
3397 neighbour_[faceIndex] = newCellIndex[0];
3404 // Flip is unnecessary. Just update neighbour
3405 neighbour_[faceIndex] = newCellIndex[0];
3408 // Add this face to the cell
3409 newTetCell[0][nF0++] = faceIndex;
3414 // Remove the faces and update associated edges
3415 forAll(facesForRemoval, faceI)
3418 forAll(faceEdges_[facesForRemoval[faceI]], edgeI)
3420 label edgeIndex = faceEdges_[facesForRemoval[faceI]][edgeI];
3422 if (edgeIndex != eIndex)
3424 meshOps::sizeDownList
3426 facesForRemoval[faceI],
3427 edgeFaces_[edgeIndex]
3432 // Now remove the face...
3433 removeFace(facesForRemoval[faceI]);
3436 map.removeFace(facesForRemoval[faceI]);
3439 forAll(cellRemovalList, cellI)
3441 removeCell(cellRemovalList[cellI]);
3444 map.removeCell(cellRemovalList[cellI]);
3447 // Update the cell list with newly configured cells.
3448 forAll(newCellIndex, cellI)
3450 cells_[newCellIndex[cellI]] = newTetCell[cellI];
3452 // Set the mapping for this cell
3453 setCellMapping(newCellIndex[cellI], hullCells);
3456 // Set fill-in mapping for two new boundary faces
3459 forAll(newBdyFaceIndex, i)
3461 // Set the mapping for this face
3462 setFaceMapping(newBdyFaceIndex[i], oldBdyFaceIndex);
3466 // Fill in mapping information for the new face.
3467 // Since it is internal, interpolate fluxes by default.
3468 setFaceMapping(newFaceIndex);
3474 Pout<< "Added edge: "
3475 << newEdgeIndex << ":: "
3476 << edges_[newEdgeIndex]
3478 << edgeFaces_[newEdgeIndex]
3482 Pout<< "Added face(s): " << nl;
3484 Pout<< newFaceIndex << ":: "
3485 << faces_[newFaceIndex];
3487 Pout<< " faceEdges: "
3488 << faceEdges_[newFaceIndex]
3493 forAll(newBdyFaceIndex, faceI)
3495 Pout<< newBdyFaceIndex[faceI] << ":: "
3496 << faces_[newBdyFaceIndex[faceI]]
3498 << faceEdges_[newBdyFaceIndex[faceI]]
3503 Pout<< "Added cells: " << nl;
3505 forAll(newCellIndex, cellI)
3507 Pout<< newCellIndex[cellI] << ":: "
3508 << cells_[newCellIndex[cellI]]
3519 + '(' + Foam::name(edgeToCheck[0])
3520 + ',' + Foam::name(edgeToCheck[1]) + ')'
3522 + Foam::name(numTriangulations) + "_"
3523 + Foam::name(triangulationIndex),
3530 // Specify that the swap was successful
3533 // Return the changeMap
3537 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3539 } // End namespace Foam
3541 // ************************************************************************* //