surfaceToCell.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-2026 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 "surfaceToCell.H"
27 #include "polyMesh.H"
28 #include "meshSearch.H"
29 #include "triSurface.H"
30 #include "triSurfaceSearch.H"
31 #include "cellClassification.H"
32 #include "cpuTime.H"
33 #include "demandDrivenData.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40  defineTypeNameAndDebug(surfaceToCell, 0);
41  addToRunTimeSelectionTable(topoSetSource, surfaceToCell, word);
42 }
43 
44 
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 
47 Foam::label Foam::surfaceToCell::getNearest
48 (
49  const triSurfaceSearch& querySurf,
50  const label pointi,
51  const point& pt,
52  const vector& span,
53  Map<label>& cache
54 )
55 {
56  Map<label>::const_iterator iter = cache.find(pointi);
57 
58  if (iter != cache.end())
59  {
60  // Found cached answer
61  return iter();
62  }
63  else
64  {
65  pointIndexHit inter = querySurf.nearest(pt, span);
66 
67  // Triangle label (can be -1)
68  label triI = inter.index();
69 
70  // Store triangle on point
71  cache.insert(pointi, triI);
72 
73  return triI;
74  }
75 }
76 
77 
78 bool Foam::surfaceToCell::differingPointNormals
79 (
80  const triSurfaceSearch& querySurf,
81 
82  const vector& span, // Current search span
83  const label celli,
84  const label cellTriI, // Nearest (to cell centre) surface triangle
85 
86  Map<label>& pointToNearest // Cache for nearest triangle to point
87 ) const
88 {
89  const triSurface& surf = querySurf.surface();
90  const vectorField& normals = surf.faceNormals();
91 
92  const faceList& faces = mesh().faces();
93  const pointField& points = mesh().points();
94 
95  const labelList& cFaces = mesh().cells()[celli];
96 
97  forAll(cFaces, cFacei)
98  {
99  const face& f = faces[cFaces[cFacei]];
100 
101  forAll(f, fp)
102  {
103  label pointi = f[fp];
104 
105  label pointTriI =
106  getNearest
107  (
108  querySurf,
109  pointi,
110  points[pointi],
111  span,
112  pointToNearest
113  );
114 
115  if (pointTriI != -1 && pointTriI != cellTriI)
116  {
117  scalar cosAngle = normals[pointTriI] & normals[cellTriI];
118 
119  if (cosAngle < 0.9)
120  {
121  return true;
122  }
123  }
124  }
125  }
126  return false;
127 }
128 
129 
130 void Foam::surfaceToCell::combine(topoSet& set, const bool add) const
131 {
132  cpuTime timer;
133 
134 
135  if (useSurfaceOrientation_ && (includeInside_ || includeOutside_))
136  {
137  //- Calculate for each searchPoint inside/outside status.
138  boolList isInside(querySurf().calcInside(mesh_.cellCentres()));
139 
140  Info<< " Marked inside/outside using surface orientation in = "
141  << timer.cpuTimeIncrement() << " s" << endl << endl;
142 
143  forAll(isInside, celli)
144  {
145  if (isInside[celli] && includeInside_)
146  {
147  addOrDelete(set, celli, add);
148  }
149  else if (!isInside[celli] && includeOutside_)
150  {
151  addOrDelete(set, celli, add);
152  }
153  }
154  }
155  else if (includeCut_ || includeInside_ || includeOutside_)
156  {
157  //
158  // Cut cells with surface and classify cells
159  //
160 
161  // Check all 'outside' points
162  forAll(outsidePoints_, outsideI)
163  {
164  const point& outsidePoint = outsidePoints_[outsideI];
165 
166  // Find cell point is in. Linear search.
167  label celli = meshSearch::findCellNoTree(mesh_, outsidePoint);
168 
169  if (returnReduce(celli, maxOp<label>()) == -1)
170  {
172  << "outsidePoint " << outsidePoint
173  << " is not inside any cell"
174  << exit(FatalError);
175  }
176  }
177 
178  // Cut faces with surface and classify cells
179 
180  cellClassification cellType(mesh_, querySurf(), outsidePoints_);
181 
182 
183  Info<< " Marked inside/outside using surface intersection in = "
184  << timer.cpuTimeIncrement() << " s" << endl << endl;
185 
186  //- Add/remove cells using set
187  forAll(cellType, celli)
188  {
189  label cType = cellType[celli];
190 
191  if
192  (
193  (
194  includeCut_
195  && (cType == cellClassification::CUT)
196  )
197  || (
198  includeInside_
199  && (cType == cellClassification::INSIDE)
200  )
201  || (
202  includeOutside_
203  && (cType == cellClassification::OUTSIDE)
204  )
205  )
206  {
207  addOrDelete(set, celli, add);
208  }
209  }
210  }
211 
212 
213  if (nearDist_ > 0)
214  {
215  //
216  // Determine distance to surface
217  //
218 
219  const pointField& ctrs = mesh_.cellCentres();
220 
221  // Box dimensions to search in octree.
222  const vector span(nearDist_, nearDist_, nearDist_);
223 
224 
225  if (curvature_ < -1)
226  {
227  Info<< " Selecting cells with cellCentre closer than "
228  << nearDist_ << " to surface" << endl;
229 
230  // No need to test curvature. Insert near cells into set.
231 
232  forAll(ctrs, celli)
233  {
234  const point& c = ctrs[celli];
235 
236  pointIndexHit inter = querySurf().nearest(c, span);
237 
238  if (inter.hit() && (mag(inter.hitPoint() - c) < nearDist_))
239  {
240  addOrDelete(set, celli, add);
241  }
242  }
243 
244  Info<< " Determined nearest surface point in = "
245  << timer.cpuTimeIncrement() << " s" << endl << endl;
246 
247  }
248  else
249  {
250  // Test near cells for curvature
251 
252  Info<< " Selecting cells with cellCentre closer than "
253  << nearDist_ << " to surface and curvature factor"
254  << " less than " << curvature_ << endl;
255 
256  // Cache for nearest surface triangle for a point
257  Map<label> pointToNearest(mesh_.nCells()/10);
258 
259  forAll(ctrs, celli)
260  {
261  const point& c = ctrs[celli];
262 
263  pointIndexHit inter = querySurf().nearest(c, span);
264 
265  if (inter.hit() && (mag(inter.hitPoint() - c) < nearDist_))
266  {
267  if
268  (
269  differingPointNormals
270  (
271  querySurf(),
272  span,
273  celli,
274  inter.index(), // nearest surface triangle
275  pointToNearest
276  )
277  )
278  {
279  addOrDelete(set, celli, add);
280  }
281  }
282  }
283 
284  Info<< " Determined nearest surface point in = "
285  << timer.cpuTimeIncrement() << " s" << endl << endl;
286  }
287  }
288 }
289 
290 
291 void Foam::surfaceToCell::checkSettings() const
292 {
293  if
294  (
295  (nearDist_ < 0)
296  && (curvature_ < -1)
297  && (
298  (includeCut_ && includeInside_ && includeOutside_)
299  || (!includeCut_ && !includeInside_ && !includeOutside_)
300  )
301  )
302  {
304  << "Illegal include cell specification."
305  << " Result would be either all or no cells." << endl
306  << "Please set one of includeCut, includeInside, includeOutside"
307  << " to true, set nearDistance to a value > 0"
308  << " or set curvature to a value -1 .. 1."
309  << exit(FatalError);
310  }
311 
312  if (useSurfaceOrientation_ && includeCut_)
313  {
315  << "Illegal include cell specification."
316  << " You cannot specify both 'useSurfaceOrientation'"
317  << " and 'includeCut'"
318  << " since 'includeCut' specifies a topological split"
319  << exit(FatalError);
320  }
321 }
322 
323 
324 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
325 
327 (
328  const polyMesh& mesh,
329  const fileName& surfName,
330  const pointField& outsidePoints,
331  const bool includeCut,
332  const bool includeInside,
333  const bool includeOutside,
334  const bool useSurfaceOrientation,
335  const scalar nearDist,
336  const scalar curvature
337 )
338 :
339  topoSetSource(mesh),
340  surfName_(surfName),
341  outsidePoints_(outsidePoints),
342  includeCut_(includeCut),
343  includeInside_(includeInside),
344  includeOutside_(includeOutside),
345  useSurfaceOrientation_(useSurfaceOrientation),
346  nearDist_(nearDist),
347  curvature_(curvature),
348  surfPtr_(new triSurface(surfName_)),
349  querySurfPtr_(new triSurfaceSearch(*surfPtr_)),
350  IOwnPtrs_(true)
351 {
352  checkSettings();
353 }
354 
355 
357 (
358  const polyMesh& mesh,
359  const fileName& surfName,
360  const triSurface& surf,
361  const triSurfaceSearch& querySurf,
362  const pointField& outsidePoints,
363  const bool includeCut,
364  const bool includeInside,
365  const bool includeOutside,
366  const bool useSurfaceOrientation,
367  const scalar nearDist,
368  const scalar curvature
369 )
370 :
371  topoSetSource(mesh),
372  surfName_(surfName),
373  outsidePoints_(outsidePoints),
374  includeCut_(includeCut),
375  includeInside_(includeInside),
376  includeOutside_(includeOutside),
377  useSurfaceOrientation_(useSurfaceOrientation),
378  nearDist_(nearDist),
379  curvature_(curvature),
380  surfPtr_(&surf),
381  querySurfPtr_(&querySurf),
382  IOwnPtrs_(false)
383 {
384  checkSettings();
385 }
386 
387 
389 (
390  const polyMesh& mesh,
391  const dictionary& dict
392 )
393 :
394  topoSetSource(mesh),
395  surfName_(fileName(dict.lookup("file")).expand()),
396  outsidePoints_(dict.lookup<List<point>>("outsidePoints", dimLength)),
397  includeCut_(readBool(dict.lookup("includeCut"))),
398  includeInside_(readBool(dict.lookup("includeInside"))),
399  includeOutside_(readBool(dict.lookup("includeOutside"))),
400  useSurfaceOrientation_
401  (
402  dict.lookupOrDefault<bool>("useSurfaceOrientation", false)
403  ),
404  nearDist_(dict.lookup<scalar>("nearDistance", dimLength)),
405  curvature_(dict.lookup<scalar>("curvature", units::none)),
406  surfPtr_(new triSurface(surfName_)),
407  querySurfPtr_(new triSurfaceSearch(*surfPtr_)),
408  IOwnPtrs_(true)
409 {
410  checkSettings();
411 }
412 
413 
414 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
415 
417 {
418  if (IOwnPtrs_)
419  {
420  deleteDemandDrivenData(surfPtr_);
421  deleteDemandDrivenData(querySurfPtr_);
422  }
423 }
424 
425 
426 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
427 
429 (
430  const topoSetSource::setAction action,
431  topoSet& set
432 ) const
433 {
434  if ((action == topoSetSource::NEW) || (action == topoSetSource::ADD))
435  {
436  Info<< " Adding cells in relation to surface " << surfName_
437  << " ..." << endl;
438 
439  combine(set, true);
440  }
441  else if (action == topoSetSource::DELETE)
442  {
443  Info<< " Removing cells in relation to surface " << surfName_
444  << " ..." << endl;
445 
446  combine(set, false);
447  }
448 }
449 
450 
451 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Macros for easy insertion into run-time selection tables.
friend class const_iterator
Declare friendship with the const_iterator.
Definition: HashTable.H:197
static label findCellNoTree(const polyMesh &mesh, const point &p, const pointInCellShapes=pointInCellShapes::tets)
Find the cell containing the given point. Do a.
Definition: meshSearch.C:183
Motion of the mesh specified as a list of pointMeshMovers.
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
const cellList & cells() const
surfaceToCell(const polyMesh &mesh, const fileName &surfName, const pointField &outsidePoints, const bool includeCut, const bool includeInside, const bool includeOutside, const bool useSurfaceOrientation, const scalar nearDist, const scalar curvature)
Construct from components.
virtual void applyToSet(const topoSetSource::setAction action, topoSet &) const
virtual ~surfaceToCell()
Destructor.
setAction
Enumeration defining the valid actions.
Definition: topoSetSource.H:83
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
Template functions to aid in the implementation of demand driven data.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
const pointField & points
const dimensionedScalar c
Speed of light in a vacuum.
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
bool readBool(Istream &)
Definition: boolIO.C:63
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
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, word)
void add(GeometricField< typename typeOfSum< Type1, Type2 >::type, GeoMesh, PrimitiveField1 > &gf, const GeometricField< Type1, GeoMesh, PrimitiveField2 > &gf1, const GeometricField< Type2, GeoMesh, PrimitiveField3 > &gf2)
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:42
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
const dimensionSet & dimLength
Definition: dimensions.C:141
void deleteDemandDrivenData(DataType *&dataPtr)
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
vector point
Point is a vector.
Definition: point.H:41
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Field< vector > vectorField
Specialisation of Field<T> for vector.
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
error FatalError
treeBoundBox combine(const treeBoundBox &a, const treeBoundBox &b)
Definition: patchToPatch.C:78
List< face > faceList
Definition: faceListFwd.H:41
defineTypeNameAndDebug(atmosphericBoundaryLayer, 0)
string expand(const string &s, string::size_type &index, const dictionary &dict, const bool allowEnvVars, const bool allowEmpty)
Definition: stringOps.C:146
labelList f(nPoints)
dictionary dict