1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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
25 \*---------------------------------------------------------------------------*/
27 #include "combineFaces.H"
29 #include "polyTopoChange.H"
30 #include "polyRemoveFace.H"
31 #include "polyAddFace.H"
32 #include "polyModifyFace.H"
33 #include "polyRemovePoint.H"
34 #include "polyAddPoint.H"
35 #include "syncTools.H"
36 #include "meshTools.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 defineTypeNameAndDebug(combineFaces, 0);
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 // Test face for (almost) convexeness. Allows certain convexity before
51 // For every two consecutive edges calculate the normal. If it differs too
52 // much from the average face normal complain.
53 bool Foam::combineFaces::convexFace
55 const scalar minConcaveCos,
56 const pointField& points,
60 // Get outwards pointing normal of f.
61 vector n = f.normal(points);
64 // Get edge from f[0] to f[size-1];
65 vector ePrev(points[f[0]] - points[f[f.size()-1]]);
66 scalar magEPrev = mag(ePrev);
67 ePrev /= magEPrev + VSMALL;
71 // Get vertex after fp
72 label fp1 = (fp0 + 1) % f.size();
74 // Normalized vector between two consecutive points
75 vector e10(points[f[fp1]] - points[f[fp0]]);
76 scalar magE10 = mag(e10);
77 e10 /= magE10 + VSMALL;
79 if (magEPrev > SMALL && magE10 > SMALL)
81 vector edgeNormal = ePrev ^ e10;
83 if ((edgeNormal & n) < 0)
85 // Concave. Check angle.
86 if ((ePrev & e10) < minConcaveCos)
97 // Not a single internal angle is concave so face is convex.
102 // Determines if set of faces is valid to collapse into single face.
103 bool Foam::combineFaces::validFace
105 const scalar minConcaveCos,
106 const indirectPrimitivePatch& bigFace
109 // Get outside vertices (in local vertex numbering)
110 const labelListList& edgeLoops = bigFace.edgeLoops();
112 if (edgeLoops.size() > 1)
117 // Check for convexness
118 face f(getOutsideFace(bigFace));
120 return convexFace(minConcaveCos, bigFace.points(), f);
124 void Foam::combineFaces::regioniseFaces
128 Map<label>& faceRegion
131 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
132 const labelList& cEdges = mesh_.cellEdges()[cellI];
136 label edgeI = cEdges[i];
139 meshTools::getEdgeFaces(mesh_, cellI, edgeI, f0, f1);
141 label p0 = patches.whichPatch(f0);
142 label p1 = patches.whichPatch(f1);
144 // Face can be merged if
145 // - same non-coupled patch
147 if (p0 != -1 && p0 == p1 && !patches[p0].coupled())
149 vector f0Normal = mesh_.faceAreas()[f0];
150 f0Normal /= mag(f0Normal);
151 vector f1Normal = mesh_.faceAreas()[f1];
152 f1Normal /= mag(f1Normal);
154 if ((f0Normal&f1Normal) > minCos)
156 Map<label>::const_iterator f0Fnd = faceRegion.find(f0);
159 if (f0Fnd != faceRegion.end())
164 Map<label>::const_iterator f1Fnd = faceRegion.find(f1);
167 if (f1Fnd != faceRegion.end())
176 label useRegion = faceRegion.size();
177 faceRegion.insert(f0, useRegion);
178 faceRegion.insert(f1, useRegion);
182 faceRegion.insert(f0, region1);
189 faceRegion.insert(f1, region0);
191 else if (region0 != region1)
193 // Merge the two regions
194 label useRegion = min(region0, region1);
195 label freeRegion = max(region0, region1);
197 forAllIter(Map<label>, faceRegion, iter)
199 if (iter() == freeRegion)
212 bool Foam::combineFaces::faceNeighboursValid
215 const Map<label>& faceRegion
218 if (faceRegion.size() <= 1)
223 const labelListList& faceEdges = mesh_.faceEdges();
224 const cell& cFaces = mesh_.cells()[cellI];
226 // Test for face collapsing to edge since too many neighbours merged.
227 forAll(cFaces, cFaceI)
229 label faceI = cFaces[cFaceI];
231 if (!faceRegion.found(faceI))
233 const labelList& fEdges = faceEdges[faceI];
235 // Count number of remaining faces neighbouring faceI. This has
238 // Unregioned neighbouring faces
239 DynamicList<label> neighbourFaces(cFaces.size());
240 // Regioned neighbouring faces
241 labelHashSet neighbourRegions;
245 label edgeI = fEdges[i];
246 label nbrI = meshTools::otherFace(mesh_, cellI, faceI, edgeI);
248 Map<label>::const_iterator iter = faceRegion.find(nbrI);
250 if (iter == faceRegion.end())
252 if (findIndex(neighbourFaces, nbrI) == -1)
254 neighbourFaces.append(nbrI);
259 neighbourRegions.insert(iter());
263 if ((neighbourFaces.size()+neighbourRegions.size()) < 3)
273 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
275 // Construct from mesh
276 Foam::combineFaces::combineFaces
278 const polyMesh& mesh,
285 faceSetsVertices_(0),
286 savedPointLabels_(0),
291 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
293 Foam::labelListList Foam::combineFaces::getMergeSets
295 const scalar featureCos,
296 const scalar minConcaveCos,
297 const labelHashSet& boundaryCells
300 // Lists of faces that can be merged.
301 DynamicList<labelList> allFaceSets(boundaryCells.size() / 10);
303 // On all cells regionise the faces
304 forAllConstIter(labelHashSet, boundaryCells, iter)
306 label cellI = iter.key();
308 const cell& cFaces = mesh_.cells()[cellI];
311 Map<label> faceRegion(cFaces.size());
312 regioniseFaces(featureCos, cellI, faceRegion);
314 // Now we have in faceRegion for every face the region with planar
315 // face sharing the same region. We now check whether the resulting
317 // - to become a set of edges since too many faces are merged.
318 // - to become convex
320 if (faceNeighboursValid(cellI, faceRegion))
322 // Create region-to-faces addressing
323 Map<labelList> regionToFaces(faceRegion.size());
325 forAllConstIter(Map<label>, faceRegion, iter)
327 label faceI = iter.key();
328 label region = iter();
330 Map<labelList>::iterator regionFnd = regionToFaces.find(region);
332 if (regionFnd != regionToFaces.end())
334 labelList& setFaces = regionFnd();
335 label sz = setFaces.size();
336 setFaces.setSize(sz+1);
337 setFaces[sz] = faceI;
341 regionToFaces.insert(region, labelList(1, faceI));
345 // For every set check if it forms a valid convex face
347 forAllConstIter(Map<labelList>, regionToFaces, iter)
349 // Make face out of setFaces
350 indirectPrimitivePatch bigFace
360 // Only store if -only one outside loop -which forms convex face
361 if (validFace(minConcaveCos, bigFace))
363 allFaceSets.append(iter());
369 return allFaceSets.shrink();
373 Foam::labelListList Foam::combineFaces::getMergeSets
375 const scalar featureCos,
376 const scalar minConcaveCos
379 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
381 // Pick up all cells on boundary
382 labelHashSet boundaryCells(mesh_.nFaces()-mesh_.nInternalFaces());
384 forAll(patches, patchI)
386 const polyPatch& patch = patches[patchI];
388 if (!patch.coupled())
392 boundaryCells.insert(mesh_.faceOwner()[patch.start()+i]);
397 return getMergeSets(featureCos, minConcaveCos, boundaryCells);
401 // Gets outside edgeloop as a face
402 // - in same order as faces
403 // - in mesh vertex labels
404 Foam::face Foam::combineFaces::getOutsideFace
406 const indirectPrimitivePatch& fp
409 if (fp.edgeLoops().size() != 1)
413 "combineFaces::getOutsideFace(const indirectPrimitivePatch&)"
414 ) << "Multiple outside loops:" << fp.edgeLoops()
415 << abort(FatalError);
418 // Get first boundary edge. Since guaranteed one edgeLoop when in here this
419 // edge must be on it.
420 label bEdgeI = fp.nInternalEdges();
422 const edge& e = fp.edges()[bEdgeI];
424 const labelList& eFaces = fp.edgeFaces()[bEdgeI];
426 if (eFaces.size() != 1)
430 "combineFaces::getOutsideFace(const indirectPrimitivePatch&)"
431 ) << "boundary edge:" << bEdgeI
432 << " points:" << fp.meshPoints()[e[0]]
433 << ' ' << fp.meshPoints()[e[1]]
434 << " on indirectPrimitivePatch has " << eFaces.size()
435 << " faces using it" << abort(FatalError);
440 const labelList& outsideLoop = fp.edgeLoops()[0];
443 // Get order of edge e in outside loop
444 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
446 // edgeLoopConsistent : true = edge in same order as outsideloop
447 // false = opposite order
448 bool edgeLoopConsistent = false;
451 label index0 = findIndex(outsideLoop, e[0]);
452 label index1 = findIndex(outsideLoop, e[1]);
454 if (index0 == -1 || index1 == -1)
458 "combineFaces::getOutsideFace"
459 "(const indirectPrimitivePatch&)"
460 ) << "Cannot find boundary edge:" << e
461 << " points:" << fp.meshPoints()[e[0]]
462 << ' ' << fp.meshPoints()[e[1]]
463 << " in edgeLoop:" << outsideLoop << abort(FatalError);
465 else if (index1 == outsideLoop.fcIndex(index0))
467 edgeLoopConsistent = true;
469 else if (index0 == outsideLoop.fcIndex(index1))
471 edgeLoopConsistent = false;
477 "combineFaces::getOutsideFace"
478 "(const indirectPrimitivePatch&)"
479 ) << "Cannot find boundary edge:" << e
480 << " points:" << fp.meshPoints()[e[0]]
481 << ' ' << fp.meshPoints()[e[1]]
482 << " on consecutive points in edgeLoop:"
483 << outsideLoop << abort(FatalError);
488 // Get face in local vertices
489 const face& localF = fp.localFaces()[eFaces[0]];
491 // Get order of edge in localF
492 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
494 // faceEdgeConsistent : true = edge in same order as localF
495 // false = opposite order
496 bool faceEdgeConsistent = false;
499 // Find edge in face.
500 label index = findIndex(fp.faceEdges()[eFaces[0]], bEdgeI);
506 "combineFaces::getOutsideFace"
507 "(const indirectPrimitivePatch&)"
508 ) << "Cannot find boundary edge:" << e
509 << " points:" << fp.meshPoints()[e[0]]
510 << ' ' << fp.meshPoints()[e[1]]
511 << " in face:" << eFaces[0]
512 << " edges:" << fp.faceEdges()[eFaces[0]]
513 << abort(FatalError);
515 else if (localF[index] == e[0] && localF.nextLabel(index) == e[1])
517 faceEdgeConsistent = true;
519 else if (localF[index] == e[1] && localF.nextLabel(index) == e[0])
521 faceEdgeConsistent = false;
527 "combineFaces::getOutsideFace"
528 "(const indirectPrimitivePatch&)"
529 ) << "Cannot find boundary edge:" << e
530 << " points:" << fp.meshPoints()[e[0]]
531 << ' ' << fp.meshPoints()[e[1]]
532 << " in face:" << eFaces[0] << " verts:" << localF
533 << abort(FatalError);
537 // Get face in mesh points.
538 face meshFace(renumber(fp.meshPoints(), outsideLoop));
540 if (faceEdgeConsistent != edgeLoopConsistent)
548 void Foam::combineFaces::setRefinement
550 const labelListList& faceSets,
551 polyTopoChange& meshMod
556 masterFace_.setSize(faceSets.size());
557 faceSetsVertices_.setSize(faceSets.size());
558 forAll(faceSets, setI)
560 const labelList& setFaces = faceSets[setI];
562 masterFace_[setI] = setFaces[0];
563 faceSetsVertices_[setI] = IndirectList<face>
571 // Running count of number of faces using a point
572 labelList nPointFaces(mesh_.nPoints(), 0);
574 const labelListList& pointFaces = mesh_.pointFaces();
576 forAll(pointFaces, pointI)
578 nPointFaces[pointI] = pointFaces[pointI].size();
581 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
583 forAll(faceSets, setI)
585 const labelList& setFaces = faceSets[setI];
592 label patchI = patches.whichPatch(setFaces[i]);
594 if (patchI == -1 || patches[patchI].coupled())
598 "combineFaces::setRefinement"
599 "(const bool, const labelListList&"
601 ) << "Can only merge non-coupled boundary faces"
602 << " but found internal or coupled face:"
603 << setFaces[i] << " in set " << setI
604 << abort(FatalError);
609 // Make face out of setFaces
610 indirectPrimitivePatch bigFace
620 // Get outside vertices (in local vertex numbering)
621 const labelListList& edgeLoops = bigFace.edgeLoops();
623 if (edgeLoops.size() != 1)
627 "combineFaces::setRefinement"
628 "(const bool, const labelListList&, polyTopoChange&)"
629 ) << "Faces to-be-merged " << setFaces
630 << " do not form a single big face." << nl
631 << abort(FatalError);
635 // Delete all faces except master, whose face gets modified.
637 // Modify master face
638 // ~~~~~~~~~~~~~~~~~~
640 label masterFaceI = setFaces[0];
642 // Get outside face in mesh vertex labels
643 face outsideFace(getOutsideFace(bigFace));
645 label zoneID = mesh_.faceZones().whichZone(masterFaceI);
647 bool zoneFlip = false;
651 const faceZone& fZone = mesh_.faceZones()[zoneID];
653 zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
656 label patchI = mesh_.boundaryMesh().whichPatch(masterFaceI);
662 outsideFace, // modified face
663 masterFaceI, // label of face being modified
664 mesh_.faceOwner()[masterFaceI], // owner
667 patchI, // patch for face
668 false, // remove from zone
669 zoneID, // zone for face
670 zoneFlip // face flip in zone
675 // Delete all non-master faces
676 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
678 for (label i = 1; i < setFaces.size(); i++)
680 meshMod.setAction(polyRemoveFace(setFaces[i]));
684 // Mark unused points for deletion
685 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
687 // Remove count of all faces combined
690 const face& f = mesh_.faces()[setFaces[i]];
694 nPointFaces[f[fp]]--;
697 // But keep count on new outside face
698 forAll(outsideFace, fp)
700 nPointFaces[outsideFace[fp]]++;
705 // If one or more processors use the point it needs to be kept.
706 syncTools::syncPointList
712 false // no separation
715 // Remove all unused points. Store position if undoable.
718 forAll(nPointFaces, pointI)
720 if (nPointFaces[pointI] == 0)
722 meshMod.setAction(polyRemovePoint(pointI));
728 // Count removed points
730 forAll(nPointFaces, pointI)
732 if (nPointFaces[pointI] == 0)
738 savedPointLabels_.setSize(n);
739 savedPoints_.setSize(n);
740 Map<label> meshToSaved(2*n);
742 // Remove points and store position
744 forAll(nPointFaces, pointI)
746 if (nPointFaces[pointI] == 0)
748 meshMod.setAction(polyRemovePoint(pointI));
750 savedPointLabels_[n] = pointI;
751 savedPoints_[n] = mesh_.points()[pointI];
753 meshToSaved.insert(pointI, n);
758 // Update stored vertex labels. Negative indices index into local points
759 forAll(faceSetsVertices_, setI)
761 faceList& setFaces = faceSetsVertices_[setI];
765 face& f = setFaces[i];
769 label pointI = f[fp];
771 if (nPointFaces[pointI] == 0)
773 f[fp] = -meshToSaved[pointI]-1;
782 void Foam::combineFaces::updateMesh(const mapPolyMesh& map)
786 // Master face just renumbering of point labels
787 inplaceRenumber(map.reverseFaceMap(), masterFace_);
789 // Stored faces refer to backed-up vertices (not changed)
790 // and normal vertices (need to be renumbered)
791 forAll(faceSetsVertices_, setI)
793 faceList& faces = faceSetsVertices_[setI];
797 // Note: faces[i] can have negative elements.
802 label pointI = f[fp];
806 f[fp] = map.reversePointMap()[pointI];
812 "combineFaces::updateMesh"
813 "(const mapPolyMesh&)"
814 ) << "In set " << setI << " at position " << i
815 << " with master face "
816 << masterFace_[setI] << nl
817 << "the points of the slave face " << faces[i]
818 << " don't exist anymore."
819 << abort(FatalError);
829 // Note that faces on coupled patches are never combined (or at least
830 // getMergeSets never picks them up. Thus the points on them will never get
831 // deleted since still used by the coupled faces. So never a risk of undoing
832 // things (faces/points) on coupled patches.
833 void Foam::combineFaces::setUnrefinement
835 const labelList& masterFaces,
836 polyTopoChange& meshMod,
837 Map<label>& restoredPoints,
838 Map<label>& restoredFaces,
839 Map<label>& restoredCells
846 "combineFaces::setUnrefinement"
847 "(const labelList&, polyTopoChange&"
848 ", Map<label>&, Map<label>&, Map<label>&)"
849 ) << "Can only call setUnrefinement if constructed with"
850 << " unrefinement capability." << exit(FatalError);
855 labelList addedPoints(savedPoints_.size(), -1);
857 // Invert set-to-master-face
858 Map<label> masterToSet(masterFace_.size());
860 forAll(masterFace_, setI)
862 if (masterFace_[setI] >= 0)
864 masterToSet.insert(masterFace_[setI], setI);
868 forAll(masterFaces, i)
870 label masterFaceI = masterFaces[i];
872 Map<label>::const_iterator iter = masterToSet.find(masterFaceI);
874 if (iter == masterToSet.end())
878 "combineFaces::setUnrefinement"
879 "(const labelList&, polyTopoChange&"
880 ", Map<label>&, Map<label>&, Map<label>&)"
881 ) << "Master face " << masterFaceI
882 << " is not the master of one of the merge sets"
883 << " or has already been merged"
884 << abort(FatalError);
890 // Update faces of the merge setI for reintroduced vertices
891 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
893 faceList& faces = faceSetsVertices_[setI];
895 if (faces.size() == 0)
899 "combineFaces::setUnrefinement"
900 "(const labelList&, polyTopoChange&"
901 ", Map<label>&, Map<label>&, Map<label>&)"
902 ) << "Set " << setI << " with master face " << masterFaceI
903 << " has already been merged." << abort(FatalError);
912 label pointI = f[fp];
916 label localI = -pointI-1;
918 if (addedPoints[localI] == -1)
920 // First occurrence of saved point. Reintroduce point
921 addedPoints[localI] = meshMod.setAction
925 savedPoints_[localI], // point
927 -1, // zone for point
928 true // supports a cell
931 restoredPoints.insert
933 addedPoints[localI], // current point label
934 savedPointLabels_[localI] // point label when it
938 f[fp] = addedPoints[localI];
947 label own = mesh_.faceOwner()[masterFaceI];
948 label zoneID = mesh_.faceZones().whichZone(masterFaceI);
949 bool zoneFlip = false;
952 const faceZone& fZone = mesh_.faceZones()[zoneID];
953 zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
955 label patchI = mesh_.boundaryMesh().whichPatch(masterFaceI);
957 if (mesh_.boundaryMesh()[patchI].coupled())
961 "combineFaces::setUnrefinement"
962 "(const labelList&, polyTopoChange&"
963 ", Map<label>&, Map<label>&, Map<label>&)"
964 ) << "Master face " << masterFaceI << " is on coupled patch "
965 << mesh_.boundaryMesh()[patchI].name()
966 << abort(FatalError);
969 //Pout<< "Restoring new master face " << masterFaceI
970 // << " to vertices " << faces[0] << endl;
972 // Modify the master face.
977 faces[0], // original face
978 masterFaceI, // label of face
982 patchI, // patch for face
983 false, // remove from zone
984 zoneID, // zone for face
985 zoneFlip // face flip in zone
989 // Add the previously removed faces
990 for (label i = 1; i < faces.size(); i++)
992 //Pout<< "Restoring removed face with vertices " << faces[i]
999 faces[i], // vertices
1002 -1, // masterPointID,
1003 -1, // masterEdgeID,
1004 masterFaceI, // masterFaceID,
1005 false, // flipFaceFlux,
1008 zoneFlip // zoneFlip
1013 // Clear out restored set
1014 faceSetsVertices_[setI].clear();
1015 masterFace_[setI] = -1;
1020 // ************************************************************************* //