1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "meshCutter.H"
28 #include "polyTopoChange.H"
30 #include "mapPolyMesh.H"
31 #include "meshTools.H"
32 #include "polyModifyFace.H"
33 #include "polyAddPoint.H"
34 #include "polyAddFace.H"
35 #include "polyAddCell.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(Foam::meshCutter, 0);
42 // * * * * * * * * * * * * * Private Static Functions * * * * * * * * * * * //
44 // Returns true if lst1 and lst2 share elements
45 bool Foam::meshCutter::uses(const labelList& elems1, const labelList& elems2)
49 if (findIndex(elems2, elems1[elemI]) != -1)
58 // Check if twoCuts at two consecutive position in cuts.
59 bool Foam::meshCutter::isIn
65 label index = findIndex(cuts, twoCuts[0]);
74 cuts[cuts.fcIndex(index)] == twoCuts[1]
75 || cuts[cuts.rcIndex(index)] == twoCuts[1]
80 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
82 // Returns the cell in cellLabels that is cut. Or -1.
83 Foam::label Foam::meshCutter::findCutCell
86 const labelList& cellLabels
89 forAll(cellLabels, labelI)
91 label cellI = cellLabels[labelI];
93 if (cuts.cellLoops()[cellI].size())
102 //- Returns first pointI in pointLabels that uses an internal
103 // face. Used to find point to inflate cell/face from (has to be
104 // connected to internal face). Returns -1 (so inflate from nothing) if
106 Foam::label Foam::meshCutter::findInternalFacePoint
108 const labelList& pointLabels
111 forAll(pointLabels, labelI)
113 label pointI = pointLabels[labelI];
115 const labelList& pFaces = mesh().pointFaces()[pointI];
117 forAll(pFaces, pFaceI)
119 label faceI = pFaces[pFaceI];
121 if (mesh().isInternalFace(faceI))
128 if (pointLabels.empty())
130 FatalErrorIn("meshCutter::findInternalFacePoint(const labelList&)")
131 << "Empty pointLabels" << abort(FatalError);
138 // Get new owner and neighbour of face. Checks anchor points to see if
139 // need to get original or added cell.
140 void Foam::meshCutter::faceCells
142 const cellCuts& cuts,
148 const labelListList& anchorPts = cuts.cellAnchorPoints();
149 const labelListList& cellLoops = cuts.cellLoops();
151 const face& f = mesh().faces()[faceI];
153 own = mesh().faceOwner()[faceI];
155 if (cellLoops[own].size() && uses(f, anchorPts[own]))
157 own = addedCells_[own];
162 if (mesh().isInternalFace(faceI))
164 nei = mesh().faceNeighbour()[faceI];
166 if (cellLoops[nei].size() && uses(f, anchorPts[nei]))
168 nei = addedCells_[nei];
174 void Foam::meshCutter::getFaceInfo
184 if (!mesh().isInternalFace(faceI))
186 patchID = mesh().boundaryMesh().whichPatch(faceI);
189 zoneID = mesh().faceZones().whichZone(faceI);
195 const faceZone& fZone = mesh().faceZones()[zoneID];
197 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
202 // Adds a face on top of existing faceI.
203 void Foam::meshCutter::addFace
205 polyTopoChange& meshMod,
212 label patchID, zoneID, zoneFlip;
214 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
216 if ((nei == -1) || (own < nei))
221 Pout<< "Adding face " << newFace
222 << " with new owner:" << own
223 << " with new neighbour:" << nei
224 << " patchID:" << patchID
225 << " zoneID:" << zoneID
226 << " zoneFlip:" << zoneFlip
239 faceI, // master face for addition
241 patchID, // patch for face
242 zoneID, // zone for face
243 zoneFlip // face zone flip
249 // Reverse owner/neighbour
252 Pout<< "Adding (reversed) face " << newFace.reverseFace()
253 << " with new owner:" << nei
254 << " with new neighbour:" << own
255 << " patchID:" << patchID
256 << " zoneID:" << zoneID
257 << " zoneFlip:" << zoneFlip
265 newFace.reverseFace(), // face
270 faceI, // master face for addition
272 patchID, // patch for face
273 zoneID, // zone for face
274 zoneFlip // face zone flip
281 // Modifies existing faceI for either new owner/neighbour or new face points.
282 void Foam::meshCutter::modFace
284 polyTopoChange& meshMod,
291 label patchID, zoneID, zoneFlip;
293 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
297 (own != mesh().faceOwner()[faceI])
299 mesh().isInternalFace(faceI)
300 && (nei != mesh().faceNeighbour()[faceI])
302 || (newFace != mesh().faces()[faceI])
307 Pout<< "Modifying face " << faceI
308 << " old vertices:" << mesh().faces()[faceI]
309 << " new vertices:" << newFace
310 << " new owner:" << own
311 << " new neighbour:" << nei
312 << " new zoneID:" << zoneID
313 << " new zoneFlip:" << zoneFlip
317 if ((nei == -1) || (own < nei))
323 newFace, // modified face
324 faceI, // label of face being modified
328 patchID, // patch for face
329 false, // remove from zone
330 zoneID, // zone for face
331 zoneFlip // face flip in zone
341 newFace.reverseFace(), // modified face
342 faceI, // label of face being modified
346 patchID, // patch for face
347 false, // remove from zone
348 zoneID, // zone for face
349 zoneFlip // face flip in zone
357 // Copies face starting from startFp up to and including endFp.
358 void Foam::meshCutter::copyFace
372 newFace[newFp++] = f[fp];
374 fp = (fp + 1) % f.size();
376 newFace[newFp] = f[fp];
380 // Actually split face in two along splitEdge v0, v1 (the two vertices in new
381 // vertex numbering). Generates faces in same ordering
382 // as original face. Replaces cutEdges by the points introduced on them
384 void Foam::meshCutter::splitFace
394 // Check if we find any new vertex which is part of the splitEdge.
395 label startFp = findIndex(f, v0);
401 "meshCutter::splitFace"
402 ", const face&, const label, const label, face&, face&)"
403 ) << "Cannot find vertex (new numbering) " << v0
405 << abort(FatalError);
408 label endFp = findIndex(f, v1);
414 "meshCutter::splitFace("
415 ", const face&, const label, const label, face&, face&)"
416 ) << "Cannot find vertex (new numbering) " << v1
418 << abort(FatalError);
422 f0.setSize((endFp + 1 + f.size() - startFp) % f.size());
423 f1.setSize(f.size() - f0.size() + 2);
425 copyFace(f, startFp, endFp, f0);
426 copyFace(f, endFp, startFp, f1);
430 // Adds additional vertices (from edge cutting) to face. Used for faces which
431 // are not split but still might use edge that has been cut.
432 Foam::face Foam::meshCutter::addEdgeCutsToFace(const label faceI) const
434 const face& f = mesh().faces()[faceI];
436 face newFace(2 * f.size());
442 // Duplicate face vertex .
443 newFace[newFp++] = f[fp];
445 // Check if edge has been cut.
446 label fp1 = f.fcIndex(fp);
448 HashTable<label, edge, Hash<edge> >::const_iterator fnd =
449 addedPoints_.find(edge(f[fp], f[fp1]));
451 if (fnd != addedPoints_.end())
453 // edge has been cut. Introduce new vertex.
454 newFace[newFp++] = fnd();
458 newFace.setSize(newFp);
464 // Walk loop (loop of cuts) across circumference of cellI. Returns face in
466 // Note: tricky bit is that it can use existing edges which have been split.
467 Foam::face Foam::meshCutter::loopToFace
470 const labelList& loop
473 face newFace(2*loop.size());
479 label cut = loop[fp];
483 label edgeI = getEdge(cut);
485 const edge& e = mesh().edges()[edgeI];
487 label vertI = addedPoints_[e];
489 newFace[newFaceI++] = vertI;
494 label vertI = getVertex(cut);
496 newFace[newFaceI++] = vertI;
498 label nextCut = loop[loop.fcIndex(fp)];
500 if (!isEdge(nextCut))
502 // From vertex to vertex -> cross cut only if no existing edge.
503 label nextVertI = getVertex(nextCut);
505 label edgeI = meshTools::findEdge(mesh(), vertI, nextVertI);
509 // Existing edge. Insert split-edge point if any.
510 HashTable<label, edge, Hash<edge> >::const_iterator fnd =
511 addedPoints_.find(mesh().edges()[edgeI]);
513 if (fnd != addedPoints_.end())
515 newFace[newFaceI++] = fnd();
521 newFace.setSize(newFaceI);
527 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
529 // Construct from components
530 Foam::meshCutter::meshCutter(const polyMesh& mesh)
540 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
542 Foam::meshCutter::~meshCutter()
546 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
548 void Foam::meshCutter::setRefinement
550 const cellCuts& cuts,
551 polyTopoChange& meshMod
554 // Clear and size maps here since mesh size will change.
556 addedCells_.resize(cuts.nLoops());
559 addedFaces_.resize(cuts.nLoops());
561 addedPoints_.clear();
562 addedPoints_.resize(cuts.nLoops());
564 if (cuts.nLoops() == 0)
569 const labelListList& anchorPts = cuts.cellAnchorPoints();
570 const labelListList& cellLoops = cuts.cellLoops();
573 // Add new points along cut edges.
576 forAll(cuts.edgeIsCut(), edgeI)
578 if (cuts.edgeIsCut()[edgeI])
580 const edge& e = mesh().edges()[edgeI];
582 // Check if there is any cell using this edge.
583 if (debug && findCutCell(cuts, mesh().edgeCells()[edgeI]) == -1)
587 "meshCutter::setRefinement(const cellCuts&"
589 ) << "Problem: cut edge but none of the cells using it is\n"
590 << "edge:" << edgeI << " verts:" << e
591 << abort(FatalError);
594 // One of the edge end points should be master point of nbCellI.
595 label masterPointI = e.start();
597 const point& v0 = mesh().points()[e.start()];
598 const point& v1 = mesh().points()[e.end()];
600 scalar weight = cuts.edgeWeight()[edgeI];
602 point newPt = weight*v1 + (1.0-weight)*v0;
610 masterPointI, // master point
611 -1, // zone for point
612 true // supports a cell
616 // Store on (hash of) edge.
617 addedPoints_.insert(e, addedPointI);
621 Pout<< "Added point " << addedPointI
623 << masterPointI << " of edge " << edgeI
624 << " vertices " << e << endl;
630 // Add cells (on 'anchor' side of cell)
633 forAll(cellLoops, cellI)
635 if (cellLoops[cellI].size())
637 // Add a cell to the existing cell
646 cellI, // master cell
651 addedCells_.insert(cellI, addedCellI);
655 Pout<< "Added cell " << addedCells_[cellI] << " to cell "
663 // For all cut cells add an internal face
666 forAll(cellLoops, cellI)
668 const labelList& loop = cellLoops[cellI];
673 // Convert loop (=list of cuts) into proper face.
674 // Orientation should already be ok. (done by cellCuts)
676 face newFace(loopToFace(cellI, loop));
678 // Pick any anchor point on cell
679 label masterPointI = findInternalFacePoint(anchorPts[cellI]);
688 addedCells_[cellI], // neighbour
689 masterPointI, // master point
691 -1, // master face for addition
693 -1, // patch for face
695 false // face zone flip
699 addedFaces_.insert(cellI, addedFaceI);
703 // Gets edgeweights of loop
704 scalarField weights(loop.size());
712 ? cuts.edgeWeight()[getEdge(cut)]
717 Pout<< "Added splitting face " << newFace << " index:"
719 << " to owner " << cellI
720 << " neighbour " << addedCells_[cellI]
722 writeCuts(Pout, loop, weights);
730 // Modify faces on the outside and create new ones
731 // (in effect split old faces into two)
734 // Maintain whether face has been updated (for -split edges
735 // -new owner/neighbour)
736 boolList faceUptodate(mesh().nFaces(), false);
738 const Map<edge>& faceSplitCuts = cuts.faceSplitCut();
740 forAllConstIter(Map<edge>, faceSplitCuts, iter)
742 label faceI = iter.key();
744 // Renumber face to include split edges.
745 face newFace(addEdgeCutsToFace(faceI));
747 // Edge splitting the face. Convert cuts to new vertex numbering.
748 const edge& splitEdge = iter();
750 label cut0 = splitEdge[0];
755 label edgeI = getEdge(cut0);
756 v0 = addedPoints_[mesh().edges()[edgeI]];
760 v0 = getVertex(cut0);
763 label cut1 = splitEdge[1];
767 label edgeI = getEdge(cut1);
768 v1 = addedPoints_[mesh().edges()[edgeI]];
772 v1 = getVertex(cut1);
775 // Split face along the elements of the splitEdge.
777 splitFace(newFace, v0, v1, f0, f1);
779 label own = mesh().faceOwner()[faceI];
783 if (mesh().isInternalFace(faceI))
785 nei = mesh().faceNeighbour()[faceI];
790 Pout<< "Split face " << mesh().faces()[faceI]
791 << " own:" << own << " nei:" << nei
793 << " and f1:" << f1 << endl;
796 // Check which face uses anchorPoints (connects to addedCell)
797 // and which one doesn't (connects to original cell)
799 // Bit tricky. We have to know whether this faceSplit splits owner/
800 // neighbour or both. Even if cell is cut we have to make sure this is
801 // the one that cuts it (this face cut might not be the one splitting
804 const face& f = mesh().faces()[faceI];
809 if (cellLoops[own].empty())
814 else if (isIn(splitEdge, cellLoops[own]))
816 // Owner is cut by this splitCut. See which of f0, f1 gets
817 // owner, which gets addedCells_[owner]
818 if (uses(f0, anchorPts[own]))
820 f0Owner = addedCells_[own];
826 f1Owner = addedCells_[own];
831 // Owner not cut by this splitCut. Check on original face whether
833 if (uses(f, anchorPts[own]))
835 label newCellI = addedCells_[own];
847 label f0Neighbour = -1;
848 label f1Neighbour = -1;
852 if (cellLoops[nei].empty())
857 else if (isIn(splitEdge, cellLoops[nei]))
859 // Neighbour is cut by this splitCut. See which of f0, f1
860 // gets which neighbour/addedCells_[neighbour]
861 if (uses(f0, anchorPts[nei]))
863 f0Neighbour = addedCells_[nei];
869 f1Neighbour = addedCells_[nei];
874 // neighbour not cut by this splitCut. Check on original face
875 // whether use anchorPts.
876 if (uses(f, anchorPts[nei]))
878 label newCellI = addedCells_[nei];
879 f0Neighbour = newCellI;
880 f1Neighbour = newCellI;
890 // f0 is the added face, f1 the modified one
891 addFace(meshMod, faceI, f0, f0Owner, f0Neighbour);
893 modFace(meshMod, faceI, f1, f1Owner, f1Neighbour);
895 faceUptodate[faceI] = true;
900 // Faces that have not been split but just appended to. Are guaranteed
901 // to be reachable from an edgeCut.
904 const boolList& edgeIsCut = cuts.edgeIsCut();
906 forAll(edgeIsCut, edgeI)
908 if (edgeIsCut[edgeI])
910 const labelList& eFaces = mesh().edgeFaces()[edgeI];
914 label faceI = eFaces[i];
916 if (!faceUptodate[faceI])
918 // Renumber face to include split edges.
919 face newFace(addEdgeCutsToFace(faceI));
923 Pout<< "Added edge cuts to face " << faceI
924 << " f:" << mesh().faces()[faceI]
925 << " newFace:" << newFace << endl;
928 // Get (new or original) owner and neighbour of faceI
930 faceCells(cuts, faceI, own, nei);
932 modFace(meshMod, faceI, newFace, own, nei);
934 faceUptodate[faceI] = true;
942 // Correct any original faces on split cell for new neighbour/owner
945 forAll(cellLoops, cellI)
947 if (cellLoops[cellI].size())
949 const labelList& cllFaces = mesh().cells()[cellI];
951 forAll(cllFaces, cllFaceI)
953 label faceI = cllFaces[cllFaceI];
955 if (!faceUptodate[faceI])
957 // Update face with new owner/neighbour (if any)
958 const face& f = mesh().faces()[faceI];
960 if (debug && (f != addEdgeCutsToFace(faceI)))
964 "meshCutter::setRefinement(const cellCuts&"
966 ) << "Problem: edges added to face which does "
967 << " not use a marked cut" << endl
968 << "faceI:" << faceI << endl
969 << "face:" << f << endl
970 << "newFace:" << addEdgeCutsToFace(faceI)
971 << abort(FatalError);
974 // Get (new or original) owner and neighbour of faceI
976 faceCells(cuts, faceI, own, nei);
987 faceUptodate[faceI] = true;
995 Pout<< "meshCutter:" << nl
996 << " cells split:" << addedCells_.size() << nl
997 << " faces added:" << addedFaces_.size() << nl
998 << " points added on edges:" << addedPoints_.size() << nl
1004 void Foam::meshCutter::updateMesh(const mapPolyMesh& morphMap)
1006 // Update stored labels for mesh change.
1009 // Create copy since new label might (temporarily) clash with existing
1011 Map<label> newAddedCells(addedCells_.size());
1013 forAllConstIter(Map<label>, addedCells_, iter)
1015 label cellI = iter.key();
1016 label newCellI = morphMap.reverseCellMap()[cellI];
1018 label addedCellI = iter();
1020 label newAddedCellI = morphMap.reverseCellMap()[addedCellI];
1022 if (newCellI >= 0 && newAddedCellI >= 0)
1027 && (newCellI != cellI || newAddedCellI != addedCellI)
1030 Pout<< "meshCutter::updateMesh :"
1031 << " updating addedCell for cell " << cellI
1032 << " from " << addedCellI
1033 << " to " << newAddedCellI << endl;
1035 newAddedCells.insert(newCellI, newAddedCellI);
1040 addedCells_.transfer(newAddedCells);
1044 Map<label> newAddedFaces(addedFaces_.size());
1046 forAllConstIter(Map<label>, addedFaces_, iter)
1048 label cellI = iter.key();
1049 label newCellI = morphMap.reverseCellMap()[cellI];
1051 label addedFaceI = iter();
1053 label newAddedFaceI = morphMap.reverseFaceMap()[addedFaceI];
1055 if ((newCellI >= 0) && (newAddedFaceI >= 0))
1060 && (newCellI != cellI || newAddedFaceI != addedFaceI)
1063 Pout<< "meshCutter::updateMesh :"
1064 << " updating addedFace for cell " << cellI
1065 << " from " << addedFaceI
1066 << " to " << newAddedFaceI
1069 newAddedFaces.insert(newCellI, newAddedFaceI);
1074 addedFaces_.transfer(newAddedFaces);
1078 HashTable<label, edge, Hash<edge> > newAddedPoints(addedPoints_.size());
1082 HashTable<label, edge, Hash<edge> >::const_iterator iter =
1083 addedPoints_.begin();
1084 iter != addedPoints_.end();
1088 const edge& e = iter.key();
1090 label newStart = morphMap.reversePointMap()[e.start()];
1092 label newEnd = morphMap.reversePointMap()[e.end()];
1094 label addedPointI = iter();
1096 label newAddedPointI = morphMap.reversePointMap()[addedPointI];
1098 if ((newStart >= 0) && (newEnd >= 0) && (newAddedPointI >= 0))
1100 edge newE = edge(newStart, newEnd);
1105 && (e != newE || newAddedPointI != addedPointI)
1108 Pout<< "meshCutter::updateMesh :"
1109 << " updating addedPoints for edge " << e
1110 << " from " << addedPointI
1111 << " to " << newAddedPointI
1115 newAddedPoints.insert(newE, newAddedPointI);
1120 addedPoints_.transfer(newAddedPoints);
1125 // ************************************************************************* //