faceTemplates.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-2023 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 "face.H"
27 #include "vectorAndError.H"
28 
29 // * * * * * * * * * * * * * * * Static Functions * * * * * * * * * * * * * //
30 
31 template<class PointField>
33 {
34  // If the face is a triangle, do a direct calculation
35  if (ps.size() == 3)
36  {
37  return (1.0/2.0)*((ps[1] - ps[0])^(ps[2] - ps[0]));
38  }
39 
40  // For more complex faces, decompose into triangles ...
41 
42  // Compute an estimate of the centre as the average of the points
43  point pAvg = Zero;
44  forAll(ps, pi)
45  {
46  pAvg += ps[pi];
47  }
48  pAvg /= ps.size();
49 
50  // Compute the face area normal and unit normal by summing up the
51  // normals of the triangles formed by connecting each edge to the
52  // point average.
53  vector sumA = Zero;
54  forAll(ps, pi)
55  {
56  const point& p = ps[pi];
57  const point& pNext = ps[ps.fcIndex(pi)];
58 
59  const vector a = (pNext - p)^(pAvg - p);
60 
61  sumA += a;
62  }
63 
64  return (1.0/2.0)*sumA;
65 }
66 
67 
68 template<class PointField>
70 {
71  // The overhead associated with additionally calculating the area is small,
72  // and the optimiser may even remove the additional expense all together,
73  // so just use the face::areaAndCentre function and discard the area
74  return areaAndCentre(ps).second();
75 }
76 
77 
78 template<class PointField>
80 (
81  const PointField& ps
82 )
83 {
84  // If the face is a triangle, do a direct calculation
85  if (ps.size() == 3)
86  {
87  return
89  (
90  (1.0/2.0)*((ps[1] - ps[0])^(ps[2] - ps[0])),
91  (1.0/3.0)*(ps[0] + ps[1] + ps[2])
92  );
93  }
94 
95  // For more complex faces, decompose into triangles ...
96 
97  // Compute an estimate of the centre as the average of the points
98  point pAvg = Zero;
99  forAll(ps, pi)
100  {
101  pAvg += ps[pi];
102  }
103  pAvg /= ps.size();
104 
105  // Compute the face area normal and unit normal by summing up the
106  // normals of the triangles formed by connecting each edge to the
107  // point average.
108  vector sumA = Zero;
109  forAll(ps, pi)
110  {
111  const point& p = ps[pi];
112  const point& pNext = ps[ps.fcIndex(pi)];
113 
114  const vector a = (pNext - p)^(pAvg - p);
115 
116  sumA += a;
117  }
118  const vector sumAHat = normalised(sumA);
119 
120  // Compute the area-weighted sum of the triangle centres. Note use
121  // the triangle area projected in the direction of the face normal
122  // as the weight, *not* the triangle area magnitude. Only the
123  // former makes the calculation independent of the initial estimate.
124  scalar sumAn = 0;
125  vector sumAnc = Zero;
126  forAll(ps, pi)
127  {
128  const point& p = ps[pi];
129  const point& pNext = ps[ps.fcIndex(pi)];
130 
131  const vector a = (pNext - p)^(pAvg - p);
132  const vector c = p + pNext + pAvg;
133 
134  const scalar an = a & sumAHat;
135 
136  sumAn += an;
137  sumAnc += an*c;
138  }
139 
140  // Complete calculating centres and areas. If the face is too small
141  // for the sums to be reliably divided then just set the centre to
142  // the point average.
143  return
145  (
146  (1.0/2.0)*sumA,
147  sumAn > vSmall ? (1.0/3.0)*sumAnc/sumAn : pAvg
148  );
149 }
150 
151 
152 template<class PointField>
154 (
155  const PointField& ps
156 )
157 {
158  // If the face is a triangle then there are no stability concerns, so use
159  // the un-stabilised algorithm
160  if (ps.size() == 3)
161  {
162  return areaAndCentre(ps);
163  }
164 
165  // As face::areaAndCentre
166  point pAvg = Zero;
167  forAll(ps, pi)
168  {
169  pAvg += ps[pi];
170  }
171  pAvg /= ps.size();
172 
173  // As face::areaAndCentre, but also track round-off error in the calculation
174  vectorAndError sumA(Zero);
175  forAll(ps, pi)
176  {
177  const point& p = ps[pi];
178  const point& pNext = ps[ps.fcIndex(pi)];
179 
180  const vectorAndError a =
181  (vectorAndError(pNext) - vectorAndError(p))
182  ^(vectorAndError(pAvg) - vectorAndError(p));
183 
184  sumA += a;
185  }
186  const vectorAndError sumAHat = normalised(sumA);
187 
188  // As face::areaAndCentre, but also track round-off error in the calculation
189  scalarAndError sumAn = 0;
190  vector sumAnc(Zero);
191  forAll(ps, pi)
192  {
193  const point& p = ps[pi];
194  const point& pNext = ps[ps.fcIndex(pi)];
195 
196  const vectorAndError a =
197  (vectorAndError(pNext) - vectorAndError(p))
198  ^(vectorAndError(pAvg) - vectorAndError(p));
199  const point c = p + pNext + pAvg;
200 
201  const scalarAndError an = a & sumAHat;
202 
203  sumAn += an;
204  sumAnc += an.value*c;
205  }
206 
207  // As face::areaAndCentre, but blend the calculated centroid and the point
208  // average by the fraction of error in the calculated normal area
209  Tuple2<vector, point> result((1.0/2.0)*sumA.value(), pAvg);
210  if (sumAn.value >= vSmall)
211  {
212  const scalar f = min(max(sumAn.error/sumAn.value, 0), 1);
213  result.second() = (1 - f)*(1.0/3.0)*sumAnc/sumAn.value + f*pAvg;
214  }
215  return result;
216 }
217 
218 
219 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
220 
221 template<class Type>
223 (
224  const pointField& ps,
225  const Field<Type>& fld
226 ) const
227 {
228  // If the face is a triangle, do a direct calculation
229  if (size() == 3)
230  {
231  return
232  (1.0/3.0)
233  *(
234  fld[operator[](0)]
235  + fld[operator[](1)]
236  + fld[operator[](2)]
237  );
238  }
239 
240  // For more complex faces, decompose into triangles ...
241 
242  // Compute an estimate of the centre and the field average as the average
243  // of the point values
244  point pAvg = Zero;
245  Type fldAvg = Zero;
246  forAll(*this, pi)
247  {
248  pAvg += ps[operator[](pi)];
249  fldAvg += fld[operator[](pi)];
250  }
251  pAvg /= size();
252  fldAvg /= size();
253 
254  // Compute the face area normal and unit normal by summing up the
255  // normals of the triangles formed by connecting each edge to the
256  // point average.
257  vector sumA = Zero;
258  forAll(*this, pi)
259  {
260  const point& p = ps[operator[](pi)];
261  const point& pNext = ps[operator[](fcIndex(pi))];
262 
263  const vector a = (pNext - p)^(pAvg - p);
264 
265  sumA += a;
266  }
267  const vector sumAHat = normalised(sumA);
268 
269  // Compute the area-weighted sum of the average field values on each
270  // triangle
271  scalar sumAn = 0;
272  Type sumAnf = Zero;
273  forAll(*this, pi)
274  {
275  const point& p = ps[operator[](pi)];
276  const point& pNext = ps[operator[](fcIndex(pi))];
277 
278  const vector a = (pNext - p)^(pAvg - p);
279  const Type f =
280  fld[operator[](pi)]
281  + fld[operator[](fcIndex(pi))]
282  + fldAvg;
283 
284  const scalar an = a & sumAHat;
285 
286  sumAn += an;
287  sumAnf += an*f;
288  }
289 
290  // Complete calculating the average. If the face is too small for the sums
291  // to be reliably divided then just set the average to the initial
292  // estimate.
293  if (sumAn > vSmall)
294  {
295  return (1.0/3.0)*sumAnf/sumAn;
296  }
297  else
298  {
299  return fldAvg;
300  }
301 }
302 
303 
304 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
const Type2 & second() const
Return second.
Definition: Tuple2.H:131
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
static vector centre(const PointField &ps)
Return centre point given face points.
Type average(const pointField &, const Field< Type > &) const
Calculate average value at centroid of face.
static Tuple2< vector, point > areaAndCentreStabilised(const PointField &)
Return vector area and centre point given face points. Stabilised.
static vector area(const PointField &ps)
Return vector area given face points.
static Tuple2< vector, point > areaAndCentre(const PointField &)
Return vector area and centre point given face points.
Class to encapsulate a scalar value and an associated round-off error. The error is tracked through o...
scalar error
The error.
scalar value
The value.
Vector of scalarAndError-s.
Vector< scalar > value() const
Return the value.
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const dimensionedScalar c
Speed of light in a vacuum.
static const zero Zero
Definition: zero.H:97
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensionSet normalised(const dimensionSet &)
Definition: dimensionSet.C:510
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
labelList f(nPoints)
volScalarField & p