1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 \*---------------------------------------------------------------------------*/
29 #include "meshCutter.H"
31 #include "polyTopoChange.H"
33 #include "mapPolyMesh.H"
34 #include "meshTools.H"
35 #include "polyModifyFace.H"
36 #include "polyAddPoint.H"
37 #include "polyAddFace.H"
38 #include "polyAddCell.H"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 defineTypeNameAndDebug(Foam::meshCutter, 0);
45 // * * * * * * * * * * * * * Private Static Functions * * * * * * * * * * * //
47 // Returns true if lst1 and lst2 share elements
48 bool Foam::meshCutter::uses(const labelList& elems1, const labelList& elems2)
52 if (findIndex(elems2, elems1[elemI]) != -1)
61 // Check if twoCuts at two consecutive position in cuts.
62 bool Foam::meshCutter::isIn
68 label index = findIndex(cuts, twoCuts[0]);
77 cuts[cuts.fcIndex(index)] == twoCuts[1]
78 || cuts[cuts.rcIndex(index)] == twoCuts[1]
83 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
85 // Returns the cell in cellLabels that is cut. Or -1.
86 Foam::label Foam::meshCutter::findCutCell
89 const labelList& cellLabels
92 forAll(cellLabels, labelI)
94 label cellI = cellLabels[labelI];
96 if (cuts.cellLoops()[cellI].size())
105 //- Returns first pointI in pointLabels that uses an internal
106 // face. Used to find point to inflate cell/face from (has to be
107 // connected to internal face). Returns -1 (so inflate from nothing) if
109 Foam::label Foam::meshCutter::findInternalFacePoint
111 const labelList& pointLabels
114 forAll(pointLabels, labelI)
116 label pointI = pointLabels[labelI];
118 const labelList& pFaces = mesh().pointFaces()[pointI];
120 forAll(pFaces, pFaceI)
122 label faceI = pFaces[pFaceI];
124 if (mesh().isInternalFace(faceI))
131 if (pointLabels.empty())
133 FatalErrorIn("meshCutter::findInternalFacePoint(const labelList&)")
134 << "Empty pointLabels" << abort(FatalError);
141 // Get new owner and neighbour of face. Checks anchor points to see if
142 // need to get original or added cell.
143 void Foam::meshCutter::faceCells
145 const cellCuts& cuts,
151 const labelListList& anchorPts = cuts.cellAnchorPoints();
152 const labelListList& cellLoops = cuts.cellLoops();
154 const face& f = mesh().faces()[faceI];
156 own = mesh().faceOwner()[faceI];
158 if (cellLoops[own].size() && uses(f, anchorPts[own]))
160 own = addedCells_[own];
165 if (mesh().isInternalFace(faceI))
167 nei = mesh().faceNeighbour()[faceI];
169 if (cellLoops[nei].size() && uses(f, anchorPts[nei]))
171 nei = addedCells_[nei];
177 void Foam::meshCutter::getFaceInfo
187 if (!mesh().isInternalFace(faceI))
189 patchID = mesh().boundaryMesh().whichPatch(faceI);
192 zoneID = mesh().faceZones().whichZone(faceI);
198 const faceZone& fZone = mesh().faceZones()[zoneID];
200 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
205 // Adds a face on top of existing faceI.
206 void Foam::meshCutter::addFace
208 polyTopoChange& meshMod,
215 label patchID, zoneID, zoneFlip;
217 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
219 if ((nei == -1) || (own < nei))
224 Pout<< "Adding face " << newFace
225 << " with new owner:" << own
226 << " with new neighbour:" << nei
227 << " patchID:" << patchID
228 << " zoneID:" << zoneID
229 << " zoneFlip:" << zoneFlip
242 faceI, // master face for addition
244 patchID, // patch for face
245 zoneID, // zone for face
246 zoneFlip // face zone flip
252 // Reverse owner/neighbour
255 Pout<< "Adding (reversed) face " << newFace.reverseFace()
256 << " with new owner:" << nei
257 << " with new neighbour:" << own
258 << " patchID:" << patchID
259 << " zoneID:" << zoneID
260 << " zoneFlip:" << zoneFlip
268 newFace.reverseFace(), // face
273 faceI, // master face for addition
275 patchID, // patch for face
276 zoneID, // zone for face
277 zoneFlip // face zone flip
284 // Modifies existing faceI for either new owner/neighbour or new face points.
285 void Foam::meshCutter::modFace
287 polyTopoChange& meshMod,
294 label patchID, zoneID, zoneFlip;
296 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
300 (own != mesh().faceOwner()[faceI])
302 mesh().isInternalFace(faceI)
303 && (nei != mesh().faceNeighbour()[faceI])
305 || (newFace != mesh().faces()[faceI])
310 Pout<< "Modifying face " << faceI
311 << " old vertices:" << mesh().faces()[faceI]
312 << " new vertices:" << newFace
313 << " new owner:" << own
314 << " new neighbour:" << nei
315 << " new zoneID:" << zoneID
316 << " new zoneFlip:" << zoneFlip
320 if ((nei == -1) || (own < nei))
326 newFace, // modified face
327 faceI, // label of face being modified
331 patchID, // patch for face
332 false, // remove from zone
333 zoneID, // zone for face
334 zoneFlip // face flip in zone
344 newFace.reverseFace(), // modified face
345 faceI, // label of face being modified
349 patchID, // patch for face
350 false, // remove from zone
351 zoneID, // zone for face
352 zoneFlip // face flip in zone
360 // Copies face starting from startFp up to and including endFp.
361 void Foam::meshCutter::copyFace
375 newFace[newFp++] = f[fp];
377 fp = (fp + 1) % f.size();
379 newFace[newFp] = f[fp];
383 // Actually split face in two along splitEdge v0, v1 (the two vertices in new
384 // vertex numbering). Generates faces in same ordering
385 // as original face. Replaces cutEdges by the points introduced on them
387 void Foam::meshCutter::splitFace
397 // Check if we find any new vertex which is part of the splitEdge.
398 label startFp = findIndex(f, v0);
404 "meshCutter::splitFace"
405 ", const face&, const label, const label, face&, face&)"
406 ) << "Cannot find vertex (new numbering) " << v0
408 << abort(FatalError);
411 label endFp = findIndex(f, v1);
417 "meshCutter::splitFace("
418 ", const face&, const label, const label, face&, face&)"
419 ) << "Cannot find vertex (new numbering) " << v1
421 << abort(FatalError);
425 f0.setSize((endFp + 1 + f.size() - startFp) % f.size());
426 f1.setSize(f.size() - f0.size() + 2);
428 copyFace(f, startFp, endFp, f0);
429 copyFace(f, endFp, startFp, f1);
433 // Adds additional vertices (from edge cutting) to face. Used for faces which
434 // are not split but still might use edge that has been cut.
435 Foam::face Foam::meshCutter::addEdgeCutsToFace(const label faceI) const
437 const face& f = mesh().faces()[faceI];
439 face newFace(2 * f.size());
445 // Duplicate face vertex .
446 newFace[newFp++] = f[fp];
448 // Check if edge has been cut.
449 label fp1 = f.fcIndex(fp);
451 HashTable<label, edge, Hash<edge> >::const_iterator fnd =
452 addedPoints_.find(edge(f[fp], f[fp1]));
454 if (fnd != addedPoints_.end())
456 // edge has been cut. Introduce new vertex.
457 newFace[newFp++] = fnd();
461 newFace.setSize(newFp);
467 // Walk loop (loop of cuts) across circumference of cellI. Returns face in
469 // Note: tricky bit is that it can use existing edges which have been split.
470 Foam::face Foam::meshCutter::loopToFace
473 const labelList& loop
476 face newFace(2*loop.size());
482 label cut = loop[fp];
486 label edgeI = getEdge(cut);
488 const edge& e = mesh().edges()[edgeI];
490 label vertI = addedPoints_[e];
492 newFace[newFaceI++] = vertI;
497 label vertI = getVertex(cut);
499 newFace[newFaceI++] = vertI;
501 label nextCut = loop[loop.fcIndex(fp)];
503 if (!isEdge(nextCut))
505 // From vertex to vertex -> cross cut only if no existing edge.
506 label nextVertI = getVertex(nextCut);
508 label edgeI = meshTools::findEdge(mesh(), vertI, nextVertI);
512 // Existing edge. Insert split-edge point if any.
513 HashTable<label, edge, Hash<edge> >::const_iterator fnd =
514 addedPoints_.find(mesh().edges()[edgeI]);
516 if (fnd != addedPoints_.end())
518 newFace[newFaceI++] = fnd();
524 newFace.setSize(newFaceI);
530 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
532 // Construct from components
533 Foam::meshCutter::meshCutter(const polyMesh& mesh)
543 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
545 Foam::meshCutter::~meshCutter()
549 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
551 void Foam::meshCutter::setRefinement
553 const cellCuts& cuts,
554 polyTopoChange& meshMod
557 // Clear and size maps here since mesh size will change.
559 addedCells_.resize(cuts.nLoops());
562 addedFaces_.resize(cuts.nLoops());
564 addedPoints_.clear();
565 addedPoints_.resize(cuts.nLoops());
567 if (cuts.nLoops() == 0)
572 const labelListList& anchorPts = cuts.cellAnchorPoints();
573 const labelListList& cellLoops = cuts.cellLoops();
576 // Add new points along cut edges.
579 forAll(cuts.edgeIsCut(), edgeI)
581 if (cuts.edgeIsCut()[edgeI])
583 const edge& e = mesh().edges()[edgeI];
585 // Check if there is any cell using this edge.
586 if (debug && findCutCell(cuts, mesh().edgeCells()[edgeI]) == -1)
590 "meshCutter::setRefinement(const cellCuts&"
592 ) << "Problem: cut edge but none of the cells using it is\n"
593 << "edge:" << edgeI << " verts:" << e
594 << abort(FatalError);
597 // One of the edge end points should be master point of nbCellI.
598 label masterPointI = e.start();
600 const point& v0 = mesh().points()[e.start()];
601 const point& v1 = mesh().points()[e.end()];
603 scalar weight = cuts.edgeWeight()[edgeI];
605 point newPt = weight*v1 + (1.0-weight)*v0;
613 masterPointI, // master point
614 -1, // zone for point
615 true // supports a cell
619 // Store on (hash of) edge.
620 addedPoints_.insert(e, addedPointI);
624 Pout<< "Added point " << addedPointI
626 << masterPointI << " of edge " << edgeI
627 << " vertices " << e << endl;
633 // Add cells (on 'anchor' side of cell)
636 forAll(cellLoops, cellI)
638 if (cellLoops[cellI].size())
640 // Add a cell to the existing cell
649 cellI, // master cell
654 addedCells_.insert(cellI, addedCellI);
658 Pout<< "Added cell " << addedCells_[cellI] << " to cell "
666 // For all cut cells add an internal face
669 forAll(cellLoops, cellI)
671 const labelList& loop = cellLoops[cellI];
676 // Convert loop (=list of cuts) into proper face.
677 // Orientation should already be ok. (done by cellCuts)
679 face newFace(loopToFace(cellI, loop));
681 // Pick any anchor point on cell
682 label masterPointI = findInternalFacePoint(anchorPts[cellI]);
691 addedCells_[cellI], // neighbour
692 masterPointI, // master point
694 -1, // master face for addition
696 -1, // patch for face
698 false // face zone flip
702 addedFaces_.insert(cellI, addedFaceI);
706 // Gets edgeweights of loop
707 scalarField weights(loop.size());
715 ? cuts.edgeWeight()[getEdge(cut)]
720 Pout<< "Added splitting face " << newFace << " index:"
722 << " to owner " << cellI
723 << " neighbour " << addedCells_[cellI]
725 writeCuts(Pout, loop, weights);
733 // Modify faces on the outside and create new ones
734 // (in effect split old faces into two)
737 // Maintain whether face has been updated (for -split edges
738 // -new owner/neighbour)
739 boolList faceUptodate(mesh().nFaces(), false);
741 const Map<edge>& faceSplitCuts = cuts.faceSplitCut();
745 Map<edge>::const_iterator iter = faceSplitCuts.begin();
746 iter != faceSplitCuts.end();
750 label faceI = iter.key();
752 // Renumber face to include split edges.
753 face newFace(addEdgeCutsToFace(faceI));
755 // Edge splitting the face. Convert cuts to new vertex numbering.
756 const edge& splitEdge = iter();
758 label cut0 = splitEdge[0];
763 label edgeI = getEdge(cut0);
764 v0 = addedPoints_[mesh().edges()[edgeI]];
768 v0 = getVertex(cut0);
771 label cut1 = splitEdge[1];
775 label edgeI = getEdge(cut1);
776 v1 = addedPoints_[mesh().edges()[edgeI]];
780 v1 = getVertex(cut1);
783 // Split face along the elements of the splitEdge.
785 splitFace(newFace, v0, v1, f0, f1);
787 label own = mesh().faceOwner()[faceI];
791 if (mesh().isInternalFace(faceI))
793 nei = mesh().faceNeighbour()[faceI];
798 Pout<< "Split face " << mesh().faces()[faceI]
799 << " own:" << own << " nei:" << nei
801 << " and f1:" << f1 << endl;
804 // Check which face uses anchorPoints (connects to addedCell)
805 // and which one doesn't (connects to original cell)
807 // Bit tricky. We have to know whether this faceSplit splits owner/
808 // neighbour or both. Even if cell is cut we have to make sure this is
809 // the one that cuts it (this face cut might not be the one splitting
812 const face& f = mesh().faces()[faceI];
817 if (cellLoops[own].empty())
822 else if (isIn(splitEdge, cellLoops[own]))
824 // Owner is cut by this splitCut. See which of f0, f1 gets
825 // owner, which gets addedCells_[owner]
826 if (uses(f0, anchorPts[own]))
828 f0Owner = addedCells_[own];
834 f1Owner = addedCells_[own];
839 // Owner not cut by this splitCut. Check on original face whether
841 if (uses(f, anchorPts[own]))
843 label newCellI = addedCells_[own];
855 label f0Neighbour = -1;
856 label f1Neighbour = -1;
860 if (cellLoops[nei].empty())
865 else if (isIn(splitEdge, cellLoops[nei]))
867 // Neighbour is cut by this splitCut. See which of f0, f1
868 // gets which neighbour/addedCells_[neighbour]
869 if (uses(f0, anchorPts[nei]))
871 f0Neighbour = addedCells_[nei];
877 f1Neighbour = addedCells_[nei];
882 // neighbour not cut by this splitCut. Check on original face
883 // whether use anchorPts.
884 if (uses(f, anchorPts[nei]))
886 label newCellI = addedCells_[nei];
887 f0Neighbour = newCellI;
888 f1Neighbour = newCellI;
898 // f0 is the added face, f1 the modified one
899 addFace(meshMod, faceI, f0, f0Owner, f0Neighbour);
901 modFace(meshMod, faceI, f1, f1Owner, f1Neighbour);
903 faceUptodate[faceI] = true;
908 // Faces that have not been split but just appended to. Are guaranteed
909 // to be reachable from an edgeCut.
912 const boolList& edgeIsCut = cuts.edgeIsCut();
914 forAll(edgeIsCut, edgeI)
916 if (edgeIsCut[edgeI])
918 const labelList& eFaces = mesh().edgeFaces()[edgeI];
922 label faceI = eFaces[i];
924 if (!faceUptodate[faceI])
926 // Renumber face to include split edges.
927 face newFace(addEdgeCutsToFace(faceI));
931 Pout<< "Added edge cuts to face " << faceI
932 << " f:" << mesh().faces()[faceI]
933 << " newFace:" << newFace << endl;
936 // Get (new or original) owner and neighbour of faceI
938 faceCells(cuts, faceI, own, nei);
940 modFace(meshMod, faceI, newFace, own, nei);
942 faceUptodate[faceI] = true;
950 // Correct any original faces on split cell for new neighbour/owner
953 forAll(cellLoops, cellI)
955 if (cellLoops[cellI].size())
957 const labelList& cllFaces = mesh().cells()[cellI];
959 forAll(cllFaces, cllFaceI)
961 label faceI = cllFaces[cllFaceI];
963 if (!faceUptodate[faceI])
965 // Update face with new owner/neighbour (if any)
966 const face& f = mesh().faces()[faceI];
968 if (debug && (f != addEdgeCutsToFace(faceI)))
972 "meshCutter::setRefinement(const cellCuts&"
974 ) << "Problem: edges added to face which does "
975 << " not use a marked cut" << endl
976 << "faceI:" << faceI << endl
977 << "face:" << f << endl
978 << "newFace:" << addEdgeCutsToFace(faceI)
979 << abort(FatalError);
982 // Get (new or original) owner and neighbour of faceI
984 faceCells(cuts, faceI, own, nei);
995 faceUptodate[faceI] = true;
1003 Pout<< "meshCutter:" << nl
1004 << " cells split:" << addedCells_.size() << nl
1005 << " faces added:" << addedFaces_.size() << nl
1006 << " points added on edges:" << addedPoints_.size() << nl
1012 void Foam::meshCutter::updateMesh(const mapPolyMesh& morphMap)
1014 // Update stored labels for mesh change.
1017 // Create copy since new label might (temporarily) clash with existing
1019 Map<label> newAddedCells(addedCells_.size());
1023 Map<label>::const_iterator iter = addedCells_.begin();
1024 iter != addedCells_.end();
1028 label cellI = iter.key();
1030 label newCellI = morphMap.reverseCellMap()[cellI];
1032 label addedCellI = iter();
1034 label newAddedCellI = morphMap.reverseCellMap()[addedCellI];
1036 if (newCellI >= 0 && newAddedCellI >= 0)
1041 && (newCellI != cellI || newAddedCellI != addedCellI)
1044 Pout<< "meshCutter::updateMesh :"
1045 << " updating addedCell for cell " << cellI
1046 << " from " << addedCellI
1047 << " to " << newAddedCellI << endl;
1049 newAddedCells.insert(newCellI, newAddedCellI);
1054 addedCells_.transfer(newAddedCells);
1058 Map<label> newAddedFaces(addedFaces_.size());
1062 Map<label>::const_iterator iter = addedFaces_.begin();
1063 iter != addedFaces_.end();
1067 label cellI = iter.key();
1069 label newCellI = morphMap.reverseCellMap()[cellI];
1071 label addedFaceI = iter();
1073 label newAddedFaceI = morphMap.reverseFaceMap()[addedFaceI];
1075 if ((newCellI >= 0) && (newAddedFaceI >= 0))
1080 && (newCellI != cellI || newAddedFaceI != addedFaceI)
1083 Pout<< "meshCutter::updateMesh :"
1084 << " updating addedFace for cell " << cellI
1085 << " from " << addedFaceI
1086 << " to " << newAddedFaceI
1089 newAddedFaces.insert(newCellI, newAddedFaceI);
1094 addedFaces_.transfer(newAddedFaces);
1098 HashTable<label, edge, Hash<edge> > newAddedPoints(addedPoints_.size());
1102 HashTable<label, edge, Hash<edge> >::const_iterator iter =
1103 addedPoints_.begin();
1104 iter != addedPoints_.end();
1108 const edge& e = iter.key();
1110 label newStart = morphMap.reversePointMap()[e.start()];
1112 label newEnd = morphMap.reversePointMap()[e.end()];
1114 label addedPointI = iter();
1116 label newAddedPointI = morphMap.reversePointMap()[addedPointI];
1118 if ((newStart >= 0) && (newEnd >= 0) && (newAddedPointI >= 0))
1120 edge newE = edge(newStart, newEnd);
1125 && (e != newE || newAddedPointI != addedPointI)
1128 Pout<< "meshCutter::updateMesh :"
1129 << " updating addedPoints for edge " << e
1130 << " from " << addedPointI
1131 << " to " << newAddedPointI
1135 newAddedPoints.insert(newE, newAddedPointI);
1140 addedPoints_.transfer(newAddedPoints);
1145 // ************************************************************************* //