meshRefinementBlock.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) 2018-2019 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "meshRefinement.H"
29 #include "fvMesh.H"
30 #include "Time.H"
31 #include "refinementSurfaces.H"
32 #include "removeCells.H"
33 #include "unitConversion.H"
34 #include "bitSet.H"
35 
36 #include "FaceCellWave.H"
37 #include "volFields.H"
38 #include "wallPoints.H"
39 #include "searchableSurfaces.H"
41 
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 
44 //Foam::label Foam::meshRefinement::markFakeGapRefinement
45 //(
46 // const scalar planarCos,
47 //
48 // const label nAllowRefine,
49 // const labelList& neiLevel,
50 // const pointField& neiCc,
51 //
52 // labelList& refineCell,
53 // label& nRefine
54 //) const
55 //{
56 // label oldNRefine = nRefine;
57 //
58 //
59 // // Collect candidate faces (i.e. intersecting any surface and
60 // // owner/neighbour not yet refined.
61 // const labelList testFaces(getRefineCandidateFaces(refineCell));
62 //
63 // // Collect segments
64 // pointField start(testFaces.size());
65 // pointField end(testFaces.size());
66 // labelList minLevel(testFaces.size());
67 //
68 // calcCellCellRays
69 // (
70 // neiCc,
71 // neiLevel,
72 // testFaces,
73 // start,
74 // end,
75 // minLevel
76 // );
77 //
78 //
79 // // Re-use the gap shooting methods. This needs:
80 // // - shell gapLevel : faked. Set to 0,labelMax
81 // // - surface gapLevel : faked by overwriting
82 //
83 //
84 // List<FixedList<label, 3>>& surfGapLevel = const_cast
85 // <
86 // List<FixedList<label, 3>>&
87 // >(surfaces_.extendedGapLevel());
88 //
89 // List<volumeType>& surfGapMode = const_cast
90 // <
91 // List<volumeType>&
92 // >(surfaces_.extendedGapMode());
93 //
94 // const List<FixedList<label, 3>> surfOldLevel(surfGapLevel);
95 // const List<volumeType> surfOldMode(surfGapMode);
96 //
97 // // Set the extended gap levels
98 // forAll(surfaces_.gapLevel(), regioni)
99 // {
100 // surfGapLevel[regioni] = FixedList<label, 3>
101 // ({
102 // 3,
103 // -1,
104 // surfaces_.gapLevel()[regioni]+1
105 // });
106 // }
107 // surfGapMode = volumeType::MIXED;
108 //
109 //Pout<< "gapLevel was:" << surfOldLevel << endl;
110 //Pout<< "gapLevel now:" << surfGapLevel << endl;
111 //Pout<< "gapMode was:" << surfOldMode << endl;
112 //Pout<< "gapMode now:" << surfGapMode << endl;
113 //Pout<< "nRefine was:" << oldNRefine << endl;
114 //
115 //
116 //
117 // List<List<FixedList<label, 3>>>& shellGapLevel = const_cast
118 // <
119 // List<List<FixedList<label, 3>>>&
120 // >(shells_.extendedGapLevel());
121 //
122 // List<List<volumeType>>& shellGapMode = const_cast
123 // <
124 // List<List<volumeType>>&
125 // >(shells_.extendedGapMode());
126 //
127 // const List<List<FixedList<label, 3>>> shellOldLevel(shellGapLevel);
128 // const List<List<volumeType>> shellOldMode(shellGapMode);
129 //
130 // // Set the extended gap levels
131 // forAll(shellGapLevel, shelli)
132 // {
133 // shellGapLevel[shelli] = FixedList<label, 3>({3, -1, labelMax});
134 // shellGapMode[shelli] = volumeType::MIXED;
135 // }
136 //Pout<< "shellLevel was:" << shellOldLevel << endl;
137 //Pout<< "shellLevel now:" << shellGapLevel << endl;
138 //
139 // const label nAdditionalRefined = markSurfaceGapRefinement
140 // (
141 // planarCos,
142 //
143 // nAllowRefine,
144 // neiLevel,
145 // neiCc,
146 //
147 // refineCell,
148 // nRefine
149 // );
150 //
151 //Pout<< "nRefine now:" << nRefine << endl;
152 //
153 // // Restore
154 // surfGapLevel = surfOldLevel;
155 // surfGapMode = surfOldMode;
156 // shellGapLevel = shellOldLevel;
157 // shellGapMode = shellOldMode;
158 //
159 // return nAdditionalRefined;
160 //}
161 
162 
164 (
165  const labelList& cellLevel,
166  const labelList& neiLevel,
167  const labelList& refineCell,
168  bitSet& isOutsideFace
169 ) const
170 {
171  // Get faces:
172  // - on outside of cell set
173  // - inbetween same cell level (i.e. quads)
174 
175  isOutsideFace.setSize(mesh_.nFaces());
176  isOutsideFace = Zero;
177 
178  forAll(mesh_.faceNeighbour(), facei)
179  {
180  label own = mesh_.faceOwner()[facei];
181  label nei = mesh_.faceNeighbour()[facei];
182  if
183  (
184  (cellLevel[own] == cellLevel[nei])
185  && (
186  (refineCell[own] != -1)
187  != (refineCell[nei] != -1)
188  )
189  )
190  {
191  isOutsideFace.set(facei);
192  }
193  }
194  {
195 
196  const label nBnd = mesh_.nFaces()-mesh_.nInternalFaces();
197 
198  labelList neiRefineCell(nBnd);
199  syncTools::swapBoundaryCellList(mesh_, refineCell, neiRefineCell);
200  for (label bFacei = 0; bFacei < nBnd; ++bFacei)
201  {
202  label facei = mesh_.nInternalFaces()+bFacei;
203  label own = mesh_.faceOwner()[facei];
204 
205  if
206  (
207  (cellLevel[own] == neiLevel[bFacei])
208  && (
209  (refineCell[own] != -1)
210  != (neiRefineCell[bFacei] != -1)
211  )
212  )
213  {
214  isOutsideFace.set(facei);
215  }
216  }
217  }
218 }
219 
220 
222 (
223  const bitSet& isOutsideFace,
224  const label celli
225 ) const
226 {
227  const cell& cFaces = mesh_.cells()[celli];
228  const vectorField& faceAreas = mesh_.faceAreas();
229 
230  Vector<bool> haveDirs(vector::uniform(false));
231 
232  forAll(cFaces, cFacei)
233  {
234  const label facei = cFaces[cFacei];
235 
236  if (isOutsideFace[facei])
237  {
238  const vector& n = faceAreas[facei];
239  scalar magSqrN = magSqr(n);
240 
241  if (magSqrN > ROOTVSMALL)
242  {
243  for
244  (
245  direction dir = 0;
246  dir < pTraits<vector>::nComponents;
247  dir++
248  )
249  {
250  if (Foam::sqr(n[dir]) > 0.99*magSqrN)
251  {
252  haveDirs[dir] = true;
253  break;
254  }
255  }
256  }
257  }
258  }
259 
260  label nDirs = 0;
261  forAll(haveDirs, dir)
262  {
263  if (haveDirs[dir])
264  {
265  nDirs++;
266  }
267  }
268  return nDirs;
269 }
270 
271 
273 (
274  const labelList& neiLevel,
275  const bitSet& isOutsideFace,
277  label& nRefine
278 ) const
279 {
280  // Get cells with three or more outside faces
281  const cellList& cells = mesh_.cells();
282  forAll(cells, celli)
283  {
284  if (refineCell[celli] == -1)
285  {
286  if (countFaceDirs(isOutsideFace, celli) == 3)
287  {
288  // Mark cell with any value
289  refineCell[celli] = 0;
290  nRefine++;
291  }
292  }
293  }
294 }
295 
296 
297 void Foam::meshRefinement::markMultiRegionCell
298 (
299  const label celli,
300  const FixedList<label, 3>& surface,
301 
302  Map<FixedList<label, 3>>& cellToRegions,
303  bitSet& isMultiRegion
304 ) const
305 {
306  if (!isMultiRegion[celli])
307  {
308  Map<FixedList<label, 3>>::iterator fnd = cellToRegions.find(celli);
309  if (!fnd.found())
310  {
311  cellToRegions.insert(celli, surface);
312  }
313  else if (fnd() != surface)
314  {
315  // Found multiple intersections on cell
316  isMultiRegion.set(celli);
317  }
318  }
319 }
320 
321 
322 void Foam::meshRefinement::detectMultiRegionCells
323 (
324  const labelListList& faceZones,
325  const labelList& testFaces,
326 
327  const labelList& surface1,
328  const List<pointIndexHit>& hit1,
329  const labelList& region1,
330 
331  const labelList& surface2,
332  const List<pointIndexHit>& hit2,
333  const labelList& region2,
334 
335  bitSet& isMultiRegion
336 ) const
337 {
338  isMultiRegion.clear();
339  isMultiRegion.setSize(mesh_.nCells());
340 
341  Map<FixedList<label, 3>> cellToRegions(testFaces.size());
342 
343  forAll(testFaces, i)
344  {
345  const pointIndexHit& info1 = hit1[i];
346  if (info1.hit())
347  {
348  const label facei = testFaces[i];
349  const labelList& fz1 = faceZones[surface1[i]];
350  const FixedList<label, 3> surfaceInfo1
351  ({
352  surface1[i],
353  region1[i],
354  (fz1.size() ? fz1[info1.index()] : region1[i])
355  });
356 
357  markMultiRegionCell
358  (
359  mesh_.faceOwner()[facei],
360  surfaceInfo1,
361  cellToRegions,
362  isMultiRegion
363  );
364  if (mesh_.isInternalFace(facei))
365  {
366  markMultiRegionCell
367  (
368  mesh_.faceNeighbour()[facei],
369  surfaceInfo1,
370  cellToRegions,
371  isMultiRegion
372  );
373  }
374 
375  const pointIndexHit& info2 = hit2[i];
376 
377  if (info2.hit() && info1 != info2)
378  {
379  const labelList& fz2 = faceZones[surface2[i]];
380  const FixedList<label, 3> surfaceInfo2
381  ({
382  surface2[i],
383  region2[i],
384  (fz2.size() ? fz2[info2.index()] : region2[i])
385  });
386 
387  markMultiRegionCell
388  (
389  mesh_.faceOwner()[facei],
390  surfaceInfo2,
391  cellToRegions,
392  isMultiRegion
393  );
394  if (mesh_.isInternalFace(facei))
395  {
396  markMultiRegionCell
397  (
398  mesh_.faceNeighbour()[facei],
399  surfaceInfo2,
400  cellToRegions,
401  isMultiRegion
402  );
403  }
404  }
405  }
406  }
407 
408 
410  {
411  volScalarField multiCell
412  (
413  IOobject
414  (
415  "multiCell",
416  mesh_.time().timeName(),
417  mesh_,
420  false
421  ),
422  mesh_,
424  (
425  "zero",
426  dimensionSet(0, 1, 0, 0, 0),
427  0.0
428  )
429  );
430  forAll(isMultiRegion, celli)
431  {
432  if (isMultiRegion[celli])
433  {
434  multiCell[celli] = 1.0;
435  }
436  }
437 
438  Info<< "Writing all multi cells to " << multiCell.name() << endl;
439  multiCell.write();
440  }
441 }
442 
443 
444 Foam::label Foam::meshRefinement::markProximityRefinementWave
445 (
446  const scalar planarCos,
447  const labelList& blockedSurfaces,
448  const label nAllowRefine,
449  const labelList& neiLevel,
450  const pointField& neiCc,
451 
452  labelList& refineCell,
453  label& nRefine
454 ) const
455 {
456  labelListList faceZones(surfaces_.surfaces().size());
457  {
458  // If triSurface do additional zoning based on connectivity
459  for (const label surfi : blockedSurfaces)
460  {
461  const label geomi = surfaces_.surfaces()[surfi];
462  const searchableSurface& s = surfaces_.geometry()[geomi];
463  if (isA<triSurfaceMesh>(s) && !isA<distributedTriSurfaceMesh>(s))
464  {
465  const triSurfaceMesh& surf = refCast<const triSurfaceMesh>(s);
466  const labelListList& edFaces = surf.edgeFaces();
467  boolList isOpenEdge(edFaces.size(), false);
468  forAll(edFaces, i)
469  {
470  if (edFaces[i].size() == 1)
471  {
472  isOpenEdge[i] = true;
473  }
474  }
475 
476  labelList faceZone;
477  const label nZones = surf.markZones(isOpenEdge, faceZone);
478  if (nZones > 1)
479  {
480  faceZones[surfi].transfer(faceZone);
481  }
482  }
483  }
484  }
485 
486 
487  // Re-work the blockLevel of the blockedSurfaces into a length scale
488  // and a number of cells to cross
489  scalarField regionToBlockSize(surfaces_.blockLevel().size(), 0);
490  //label nIters = 2;
491 
492  for (const label surfi : blockedSurfaces)
493  {
494  const label geomi = surfaces_.surfaces()[surfi];
495  const searchableSurface& s = surfaces_.geometry()[geomi];
496  const label nRegions = s.regions().size();
497  for (label regioni = 0; regioni < nRegions; regioni++)
498  {
499  const label globalRegioni = surfaces_.globalRegion(surfi, regioni);
500  const label bLevel = surfaces_.blockLevel()[globalRegioni];
501  regionToBlockSize[globalRegioni] =
502  meshCutter_.level0EdgeLength()/pow(2.0, bLevel);
503 
504  //const label mLevel = surfaces_.maxLevel()[globalRegioni];
508  //if (isA<triSurfaceMesh>(s) && !isA<distributedTriSurfaceMesh>(s))
509  //{
510  // const triSurfaceMesh& surf = refCast<const triSurfaceMesh>(s);
511  //}
512 
513  //nIters = max(nIters, (2<<(mLevel-bLevel)));
514  }
515  }
516  // Clever limiting of the number of iterations (= max cells in the channel)
517  // since it has too many problematic issues, e.g. with volume refinement
518  // and the real check uses the proper distance anyway just disable.
519  const label nIters = mesh_.globalData().nTotalCells();
520 
521 
522  // Collect candidate faces (i.e. intersecting any surface and
523  // owner/neighbour not yet refined)
524  const labelList testFaces(getRefineCandidateFaces(refineCell));
525 
526  // Collect segments
527  pointField start(testFaces.size());
528  pointField end(testFaces.size());
529  labelList minLevel(testFaces.size());
530 
531  calcCellCellRays
532  (
533  neiCc,
534  neiLevel,
535  testFaces,
536  start,
537  end,
538  minLevel
539  );
540  // TBD. correct nIters for actual cellLevel (since e.g. volume refinement
541  // might add to cell level). Unfortunately we only have minLevel,
542  // not maxLevel. Problem: what if volume refinement only in middle of
543  // channel? Workaround: have dummy surface with e.g. maxLevel 100 to
544  // force nIters to be high enough.
545 
546 
547  // Test for all intersections (with surfaces of higher gap level than
548  // minLevel) and cache per cell the max surface level and the local normal
549  // on that surface.
550 
551  labelList surface1;
552  List<pointIndexHit> hit1;
553  labelList region1;
554  vectorField normal1;
555 
556  labelList surface2;
557  List<pointIndexHit> hit2;
558  labelList region2;
559  vectorField normal2;
560 
561  surfaces_.findNearestIntersection
562  (
563  blockedSurfaces,
564  start,
565  end,
566 
567  surface1,
568  hit1,
569  region1, // local region
570  normal1,
571 
572  surface2,
573  hit2,
574  region2, // local region
575  normal2
576  );
577 
578 
579  // Detect cells that are using multiple surface regions
580  bitSet isMultiRegion;
581  detectMultiRegionCells
582  (
583  faceZones,
584  testFaces,
585 
586  surface1,
587  hit1,
588  region1,
589 
590  surface2,
591  hit2,
592  region2,
593 
594  isMultiRegion
595  );
596 
597 
598  label n = 0;
599  forAll(testFaces, i)
600  {
601  if (hit1[i].hit())
602  {
603  n++;
604  }
605  }
606 
607  List<wallPoints> faceDist(n);
608  labelList changedFaces(n);
609  n = 0;
610 
611  DynamicList<point> originLocation(2);
612  DynamicList<scalar> originDistSqr(2);
613  DynamicList<FixedList<label, 3>> originSurface(2);
614  //DynamicList<point> originNormal(2);
615 
616 
617  //- To avoid walking through surfaces we mark all faces that have been
618  // intersected. We can either mark only those faces intersecting
619  // blockedSurfaces (i.e. with a 'blockLevel') or mark faces intersecting
620  // any (refinement) surface (this includes e.g. faceZones). This is
621  // much easier since that information is already cached
622  // (meshRefinement::intersectedFaces())
623 
624  //bitSet isBlockedFace(mesh_.nFaces());
625  forAll(testFaces, i)
626  {
627  if (hit1[i].hit())
628  {
629  const label facei = testFaces[i];
630  //isBlockedFace.set(facei);
631  const point& fc = mesh_.faceCentres()[facei];
632  const labelList& fz1 = faceZones[surface1[i]];
633 
634  originLocation.clear();
635  originDistSqr.clear();
636  //originNormal.clear();
637  originSurface.clear();
638 
639  originLocation.append(hit1[i].hitPoint());
640  originDistSqr.append(magSqr(fc-hit1[i].hitPoint()));
641  //originNormal.append(normal1[i]);
642  originSurface.append
643  (
644  FixedList<label, 3>
645  ({
646  surface1[i],
647  region1[i],
648  (fz1.size() ? fz1[hit1[i].index()] : region1[i])
649  })
650  );
651 
652  if (hit2[i].hit() && hit1[i] != hit2[i])
653  {
654  const labelList& fz2 = faceZones[surface2[i]];
655  originLocation.append(hit2[i].hitPoint());
656  originDistSqr.append(magSqr(fc-hit2[i].hitPoint()));
657  //originNormal.append(normal2[i]);
658  originSurface.append
659  (
660  FixedList<label, 3>
661  ({
662  surface2[i],
663  region2[i],
664  (fz2.size() ? fz2[hit2[i].index()] : region2[i])
665  })
666  );
667  }
668 
669  // Collect all seed data. Currently walking does not look at
670  // surface direction - if so pass in surface normal as well
671  faceDist[n] = wallPoints
672  (
673  originLocation, // origin
674  originDistSqr, // distance to origin
675  originSurface // surface+region+zone
676  //originNormal // normal at origin
677  );
678  changedFaces[n] = facei;
679  n++;
680  }
681  }
682 
683 
684  // Clear intersection info
685  surface1.clear();
686  hit1.clear();
687  region1.clear();
688  normal1.clear();
689  surface2.clear();
690  hit2.clear();
691  region2.clear();
692  normal2.clear();
693 
694 
695  List<wallPoints> allFaceInfo(mesh_.nFaces());
696  List<wallPoints> allCellInfo(mesh_.nCells());
697 
698  // Any refinement surface (even a faceZone) should stop the gap walking.
699  // This is exactly the information which is cached in the surfaceIndex_
700  // field.
701  const bitSet isBlockedFace(intersectedFaces());
702 
703  wallPoints::trackData td(isBlockedFace);
704  FaceCellWave<wallPoints, wallPoints::trackData> wallDistCalc
705  (
706  mesh_,
707  changedFaces,
708  faceDist,
709  allFaceInfo,
710  allCellInfo,
711  0, // max iterations
712  td
713  );
714  wallDistCalc.iterate(nIters);
715 
716 
718  {
719  // Dump current nearest opposite surfaces
721  (
722  IOobject
723  (
724  "gapSize",
725  mesh_.time().timeName(),
726  mesh_,
729  false
730  ),
731  mesh_,
733  (
734  "zero",
735  dimLength, //dimensionSet(0, 1, 0, 0, 0),
736  -1
737  )
738  );
739 
740  forAll(allCellInfo, celli)
741  {
742  if (allCellInfo[celli].valid(wallDistCalc.data()))
743  {
744  const point& cc = mesh_.C()[celli];
745  // Nearest surface points
746  const List<point>& origin = allCellInfo[celli].origin();
747 
748  // Find 'opposite' pair with minimum distance
749  for (label i = 0; i < origin.size(); i++)
750  {
751  for (label j = i + 1; j < origin.size(); j++)
752  {
753  if (((cc-origin[i]) & (cc-origin[j])) < 0)
754  {
755  const scalar d(mag(origin[i]-origin[j]));
756  if (distance[celli] < 0)
757  {
758  distance[celli] = d;
759  }
760  else
761  {
762  distance[celli] = min(distance[celli], d);
763  }
764  }
765  }
766  }
767  }
768  }
769  distance.correctBoundaryConditions();
770 
771  Info<< "Writing measured gap distance to "
772  << distance.name() << endl;
773  distance.write();
774  }
775 
776 
777 
778  // Detect tight gaps:
779  // - cell is inbetween the two surfaces
780  // - two surfaces are planarish
781  // - two surfaces are not too far apart
782  // (number of walking iterations is a too-coarse measure)
783 
784  scalarField smallGapDistance(mesh_.nCells(), 0.0);
785  label nMulti = 0;
786  label nSmallGap = 0;
787 
788  //OBJstream str(mesh_.time().timePath()/"multiRegion.obj");
789 
790 
791  forAll(allCellInfo, celli)
792  {
793  if (allCellInfo[celli].valid(wallDistCalc.data()))
794  {
795  const point& cc = mesh_.C()[celli];
796 
797  const List<point>& origin = allCellInfo[celli].origin();
798  const List<FixedList<label, 3>>& surface =
799  allCellInfo[celli].surface();
800 
801  // Find pair with minimum distance
802  for (label i = 0; i < origin.size(); i++)
803  {
804  for (label j = i + 1; j < origin.size(); j++)
805  {
806  scalar maxDist
807  (
808  max
809  (
810  mag(cc-origin[i]),
811  mag(cc-origin[j])
812  )
813  );
814 
815  //if (isMultiRegion[celli])
816  //{
817  // // The intersection locations are too inaccurate
818  // // (since not proper nearest, just a cell-cell ray
819  // // intersection) so include always
820  //
821  // smallGapDistance[celli] =
822  // max(smallGapDistance[celli], maxDist);
823  //
824  //
825  // str.write(linePointRef(cc, origin[i]));
826  // str.write(linePointRef(cc, origin[j]));
827  //
828  // nMulti++;
829  //}
830  //else
831  if (((cc-origin[i]) & (cc-origin[j])) < 0)
832  {
833  const label globalRegioni = surfaces_.globalRegion
834  (
835  surface[i][0],
836  surface[i][1]
837  );
838  const label globalRegionj = surfaces_.globalRegion
839  (
840  surface[j][0],
841  surface[j][1]
842  );
843 
844  const scalar maxSize = max
845  (
846  regionToBlockSize[globalRegioni],
847  regionToBlockSize[globalRegionj]
848  );
849 
850  if
851  (
852  magSqr(origin[i]-origin[j])
853  < Foam::sqr(2*maxSize)
854  )
855  {
856  smallGapDistance[celli] =
857  max(smallGapDistance[celli], maxDist);
858  nSmallGap++;
859  }
860  }
861  }
862  }
863  }
864  }
865 
866 
867  if (debug)
868  {
869  Info<< "Marked for blocking due to intersecting multiple surfaces : "
870  << returnReduce(nMulti, sumOp<label>()) << " cells." << endl;
871  Info<< "Marked for blocking due to close opposite surfaces : "
872  << returnReduce(nSmallGap, sumOp<label>()) << " cells." << endl;
873  }
874 
876  {
878  (
879  IOobject
880  (
881  "smallGapDistance",
882  mesh_.time().timeName(),
883  mesh_,
886  false
887  ),
888  mesh_,
890  (
891  "zero",
892  dimensionSet(0, 1, 0, 0, 0),
893  0.0
894  )
895  );
896  distance.field() = smallGapDistance;
897  distance.correctBoundaryConditions();
898 
899  Info<< "Writing all small-gap cells to "
900  << distance.name() << endl;
901  distance.write();
902  }
903 
904 
905  // Mark refinement
906  const label oldNRefine = nRefine;
907  forAll(smallGapDistance, celli)
908  {
909  if (smallGapDistance[celli] > SMALL)
910  {
911  if
912  (
913  !markForRefine
914  (
915  0, // mark level
916  nAllowRefine,
917  refineCell[celli],
918  nRefine
919  )
920  )
921  {
922  if (debug)
923  {
924  Pout<< "Stopped refining since reaching my cell"
925  << " limit of " << mesh_.nCells()+7*nRefine
926  << endl;
927  }
928  break;
929  }
930  }
931  }
932 
933  if
934  (
935  returnReduce(nRefine, sumOp<label>())
936  > returnReduce(nAllowRefine, sumOp<label>())
937  )
938  {
939  Info<< "Reached refinement limit." << endl;
940  }
941 
942  return returnReduce(nRefine-oldNRefine, sumOp<label>());
943 }
944 
945 
947 (
948  const scalar planarAngle,
949  const labelList& minSurfaceLevel,
950  const labelList& globalToMasterPatch,
951  const label growIter
952 )
953 {
954  // Swap neighbouring cell centres and cell level
955  labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
956  pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
957  calcNeighbourData(neiLevel, neiCc);
958 
959  labelList refineCell(mesh_.nCells(), -1);
960  label nRefine = 0;
961  //markProximityRefinement
962  //(
963  // Foam::cos(degToRad(planarAngle)),
964  //
965  // minSurfaceLevel, // surface min level
966  // labelList(minSurfaceLevel.size(), labelMax), // surfaceGapLevel
967  //
968  // labelMax/Pstream::nProcs(), //nAllowRefine,
969  // neiLevel,
970  // neiCc,
971  //
972  // refineCell,
973  // nRefine
974  //);
975 
976 
977  // Determine minimum blockLevel per surface
978  Map<label> surfToBlockLevel;
979 
980  forAll(surfaces_.surfaces(), surfi)
981  {
982  const label geomi = surfaces_.surfaces()[surfi];
983  const searchableSurface& s = surfaces_.geometry()[geomi];
984  const label nRegions = s.regions().size();
985 
986  label minBlockLevel = labelMax;
987  for (label regioni = 0; regioni < nRegions; regioni++)
988  {
989  const label globalRegioni = surfaces_.globalRegion(surfi, regioni);
990  minBlockLevel = min
991  (
992  minBlockLevel,
993  surfaces_.blockLevel()[globalRegioni]
994  );
995  }
996 
997  if (minBlockLevel < labelMax)
998  {
999  surfToBlockLevel.insert(surfi, minBlockLevel);
1000  }
1001  }
1002 
1003 
1004  markProximityRefinementWave
1005  (
1006  Foam::cos(degToRad(planarAngle)),
1007  surfToBlockLevel.sortedToc(),
1008 
1009  labelMax/Pstream::nProcs(), //nAllowRefine,
1010  neiLevel,
1011  neiCc,
1012 
1013  refineCell,
1014  nRefine
1015  );
1016 
1017 
1019  //markFakeGapRefinement
1020  //(
1021  // Foam::cos(degToRad(planarAngle)),
1022  //
1023  // labelMax/Pstream::nProcs(), //nAllowRefine,
1024  // neiLevel,
1025  // neiCc,
1026  //
1027  // refineCell,
1028  // nRefine
1029  //);
1030 
1031 
1032  Info<< "Marked for blocking due to close opposite surfaces : "
1033  << returnReduce(nRefine, sumOp<label>()) << " cells." << endl;
1034 
1035  // Remove outliers, i.e. cells with all points exposed
1036  if (growIter)
1037  {
1038  labelList oldRefineCell(refineCell);
1039 
1040  // Pass1: extend the set to fill in gaps
1041  bitSet isOutsideFace;
1042  for (label iter = 0; iter < growIter; iter++)
1043  {
1044  // Get outside faces
1045  markOutsideFaces
1046  (
1047  meshCutter_.cellLevel(),
1048  neiLevel,
1049  refineCell,
1050  isOutsideFace
1051  );
1052  // Extend with cells with three outside faces
1053  growSet(neiLevel, isOutsideFace, refineCell, nRefine);
1054  }
1055 
1056 
1057  // Pass2: erode back to original set if pass1 didn't help
1058  for (label iter = 0; iter < growIter; iter++)
1059  {
1060  // Get outside faces. Ignore cell level.
1061  markOutsideFaces
1062  (
1063  labelList(mesh_.nCells(), 0),
1064  labelList(neiLevel.size(), 0),
1065  refineCell,
1066  isOutsideFace
1067  );
1068 
1069  // Unmark cells with three or more outside faces
1070  for (label celli = 0; celli < mesh_.nCells(); celli++)
1071  {
1072  if (refineCell[celli] != -1 && oldRefineCell[celli] == -1)
1073  {
1074  if (countFaceDirs(isOutsideFace, celli) >= 3)
1075  {
1076  refineCell[celli] = -1;
1077  --nRefine;
1078  }
1079  }
1080  }
1081  }
1082 
1083  Info<< "Marked for blocking after filtering : "
1084  << returnReduce(nRefine, sumOp<label>()) << " cells." << endl;
1085  }
1086 
1087 
1088  // Determine patch for every mesh face
1089  const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
1090  labelList unnamedSurfaces(surfaceZonesInfo::getUnnamedSurfaces(surfZones));
1091  const label defaultRegion(surfaces_.globalRegion(unnamedSurfaces[0], 0));
1092 
1093  const labelList nearestRegion
1094  (
1095  nearestIntersection
1096  (
1097  unnamedSurfaces,
1098  defaultRegion
1099  )
1100  );
1101 
1102  // Pack
1103  labelList cellsToRemove(nRefine);
1104  nRefine = 0;
1105 
1106  forAll(refineCell, cellI)
1107  {
1108  if (refineCell[cellI] != -1)
1109  {
1110  cellsToRemove[nRefine++] = cellI;
1111  }
1112  }
1113 
1114  // Remove cells
1115  removeCells cellRemover(mesh_);
1116  labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
1117 
1118  labelList exposedPatches(exposedFaces.size());
1119  forAll(exposedFaces, i)
1120  {
1121  label facei = exposedFaces[i];
1122  exposedPatches[i] = globalToMasterPatch[nearestRegion[facei]];
1123  }
1124 
1125  return doRemoveCells
1126  (
1127  cellsToRemove,
1128  exposedFaces,
1129  exposedPatches,
1130  cellRemover
1131  );
1132 }
1133 
1134 
1135 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
nZones
label nZones
Definition: interpolatedFaces.H:24
Foam::IOobject::NO_WRITE
Definition: IOobject.H:195
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
volFields.H
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::meshRefinement::removeGapCells
autoPtr< mapPolyMesh > removeGapCells(const scalar planarAngle, const labelList &minSurfaceLevel, const labelList &globalToMasterPatch, const label growIter)
Detect gapRefinement cells and remove them.
Definition: meshRefinementBlock.C:947
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
distributedTriSurfaceMesh.H
Foam::labelMax
constexpr label labelMax
Definition: label.H:61
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
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::dimLength
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:52
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::removeCells
Given list of cells to remove, insert all the topology changes.
Definition: removeCells.H:63
Foam::meshRefinement::countFaceDirs
label countFaceDirs(const bitSet &isOutsideFace, const label celli) const
Count number of faces on cell that are in set.
Definition: meshRefinementBlock.C:222
Foam::bitSet::set
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:574
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::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
removeCells.H
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
bitSet.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::sumOp
Definition: ops.H:213
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
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::meshRefinement::growSet
void growSet(const labelList &neiLevel, const bitSet &isOutsideFace, labelList &refineCell, label &nRefine) const
Add one layer of cells to set.
Definition: meshRefinementBlock.C:273
searchableSurfaces.H
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::Field< vector >
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
refinementSurfaces.H
Foam::searchableSurface
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
Definition: searchableSurface.H:69
Foam::dimensionedScalar
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Definition: dimensionedScalarFwd.H:42
Foam::PtrList
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: List.H:59
Foam::volScalarField
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:57
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:75
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::PackedList::setSize
void setSize(const label n, unsigned int val=0u)
Alias for resize()
Definition: PackedList.H:558
meshRefinement.H
wallPoints.H
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:121
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
fvMesh.H
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::distance
scalar distance(const vector &p1, const vector &p2)
Definition: curveTools.C:12
Foam::surfaceZonesInfo::getUnnamedSurfaces
static labelList getUnnamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of unnamed surfaces (surfaces without faceZoneName)
Definition: surfaceZonesInfo.C:242
Time.H
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::refineCell
Container with cells to refine. Refinement given as single direction.
Definition: refineCell.H:56
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::pointIndexHit
PointIndexHit< point > pointIndexHit
A PointIndexHit for 3D points.
Definition: pointIndexHit.H:46
Foam::Vector
Templated 3D Vector derived from VectorSpace adding construction from 3 components,...
Definition: Vector.H:62
Foam::List< label >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::FixedList< label, 3 >
FaceCellWave.H
Foam::List::clear
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
Foam::direction
uint8_t direction
Definition: direction.H:52
cells
const cellShapeList & cells
Definition: gmvOutputHeader.H:3
Foam::meshRefinement::markOutsideFaces
void markOutsideFaces(const labelList &cellLevel, const labelList &neiLevel, const labelList &refineCell, bitSet &isOutsideFace) const
Mark faces on interface between set and rest.
Definition: meshRefinementBlock.C:164
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::IOobject::NO_READ
Definition: IOobject.H:188
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:54
Foam::meshRefinement::MESH
Definition: meshRefinement.H:94
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:445
Foam::removeCells::getExposedFaces
labelList getExposedFaces(const bitSet &removedCell) const
Get labels of faces exposed after cells removal.
Definition: removeCells.C:97
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265