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 "boundaryCutter.H"
31 #include "polyTopoChange.H"
32 #include "polyAddCell.H"
33 #include "polyAddFace.H"
34 #include "polyAddPoint.H"
35 #include "polyModifyFace.H"
36 #include "polyModifyPoint.H"
37 #include "mapPolyMesh.H"
38 #include "meshTools.H"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 defineTypeNameAndDebug(boundaryCutter, 0);
50 // * * * * * * * * * * * * * Private Static Functions * * * * * * * * * * * //
53 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55 void Foam::boundaryCutter::getFaceInfo
65 if (!mesh_.isInternalFace(faceI))
67 patchID = mesh_.boundaryMesh().whichPatch(faceI);
70 zoneID = mesh_.faceZones().whichZone(faceI);
76 const faceZone& fZone = mesh_.faceZones()[zoneID];
78 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
83 // Adds additional vertices (from edge cutting) to face. Used for faces which
84 // are not split but still might use edge that has been cut.
85 Foam::face Foam::boundaryCutter::addEdgeCutsToFace
88 const Map<labelList>& edgeToAddedPoints
91 const edgeList& edges = mesh_.edges();
92 const face& f = mesh_.faces()[faceI];
93 const labelList& fEdges = mesh_.faceEdges()[faceI];
96 DynamicList<label> newFace(2 * f.size());
100 // Duplicate face vertex .
101 newFace.append(f[fp]);
103 // Check if edge has been cut.
104 label v1 = f.nextLabel(fp);
106 label edgeI = meshTools::findEdge(edges, fEdges, f[fp], v1);
108 Map<labelList>::const_iterator fnd = edgeToAddedPoints.find(edgeI);
110 if (fnd != edgeToAddedPoints.end())
112 // edge has been cut. Introduce new vertices. Check order.
113 const labelList& addedPoints = fnd();
115 if (edges[edgeI].start() == f[fp])
117 // Introduce in same order.
118 forAll(addedPoints, i)
120 newFace.append(addedPoints[i]);
125 // Introduce in opposite order.
126 forAllReverse(addedPoints, i)
128 newFace.append(addedPoints[i]);
135 returnFace.transfer(newFace);
139 Pout<< "addEdgeCutsToFace:" << nl
140 << " from : " << f << nl
141 << " to : " << returnFace << endl;
148 void Foam::boundaryCutter::addFace
153 bool& modifiedFace, // have we already 'used' faceI
154 polyTopoChange& meshMod
157 // Information about old face
158 label patchID, zoneID, zoneFlip;
159 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
160 label own = mesh_.faceOwner()[faceI];
161 label masterPoint = mesh_.faces()[faceI][0];
174 patchID, // patch for face
175 false, // remove from zone
176 zoneID, // zone for face
177 zoneFlip // face zone flip
192 masterPoint, // master point
194 -1, // master face for addition
196 patchID, // patch for face
197 zoneID, // zone for face
198 zoneFlip // face zone flip
206 // Splits a face using the cut edges and modified points
207 bool Foam::boundaryCutter::splitFace
210 const Map<point>& pointToPos,
211 const Map<labelList>& edgeToAddedPoints,
212 polyTopoChange& meshMod
215 const edgeList& edges = mesh_.edges();
216 const face& f = mesh_.faces()[faceI];
217 const labelList& fEdges = mesh_.faceEdges()[faceI];
219 // Count number of split edges and total number of splits.
220 label nSplitEdges = 0;
221 label nModPoints = 0;
222 label nTotalSplits = 0;
226 if (pointToPos.found(f[fp]))
232 // Check if edge has been cut.
233 label nextV = f.nextLabel(fp);
235 label edgeI = meshTools::findEdge(edges, fEdges, f[fp], nextV);
237 Map<labelList>::const_iterator fnd = edgeToAddedPoints.find(edgeI);
239 if (fnd != edgeToAddedPoints.end())
242 nTotalSplits += fnd().size();
248 Pout<< "Face:" << faceI
249 << " nModPoints:" << nModPoints
250 << " nSplitEdges:" << nSplitEdges
251 << " nTotalSplits:" << nTotalSplits << endl;
254 if (nSplitEdges == 0 && nModPoints == 0)
256 FatalErrorIn("boundaryCutter::splitFace") << "Problem : face:" << faceI
257 << " nSplitEdges:" << nSplitEdges
258 << " nTotalSplits:" << nTotalSplits
259 << abort(FatalError);
262 else if (nSplitEdges + nModPoints == 1)
264 // single or multiple cuts on a single edge or single modified point
265 // Dont cut and let caller handle this.
266 Warning << "Face " << faceI << " has only one edge cut " << endl;
271 // So guaranteed to have two edges cut or points modified. Split face:
272 // - find starting cut
273 // - walk to next cut. Make face
274 // - loop until face done.
276 // Information about old face
277 label patchID, zoneID, zoneFlip;
278 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
280 // Get face with new points on cut edges for ease of looping
281 face extendedFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
283 // Find first added point. This is the starting vertex for splitting.
286 forAll(extendedFace, fp)
288 if (extendedFace[fp] >= mesh_.nPoints())
297 // No added point. Maybe there is a modified point?
298 forAll(extendedFace, fp)
300 if (pointToPos.found(extendedFace[fp]))
310 FatalErrorIn("boundaryCutter::splitFace")
311 << "Problem" << abort(FatalError);
314 // Have we already modified existing face (first face gets done
315 // as modification; all following ones as polyAddFace)
316 bool modifiedFace = false;
327 // Needs to get split into:
328 // - three 'side' faces a,b,c
329 // - one middle face d
339 // Storage for new face
340 DynamicList<label> newFace(extendedFace.size());
344 forAll(extendedFace, i)
346 label pointI = extendedFace[fp];
348 newFace.append(pointI);
354 pointI >= mesh_.nPoints()
355 || pointToPos.found(pointI)
359 // Enough vertices to create a face from.
361 tmpFace.transfer(newFace);
364 addFace(faceI, tmpFace, modifiedFace, meshMod);
366 // Starting point is also the starting point for the new face
367 newFace.append(extendedFace[startFp]);
368 newFace.append(extendedFace[fp]);
371 fp = (fp+1) % extendedFace.size();
375 if (newFace.size() > 2)
377 // Enough vertices to create a face from.
379 tmpFace.transfer(newFace);
382 addFace(faceI, tmpFace, modifiedFace, meshMod);
391 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
393 // Construct from components
394 Foam::boundaryCutter::boundaryCutter(const polyMesh& mesh)
402 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
404 Foam::boundaryCutter::~boundaryCutter()
408 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
410 void Foam::boundaryCutter::setRefinement
412 const Map<point>& pointToPos,
413 const Map<List<point> >& edgeToCuts,
414 const Map<labelPair>& faceToSplit,
415 const Map<point>& faceToFeaturePoint,
416 polyTopoChange& meshMod
419 // Clear and size maps here since mesh size will change.
420 edgeAddedPoints_.clear();
422 faceAddedPoint_.clear();
423 faceAddedPoint_.resize(faceToFeaturePoint.size());
427 // Points that just need to be moved
428 // Note: could just as well be handled outside of setRefinement.
431 forAllConstIter(Map<point>, pointToPos, iter)
440 -1, // zone for point
441 true // supports a cell
448 // Add new points along cut edges.
451 // Map from edge label to sorted list of points
452 Map<labelList> edgeToAddedPoints(edgeToCuts.size());
454 forAllConstIter(Map<List<point> >, edgeToCuts, iter)
456 label edgeI = iter.key();
458 const edge& e = mesh_.edges()[edgeI];
460 // Sorted (from start to end) list of cuts on edge
461 const List<point>& cuts = iter();
465 // point on feature to move to
466 const point& featurePoint = cuts[cutI];
473 featurePoint, // point
474 e.start(), // master point
475 -1, // zone for point
476 true // supports a cell
480 Map<labelList>::iterator fnd = edgeToAddedPoints.find(edgeI);
482 if (fnd != edgeToAddedPoints.end())
484 labelList& addedPoints = fnd();
486 label sz = addedPoints.size();
487 addedPoints.setSize(sz+1);
488 addedPoints[sz] = addedPointI;
492 edgeToAddedPoints.insert(edgeI, labelList(1, addedPointI));
497 Pout<< "Added point " << addedPointI << " for edge " << edgeI
498 << " with cuts:" << edgeToAddedPoints[edgeI] << endl;
505 // Introduce feature points.
508 forAllConstIter(Map<point>, faceToFeaturePoint, iter)
510 label faceI = iter.key();
512 const face& f = mesh_.faces()[faceI];
514 if (faceToSplit.found(faceI))
516 FatalErrorIn("boundaryCutter::setRefinement")
517 << "Face " << faceI << " vertices " << f
518 << " is both marked for face-centre decomposition and"
519 << " diagonal splitting."
520 << abort(FatalError);
523 if (mesh_.isInternalFace(faceI))
525 FatalErrorIn("boundaryCutter::setRefinement")
526 << "Face " << faceI << " vertices " << f
527 << " is not an external face. Cannot split it"
528 << abort(FatalError);
537 f[0], // master point
538 -1, // zone for point
539 true // supports a cell
542 faceAddedPoint_.insert(faceI, addedPointI);
546 Pout<< "Added point " << addedPointI << " for feature point "
547 << iter() << " on face " << faceI << " with centre "
548 << mesh_.faceCentres()[faceI] << endl;
554 // Split or retriangulate faces
558 // Maintain whether face has been updated (for -split edges
559 // -new owner/neighbour)
560 boolList faceUptodate(mesh_.nFaces(), false);
563 // Triangulate faces containing feature points
564 forAllConstIter(Map<label>, faceAddedPoint_, iter)
566 label faceI = iter.key();
568 // Get face with new points on cut edges.
569 face newFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
571 label addedPointI = iter();
573 // Information about old face
574 label patchID, zoneID, zoneFlip;
575 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
576 label own = mesh_.faceOwner()[faceI];
577 label masterPoint = mesh_.faces()[faceI][0];
579 // Triangulate face around mid point
585 label nextV = newFace.nextLabel(fp);
587 tri[0] = newFace[fp];
589 tri[2] = addedPointI;
593 // Modify the existing face.
603 patchID, // patch for face
604 false, // remove from zone
605 zoneID, // zone for face
606 zoneFlip // face zone flip
612 // Add additional faces
620 masterPoint, // master point
622 -1, // master face for addition
624 patchID, // patch for face
625 zoneID, // zone for face
626 zoneFlip // face zone flip
632 faceUptodate[faceI] = true;
636 // Diagonally split faces
637 forAllConstIter(Map<labelPair>, faceToSplit, iter)
639 label faceI = iter.key();
641 const face& f = mesh_.faces()[faceI];
643 if (faceAddedPoint_.found(faceI))
645 FatalErrorIn("boundaryCutter::setRefinement")
646 << "Face " << faceI << " vertices " << f
647 << " is both marked for face-centre decomposition and"
648 << " diagonal splitting."
649 << abort(FatalError);
653 // Get face with new points on cut edges.
654 face newFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
656 // Information about old face
657 label patchID, zoneID, zoneFlip;
658 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
659 label own = mesh_.faceOwner()[faceI];
660 label masterPoint = mesh_.faces()[faceI][0];
662 // Split face from one side of diagonal to other.
663 const labelPair& diag = iter();
665 label fp0 = findIndex(newFace, f[diag[0]]);
666 label fp1 = findIndex(newFace, f[diag[1]]);
668 if (fp0 == -1 || fp1 == -1 || fp0 == fp1)
670 FatalErrorIn("boundaryCutter::setRefinement")
671 << "Problem : Face " << faceI << " vertices " << f
672 << " newFace:" << newFace << " diagonal:" << f[diag[0]]
674 << abort(FatalError);
677 // Replace existing face by newFace from fp0 to fp1 and add new one
680 DynamicList<label> newVerts(newFace.size());
682 // Get vertices from fp0 to (and including) fp1
687 newVerts.append(newFace[fp]);
689 fp = (fp == newFace.size()-1 ? 0 : fp+1);
693 newVerts.append(newFace[fp1]);
696 // Modify the existing face.
701 face(newVerts.shrink()), // face
706 patchID, // patch for face
707 false, // remove from zone
708 zoneID, // zone for face
709 zoneFlip // face zone flip
716 // Get vertices from fp1 to (and including) fp0
720 newVerts.append(newFace[fp]);
722 fp = (fp == newFace.size()-1 ? 0 : fp+1);
726 newVerts.append(newFace[fp0]);
728 // Add additional face
733 face(newVerts.shrink()), // face
736 masterPoint, // master point
738 -1, // master face for addition
740 patchID, // patch for face
741 zoneID, // zone for face
742 zoneFlip // face zone flip
746 faceUptodate[faceI] = true;
750 // Split external faces without feature point but using cut edges.
751 // Does right handed walk but not really.
752 forAllConstIter(Map<labelList>, edgeToAddedPoints, iter)
754 label edgeI = iter.key();
756 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
760 label faceI = eFaces[i];
762 if (!faceUptodate[faceI] && !mesh_.isInternalFace(faceI))
764 // Is external face so split
765 if (splitFace(faceI, pointToPos, edgeToAddedPoints, meshMod))
768 faceUptodate[faceI] = true;
775 // Add cut edges (but don't split) any other faces using any cut edge.
776 // These can be external faces where splitFace hasn't cut them or
778 forAllConstIter(Map<labelList>, edgeToAddedPoints, iter)
780 label edgeI = iter.key();
782 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
786 label faceI = eFaces[i];
788 if (!faceUptodate[faceI])
790 // Renumber face to include split edges.
791 face newFace(addEdgeCutsToFace(faceI, edgeToAddedPoints));
793 label own = mesh_.faceOwner()[faceI];
797 if (mesh_.isInternalFace(faceI))
799 nei = mesh_.faceNeighbour()[faceI];
802 label patchID, zoneID, zoneFlip;
803 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
809 newFace, // modified face
810 faceI, // label of face being modified
814 patchID, // patch for face
815 false, // remove from zone
816 zoneID, // zone for face
817 zoneFlip // face flip in zone
821 faceUptodate[faceI] = true;
826 // Convert edge to points storage from edge labels (not preserved)
828 edgeAddedPoints_.resize(edgeToCuts.size());
830 forAllConstIter(Map<labelList>, edgeToAddedPoints, iter)
832 edgeAddedPoints_.insert(mesh_.edges()[iter.key()], iter());
837 void Foam::boundaryCutter::updateMesh(const mapPolyMesh& morphMap)
839 // Update stored labels for mesh change.
842 // Do faceToAddedPoint
846 // Create copy since we're deleting entries.
847 Map<label> newAddedPoints(faceAddedPoint_.size());
849 forAllConstIter(Map<label>, faceAddedPoint_, iter)
851 label oldFaceI = iter.key();
853 label newFaceI = morphMap.reverseFaceMap()[oldFaceI];
855 label oldPointI = iter();
857 label newPointI = morphMap.reversePointMap()[oldPointI];
859 if (newFaceI >= 0 && newPointI >= 0)
861 newAddedPoints.insert(newFaceI, newPointI);
866 faceAddedPoint_.transfer(newAddedPoints);
871 // Do edgeToAddedPoints
876 // Create copy since we're deleting entries
877 HashTable<labelList, edge, Hash<edge> >
878 newEdgeAddedPoints(edgeAddedPoints_.size());
882 HashTable<labelList, edge, Hash<edge> >::const_iterator iter =
883 edgeAddedPoints_.begin();
884 iter != edgeAddedPoints_.end();
888 const edge& e = iter.key();
890 label newStart = morphMap.reversePointMap()[e.start()];
892 label newEnd = morphMap.reversePointMap()[e.end()];
894 if (newStart >= 0 && newEnd >= 0)
896 const labelList& addedPoints = iter();
898 labelList newAddedPoints(addedPoints.size());
901 forAll(addedPoints, i)
903 label newAddedPointI =
904 morphMap.reversePointMap()[addedPoints[i]];
906 if (newAddedPointI >= 0)
908 newAddedPoints[newI++] = newAddedPointI;
913 newAddedPoints.setSize(newI);
915 edge newE = edge(newStart, newEnd);
917 newEdgeAddedPoints.insert(newE, newAddedPoints);
923 edgeAddedPoints_.transfer(newEdgeAddedPoints);
928 // ************************************************************************* //