meshRefinementProblemCells.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-2015 OpenFOAM Foundation
9  Copyright (C) 2015-2020 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 "meshRefinement.H"
30 #include "fvMesh.H"
31 #include "syncTools.H"
32 #include "Time.H"
33 #include "refinementSurfaces.H"
34 #include "pointSet.H"
35 #include "faceSet.H"
36 #include "indirectPrimitivePatch.H"
37 #include "cellSet.H"
38 #include "searchableSurfaces.H"
39 #include "polyMeshGeometry.H"
40 #include "IOmanip.H"
41 #include "unitConversion.H"
42 #include "snappySnapDriver.H"
43 
44 #include "snapParameters.H"
45 #include "motionSmoother.H"
46 
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
48 
49 void Foam::meshRefinement::markBoundaryFace
50 (
51  const label facei,
52  boolList& isBoundaryFace,
53  boolList& isBoundaryEdge,
54  boolList& isBoundaryPoint
55 ) const
56 {
57  isBoundaryFace[facei] = true;
58 
59  const labelList& fEdges = mesh_.faceEdges(facei);
60 
61  for (const label edgei : fEdges)
62  {
63  isBoundaryEdge[edgei] = true;
64  }
65 
66  const face& f = mesh_.faces()[facei];
67 
68  for (const label pointi : f)
69  {
70  isBoundaryPoint[pointi] = true;
71  }
72 }
73 
74 
75 void Foam::meshRefinement::findNearest
76 (
77  const labelList& meshFaces,
78  List<pointIndexHit>& nearestInfo,
79  labelList& nearestSurface,
80  labelList& nearestRegion,
81  vectorField& nearestNormal
82 ) const
83 {
84  pointField fc(meshFaces.size());
85  forAll(meshFaces, i)
86  {
87  fc[i] = mesh_.faceCentres()[meshFaces[i]];
88  }
89 
90  const labelList allSurfaces(identity(surfaces_.surfaces().size()));
91 
92  surfaces_.findNearest
93  (
94  allSurfaces,
95  fc,
96  scalarField(fc.size(), sqr(GREAT)), // sqr of attraction
97  nearestSurface,
98  nearestInfo
99  );
100 
101  // Do normal testing per surface.
102  nearestNormal.setSize(nearestInfo.size());
103  nearestRegion.setSize(nearestInfo.size());
104 
105  forAll(allSurfaces, surfI)
106  {
107  DynamicList<pointIndexHit> localHits;
108 
109  forAll(nearestSurface, i)
110  {
111  if (nearestSurface[i] == surfI)
112  {
113  localHits.append(nearestInfo[i]);
114  }
115  }
116 
117  label geomI = surfaces_.surfaces()[surfI];
118 
119  pointField localNormals;
120  surfaces_.geometry()[geomI].getNormal(localHits, localNormals);
121 
122  labelList localRegion;
123  surfaces_.geometry()[geomI].getRegion(localHits, localRegion);
124 
125  label localI = 0;
126  forAll(nearestSurface, i)
127  {
128  if (nearestSurface[i] == surfI)
129  {
130  nearestNormal[i] = localNormals[localI];
131  nearestRegion[i] = localRegion[localI];
132  localI++;
133  }
134  }
135  }
136 }
137 
138 
139 Foam::Map<Foam::label> Foam::meshRefinement::findEdgeConnectedProblemCells
140 (
141  const scalarField& perpendicularAngle,
142  const labelList& globalToPatch
143 ) const
144 {
145  // Construct addressing engine from all patches added for meshing.
146  autoPtr<indirectPrimitivePatch> ppPtr
147  (
149  (
150  mesh_,
151  meshedPatches()
152  )
153  );
154  const indirectPrimitivePatch& pp = ppPtr();
155 
156 
157  // 1. Collect faces to test
158  // ~~~~~~~~~~~~~~~~~~~~~~~~
159 
160  DynamicList<label> candidateFaces(pp.size()/20);
161 
162  const labelListList& edgeFaces = pp.edgeFaces();
163 
164  const labelList& cellLevel = meshCutter_.cellLevel();
165 
166  forAll(edgeFaces, edgeI)
167  {
168  const labelList& eFaces = edgeFaces[edgeI];
169 
170  if (eFaces.size() == 2)
171  {
172  label face0 = pp.addressing()[eFaces[0]];
173  label face1 = pp.addressing()[eFaces[1]];
174 
175  label cell0 = mesh_.faceOwner()[face0];
176  label cell1 = mesh_.faceOwner()[face1];
177 
178  if (cellLevel[cell0] > cellLevel[cell1])
179  {
180  // cell0 smaller.
181  const vector& n0 = pp.faceNormals()[eFaces[0]];
182  const vector& n1 = pp.faceNormals()[eFaces[1]];
183 
184  if (mag(n0 & n1) < 0.1)
185  {
186  candidateFaces.append(face0);
187  }
188  }
189  else if (cellLevel[cell1] > cellLevel[cell0])
190  {
191  // cell1 smaller.
192  const vector& n0 = pp.faceNormals()[eFaces[0]];
193  const vector& n1 = pp.faceNormals()[eFaces[1]];
194 
195  if (mag(n0 & n1) < 0.1)
196  {
197  candidateFaces.append(face1);
198  }
199  }
200  }
201  }
202  candidateFaces.shrink();
203 
204  Info<< "Testing " << returnReduce(candidateFaces.size(), sumOp<label>())
205  << " faces on edge-connected cells of differing level."
206  << endl;
207 
209  {
210  faceSet fSet(mesh_, "edgeConnectedFaces", candidateFaces);
211  fSet.instance() = timeName();
212  Pout<< "Writing " << fSet.size()
213  << " with problematic topology to faceSet "
214  << fSet.objectPath() << endl;
215  fSet.write();
216  }
217 
218 
219  // 2. Find nearest surface on candidate faces
220  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
221 
222  List<pointIndexHit> nearestInfo;
223  labelList nearestSurface;
224  labelList nearestRegion;
225  vectorField nearestNormal;
226  findNearest
227  (
228  candidateFaces,
229  nearestInfo,
230  nearestSurface,
231  nearestRegion,
232  nearestNormal
233  );
234 
235 
236  // 3. Test angle to surface
237  // ~~~~~~~~~~~~~~~~~~~~~~~~
238 
239  Map<label> candidateCells(candidateFaces.size());
240 
241  faceSet perpFaces(mesh_, "perpendicularFaces", pp.size()/100);
242 
243  forAll(candidateFaces, i)
244  {
245  label facei = candidateFaces[i];
246 
247  const vector n = normalised(mesh_.faceAreas()[facei]);
248 
249  label region = surfaces_.globalRegion
250  (
251  nearestSurface[i],
252  nearestRegion[i]
253  );
254 
255  scalar angle = degToRad(perpendicularAngle[region]);
256 
257  if (angle >= 0)
258  {
259  if (mag(n & nearestNormal[i]) < Foam::sin(angle))
260  {
261  perpFaces.insert(facei);
262  candidateCells.insert
263  (
264  mesh_.faceOwner()[facei],
265  globalToPatch[region]
266  );
267  }
268  }
269  }
270 
272  {
273  perpFaces.instance() = timeName();
274  Pout<< "Writing " << perpFaces.size()
275  << " faces that are perpendicular to the surface to set "
276  << perpFaces.objectPath() << endl;
277  perpFaces.write();
278  }
279  return candidateCells;
280 }
281 
282 
283 // Check if moving face to new points causes a 'collapsed' face.
284 // Uses new point position only for the face, not the neighbouring
285 // cell centres
286 bool Foam::meshRefinement::isCollapsedFace
287 (
288  const pointField& points,
289  const pointField& neiCc,
290  const scalar minFaceArea,
291  const scalar maxNonOrtho,
292  const label facei
293 ) const
294 {
295  // Severe nonorthogonality threshold
296  const scalar severeNonorthogonalityThreshold =
297  ::cos(degToRad(maxNonOrtho));
298 
299  vector s = mesh_.faces()[facei].areaNormal(points);
300  scalar magS = mag(s);
301 
302  // Check face area
303  if (magS < minFaceArea)
304  {
305  return true;
306  }
307 
308  // Check orthogonality
309  const point& ownCc = mesh_.cellCentres()[mesh_.faceOwner()[facei]];
310 
311  if (mesh_.isInternalFace(facei))
312  {
313  label nei = mesh_.faceNeighbour()[facei];
314  vector d = mesh_.cellCentres()[nei] - ownCc;
315 
316  scalar dDotS = (d & s)/(mag(d)*magS + VSMALL);
317 
318  if (dDotS < severeNonorthogonalityThreshold)
319  {
320  return true;
321  }
322  else
323  {
324  return false;
325  }
326  }
327  else
328  {
329  label patchi = mesh_.boundaryMesh().whichPatch(facei);
330 
331  if (mesh_.boundaryMesh()[patchi].coupled())
332  {
333  vector d = neiCc[facei-mesh_.nInternalFaces()] - ownCc;
334 
335  scalar dDotS = (d & s)/(mag(d)*magS + VSMALL);
336 
337  if (dDotS < severeNonorthogonalityThreshold)
338  {
339  return true;
340  }
341  else
342  {
343  return false;
344  }
345  }
346  else
347  {
348  // Collapsing normal boundary face does not cause problems with
349  // non-orthogonality
350  return false;
351  }
352  }
353 }
354 
355 
356 // Check if moving cell to new points causes it to collapse.
357 bool Foam::meshRefinement::isCollapsedCell
358 (
359  const pointField& points,
360  const scalar volFraction,
361  const label celli
362 ) const
363 {
364  scalar vol = mesh_.cells()[celli].mag(points, mesh_.faces());
365 
366  if (vol/mesh_.cellVolumes()[celli] < volFraction)
367  {
368  return true;
369  }
370  else
371  {
372  return false;
373  }
374 }
375 
376 
377 // Returns list with for every internal face -1 or the patch they should
378 // be baffled into. Gets run after createBaffles so all the unzoned surface
379 // intersections have already been turned into baffles. (Note: zoned surfaces
380 // are not baffled at this stage)
381 // Used to remove cells by baffling all their faces and have the
382 // splitMeshRegions chuck away non used regions.
383 Foam::labelList Foam::meshRefinement::markFacesOnProblemCells
384 (
385  const dictionary& motionDict,
386  const bool removeEdgeConnectedCells,
387  const scalarField& perpendicularAngle,
388  const labelList& globalToPatch
389 ) const
390 {
391  const labelList& cellLevel = meshCutter_.cellLevel();
392  const labelList& pointLevel = meshCutter_.pointLevel();
393  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
394 
395 
396  // Mark all points and edges on baffle patches (so not on any inlets,
397  // outlets etc.)
398  boolList isBoundaryPoint(mesh_.nPoints(), false);
399  boolList isBoundaryEdge(mesh_.nEdges(), false);
400  boolList isBoundaryFace(mesh_.nFaces(), false);
401 
402  // Fill boundary data. All elements on meshed patches get marked.
403  // Get the labels of added patches.
404  labelList adaptPatchIDs(meshedPatches());
405 
406  forAll(adaptPatchIDs, i)
407  {
408  const polyPatch& pp = patches[adaptPatchIDs[i]];
409 
410  label facei = pp.start();
411 
412  forAll(pp, j)
413  {
414  markBoundaryFace
415  (
416  facei,
417  isBoundaryFace,
418  isBoundaryEdge,
419  isBoundaryPoint
420  );
421 
422  facei++;
423  }
424  }
425 
426 
427  // Per face the nearest adaptPatch
428  const labelList nearestAdaptPatch(nearestPatch(adaptPatchIDs));
429 
430 
431  // Per internal face (boundary faces not used) the patch that the
432  // baffle should get (or -1)
433  labelList facePatch(mesh_.nFaces(), -1);
434 
435  // Swap neighbouring cell centres and cell level
436  labelList neiLevel(mesh_.nBoundaryFaces());
437  pointField neiCc(mesh_.nBoundaryFaces());
438  calcNeighbourData(neiLevel, neiCc);
439 
440 
441  // Count of faces marked for baffling
442  label nBaffleFaces = 0;
443  bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
444 
445  // Count of faces not baffled since would not cause a collapse
446  label nPrevented = 0;
447 
448  if (removeEdgeConnectedCells && max(perpendicularAngle) >= 0)
449  {
450  Info<< "markFacesOnProblemCells :"
451  << " Checking for edge-connected cells of highly differing sizes."
452  << endl;
453 
454  // Pick up the cells that need to be removed and (a guess for)
455  // the patch they should be patched with.
456  Map<label> problemCells
457  (
458  findEdgeConnectedProblemCells
459  (
460  perpendicularAngle,
461  globalToPatch
462  )
463  );
464 
465  // Baffle all faces of cells that need to be removed
466  forAllConstIters(problemCells, iter)
467  {
468  const cell& cFaces = mesh_.cells()[iter.key()];
469 
470  forAll(cFaces, i)
471  {
472  label facei = cFaces[i];
473 
474  if (facePatch[facei] == -1 && mesh_.isInternalFace(facei))
475  {
476  facePatch[facei] = nearestAdaptPatch[facei];
477  nBaffleFaces++;
478 
479  // Mark face as a 'boundary'
480  markBoundaryFace
481  (
482  facei,
483  isBoundaryFace,
484  isBoundaryEdge,
485  isBoundaryPoint
486  );
487  }
488  }
489  }
490  Info<< "markFacesOnProblemCells : Marked "
491  << returnReduce(nBaffleFaces, sumOp<label>())
492  << " additional internal faces to be converted into baffles"
493  << " due to "
494  << returnReduce(problemCells.size(), sumOp<label>())
495  << " cells edge-connected to lower level cells." << endl;
496 
498  {
499  cellSet problemCellSet(mesh_, "problemCells", problemCells.toc());
500  problemCellSet.instance() = timeName();
501  Pout<< "Writing " << problemCellSet.size()
502  << " cells that are edge connected to coarser cell to set "
503  << problemCellSet.objectPath() << endl;
504  problemCellSet.write();
505  }
506  }
507 
509  (
510  mesh_,
511  isBoundaryPoint,
512  orEqOp<bool>(),
513  false // null value
514  );
515 
517  (
518  mesh_,
519  isBoundaryEdge,
520  orEqOp<bool>(),
521  false // null value
522  );
523 
525  (
526  mesh_,
527  isBoundaryFace,
528  orEqOp<bool>()
529  );
530 
531 
532  // See if checking for collapse
533  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
534 
535  // Collapse checking parameters
536  const scalar volFraction =
537  motionDict.getOrDefault<scalar>("minVolCollapseRatio", -1);
538 
539  const bool checkCollapse = (volFraction > 0);
540  scalar minArea = -1;
541  scalar maxNonOrtho = -1;
542 
543 
544  // Find nearest (non-baffle) surface
545  pointField newPoints;
546 
547  if (checkCollapse)
548  {
549  minArea = get<scalar>(motionDict, "minArea", dryRun_);
550  maxNonOrtho = get<scalar>(motionDict, "maxNonOrtho", dryRun_);
551 
552  Info<< "markFacesOnProblemCells :"
553  << " Deleting all-anchor surface cells only if"
554  << " snapping them violates mesh quality constraints:" << nl
555  << " snapped/original cell volume < " << volFraction << nl
556  << " face area < " << minArea << nl
557  << " non-orthogonality > " << maxNonOrtho << nl
558  << endl;
559 
560  // Construct addressing engine.
561  autoPtr<indirectPrimitivePatch> ppPtr
562  (
564  (
565  mesh_,
566  adaptPatchIDs
567  )
568  );
569  const indirectPrimitivePatch& pp = ppPtr();
570  const pointField& localPoints = pp.localPoints();
571  const labelList& meshPoints = pp.meshPoints();
572 
573  List<pointIndexHit> hitInfo;
574  labelList hitSurface;
575  surfaces_.findNearest
576  (
577  surfaceZonesInfo::getUnnamedSurfaces(surfaces_.surfZones()),
578  localPoints,
579  scalarField(localPoints.size(), sqr(GREAT)), // sqr of attraction
580  hitSurface,
581  hitInfo
582  );
583 
584  // Start off from current points
585  newPoints = mesh_.points();
586 
587  forAll(hitInfo, i)
588  {
589  if (hitInfo[i].hit())
590  {
591  newPoints[meshPoints[i]] = hitInfo[i].hitPoint();
592  }
593  }
594 
596  {
597  const_cast<Time&>(mesh_.time())++;
598  pointField oldPoints(mesh_.points());
599  mesh_.movePoints(newPoints);
600  Pout<< "Writing newPoints mesh to time " << timeName()
601  << endl;
602  write
603  (
604  debugType(debug),
605  writeType(writeLevel() | WRITEMESH),
606  mesh_.time().path()/"newPoints"
607  );
608  mesh_.movePoints(oldPoints);
609  }
610  }
611 
612 
613 
614  // For each cell count the number of anchor points that are on
615  // the boundary:
616  // 8 : check the number of (baffle) boundary faces. If 3 or more block
617  // off the cell since the cell would get squeezed down to a diamond
618  // (probably; if the 3 or more faces are unrefined (only use the
619  // anchor points))
620  // 7 : store. Used to check later on whether there are points with
621  // 3 or more of these cells. (note that on a flat surface a boundary
622  // point will only have 4 cells connected to it)
623 
624 
625  // Does cell have exactly 7 of its 8 anchor points on the boundary?
626  bitSet hasSevenBoundaryAnchorPoints(mesh_.nCells());
627  // If so what is the remaining non-boundary anchor point?
628  labelHashSet nonBoundaryAnchors(mesh_.nCells()/10000);
629 
630  // On-the-fly addressing storage.
631  DynamicList<label> dynFEdges;
632  DynamicList<label> dynCPoints;
633  labelHashSet pSet;
634 
635  forAll(cellLevel, celli)
636  {
637  const labelList& cPoints = mesh_.cellPoints(celli, pSet, dynCPoints);
638 
639  // Get number of anchor points (pointLevel <= cellLevel)
640 
641  label nBoundaryAnchors = 0;
642  label nNonAnchorBoundary = 0;
643  label nonBoundaryAnchor = -1;
644 
645  for (const label pointi : cPoints)
646  {
647  if (pointLevel[pointi] <= cellLevel[celli])
648  {
649  // Anchor point
650  if (isBoundaryPoint[pointi])
651  {
652  nBoundaryAnchors++;
653  }
654  else
655  {
656  // Anchor point which is not on the surface
657  nonBoundaryAnchor = pointi;
658  }
659  }
660  else if (isBoundaryPoint[pointi])
661  {
662  nNonAnchorBoundary++;
663  }
664  }
665 
666  if (nBoundaryAnchors == 8)
667  {
668  const cell& cFaces = mesh_.cells()[celli];
669 
670  // Count boundary faces.
671  label nBfaces = 0;
672 
673  forAll(cFaces, cFacei)
674  {
675  if (isBoundaryFace[cFaces[cFacei]])
676  {
677  nBfaces++;
678  }
679  }
680 
681  // If nBfaces > 1 make all non-boundary non-baffle faces baffles.
682  // We assume that this situation is where there is a single
683  // cell sticking out which would get flattened.
684 
685  // Eugene: delete cell no matter what.
686  //if (nBfaces > 1)
687  {
688  if
689  (
690  checkCollapse
691  && !isCollapsedCell(newPoints, volFraction, celli)
692  )
693  {
694  nPrevented++;
695  //Pout<< "Preventing baffling/removal of 8 anchor point"
696  // << " cell "
697  // << celli << " at " << mesh_.cellCentres()[celli]
698  // << " since new volume "
699  // << mesh_.cells()[celli].mag(newPoints, mesh_.faces())
700  // << " old volume " << mesh_.cellVolumes()[celli]
701  // << endl;
702  }
703  else
704  {
705  // Block all faces of cell
706  forAll(cFaces, cf)
707  {
708  label facei = cFaces[cf];
709 
710  if
711  (
712  facePatch[facei] == -1
713  && mesh_.isInternalFace(facei)
714  )
715  {
716  facePatch[facei] = nearestAdaptPatch[facei];
717  nBaffleFaces++;
718 
719  // Mark face as a 'boundary'
720  markBoundaryFace
721  (
722  facei,
723  isBoundaryFace,
724  isBoundaryEdge,
725  isBoundaryPoint
726  );
727  }
728  }
729  }
730  }
731  }
732  else if (nBoundaryAnchors == 7 && nonBoundaryAnchor != -1)
733  {
734  // Mark the cell. Store the (single!) non-boundary anchor point.
735  hasSevenBoundaryAnchorPoints.set(celli);
736  nonBoundaryAnchors.insert(nonBoundaryAnchor);
737  }
738  }
739 
740 
741  // Loop over all points. If a point is connected to 4 or more cells
742  // with 7 anchor points on the boundary set those cell's non-boundary faces
743  // to baffles
744 
745  DynamicList<label> dynPCells;
746 
747  for (const label pointi : nonBoundaryAnchors)
748  {
749  const labelList& pCells = mesh_.pointCells(pointi, dynPCells);
750 
751  // Count number of 'hasSevenBoundaryAnchorPoints' cells.
752  label n = 0;
753 
754  for (const label celli : pCells)
755  {
756  if (hasSevenBoundaryAnchorPoints.test(celli))
757  {
758  ++n;
759  }
760  }
761 
762  if (n > 3)
763  {
764  // Point in danger of being what? Remove all 7-cells.
765  for (const label celli : pCells)
766  {
767  if (hasSevenBoundaryAnchorPoints.test(celli))
768  {
769  if
770  (
771  checkCollapse
772  && !isCollapsedCell(newPoints, volFraction, celli)
773  )
774  {
775  nPrevented++;
776  //Pout<< "Preventing baffling of 7 anchor cell "
777  // << celli
778  // << " at " << mesh_.cellCentres()[celli]
779  // << " since new volume "
780  // << mesh_.cells()[celli].mag
781  // (newPoints, mesh_.faces())
782  // << " old volume " << mesh_.cellVolumes()[celli]
783  // << endl;
784  }
785  else
786  {
787  const cell& cFaces = mesh_.cells()[celli];
788 
789  for (const label facei : cFaces)
790  {
791  if
792  (
793  facePatch[facei] == -1
794  && mesh_.isInternalFace(facei)
795  )
796  {
797  facePatch[facei] = nearestAdaptPatch[facei];
798  nBaffleFaces++;
799 
800  // Mark face as a 'boundary'
801  markBoundaryFace
802  (
803  facei,
804  isBoundaryFace,
805  isBoundaryEdge,
806  isBoundaryPoint
807  );
808  }
809  }
810  }
811  }
812  }
813  }
814  }
815 
816 
817  // Sync all. (note that pointdata and facedata not used anymore but sync
818  // anyway)
819 
821  (
822  mesh_,
823  isBoundaryPoint,
824  orEqOp<bool>(),
825  false // null value
826  );
827 
829  (
830  mesh_,
831  isBoundaryEdge,
832  orEqOp<bool>(),
833  false // null value
834  );
835 
837  (
838  mesh_,
839  isBoundaryFace,
840  orEqOp<bool>()
841  );
842 
843 
844  // Find faces with all edges on the boundary and make them baffles
845  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
846  {
847  if (facePatch[facei] == -1)
848  {
849  const labelList& fEdges = mesh_.faceEdges(facei, dynFEdges);
850  label nFaceBoundaryEdges = 0;
851 
852  for (const label edgei : fEdges)
853  {
854  if (isBoundaryEdge[edgei])
855  {
856  ++nFaceBoundaryEdges;
857  }
858  }
859 
860  if (nFaceBoundaryEdges == fEdges.size())
861  {
862  if
863  (
864  checkCollapse
865  && !isCollapsedFace
866  (
867  newPoints,
868  neiCc,
869  minArea,
870  maxNonOrtho,
871  facei
872  )
873  )
874  {
875  nPrevented++;
876  //Pout<< "Preventing baffling (to avoid collapse) of face "
877  // << facei
878  // << " with all boundary edges "
879  // << " at " << mesh_.faceCentres()[facei]
880  // << endl;
881  }
882  else
883  {
884  facePatch[facei] = nearestAdaptPatch[facei];
885  nBaffleFaces++;
886 
887  // Do NOT update boundary data since this would grow blocked
888  // faces across gaps.
889  }
890  }
891  }
892  }
893 
894  for (const polyPatch& pp : patches)
895  {
896  if (pp.coupled())
897  {
898  label facei = pp.start();
899 
900  forAll(pp, i)
901  {
902  if (facePatch[facei] == -1)
903  {
904  const labelList& fEdges = mesh_.faceEdges(facei, dynFEdges);
905  label nFaceBoundaryEdges = 0;
906 
907  for (const label edgei : fEdges)
908  {
909  if (isBoundaryEdge[edgei])
910  {
911  ++nFaceBoundaryEdges;
912  }
913  }
914 
915  if (nFaceBoundaryEdges == fEdges.size())
916  {
917  if
918  (
919  checkCollapse
920  && !isCollapsedFace
921  (
922  newPoints,
923  neiCc,
924  minArea,
925  maxNonOrtho,
926  facei
927  )
928  )
929  {
930  nPrevented++;
931  //Pout<< "Preventing baffling of coupled face "
932  // << facei
933  // << " with all boundary edges "
934  // << " at " << mesh_.faceCentres()[facei]
935  // << endl;
936  }
937  else
938  {
939  facePatch[facei] = nearestAdaptPatch[facei];
940  if (isMasterFace.test(facei))
941  {
942  ++nBaffleFaces;
943  }
944 
945  // Do NOT update boundary data since this would grow
946  // blocked faces across gaps.
947  }
948  }
949  }
950 
951  facei++;
952  }
953  }
954  }
955 
956 
957  // Because of isCollapsedFace one side can decide not to baffle whereas
958  // the other side does so sync. Baffling is preferred over not baffling.
959  if (checkCollapse) // Or always?
960  {
962  (
963  mesh_,
964  facePatch,
965  maxEqOp<label>()
966  );
967  }
968 
969  Info<< "markFacesOnProblemCells : marked "
970  << returnReduce(nBaffleFaces, sumOp<label>())
971  << " additional internal faces to be converted into baffles."
972  << endl;
973 
974  if (checkCollapse)
975  {
976  Info<< "markFacesOnProblemCells : prevented "
977  << returnReduce(nPrevented, sumOp<label>())
978  << " internal faces from getting converted into baffles."
979  << endl;
980  }
981 
982  return facePatch;
983 }
984 
985 
986 // Mark faces to be baffled to prevent snapping problems. Does
987 // test to find nearest surface and checks which faces would get squashed.
988 Foam::labelList Foam::meshRefinement::markFacesOnProblemCellsGeometric
989 (
990  const snapParameters& snapParams,
991  const dictionary& motionDict,
992  const labelList& globalToMasterPatch,
993  const labelList& globalToSlavePatch
994 ) const
995 {
996  pointField oldPoints(mesh_.points());
997 
998  // Repeat (most of) snappySnapDriver::doSnap
999  {
1000  labelList adaptPatchIDs(meshedPatches());
1001 
1002  // Construct addressing engine.
1003  autoPtr<indirectPrimitivePatch> ppPtr
1004  (
1006  (
1007  mesh_,
1008  adaptPatchIDs
1009  )
1010  );
1011  indirectPrimitivePatch& pp = ppPtr();
1012 
1013  // Distance to attract to nearest feature on surface
1014  const scalarField snapDist
1015  (
1016  snappySnapDriver::calcSnapDistance(mesh_, snapParams, pp)
1017  );
1018 
1019 
1020  // Construct iterative mesh mover.
1021  Info<< "Constructing mesh displacer ..." << endl;
1022  Info<< "Using mesh parameters " << motionDict << nl << endl;
1023 
1024  const pointMesh& pMesh = pointMesh::New(mesh_);
1025 
1026  motionSmoother meshMover
1027  (
1028  mesh_,
1029  pp,
1030  adaptPatchIDs,
1031  meshRefinement::makeDisplacementField(pMesh, adaptPatchIDs)(),
1032  motionDict
1033  );
1034 
1035 
1036  // Check initial mesh
1037  Info<< "Checking initial mesh ..." << endl;
1038  labelHashSet wrongFaces(mesh_.nFaces()/100);
1040  (
1041  false,
1042  mesh_,
1043  motionDict,
1044  wrongFaces,
1045  dryRun_
1046  );
1047  const label nInitErrors = returnReduce
1048  (
1049  wrongFaces.size(),
1050  sumOp<label>()
1051  );
1052 
1053  Info<< "Detected " << nInitErrors << " illegal faces"
1054  << " (concave, zero area or negative cell pyramid volume)"
1055  << endl;
1056 
1057 
1058  Info<< "Checked initial mesh in = "
1059  << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl;
1060 
1061  // Pre-smooth patch vertices (so before determining nearest)
1063  (
1064  *this,
1065  snapParams,
1066  nInitErrors,
1067  List<labelPair>(0), //baffles
1068  meshMover
1069  );
1070 
1071  pointField nearestPoint;
1072  vectorField nearestNormal;
1073  const vectorField disp
1074  (
1075  snappySnapDriver::calcNearestSurface
1076  (
1077  snapParams.strictRegionSnap(),
1078  *this,
1079  globalToMasterPatch,
1080  globalToSlavePatch,
1081  snapDist, // attraction
1082  pp,
1083  nearestPoint,
1084  nearestNormal
1085  )
1086  );
1087 
1088  const labelList& meshPoints = pp.meshPoints();
1089 
1090  pointField newPoints(mesh_.points());
1091  forAll(meshPoints, i)
1092  {
1093  newPoints[meshPoints[i]] += disp[i];
1094  }
1095 
1097  (
1098  mesh_,
1099  newPoints,
1100  minMagSqrEqOp<point>(), // combine op
1101  vector(GREAT, GREAT, GREAT) // null value (note: cannot use VGREAT)
1102  );
1103 
1104  mesh_.movePoints(newPoints);
1105  }
1106 
1107 
1108  // Per face the nearest adaptPatch
1109  const labelList nearestAdaptPatch(nearestPatch(meshedPatches()));
1110 
1111  // Per face (internal or coupled!) the patch that the
1112  // baffle should get (or -1).
1113  labelList facePatch(mesh_.nFaces(), -1);
1114  // Count of baffled faces
1115  label nBaffleFaces = 0;
1116 
1117  {
1118  faceSet wrongFaces(mesh_, "wrongFaces", 100);
1119  {
1120  //motionSmoother::checkMesh(false, mesh_, motionDict, wrongFaces);
1121 
1122  // Just check the errors from squashing
1123  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1124 
1125  const labelList allFaces(identity(mesh_.nFaces()));
1126  label nWrongFaces = 0;
1127 
1128  //const scalar minV
1129  //(motionDict.get<scalar>("minVol", keyType::REGEX_RECURSIVE));
1130  //if (minV > -GREAT)
1131  //{
1132  // polyMeshGeometry::checkFacePyramids
1133  // (
1134  // false,
1135  // minV,
1136  // mesh_,
1137  // mesh_.cellCentres(),
1138  // mesh_.points(),
1139  // allFaces,
1140  // List<labelPair>(0),
1141  // &wrongFaces
1142  // );
1143  //
1144  // label nNewWrongFaces = returnReduce
1145  // (
1146  // wrongFaces.size(),
1147  // sumOp<label>()
1148  // );
1149  //
1150  // Info<< " faces with pyramid volume < "
1151  // << setw(5) << minV
1152  // << " m^3 : "
1153  // << nNewWrongFaces-nWrongFaces << endl;
1154  //
1155  // nWrongFaces = nNewWrongFaces;
1156  //}
1157 
1158  scalar minArea(get<scalar>(motionDict, "minArea", dryRun_));
1159  if (minArea > -SMALL)
1160  {
1162  (
1163  false,
1164  minArea,
1165  mesh_,
1166  mesh_.faceAreas(),
1167  allFaces,
1168  &wrongFaces
1169  );
1170 
1171  label nNewWrongFaces = returnReduce
1172  (
1173  wrongFaces.size(),
1174  sumOp<label>()
1175  );
1176 
1177  Info<< " faces with area < "
1178  << setw(5) << minArea
1179  << " m^2 : "
1180  << nNewWrongFaces-nWrongFaces << endl;
1181 
1182  nWrongFaces = nNewWrongFaces;
1183  }
1184 
1185  scalar minDet(get<scalar>(motionDict, "minDeterminant", dryRun_));
1186  if (minDet > -1)
1187  {
1189  (
1190  false,
1191  minDet,
1192  mesh_,
1193  mesh_.faceAreas(),
1194  allFaces,
1195  polyMeshGeometry::affectedCells(mesh_, allFaces),
1196  &wrongFaces
1197  );
1198 
1199  label nNewWrongFaces = returnReduce
1200  (
1201  wrongFaces.size(),
1202  sumOp<label>()
1203  );
1204 
1205  Info<< " faces on cells with determinant < "
1206  << setw(5) << minDet << " : "
1207  << nNewWrongFaces-nWrongFaces << endl;
1208 
1209  nWrongFaces = nNewWrongFaces;
1210  }
1211  }
1212 
1213 
1214  for (const label facei : wrongFaces)
1215  {
1216  const label patchi = mesh_.boundaryMesh().whichPatch(facei);
1217 
1218  if (patchi == -1 || mesh_.boundaryMesh()[patchi].coupled())
1219  {
1220  facePatch[facei] = nearestAdaptPatch[facei];
1221  nBaffleFaces++;
1222 
1223  //Pout<< " " << facei
1224  // //<< " on patch " << mesh_.boundaryMesh()[patchi].name()
1225  // << " is destined for patch " << facePatch[facei]
1226  // << endl;
1227  }
1228  }
1229  }
1230 
1231 
1232  // Restore points.
1233  mesh_.movePoints(oldPoints);
1234 
1235 
1236  Info<< "markFacesOnProblemCellsGeometric : marked "
1237  << returnReduce(nBaffleFaces, sumOp<label>())
1238  << " additional internal and coupled faces"
1239  << " to be converted into baffles." << endl;
1240 
1242  (
1243  mesh_,
1244  facePatch,
1245  maxEqOp<label>()
1246  );
1247 
1248  return facePatch;
1249 }
1250 
1251 
1252 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::syncTools::syncEdgeList
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
Definition: syncToolsTemplates.C:800
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::snappySnapDriver::calcSnapDistance
static scalarField calcSnapDistance(const fvMesh &mesh, const snapParameters &snapParams, const indirectPrimitivePatch &)
Calculate edge length per patch point.
Definition: snappySnapDriver.C:764
snappySnapDriver.H
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputSpray.H:25
polyMeshGeometry.H
Foam::sin
dimensionedScalar sin(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:264
motionSmoother.H
Foam::MeshObject< polyMesh, UpdateableMeshObject, pointMesh >::New
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create a new MeshObject.
Definition: MeshObject.C:48
Foam::Map
A HashTable to objects of type <T> with a label key.
Definition: lumpedPointController.H:69
unitConversion.H
Unit conversion functions.
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:65
Foam::motionSmootherAlgo::checkMesh
static bool checkMesh(const bool report, const polyMesh &mesh, const dictionary &dict, labelHashSet &wrongFaces, const bool dryRun=false)
Check mesh with mesh settings in dict. Collects incorrect faces.
Definition: motionSmootherAlgoCheck.C:462
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::syncTools::getMasterFaces
static bitSet getMasterFaces(const polyMesh &mesh)
Definition: syncTools.C:126
Foam::syncTools::syncPointPositions
static void syncPointPositions(const polyMesh &mesh, List< point > &positions, const CombineOp &cop, const point &nullValue)
Synchronize locations on all mesh points.
Definition: syncTools.H:201
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
syncTools.H
Foam::polyBoundaryMesh::start
label start() const
The start label of the boundary faces in the polyMesh face list.
Definition: polyBoundaryMesh.C:611
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:721
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
searchableSurfaces.H
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::syncTools::syncFaceList
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:396
Foam::polyMeshGeometry::affectedCells
static labelList affectedCells(const polyMesh &, const labelList &changedFaces)
Helper function: get affected cells from faces.
Definition: polyMeshGeometry.C:183
Foam::polyMeshGeometry::checkFaceArea
static bool checkFaceArea(const bool report, const scalar minArea, const polyMesh &, const vectorField &faceAreas, const labelList &checkFaces, labelHashSet *setPtr)
Small faces.
Definition: polyMeshGeometry.C:1932
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
refinementSurfaces.H
faceSet.H
Foam::primitiveMesh::faceEdges
const labelListList & faceEdges() const
Definition: primitiveMeshEdges.C:528
nBfaces
label nBfaces
Definition: readKivaGrid.H:45
IOmanip.H
Istream and Ostream manipulators taking arguments.
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
indirectPrimitivePatch.H
timeName
word timeName
Definition: getTimeIndex.H:3
Foam::meshRefinement::makePatch
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
Definition: meshRefinement.C:1898
meshRefinement.H
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
fvMesh.H
Foam::setw
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::surfaceZonesInfo::getUnnamedSurfaces
static labelList getUnnamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of unnamed surfaces (surfaces without faceZoneName)
Definition: surfaceZonesInfo.C:242
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:487
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
Time.H
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::polyMesh::faces
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1094
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::nl
constexpr char nl
Definition: Ostream.H:404
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
f
labelList f(nPoints)
Foam::List< label >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
snapParameters.H
Foam::vtk::write
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Definition: foamVtkOutputTemplates.C:36
cellSet.H
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::polyMeshGeometry::checkCellDeterminant
static bool checkCellDeterminant(const bool report, const scalar minDet, const polyMesh &, const vectorField &faceAreas, const labelList &checkFaces, const labelList &affectedCells, labelHashSet *setPtr)
Area of internal faces v.s. boundary faces.
Definition: polyMeshGeometry.C:1989
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Foam::snappySnapDriver::preSmoothPatch
static void preSmoothPatch(const meshRefinement &meshRefiner, const snapParameters &snapParams, const label nInitErrors, const List< labelPair > &baffles, motionSmoother &)
Smooth the mesh (patch and internal) to increase visibility.
Definition: snappySnapDriver.C:804
Foam::meshRefinement::makeDisplacementField
static tmp< pointVectorField > makeDisplacementField(const pointMesh &pMesh, const labelList &adaptPatchIDs)
Helper function to make a pointVectorField with correct.
Definition: meshRefinement.C:1940
Foam::meshRefinement::MESH
Definition: meshRefinement.H:94
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265
pointSet.H