shellSurfaces.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-2024 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 "shellSurfaces.H"
30 #include "searchableSurface.H"
31 #include "boundBox.H"
32 #include "triSurfaceMesh.H"
33 #include "refinementSurfaces.H"
34 #include "searchableSurfaces.H"
35 #include "orientedSurface.H"
36 #include "pointIndexHit.H"
37 #include "volumeType.H"
39 
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 
42 const Foam::Enum
43 <
45 >
46 Foam::shellSurfaces::refineModeNames_
47 ({
48  { refineMode::INSIDE, "inside" },
49  { refineMode::OUTSIDE, "outside" },
50  { refineMode::DISTANCE, "distance" },
51 });
52 
53 
54 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55 
56 void Foam::shellSurfaces::setAndCheckLevels
57 (
58  const label shellI,
59  const List<Tuple2<scalar, label>>& distLevels
60 )
61 {
62  const searchableSurface& shell = allGeometry_[shells_[shellI]];
63 
64  if (modes_[shellI] != DISTANCE && distLevels.size() != 1)
65  {
67  << "For refinement mode "
68  << refineModeNames_[modes_[shellI]]
69  << " specify only one distance+level."
70  << " (its distance gets discarded)"
71  << exit(FatalError);
72  }
73  // Extract information into separate distance and level
74  distances_[shellI].setSize(distLevels.size());
75  levels_[shellI].setSize(distLevels.size());
76 
77  forAll(distLevels, j)
78  {
79  distances_[shellI][j] = distLevels[j].first();
80  levels_[shellI][j] = distLevels[j].second();
81 
82  if (levels_[shellI][j] < -1)
83  {
85  << "Shell " << shell.name()
86  << " has illegal refinement level "
87  << levels_[shellI][j]
88  << exit(FatalError);
89  }
90 
91 
92  // Check in incremental order
93  if (j > 0)
94  {
95  if
96  (
97  (distances_[shellI][j] <= distances_[shellI][j-1])
98  || (levels_[shellI][j] > levels_[shellI][j-1])
99  )
100  {
102  << "For refinement mode "
103  << refineModeNames_[modes_[shellI]]
104  << " : Refinement should be specified in order"
105  << " of increasing distance"
106  << " (and decreasing refinement level)." << endl
107  << "Distance:" << distances_[shellI][j]
108  << " refinementLevel:" << levels_[shellI][j]
109  << exit(FatalError);
110  }
111  }
112  }
113 
114  if (modes_[shellI] == DISTANCE)
115  {
116  if (!dryRun_)
117  {
118  Info<< "Refinement level according to distance to "
119  << shell.name() << endl;
120  forAll(levels_[shellI], j)
121  {
122  Info<< " level " << levels_[shellI][j]
123  << " for all cells within " << distances_[shellI][j]
124  << " metre." << endl;
125  }
126  }
127  }
128  else
129  {
130  if (!shell.hasVolumeType())
131  {
133  << "Shell " << shell.name()
134  << " does not support testing for "
135  << refineModeNames_[modes_[shellI]] << endl
136  << "Probably it is not closed."
137  << exit(FatalError);
138  }
139 
140  if (!dryRun_)
141  {
142  if (modes_[shellI] == INSIDE)
143  {
144  Info<< "Refinement level " << levels_[shellI][0]
145  << " for all cells inside " << shell.name() << endl;
146  }
147  else
148  {
149  Info<< "Refinement level " << levels_[shellI][0]
150  << " for all cells outside " << shell.name() << endl;
151  }
152  }
153  }
154 }
155 
156 
157 // Specifically orient triSurfaces using a calculated point outside.
158 // Done since quite often triSurfaces not of consistent orientation which
159 // is (currently) necessary for sideness calculation
160 void Foam::shellSurfaces::orient()
161 {
162  // Determine outside point.
163  boundBox overallBb;
164 
165  bool hasSurface = false;
166 
167  forAll(shells_, shellI)
168  {
169  const searchableSurface& s = allGeometry_[shells_[shellI]];
170 
171  if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
172  {
173  hasSurface = true;
174 
175  const triSurfaceMesh& shell = refCast<const triSurfaceMesh>(s);
176  if (shell.triSurface::size())
177  {
178  // Assume surface is compact!
179  overallBb.add(s.bounds());
180  }
181  }
182  }
183 
184  if (returnReduceOr(hasSurface))
185  {
186  const point outsidePt = overallBb.max() + overallBb.span();
187 
188  //Info<< "Using point " << outsidePt << " to orient shells" << endl;
189 
190  forAll(shells_, shellI)
191  {
192  const searchableSurface& s = allGeometry_[shells_[shellI]];
193 
194  if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
195  {
196  triSurfaceMesh& shell = const_cast<triSurfaceMesh&>
197  (
198  refCast<const triSurfaceMesh>(s)
199  );
200  bool anyFlipped = false;
201  if (!isA<distributedTriSurfaceMesh>(s))
202  {
203  anyFlipped = orientedSurface::orient
204  (
205  shell,
206  outsidePt,
207  true
208  );
209  }
210  else
211  {
212  // TBD. - determine nearest with normal
213  // - override nearest only if better normal
214 
215  // Make sure that normals are consistent. Does not change
216  // anything if surface is consistent.
218 
219  List<pointIndexHit> info;
220  vectorField normal;
221  labelList region;
222  s.findNearest
223  (
224  pointField(1, outsidePt),
225  scalarField(1, GREAT),
226  info,
227  normal,
228  region
229  );
230 
231  if ((normal[0] & (info[0].point()-outsidePt)) > 0)
232  {
233  shell.flip();
234  anyFlipped = true;
235  }
236  }
237 
238  if (anyFlipped && !dryRun_)
239  {
240  Info<< "shellSurfaces : Flipped orientation of surface "
241  << s.name()
242  << " so point " << outsidePt << " is outside." << endl;
243  }
244  }
245  }
246  }
247 }
248 
249 
250 // Find maximum level of a shell.
251 void Foam::shellSurfaces::findHigherLevel
252 (
253  const pointField& pt,
254  const label shellI,
255  labelList& maxLevel
256 ) const
257 {
258  const labelList& levels = levels_[shellI];
259 
260  if (modes_[shellI] == DISTANCE)
261  {
262  // Distance mode.
263 
264  const scalarField& distances = distances_[shellI];
265 
266  // Collect all those points that have a current maxLevel less than
267  // (any of) the shell. Also collect the furthest distance allowable
268  // to any shell with a higher level.
269 
270  labelList candidateMap(pt.size());
271  scalarField candidateDistSqr(pt.size());
272  label candidateI = 0;
273 
274  forAll(maxLevel, pointi)
275  {
276  forAllReverse(levels, levelI)
277  {
278  if (levels[levelI] > maxLevel[pointi])
279  {
280  candidateMap[candidateI] = pointi;
281  candidateDistSqr[candidateI] = sqr(distances[levelI]);
282  candidateI++;
283  break;
284  }
285  }
286  }
287  candidateMap.setSize(candidateI);
288  candidateDistSqr.setSize(candidateI);
289 
290  // Do the expensive nearest test only for the candidate points.
291  List<pointIndexHit> nearInfo;
292  allGeometry_[shells_[shellI]].findNearest
293  (
294  pointField(pt, candidateMap),
295  candidateDistSqr,
296  nearInfo
297  );
298 
299  // Update maxLevel
300  forAll(nearInfo, i)
301  {
302  if (nearInfo[i].hit())
303  {
304  const label pointi = candidateMap[i];
305 
306  // Check which level it actually is in.
307  const label minDistI = findLower
308  (
309  distances,
310  nearInfo[i].point().dist(pt[pointi])
311  );
312 
313  // pt is inbetween shell[minDistI] and shell[minDistI+1]
314  maxLevel[pointi] = levels[minDistI+1];
315  }
316  }
317  }
318  else
319  {
320  // Inside/outside mode
321 
322  // Collect all those points that have a current maxLevel less than the
323  // shell.
324 
325  pointField candidates(pt.size());
326  labelList candidateMap(pt.size());
327  label candidateI = 0;
328 
329  forAll(maxLevel, pointi)
330  {
331  if (levels[0] > maxLevel[pointi])
332  {
333  candidates[candidateI] = pt[pointi];
334  candidateMap[candidateI] = pointi;
335  candidateI++;
336  }
337  }
338  candidates.setSize(candidateI);
339  candidateMap.setSize(candidateI);
340 
341  // Do the expensive nearest test only for the candidate points.
342  List<volumeType> volType;
343  allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
344 
345  forAll(volType, i)
346  {
347  label pointi = candidateMap[i];
348 
349  if
350  (
351  (
352  modes_[shellI] == INSIDE
353  && volType[i] == volumeType::INSIDE
354  )
355  || (
356  modes_[shellI] == OUTSIDE
357  && volType[i] == volumeType::OUTSIDE
358  )
359  )
360  {
361  maxLevel[pointi] = levels[0];
362  }
363  }
364  }
365 }
366 
367 
368 void Foam::shellSurfaces::findHigherGapLevel
369 (
370  const pointField& pt,
371  const labelList& ptLevel,
372  const label shellI,
373  labelList& gapShell,
374  List<FixedList<label, 3>>& gapInfo,
375  List<volumeType>& gapMode
376 ) const
377 {
378  //TBD: hardcoded for region 0 information
379  const FixedList<label, 3>& info = extendedGapLevel_[shellI][0];
380  const volumeType mode = extendedGapMode_[shellI][0];
381 
382  if (info[2] == 0)
383  {
384  return;
385  }
386 
387  if (modes_[shellI] == DISTANCE)
388  {
389  // Distance mode.
390  const scalar distance = distances_[shellI][0];
391 
392  labelList candidateMap(pt.size());
393  scalarField candidateDistSqr(pt.size());
394  label candidateI = 0;
395 
396  forAll(ptLevel, pointI)
397  {
398  if (ptLevel[pointI] >= info[1] && ptLevel[pointI] < info[2])
399  {
400  candidateMap[candidateI] = pointI;
401  candidateDistSqr[candidateI] = sqr(distance);
402  candidateI++;
403  }
404  }
405  candidateMap.setSize(candidateI);
406  candidateDistSqr.setSize(candidateI);
407 
408  // Do the expensive nearest test only for the candidate points.
409  List<pointIndexHit> nearInfo;
410  allGeometry_[shells_[shellI]].findNearest
411  (
412  pointField(pt, candidateMap),
413  candidateDistSqr,
414  nearInfo
415  );
416 
417  // Update info
418  forAll(nearInfo, i)
419  {
420  if (nearInfo[i].hit())
421  {
422  const label pointI = candidateMap[i];
423  gapShell[pointI] = shellI;
424  gapInfo[pointI] = info;
425  gapMode[pointI] = mode;
426  }
427  }
428  }
429  else
430  {
431  // Collect all those points that have a current maxLevel less than the
432  // shell.
433 
434  labelList candidateMap(pt.size());
435  label candidateI = 0;
436 
437  forAll(ptLevel, pointI)
438  {
439  if (ptLevel[pointI] >= info[1] && ptLevel[pointI] < info[2])
440  {
441  candidateMap[candidateI++] = pointI;
442  }
443  }
444  candidateMap.setSize(candidateI);
445 
446  // Do the expensive nearest test only for the candidate points.
447  List<volumeType> volType;
448  allGeometry_[shells_[shellI]].getVolumeType
449  (
450  pointField(pt, candidateMap),
451  volType
452  );
453 
454  forAll(volType, i)
455  {
456  const label pointI = candidateMap[i];
457  const bool isInside = (volType[i] == volumeType::INSIDE);
458 
459  if
460  (
461  (
462  (modes_[shellI] == INSIDE && isInside)
463  || (modes_[shellI] == OUTSIDE && !isInside)
464  )
465  && info[2] > gapInfo[pointI][2]
466  )
467  {
468  gapShell[pointI] = shellI;
469  gapInfo[pointI] = info;
470  gapMode[pointI] = mode;
471  }
472  }
473  }
474 }
475 
476 
477 void Foam::shellSurfaces::findLevel
478 (
479  const pointField& pt,
480  const label shellI,
481  labelList& minLevel,
482  labelList& shell
483 ) const
484 {
485  const labelList& levels = levels_[shellI];
486 
487  if (modes_[shellI] == DISTANCE)
488  {
489  // Distance mode.
490 
491  const scalarField& distances = distances_[shellI];
492 
493  // Collect all those points that have a current level equal/greater
494  // (any of) the shell. Also collect the furthest distance allowable
495  // to any shell with a higher level.
496 
497  pointField candidates(pt.size());
498  labelList candidateMap(pt.size());
499  scalarField candidateDistSqr(pt.size());
500  label candidateI = 0;
501 
502  forAll(shell, pointI)
503  {
504  if (shell[pointI] == -1)
505  {
506  forAllReverse(levels, levelI)
507  {
508  if (levels[levelI] <= minLevel[pointI])
509  {
510  candidates[candidateI] = pt[pointI];
511  candidateMap[candidateI] = pointI;
512  candidateDistSqr[candidateI] = sqr(distances[levelI]);
513  candidateI++;
514  break;
515  }
516  }
517  }
518  }
519  candidates.setSize(candidateI);
520  candidateMap.setSize(candidateI);
521  candidateDistSqr.setSize(candidateI);
522 
523  // Do the expensive nearest test only for the candidate points.
524  List<pointIndexHit> nearInfo;
525  allGeometry_[shells_[shellI]].findNearest
526  (
527  candidates,
528  candidateDistSqr,
529  nearInfo
530  );
531 
532  // Update maxLevel
533  forAll(nearInfo, i)
534  {
535  if (nearInfo[i].hit())
536  {
537  // Check which level it actually is in.
538  label minDistI = findLower
539  (
540  distances,
541  nearInfo[i].point().dist(candidates[i])
542  );
543 
544  label pointI = candidateMap[i];
545 
546  // pt is inbetween shell[minDistI] and shell[minDistI+1]
547  shell[pointI] = shellI;
548  minLevel[pointI] = levels[minDistI+1];
549  }
550  }
551  }
552  else
553  {
554  // Inside/outside mode
555 
556  // Collect all those points that have a current maxLevel less than the
557  // shell.
558 
559  pointField candidates(pt.size());
560  labelList candidateMap(pt.size());
561  label candidateI = 0;
562 
563  forAll(shell, pointI)
564  {
565  if (shell[pointI] == -1 && levels[0] <= minLevel[pointI])
566  {
567  candidates[candidateI] = pt[pointI];
568  candidateMap[candidateI] = pointI;
569  candidateI++;
570  }
571  }
572  candidates.setSize(candidateI);
573  candidateMap.setSize(candidateI);
574 
575  // Do the expensive nearest test only for the candidate points.
576  List<volumeType> volType;
577  allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
578 
579  forAll(volType, i)
580  {
581  if
582  (
583  (
584  modes_[shellI] == INSIDE
585  && volType[i] == volumeType::INSIDE
586  )
587  || (
588  modes_[shellI] == OUTSIDE
589  && volType[i] == volumeType::OUTSIDE
590  )
591  )
592  {
593  label pointI = candidateMap[i];
594  shell[pointI] = shellI;
595  minLevel[pointI] = levels[0];
596  }
597  }
598  }
599 }
600 
601 
602 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
603 
605 (
606  const searchableSurfaces& allGeometry,
607  const dictionary& shellsDict,
608  const bool dryRun
609 )
610 :
611  allGeometry_(allGeometry),
612  dryRun_(dryRun)
613 {
614  // Wildcard specification : loop over all surfaces and try to find a match.
615 
616  // Count number of shells.
617  label shellI = 0;
618  for (const word& geomName : allGeometry_.names())
619  {
620  if (shellsDict.found(geomName))
621  {
622  ++shellI;
623  }
624  }
625 
626 
627  // Size lists
628  shells_.setSize(shellI);
629  modes_.setSize(shellI);
630  distances_.setSize(shellI);
631  levels_.setSize(shellI);
632  dirLevels_.setSize(shellI);
633  smoothDirection_.setSize(shellI);
634  nSmoothExpansion_.setSize(shellI);
635  nSmoothPosition_.setSize(shellI);
636 
637  extendedGapLevel_.setSize(shellI);
638  extendedGapMode_.setSize(shellI);
639  selfProximity_.setSize(shellI);
640 
641  const FixedList<label, 3> nullGapLevel({0, 0, 0});
642 
643  wordHashSet unmatchedKeys(shellsDict.toc());
644  shellI = 0;
645 
646  forAll(allGeometry_.names(), geomI)
647  {
648  const word& geomName = allGeometry_.names()[geomI];
649 
650  const entry* eptr = shellsDict.findEntry(geomName, keyType::REGEX);
651 
652  if (eptr)
653  {
654  const dictionary& dict = eptr->dict();
655  unmatchedKeys.erase(eptr->keyword());
656 
657  shells_[shellI] = geomI;
658  modes_[shellI] = refineModeNames_.get("mode", dict);
659 
660  // Read pairs of distance+level
661  setAndCheckLevels(shellI, dict.lookup("levels"));
662 
663 
664  // Directional refinement
665  // ~~~~~~~~~~~~~~~~~~~~~~
666 
667  dirLevels_[shellI] = Tuple2<labelPair,labelVector>
668  (
671  );
672  const entry* levelPtr =
673  dict.findEntry("levelIncrement", keyType::REGEX);
674 
675  if (levelPtr)
676  {
677  // Do reading ourselves since using labelPair would require
678  // additional bracket pair
679  ITstream& is = levelPtr->stream();
680 
681  is.readBegin("levelIncrement");
682  is >> dirLevels_[shellI].first().first()
683  >> dirLevels_[shellI].first().second()
684  >> dirLevels_[shellI].second();
685  is.readEnd("levelIncrement");
686 
687  if (modes_[shellI] == INSIDE)
688  {
689  if (!dryRun_)
690  {
691  Info<< "Additional directional refinement level"
692  << " for all cells inside " << geomName << endl;
693  }
694  }
695  else if (modes_[shellI] == OUTSIDE)
696  {
697  if (!dryRun_)
698  {
699  Info<< "Additional directional refinement level"
700  << " for all cells outside " << geomName << endl;
701  }
702  }
703  else
704  {
705  FatalIOErrorInFunction(shellsDict)
706  << "Unsupported mode "
707  << refineModeNames_[modes_[shellI]]
708  << exit(FatalIOError);
709  }
710  }
711 
712  // Directional smoothing
713  // ~~~~~~~~~~~~~~~~~~~~~
714 
715  nSmoothExpansion_[shellI] = 0;
716  nSmoothPosition_[shellI] = 0;
717  smoothDirection_[shellI] =
718  dict.getOrDefault("smoothDirection", vector::zero);
719 
720  if (smoothDirection_[shellI] != vector::zero)
721  {
722  dict.readEntry("nSmoothExpansion", nSmoothExpansion_[shellI]);
723  dict.readEntry("nSmoothPosition", nSmoothPosition_[shellI]);
724  }
725 
726 
727  // Gap specification
728  // ~~~~~~~~~~~~~~~~~
729 
730 
731  // Shell-wide gap level specification
732  const searchableSurface& surface = allGeometry_[geomI];
733  const wordList& regionNames = surface.regions();
734 
735  FixedList<label, 3> gapSpec
736  (
737  dict.getOrDefault
738  (
739  "gapLevel",
740  nullGapLevel
741  )
742  );
743  extendedGapLevel_[shellI].setSize(regionNames.size());
744  extendedGapLevel_[shellI] = gapSpec;
745 
746  extendedGapMode_[shellI].setSize(regionNames.size());
747  extendedGapMode_[shellI] =
748  volumeType("gapMode", dict, volumeType::MIXED);
749 
750  // Detect self-intersections
751  selfProximity_[shellI].setSize
752  (
753  regionNames.size(),
754  dict.getOrDefault<bool>("gapSelf", true)
755  );
756 
757 
758  // Override on a per-region basis?
759 
760  if (dict.found("regions"))
761  {
762  const dictionary& regionsDict = dict.subDict("regions");
763  forAll(regionNames, regionI)
764  {
765  if (regionsDict.found(regionNames[regionI]))
766  {
767  // Get the dictionary for region
768  const dictionary& regionDict = regionsDict.subDict
769  (
770  regionNames[regionI]
771  );
772  FixedList<label, 3> gapSpec
773  (
774  regionDict.getOrDefault
775  (
776  "gapLevel",
777  nullGapLevel
778  )
779  );
780  extendedGapLevel_[shellI][regionI] = gapSpec;
781 
782  extendedGapMode_[shellI][regionI] =
783  volumeType
784  (
785  "gapMode",
786  regionDict,
788  );
789 
790  selfProximity_[shellI][regionI] =
791  regionDict.getOrDefault<bool>
792  (
793  "gapSelf",
794  true
795  );
796  }
797  }
798  }
799 
800  if (extendedGapLevel_[shellI][0][0] > 0)
801  {
802  Info<< "Refinement level up to "
803  << extendedGapLevel_[shellI][0][2]
804  << " for all cells in gaps for shell "
805  << geomName << endl;
806 
807  if (distances_[shellI].size() > 1)
808  {
809  WarningInFunction << "Using first distance only out of "
810  << distances_[shellI] << " to detect gaps for shell "
811  << geomName << endl;
812  }
813  }
814 
815  shellI++;
816  }
817  }
818 
819  if (unmatchedKeys.size() > 0)
820  {
821  IOWarningInFunction(shellsDict)
822  << "Not all entries in refinementRegions dictionary were used."
823  << " The following entries were not used : "
824  << unmatchedKeys.sortedToc()
825  << endl;
826  }
827 
828  // Orient shell surfaces before any searching is done. Note that this
829  // only needs to be done for inside or outside. Orienting surfaces
830  // constructs lots of addressing which we want to avoid.
831  orient();
832 }
833 
834 
835 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
836 
837 // Highest shell level
838 Foam::label Foam::shellSurfaces::maxLevel() const
839 {
840  label overallMax = 0;
841  forAll(levels_, shellI)
842  {
843  overallMax = max(overallMax, max(levels_[shellI]));
844  }
845  return overallMax;
846 }
847 
848 
850 {
851  labelList surfaceMax(extendedGapLevel_.size(), Zero);
852 
853  forAll(extendedGapLevel_, shelli)
854  {
855  const List<FixedList<label, 3>>& levels = extendedGapLevel_[shelli];
856  forAll(levels, i)
857  {
858  surfaceMax[shelli] = max(surfaceMax[shelli], levels[i][2]);
859  }
860  }
861  return surfaceMax;
862 }
863 
864 
866 {
867  labelPairList levels(dirLevels_.size());
868  forAll(dirLevels_, shelli)
869  {
870  levels[shelli] = dirLevels_[shelli].first();
871  }
872  return levels;
873 }
874 
877 {
878  return nSmoothExpansion_;
879 }
880 
883 {
884  return smoothDirection_;
885 }
886 
887 
889 {
890  return nSmoothPosition_;
891 }
892 
893 
894 void Foam::shellSurfaces::findHigherLevel
895 (
896  const pointField& pt,
897  const labelList& ptLevel,
898  labelList& maxLevel
899 ) const
900 {
901  // Maximum level of any shell. Start off with level of point.
902  maxLevel = ptLevel;
903 
904  forAll(shells_, shelli)
905  {
906  findHigherLevel(pt, shelli, maxLevel);
907  }
908 }
909 
910 
911 void Foam::shellSurfaces::findHigherGapLevel
912 (
913  const pointField& pt,
914  const labelList& ptLevel,
915  labelList& gapShell,
916  List<FixedList<label, 3>>& gapInfo,
917  List<volumeType>& gapMode
918 ) const
919 {
920  gapShell.setSize(pt.size());
921  gapShell = -1;
922 
923  gapInfo.setSize(pt.size());
924  gapInfo = FixedList<label, 3>({0, 0, 0});
925 
926  gapMode.setSize(pt.size());
927  gapMode = volumeType::MIXED;
928 
929  forAll(shells_, shelli)
930  {
931  findHigherGapLevel(pt, ptLevel, shelli, gapShell, gapInfo, gapMode);
932  }
933 }
934 
935 
936 void Foam::shellSurfaces::findHigherGapLevel
937 (
938  const pointField& pt,
939  const labelList& ptLevel,
940  List<FixedList<label, 3>>& gapInfo,
941  List<volumeType>& gapMode
942 ) const
943 {
944  labelList gapShell;
945  findHigherGapLevel(pt, ptLevel, gapShell, gapInfo, gapMode);
946 }
947 
948 
949 void Foam::shellSurfaces::findLevel
950 (
951  const pointField& pt,
952  const labelList& ptLevel,
953  labelList& shell
954 ) const
955 {
956  shell.setSize(pt.size());
957  shell = -1;
958 
959  labelList minLevel(ptLevel);
960 
961  forAll(shells_, shelli)
962  {
963  findLevel(pt, shelli, minLevel, shell);
964  }
965 }
966 
967 
969 (
970  const pointField& pt,
971  const labelList& ptLevel,
972  const labelList& dirLevel, // directional level
973  const direction dir,
974  labelList& shell
975 ) const
976 {
977  shell.setSize(pt.size());
978  shell = -1;
979 
980  List<volumeType> volType;
981 
982  // Current back to original
983  DynamicList<label> candidateMap(pt.size());
984 
985  forAll(shells_, shelli)
986  {
987  if (modes_[shelli] == INSIDE || modes_[shelli] == OUTSIDE)
988  {
989  const labelPair& selectLevels = dirLevels_[shelli].first();
990  const label addLevel = dirLevels_[shelli].second()[dir];
991 
992  // Collect the cells that are of the right original level
993  candidateMap.clear();
994  forAll(ptLevel, celli)
995  {
996  label level = ptLevel[celli];
997 
998  if
999  (
1000  level >= selectLevels.first()
1001  && level <= selectLevels.second()
1002  && dirLevel[celli] < level+addLevel
1003  )
1004  {
1005  candidateMap.append(celli);
1006  }
1007  }
1008 
1009  // Do geometric test
1010  pointField candidatePt(pt, candidateMap);
1011  allGeometry_[shells_[shelli]].getVolumeType(candidatePt, volType);
1012 
1013  // Extract selected cells
1014  forAll(candidateMap, i)
1015  {
1016  if
1017  (
1018  (
1019  modes_[shelli] == INSIDE
1020  && volType[i] == volumeType::INSIDE
1021  )
1022  || (
1023  modes_[shelli] == OUTSIDE
1024  && volType[i] == volumeType::OUTSIDE
1025  )
1026  )
1027  {
1028  shell[candidateMap[i]] = shelli;
1029  }
1030  }
1031  }
1032  }
1033 }
1034 
1035 
1036 // ************************************************************************* //
EnumType get(const word &enumName) const
The enumeration corresponding to the given name.
Definition: Enum.C:68
const T & first() const noexcept
Access the first element.
Definition: Pair.H:137
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
labelPairList directionalSelectLevel() const
Min and max cell level for directional refinement.
label findLower(const ListType &input, const T &val, const label start, const ComparePredicate &comp)
Binary search to find the index of the last element in a sorted list that is less than value...
uint8_t direction
Definition: direction.H:46
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensionedSymmTensor sqr(const dimensionedVector &dv)
refineMode
Volume refinement controls.
Definition: shellSurfaces.H:62
T & first()
Access first element of the list, position [0].
Definition: UList.H:886
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
static bool orient(triSurface &, const point &, const bool orientOutside)
Flip faces such that normals are consistent with point:
const labelList & nSmoothExpansion() const
Per shell the directional smoothing iterations.
scalar distance(const vector &p1, const vector &p2)
Definition: curveTools.C:12
label maxLevel() const
Highest shell level.
List< labelPair > labelPairList
List of labelPair.
Definition: labelPair.H:33
constexpr label labelMin
Definition: label.H:54
wordList regionNames
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:325
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:73
A location inside the volume.
Definition: volumeType.H:65
A location outside the volume.
Definition: volumeType.H:66
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
labelList maxGapLevel() const
Highest shell gap level.
const wordList surface
Standard surface field types (scalar, vector, tensor, etc)
A location that is partly inside and outside.
Definition: volumeType.H:67
void findDirectionalLevel(const pointField &pt, const labelList &ptLevel, const labelList &dirLevel, const direction dir, labelList &shell) const
Find any shell (or -1) with higher wanted directional level.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
static bool orientConsistent(triSurface &s)
Make sure surface has consistent orientation across connected.
shellSurfaces(const searchableSurfaces &allGeometry, const dictionary &shellsDict, const bool dryRun=false)
Construct from geometry and dictionary.
const vectorField & smoothDirection() const
Per shell the smoothing direction.
const labelList & nSmoothPosition() const
Per shell the positional smoothing iterations.
List< word > wordList
List of word.
Definition: fileName.H:59
vector point
Point is a vector.
Definition: point.H:37
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:629
const wordList & names() const
Surface names, not region names.
messageStream Info
Information stream (stdout output on master, null elsewhere)
constexpr label labelMax
Definition: label.H:55
Field< vector > vectorField
Specialisation of Field<T> for vector.
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:302
List< label > labelList
A List of labels.
Definition: List.H:61
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))
mode_t mode(const fileName &name, const bool followLink=true)
Return the file mode, normally following symbolic links.
Definition: POSIX.C:775
Regular expression.
Definition: keyType.H:83
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127