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 "removeFaces.H"
29 #include "polyTopoChange.H"
30 #include "meshTools.H"
31 #include "polyModifyFace.H"
32 #include "polyRemoveFace.H"
33 #include "polyRemoveCell.H"
34 #include "polyRemovePoint.H"
35 #include "syncTools.H"
37 #include "indirectPrimitivePatch.H"
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
46 defineTypeNameAndDebug(removeFaces, 0);
50 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
52 // Changes region of connected set of cells. Can be recursive since hopefully
53 // only small area of faces removed in one go.
54 void Foam::removeFaces::changeCellRegion
57 const label oldRegion,
58 const label newRegion,
62 if (cellRegion[cellI] == oldRegion)
64 cellRegion[cellI] = newRegion;
66 // Step to neighbouring cells
68 const labelList& cCells = mesh_.cellCells()[cellI];
72 changeCellRegion(cCells[i], oldRegion, newRegion, cellRegion);
78 // Changes region of connected set of faces. Returns number of changed faces.
79 Foam::label Foam::removeFaces::changeFaceRegion
81 const labelList& cellRegion,
82 const boolList& removedFace,
83 const labelList& nFacesPerEdge,
85 const label newRegion,
91 if (faceRegion[faceI] == -1 && !removedFace[faceI])
93 faceRegion[faceI] = newRegion;
97 // Step to neighbouring faces across edges that will get removed
99 const labelList& fEdges = mesh_.faceEdges()[faceI];
103 label edgeI = fEdges[i];
105 if (nFacesPerEdge[edgeI] >= 0 && nFacesPerEdge[edgeI] <= 2)
107 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
111 nChanged += changeFaceRegion
128 // Mark all faces affected in any way by
129 // - removal of cells
130 // - removal of faces
131 // - removal of edges
132 // - removal of points
133 Foam::boolList Foam::removeFaces::getFacesAffected
135 const labelList& cellRegion,
136 const labelList& cellRegionMaster,
137 const labelList& facesToRemove,
138 const labelHashSet& edgesToRemove,
139 const labelHashSet& pointsToRemove
142 boolList affectedFace(mesh_.nFaces(), false);
144 // Mark faces affected by removal of cells
145 forAll(cellRegion, cellI)
147 label region = cellRegion[cellI];
149 if (region != -1 && (cellI != cellRegionMaster[region]))
151 const labelList& cFaces = mesh_.cells()[cellI];
153 forAll(cFaces, cFaceI)
155 affectedFace[cFaces[cFaceI]] = true;
160 // Mark faces affected by removal of face.
161 forAll(facesToRemove, i)
163 affectedFace[facesToRemove[i]] = true;
166 // Mark faces affected by removal of edges
167 forAllConstIter(labelHashSet, edgesToRemove, iter)
169 const labelList& eFaces = mesh_.edgeFaces()[iter.key()];
171 forAll(eFaces, eFaceI)
173 affectedFace[eFaces[eFaceI]] = true;
177 // Mark faces affected by removal of points
178 forAllConstIter(labelHashSet, pointsToRemove, iter)
180 label pointI = iter.key();
182 const labelList& pFaces = mesh_.pointFaces()[pointI];
184 forAll(pFaces, pFaceI)
186 affectedFace[pFaces[pFaceI]] = true;
193 void Foam::removeFaces::writeOBJ
195 const indirectPrimitivePatch& fp,
196 const fileName& fName
200 Pout<< "removeFaces::writeOBJ : Writing faces to file "
201 << str.name() << endl;
203 const pointField& localPoints = fp.localPoints();
205 forAll(localPoints, i)
207 meshTools::writeOBJ(str, localPoints[i]);
210 const faceList& localFaces = fp.localFaces();
212 forAll(localFaces, i)
214 const face& f = localFaces[i];
220 str<< ' ' << f[fp]+1;
227 // Inserts commands to merge faceLabels into one face.
228 void Foam::removeFaces::mergeFaces
230 const labelList& cellRegion,
231 const labelList& cellRegionMaster,
232 const labelHashSet& pointsToRemove,
233 const labelList& faceLabels,
234 polyTopoChange& meshMod
237 // Construct addressing engine from faceLabels (in order of faceLabels as
239 indirectPrimitivePatch fp
249 // Get outside vertices (in local vertex numbering)
251 if (fp.edgeLoops().size() != 1)
253 writeOBJ(fp, mesh_.time().path()/"facesToBeMerged.obj");
254 FatalErrorIn("removeFaces::mergeFaces")
255 << "Cannot merge faces " << faceLabels
256 << " into single face since outside vertices " << fp.edgeLoops()
257 << " do not form single loop but form " << fp.edgeLoops().size()
258 << " loops instead." << abort(FatalError);
261 const labelList& edgeLoop = fp.edgeLoops()[0];
263 // Get outside vertices in order of one of the faces in faceLabels.
264 // (this becomes the master face)
265 // Find the first face that uses edgeLoop[0] and edgeLoop[1] as consecutive
268 label masterIndex = -1;
269 bool reverseLoop = false;
271 const labelList& pFaces = fp.pointFaces()[edgeLoop[0]];
273 // Find face among pFaces which uses edgeLoop[1]
276 label faceI = pFaces[i];
278 const face& f = fp.localFaces()[faceI];
280 label index1 = findIndex(f, edgeLoop[1]);
284 // Check whether consecutive to edgeLoop[0]
285 label index0 = findIndex(f, edgeLoop[0]);
289 if (index1 == f.fcIndex(index0))
295 else if (index1 == f.rcIndex(index0))
305 if (masterIndex == -1)
307 writeOBJ(fp, mesh_.time().path()/"facesToBeMerged.obj");
308 FatalErrorIn("removeFaces::mergeFaces")
309 << "Problem" << abort(FatalError);
313 // Modify the master face.
314 // ~~~~~~~~~~~~~~~~~~~~~~~
316 // Modify first face.
317 label faceI = faceLabels[masterIndex];
319 label own = mesh_.faceOwner()[faceI];
321 if (cellRegion[own] != -1)
323 own = cellRegionMaster[cellRegion[own]];
326 label patchID, zoneID, zoneFlip;
328 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
332 if (mesh_.isInternalFace(faceI))
334 nei = mesh_.faceNeighbour()[faceI];
336 if (cellRegion[nei] != -1)
338 nei = cellRegionMaster[cellRegion[nei]];
343 DynamicList<label> faceVerts(edgeLoop.size());
347 label pointI = fp.meshPoints()[edgeLoop[i]];
349 if (pointsToRemove.found(pointI))
351 //Pout<< "**Removing point " << pointI << " from "
352 // << edgeLoop << endl;
356 faceVerts.append(pointI);
361 mergedFace.transfer(faceVerts.shrink());
370 // Pout<< "Modifying masterface " << faceI
371 // << " from faces:" << faceLabels
372 // << " old verts:" << IndirectList<face>(mesh_.faces(), faceLabels)
373 // << " for new verts:"
375 // << " possibly new owner " << own
376 // << " or new nei " << nei
382 mergedFace, // modified face
383 faceI, // label of face being modified
387 patchID, // patch for face
388 false, // remove from zone
389 zoneID, // zone for face
390 zoneFlip, // face flip in zone
396 // Remove all but master face.
397 forAll(faceLabels, patchFaceI)
399 if (patchFaceI != masterIndex)
401 //Pout<< "Removing face " << faceLabels[patchFaceI] << endl;
403 meshMod.setAction(polyRemoveFace(faceLabels[patchFaceI], faceI));
409 // Get patch, zone info for faceI
410 void Foam::removeFaces::getFaceInfo
421 if (!mesh_.isInternalFace(faceI))
423 patchID = mesh_.boundaryMesh().whichPatch(faceI);
426 zoneID = mesh_.faceZones().whichZone(faceI);
432 const faceZone& fZone = mesh_.faceZones()[zoneID];
434 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
439 // Return face with all pointsToRemove removed.
440 Foam::face Foam::removeFaces::filterFace
442 const labelHashSet& pointsToRemove,
446 const face& f = mesh_.faces()[faceI];
448 labelList newFace(f.size(), -1);
456 if (!pointsToRemove.found(vertI))
458 newFace[newFp++] = vertI;
462 newFace.setSize(newFp);
464 return face(newFace);
468 // Wrapper for meshMod.modifyFace. Reverses face if own>nei.
469 void Foam::removeFaces::modFace
472 const label masterFaceID,
475 const bool flipFaceFlux,
476 const label newPatchID,
477 const bool removeFromZone,
481 polyTopoChange& meshMod
484 if ((nei == -1) || (own < nei))
488 // Pout<< "ModifyFace (unreversed) :"
489 // << " faceI:" << masterFaceID
493 // << " flipFaceFlux:" << flipFaceFlux
494 // << " newPatchID:" << newPatchID
495 // << " removeFromZone:" << removeFromZone
496 // << " zoneID:" << zoneID
497 // << " zoneFlip:" << zoneFlip
506 masterFaceID, // label of face being modified
509 flipFaceFlux, // face flip
510 newPatchID, // patch for face
511 removeFromZone, // remove from zone
512 zoneID, // zone for face
513 zoneFlip // face flip in zone
521 // Pout<< "ModifyFace (!reversed) :"
522 // << " faceI:" << masterFaceID
523 // << " f:" << f.reverseFace()
526 // << " flipFaceFlux:" << flipFaceFlux
527 // << " newPatchID:" << newPatchID
528 // << " removeFromZone:" << removeFromZone
529 // << " zoneID:" << zoneID
530 // << " zoneFlip:" << zoneFlip
538 f.reverseFace(),// modified face
539 masterFaceID, // label of face being modified
542 flipFaceFlux, // face flip
543 newPatchID, // patch for face
544 removeFromZone, // remove from zone
545 zoneID, // zone for face
546 zoneFlip // face flip in zone
553 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
555 // Construct from mesh
556 Foam::removeFaces::removeFaces
558 const polyMesh& mesh,
567 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
569 // Removing face connects cells. This function works out a consistent set of
571 // - returns faces to remove. Can be extended with additional faces
572 // (if owner would become neighbour)
573 // - sets cellRegion to -1 or to region number
574 // - regionMaster contains for every region number a master cell.
575 Foam::label Foam::removeFaces::compatibleRemoves
577 const labelList& facesToRemove,
578 labelList& cellRegion,
579 labelList& regionMaster,
580 labelList& newFacesToRemove
583 const labelList& faceOwner = mesh_.faceOwner();
584 const labelList& faceNeighbour = mesh_.faceNeighbour();
586 cellRegion.setSize(mesh_.nCells());
589 regionMaster.setSize(mesh_.nCells());
594 forAll(facesToRemove, i)
596 label faceI = facesToRemove[i];
598 if (!mesh_.isInternalFace(faceI))
602 "removeFaces::compatibleRemoves(const labelList&"
603 ", labelList&, labelList&, labelList&)"
604 ) << "Not internal face:" << faceI << abort(FatalError);
608 label own = faceOwner[faceI];
609 label nei = faceNeighbour[faceI];
611 label region0 = cellRegion[own];
612 label region1 = cellRegion[nei];
619 cellRegion[own] = nRegions;
620 cellRegion[nei] = nRegions;
622 // Make owner (lowest numbered!) the master of the region
623 regionMaster[nRegions] = own;
628 // Add owner to neighbour region
629 cellRegion[own] = region1;
630 // See if owner becomes the master of the region
631 regionMaster[region1] = min(own, regionMaster[region1]);
638 // Add neighbour to owner region
639 cellRegion[nei] = region0;
640 // nei is higher numbered than own so guaranteed not lower
641 // than master of region0.
643 else if (region0 != region1)
645 // Both have regions. Keep lowest numbered region and master.
646 label freedRegion = -1;
647 label keptRegion = -1;
649 if (region0 < region1)
654 region1, // old region
655 region0, // new region
659 keptRegion = region0;
660 freedRegion = region1;
662 else if (region1 < region0)
667 region0, // old region
668 region1, // new region
672 keptRegion = region1;
673 freedRegion = region0;
676 label master0 = regionMaster[region0];
677 label master1 = regionMaster[region1];
679 regionMaster[freedRegion] = -1;
680 regionMaster[keptRegion] = min(master0, master1);
685 regionMaster.setSize(nRegions);
689 // - master is lowest numbered in any region
690 // - regions have more than 1 cell
692 labelList nCells(regionMaster.size(), 0);
694 forAll(cellRegion, cellI)
696 label r = cellRegion[cellI];
702 if (cellI < regionMaster[r])
706 "removeFaces::compatibleRemoves(const labelList&"
707 ", labelList&, labelList&, labelList&)"
708 ) << "Not lowest numbered : cell:" << cellI
710 << " regionmaster:" << regionMaster[r]
711 << abort(FatalError);
716 forAll(nCells, region)
718 if (nCells[region] == 1)
722 "removeFaces::compatibleRemoves(const labelList&"
723 ", labelList&, labelList&, labelList&)"
724 ) << "Region " << region
725 << " has only " << nCells[region] << " cells in it"
726 << abort(FatalError);
732 // Count number of used regions
733 label nUsedRegions = 0;
735 forAll(regionMaster, i)
737 if (regionMaster[i] != -1)
743 // Recreate facesToRemove to be consistent with the cellRegions.
744 DynamicList<label> allFacesToRemove(facesToRemove.size());
746 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
748 label own = faceOwner[faceI];
749 label nei = faceNeighbour[faceI];
751 if (cellRegion[own] != -1 && cellRegion[own] == cellRegion[nei])
753 // Both will become the same cell so add face to list of faces
755 allFacesToRemove.append(faceI);
759 newFacesToRemove.transfer(allFacesToRemove.shrink());
760 allFacesToRemove.clear();
766 void Foam::removeFaces::setRefinement
768 const labelList& faceLabels,
769 const labelList& cellRegion,
770 const labelList& cellRegionMaster,
771 polyTopoChange& meshMod
776 faceSet facesToRemove(mesh_, "facesToRemove", faceLabels);
777 Pout<< "Writing faces to remove to faceSet " << facesToRemove.name()
779 facesToRemove.write();
782 // Make map of all faces to be removed
783 boolList removedFace(mesh_.nFaces(), false);
785 forAll(faceLabels, i)
787 label faceI = faceLabels[i];
789 if (!mesh_.isInternalFace(faceI))
793 "removeFaces::setRefinement(const labelList&"
794 ", const labelList&, const labelList&, polyTopoChange&)"
795 ) << "Face to remove is not internal face:" << faceI
796 << abort(FatalError);
799 removedFace[faceI] = true;
803 // Edges to be removed
804 // ~~~~~~~~~~~~~~~~~~~
808 labelHashSet edgesToRemove(faceLabels.size());
810 // Per face the region it is. -1 for removed faces, -2 for regions
811 // consisting of single face only.
812 labelList faceRegion(mesh_.nFaces(), -1);
814 // Number of connected face regions
819 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
821 // Usage of edges by non-removed faces.
822 // See below about initialization.
823 labelList nFacesPerEdge(mesh_.nEdges(), -1);
825 // Count usage of edges by non-removed faces.
826 forAll(faceLabels, i)
828 label faceI = faceLabels[i];
830 const labelList& fEdges = mesh_.faceEdges()[faceI];
834 label edgeI = fEdges[i];
836 if (nFacesPerEdge[edgeI] == -1)
838 nFacesPerEdge[edgeI] =
839 mesh_.edgeFaces()[edgeI].size()-1;
843 nFacesPerEdge[edgeI]--;
848 // Count usage for edges not on faces-to-be-removed.
849 // Note that this only needs to be done for possibly coupled edges
850 // so we could choose to loop only over boundary faces and use faceEdges
852 const labelListList& edgeFaces = mesh_.edgeFaces();
854 forAll(edgeFaces, edgeI)
856 if (nFacesPerEdge[edgeI] == -1)
858 // Edge not yet handled in loop above so is not used by any
859 // face to be removed.
861 const labelList& eFaces = edgeFaces[edgeI];
863 if (eFaces.size() > 2)
865 nFacesPerEdge[edgeI] = eFaces.size();
867 else if (eFaces.size() == 2)
869 // nFacesPerEdge already -1 so do nothing.
873 const edge& e = mesh_.edges()[edgeI];
875 FatalErrorIn("removeFaces::setRefinement")
876 << "Problem : edge has too few face neighbours:"
880 << " coords:" << mesh_.points()[e[0]]
881 << mesh_.points()[e[1]]
882 << abort(FatalError);
891 OFstream str(mesh_.time().path()/"edgesWithTwoFaces.obj");
892 Pout<< "Dumping edgesWithTwoFaces to " << str.name() << endl;
895 forAll(nFacesPerEdge, edgeI)
897 if (nFacesPerEdge[edgeI] == 2)
899 // Edge will get removed.
900 const edge& e = mesh_.edges()[edgeI];
902 meshTools::writeOBJ(str, mesh_.points()[e[0]]);
904 meshTools::writeOBJ(str, mesh_.points()[e[1]]);
906 str<< "l " << vertI-1 << ' ' << vertI << nl;
912 // Now all unaffected edges will have labelMax, all affected edges the
913 // number of unremoved faces.
915 // Filter for edges inbetween two remaining boundary faces that
916 // make too big an angle.
917 forAll(nFacesPerEdge, edgeI)
919 if (nFacesPerEdge[edgeI] == 2)
921 // See if they are two boundary faces
925 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
929 label faceI = eFaces[i];
931 if (!removedFace[faceI] && !mesh_.isInternalFace(faceI))
945 if (f0 != -1 && f1 != -1)
947 // Edge has two boundary faces remaining.
948 // See if should be merged.
950 label patch0 = patches.whichPatch(f0);
951 label patch1 = patches.whichPatch(f1);
953 if (patch0 != patch1)
955 // Different patches. Do not merge edge.
956 WarningIn("removeFaces::setRefinement")
957 << "not merging faces " << f0 << " and "
958 << f1 << " across patch boundary edge " << edgeI
961 // Mark so it gets preserved
962 nFacesPerEdge[edgeI] = 3;
964 else if (minCos_ < 1 && minCos_ > -1)
966 const polyPatch& pp0 = patches[patch0];
967 const vectorField& n0 = pp0.faceNormals();
974 & n0[f1 - pp0.start()]
979 WarningIn("removeFaces::setRefinement")
980 << "not merging faces " << f0 << " and "
981 << f1 << " across edge " << edgeI
984 // Angle between two remaining faces too large.
985 // Mark so it gets preserved
986 nFacesPerEdge[edgeI] = 3;
990 else if (f0 != -1 || f1 != -1)
992 const edge& e = mesh_.edges()[edgeI];
994 // Only found one boundary face. Problem.
995 FatalErrorIn("removeFaces::setRefinement")
996 << "Problem : edge would have one boundary face"
997 << " and one internal face using it." << endl
998 << "Your remove pattern is probably incorrect." << endl
1000 << " nFaces:" << nFacesPerEdge[edgeI]
1001 << " vertices:" << e
1002 << " coords:" << mesh_.points()[e[0]]
1003 << mesh_.points()[e[1]]
1006 << abort(FatalError);
1013 // Check locally (before synchronizing) for strangeness
1014 forAll(nFacesPerEdge, edgeI)
1016 if (nFacesPerEdge[edgeI] == 1)
1018 const edge& e = mesh_.edges()[edgeI];
1020 FatalErrorIn("removeFaces::setRefinement")
1021 << "Problem : edge would get 1 face using it only"
1022 << " edge:" << edgeI
1023 << " nFaces:" << nFacesPerEdge[edgeI]
1024 << " vertices:" << e
1025 << " coords:" << mesh_.points()[e[0]]
1026 << ' ' << mesh_.points()[e[1]]
1027 << abort(FatalError);
1029 // Could check here for boundary edge with <=1 faces remaining.
1033 // Synchronize edge usage. This is to make sure that both sides remove
1034 // (or not remove) an edge on the boundary at the same time.
1036 // Coupled edges (edge0, edge1 are opposite each other)
1037 // a. edge not on face to be removed, edge has >= 3 faces
1038 // b. ,, edge has 2 faces
1039 // c. edge has >= 3 remaining faces
1040 // d. edge has 2 remaining faces (assume angle>minCos already handled)
1042 // - a + a: do not remove edge
1043 // - a + b: do not remove edge
1044 // - a + c: do not remove edge
1045 // - a + d: do not remove edge
1047 // - b + b: do not remove edge
1048 // - b + c: do not remove edge
1049 // - b + d: remove edge
1051 // - c + c: do not remove edge
1052 // - c + d: do not remove edge
1053 // - d + d: remove edge
1056 // So code situation a. with >= 3
1060 // then do max and check result.
1062 // a+a : max(3,3) = 3. do not remove
1063 // a+b : max(3,-1) = 3. do not remove
1064 // a+c : max(3,3) = 3. do not remove
1065 // a+d : max(3,2) = 3. do not remove
1067 // b+b : max(-1,-1) = -1. do not remove
1068 // b+c : max(-1,3) = 3. do not remove
1069 // b+d : max(-1,2) = 2. remove
1071 // c+c : max(3,3) = 3. do not remove
1072 // c+d : max(3,2) = 3. do not remove
1074 // d+d : max(2,2) = 2. remove
1076 syncTools::syncEdgeList
1081 labelMin, // guaranteed to be overridden by maxEqOp
1082 false // no separation
1085 // Convert to labelHashSet
1086 forAll(nFacesPerEdge, edgeI)
1088 if (nFacesPerEdge[edgeI] == 0)
1090 // 0: edge not used anymore.
1091 edgesToRemove.insert(edgeI);
1093 else if (nFacesPerEdge[edgeI] == 1)
1095 // 1: illegal. Tested above.
1097 else if (nFacesPerEdge[edgeI] == 2)
1100 edgesToRemove.insert(edgeI);
1106 OFstream str(mesh_.time().path()/"edgesToRemove.obj");
1107 Pout<< "Dumping edgesToRemove to " << str.name() << endl;
1110 forAllConstIter(labelHashSet, edgesToRemove, iter)
1112 // Edge will get removed.
1113 const edge& e = mesh_.edges()[iter.key()];
1115 meshTools::writeOBJ(str, mesh_.points()[e[0]]);
1117 meshTools::writeOBJ(str, mesh_.points()[e[1]]);
1119 str<< "l " << vertI-1 << ' ' << vertI << nl;
1124 // Walk to fill faceRegion with faces that will be connected across
1125 // edges that will be removed.
1127 label startFaceI = 0;
1131 // Find unset region.
1132 for (; startFaceI < mesh_.nFaces(); startFaceI++)
1134 if (faceRegion[startFaceI] == -1 && !removedFace[startFaceI])
1140 if (startFaceI == mesh_.nFaces())
1145 // Start walking face-edge-face, crossing edges that will get
1146 // removed. Every thus connected region will get single region
1148 label nRegion = changeFaceRegion
1160 FatalErrorIn("setRefinement") << "Problem" << abort(FatalError);
1162 else if (nRegion == 1)
1164 // Reset face to be single region.
1165 faceRegion[startFaceI] = -2;
1174 // Check we're deciding the same on both sides. Since the regioning
1175 // is done based on nFacesPerEdge (which is synced) this should
1176 // indeed be the case.
1178 labelList nbrFaceRegion(faceRegion);
1180 syncTools::swapFaceList
1184 false // no separation
1187 labelList toNbrRegion(nRegions, -1);
1191 label faceI = mesh_.nInternalFaces();
1192 faceI < mesh_.nFaces();
1196 // Get the neighbouring region.
1197 label nbrRegion = nbrFaceRegion[faceI];
1198 label myRegion = faceRegion[faceI];
1200 if (myRegion <= -1 || nbrRegion <= -1)
1202 if (nbrRegion != myRegion)
1204 FatalErrorIn("removeFaces::setRefinement")
1205 << "Inconsistent face region across coupled patches."
1207 << "This side has for faceI:" << faceI
1208 << " region:" << myRegion << endl
1209 << "The other side has region:" << nbrRegion
1211 << "(region -1 means face is to be deleted)"
1212 << abort(FatalError);
1215 else if (toNbrRegion[myRegion] == -1)
1217 // First visit of region. Store correspondence.
1218 toNbrRegion[myRegion] = nbrRegion;
1222 // Second visit of this region.
1223 if (toNbrRegion[myRegion] != nbrRegion)
1225 FatalErrorIn("removeFaces::setRefinement")
1226 << "Inconsistent face region across coupled patches."
1228 << "This side has for faceI:" << faceI
1229 << " region:" << myRegion
1230 << " with coupled neighbouring regions:"
1231 << toNbrRegion[myRegion] << " and "
1233 << abort(FatalError);
1241 // labelListList regionToFaces(invertOneToMany(nRegions, faceRegion));
1243 // forAll(regionToFaces, regionI)
1245 // Pout<< " " << regionI << " faces:" << regionToFaces[regionI]
1251 // Points to be removed
1252 // ~~~~~~~~~~~~~~~~~~~~
1254 labelHashSet pointsToRemove(4*faceLabels.size());
1257 // Per point count the number of unremoved edges. Store the ones that
1258 // are only used by 2 unremoved edges.
1260 // Usage of points by non-removed edges.
1261 labelList nEdgesPerPoint(mesh_.nPoints(), labelMax);
1263 const labelListList& pointEdges = mesh_.pointEdges();
1265 forAllConstIter(labelHashSet, edgesToRemove, iter)
1267 // Edge will get removed.
1268 const edge& e = mesh_.edges()[iter.key()];
1272 label pointI = e[i];
1274 if (nEdgesPerPoint[pointI] == labelMax)
1276 nEdgesPerPoint[pointI] = pointEdges[pointI].size()-1;
1280 nEdgesPerPoint[pointI]--;
1285 // Check locally (before synchronizing) for strangeness
1286 forAll(nEdgesPerPoint, pointI)
1288 if (nEdgesPerPoint[pointI] == 1)
1290 FatalErrorIn("removeFaces::setRefinement")
1291 << "Problem : point would get 1 edge using it only."
1292 << " pointI:" << pointI
1293 << " coord:" << mesh_.points()[pointI]
1294 << abort(FatalError);
1298 // Synchronize point usage. This is to make sure that both sides remove
1299 // (or not remove) a point on the boundary at the same time.
1300 syncTools::syncPointList
1306 false // no separation
1309 forAll(nEdgesPerPoint, pointI)
1311 if (nEdgesPerPoint[pointI] == 0)
1313 pointsToRemove.insert(pointI);
1315 else if (nEdgesPerPoint[pointI] == 1)
1317 // Already checked before
1319 else if (nEdgesPerPoint[pointI] == 2)
1321 // Remove point and merge edges.
1322 pointsToRemove.insert(pointI);
1330 OFstream str(mesh_.time().path()/"pointsToRemove.obj");
1331 Pout<< "Dumping pointsToRemove to " << str.name() << endl;
1333 forAllConstIter(labelHashSet, pointsToRemove, iter)
1335 meshTools::writeOBJ(str, mesh_.points()[iter.key()]);
1340 // All faces affected in any way
1341 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1343 // Get all faces affected in any way by removal of points/edges/faces/cells
1344 boolList affectedFace
1358 // - faceLabels : faces to remove (sync since no boundary faces)
1359 // - cellRegion/Master : cells to remove (sync since cells)
1360 // - pointsToRemove : points to remove (sync)
1361 // - faceRegion : connected face region of faces to be merged (sync)
1362 // - affectedFace : faces with points removed and/or owner/neighbour
1363 // changed (non sync)
1366 // Start modifying mesh and keep track of faces changed.
1372 // Remove split faces.
1373 forAll(faceLabels, labelI)
1375 label faceI = faceLabels[labelI];
1377 // Remove face if not yet uptodate (which is never; but want to be
1378 // consistent with rest of face removals/modifications)
1379 if (affectedFace[faceI])
1381 affectedFace[faceI] = false;
1383 meshMod.setAction(polyRemoveFace(faceI, -1));
1389 forAllConstIter(labelHashSet, pointsToRemove, iter)
1391 label pointI = iter.key();
1393 meshMod.setAction(polyRemovePoint(pointI, -1));
1398 forAll(cellRegion, cellI)
1400 label region = cellRegion[cellI];
1402 if (region != -1 && (cellI != cellRegionMaster[region]))
1404 meshMod.setAction(polyRemoveCell(cellI, cellRegionMaster[region]));
1410 // Merge faces across edges to be merged
1411 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1413 // Invert faceRegion so we get region to faces.
1415 labelListList regionToFaces(invertOneToMany(nRegions, faceRegion));
1417 forAll(regionToFaces, regionI)
1419 const labelList& rFaces = regionToFaces[regionI];
1421 if (rFaces.size() <= 1)
1423 FatalErrorIn("setRefinement")
1424 << "Region:" << regionI
1425 << " contains only faces " << rFaces
1426 << abort(FatalError);
1429 // rFaces[0] is master, rest gets removed.
1441 affectedFace[rFaces[i]] = false;
1447 // Remaining affected faces
1448 // ~~~~~~~~~~~~~~~~~~~~~~~~
1450 // Check if any remaining faces have not been updated for new slave/master
1451 // or points removed.
1452 forAll(affectedFace, faceI)
1454 if (affectedFace[faceI])
1456 affectedFace[faceI] = false;
1458 face f(filterFace(pointsToRemove, faceI));
1460 label own = mesh_.faceOwner()[faceI];
1462 if (cellRegion[own] != -1)
1464 own = cellRegionMaster[cellRegion[own]];
1467 label patchID, zoneID, zoneFlip;
1469 getFaceInfo(faceI, patchID, zoneID, zoneFlip);
1473 if (mesh_.isInternalFace(faceI))
1475 nei = mesh_.faceNeighbour()[faceI];
1477 if (cellRegion[nei] != -1)
1479 nei = cellRegionMaster[cellRegion[nei]];
1485 // Pout<< "Modifying " << faceI
1486 // << " old verts:" << mesh_.faces()[faceI]
1487 // << " for new verts:" << f
1488 // << " or for new owner " << own << " or for new nei "
1496 faceI, // label of face being modified
1500 patchID, // patch for face
1501 false, // remove from zone
1502 zoneID, // zone for face
1503 zoneFlip, // face flip in zone
1512 // ************************************************************************* //