cutPolyIntegralTemplates.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) 2018-2025 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 "cutPolyIntegral.H"
27 #include <utility>
28 
29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
30 
31 namespace Foam
32 {
33 namespace cutPoly
34 {
35 
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
37 
38 template<class Int, Int Offset, class Sequence>
40 
41 template<class Int, Int Offset, Int ... Is>
42 struct OffsetSequence<Int, Offset, std::integer_sequence<Int, Is ...>>
43 {
44  using type = std::integer_sequence<Int, Is + Offset ...>;
45 };
46 
47 
48 template<class Int, Int Min, Int Max>
50 {
51  using type =
52  typename OffsetSequence
53  <
54  Int,
55  Min,
56  std::make_index_sequence<Max - Min>
57  >::type;
58 };
59 
60 
61 template<class Tuple, class Int, Int ... Is>
63 (
64  const Tuple& tuple,
65  const std::integer_sequence<Int, Is ...>&
66 )
67 {
68  return std::make_tuple(std::get<Is>(tuple) ...);
69 }
70 
71 
72 template<class Op, class Tuple, class Int, Int ... Is>
74 (
75  const Tuple& tuple,
76  const std::integer_sequence<Int, Is ...>&,
77  const Op& op
78 )
79 {
80  return std::make_tuple(op(std::get<Is>(tuple)) ...);
81 }
82 
83 
84 template<class ... Types>
85 auto tupleTail(const std::tuple<Types ...>& tuple)
86 {
87  return
89  (
90  tuple,
91  typename RangeSequence<std::size_t, 1, sizeof ... (Types)>::type()
92  );
93 }
94 
95 
96 template<class Op, class ... Types>
97 auto tupleOp(const std::tuple<Types ...>& tuple, const Op& op)
98 {
99  return
101  (
102  tuple,
103  std::make_index_sequence<sizeof ... (Types)>(),
104  op
105  );
106 }
107 
108 
109 template<class Op, class Tuple, class Int, Int ... Is>
111 (
112  Tuple& tuple,
113  const std::integer_sequence<Int, Is ...>&,
114  const Op& op
115 )
116 {
117  (void)std::initializer_list<nil>
118  {(
119  op(std::get<Is>(tuple)),
120  nil()
121  ) ... };
122 }
123 
124 
125 template<class Op, class ... Types>
126 void tupleInPlaceOp(std::tuple<Types ...>& tuple, const Op& op)
127 {
128  tupleInPlaceOp(tuple, std::make_index_sequence<sizeof ... (Types)>(), op);
129 }
130 
131 
132 template<class BinaryOp, class Tuple, class Int, Int ... Is>
134 (
135  const Tuple& tupleA,
136  const Tuple& tupleB,
137  const std::integer_sequence<Int, Is ...>&,
138  const BinaryOp& bop
139 )
140 {
141  return std::make_tuple(bop(std::get<Is>(tupleA), std::get<Is>(tupleB)) ...);
142 }
143 
144 
145 template<class BinaryOp, class ... TypesA, class ... TypesB>
147 (
148  const std::tuple<TypesA ...>& tupleA,
149  const std::tuple<TypesB ...>& tupleB,
150  const BinaryOp& bop
151 )
152 {
153  return tupleBinaryOp
154  (
155  tupleA,
156  tupleB,
157  std::make_index_sequence<sizeof ... (TypesA)>(),
158  bop
159  );
160 }
161 
162 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
163 
164 } // End namespace cutPoly
165 } // End namespace Foam
166 
167 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
168 
169 template<template<class> class FaceValues, class ... Types>
171 <
172  Foam::vector,
173  std::tuple<Foam::cutPoly::AreaIntegralType<Types> ...>
174 >
176 (
177  const FaceValues<point>& fPs,
178  const point& fPAvg,
179  const std::tuple<FaceValues<Types> ...>& fPsis,
180  const std::tuple<Types ...>& fPsiAvgs
181 )
182 {
183  vector fCutsArea = Zero;
184  auto fCutsAreaPsi = std::make_tuple(AreaIntegralType<Types>(Zero) ...);
185 
186  typename FaceValues<point>::const_iterator fPIter(fPs.begin());
187  auto fPsiIter = tupleOp(fPsis, OpBegin());
188 
189  for(; fPIter != fPs.end(); ++ fPIter)
190  {
191  const point p0 = *fPIter;
192  const point p1 = fPIter.next();
193  auto psi0 = tupleOp(fPsiIter, OpDereference());
194  auto psi1 = tupleOp(fPsiIter, OpNext());
195 
196  const vector a = ((p1 - p0)^(fPAvg - p0))/2;
197 
198  fCutsArea += a;
199  fCutsAreaPsi =
201  (
202  fCutsAreaPsi,
203  tupleOp
204  (
206  (
207  psi0,
209  (
210  psi1,
211  fPsiAvgs,
212  BinaryOpAdd()
213  ),
214  BinaryOpAdd()
215  ),
216  OpScaled<vector>(a/3)
217  ),
218  BinaryOpAdd()
219  );
220 
221  tupleInPlaceOp(fPsiIter, InPlaceOpAdvance());
222  }
223 
224  return
225  Tuple2<vector, std::tuple<AreaIntegralType<Types> ...>>
226  (
227  fCutsArea,
228  fCutsAreaPsi
229  );
230 }
231 
232 
233 template<template<class> class FaceValues, class ... Types>
234 Foam::Tuple2<Foam::vector, std::tuple<Types ...>>
236 (
237  const FaceValues<point>& fPs,
238  const point& fPAvg,
239  const std::tuple<FaceValues<Types> ...>& fPsis,
240  const std::tuple<Types ...>& fPsiAvgs
241 )
242 {
243  auto fSumPPsis = faceAreaIntegral(fPs, fPAvg, fPsis, fPsiAvgs);
244 
245  const vector& fArea = fSumPPsis.first();
246  const scalar fMagSqrArea = magSqr(fArea);
247 
248  return
249  Tuple2<vector, std::tuple<Types ...>>
250  (
251  fArea,
252  fMagSqrArea > vSmall
253  ? tupleOp(fSumPPsis.second(), OpPreInner(fArea/fMagSqrArea))
254  : fPsiAvgs
255  );
256 }
257 
258 
259 template<class ... Types>
261 <
262  Foam::vector,
263  std::tuple<Foam::cutPoly::AreaIntegralType<Types> ...>
264 >
266 (
267  const face& f,
268  const vector& fArea,
269  const std::tuple<Types ...>& fPsis,
270  const List<labelPair>& fCuts,
271  const pointField& ps,
272  const std::tuple<const Field<Types>& ...>& pPsis,
273  const scalarField& pAlphas,
274  const scalar isoAlpha,
275  const bool below
276 )
277 {
278  // If there are no cuts return either the entire face or zero, depending on
279  // which side of the iso-surface the face is
280  if (fCuts.size() == 0)
281  {
282  if ((pAlphas[f[0]] < isoAlpha) == below)
283  {
284  return
285  Tuple2<vector, std::tuple<AreaIntegralType<Types> ...>>
286  (
287  fArea,
288  tupleOp(fPsis, OpScaled<vector>(fArea))
289  );
290  }
291  else
292  {
293  return
294  Tuple2<vector, std::tuple<AreaIntegralType<Types> ...>>
295  (
296  vector::zero,
297  std::make_tuple(pTraits<AreaIntegralType<Types>>::zero ...)
298  );
299  }
300  }
301 
302  return
304  (
305  FaceCutValues<vector>(f, fCuts, ps, pAlphas, isoAlpha, below),
306  OpIndirectAverage(f)(ps),
307  tupleOp(pPsis, OpFaceCutValues(f, fCuts, pAlphas, isoAlpha, below)),
308  tupleOp(pPsis, OpIndirectAverage(f))
309  );
310 }
311 
312 
313 template<class ... Types>
314 Foam::Tuple2<Foam::scalar, std::tuple<Types ...>>
316 (
317  const cell& c,
318  const cellEdgeAddressing& cAddr,
319  const point& cPAvg,
320  const std::tuple<Types ...>& cPsiAvgs,
321  const vectorField& fAreas,
322  const pointField& fCentres,
323  const std::tuple<const Field<Types>& ...>& fPsis
324 )
325 {
326  scalar cVolume = 0;
327  std::tuple<Types ...> cVolumePsis(pTraits<Types>::zero ...);
328 
329  forAll(c, cfi)
330  {
331  const scalar pyrVolume =
332  (cAddr.cOwns()[cfi] ? +1 : -1)
333  *(fAreas[c[cfi]] & (fCentres[c[cfi]] - cPAvg))/3;
334 
335  cVolume += pyrVolume;
336  cVolumePsis =
338  (
339  cVolumePsis,
341  (
342  tupleOp
343  (
344  tupleOp(fPsis, OpIndex(c[cfi])),
345  OpScaled<scalar>(scalar(3)/scalar(4)*pyrVolume)
346  ),
347  tupleOp
348  (
349  cPsiAvgs,
350  OpScaled<scalar>(scalar(1)/scalar(4)*pyrVolume)
351  ),
352  BinaryOpAdd()
353  ),
354  BinaryOpAdd()
355  );
356  }
357 
358  return Tuple2<scalar, std::tuple<Types ...>>(cVolume, cVolumePsis);
359 }
360 
361 
362 template<class ... Types>
363 Foam::Tuple2<Foam::scalar, std::tuple<Types ...>>
365 (
366  const cell& c,
367  const cellEdgeAddressing& cAddr,
368  const scalar cVolume,
369  const std::tuple<Types ...>& cPsis,
370  const labelListList& cCuts,
371  const faceUList& fs,
372  const vectorField& fAreas,
373  const pointField& fCentres,
374  const std::tuple<const Field<Types>& ...>& fPsis,
375  const vectorField& fCutAreas,
376  const std::tuple<const Field<Types>& ...>& fCutPsis,
377  const pointField& ps,
378  const std::tuple<const Field<Types>& ...>& pPsis,
379  const scalarField& pAlphas,
380  const scalar isoAlpha,
381  const bool below
382 )
383 {
384  // If there are no cuts return either the entire cell or zero, depending on
385  // which side of the iso-surface the cell is
386  if (cCuts.size() == 0)
387  {
388  if ((pAlphas[fs[c[0]][0]] < isoAlpha) == below)
389  {
390  return
391  Tuple2<scalar, std::tuple<Types ...>>
392  (
393  cVolume,
394  tupleOp(cPsis, OpScaled<scalar>(cVolume))
395  );
396  }
397  else
398  {
399  return
400  Tuple2<scalar, std::tuple<Types ...>>
401  (
402  scalar(0),
403  std::make_tuple(pTraits<Types>::zero ...)
404  );
405  }
406  }
407 
408  // Averages
409  const point cPAvg = OpIndirectAverage(c)(fCentres);
410  auto cPsiAvgs = tupleOp(fPsis, OpIndirectAverage(c));
411 
412  // Face contributions. We use the un-cut face's centroid as the base of the
413  // pyramid formed by the cut face (see !!! below). This is potentially less
414  // exact than using the cut face's centroid, but it is consistent with the
415  // un-cut cell volume calculation. This means if you run this function with
416  // both values of "below" then the result will exactly sum to the volume of
417  // the overall cell. If we used the cut-face's centroid this would not be
418  // the case.
419  auto result =
421  (
422  c,
423  cAddr,
424  cPAvg,
425  cPsiAvgs,
426  fCutAreas,
427  fCentres, // !!!
428  fCutPsis
429  );
430 
431  // Create readably named references to the parts of the result
432  scalar& cCutsVolume = result.first();
433  std::tuple<Types ...>& cCutsVolumePsis = result.second();
434 
435  // Cut contributions
436  const cutPoly::CellCutValues<point> cCutPValues
437  (
438  c,
439  cAddr,
440  cCuts,
441  fs,
442  ps,
443  pAlphas,
444  isoAlpha
445  );
446  const point cCutPAvg = OpIterableAverage()(cCutPValues);
447  auto cCutPsiValues =
448  tupleOp
449  (
450  pPsis,
451  OpCellCutValues
452  (
453  c,
454  cAddr,
455  cCuts,
456  fs,
457  pAlphas,
458  isoAlpha
459  )
460  );
461  auto cCutPsiAvgs = tupleOp(cCutPsiValues, OpIterableAverage());
462 
463  // This method is more exact, as it uses the true centroid of the cell
464  // cut. However, to obtain that centroid we have to divide by the area
465  // magnitude, so this can't be generalised to types that do not support
466  // division.
467  const auto cCutAreaPPsis =
469  (
470  cCutPValues,
471  cCutPAvg,
472  std::tuple_cat(std::make_tuple(cCutPValues), cCutPsiValues),
473  std::tuple_cat(std::make_tuple(cCutPAvg), cCutPsiAvgs)
474  );
475  const vector& cCutArea = cCutAreaPPsis.first();
476  const vector& cCutCentre = std::get<0>(cCutAreaPPsis.second());
477  const auto cCutPsis = tupleTail(cCutAreaPPsis.second());
478 
479  /*
480  // This method is more approximate, as it uses point averages rather
481  // than centroids. This does not involve division, though, so this
482  // could be used with types like polynomials that only support addition
483  // and multiplication.
484  const vector cCutArea =
485  faceAreaIntegral
486  (
487  cCutPValues,
488  cCutPAvg,
489  std::make_tuple(),
490  std::make_tuple()
491  ).first();
492  const point& cCutCentre = cCutPAvg;
493  const auto& cCutPsis = cCutPsiAvgs;
494  */
495 
496  const scalar pyrVolume =
497  (below ? +1 : -1)*(cCutArea & (cCutCentre - cPAvg))/3;
498 
499  cCutsVolume += pyrVolume;
500  cCutsVolumePsis =
502  (
503  cCutsVolumePsis,
505  (
506  tupleOp
507  (
508  cCutPsis,
509  OpScaled<scalar>(scalar(3)/scalar(4)*pyrVolume)
510  ),
511  tupleOp
512  (
513  cPsiAvgs,
514  OpScaled<scalar>(scalar(1)/scalar(4)*pyrVolume)
515  ),
516  BinaryOpAdd()
517  ),
518  BinaryOpAdd()
519  );
520 
521  return result;
522 }
523 
524 
525 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
A zero-sized class without any storage. Used, for example, in HashSet.
Definition: nil.H:59
volScalarField scalarField(fieldObject, mesh)
volVectorField vectorField(fieldObject, mesh)
const dimensionedScalar c
Speed of light in a vacuum.
Tuple2< vector, std::tuple< AreaIntegralType< Types > ... > > faceAreaIntegral(const FaceValues< point > &fPs, const point &fPAvg, const std::tuple< FaceValues< Types > ... > &fPsis, const std::tuple< Types ... > &fPsiAvgs)
Compute the face-area and face-area-integrals of the given properties.
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.
auto tupleOp(const std::tuple< Types ... > &tuple, const Op &op)
Tuple2< scalar, std::tuple< Types ... > > cellCutVolumeIntegral(const cell &c, const cellEdgeAddressing &cAddr, const scalar cVolume, const std::tuple< Types ... > &cPsis, const labelListList &cCuts, const faceUList &fs, const vectorField &fAreas, const pointField &fCentres, const std::tuple< const Field< Types > &... > &fPsis, const vectorField &fCutAreas, const std::tuple< const Field< Types > &... > &fCutPsis, const pointField &ps, const std::tuple< const Field< Types > &... > &pPsis, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the cell-cut-volume and cell-cut-volume-integral.
Tuple2< scalar, std::tuple< Types ... > > cellVolumeIntegral(const cell &c, const cellEdgeAddressing &cAddr, const point &cPAvg, const std::tuple< Types ... > &cPsiAvgs, const vectorField &fAreas, const pointField &fCentres, const std::tuple< const Field< Types > &... > &fPsis)
Compute the cell-volume and cell-volume-integrals of the given properties.
Tuple2< vector, std::tuple< Types ... > > faceAreaAverage(const FaceValues< point > &fPs, const point &fPAvg, const std::tuple< FaceValues< Types > ... > &fPsis, const std::tuple< Types ... > &fPsiAvgs)
Compute the face-area and face-area-averages of the given properties.
auto tupleBinaryOp(const Tuple &tupleA, const Tuple &tupleB, const std::integer_sequence< Int, Is ... > &, const BinaryOp &bop)
void tupleInPlaceOp(Tuple &tuple, const std::integer_sequence< Int, Is ... > &, const Op &op)
auto tupleTail(const std::tuple< Types ... > &tuple)
void tupleInPlaceOp(std::tuple< Types ... > &tuple, const Op &op)
auto tupleBinaryOp(const std::tuple< TypesA ... > &tupleA, const std::tuple< TypesB ... > &tupleB, const BinaryOp &bop)
auto tupleSubset(const Tuple &tuple, const std::integer_sequence< Int, Is ... > &)
Namespace for OpenFOAM.
static const zero Zero
Definition: zero.H:97
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
vector point
Point is a vector.
Definition: point.H:41
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
void magSqr(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
UList< face > faceUList
Definition: faceListFwd.H:39
#define Op(opName, op)
Definition: ops.H:100
labelList f(nPoints)
typename OffsetSequence< Int, Min, std::make_index_sequence< Max - Min > >::type type