Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
11License
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
42const Foam::Enum
43<
45>
46Foam::shellSurfaces::refineModeNames_
47({
48 { refineMode::INSIDE, "inside" },
49 { refineMode::OUTSIDE, "outside" },
50 { refineMode::DISTANCE, "distance" },
51});
52
53
54// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55
56void 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
160void 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
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 (
199 );
200 bool anyFlipped = false;
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
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.
251void 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
368void 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
477void 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 }
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 (
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 (
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] =
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
838Foam::label Foam::shellSurfaces::maxLevel() const
839{
840 label overallMax = 0;
841 forAll(levels_, shellI)
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)
870 levels[shelli] = dirLevels_[shelli].first();
871 }
872 return levels;
873}
874
877{
878 return nSmoothExpansion_;
879}
880
883{
884 return smoothDirection_;
885}
886
889{
890 return nSmoothPosition_;
891}
892
893
894void 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
911void 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
936void 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
949void 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// ************************************************************************* //
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
void append(const T &val)
Copy append an element to the end of this list.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition Enum.H:57
A 1D vector of objects of type <T> with a fixed length <N>.
Definition FixedList.H:73
bool erase(T *item)
Remove the specified element from the list and delete it.
Definition ILList.C:101
An input stream of tokens.
Definition ITstream.H:56
bool readBegin(const char *funcName)
Begin read of data chunk, starts with '('.
Definition Istream.C:134
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void setSize(label n)
Alias for resize().
Definition List.H:536
const T & first() const noexcept
Access the first element.
Definition Pair.H:137
const T & second() const noexcept
Access the second element.
Definition Pair.H:147
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition Tuple2.H:51
T & first()
Access first element of the list, position [0].
Definition UList.H:957
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static const Form zero
A bounding box defined in terms of min/max extrema points.
Definition boundBox.H:71
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition dictionary.C:441
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, IOobjectOption::readOption readOpt=IOobjectOption::MUST_READ) const
Find entry and assign to T val. FatalIOError if it is found and the number of tokens is incorrect,...
const entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition dictionaryI.H:84
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
ITstream & lookup(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return an entry data stream. FatalIOError if not found, or not a stream.
Definition dictionary.C:367
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
A keyword and a list of tokens is an 'entry'.
Definition entry.H:66
@ REGEX
Regular expression.
Definition keyType.H:83
static bool orient(triSurface &, const point &, const bool orientOutside)
Flip faces such that normals are consistent with point:
static bool orientConsistent(triSurface &s)
Make sure surface has consistent orientation across connected.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
Container for searchableSurfaces. The collection is specified as a dictionary. For example,...
const vectorField & smoothDirection() const
Per shell the smoothing direction.
labelList maxGapLevel() const
Highest shell gap level.
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.
shellSurfaces(const searchableSurfaces &allGeometry, const dictionary &shellsDict, const bool dryRun=false)
Construct from geometry and dictionary.
const labelList & nSmoothPosition() const
Per shell the positional smoothing iterations.
label maxLevel() const
Highest shell level.
const labelList & nSmoothExpansion() const
Per shell the directional smoothing iterations.
refineMode
Volume refinement controls.
labelPairList directionalSelectLevel() const
Min and max cell level for directional refinement.
IOoject and searching on triSurface.
An enumeration wrapper for classification of a location as being inside/outside of a volume.
Definition volumeType.H:56
@ OUTSIDE
A location outside the volume.
Definition volumeType.H:66
@ MIXED
A location that is partly inside and outside.
Definition volumeType.H:67
@ INSIDE
A location inside the volume.
Definition volumeType.H:65
A class for handling words, derived from Foam::string.
Definition word.H:66
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
wordList regionNames
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))
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
#define WarningInFunction
Report a warning using Foam::Warning.
const wordList surface
Standard surface field types (scalar, vector, tensor, etc).
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
scalar distance(const vector &p1, const vector &p2)
Definition curveTools.C:12
List< word > wordList
List of word.
Definition fileName.H:60
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition HashSet.H:80
List< labelPair > labelPairList
List of labelPair.
Definition labelPair.H:33
List< label > labelList
A List of labels.
Definition List.H:62
dimensionedSymmTensor sqr(const dimensionedVector &dv)
constexpr label labelMin
Definition label.H:54
messageStream Info
Information stream (stdout output on master, null elsewhere).
mode_t mode(const fileName &name, const bool followLink=true)
Return the file mode, normally following symbolic links.
Definition POSIX.C:775
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.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
constexpr label labelMax
Definition label.H:55
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
Field< vector > vectorField
Specialisation of Field<T> for vector.
uint8_t direction
Definition direction.H:49
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
vector point
Point is a vector.
Definition point.H:37
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
vectorField pointField
pointField is a vectorField.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition stdFoam.H:315