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 "boundaryCutter.H"
28 #include "polyTopoChange.H"
29 #include "polyAddCell.H"
30 #include "polyAddFace.H"
31 #include "polyAddPoint.H"
32 #include "polyModifyFace.H"
33 #include "polyModifyPoint.H"
34 #include "mapPolyMesh.H"
35 #include "meshTools.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(Foam::boundaryCutter, 0);
42 // * * * * * * * * * * * * * Private Static Functions * * * * * * * * * * * //
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 void Foam::boundaryCutter::getFaceInfo
57 if (!mesh_.isInternalFace(faceI))
59 patchID = mesh_.boundaryMesh().whichPatch(faceI);
62 zoneID = mesh_.faceZones().whichZone(faceI);
68 const faceZone& fZone = mesh_.faceZones()[zoneID];
70 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
75 // Adds additional vertices (from edge cutting) to face. Used for faces which
76 // are not split but still might use edge that has been cut.
77 Foam::face Foam::boundaryCutter::addEdgeCutsToFace
80 const Map<labelList>& edgeToAddedPoints
83 const edgeList& edges = mesh_.edges();
84 const face& f = mesh_.faces()[faceI];
85 const labelList& fEdges = mesh_.faceEdges()[faceI];
88 DynamicList<label> newFace(2 * f.size());
92 // Duplicate face vertex .
93 newFace.append(f[fp]);
95 // Check if edge has been cut.
96 label v1 = f.nextLabel(fp);
98 label edgeI = meshTools::findEdge(edges, fEdges, f[fp], v1);
100 Map<labelList>::const_iterator fnd = edgeToAddedPoints.find(edgeI);
102 if (fnd != edgeToAddedPoints.end())
104 // edge has been cut. Introduce new vertices. Check order.
105 const labelList& addedPoints = fnd();
107 if (edges[edgeI].start() == f[fp])
109 // Introduce in same order.
110 forAll(addedPoints, i)
112 newFace.append(addedPoints[i]);
117 // Introduce in opposite order.
118 forAllReverse(addedPoints, i)
120 newFace.append(addedPoints[i]);
127 returnFace.transfer(newFace);
131 Pout<< "addEdgeCutsToFace:" << nl
132 << " from : " << f << nl
133 << " to : " << returnFace << endl;
140 void Foam::boundaryCutter::addFace
145 bool& modifiedFace, // have we already 'used' faceI
146 polyTopoChange& meshMod
149 // Information about old face
150 label patchID, zoneID, zoneFlip;
151 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
152 label own = mesh_.faceOwner()[faceI];
153 label masterPoint = mesh_.faces()[faceI][0];
166 patchID, // patch for face
167 false, // remove from zone
168 zoneID, // zone for face
169 zoneFlip // face zone flip
184 masterPoint, // master point
186 -1, // master face for addition
188 patchID, // patch for face
189 zoneID, // zone for face
190 zoneFlip // face zone flip
198 // Splits a face using the cut edges and modified points
199 bool Foam::boundaryCutter::splitFace
202 const Map<point>& pointToPos,
203 const Map<labelList>& edgeToAddedPoints,
204 polyTopoChange& meshMod
207 const edgeList& edges = mesh_.edges();
208 const face& f = mesh_.faces()[faceI];
209 const labelList& fEdges = mesh_.faceEdges()[faceI];
211 // Count number of split edges and total number of splits.
212 label nSplitEdges = 0;
213 label nModPoints = 0;
214 label nTotalSplits = 0;
218 if (pointToPos.found(f[fp]))
224 // Check if edge has been cut.
225 label nextV = f.nextLabel(fp);
227 label edgeI = meshTools::findEdge(edges, fEdges, f[fp], nextV);
229 Map<labelList>::const_iterator fnd = edgeToAddedPoints.find(edgeI);
231 if (fnd != edgeToAddedPoints.end())
234 nTotalSplits += fnd().size();
240 Pout<< "Face:" << faceI
241 << " nModPoints:" << nModPoints
242 << " nSplitEdges:" << nSplitEdges
243 << " nTotalSplits:" << nTotalSplits << endl;
246 if (nSplitEdges == 0 && nModPoints == 0)
248 FatalErrorIn("boundaryCutter::splitFace") << "Problem : face:" << faceI
249 << " nSplitEdges:" << nSplitEdges
250 << " nTotalSplits:" << nTotalSplits
251 << abort(FatalError);
254 else if (nSplitEdges + nModPoints == 1)
256 // single or multiple cuts on a single edge or single modified point
257 // Dont cut and let caller handle this.
258 Warning << "Face " << faceI << " has only one edge cut " << endl;
263 // So guaranteed to have two edges cut or points modified. Split face:
264 // - find starting cut
265 // - walk to next cut. Make face
266 // - loop until face done.
268 // Information about old face
269 label patchID, zoneID, zoneFlip;
270 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
272 // Get face with new points on cut edges for ease of looping
273 face extendedFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
275 // Find first added point. This is the starting vertex for splitting.
278 forAll(extendedFace, fp)
280 if (extendedFace[fp] >= mesh_.nPoints())
289 // No added point. Maybe there is a modified point?
290 forAll(extendedFace, fp)
292 if (pointToPos.found(extendedFace[fp]))
302 FatalErrorIn("boundaryCutter::splitFace")
303 << "Problem" << abort(FatalError);
306 // Have we already modified existing face (first face gets done
307 // as modification; all following ones as polyAddFace)
308 bool modifiedFace = false;
319 // Needs to get split into:
320 // - three 'side' faces a,b,c
321 // - one middle face d
331 // Storage for new face
332 DynamicList<label> newFace(extendedFace.size());
336 forAll(extendedFace, i)
338 label pointI = extendedFace[fp];
340 newFace.append(pointI);
346 pointI >= mesh_.nPoints()
347 || pointToPos.found(pointI)
351 // Enough vertices to create a face from.
353 tmpFace.transfer(newFace);
356 addFace(faceI, tmpFace, modifiedFace, meshMod);
358 // Starting point is also the starting point for the new face
359 newFace.append(extendedFace[startFp]);
360 newFace.append(extendedFace[fp]);
363 fp = (fp+1) % extendedFace.size();
367 if (newFace.size() > 2)
369 // Enough vertices to create a face from.
371 tmpFace.transfer(newFace);
374 addFace(faceI, tmpFace, modifiedFace, meshMod);
383 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
385 // Construct from components
386 Foam::boundaryCutter::boundaryCutter(const polyMesh& mesh)
394 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
396 Foam::boundaryCutter::~boundaryCutter()
400 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
402 void Foam::boundaryCutter::setRefinement
404 const Map<point>& pointToPos,
405 const Map<List<point> >& edgeToCuts,
406 const Map<labelPair>& faceToSplit,
407 const Map<point>& faceToFeaturePoint,
408 polyTopoChange& meshMod
411 // Clear and size maps here since mesh size will change.
412 edgeAddedPoints_.clear();
414 faceAddedPoint_.clear();
415 faceAddedPoint_.resize(faceToFeaturePoint.size());
419 // Points that just need to be moved
420 // Note: could just as well be handled outside of setRefinement.
423 forAllConstIter(Map<point>, pointToPos, iter)
432 -1, // zone for point
433 true // supports a cell
440 // Add new points along cut edges.
443 // Map from edge label to sorted list of points
444 Map<labelList> edgeToAddedPoints(edgeToCuts.size());
446 forAllConstIter(Map<List<point> >, edgeToCuts, iter)
448 label edgeI = iter.key();
450 const edge& e = mesh_.edges()[edgeI];
452 // Sorted (from start to end) list of cuts on edge
453 const List<point>& cuts = iter();
457 // point on feature to move to
458 const point& featurePoint = cuts[cutI];
465 featurePoint, // point
466 e.start(), // master point
467 -1, // zone for point
468 true // supports a cell
472 Map<labelList>::iterator fnd = edgeToAddedPoints.find(edgeI);
474 if (fnd != edgeToAddedPoints.end())
476 labelList& addedPoints = fnd();
478 label sz = addedPoints.size();
479 addedPoints.setSize(sz+1);
480 addedPoints[sz] = addedPointI;
484 edgeToAddedPoints.insert(edgeI, labelList(1, addedPointI));
489 Pout<< "Added point " << addedPointI << " for edge " << edgeI
490 << " with cuts:" << edgeToAddedPoints[edgeI] << endl;
497 // Introduce feature points.
500 forAllConstIter(Map<point>, faceToFeaturePoint, iter)
502 label faceI = iter.key();
504 const face& f = mesh_.faces()[faceI];
506 if (faceToSplit.found(faceI))
508 FatalErrorIn("boundaryCutter::setRefinement")
509 << "Face " << faceI << " vertices " << f
510 << " is both marked for face-centre decomposition and"
511 << " diagonal splitting."
512 << abort(FatalError);
515 if (mesh_.isInternalFace(faceI))
517 FatalErrorIn("boundaryCutter::setRefinement")
518 << "Face " << faceI << " vertices " << f
519 << " is not an external face. Cannot split it"
520 << abort(FatalError);
529 f[0], // master point
530 -1, // zone for point
531 true // supports a cell
534 faceAddedPoint_.insert(faceI, addedPointI);
538 Pout<< "Added point " << addedPointI << " for feature point "
539 << iter() << " on face " << faceI << " with centre "
540 << mesh_.faceCentres()[faceI] << endl;
546 // Split or retriangulate faces
550 // Maintain whether face has been updated (for -split edges
551 // -new owner/neighbour)
552 boolList faceUptodate(mesh_.nFaces(), false);
555 // Triangulate faces containing feature points
556 forAllConstIter(Map<label>, faceAddedPoint_, iter)
558 label faceI = iter.key();
560 // Get face with new points on cut edges.
561 face newFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
563 label addedPointI = iter();
565 // Information about old face
566 label patchID, zoneID, zoneFlip;
567 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
568 label own = mesh_.faceOwner()[faceI];
569 label masterPoint = mesh_.faces()[faceI][0];
571 // Triangulate face around mid point
577 label nextV = newFace.nextLabel(fp);
579 tri[0] = newFace[fp];
581 tri[2] = addedPointI;
585 // Modify the existing face.
595 patchID, // patch for face
596 false, // remove from zone
597 zoneID, // zone for face
598 zoneFlip // face zone flip
604 // Add additional faces
612 masterPoint, // master point
614 -1, // master face for addition
616 patchID, // patch for face
617 zoneID, // zone for face
618 zoneFlip // face zone flip
624 faceUptodate[faceI] = true;
628 // Diagonally split faces
629 forAllConstIter(Map<labelPair>, faceToSplit, iter)
631 label faceI = iter.key();
633 const face& f = mesh_.faces()[faceI];
635 if (faceAddedPoint_.found(faceI))
637 FatalErrorIn("boundaryCutter::setRefinement")
638 << "Face " << faceI << " vertices " << f
639 << " is both marked for face-centre decomposition and"
640 << " diagonal splitting."
641 << abort(FatalError);
645 // Get face with new points on cut edges.
646 face newFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
648 // Information about old face
649 label patchID, zoneID, zoneFlip;
650 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
651 label own = mesh_.faceOwner()[faceI];
652 label masterPoint = mesh_.faces()[faceI][0];
654 // Split face from one side of diagonal to other.
655 const labelPair& diag = iter();
657 label fp0 = findIndex(newFace, f[diag[0]]);
658 label fp1 = findIndex(newFace, f[diag[1]]);
660 if (fp0 == -1 || fp1 == -1 || fp0 == fp1)
662 FatalErrorIn("boundaryCutter::setRefinement")
663 << "Problem : Face " << faceI << " vertices " << f
664 << " newFace:" << newFace << " diagonal:" << f[diag[0]]
666 << abort(FatalError);
669 // Replace existing face by newFace from fp0 to fp1 and add new one
672 DynamicList<label> newVerts(newFace.size());
674 // Get vertices from fp0 to (and including) fp1
679 newVerts.append(newFace[fp]);
681 fp = (fp == newFace.size()-1 ? 0 : fp+1);
685 newVerts.append(newFace[fp1]);
688 // Modify the existing face.
693 face(newVerts.shrink()), // face
698 patchID, // patch for face
699 false, // remove from zone
700 zoneID, // zone for face
701 zoneFlip // face zone flip
708 // Get vertices from fp1 to (and including) fp0
712 newVerts.append(newFace[fp]);
714 fp = (fp == newFace.size()-1 ? 0 : fp+1);
718 newVerts.append(newFace[fp0]);
720 // Add additional face
725 face(newVerts.shrink()), // face
728 masterPoint, // master point
730 -1, // master face for addition
732 patchID, // patch for face
733 zoneID, // zone for face
734 zoneFlip // face zone flip
738 faceUptodate[faceI] = true;
742 // Split external faces without feature point but using cut edges.
743 // Does right handed walk but not really.
744 forAllConstIter(Map<labelList>, edgeToAddedPoints, iter)
746 label edgeI = iter.key();
748 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
752 label faceI = eFaces[i];
754 if (!faceUptodate[faceI] && !mesh_.isInternalFace(faceI))
756 // Is external face so split
757 if (splitFace(faceI, pointToPos, edgeToAddedPoints, meshMod))
760 faceUptodate[faceI] = true;
767 // Add cut edges (but don't split) any other faces using any cut edge.
768 // These can be external faces where splitFace hasn't cut them or
770 forAllConstIter(Map<labelList>, edgeToAddedPoints, iter)
772 label edgeI = iter.key();
774 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
778 label faceI = eFaces[i];
780 if (!faceUptodate[faceI])
782 // Renumber face to include split edges.
783 face newFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
785 label own = mesh_.faceOwner()[faceI];
789 if (mesh_.isInternalFace(faceI))
791 nei = mesh_.faceNeighbour()[faceI];
794 label patchID, zoneID, zoneFlip;
795 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
801 newFace, // modified face
802 faceI, // label of face being modified
806 patchID, // patch for face
807 false, // remove from zone
808 zoneID, // zone for face
809 zoneFlip // face flip in zone
813 faceUptodate[faceI] = true;
818 // Convert edge to points storage from edge labels (not preserved)
820 edgeAddedPoints_.resize(edgeToCuts.size());
822 forAllConstIter(Map<labelList>, edgeToAddedPoints, iter)
824 edgeAddedPoints_.insert(mesh_.edges()[iter.key()], iter());
829 void Foam::boundaryCutter::updateMesh(const mapPolyMesh& morphMap)
831 // Update stored labels for mesh change.
834 // Do faceToAddedPoint
838 // Create copy since we're deleting entries.
839 Map<label> newAddedPoints(faceAddedPoint_.size());
841 forAllConstIter(Map<label>, faceAddedPoint_, iter)
843 label oldFaceI = iter.key();
845 label newFaceI = morphMap.reverseFaceMap()[oldFaceI];
847 label oldPointI = iter();
849 label newPointI = morphMap.reversePointMap()[oldPointI];
851 if (newFaceI >= 0 && newPointI >= 0)
853 newAddedPoints.insert(newFaceI, newPointI);
858 faceAddedPoint_.transfer(newAddedPoints);
863 // Do edgeToAddedPoints
868 // Create copy since we're deleting entries
869 HashTable<labelList, edge, Hash<edge> >
870 newEdgeAddedPoints(edgeAddedPoints_.size());
874 HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
875 edgeAddedPoints_.begin();
876 iter != edgeAddedPoints_.end();
880 const edge& e = iter.key();
882 label newStart = morphMap.reversePointMap()[e.start()];
884 label newEnd = morphMap.reversePointMap()[e.end()];
886 if (newStart >= 0 && newEnd >= 0)
888 const labelList& addedPoints = iter();
890 labelList newAddedPoints(addedPoints.size());
893 forAll(addedPoints, i)
895 label newAddedPointI =
896 morphMap.reversePointMap()[addedPoints[i]];
898 if (newAddedPointI >= 0)
900 newAddedPoints[newI++] = newAddedPointI;
905 newAddedPoints.setSize(newI);
907 edge newE = edge(newStart, newEnd);
909 newEdgeAddedPoints.insert(newE, newAddedPoints);
915 edgeAddedPoints_.transfer(newEdgeAddedPoints);
920 // ************************************************************************* //