conformationSurfaces.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) 2012-2017 OpenFOAM Foundation
9  Copyright (C) 2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "conformationSurfaces.H"
30 #include "conformalVoronoiMesh.H"
31 #include "triSurface.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38  defineTypeNameAndDebug(conformationSurfaces, 0);
39 }
40 
41 
42 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
43 
44 void Foam::conformationSurfaces::hasBoundedVolume
45 (
46  List<volumeType>& referenceVolumeTypes
47 ) const
48 {
49  vector sum(Zero);
50  label totalTriangles = 0;
51 
52  forAll(surfaces_, s)
53  {
54  const searchableSurface& surface(allGeometry_[surfaces_[s]]);
55 
56  if
57  (
58  surface.hasVolumeType()
59  && (
60  normalVolumeTypes_[regionOffset_[s]]
62  )
63  )
64  {
65  pointField pts(1, locationInMesh_);
66 
67  List<volumeType> vTypes
68  (
69  pts.size(),
71  );
72 
73  surface.getVolumeType(pts, vTypes);
74 
75  referenceVolumeTypes[s] = vTypes[0];
76 
77  Info<< " is " << referenceVolumeTypes[s].str()
78  << " surface " << surface.name()
79  << endl;
80  }
81 
82  if (isA<triSurface>(surface))
83  {
84  const triSurface& triSurf = refCast<const triSurface>(surface);
85 
86  const pointField& surfPts = triSurf.points();
87 
88  Info<< " Checking " << surface.name() << endl;
89 
90  label nBaffles = 0;
91 
92  Info<< " Index = " << surfaces_[s] << endl;
93  Info<< " Offset = " << regionOffset_[s] << endl;
94 
95  for (const labelledTri& f : triSurf)
96  {
97  const label patchID = f.region() + regionOffset_[s];
98 
99  // Don't include baffle surfaces in the calculation
100  if
101  (
102  normalVolumeTypes_[patchID]
104  )
105  {
106  sum += f.areaNormal(surfPts);
107  }
108  else
109  {
110  ++nBaffles;
111  }
112  }
113  Info<< " has " << nBaffles << " baffles out of "
114  << triSurf.size() << " triangles" << nl;
115 
116  totalTriangles += triSurf.size();
117  }
118  }
119 
120  Info<< " Sum of all the surface normals (if near zero, surface is"
121  << " probably closed):" << nl
122  << " Note: Does not include baffle surfaces in calculation" << nl
123  << " Sum = " << sum/(totalTriangles + SMALL) << nl
124  << " mag(Sum) = " << mag(sum)/(totalTriangles + SMALL)
125  << endl;
126 }
127 
128 
129 void Foam::conformationSurfaces::readFeatures
130 (
131  const label surfI,
132  const dictionary& featureDict,
133  const word& surfaceName,
134  label& featureIndex
135 )
136 {
137  const word featureMethod =
138  featureDict.getOrDefault<word>("featureMethod", "none");
139 
140  if (featureMethod == "extendedFeatureEdgeMesh")
141  {
142  fileName feMeshName
143  (
144  featureDict.get<fileName>("extendedFeatureEdgeMesh")
145  );
146 
147  Info<< " features: " << feMeshName << endl;
148 
149  features_.set
150  (
151  featureIndex,
152  new extendedFeatureEdgeMesh
153  (
154  IOobject
155  (
156  feMeshName,
157  runTime_.time().constant(),
158  "extendedFeatureEdgeMesh",
159  runTime_.time(),
162  )
163  )
164  );
165 
166  featureIndex++;
167  }
168  else if (featureMethod == "extractFeatures")
169  {
170  const searchableSurface& surface = allGeometry_[surfaces_[surfI]];
171 
172  Info<< " features: " << surface.name()
173  << " of type " << surface.type()
174  << ", id: " << featureIndex << endl;
175 
176  autoPtr<searchableSurfaceFeatures> ssFeatures
177  (
178  searchableSurfaceFeatures::New(surface, featureDict)
179  );
180 
181  if (ssFeatures().hasFeatures())
182  {
183  features_.set
184  (
185  featureIndex,
186  ssFeatures().features()
187  );
188 
189  featureIndex++;
190  }
191  else
192  {
194  << surface.name() << " of type "
195  << surface.type() << " does not have features"
196  << endl;
197  }
198  }
199  else if (featureMethod == "none")
200  {
201  // Currently nothing to do
202  }
203  else
204  {
206  << "No valid featureMethod found for surface " << surfaceName
207  << nl << "Use \"extendedFeatureEdgeMesh\" "
208  << "or \"extractFeatures\"."
209  << exit(FatalError);
210  }
211 }
212 
213 void Foam::conformationSurfaces::readFeatures
214 (
215  const dictionary& featureDict,
216  const word& surfaceName,
217  label& featureIndex
218 )
219 {
220  const word featureMethod =
221  featureDict.getOrDefault<word>("featureMethod", "none");
222 
223  if (featureMethod == "extendedFeatureEdgeMesh")
224  {
225  fileName feMeshName
226  (
227  featureDict.get<fileName>("extendedFeatureEdgeMesh")
228  );
229 
230  Info<< " features: " << feMeshName << ", id: " << featureIndex
231  << endl;
232 
233  features_.set
234  (
235  featureIndex,
236  new extendedFeatureEdgeMesh
237  (
238  IOobject
239  (
240  feMeshName,
241  runTime_.time().constant(),
242  "extendedFeatureEdgeMesh",
243  runTime_.time(),
246  )
247  )
248  );
249 
250  featureIndex++;
251  }
252  else if (featureMethod == "none")
253  {
254  // Currently nothing to do
255  }
256  else
257  {
259  << "No valid featureMethod found for surface " << surfaceName
260  << nl << "Use \"extendedFeatureEdgeMesh\" "
261  << "or \"extractFeatures\"."
262  << exit(FatalError);
263  }
264 }
265 
266 
267 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
268 
269 Foam::conformationSurfaces::conformationSurfaces
270 (
271  const Time& runTime,
272  Random& rndGen,
273  const searchableSurfaces& allGeometry,
274  const dictionary& surfaceConformationDict
275 )
276 :
277  runTime_(runTime),
278  rndGen_(rndGen),
279  allGeometry_(allGeometry),
280  features_(),
281  locationInMesh_(surfaceConformationDict.get<point>("locationInMesh")),
282  surfaces_(),
283  allGeometryToSurfaces_(),
284  normalVolumeTypes_(),
285  patchNames_(),
286  surfZones_(),
287  regionOffset_(),
288  patchInfo_(),
289  globalBounds_(),
290  referenceVolumeTypes_(0)
291 {
292  const dictionary& surfacesDict
293  (
294  surfaceConformationDict.subDict("geometryToConformTo")
295  );
296 
297  const dictionary& additionalFeaturesDict
298  (
299  surfaceConformationDict.subDict("additionalFeatures")
300  );
301 
302 
303  // Wildcard specification : loop over all surface, all regions
304  // and try to find a match.
305 
306  // Count number of surfaces.
307  label surfI = 0;
308  for (const word& geomName : allGeometry_.names())
309  {
310  if (surfacesDict.found(geomName))
311  {
312  ++surfI;
313  }
314  }
315 
316  const label nAddFeat = additionalFeaturesDict.size();
317 
318  Info<< nl << "Reading geometryToConformTo" << endl;
319 
320  allGeometryToSurfaces_.setSize(allGeometry_.size(), -1);
321 
322  normalVolumeTypes_.setSize(surfI);
323  surfaces_.setSize(surfI);
324  surfZones_.setSize(surfI);
325 
326  // Features may be attached to host surfaces or independent
327  features_.setSize(surfI + nAddFeat);
328 
329  label featureI = 0;
330 
331  regionOffset_.setSize(surfI, 0);
332 
333  PtrList<dictionary> globalPatchInfo(surfI);
334  List<Map<autoPtr<dictionary>>> regionPatchInfo(surfI);
335  List<sideVolumeType> globalVolumeTypes(surfI);
336  List<Map<sideVolumeType>> regionVolumeTypes(surfI);
337 
338  wordHashSet unmatchedKeys(surfacesDict.toc());
339 
340  surfI = 0;
341  forAll(allGeometry_.names(), geomI)
342  {
343  const word& geomName = allGeometry_.names()[geomI];
344 
345  const entry* ePtr = surfacesDict.findEntry(geomName, keyType::REGEX);
346 
347  if (ePtr)
348  {
349  const dictionary& dict = ePtr->dict();
350  unmatchedKeys.erase(ePtr->keyword());
351 
352  surfaces_[surfI] = geomI;
353 
354  const searchableSurface& surface = allGeometry_[surfaces_[surfI]];
355 
356  // Surface zones
357  if (dict.found("faceZone"))
358  {
359  surfZones_.set
360  (
361  surfI,
362  new surfaceZonesInfo
363  (
364  surface,
365  dict,
366  allGeometry_.regionNames()[surfaces_[surfI]]
367  )
368  );
369  }
370 
371  allGeometryToSurfaces_[surfaces_[surfI]] = surfI;
372 
373  Info<< nl << " " << geomName << endl;
374 
375  const wordList& regionNames =
376  allGeometry_.regionNames()[surfaces_[surfI]];
377 
378  patchNames_.append(regionNames);
379 
380  globalVolumeTypes[surfI] =
381  (
383  [
384  dict.getOrDefault<word>
385  (
386  "meshableSide",
387  "inside"
388  )
389  ]
390  );
391 
392  if (!globalVolumeTypes[surfI])
393  {
394  if (!surface.hasVolumeType())
395  {
397  << "Non-baffle surface "
398  << surface.name()
399  << " does not allow inside/outside queries."
400  << " This usually is an error." << endl;
401  }
402  }
403 
404  // Load patch info
405  if (dict.found("patchInfo"))
406  {
407  globalPatchInfo.set
408  (
409  surfI,
410  dict.subDict("patchInfo").clone()
411  );
412  }
413 
414  readFeatures
415  (
416  surfI,
417  dict,
418  geomName,
419  featureI
420  );
421 
422  const wordList& rNames = surface.regions();
423 
424  if (dict.found("regions"))
425  {
426  const dictionary& regionsDict = dict.subDict("regions");
427 
428  forAll(rNames, regionI)
429  {
430  const word& regionName = rNames[regionI];
431 
432  if (regionsDict.found(regionName))
433  {
434  Info<< " region " << regionName << endl;
435 
436  // Get the dictionary for region
437  const dictionary& regionDict = regionsDict.subDict
438  (
439  regionName
440  );
441 
442  if (regionDict.found("patchInfo"))
443  {
444  regionPatchInfo[surfI].insert
445  (
446  regionI,
447  regionDict.subDict("patchInfo").clone()
448  );
449  }
450 
451  regionVolumeTypes[surfI].insert
452  (
453  regionI,
455  [
456  regionDict.getOrDefault<word>
457  (
458  "meshableSide",
459  extendedFeatureEdgeMesh::
460  sideVolumeTypeNames_
461  [
462  globalVolumeTypes[surfI]
463  ]
464  )
465  ]
466  );
467 
468  readFeatures(regionDict, regionName, featureI);
469  }
470  }
471  }
472 
473  surfI++;
474  }
475  }
476 
477 
478  if (unmatchedKeys.size() > 0)
479  {
480  IOWarningInFunction(surfacesDict)
481  << "Not all entries in conformationSurfaces dictionary were used."
482  << " The following entries were not used : "
483  << unmatchedKeys.sortedToc()
484  << endl;
485  }
486 
487 
488  // Calculate local to global region offset
489  label nRegions = 0;
490 
491  forAll(surfaces_, surfI)
492  {
493  regionOffset_[surfI] = nRegions;
494 
495  const searchableSurface& surface = allGeometry_[surfaces_[surfI]];
496  nRegions += surface.regions().size();
497  }
498 
499  // Rework surface specific information into information per global region
500  patchInfo_.setSize(nRegions);
501  normalVolumeTypes_.setSize(nRegions);
502 
503  forAll(surfaces_, surfI)
504  {
505  const searchableSurface& surface = allGeometry_[surfaces_[surfI]];
506 
507  label nRegions = surface.regions().size();
508 
509  // Initialise to global (i.e. per surface)
510  for (label i = 0; i < nRegions; i++)
511  {
512  label globalRegionI = regionOffset_[surfI] + i;
513  normalVolumeTypes_[globalRegionI] = globalVolumeTypes[surfI];
514  if (globalPatchInfo.set(surfI))
515  {
516  patchInfo_.set
517  (
518  globalRegionI,
519  globalPatchInfo[surfI].clone()
520  );
521  }
522  }
523 
524  forAllConstIters(regionVolumeTypes[surfI], iter)
525  {
526  label globalRegionI = regionOffset_[surfI] + iter.key();
527 
528  normalVolumeTypes_[globalRegionI] =
529  regionVolumeTypes[surfI][iter.key()];
530  }
531 
532  const Map<autoPtr<dictionary>>& localInfo = regionPatchInfo[surfI];
533  forAllConstIters(localInfo, iter)
534  {
535  label globalRegionI = regionOffset_[surfI] + iter.key();
536 
537  patchInfo_.set(globalRegionI, iter()().clone());
538  }
539  }
540 
541 
542 
543  if (!additionalFeaturesDict.empty())
544  {
545  Info<< nl << "Reading additionalFeatures" << endl;
546  }
547 
548  for (const entry& dEntry : additionalFeaturesDict)
549  {
550  const word& featureName = dEntry.keyword();
551  const dictionary& featureSubDict = dEntry.dict();
552 
553  Info<< nl << " " << featureName << endl;
554 
555  readFeatures(featureSubDict, featureName, featureI);
556  }
557 
558  // Remove unnecessary space from the features list
559  features_.setSize(featureI);
560 
561  globalBounds_ = treeBoundBox
562  (
563  searchableSurfacesQueries::bounds(allGeometry_, surfaces_)
564  );
565 
566  // Extend the global bounds to stop the bound box sitting on the surfaces
567  // to be conformed to
568  //globalBounds_ = globalBounds_.extend(rndGen_, 1e-4);
569 
570  vector newSpan = 1e-4*globalBounds_.span();
571 
572  globalBounds_.min() -= newSpan;
573  globalBounds_.max() += newSpan;
574 
575  // Look at all surfaces at determine whether the locationInMesh point is
576  // inside or outside each, to establish a signature for the domain to be
577  // meshed.
578 
579  referenceVolumeTypes_.setSize
580  (
581  surfaces_.size(),
583  );
584 
585  Info<< endl
586  << "Testing for locationInMesh " << locationInMesh_ << endl;
587 
588  hasBoundedVolume(referenceVolumeTypes_);
589 
590  if (debug)
591  {
592  Info<< "Names = " << allGeometry_.names() << endl;
593  Info<< "Surfaces = " << surfaces_ << endl;
594  Info<< "AllGeom to Surfaces = " << allGeometryToSurfaces_ << endl;
595  Info<< "Volume types = " << normalVolumeTypes_ << endl;
596  Info<< "Patch names = " << patchNames_ << endl;
597  Info<< "Region Offset = " << regionOffset_ << endl;
598 
599  forAll(features_, fI)
600  {
601  Info<< features_[fI].name() << endl;
602  }
603  }
604 }
605 
606 
607 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
608 
609 bool Foam::conformationSurfaces::overlaps(const treeBoundBox& bb) const
610 {
611  forAll(surfaces_, s)
612  {
613  if (allGeometry_[surfaces_[s]].overlaps(bb))
614  {
615  return true;
616  }
617  }
618 
619  return false;
620 }
621 
622 
624 (
625  const pointField& samplePts
626 ) const
627 {
628  return wellInside(samplePts, scalarField(samplePts.size(), Zero));
629 }
630 
631 
633 (
634  const point& samplePt
635 ) const
636 {
637  return wellInside(pointField(1, samplePt), scalarField(1, Zero))[0];
638 }
639 
640 
642 (
643  const pointField& samplePts
644 ) const
645 {
646  return wellOutside(samplePts, scalarField(samplePts.size(), Zero));
647 }
648 
649 
651 (
652  const point& samplePt
653 ) const
654 {
655  return wellOutside(pointField(1, samplePt), scalarField(1, Zero))[0];
656  //return !inside(samplePt);
657 }
658 
659 
661 (
662  const pointField& samplePts,
663  const scalarField& testDistSqr,
664  const bool testForInside
665 ) const
666 {
667  List<List<volumeType>> surfaceVolumeTests
668  (
669  surfaces_.size(),
670  List<volumeType>
671  (
672  samplePts.size(),
674  )
675  );
676 
677  // Get lists for the volumeTypes for each sample wrt each surface
678  forAll(surfaces_, s)
679  {
680  const searchableSurface& surface(allGeometry_[surfaces_[s]]);
681 
682  const label regionI = regionOffset_[s];
683 
684  if (normalVolumeTypes_[regionI] != extendedFeatureEdgeMesh::BOTH)
685  {
686  surface.getVolumeType(samplePts, surfaceVolumeTests[s]);
687  }
688  }
689 
690  // Compare the volumeType result for each point wrt to each surface with the
691  // reference value and if the points are inside the surface by a given
692  // distanceSquared
693 
694  // Assume that the point is wellInside until demonstrated otherwise.
695  Field<bool> insideOutsidePoint(samplePts.size(), testForInside);
696 
697  //Check if the points are inside the surface by the given distance squared
698 
699  labelList hitSurfaces;
700  List<pointIndexHit> hitInfo;
702  (
703  allGeometry_,
704  surfaces_,
705  samplePts,
706  testDistSqr,
707  hitSurfaces,
708  hitInfo
709  );
710 
711  forAll(samplePts, i)
712  {
713  const pointIndexHit& pHit = hitInfo[i];
714 
715  if (pHit.hit())
716  {
717  // If the point is within range of the surface, then it can't be
718  // well (in|out)side
719  insideOutsidePoint[i] = false;
720 
721  continue;
722  }
723 
724  forAll(surfaces_, s)
725  {
726  const label regionI = regionOffset_[s];
727 
728  if (normalVolumeTypes_[regionI] == extendedFeatureEdgeMesh::BOTH)
729  {
730  continue;
731  }
732 
733  const searchableSurface& surface(allGeometry_[surfaces_[s]]);
734 
735  if
736  (
737  !surface.hasVolumeType()
738  //&& surfaceVolumeTests[s][i] == volumeType::UNKNOWN
739  )
740  {
741  pointField sample(1, samplePts[i]);
742  scalarField nearestDistSqr(1, GREAT);
743  List<pointIndexHit> info;
744 
745  surface.findNearest(sample, nearestDistSqr, info);
746 
747  const vector hitDir =
748  normalised
749  (
750  info[0].rawPoint() - samplePts[i]
751  );
752 
753  pointIndexHit surfHit;
754  label hitSurface;
755 
756  findSurfaceNearestIntersection
757  (
758  samplePts[i],
759  info[0].rawPoint() - 1e-3*mag(hitDir)*hitDir,
760  surfHit,
761  hitSurface
762  );
763 
764  if (surfHit.hit() && hitSurface != surfaces_[s])
765  {
766  continue;
767  }
768  }
769 
770  if (surfaceVolumeTests[s][i] == volumeType::OUTSIDE)
771  {
772  if
773  (
774  normalVolumeTypes_[regionI]
776  )
777  {
778  insideOutsidePoint[i] = !testForInside;
779  break;
780  }
781  }
782  else if (surfaceVolumeTests[s][i] == volumeType::INSIDE)
783  {
784  if
785  (
786  normalVolumeTypes_[regionI]
788  )
789  {
790  insideOutsidePoint[i] = !testForInside;
791  break;
792  }
793  }
794  }
795  }
796 
797  return insideOutsidePoint;
798 }
799 
800 
802 (
803  const pointField& samplePts,
804  const scalarField& testDistSqr
805 ) const
806 {
807  return wellInOutSide(samplePts, testDistSqr, true);
808 }
809 
810 
812 (
813  const point& samplePt,
814  scalar testDistSqr
815 ) const
816 {
817  return wellInside(pointField(1, samplePt), scalarField(1, testDistSqr))[0];
818 }
819 
820 
822 (
823  const pointField& samplePts,
824  const scalarField& testDistSqr
825 ) const
826 {
827  return wellInOutSide(samplePts, testDistSqr, false);
828 }
829 
830 
832 (
833  const point& samplePt,
834  scalar testDistSqr
835 ) const
836 {
837  return wellOutside(pointField(1, samplePt), scalarField(1, testDistSqr))[0];
838 }
839 
840 
842 (
843  const point& start,
844  const point& end
845 ) const
846 {
847  labelList hitSurfaces;
848  List<pointIndexHit> hitInfo;
849 
851  (
852  allGeometry_,
853  surfaces_,
854  pointField(1, start),
855  pointField(1, end),
856  hitSurfaces,
857  hitInfo
858  );
859 
860  return hitInfo[0].hit();
861 }
862 
863 
865 (
866  const point& start,
867  const point& end,
868  pointIndexHit& surfHit,
869  label& hitSurface
870 ) const
871 {
872  labelList hitSurfaces;
873  List<pointIndexHit> hitInfo;
874 
876  (
877  allGeometry_,
878  surfaces_,
879  pointField(1, start),
880  pointField(1, end),
881  hitSurfaces,
882  hitInfo
883  );
884 
885  surfHit = hitInfo[0];
886 
887  if (surfHit.hit())
888  {
889  // hitSurfaces has returned the index of the entry in surfaces_ that was
890  // found, not the index of the surface in allGeometry_, translating this
891  // to allGeometry_
892 
893  hitSurface = surfaces_[hitSurfaces[0]];
894  }
895 }
896 
897 
899 (
900  const point& start,
901  const point& end,
902  List<pointIndexHit>& surfHit,
903  labelList& hitSurface
904 ) const
905 {
906  labelListList hitSurfaces;
907  List<List<pointIndexHit>> hitInfo;
908 
910  (
911  allGeometry_,
912  surfaces_,
913  pointField(1, start),
914  pointField(1, end),
915  hitSurfaces,
916  hitInfo
917  );
918 
919  surfHit = hitInfo[0];
920 
921  hitSurface.setSize(hitSurfaces[0].size());
922 
923  forAll(hitSurfaces[0], surfI)
924  {
925  // hitSurfaces has returned the index of the entry in surfaces_ that was
926  // found, not the index of the surface in allGeometry_, translating this
927  // to allGeometry_
928 
929  hitSurface[surfI] = surfaces_[hitSurfaces[0][surfI]];
930  }
931 }
932 
933 
935 (
936  const point& start,
937  const point& end,
938  pointIndexHit& surfHit,
939  label& hitSurface
940 ) const
941 {
942  labelList hitSurfacesStart;
943  List<pointIndexHit> hitInfoStart;
944  labelList hitSurfacesEnd;
945  List<pointIndexHit> hitInfoEnd;
946 
948  (
949  allGeometry_,
950  surfaces_,
951  pointField(1, start),
952  pointField(1, end),
953  hitSurfacesStart,
954  hitInfoStart,
955  hitSurfacesEnd,
956  hitInfoEnd
957  );
958 
959  surfHit = hitInfoStart[0];
960 
961  if (surfHit.hit())
962  {
963  // hitSurfaces has returned the index of the entry in surfaces_ that was
964  // found, not the index of the surface in allGeometry_, translating this
965  // to allGeometry_
966 
967  hitSurface = surfaces_[hitSurfacesStart[0]];
968  }
969 }
970 
971 
973 (
974  const point& sample,
975  scalar nearestDistSqr,
976  pointIndexHit& surfHit,
977  label& hitSurface
978 ) const
979 {
980  labelList hitSurfaces;
981  List<pointIndexHit> surfaceHits;
982 
984  (
985  allGeometry_,
986  surfaces_,
987  pointField(1, sample),
988  scalarField(1, nearestDistSqr),
989  hitSurfaces,
990  surfaceHits
991  );
992 
993  surfHit = surfaceHits[0];
994 
995  if (surfHit.hit())
996  {
997  // hitSurfaces has returned the index of the entry in surfaces_ that was
998  // found, not the index of the surface in allGeometry_, translating this
999  // to allGeometry_
1000 
1001  hitSurface = surfaces_[hitSurfaces[0]];
1002  }
1003 }
1004 
1005 
1007 (
1008  const pointField& samples,
1009  const scalarField& nearestDistSqr,
1010  List<pointIndexHit>& surfaceHits,
1011  labelList& hitSurfaces
1012 ) const
1013 {
1015  (
1016  allGeometry_,
1017  surfaces_,
1018  samples,
1019  nearestDistSqr,
1020  hitSurfaces,
1021  surfaceHits
1022  );
1023 
1024  forAll(surfaceHits, i)
1025  {
1026  if (surfaceHits[i].hit())
1027  {
1028  // hitSurfaces has returned the index of the entry in surfaces_ that
1029  // was found, not the index of the surface in allGeometry_,
1030  // translating this to the surface in allGeometry_.
1031 
1032  hitSurfaces[i] = surfaces_[hitSurfaces[i]];
1033  }
1034  }
1035 }
1036 
1037 
1039 (
1040  const point& sample,
1041  scalar nearestDistSqr,
1042  pointIndexHit& fpHit,
1043  label& featureHit
1044 ) const
1045 {
1046  // Work arrays
1047  scalar minDistSqr = nearestDistSqr;
1048  pointIndexHit hitInfo;
1049 
1050  forAll(features_, testI)
1051  {
1052  features_[testI].nearestFeaturePoint
1053  (
1054  sample,
1055  minDistSqr,
1056  hitInfo
1057  );
1058 
1059  if (hitInfo.hit())
1060  {
1061  minDistSqr = magSqr(hitInfo.hitPoint()- sample);
1062  fpHit = hitInfo;
1063  featureHit = testI;
1064  }
1065  }
1066 }
1067 
1068 
1070 (
1071  const point& sample,
1072  scalar nearestDistSqr,
1073  pointIndexHit& edgeHit,
1074  label& featureHit
1075 ) const
1076 {
1077  pointField samples(1, sample);
1078  scalarField nearestDistsSqr(1, nearestDistSqr);
1079 
1080  List<pointIndexHit> edgeHits;
1081  labelList featuresHit;
1082 
1083  findEdgeNearest
1084  (
1085  samples,
1086  nearestDistsSqr,
1087  edgeHits,
1088  featuresHit
1089  );
1090 
1091  edgeHit = edgeHits[0];
1092  featureHit = featuresHit[0];
1093 }
1094 
1095 
1097 (
1098  const pointField& samples,
1099  const scalarField& nearestDistsSqr,
1100  List<pointIndexHit>& edgeHits,
1101  labelList& featuresHit
1102 ) const
1103 {
1104  // Initialise
1105  featuresHit.setSize(samples.size());
1106  featuresHit = -1;
1107  edgeHits.setSize(samples.size());
1108 
1109  // Work arrays
1110  scalarField minDistSqr(nearestDistsSqr);
1111  List<pointIndexHit> hitInfo(samples.size());
1112 
1113  forAll(features_, testI)
1114  {
1115  features_[testI].nearestFeatureEdge
1116  (
1117  samples,
1118  minDistSqr,
1119  hitInfo
1120  );
1121 
1122  // Update minDistSqr and arguments
1123  forAll(hitInfo, pointi)
1124  {
1125  if (hitInfo[pointi].hit())
1126  {
1127  minDistSqr[pointi] = magSqr
1128  (
1129  hitInfo[pointi].hitPoint()
1130  - samples[pointi]
1131  );
1132  edgeHits[pointi] = hitInfo[pointi];
1133  featuresHit[pointi] = testI;
1134  }
1135  }
1136  }
1137 }
1138 
1139 
1141 (
1142  const point& sample,
1143  scalar nearestDistSqr,
1144  List<pointIndexHit>& edgeHits,
1145  List<label>& featuresHit
1146 ) const
1147 {
1148  // Initialise
1149  featuresHit.setSize(extendedFeatureEdgeMesh::nEdgeTypes);
1150  featuresHit = -1;
1151  edgeHits.setSize(extendedFeatureEdgeMesh::nEdgeTypes);
1152 
1153  // Work arrays
1154  scalarField minDistSqr(extendedFeatureEdgeMesh::nEdgeTypes, nearestDistSqr);
1155  List<pointIndexHit> hitInfo(extendedFeatureEdgeMesh::nEdgeTypes);
1156 
1157  forAll(features_, testI)
1158  {
1159  features_[testI].nearestFeatureEdgeByType
1160  (
1161  sample,
1162  minDistSqr,
1163  hitInfo
1164  );
1165 
1166  // Update minDistSqr and arguments
1167  forAll(hitInfo, typeI)
1168  {
1169  if (hitInfo[typeI].hit())
1170  {
1171  minDistSqr[typeI] = magSqr(hitInfo[typeI].hitPoint() - sample);
1172  edgeHits[typeI] = hitInfo[typeI];
1173  featuresHit[typeI] = testI;
1174  }
1175  }
1176  }
1177 }
1178 
1179 
1181 (
1182  const point& sample,
1183  const scalar searchRadiusSqr,
1184  List<List<pointIndexHit>>& edgeHitsByFeature,
1185  List<label>& featuresHit
1186 ) const
1187 {
1188  // Initialise
1189  //featuresHit.setSize(features_.size());
1190  //featuresHit = -1;
1191  //edgeHitsByFeature.setSize(features_.size());
1192 
1193  // Work arrays
1194  List<pointIndexHit> hitInfo(extendedFeatureEdgeMesh::nEdgeTypes);
1195 
1196  forAll(features_, testI)
1197  {
1198  features_[testI].allNearestFeatureEdges
1199  (
1200  sample,
1201  searchRadiusSqr,
1202  hitInfo
1203  );
1204 
1205  bool anyHit = false;
1206  forAll(hitInfo, hitI)
1207  {
1208  if (hitInfo[hitI].hit())
1209  {
1210  anyHit = true;
1211  }
1212  }
1213 
1214  if (anyHit)
1215  {
1216  edgeHitsByFeature.append(hitInfo);
1217  featuresHit.append(testI);
1218  }
1219  }
1220 }
1221 
1222 
1223 void Foam::conformationSurfaces::writeFeatureObj(const fileName& prefix) const
1224 {
1225  OFstream ftStr(runTime_.time().path()/prefix + "_allFeatures.obj");
1226 
1227  Pout<< nl << "Writing all features to " << ftStr.name() << endl;
1228 
1229  label verti = 0;
1230 
1231  forAll(features_, i)
1232  {
1233  const extendedFeatureEdgeMesh& fEM(features_[i]);
1234  const pointField pts(fEM.points());
1235  const edgeList eds(fEM.edges());
1236 
1237  ftStr << "g " << fEM.name() << endl;
1238 
1239  forAll(eds, j)
1240  {
1241  const edge& e = eds[j];
1242 
1243  meshTools::writeOBJ(ftStr, pts[e[0]]); verti++;
1244  meshTools::writeOBJ(ftStr, pts[e[1]]); verti++;
1245  ftStr << "l " << verti-1 << ' ' << verti << endl;
1246  }
1247  }
1248 }
1249 
1250 
1252 (
1253  const point& ptA,
1254  const point& ptB
1255 ) const
1256 {
1257  pointIndexHit surfHit;
1258  label hitSurface;
1259 
1260  findSurfaceAnyIntersection(ptA, ptB, surfHit, hitSurface);
1261 
1262  return getPatchID(hitSurface, surfHit);
1263 }
1264 
1265 
1266 Foam::label Foam::conformationSurfaces::findPatch(const point& pt) const
1267 {
1268  pointIndexHit surfHit;
1269  label hitSurface;
1270 
1271  findSurfaceNearest(pt, sqr(GREAT), surfHit, hitSurface);
1272 
1273  return getPatchID(hitSurface, surfHit);
1274 }
1275 
1276 
1278 (
1279  const label hitSurface,
1280  const pointIndexHit& surfHit
1281 ) const
1282 {
1283  if (!surfHit.hit())
1284  {
1285  return -1;
1286  }
1287 
1288  labelList surfLocalRegion;
1289 
1290  allGeometry_[hitSurface].getRegion
1291  (
1292  List<pointIndexHit>(1, surfHit),
1293  surfLocalRegion
1294  );
1295 
1296  const label patchID =
1297  surfLocalRegion[0]
1298  + regionOffset_[allGeometryToSurfaces_[hitSurface]];
1299 
1300  return patchID;
1301 }
1302 
1303 
1306 (
1307  const label hitSurface,
1308  const pointIndexHit& surfHit
1309 ) const
1310 {
1311  const label patchID = getPatchID(hitSurface, surfHit);
1312 
1313  if (patchID == -1)
1314  {
1316  }
1317 
1318  return normalVolumeTypes_[patchID];
1319 }
1320 
1321 
1323 (
1324  const label hitSurface,
1325  const List<pointIndexHit>& surfHit,
1326  vectorField& normal
1327 ) const
1328 {
1329  allGeometry_[hitSurface].getNormal(surfHit, normal);
1330 
1331  const label patchID = regionOffset_[allGeometryToSurfaces_[hitSurface]];
1332 
1333  // Now flip sign of normal depending on mesh side
1334  if (normalVolumeTypes_[patchID] == extendedFeatureEdgeMesh::OUTSIDE)
1335  {
1336  normal *= -1;
1337  }
1338 }
1339 
1340 
1341 // ************************************************************************* //
Foam::conformationSurfaces::wellInOutSide
Field< bool > wellInOutSide(const pointField &samplePts, const scalarField &testDistSqr, bool testForInside) const
Check if point is closer to the surfaces to conform to than.
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::conformationSurfaces::findSurfaceNearest
void findSurfaceNearest(const point &sample, scalar nearestDistSqr, pointIndexHit &surfHit, label &hitSurface) const
Find the nearest point to the sample and return it to the.
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
runTime
engineTime & runTime
Definition: createEngineTime.H:13
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
searchableSurfaceFeatures.H
Foam::conformationSurfaces::findSurfaceAllIntersections
void findSurfaceAllIntersections(const point &start, const point &end, List< pointIndexHit > &surfHit, labelList &hitSurface) const
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputSpray.H:25
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::extendedEdgeMesh::NEITHER
not sure when this may be used
Definition: extendedEdgeMesh.H:122
Foam::dictionary::found
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Search for an entry (const access) with the given keyword.
Definition: dictionary.C:364
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
Foam::conformationSurfaces::writeFeatureObj
void writeFeatureObj(const fileName &prefix) const
Write all components of all the extendedFeatureEdgeMeshes as.
Foam::searchableSurfacesQueries::findAnyIntersection
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.
Definition: searchableSurfacesQueries.C:122
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:182
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
triSurface.H
Foam::conformationSurfaces::getPatchID
label getPatchID(const label hitSurface, const pointIndexHit &surfHit) const
Get the region number of a hit surface.
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::extendedEdgeMesh::sideVolumeTypeNames_
static const Enum< sideVolumeType > sideVolumeTypeNames_
Definition: extendedEdgeMesh.H:125
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::wordList
List< word > wordList
A List of words.
Definition: fileName.H:59
Foam::conformationSurfaces::findSurfaceNearestIntersection
void findSurfaceNearestIntersection(const point &start, const point &end, pointIndexHit &surfHit, label &hitSurface) const
Finding the nearestIntersection of the surface to start.
Foam::conformationSurfaces::inside
Field< bool > inside(const pointField &samplePts) const
Check if points are inside surfaces to conform to.
regionName
Foam::word regionName
Definition: createNamedDynamicFvMesh.H:1
Foam::searchableSurfacesQueries::findNearestIntersection
static void findNearestIntersection(const PtrList< searchableSurface > &allSurfaces, const labelList &surfacesToTest, const pointField &start, const pointField &end, labelList &surface1, List< pointIndexHit > &hit1, labelList &surface2, List< pointIndexHit > &hit2)
Find intersections of edge nearest to both endpoints.
Definition: searchableSurfacesQueries.C:262
Foam::Field< bool >
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::extendedEdgeMesh::nEdgeTypes
static constexpr label nEdgeTypes
Number of possible feature edge types (i.e. number of slices)
Definition: extendedEdgeMesh.H:254
Foam::volumeType::UNKNOWN
Unknown state.
Definition: volumeType.H:67
Foam::extendedEdgeMesh::sideVolumeType
sideVolumeType
Normals point to the outside.
Definition: extendedEdgeMesh.H:117
patchID
label patchID
Definition: boundaryProcessorFaPatchPoints.H:5
Foam::conformationSurfaces::wellInside
Field< bool > wellInside(const pointField &samplePts, const scalarField &testDistSqr) const
Check if point is inside surfaces to conform to by at least.
Foam::dictionary::subDict
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:528
conformationSurfaces.H
Foam::conformationSurfaces::overlaps
bool overlaps(const treeBoundBox &bb) const
Check if the supplied bound box overlaps any part of any of.
Foam::conformationSurfaces::findEdgeNearestByType
void findEdgeNearestByType(const point &sample, scalar nearestDistSqr, List< pointIndexHit > &edgeHit, List< label > &featuresHit) const
Find the nearest point on each type of feature edge.
Foam::conformationSurfaces::outside
Field< bool > outside(const pointField &samplePts) const
Check if points are outside surfaces to conform to.
samples
scalarField samples(nIntervals, Zero)
Foam::conformationSurfaces::findPatch
label findPatch(const point &ptA, const point &ptB) const
Find which patch is intersected by the line from one point to.
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::extendedEdgeMesh::OUTSIDE
mesh outside
Definition: extendedEdgeMesh.H:120
Foam::extendedEdgeMesh::INSIDE
mesh inside
Definition: extendedEdgeMesh.H:119
Foam::FatalError
error FatalError
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:121
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:483
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::conformationSurfaces::meshableSide
extendedFeatureEdgeMesh::sideVolumeType meshableSide(const label hitSurface, const pointIndexHit &surfHit) const
Is the surface a baffle.
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::pointIndexHit
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:45
Foam::searchableSurfacesQueries::bounds
static boundBox bounds(const PtrList< searchableSurface > &allSurfaces, const labelUList &surfacesToTest)
Find the boundBox of the selected surfaces.
Definition: searchableSurfacesQueries.C:697
Foam::nl
constexpr char nl
Definition: Ostream.H:385
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::searchableSurfaceFeatures::New
static autoPtr< searchableSurfaceFeatures > New(const searchableSurface &surface, const dictionary &dict)
Return a reference to the selected searchableSurfaceFeatures.
Foam::ILList::erase
bool erase(T *item)
Remove the specified element from the list and delete it.
Definition: ILList.C:97
f
labelList f(nPoints)
Foam::extendedEdgeMesh::BOTH
e.g. a baffle
Definition: extendedEdgeMesh.H:121
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::dictionary::clone
autoPtr< dictionary > clone() const
Construct and return clone.
Definition: dictionary.C:178
Foam::keyType::REGEX
Regular expression.
Definition: keyType.H:74
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:327
Foam::conformationSurfaces::findFeaturePointNearest
void findFeaturePointNearest(const point &sample, scalar nearestDistSqr, pointIndexHit &fpHit, label &featureHit) const
Find the nearest point on any feature edge.
Foam::volumeType::INSIDE
A location inside the volume.
Definition: volumeType.H:68
Foam::conformationSurfaces::findSurfaceAnyIntersection
bool findSurfaceAnyIntersection(const point &start, const point &end) const
Foam::searchableSurfacesQueries::findAllIntersections
static void findAllIntersections(const PtrList< searchableSurface > &, const labelList &surfacesToTest, const pointField &start, const pointField &end, labelListList &surfaces, List< List< pointIndexHit >> &surfaceHits)
Find all intersections in order from start to end. Returns for.
Definition: searchableSurfacesQueries.C:183
Foam::wordHashSet
HashSet< word > wordHashSet
A HashSet with word keys.
Definition: HashSet.H:407
rndGen
Random rndGen
Definition: createFields.H:23
IOWarningInFunction
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
Definition: messageStream.H:310
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::conformationSurfaces::findEdgeNearest
void findEdgeNearest(const point &sample, scalar nearestDistSqr, pointIndexHit &edgeHit, label &featureHit) const
Find the nearest point on any feature edge.
Foam::dictionary::getOrDefault
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:122
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:298
Foam::searchableSurfacesQueries::findNearest
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.
Definition: searchableSurfacesQueries.C:349
Foam::volumeType::OUTSIDE
A location outside the volume.
Definition: volumeType.H:69
Foam::conformationSurfaces::getNormal
void getNormal(const label hitSurface, const List< pointIndexHit > &surfHit, vectorField &normal) const
conformalVoronoiMesh.H
Foam::conformationSurfaces::findAllNearestEdges
void findAllNearestEdges(const point &sample, const scalar searchRadiusSqr, List< List< pointIndexHit >> &edgeHitsByFeature, List< label > &featuresHit) const
Find the nearest points on each feature edge that is within.
Foam::IOobject::MUST_READ
Definition: IOobject.H:120
Foam::conformationSurfaces::wellOutside
Field< bool > wellOutside(const pointField &samplePts, const scalarField &testDistSqr) const
Check if point is outside surfaces to conform to by at least.