refinementSurfaces.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "refinementSurfaces.H"
27 #include "Time.H"
28 #include "searchableSurfaces.H"
29 #include "refinementRegions.H"
30 #include "labelPair.H"
32 #include "UPtrList.H"
33 #include "volumeType.H"
34 
35 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
36 
38 (
39  const searchableSurfaces& allGeometry,
40  const dictionary& surfacesDict,
41  const label gapLevelIncrement
42 )
43 :
44  allGeometry_(allGeometry),
45  surfaces_(surfacesDict.size()),
46  names_(surfacesDict.size()),
47  surfZones_(surfacesDict.size()),
48  regionOffset_(surfacesDict.size())
49 {
50  // Wildcard specification : loop over all surface, all regions
51  // and try to find a match.
52 
53  // Count number of surfaces.
54  label surfi = 0;
55  forAll(allGeometry_.names(), geomi)
56  {
57  const word& geomName = allGeometry_.names()[geomi];
58 
59  if (surfacesDict.found(geomName))
60  {
61  surfi++;
62  }
63  }
64 
65  // Size lists
66  surfaces_.setSize(surfi);
67  names_.setSize(surfi);
68  surfZones_.setSize(surfi);
69  regionOffset_.setSize(surfi);
70 
71  labelList globalMinLevel(surfi, 0);
72  labelList globalMaxLevel(surfi, 0);
73  labelList globalLevelIncr(surfi, 0);
74  scalarField globalAngle(surfi, -great);
75  PtrList<dictionary> globalPatchInfo(surfi);
76  List<Map<label>> regionMinLevel(surfi);
77  List<Map<label>> regionMaxLevel(surfi);
78  List<Map<label>> regionLevelIncr(surfi);
79  List<Map<scalar>> regionAngle(surfi);
80  List<Map<autoPtr<dictionary>>> regionPatchInfo(surfi);
81 
82 
83  HashSet<word> unmatchedKeys(surfacesDict.toc());
84 
85  surfi = 0;
86  forAll(allGeometry_.names(), geomi)
87  {
88  const word& geomName = allGeometry_.names()[geomi];
89 
90  const entry* ePtr = surfacesDict.lookupEntryPtr(geomName, false, true);
91 
92  if (ePtr)
93  {
94  const dictionary& dict = ePtr->dict();
95  unmatchedKeys.erase(ePtr->keyword());
96 
97  names_[surfi] = geomName;
98  surfaces_[surfi] = geomi;
99 
100  const labelPair refLevel(dict.lookup("level"));
101  globalMinLevel[surfi] = refLevel[0];
102  globalMaxLevel[surfi] = refLevel[1];
103  globalLevelIncr[surfi] = dict.lookupOrDefault
104  (
105  "gapLevelIncrement",
106  gapLevelIncrement
107  );
108 
109  if
110  (
111  globalMinLevel[surfi] < 0
112  || globalMaxLevel[surfi] < globalMinLevel[surfi]
113  || globalLevelIncr[surfi] < 0
114  )
115  {
117  (
118  dict
119  ) << "Illegal level specification for surface "
120  << names_[surfi]
121  << " : minLevel:" << globalMinLevel[surfi]
122  << " maxLevel:" << globalMaxLevel[surfi]
123  << " levelincrement:" << globalLevelIncr[surfi]
124  << exit(FatalIOError);
125  }
126 
127  const searchableSurface& surface = allGeometry_[surfaces_[surfi]];
128 
129  // Surface zones
130  surfZones_.set(surfi, new surfaceZonesInfo(surface, dict));
131 
132  // Global perpendicular angle
133  if (dict.found("patchInfo"))
134  {
135  globalPatchInfo.set
136  (
137  surfi,
138  dict.subDict("patchInfo").clone()
139  );
140  }
141  dict.readIfPresent("perpendicularAngle", globalAngle[surfi]);
142 
143  if (dict.found("regions"))
144  {
145  const dictionary& regionsDict = dict.subDict("regions");
146  const wordList& regionNames = surface.regions();
147 
148  forAll(regionNames, regioni)
149  {
150  if (regionsDict.found(regionNames[regioni]))
151  {
152  // Get the dictionary for region
153  const dictionary& regionDict = regionsDict.subDict
154  (
155  regionNames[regioni]
156  );
157 
158  const labelPair refLevel(regionDict.lookup("level"));
159 
160  regionMinLevel[surfi].insert(regioni, refLevel[0]);
161  regionMaxLevel[surfi].insert(regioni, refLevel[1]);
162  label levelincr = regionDict.lookupOrDefault
163  (
164  "gapLevelIncrement",
165  gapLevelIncrement
166  );
167  regionLevelIncr[surfi].insert(regioni, levelincr);
168 
169  if
170  (
171  refLevel[0] < 0
172  || refLevel[1] < refLevel[0]
173  || levelincr < 0
174  )
175  {
177  (
178  dict
179  ) << "Illegal level specification for surface "
180  << names_[surfi] << " region "
181  << regionNames[regioni]
182  << " : minLevel:" << refLevel[0]
183  << " maxLevel:" << refLevel[1]
184  << " levelincrement:" << levelincr
185  << exit(FatalIOError);
186  }
187 
188  if (regionDict.found("perpendicularAngle"))
189  {
190  regionAngle[surfi].insert
191  (
192  regioni,
193  regionDict.lookup<scalar>("perpendicularAngle")
194  );
195  }
196 
197  if (regionDict.found("patchInfo"))
198  {
199  regionPatchInfo[surfi].insert
200  (
201  regioni,
202  regionDict.subDict("patchInfo").clone()
203  );
204  }
205  }
206  }
207  }
208  surfi++;
209  }
210  }
211 
212  if (unmatchedKeys.size() > 0)
213  {
215  (
216  surfacesDict
217  ) << "Not all entries in refinementSurfaces dictionary were used."
218  << " The following entries were not used : "
219  << unmatchedKeys.sortedToc()
220  << endl;
221  }
222 
223 
224  // Calculate local to global region offset
225  label nRegions = 0;
226 
227  forAll(surfaces_, surfi)
228  {
229  regionOffset_[surfi] = nRegions;
230  nRegions += allGeometry_[surfaces_[surfi]].regions().size();
231  }
232 
233  // Rework surface specific information into information per global region
234  minLevel_.setSize(nRegions);
235  minLevel_ = 0;
236  maxLevel_.setSize(nRegions);
237  maxLevel_ = 0;
238  gapLevel_.setSize(nRegions);
239  gapLevel_ = -1;
240  perpendicularAngle_.setSize(nRegions);
241  perpendicularAngle_ = -great;
242  patchInfo_.setSize(nRegions);
243 
244 
245  forAll(globalMinLevel, surfi)
246  {
247  label nRegions = allGeometry_[surfaces_[surfi]].regions().size();
248 
249  // Initialise to global (i.e. per surface)
250  for (label i = 0; i < nRegions; i++)
251  {
252  label globalRegioni = regionOffset_[surfi] + i;
253  minLevel_[globalRegioni] = globalMinLevel[surfi];
254  maxLevel_[globalRegioni] = globalMaxLevel[surfi];
255  gapLevel_[globalRegioni] =
256  maxLevel_[globalRegioni]
257  + globalLevelIncr[surfi];
258 
259  perpendicularAngle_[globalRegioni] = globalAngle[surfi];
260  if (globalPatchInfo.set(surfi))
261  {
262  patchInfo_.set
263  (
264  globalRegioni,
265  globalPatchInfo[surfi].clone()
266  );
267  }
268  }
269 
270  // Overwrite with region specific information
271  forAllConstIter(Map<label>, regionMinLevel[surfi], iter)
272  {
273  label globalRegioni = regionOffset_[surfi] + iter.key();
274 
275  minLevel_[globalRegioni] = iter();
276  maxLevel_[globalRegioni] = regionMaxLevel[surfi][iter.key()];
277  gapLevel_[globalRegioni] =
278  maxLevel_[globalRegioni]
279  + regionLevelIncr[surfi][iter.key()];
280  }
281  forAllConstIter(Map<scalar>, regionAngle[surfi], iter)
282  {
283  label globalRegioni = regionOffset_[surfi] + iter.key();
284 
285  perpendicularAngle_[globalRegioni] = regionAngle[surfi][iter.key()];
286  }
287 
288  const Map<autoPtr<dictionary>>& localInfo = regionPatchInfo[surfi];
289  forAllConstIter(Map<autoPtr<dictionary>>, localInfo, iter)
290  {
291  label globalRegioni = regionOffset_[surfi] + iter.key();
292 
293  patchInfo_.set(globalRegioni, iter()().clone());
294  }
295  }
296 }
297 
298 
300 (
301  const searchableSurfaces& allGeometry,
302  const labelList& surfaces,
303  const wordList& names,
304  const PtrList<surfaceZonesInfo>& surfZones,
305  const labelList& regionOffset,
306  const labelList& minLevel,
307  const labelList& maxLevel,
308  const labelList& gapLevel,
309  const scalarField& perpendicularAngle,
310  PtrList<dictionary>& patchInfo
311 )
312 :
313  allGeometry_(allGeometry),
314  surfaces_(surfaces),
315  names_(names),
316  surfZones_(surfZones),
317  regionOffset_(regionOffset),
318  minLevel_(minLevel),
319  maxLevel_(maxLevel),
320  gapLevel_(gapLevel),
321  perpendicularAngle_(perpendicularAngle),
322  patchInfo_(patchInfo.size())
323 {
324  forAll(patchInfo_, pi)
325  {
326  if (patchInfo.set(pi))
327  {
328  patchInfo_.set(pi, patchInfo.set(pi, nullptr));
329  }
330  }
331 }
332 
333 
334 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
335 
337 (
338  const refinementRegions& shells,
339  const scalar level0EdgeLength,
340  const bool extendedRefinementSpan
341 )
342 {
343  forAll(surfaces_, surfi)
344  {
345  const searchableSurface& geom = allGeometry_[surfaces_[surfi]];
346 
347  // Precalculation only makes sense if there are different regions
348  // (so different refinement levels possible) and there are some
349  // elements. Possibly should have 'enough' elements to have fine
350  // enough resolution but for now just make sure we don't catch e.g.
351  // searchableBox (size=6)
352  if (geom.regions().size() > 1 && geom.globalSize() > 10)
353  {
354  // Representative local coordinates and bounding sphere
355  pointField ctrs;
356  scalarField radiusSqr;
357  geom.boundingSpheres(ctrs, radiusSqr);
358 
359  labelList minLevelField(ctrs.size(), -1);
360  {
361  // Get the element index in a roundabout way. Problem is e.g.
362  // distributed surface where local indices differ from global
363  // ones (needed for getRegion call)
364  List<pointIndexHit> info;
365  geom.findNearest(ctrs, radiusSqr, info);
366 
367  // Get per element the region
368  labelList region;
369  geom.getRegion(info, region);
370 
371  // From the region get the surface-wise refinement level
372  forAll(minLevelField, i)
373  {
374  if (info[i].hit()) // Note: should not be necessary
375  {
376  minLevelField[i] = minLevel(surfi, region[i]);
377  }
378  }
379  }
380 
381  // Find out if triangle inside shell with higher level
382  // What level does shell want to refine fc to?
383  //
384  // Note: for triangulated surfaces with triangles that
385  // span refinement regions it introduces unnecessary refinement
386  if (extendedRefinementSpan)
387  {
388  labelList shellLevel;
389  shells.findHigherLevel
390  (
391  ctrs,
392  minLevelField,
393  level0EdgeLength,
394  shellLevel
395  );
396 
397  forAll(minLevelField, i)
398  {
399  minLevelField[i] = max(minLevelField[i], shellLevel[i]);
400  }
401  }
402 
403  // Store minLevelField on surface
404  const_cast<searchableSurface&>(geom).setField(minLevelField);
405  }
406  }
407 }
408 
409 
411 (
412  const pointField& start,
413  const pointField& end,
414  const labelList& currentLevel, // current cell refinement level
415 
416  labelList& surfaces,
417  labelList& surfaceLevel
418 ) const
419 {
420  surfaces.setSize(start.size());
421  surfaces = -1;
422  surfaceLevel.setSize(start.size());
423  surfaceLevel = -1;
424 
425  if (surfaces_.empty())
426  {
427  return;
428  }
429 
430  if (surfaces_.size() == 1)
431  {
432  // Optimisation: single segmented surface. No need to duplicate
433  // point storage.
434 
435  label surfi = 0;
436 
437  const searchableSurface& geom = allGeometry_[surfaces_[surfi]];
438 
439  // Do intersection test
440  List<pointIndexHit> intersectionInfo(start.size());
441  geom.findLineAny(start, end, intersectionInfo);
442 
443  // See if a cached level field available
444  labelList minLevelField;
445  geom.getField(intersectionInfo, minLevelField);
446  bool haveLevelField =
447  (
448  returnReduce(minLevelField.size(), sumOp<label>())
449  > 0
450  );
451 
452  if (!haveLevelField && geom.regions().size() == 1)
453  {
454  minLevelField = labelList
455  (
456  intersectionInfo.size(),
457  minLevel(surfi, 0)
458  );
459  haveLevelField = true;
460  }
461 
462  if (haveLevelField)
463  {
464  forAll(intersectionInfo, i)
465  {
466  if
467  (
468  intersectionInfo[i].hit()
469  && minLevelField[i] > currentLevel[i]
470  )
471  {
472  surfaces[i] = surfi; // index of surface
473  surfaceLevel[i] = minLevelField[i];
474  }
475  }
476  return;
477  }
478  }
479 
480 
481  // Work arrays
482  pointField p0(start);
483  pointField p1(end);
484  labelList intersectionToPoint(identityMap(start.size()));
485  List<pointIndexHit> intersectionInfo(start.size());
486 
487  forAll(surfaces_, surfi)
488  {
489  const searchableSurface& geom = allGeometry_[surfaces_[surfi]];
490 
491  // Do intersection test
492  geom.findLineAny(p0, p1, intersectionInfo);
493 
494  // See if a cached level field available
495  labelList minLevelField;
496  geom.getField(intersectionInfo, minLevelField);
497 
498  // Copy all hits into arguments, In-place compact misses.
499  label missI = 0;
500  forAll(intersectionInfo, i)
501  {
502  // Get the minLevel for the point
503  label minLocalLevel = -1;
504 
505  if (intersectionInfo[i].hit())
506  {
507  // Check if minLevelField for this surface.
508  if (minLevelField.size())
509  {
510  minLocalLevel = minLevelField[i];
511  }
512  else
513  {
514  // Use the min level for the surface instead. Assume
515  // single region 0.
516  minLocalLevel = minLevel(surfi, 0);
517  }
518  }
519 
520 
521  label pointi = intersectionToPoint[i];
522 
523  if (minLocalLevel > currentLevel[pointi])
524  {
525  // Mark point for refinement
526  surfaces[pointi] = surfi;
527  surfaceLevel[pointi] = minLocalLevel;
528  }
529  else
530  {
531  p0[missI] = start[pointi];
532  p1[missI] = end[pointi];
533  intersectionToPoint[missI] = pointi;
534  missI++;
535  }
536  }
537 
538  // All done? Note that this decision should be synchronised
539  if (returnReduce(missI, sumOp<label>()) == 0)
540  {
541  break;
542  }
543 
544  // Trim misses
545  p0.setSize(missI);
546  p1.setSize(missI);
547  intersectionToPoint.setSize(missI);
548  intersectionInfo.setSize(missI);
549  }
550 }
551 
552 
554 (
555  const pointField& start,
556  const pointField& end,
557  const labelList& currentLevel, // current cell refinement level
558 
559  const labelList& globalRegionLevel,
560 
561  List<vectorList>& surfaceNormal,
562  labelListList& surfaceLevel
563 ) const
564 {
565  surfaceLevel.setSize(start.size());
566  surfaceNormal.setSize(start.size());
567 
568  if (surfaces_.empty())
569  {
570  return;
571  }
572 
573  // Work arrays
574  List<List<pointIndexHit>> hitinfo;
575  labelList pRegions;
576  vectorField pNormals;
577 
578  forAll(surfaces_, surfi)
579  {
580  const searchableSurface& surface = allGeometry_[surfaces_[surfi]];
581 
582  surface.findLineAll(start, end, hitinfo);
583 
584  // Repack hits for surface into flat list
585  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
586  // To avoid overhead of calling getRegion for every point
587 
588  label n = 0;
589  forAll(hitinfo, pointi)
590  {
591  n += hitinfo[pointi].size();
592  }
593 
594  List<pointIndexHit> surfinfo(n);
595  labelList pointMap(n);
596  n = 0;
597 
598  forAll(hitinfo, pointi)
599  {
600  const List<pointIndexHit>& pHits = hitinfo[pointi];
601 
602  forAll(pHits, i)
603  {
604  surfinfo[n] = pHits[i];
605  pointMap[n] = pointi;
606  n++;
607  }
608  }
609 
610  labelList surfRegion(n);
611  vectorField surfNormal(n);
612  surface.getRegion(surfinfo, surfRegion);
613  surface.getNormal(surfinfo, surfNormal);
614 
615  surfinfo.clear();
616 
617 
618  // Extract back into pointwise
619  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
620 
621  forAll(surfRegion, i)
622  {
623  label region = globalRegion(surfi, surfRegion[i]);
624  label pointi = pointMap[i];
625 
626  if (globalRegionLevel[region] > currentLevel[pointi])
627  {
628  // Append to pointi info
629  label sz = surfaceNormal[pointi].size();
630  surfaceNormal[pointi].setSize(sz+1);
631  surfaceNormal[pointi][sz] = surfNormal[i];
632 
633  surfaceLevel[pointi].setSize(sz+1);
634  surfaceLevel[pointi][sz] = globalRegionLevel[region];
635  }
636  }
637  }
638 }
639 
640 
642 (
643  const pointField& start,
644  const pointField& end,
645  const labelList& currentLevel, // current cell refinement level
646 
647  const labelList& globalRegionLevel,
648 
650  List<vectorList>& surfaceNormal,
651  labelListList& surfaceLevel
652 ) const
653 {
654  surfaceLevel.setSize(start.size());
655  surfaceNormal.setSize(start.size());
656  surfaceLocation.setSize(start.size());
657 
658  if (surfaces_.empty())
659  {
660  return;
661  }
662 
663  // Work arrays
664  List<List<pointIndexHit>> hitinfo;
665  labelList pRegions;
666  vectorField pNormals;
667 
668  forAll(surfaces_, surfi)
669  {
670  const searchableSurface& surface = allGeometry_[surfaces_[surfi]];
671 
672  surface.findLineAll(start, end, hitinfo);
673 
674  // Repack hits for surface into flat list
675  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
676  // To avoid overhead of calling getRegion for every point
677 
678  label n = 0;
679  forAll(hitinfo, pointi)
680  {
681  n += hitinfo[pointi].size();
682  }
683 
684  List<pointIndexHit> surfinfo(n);
685  labelList pointMap(n);
686  n = 0;
687 
688  forAll(hitinfo, pointi)
689  {
690  const List<pointIndexHit>& pHits = hitinfo[pointi];
691 
692  forAll(pHits, i)
693  {
694  surfinfo[n] = pHits[i];
695  pointMap[n] = pointi;
696  n++;
697  }
698  }
699 
700  labelList surfRegion(n);
701  vectorField surfNormal(n);
702  surface.getRegion(surfinfo, surfRegion);
703  surface.getNormal(surfinfo, surfNormal);
704 
705  // Extract back into pointwise
706  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
707 
708  forAll(surfRegion, i)
709  {
710  label region = globalRegion(surfi, surfRegion[i]);
711  label pointi = pointMap[i];
712 
713  if (globalRegionLevel[region] > currentLevel[pointi])
714  {
715  // Append to pointi info
716  label sz = surfaceNormal[pointi].size();
717  surfaceLocation[pointi].setSize(sz+1);
718  surfaceLocation[pointi][sz] = surfinfo[i].hitPoint();
719 
720  surfaceNormal[pointi].setSize(sz+1);
721  surfaceNormal[pointi][sz] = surfNormal[i];
722 
723  surfaceLevel[pointi].setSize(sz+1);
724  surfaceLevel[pointi][sz] = globalRegionLevel[region];
725  }
726  }
727  }
728 }
729 
730 
732 (
733  const labelList& surfacesToTest,
734  const pointField& start,
735  const pointField& end,
736 
737  labelList& surface1,
738  List<pointIndexHit>& hit1,
739  labelList& region1,
740  labelList& surface2,
741  List<pointIndexHit>& hit2,
742  labelList& region2
743 ) const
744 {
745  // 1. intersection from start to end
746  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
747 
748  // Initialise arguments
749  surface1.setSize(start.size());
750  surface1 = -1;
751  hit1.setSize(start.size());
752  region1.setSize(start.size());
753 
754  // Current end of segment to test.
755  pointField nearest(end);
756  // Work array
757  List<pointIndexHit> nearestInfo(start.size());
758  labelList region;
759 
760  forAll(surfacesToTest, testi)
761  {
762  label surfi = surfacesToTest[testi];
763 
764  const searchableSurface& surface = allGeometry_[surfaces_[surfi]];
765 
766  // See if any intersection between start and current nearest
767  surface.findLine
768  (
769  start,
770  nearest,
771  nearestInfo
772  );
773  surface.getRegion
774  (
775  nearestInfo,
776  region
777  );
778 
779  forAll(nearestInfo, pointi)
780  {
781  if (nearestInfo[pointi].hit())
782  {
783  hit1[pointi] = nearestInfo[pointi];
784  surface1[pointi] = surfi;
785  region1[pointi] = region[pointi];
786  nearest[pointi] = hit1[pointi].hitPoint();
787  }
788  }
789  }
790 
791 
792  // 2. intersection from end to last intersection
793  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
794 
795  // Find the nearest intersection from end to start. Note that we initialise
796  // to the first intersection (if any).
797  surface2 = surface1;
798  hit2 = hit1;
799  region2 = region1;
800 
801  // Set current end of segment to test.
802  forAll(nearest, pointi)
803  {
804  if (hit1[pointi].hit())
805  {
806  nearest[pointi] = hit1[pointi].hitPoint();
807  }
808  else
809  {
810  // Disable testing by setting to end.
811  nearest[pointi] = end[pointi];
812  }
813  }
814 
815  forAll(surfacesToTest, testi)
816  {
817  label surfi = surfacesToTest[testi];
818 
819  const searchableSurface& surface = allGeometry_[surfaces_[surfi]];
820 
821  // See if any intersection between end and current nearest
822  surface.findLine
823  (
824  end,
825  nearest,
826  nearestInfo
827  );
828  surface.getRegion
829  (
830  nearestInfo,
831  region
832  );
833 
834  forAll(nearestInfo, pointi)
835  {
836  if (nearestInfo[pointi].hit())
837  {
838  hit2[pointi] = nearestInfo[pointi];
839  surface2[pointi] = surfi;
840  region2[pointi] = region[pointi];
841  nearest[pointi] = hit2[pointi].hitPoint();
842  }
843  }
844  }
845 
846 
847  // Make sure that if hit1 has hit something, hit2 will have at least the
848  // same point (due to tolerances it might miss its end point)
849  forAll(hit1, pointi)
850  {
851  if (hit1[pointi].hit() && !hit2[pointi].hit())
852  {
853  hit2[pointi] = hit1[pointi];
854  surface2[pointi] = surface1[pointi];
855  region2[pointi] = region1[pointi];
856  }
857  }
858 }
859 
860 
862 (
863  const labelList& surfacesToTest,
864  const pointField& start,
865  const pointField& end,
866 
867  labelList& surface1,
868  List<pointIndexHit>& hit1,
869  labelList& region1,
870  vectorField& normal1,
871 
872  labelList& surface2,
873  List<pointIndexHit>& hit2,
874  labelList& region2,
875  vectorField& normal2
876 ) const
877 {
878  // 1. intersection from start to end
879  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
880 
881  // Initialise arguments
882  surface1.setSize(start.size());
883  surface1 = -1;
884  hit1.setSize(start.size());
885  region1.setSize(start.size());
886  region1 = -1;
887  normal1.setSize(start.size());
888  normal1 = Zero;
889 
890  // Current end of segment to test.
891  pointField nearest(end);
892  // Work array
893  List<pointIndexHit> nearestInfo(start.size());
894  labelList region;
895  vectorField normal;
896 
897  forAll(surfacesToTest, testi)
898  {
899  label surfi = surfacesToTest[testi];
900  const searchableSurface& geom = allGeometry_[surfaces_[surfi]];
901 
902  // See if any intersection between start and current nearest
903  geom.findLine(start, nearest, nearestInfo);
904  geom.getRegion(nearestInfo, region);
905  geom.getNormal(nearestInfo, normal);
906 
907  forAll(nearestInfo, pointi)
908  {
909  if (nearestInfo[pointi].hit())
910  {
911  hit1[pointi] = nearestInfo[pointi];
912  surface1[pointi] = surfi;
913  region1[pointi] = region[pointi];
914  normal1[pointi] = normal[pointi];
915  nearest[pointi] = hit1[pointi].hitPoint();
916  }
917  }
918  }
919 
920 
921  // 2. intersection from end to last intersection
922  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
923 
924  // Find the nearest intersection from end to start. Note that we initialise
925  // to the first intersection (if any).
926  surface2 = surface1;
927  hit2 = hit1;
928  region2 = region1;
929  normal2 = normal1;
930 
931  // Set current end of segment to test.
932  forAll(nearest, pointi)
933  {
934  if (hit1[pointi].hit())
935  {
936  nearest[pointi] = hit1[pointi].hitPoint();
937  }
938  else
939  {
940  // Disable testing by setting to end.
941  nearest[pointi] = end[pointi];
942  }
943  }
944 
945  forAll(surfacesToTest, testi)
946  {
947  label surfi = surfacesToTest[testi];
948  const searchableSurface& geom = allGeometry_[surfaces_[surfi]];
949 
950  // See if any intersection between end and current nearest
951  geom.findLine(end, nearest, nearestInfo);
952  geom.getRegion(nearestInfo, region);
953  geom.getNormal(nearestInfo, normal);
954 
955  forAll(nearestInfo, pointi)
956  {
957  if (nearestInfo[pointi].hit())
958  {
959  hit2[pointi] = nearestInfo[pointi];
960  surface2[pointi] = surfi;
961  region2[pointi] = region[pointi];
962  normal2[pointi] = normal[pointi];
963  nearest[pointi] = hit2[pointi].hitPoint();
964  }
965  }
966  }
967 
968 
969  // Make sure that if hit1 has hit something, hit2 will have at least the
970  // same point (due to tolerances it might miss its end point)
971  forAll(hit1, pointi)
972  {
973  if (hit1[pointi].hit() && !hit2[pointi].hit())
974  {
975  hit2[pointi] = hit1[pointi];
976  surface2[pointi] = surface1[pointi];
977  region2[pointi] = region1[pointi];
978  normal2[pointi] = normal1[pointi];
979  }
980  }
981 }
982 
983 
985 (
986  const pointField& start,
987  const pointField& end,
988 
989  labelList& hitSurface,
990  List<pointIndexHit>& hitinfo
991 ) const
992 {
994  (
995  allGeometry_,
996  surfaces_,
997  start,
998  end,
999  hitSurface,
1000  hitinfo
1001  );
1002 }
1003 
1004 
1006 (
1007  const labelList& surfacesToTest,
1008  const pointField& samples,
1009  const scalarField& nearestDistSqr,
1010  labelList& hitSurface,
1011  List<pointIndexHit>& hitinfo
1012 ) const
1013 {
1014  labelList geometries(UIndirectList<label>(surfaces_, surfacesToTest));
1015 
1016  // Do the tests. Note that findNearest returns index in geometries.
1018  (
1019  allGeometry_,
1020  geometries,
1021  samples,
1022  nearestDistSqr,
1023  hitSurface,
1024  hitinfo
1025  );
1026 
1027  // Rework the hitSurface to be surface (i.e. index into surfaces_)
1028  forAll(hitSurface, pointi)
1029  {
1030  if (hitSurface[pointi] != -1)
1031  {
1032  hitSurface[pointi] = surfacesToTest[hitSurface[pointi]];
1033  }
1034  }
1035 }
1036 
1037 
1039 (
1040  const labelList& surfacesToTest,
1041  const pointField& samples,
1042  const scalarField& nearestDistSqr,
1043  labelList& hitSurface,
1044  labelList& hitRegion
1045 ) const
1046 {
1047  labelList geometries(UIndirectList<label>(surfaces_, surfacesToTest));
1048 
1049  // Do the tests. Note that findNearest returns index in geometries.
1050  List<pointIndexHit> hitinfo;
1052  (
1053  allGeometry_,
1054  geometries,
1055  samples,
1056  nearestDistSqr,
1057  hitSurface,
1058  hitinfo
1059  );
1060 
1061  // Rework the hitSurface to be surface (i.e. index into surfaces_)
1062  forAll(hitSurface, pointi)
1063  {
1064  if (hitSurface[pointi] != -1)
1065  {
1066  hitSurface[pointi] = surfacesToTest[hitSurface[pointi]];
1067  }
1068  }
1069 
1070  // Collect the region
1071  hitRegion.setSize(hitSurface.size());
1072  hitRegion = -1;
1073 
1074  forAll(surfacesToTest, i)
1075  {
1076  label surfi = surfacesToTest[i];
1077 
1078  // Collect hits for surfi
1079  const labelList localIndices(findIndices(hitSurface, surfi));
1080 
1081  List<pointIndexHit> localHits
1082  (
1084  (
1085  hitinfo,
1086  localIndices
1087  )
1088  );
1089 
1090  labelList localRegion;
1091  allGeometry_[surfaces_[surfi]].getRegion(localHits, localRegion);
1092 
1093  forAll(localIndices, i)
1094  {
1095  hitRegion[localIndices[i]] = localRegion[i];
1096  }
1097  }
1098 }
1099 
1100 
1102 (
1103  const labelList& surfacesToTest,
1104  const pointField& samples,
1105  const scalarField& nearestDistSqr,
1106  labelList& hitSurface,
1107  List<pointIndexHit>& hitinfo,
1108  labelList& hitRegion,
1109  vectorField& hitNormal
1110 ) const
1111 {
1112  labelList geometries(UIndirectList<label>(surfaces_, surfacesToTest));
1113 
1114  // Do the tests. Note that findNearest returns index in geometries.
1116  (
1117  allGeometry_,
1118  geometries,
1119  samples,
1120  nearestDistSqr,
1121  hitSurface,
1122  hitinfo
1123  );
1124 
1125  // Rework the hitSurface to be surface (i.e. index into surfaces_)
1126  forAll(hitSurface, pointi)
1127  {
1128  if (hitSurface[pointi] != -1)
1129  {
1130  hitSurface[pointi] = surfacesToTest[hitSurface[pointi]];
1131  }
1132  }
1133 
1134  // Collect the region
1135  hitRegion.setSize(hitSurface.size());
1136  hitRegion = -1;
1137  hitNormal.setSize(hitSurface.size());
1138  hitNormal = Zero;
1139 
1140  forAll(surfacesToTest, i)
1141  {
1142  label surfi = surfacesToTest[i];
1143 
1144  // Collect hits for surfi
1145  const labelList localIndices(findIndices(hitSurface, surfi));
1146 
1147  List<pointIndexHit> localHits
1148  (
1150  (
1151  hitinfo,
1152  localIndices
1153  )
1154  );
1155 
1156  // Region
1157  labelList localRegion;
1158  allGeometry_[surfaces_[surfi]].getRegion(localHits, localRegion);
1159 
1160  forAll(localIndices, i)
1161  {
1162  hitRegion[localIndices[i]] = localRegion[i];
1163  }
1164 
1165  // Normal
1166  vectorField localNormal;
1167  allGeometry_[surfaces_[surfi]].getNormal(localHits, localNormal);
1168 
1169  forAll(localIndices, i)
1170  {
1171  hitNormal[localIndices[i]] = localNormal[i];
1172  }
1173  }
1174 }
1175 
1176 
1178 (
1179  const labelList& testSurfaces,
1180  const pointField& pt,
1181  labelList& insideSurfaces
1182 ) const
1183 {
1184  insideSurfaces.setSize(pt.size());
1185  insideSurfaces = -1;
1186 
1187  forAll(testSurfaces, i)
1188  {
1189  label surfi = testSurfaces[i];
1190 
1191  const searchableSurface& surface = allGeometry_[surfaces_[surfi]];
1192 
1193  const surfaceZonesInfo::areaSelectionAlgo selectionMethod =
1194  surfZones_[surfi].zoneInside();
1195 
1196  if
1197  (
1198  selectionMethod != surfaceZonesInfo::INSIDE
1199  && selectionMethod != surfaceZonesInfo::OUTSIDE
1200  )
1201  {
1203  << "Trying to use surface "
1204  << surface.name()
1205  << " which has non-geometric inside selection method "
1206  << surfaceZonesInfo::areaSelectionAlgoNames[selectionMethod]
1207  << exit(FatalError);
1208  }
1209 
1210  if (surface.hasVolumeType())
1211  {
1212  List<volumeType> volType;
1213  surface.getVolumeType(pt, volType);
1214 
1215  forAll(volType, pointi)
1216  {
1217  if (insideSurfaces[pointi] == -1)
1218  {
1219  if
1220  (
1221  (
1222  volType[pointi] == volumeType::inside
1223  && selectionMethod == surfaceZonesInfo::INSIDE
1224  )
1225  || (
1226  volType[pointi] == volumeType::outside
1227  && selectionMethod == surfaceZonesInfo::OUTSIDE
1228  )
1229  )
1230  {
1231  insideSurfaces[pointi] = surfi;
1232  }
1233  }
1234  }
1235  }
1236  }
1237 }
1238 
1239 
1240 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
A HashTable with keys but without contents.
Definition: HashSet.H:62
List< Key > sortedToc() const
Return the table of contents as a sorted list.
Definition: HashTable.C:242
bool erase(const iterator &)
Erase a hashedEntry specified by given iterator.
Definition: HashTable.C:445
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
const word & name() const
Return name.
Definition: IOobject.H:310
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
void setSize(const label)
Reset size of List.
Definition: List.C:281
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
bool set(const label) const
Is element set.
Definition: PtrListI.H:62
A List with indirect addressing.
Definition: UIndirectList.H:60
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
autoPtr< dictionary > clone() const
Construct and return clone.
Definition: dictionary.C:398
const entry * lookupEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:548
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T, if not found return the given default.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:710
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:843
wordList toc() const
Return the table of contents.
Definition: dictionary.C:976
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:509
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:68
const keyType & keyword() const
Return keyword.
Definition: entry.H:123
virtual const dictionary & dict() const =0
Return dictionary if this entry is a dictionary.
Encapsulates queries for volume refinement ('refine all cells within shell').
void findAllHigherIntersections(const pointField &start, const pointField &end, const labelList &currentLevel, const labelList &globalRegionLevel, List< vectorList > &surfaceNormal, labelListList &surfaceLevel) const
Find all intersections of edge. Unsorted order.
void findNearest(const labelList &surfacesToTest, const pointField &samples, const scalarField &nearestDistSqr, labelList &surfaces, List< pointIndexHit > &) const
Find nearest point on surfaces.
refinementSurfaces(const searchableSurfaces &allGeometry, const dictionary &, const label gapLevelIncrement)
Construct from surfaces and dictionary.
const PtrList< dictionary > & patchInfo() const
From global region number to patch type.
void findInside(const labelList &surfacesToTest, const pointField &pt, labelList &insideSurfaces) const
Detect if a point is 'inside' (closed) surfaces.
void findNearestRegion(const labelList &surfacesToTest, const pointField &samples, const scalarField &nearestDistSqr, labelList &hitSurface, labelList &hitRegion) const
Find nearest point on surfaces. Return surface and region on.
void findAnyIntersection(const pointField &start, const pointField &end, labelList &surfaces, List< pointIndexHit > &) const
Used for debugging only: find intersection of edge.
void findHigherIntersection(const pointField &start, const pointField &end, const labelList &currentLevel, labelList &surfaces, labelList &surfaceLevel) const
Find intersection of edge. Return -1 or first surface.
void setMinLevelFields(const refinementRegions &shells, const scalar level0EdgeLength, const bool extendedRefinementSpan)
Calculate the refinement level for every element.
void findNearestIntersection(const labelList &surfacesToTest, const pointField &start, const pointField &end, labelList &surface1, List< pointIndexHit > &hit1, labelList &region1, labelList &surface2, List< pointIndexHit > &hit2, labelList &region2) const
Find intersection nearest to the endpoints. surface1,2 are.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
virtual void getRegion(const List< pointIndexHit > &, labelList &region) const =0
From a set of points and indices get the region.
virtual void findLine(const pointField &start, const pointField &end, List< pointIndexHit > &) const =0
Find first intersection on segment from start to end.
virtual void getVolumeType(const pointField &, List< volumeType > &) const =0
Determine type (inside/outside) for point. unknown if.
virtual void findNearest(const pointField &sample, const scalarField &nearestDistSqr, List< pointIndexHit > &) const =0
virtual bool hasVolumeType() const =0
Whether supports volume type below.
virtual void getField(const List< pointIndexHit > &, labelList &values) const
WIP. From a set of hits (points and.
virtual const wordList & regions() const =0
Names of regions.
virtual void findLineAll(const pointField &start, const pointField &end, List< List< pointIndexHit >> &) const =0
Get all intersections in order from start to end.
virtual void findLineAny(const pointField &start, const pointField &end, List< pointIndexHit > &) const =0
Return any intersection on segment from start to end.
virtual label globalSize() const
Range of global indices that can be returned.
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const =0
From a set of points and indices get the normal.
virtual void boundingSpheres(pointField &centres, scalarField &radiusSqr) const =0
Get bounding spheres (centre and radius squared), one per element.
static void findAnyIntersection(const PtrList< searchableSurface > &, const labelList &surfacesToTest, const pointField &start, const pointField &end, labelList &surfaces, List< pointIndexHit > &)
Find any intersection. Return hit point information and.
static void findNearest(const PtrList< searchableSurface > &, const labelList &surfacesToTest, const pointField &, const scalarField &nearestDistSqr, labelList &surfaces, List< pointIndexHit > &)
Find nearest. Return -1 (and a miss()) or surface and nearest.
Container for searchableSurfaces.
const wordList & names() const
Contains information about location on a triSurface.
areaSelectionAlgo
Types of selection of area.
static const NamedEnum< areaSelectionAlgo, 4 > areaSelectionAlgoNames
A class for handling words, derived from string.
Definition: word.H:62
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
labelList findIndices(const ListType &, typename ListType::const_reference, const label start=0)
Find all occurrences of given element. Linear search.
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
T clone(const T &t)
Definition: List.H:55
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
IOerror FatalIOError
error FatalError
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
dictionary dict
surfacesMesh setField(triSurfaceToAgglom)
const Foam::wordList regionNames(args.optionFound("allRegions") ? runTime .controlDict().subDict("regionSolvers").toc() :wordList(1, args.optionFound("region") ? args.optionRead< word >("region") :polyMesh::defaultRegion))
scalarField samples(nIntervals, 0)