combineFaces.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2018-2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "combineFaces.H"
30 #include "polyMesh.H"
31 #include "polyTopoChange.H"
32 #include "polyRemoveFace.H"
33 #include "polyAddFace.H"
34 #include "polyModifyFace.H"
35 #include "polyRemovePoint.H"
36 #include "polyAddPoint.H"
37 #include "syncTools.H"
38 #include "meshTools.H"
39 
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
44  defineTypeNameAndDebug(combineFaces, 0);
45 }
46 
47 
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 
50 // Test face for (almost) convexeness. Allows certain convexity before
51 // complaining.
52 // For every two consecutive edges calculate the normal. If it differs too
53 // much from the average face normal complain.
54 bool Foam::combineFaces::convexFace
55 (
56  const scalar minConcaveCos,
57  const pointField& points,
58  const face& f
59 )
60 {
61  // Get outwards pointing normal of f, only the sign matters.
62  const vector areaNorm = f.areaNormal(points);
63 
64  // Get edge from f[0] to f[size-1];
65  vector ePrev(points[f.first()] - points[f.last()]);
66  scalar magEPrev = mag(ePrev);
67  ePrev /= magEPrev + VSMALL;
68 
69  forAll(f, fp0)
70  {
71  // Get vertex after fp
72  label fp1 = f.fcIndex(fp0);
73 
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;
78 
79  if (magEPrev > SMALL && magE10 > SMALL)
80  {
81  vector edgeNormal = ePrev ^ e10;
82 
83  if ((edgeNormal & areaNorm) < 0)
84  {
85  // Concave. Check angle.
86  if ((ePrev & e10) < minConcaveCos)
87  {
88  return false;
89  }
90  }
91  }
92 
93  ePrev = e10;
94  magEPrev = magE10;
95  }
96 
97  // Not a single internal angle is concave so face is convex.
98  return true;
99 }
100 
101 
102 // Determines if set of faces is valid to collapse into single face.
103 bool Foam::combineFaces::validFace
104 (
105  const scalar minConcaveCos,
106  const indirectPrimitivePatch& bigFace
107 )
108 {
109  // Get outside vertices (in local vertex numbering)
110  const labelListList& edgeLoops = bigFace.edgeLoops();
111 
112  if (edgeLoops.size() > 1)
113  {
114  return false;
115  }
116 
117  bool isNonManifold = bigFace.checkPointManifold(false, nullptr);
118  if (isNonManifold)
119  {
120  return false;
121  }
122 
123  // Check for convexness
124  face f(getOutsideFace(bigFace));
125 
126  return convexFace(minConcaveCos, bigFace.points(), f);
127 }
128 
129 
130 void Foam::combineFaces::regioniseFaces
131 (
132  const scalar minCos,
133  const bool mergeAcrossPatches,
134  const label celli,
135  const labelList& cEdges,
136  Map<label>& faceRegion
137 ) const
138 {
139  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
140 
141  forAll(cEdges, i)
142  {
143  const label edgeI = cEdges[i];
144 
145  label f0, f1;
146  meshTools::getEdgeFaces(mesh_, celli, edgeI, f0, f1);
147 
148  const vector& a0 = mesh_.faceAreas()[f0];
149  const vector& a1 = mesh_.faceAreas()[f1];
150 
151  const label p0 = patches.whichPatch(f0);
152  const label p1 = patches.whichPatch(f1);
153 
154  // Face can be merged if
155  // - small angle
156  // - mergeAcrossPatches=false : same non-constraint patch
157  // - mergeAcrossPatches=true : always (if non-constraint patch)
158  // (this logic could be extended to e.g. merge faces on symm plane
159  // if they have similar normals. But there might be lots of other
160  // constraints which disallow merging so this decision ideally should
161  // be up to patch type)
162  if
163  (
164  p0 != -1
165  && p1 != -1
166  && !(
169  )
170  )
171  {
172  if (!mergeAcrossPatches && (p0 != p1))
173  {
174  continue;
175  }
176 
177  const vector f0Normal = normalised(a0);
178  const vector f1Normal = normalised(a1);
179 
180  if ((f0Normal & f1Normal) > minCos)
181  {
182  const label region0 = faceRegion.lookup(f0, -1);
183  const label region1 = faceRegion.lookup(f1, -1);
184 
185  if (region0 == -1)
186  {
187  if (region1 == -1)
188  {
189  const label useRegion = faceRegion.size();
190  faceRegion.insert(f0, useRegion);
191  faceRegion.insert(f1, useRegion);
192  }
193  else
194  {
195  faceRegion.insert(f0, region1);
196  }
197  }
198  else
199  {
200  if (region1 == -1)
201  {
202  faceRegion.insert(f1, region0);
203  }
204  else if (region0 != region1)
205  {
206  // Merge the two regions
207  const label useRegion = min(region0, region1);
208  const label freeRegion = max(region0, region1);
209 
210  forAllIters(faceRegion, iter)
211  {
212  if (iter.val() == freeRegion)
213  {
214  iter.val() = useRegion;
215  }
216  }
217  }
218  }
219  }
220  }
221  }
222 }
223 
224 
225 bool Foam::combineFaces::faceNeighboursValid
226 (
227  const label celli,
228  const Map<label>& faceRegion
229 ) const
230 {
231  if (faceRegion.size() <= 1)
232  {
233  return true;
234  }
235 
236  const cell& cFaces = mesh_.cells()[celli];
237 
238  DynamicList<label> storage;
239 
240  // Test for face collapsing to edge since too many neighbours merged.
241  forAll(cFaces, cFacei)
242  {
243  label facei = cFaces[cFacei];
244 
245  if (!faceRegion.found(facei))
246  {
247  const labelList& fEdges = mesh_.faceEdges(facei, storage);
248 
249  // Count number of remaining faces neighbouring facei. This has
250  // to be 3 or more.
251 
252  // Unregioned neighbouring faces
253  DynamicList<label> neighbourFaces(cFaces.size());
254  // Regioned neighbouring faces
255  labelHashSet neighbourRegions;
256 
257  forAll(fEdges, i)
258  {
259  const label edgeI = fEdges[i];
260  label nbrI = meshTools::otherFace(mesh_, celli, facei, edgeI);
261 
262  const auto iter = faceRegion.cfind(nbrI);
263 
264  if (iter.found())
265  {
266  neighbourRegions.insert(iter.val());
267  }
268  else
269  {
270  if (!neighbourFaces.found(nbrI))
271  {
272  neighbourFaces.append(nbrI);
273  }
274  }
275  }
276 
277  if ((neighbourFaces.size()+neighbourRegions.size()) < 3)
278  {
279  return false;
280  }
281  }
282  }
283  return true;
284 }
285 
286 
287 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
288 
289 // Construct from mesh
290 Foam::combineFaces::combineFaces
291 (
292  const polyMesh& mesh,
293  const bool undoable
294 )
295 :
296  mesh_(mesh),
297  undoable_(undoable),
298  masterFace_(0),
299  faceSetsVertices_(0),
300  savedPointLabels_(0),
301  savedPoints_(0)
302 {}
303 
304 
305 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
306 
308 (
309  const scalar featureCos,
310  const scalar minConcaveCos,
311  const labelHashSet& boundaryCells,
312  const bool mergeAcrossPatches
313 ) const
314 {
315  // Lists of faces that can be merged.
316  DynamicList<labelList> allFaceSets(boundaryCells.size() / 10);
317  // Storage for on-the-fly cell-edge addressing.
319  DynamicList<label> storage;
320 
321  // On all cells regionise the faces
322  for (const label celli : boundaryCells)
323  {
324  const cell& cFaces = mesh_.cells()[celli];
325 
326  const labelList& cEdges = mesh_.cellEdges(celli, set, storage);
327 
328  // Region per face
329  Map<label> faceRegion(cFaces.size());
330  regioniseFaces
331  (
332  featureCos,
333  mergeAcrossPatches,
334  celli,
335  cEdges,
336  faceRegion
337  );
338 
339  // Now we have in faceRegion for every face the region with planar
340  // face sharing the same region. We now check whether the resulting
341  // sets cause a face
342  // - to become a set of edges since too many faces are merged.
343  // - to become convex
344 
345  if (faceNeighboursValid(celli, faceRegion))
346  {
347  // Create region-to-faces addressing
348  Map<labelList> regionToFaces(faceRegion.size());
349 
350  forAllConstIters(faceRegion, iter)
351  {
352  const label facei = iter.key();
353  const label region = iter.val();
354 
355  auto regionFnd = regionToFaces.find(region);
356 
357  if (regionFnd.found())
358  {
359  labelList& setFaces = regionFnd();
360  label sz = setFaces.size();
361  setFaces.setSize(sz+1);
362  setFaces[sz] = facei;
363  }
364  else
365  {
366  regionToFaces.insert(region, labelList(1, facei));
367  }
368  }
369 
370  // For every set check if it forms a valid convex face
371 
372  forAllIters(regionToFaces, iter)
373  {
374  // Make face out of setFaces
375  indirectPrimitivePatch bigFace
376  (
378  (
379  mesh_.faces(),
380  iter.val()
381  ),
382  mesh_.points()
383  );
384 
385  // Only store if -only one outside loop -which forms convex face
386  if (validFace(minConcaveCos, bigFace))
387  {
388  labelList& faceIDs = iter.val();
389 
390  // For cross-patch merging we want to make the
391  // largest face the one to decide the final patch
392  // (i.e. master face)
393  if (mergeAcrossPatches)
394  {
395  const vectorField& areas = mesh_.faceAreas();
396 
397  label maxIndex = 0;
398  scalar maxMagSqr = magSqr(areas[faceIDs[0]]);
399  for (label i = 1; i < faceIDs.size(); ++i)
400  {
401  const scalar a2 = magSqr(areas[faceIDs[i]]);
402  if (a2 > maxMagSqr)
403  {
404  maxMagSqr = a2;
405  maxIndex = i;
406  }
407  }
408  if (maxIndex != 0)
409  {
410  Swap(faceIDs[0], faceIDs[maxIndex]);
411  }
412  }
413 
414  allFaceSets.append(faceIDs);
415  }
416  }
417  }
418  }
419 
420  return allFaceSets.shrink();
421 }
422 
423 
425 (
426  const scalar featureCos,
427  const scalar minConcaveCos,
428  const bool mergeAcrossPatches
429 ) const
430 {
431  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
432 
433  // Pick up all cells on boundary
434  labelHashSet boundaryCells(mesh_.nBoundaryFaces());
435 
436  forAll(patches, patchi)
437  {
438  const polyPatch& patch = patches[patchi];
439 
440  if (!patch.coupled())
441  {
442  forAll(patch, i)
443  {
444  boundaryCells.insert(mesh_.faceOwner()[patch.start()+i]);
445  }
446  }
447  }
448 
449  return getMergeSets
450  (
451  featureCos,
452  minConcaveCos,
453  boundaryCells,
454  mergeAcrossPatches
455  );
456 }
457 
458 
459 // Gets outside edgeloop as a face
460 // - in same order as faces
461 // - in mesh vertex labels
463 (
464  const indirectPrimitivePatch& fp
465 )
466 {
467  if (fp.edgeLoops().size() != 1)
468  {
470  << "Multiple outside loops:" << fp.edgeLoops()
471  << abort(FatalError);
472  }
473 
474  // Get first boundary edge. Since guaranteed one edgeLoop when in here this
475  // edge must be on it.
476  label bEdgeI = fp.nInternalEdges();
477 
478  const edge& e = fp.edges()[bEdgeI];
479 
480  const labelList& eFaces = fp.edgeFaces()[bEdgeI];
481 
482  if (eFaces.size() != 1)
483  {
485  << "boundary edge:" << bEdgeI
486  << " points:" << fp.meshPoints()[e[0]]
487  << ' ' << fp.meshPoints()[e[1]]
488  << " on indirectPrimitivePatch has " << eFaces.size()
489  << " faces using it" << abort(FatalError);
490  }
491 
492 
493  // Outside loop
494  const labelList& outsideLoop = fp.edgeLoops()[0];
495 
496 
497  // Get order of edge e in outside loop
498  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
499 
500  // edgeLoopConsistent : true = edge in same order as outsideloop
501  // false = opposite order
502  bool edgeLoopConsistent = false;
503 
504  {
505  label index0 = outsideLoop.find(e[0]);
506  label index1 = outsideLoop.find(e[1]);
507 
508  if (index0 == -1 || index1 == -1)
509  {
511  << "Cannot find boundary edge:" << e
512  << " points:" << fp.meshPoints()[e[0]]
513  << ' ' << fp.meshPoints()[e[1]]
514  << " in edgeLoop:" << outsideLoop << abort(FatalError);
515  }
516  else if (index1 == outsideLoop.fcIndex(index0))
517  {
518  edgeLoopConsistent = true;
519  }
520  else if (index0 == outsideLoop.fcIndex(index1))
521  {
522  edgeLoopConsistent = false;
523  }
524  else
525  {
527  << "Cannot find boundary edge:" << e
528  << " points:" << fp.meshPoints()[e[0]]
529  << ' ' << fp.meshPoints()[e[1]]
530  << " on consecutive points in edgeLoop:"
531  << outsideLoop << abort(FatalError);
532  }
533  }
534 
535 
536  // Get face in local vertices
537  const face& localF = fp.localFaces()[eFaces[0]];
538 
539  // Get order of edge in localF
540  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
541 
542  // faceEdgeConsistent : true = edge in same order as localF
543  // false = opposite order
544  bool faceEdgeConsistent = false;
545 
546  {
547  // Find edge in face.
548  label index = fp.faceEdges()[eFaces[0]].find(bEdgeI);
549 
550  if (index == -1)
551  {
553  << "Cannot find boundary edge:" << e
554  << " points:" << fp.meshPoints()[e[0]]
555  << ' ' << fp.meshPoints()[e[1]]
556  << " in face:" << eFaces[0]
557  << " edges:" << fp.faceEdges()[eFaces[0]]
558  << abort(FatalError);
559  }
560  else if (localF[index] == e[0] && localF.nextLabel(index) == e[1])
561  {
562  faceEdgeConsistent = true;
563  }
564  else if (localF[index] == e[1] && localF.nextLabel(index) == e[0])
565  {
566  faceEdgeConsistent = false;
567  }
568  else
569  {
571  << "Cannot find boundary edge:" << e
572  << " points:" << fp.meshPoints()[e[0]]
573  << ' ' << fp.meshPoints()[e[1]]
574  << " in face:" << eFaces[0] << " verts:" << localF
575  << abort(FatalError);
576  }
577  }
578 
579  // Get face in mesh points.
580  face meshFace(renumber(fp.meshPoints(), outsideLoop));
581 
582  if (faceEdgeConsistent != edgeLoopConsistent)
583  {
584  reverse(meshFace);
585  }
586  return meshFace;
587 }
588 
589 
591 (
592  const labelListList& faceSets,
593  polyTopoChange& meshMod
594 )
595 {
596  if (undoable_)
597  {
598  masterFace_.setSize(faceSets.size());
599  faceSetsVertices_.setSize(faceSets.size());
600  forAll(faceSets, setI)
601  {
602  const labelList& setFaces = faceSets[setI];
603 
604  masterFace_[setI] = setFaces[0];
605  faceSetsVertices_[setI] = UIndirectList<face>
606  (
607  mesh_.faces(),
608  setFaces
609  );
610  }
611  }
612 
613  // Running count of number of faces using a point
614  labelList nPointFaces(mesh_.nPoints(), Zero);
615 
616  const labelListList& pointFaces = mesh_.pointFaces();
617 
618  forAll(pointFaces, pointi)
619  {
620  nPointFaces[pointi] = pointFaces[pointi].size();
621  }
622 
623  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
624 
625  forAll(faceSets, setI)
626  {
627  const labelList& setFaces = faceSets[setI];
628 
629  // Check
630  if (debug)
631  {
632  forAll(setFaces, i)
633  {
634  label patchi = patches.whichPatch(setFaces[i]);
635 
636  if (patchi == -1 || patches[patchi].coupled())
637  {
639  << "Can only merge non-coupled boundary faces"
640  << " but found internal or coupled face:"
641  << setFaces[i] << " in set " << setI
642  << abort(FatalError);
643  }
644  }
645  }
646 
647  // Make face out of setFaces
648  indirectPrimitivePatch bigFace
649  (
651  (
652  mesh_.faces(),
653  setFaces
654  ),
655  mesh_.points()
656  );
657 
658  // Get outside vertices (in local vertex numbering)
659  const labelListList& edgeLoops = bigFace.edgeLoops();
660 
661  if (edgeLoops.size() != 1)
662  {
664  << "Faces to-be-merged " << setFaces
665  << " do not form a single big face." << nl
666  << abort(FatalError);
667  }
668 
669 
670  // Delete all faces except master, whose face gets modified.
671 
672  // Modify master face
673  // ~~~~~~~~~~~~~~~~~~
674 
675  label masterFacei = setFaces[0];
676 
677  // Get outside face in mesh vertex labels
678  face outsideFace(getOutsideFace(bigFace));
679 
680  label zoneID = mesh_.faceZones().whichZone(masterFacei);
681 
682  bool zoneFlip = false;
683 
684  if (zoneID >= 0)
685  {
686  const faceZone& fZone = mesh_.faceZones()[zoneID];
687 
688  zoneFlip = fZone.flipMap()[fZone.whichFace(masterFacei)];
689  }
690 
691  label patchi = mesh_.boundaryMesh().whichPatch(masterFacei);
692 
693  meshMod.setAction
694  (
696  (
697  outsideFace, // modified face
698  masterFacei, // label of face being modified
699  mesh_.faceOwner()[masterFacei], // owner
700  -1, // neighbour
701  false, // face flip
702  patchi, // patch for face
703  false, // remove from zone
704  zoneID, // zone for face
705  zoneFlip // face flip in zone
706  )
707  );
708 
709 
710  // Delete all non-master faces
711  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
712 
713  for (label i = 1; i < setFaces.size(); i++)
714  {
715  meshMod.setAction(polyRemoveFace(setFaces[i]));
716  }
717 
718 
719  // Mark unused points for deletion
720  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
721 
722  // Remove count of all faces combined
723  forAll(setFaces, i)
724  {
725  const face& f = mesh_.faces()[setFaces[i]];
726 
727  forAll(f, fp)
728  {
729  nPointFaces[f[fp]]--;
730  }
731  }
732  // But keep count on new outside face
733  forAll(outsideFace, fp)
734  {
735  nPointFaces[outsideFace[fp]]++;
736  }
737  }
738 
739 
740  // If one or more processors use the point it needs to be kept.
742  (
743  mesh_,
744  nPointFaces,
745  plusEqOp<label>(),
746  label(0) // null value
747  );
748 
749  // Remove all unused points. Store position if undoable.
750  if (!undoable_)
751  {
752  forAll(nPointFaces, pointi)
753  {
754  if (nPointFaces[pointi] == 0)
755  {
756  meshMod.setAction(polyRemovePoint(pointi));
757  }
758  }
759  }
760  else
761  {
762  // Count removed points
763  label n = 0;
764  forAll(nPointFaces, pointi)
765  {
766  if (nPointFaces[pointi] == 0)
767  {
768  n++;
769  }
770  }
771 
772  savedPointLabels_.setSize(n);
773  savedPoints_.setSize(n);
774  Map<label> meshToSaved(2*n);
775 
776  // Remove points and store position
777  n = 0;
778  forAll(nPointFaces, pointi)
779  {
780  if (nPointFaces[pointi] == 0)
781  {
782  meshMod.setAction(polyRemovePoint(pointi));
783 
784  savedPointLabels_[n] = pointi;
785  savedPoints_[n] = mesh_.points()[pointi];
786 
787  meshToSaved.insert(pointi, n);
788  n++;
789  }
790  }
791 
792  // Update stored vertex labels. Negative indices index into local points
793  forAll(faceSetsVertices_, setI)
794  {
795  faceList& setFaces = faceSetsVertices_[setI];
796 
797  forAll(setFaces, i)
798  {
799  face& f = setFaces[i];
800 
801  forAll(f, fp)
802  {
803  label pointi = f[fp];
804 
805  if (nPointFaces[pointi] == 0)
806  {
807  f[fp] = -meshToSaved[pointi]-1;
808  }
809  }
810  }
811  }
812  }
813 }
814 
815 
817 {
818  if (undoable_)
819  {
820  // Master face just renumbering of point labels
821  inplaceRenumber(map.reverseFaceMap(), masterFace_);
822 
823  // Stored faces refer to backed-up vertices (not changed)
824  // and normal vertices (need to be renumbered)
825  forAll(faceSetsVertices_, setI)
826  {
827  faceList& faces = faceSetsVertices_[setI];
828 
829  forAll(faces, i)
830  {
831  // Note: faces[i] can have negative elements.
832  face& f = faces[i];
833 
834  forAll(f, fp)
835  {
836  label pointi = f[fp];
837 
838  if (pointi >= 0)
839  {
840  f[fp] = map.reversePointMap()[pointi];
841 
842  if (f[fp] < 0)
843  {
845  << "In set " << setI << " at position " << i
846  << " with master face "
847  << masterFace_[setI] << nl
848  << "the points of the slave face " << faces[i]
849  << " don't exist anymore."
850  << abort(FatalError);
851  }
852  }
853  }
854  }
855  }
856  }
857 }
858 
859 
860 // Note that faces on coupled patches are never combined (or at least
861 // getMergeSets never picks them up. Thus the points on them will never get
862 // deleted since still used by the coupled faces. So never a risk of undoing
863 // things (faces/points) on coupled patches.
865 (
866  const labelList& masterFaces,
867  polyTopoChange& meshMod,
868  Map<label>& restoredPoints,
869  Map<label>& restoredFaces,
870  Map<label>& restoredCells
871 )
872 {
873  if (!undoable_)
874  {
876  << "Can only call setUnrefinement if constructed with"
877  << " unrefinement capability." << exit(FatalError);
878  }
879 
880 
881  // Restored points
882  labelList addedPoints(savedPoints_.size(), -1);
883 
884  // Invert set-to-master-face
885  Map<label> masterToSet(masterFace_.size());
886 
887  forAll(masterFace_, setI)
888  {
889  if (masterFace_[setI] >= 0)
890  {
891  masterToSet.insert(masterFace_[setI], setI);
892  }
893  }
894 
895  forAll(masterFaces, i)
896  {
897  const label masterFacei = masterFaces[i];
898 
899  const auto iter = masterToSet.cfind(masterFacei);
900 
901  if (!iter.found())
902  {
904  << "Master face " << masterFacei
905  << " is not the master of one of the merge sets"
906  << " or has already been merged"
907  << abort(FatalError);
908  }
909 
910  const label setI = iter.val();
911 
912 
913  // Update faces of the merge setI for reintroduced vertices
914  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
915 
916  faceList& faces = faceSetsVertices_[setI];
917 
918  if (faces.empty())
919  {
921  << "Set " << setI << " with master face " << masterFacei
922  << " has already been merged." << abort(FatalError);
923  }
924 
925  forAll(faces, i)
926  {
927  face& f = faces[i];
928 
929  forAll(f, fp)
930  {
931  label pointi = f[fp];
932 
933  if (pointi < 0)
934  {
935  label localI = -pointi-1;
936 
937  if (addedPoints[localI] == -1)
938  {
939  // First occurrence of saved point. Reintroduce point
940  addedPoints[localI] = meshMod.setAction
941  (
943  (
944  savedPoints_[localI], // point
945  -1, // master point
946  -1, // zone for point
947  true // supports a cell
948  )
949  );
950  restoredPoints.insert
951  (
952  addedPoints[localI], // current point label
953  savedPointLabels_[localI] // point label when it
954  // was stored
955  );
956  }
957  f[fp] = addedPoints[localI];
958  }
959  }
960  }
961 
962 
963  // Restore
964  // ~~~~~~~
965 
966  label own = mesh_.faceOwner()[masterFacei];
967  label zoneID = mesh_.faceZones().whichZone(masterFacei);
968  bool zoneFlip = false;
969  if (zoneID >= 0)
970  {
971  const faceZone& fZone = mesh_.faceZones()[zoneID];
972  zoneFlip = fZone.flipMap()[fZone.whichFace(masterFacei)];
973  }
974  label patchi = mesh_.boundaryMesh().whichPatch(masterFacei);
975 
976  if (mesh_.boundaryMesh()[patchi].coupled())
977  {
979  << "Master face " << masterFacei << " is on coupled patch "
980  << mesh_.boundaryMesh()[patchi].name()
981  << abort(FatalError);
982  }
983 
984  //Pout<< "Restoring new master face " << masterFacei
985  // << " to vertices " << faces[0] << endl;
986 
987  // Modify the master face.
988  meshMod.setAction
989  (
991  (
992  faces[0], // original face
993  masterFacei, // label of face
994  own, // owner
995  -1, // neighbour
996  false, // face flip
997  patchi, // patch for face
998  false, // remove from zone
999  zoneID, // zone for face
1000  zoneFlip // face flip in zone
1001  )
1002  );
1003  restoredFaces.insert(masterFacei, masterFacei);
1004 
1005  // Add the previously removed faces
1006  for (label i = 1; i < faces.size(); i++)
1007  {
1008  //Pout<< "Restoring removed face with vertices " << faces[i]
1009  // << endl;
1010 
1011  label facei = meshMod.setAction
1012  (
1013  polyAddFace
1014  (
1015  faces[i], // vertices
1016  own, // owner,
1017  -1, // neighbour,
1018  -1, // masterPointID,
1019  -1, // masterEdgeID,
1020  masterFacei, // masterFaceID,
1021  false, // flipFaceFlux,
1022  patchi, // patchID,
1023  zoneID, // zoneID,
1024  zoneFlip // zoneFlip
1025  )
1026  );
1027  restoredFaces.insert(facei, masterFacei);
1028  }
1029 
1030  // Clear out restored set
1031  faceSetsVertices_[setI].clear();
1032  masterFace_[setI] = -1;
1033  }
1034 }
1035 
1036 
1037 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::HashTable::size
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
Foam::reverse
void reverse(UList< T > &list, const label n)
Definition: UListI.H:396
meshTools.H
Foam::BitOps::set
void set(List< bool > &bools, const labelRange &range)
Set the specified range 'on' in a boolList.
Definition: BitOps.C:37
Foam::combineFaces::getOutsideFace
static face getOutsideFace(const indirectPrimitivePatch &)
Gets outside of patch as a face (in mesh point labels)
Definition: combineFaces.C:463
Foam::PrimitivePatch::edgeFaces
const labelListList & edgeFaces() const
Return edge-face addressing.
Definition: PrimitivePatch.C:242
polyRemovePoint.H
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::PrimitivePatch::edges
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
Definition: PrimitivePatch.C:190
Foam::polyRemovePoint
Class containing data for point removal.
Definition: polyRemovePoint.H:48
Foam::meshTools::otherFace
label otherFace(const primitiveMesh &mesh, const label celli, const label facei, const label edgeI)
Return face on cell using edgeI but not facei. Throws error.
Definition: meshTools.C:555
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
Foam::combineFaces::getMergeSets
labelListList getMergeSets(const scalar featureCos, const scalar minConcaveCos, const labelHashSet &boundaryCells, const bool mergeAcrossPatches=false) const
Extract lists of all (non-coupled) boundary faces on selected.
Definition: combineFaces.C:308
polyAddFace.H
polyRemoveFace.H
polyTopoChange.H
combineFaces.H
Foam::polyTopoChange
Direct mesh changes based on v1.3 polyTopoChange syntax.
Definition: polyTopoChange.H:99
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
Foam::Map< label >
Foam::polyModifyFace
Class describing modification of a face.
Definition: polyModifyFace.H:50
Foam::PrimitivePatch::faceEdges
const labelListList & faceEdges() const
Return face-edge addressing.
Definition: PrimitivePatch.C:255
polyMesh.H
Foam::HashSet< label, Hash< label > >
Foam::Swap
void Swap(DynamicList< T, SizeMin1 > &a, DynamicList< T, SizeMin2 > &b)
Definition: DynamicListI.H:913
syncTools.H
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
Foam::syncTools::syncPointList
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
Definition: syncToolsTemplates.C:724
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::maxMagSqr
Type maxMagSqr(const UList< Type > &f)
Definition: FieldFunctions.C:417
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::Field< vector >
Foam::faceZone
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::combineFaces::updateMesh
void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: combineFaces.C:816
Foam::combineFaces::setUnrefinement
void setUnrefinement(const labelList &masterFaces, polyTopoChange &meshMod, Map< label > &restoredPoints, Map< label > &restoredFaces, Map< label > &restoredCells)
Play commands into polyTopoChange to reinsert original faces.
Definition: combineFaces.C:865
Foam::meshTools::getEdgeFaces
void getEdgeFaces(const primitiveMesh &mesh, const label celli, const label edgeI, label &face0, label &face1)
Get faces on cell using edgeI. Throws error if no two found.
Definition: meshTools.C:479
Foam::IndirectList
A List with indirect addressing.
Definition: IndirectList.H:56
Foam::polyBoundaryMesh::whichPatch
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
Definition: polyBoundaryMesh.C:810
polyAddPoint.H
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::polyPatch::constraintType
static bool constraintType(const word &pt)
Return true if the given type is a constraint type.
Definition: polyPatch.C:275
forAllIters
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:223
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::PrimitivePatch::localFaces
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
Definition: PrimitivePatch.C:297
zoneID
const labelIOList & zoneID
Definition: interpolatedFaces.H:22
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::faceZone::whichFace
label whichFace(const label globalCellID) const
Helper function to re-direct to zone::localID(...)
Definition: faceZone.C:379
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
polyModifyFace.H
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::mapPolyMesh::reverseFaceMap
const labelList & reverseFaceMap() const
Reverse face map.
Definition: mapPolyMesh.H:501
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:483
Foam::indirectPrimitivePatch
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
Definition: indirectPrimitivePatch.H:49
Foam::PrimitivePatch::nInternalEdges
label nInternalEdges() const
Number of internal edges.
Definition: PrimitivePatch.C:203
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::renumber
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:37
Foam::constant::atomic::a0
const dimensionedScalar a0
Bohr radius: default SI units: [m].
Foam::face::nextLabel
label nextLabel(const label i) const
Next vertex on face.
Definition: faceI.H:161
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::polyTopoChange::setAction
label setAction(const topoAction &action)
For compatibility with polyTopoChange: set topological action.
Definition: polyTopoChange.C:2460
Foam::nl
constexpr char nl
Definition: Ostream.H:385
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
f
labelList f(nPoints)
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::mapPolyMesh::reversePointMap
const labelList & reversePointMap() const
Reverse point map.
Definition: mapPolyMesh.H:469
Foam::polyRemoveFace
Class containing data for face removal.
Definition: polyRemoveFace.H:48
Foam::PrimitivePatch::edgeLoops
const labelListList & edgeLoops() const
Return list of closed loops of boundary vertices.
Definition: PrimitivePatchEdgeLoops.C:148
Foam::List< labelList >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::type
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:590
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:181
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::polyAddPoint
Class containing data for point addition.
Definition: polyAddPoint.H:49
Foam::mapPolyMesh
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:161
Foam::polyAddFace
A face addition data class. A face can be inflated either from a point or from another face and can e...
Definition: polyAddFace.H:53
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::combineFaces::setRefinement
void setRefinement(const labelListList &, polyTopoChange &)
Play commands into polyTopoChange to combine faces. Gets.
Definition: combineFaces.C:591
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::plusEqOp
Definition: ops.H:72
p0
const volScalarField & p0
Definition: EEqn.H:36
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys and label hasher.
Definition: HashSet.H:409
Foam::PrimitivePatch::meshPoints
const labelList & meshPoints() const
Return labelList of mesh points in patch.
Definition: PrimitivePatch.C:310
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::faceZone::flipMap
const boolList & flipMap() const
Return face flip map.
Definition: faceZone.H:271
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:54
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:85