searchableSurfacesInsideFraction.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) 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 
27 #include "syncTools.H"
28 #include "cutPolyIntegral.H"
29 
30 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
31 
33 (
34  const searchableSurface& surface,
35  const polyMesh& mesh
36 )
37 {
38  const boundBox& surfaceBb = surface.bounds();
39 
40  // Step 1. Calculate a length scale for each mesh point. This is used to
41  // determine if a point is in the range of the surface and thereby prevent
42  // expensive surface tests on points that are far away.
43 
44  scalarField pointLengthScale(mesh.nPoints(), -vGreat);
45  forAll(mesh.faces(), facei)
46  {
47  forAll(mesh.faces()[facei], faceEdgei)
48  {
49  const edge e = mesh.faces()[facei].faceEdge(faceEdgei);
50  const scalar l = e.mag(mesh.points());
51 
52  forAll(e, i)
53  {
54  pointLengthScale[e[i]] = max(pointLengthScale[e[i]], l);
55  pointLengthScale[e[i]] = max(pointLengthScale[e[i]], l);
56  }
57  }
58  }
59  syncTools::syncPointList
60  (
61  mesh,
62  pointLengthScale,
64  -vGreat
65  );
66 
67  // Step 2. Calculate a signed distance field from the surface
68 
69  // Determine points in range of the surface
70  DynamicList<label> nearPointPointis(mesh.nPoints());
71  forAll(mesh.points(), pointi)
72  {
73  const point& p = mesh.points()[pointi];
74  const vector l = pointLengthScale[pointi]*vector::one;
75 
76  if (surfaceBb.overlaps(boundBox(p - l, p + l)))
77  {
78  nearPointPointis.append(pointi);
79  }
80  }
81  nearPointPointis.shrink();
82  const pointField nearPoints(mesh.points(), nearPointPointis);
83 
84  // Search for mesh points' nearest surface points
85  List<pointIndexHit> nearPointHits(nearPoints.size());
86  surface.findNearest
87  (
88  nearPoints,
89  scalarField(nearPoints.size(), rootVGreat),
90  nearPointHits
91  );
92 
93  // Determine whether the mesh points are inside or outside the surface
94  List<volumeType> nearPointsVolumeType(nearPoints.size());
95  surface.getVolumeType(nearPoints, nearPointsVolumeType);
96 
97  // Convert points into distances, and use the inside/outside status to
98  // assign a sign to that distance
99  scalarField pointDistances(mesh.nPoints(), rootVGreat);
100  forAll(nearPoints, nearPointi)
101  {
102  const label pointi = nearPointPointis[nearPointi];
103 
104  const scalar d =
105  mag(nearPoints[nearPointi] - nearPointHits[nearPointi].hitPoint());
106 
107  switch (nearPointsVolumeType[nearPointi])
108  {
109  case volumeType::unknown:
110  case volumeType::mixed:
111  pointDistances[pointi] = vGreat;
112  break;
113  case volumeType::outside:
114  pointDistances[pointi] = d;
115  break;
116  case volumeType::inside:
117  pointDistances[pointi] = -d;
118  break;
119  }
120  }
121 
122  // Step 3. Cut the mesh at the zero iso-surface of the signed distance
123  // field, and obtain the volumes that result.
124 
126 
128  forAll(mesh.faces(), facei)
129  {
130  faceCuts[facei] =
132  (
133  mesh.faces()[facei],
134  pointDistances,
135  0
136  );
137  }
138 
140  forAll(mesh.cells(), celli)
141  {
142  cellCuts[celli] =
144  (
145  mesh.cells()[celli],
146  cAddrs[celli],
147  mesh.faces(),
148  faceCuts,
149  pointDistances,
150  0
151  );
152  }
153 
154  vectorField faceCutAreas(mesh.faces().size());
155  pointField faceCutCentres(mesh.faces().size());
156  forAll(mesh.faces(), facei)
157  {
158  const Tuple2<vector, tensor> fCutAreaCentre =
160  (
161  mesh.faces()[facei],
162  mesh.faceAreas()[facei],
163  mesh.faceCentres()[facei],
164  faceCuts[facei],
165  mesh.points(),
166  mesh.points(),
167  pointDistances,
168  0,
169  true
170  );
171 
172  const vector fCutArea = fCutAreaCentre.first();
173  const scalar fMagSqrCutArea = magSqr(fCutArea);
174 
175  faceCutAreas[facei] = fCutArea;
176  faceCutCentres[facei] =
177  fMagSqrCutArea > vSmall
178  ? (fCutArea & fCutAreaCentre.second())/fMagSqrCutArea
179  : mesh.faceCentres()[facei];
180  }
181 
182  scalarField cellCutVolumes(mesh.cells().size());
183  forAll(mesh.cells(), celli)
184  {
185  cellCutVolumes[celli] =
187  (
188  mesh.cells()[celli],
189  cAddrs[celli],
190  mesh.cellVolumes()[celli],
191  cellCuts[celli],
192  mesh.faces(),
193  mesh.faceAreas(),
194  mesh.faceCentres(),
195  faceCutAreas,
196  mesh.points(),
197  pointDistances,
198  0,
199  true
200  );
201  }
202 
203  // Step 4. Divide the cut volumes through by the total cell volumes to get
204  // the volume fraction
205 
206  return cellCutVolumes/mesh.cellVolumes();
207 }
208 
209 
211 (
212  const searchableSurface& surface,
213  const polyPatch& patch
214 )
215 {
216  const pointField& points = patch.localPoints();
217  const faceList& faces = patch.localFaces();
218  const vectorField::subField& faceAreas = patch.faceAreas();
219 
220  // Search for mesh points' nearest surface points
221  List<pointIndexHit> pointHits(points.size());
222  surface.findNearest
223  (
224  points,
225  scalarField(points.size(), rootVGreat),
226  pointHits
227  );
228 
229  // Determine whether the mesh points are inside or outside the surface
230  List<volumeType> pointsVolumeType(points.size());
231  surface.getVolumeType(points, pointsVolumeType);
232 
233  // Convert points into distances, and use the inside/outside status to
234  // assign a sign to that distance
235  scalarField pointDistances(points.size(), rootVGreat);
236  forAll(points, pointi)
237  {
238  const scalar d =
239  mag(points[pointi] - pointHits[pointi].hitPoint());
240 
241  switch (pointsVolumeType[pointi])
242  {
243  case volumeType::unknown:
244  case volumeType::mixed:
245  pointDistances[pointi] = vGreat;
246  break;
247  case volumeType::outside:
248  pointDistances[pointi] = d;
249  break;
250  case volumeType::inside:
251  pointDistances[pointi] = -d;
252  break;
253  }
254  }
255 
256  // Cut the faces at the zero iso-surface of the signed distance field, and
257  // obtain the areas that result.
259  forAll(faces, facei)
260  {
261  faceCuts[facei] =
263  (
264  faces[facei],
265  pointDistances,
266  0
267  );
268  }
269 
270  vectorField faceCutAreas(faces.size());
271  forAll(faces, facei)
272  {
273  faceCutAreas[facei] =
275  (
276  faces[facei],
277  faceAreas[facei],
278  faceCuts[facei],
279  points,
280  pointDistances,
281  0,
282  true
283  );
284  }
285 
286  // Divide the cut areas through by the total face areas to get the area
287  // fraction
288  return mag(faceCutAreas)/mag(faceAreas);
289 }
290 
291 
292 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:252
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
const List< FaceType > & localFaces() const
Return patch faces addressing into local point list.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
Pre-declare related SubField type.
Definition: SubField.H:63
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
const Type2 & second() const
Return second.
Definition: Tuple2.H:131
const Type1 & first() const
Return first.
Definition: Tuple2.H:119
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:60
bool overlaps(const boundBox &) const
Overlaps/touches boundingBox?
Definition: boundBoxI.H:154
Description of cuts across cells.
Definition: cellCuts.H:111
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:61
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
const vectorField::subField faceAreas() const
Return face areas.
Definition: polyPatch.C:233
const vectorField & faceCentres() const
const scalarField & cellVolumes() const
label nPoints() const
const vectorField & faceAreas() const
const cellList & cells() const
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
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
const boundBox & bounds() const
Return const reference to boundBox.
A class for managing temporary objects.
Definition: tmp.H:55
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
volScalarField scalarField(fieldObject, mesh)
const pointField & points
const dimensionedScalar e
Elementary charge.
Tuple2< vector, std::tuple< AreaIntegralType< Types > ... > > faceCutAreaIntegral(const face &f, const vector &fArea, const std::tuple< Types ... > &fPsis, const List< labelPair > &fCuts, const pointField &ps, const std::tuple< const Field< Types > &... > &pPsis, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the face-cut-area and face-cut-area-integral of the given properties.
vector faceCutArea(const face &f, const vector &fArea, const List< labelPair > &fCuts, const pointField &ps, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the face-cut-area.
List< labelPair > faceCuts(const face &f, const scalarField &pAlphas, const scalar isoAlpha)
Return the cuts for a given face. This returns a list of pairs of.
Definition: cutPoly.C:61
labelListList cellCuts(const cell &c, const cellEdgeAddressing &cAddr, const faceUList &fs, const List< List< labelPair >> &fCuts, const scalarField &pAlphas, const scalar isoAlpha)
Return the cuts for a given cell. This returns a list of lists of cell-edge.
Definition: cutPoly.C:121
scalar cellCutVolume(const cell &c, const cellEdgeAddressing &cAddr, const scalar cVolume, const labelListList &cCuts, const faceUList &fs, const vectorField &fAreas, const pointField &fCentres, const vectorField &fCutAreas, const pointField &ps, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the cell-cut-volume.
tmp< scalarField > insideFraction(const searchableSurface &surface, const polyMesh &mesh)
Return a cell-field of the volume fraction inside the given surface.
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
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
tmp< DimensionedField< scalar, GeoMesh, Field > > magSqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
volScalarField & p