unintegrable.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) 2023-2024 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 "unintegrable.H"
27 #include "quadraticEqn.H"
28 #include "SubField.H"
30 
31 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
32 
34 (
35  const scalarField& x,
36  const scalarField& y
37 )
38 {
39  tmp<scalarField> tResult(new scalarField(x.size()));
40  scalarField& result = tResult.ref();
41 
42  result[0] = 0;
43 
44  for (label i = 1; i < x.size(); ++ i)
45  {
46  result[i] = result[i - 1] + (x[i] - x[i - 1])*(y[i] + y[i - 1])/2;
47  }
48 
49  return tResult;
50 }
51 
52 
54 (
55  const scalarField& x,
56  const scalarField& y
57 )
58 {
59  tmp<scalarField> tResult(new scalarField(x.size()));
60  scalarField& result = tResult.ref();
61 
62  result[0] = 0;
63 
64  for (label i = 1; i < x.size(); ++ i)
65  {
66  const scalar x0 = x[i - 1], x1 = x[i];
67  const scalar y0 = y[i - 1], y1 = y[i];
68 
69  result[i] =
70  result[i - 1] + (x1 - x0)*(2*x0*y0 + x0*y1 + x1*y0 + 2*x1*y1)/6;
71  }
72 
73  return tResult;
74 }
75 
76 
79 (
80  const scalarField& xStar,
81  const label e,
82  const scalarField& yStar,
83  const scalarField& x
84 )
85 {
86  tmp<scalarField> tResult(new scalarField(x.size()));
87  scalarField& result = tResult.ref();
88 
89  label i = 0;
90 
91  while (i < x.size() && x[i] < xStar[0])
92  {
93  result[i] = 0;
94  i ++;
95  }
96 
97  scalar integral_PDFxPowE_0_j = 0;
98 
99  for (label iStar = 0; iStar < xStar.size() - 1; ++ iStar)
100  {
101  const scalar xPowE1_j = integerPow(xStar[iStar], e + 1);
102 
103  auto integral_xPowE1_j_x = [&](const scalar x)
104  {
105  const scalar xPowE1_i = integerPow(x, e + 1);
106 
107  const scalar integral_xPowE_j_x =
108  e + 1 == 0
109  ? log(x/xStar[iStar])
110  : (xPowE1_i - xPowE1_j)/(e + 1);
111  const scalar integral_xPowE1_j_x =
112  e + 2 == 0
113  ? log(x/xStar[iStar])
114  : (xPowE1_i*x - xPowE1_j*xStar[iStar])/(e + 2);
115 
116  return
117  yStar[iStar]*integral_xPowE_j_x
118  + (yStar[iStar + 1] - yStar[iStar])
119  /(xStar[iStar + 1] - xStar[iStar])
120  *(integral_xPowE1_j_x - xStar[iStar]*integral_xPowE_j_x);
121  };
122 
123  while (i < x.size() && x[i] < xStar[iStar + 1])
124  {
125  result[i] = integral_PDFxPowE_0_j + integral_xPowE1_j_x(x[i]);
126 
127  i ++;
128  }
129 
130  integral_PDFxPowE_0_j += integral_xPowE1_j_x(xStar[iStar + 1]);
131  }
132 
133  while (i < x.size())
134  {
135  result[i] = integral_PDFxPowE_0_j;
136  i ++;
137  }
138 
139  return tResult;
140 }
141 
142 
144 (
145  const Pair<scalar>& x,
146  const Pair<scalar>& Phi,
147  const scalar s
148 )
149 {
150  // Do a linear interpolation
151  scalar f = (s - Phi[0])/(Phi[1] - Phi[0]);
152 
153  // Interpolate
154  return (1 - f)*x[0] + f*x[1];
155 }
156 
157 
159 (
160  const Pair<scalar>& x,
161  const Pair<scalar>& phi,
162  const Pair<scalar>& Phi,
163  const scalar s
164 )
165 {
166  // Do a linear interpolation
167  scalar f = (s - Phi[0])/(Phi[1] - Phi[0]);
168 
169  // Attempt to improve by doing a quadratic interpolation
170  const scalar a = (x[1] - x[0])*(phi[1] - phi[0])/2;
171  const scalar b = Phi[1] - Phi[0] - a;
172  const scalar c = Phi[0] - s;
173  const quadraticEqn eqn(a, b, c);
174  const Roots<2> roots = eqn.roots();
175  forAll(roots, rooti)
176  {
177  if
178  (
179  roots.type(rooti) == rootType::real
180  && roots[rooti] > 0
181  && roots[rooti] < 1
182  )
183  {
184  f = roots[rooti];
185  }
186  }
187 
188  // Interpolate
189  return (1 - f)*x[0] + f*x[1];
190 }
191 
192 
194 (
195  const scalarField& x,
196  const scalarField& Phi,
197  const scalar s
198 )
199 {
200  // Find the interval
201  label i = 0;
202  for (; i < x.size() && Phi[i + 1] < s; ++ i);
203 
204  // Sample
205  return
206  sampleInterval
207  (
208  {x[i], x[i + 1]},
209  {Phi[i], Phi[i + 1]},
210  s
211  );
212 }
213 
214 
216 (
217  const scalarField& x,
218  const scalarField& phi,
219  const scalarField& Phi,
220  const scalar s
221 )
222 {
223  // Find the interval
224  label i = 0;
225  for (; i < x.size() && Phi[i + 1] < s; ++ i);
226 
227  // Sample
228  return
229  sampleInterval
230  (
231  {x[i], x[i + 1]},
232  {phi[i], phi[i + 1]},
233  {Phi[i], Phi[i + 1]},
234  s
235  );
236 }
237 
238 
239 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
240 
241 const Foam::scalarField& Foam::distributions::unintegrable::x() const
242 {
243  if (xPtr_.valid()) return xPtr_();
244 
245  xPtr_.set(new scalarField(n_));
246  scalarField& x = xPtr_();
247 
248  forAll(x, i)
249  {
250  const scalar f = scalar(i)/(n_ + 1);
251  x[i] = (1 - f)*this->min() + f*this->max();
252  }
253 
254  static const scalar tol = sqrt(sqrt(pow3(small)));
255 
256  for (label iter = 0; iter < ceil(std::log2(1/tol)); ++ iter)
257  {
258  const scalarField phi(this->phi(this->q(), x));
259  const scalarField Phi(integrate(x, phi));
260 
261  const scalar dPhi = (Phi.last() - Phi.first())/(n_ - 1);
262 
263  if (distribution::debug)
264  {
265  scalar error = -vGreat;
266  for (label i = 0; i < n_ - 1; ++ i)
267  {
268  error = Foam::max(error, (1 - (Phi[i + 1] - Phi[i])/dPhi)/n_);
269  }
270 
271  Info<< indent << "Interval spacing iteration #" << iter
272  << ", error=" << error << endl;
273  }
274 
275  const scalarField xPrev(x);
276 
277  x.first() = this->min();
278 
279  for (label i0 = 0, i = 1; i0 < n_ - 1; ++ i0)
280  {
281  while (Phi[i0 + 1] > i*dPhi)
282  {
283  const scalar xNext =
284  sampleInterval
285  (
286  {xPrev[i0], xPrev[i0 + 1]},
287  {phi[i0], phi[i0 + 1]},
288  {Phi[i0], Phi[i0 + 1]},
289  i*dPhi
290  );
291 
292  x[i] = (x[i] + xNext)/2;
293 
294  i ++;
295  }
296  }
297 
298  x.last() = this->max();
299  }
300 
301  return x;
302 }
303 
304 
305 const Foam::scalarField& Foam::distributions::unintegrable::PDF() const
306 {
307  if (PDFPtr_.valid()) return PDFPtr_();
308 
309  const Pair<scalar> Phi01 = this->Phi01();
310 
311  PDFPtr_.set((phi(this->q(), x())/(Phi01[1] - Phi01[0])).ptr());
312 
313  return PDFPtr_();
314 }
315 
316 
317 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
318 
320 (
321  const label q,
322  const scalarField& x
323 ) const
324 {
325  return integrate(x, phi(q, x));
326 }
327 
328 
330 (
331  const label q
332 ) const
333 {
334  const scalarField Phi(this->Phi(this->q(), x()));
335  return Pair<scalar>(Phi.first(), Phi.last());
336 }
337 
338 
341 {
342  if (Phi01Ptr_.valid()) return Phi01Ptr_();
343 
344  Phi01Ptr_.set(new Pair<scalar>(Phi01(this->q())));
345 
346  return Phi01Ptr_();
347 }
348 
349 
350 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
351 
353 (
354  const word& name,
355  const unitConversion& units,
356  const dictionary& dict,
357  const label sampleQ,
359 )
360 :
361  distribution(name, units, dict, sampleQ, std::move(rndGen)),
362  n_((1<<dict.lookupOrDefault<label>("level", 16)) + 1)
363 {}
364 
365 
367 (
368  const label Q,
369  const label sampleQ,
371  const label n
372 )
373 :
374  distribution(Q, sampleQ, std::move(rndGen)),
375  n_(n)
376 {}
377 
378 
380 (
381  const unintegrable& d,
382  const label sampleQ
383 )
384 :
385  distribution(d, sampleQ),
386  n_(d.n_)
387 {
388  // Copy the data over if it exists and if the sampling moment is the same,
389  // otherwise leave it to be re-generated
390  if (q() == d.q())
391  {
392  if (d.xPtr_.valid())
393  {
394  xPtr_.set(new scalarField(d.xPtr_()));
395  }
396  if (d.Phi01Ptr_.valid())
397  {
398  Phi01Ptr_.set(new Pair<scalar>(d.Phi01Ptr_()));
399  }
400  if (d.PDFPtr_.valid())
401  {
402  PDFPtr_.set(new scalarField(d.PDFPtr_()));
403  }
404  }
405 }
406 
407 
408 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
409 
411 {}
412 
413 
414 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
415 
417 {
418  const scalar s = this->rndGen_.template sample01<scalar>();
419 
420  const scalar dCDF = scalar(1)/(n_ - 1);
421  const label samplei = floor(s/dCDF);
422 
423  return
424  sampleInterval
425  (
426  {x()[samplei], x()[samplei + 1]},
427  {PDF()[samplei], PDF()[samplei + 1]},
428  {samplei*dCDF, (samplei + 1)*dCDF},
429  s
430  );
431 }
432 
433 
435 {
436  const Pair<scalar> Phi01 = this->Phi01();
437  const scalarField Mu(Phi(this->q() + 1, x()));
438  const Pair<scalar> Mu01(Mu.first(), Mu.last());
439  return (Mu01[1] - Mu01[0])/(Phi01[1] - Phi01[0]);
440 }
441 
442 
445 (
446  const scalarField& x,
447  const label e,
448  const bool
449 ) const
450 {
451  return interpolateIntegrateXPow(this->x(), e, this->PDF(), x);
452 }
453 
454 
456 (
457  Ostream& os,
458  const unitConversion& units
459 ) const
460 {
462 
463  // Recover the level
464  label n = n_ - 1, level = 0;
465  while (n >>= 1) ++ level;
466 
467  writeEntryIfDifferent(os, "level", label(16), level);
468 }
469 
470 
473 {
474  const scalarField phi(this->phi(this->q(), x));
475  const Pair<scalar> Phi01 = this->Phi01();
476  return this->clipPDF(x, phi/(Phi01[1] - Phi01[0]));
477 }
478 
479 
480 // ************************************************************************* //
scalar y
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
Macros for easy insertion into run-time selection tables.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
Templated storage for the roots of polynomial equations, plus flags to indicate the nature of the roo...
Definition: Roots.H:67
void type(const direction i, const rootType t)
Set the type of the i-th root.
Definition: RootsI.H:120
T & first()
Return the first element of the list.
Definition: UListI.H:114
T & last()
Return the last element of the list.
Definition: UListI.H:128
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
Base class for statistical distributions.
Definition: distribution.H:76
label q() const
Return the effective distribution size exponent.
Definition: distribution.H:107
virtual void write(Ostream &os, const unitConversion &units) const
Write to a stream.
Definition: distribution.C:153
Base class for distributions that do not have a closed integral form for the cumulative density funct...
Definition: unintegrable.H:58
virtual tmp< scalarField > Phi(const label q, const scalarField &x) const
Return values of the un-normalised CDF for the given size exponent.
Definition: unintegrable.C:320
virtual tmp< scalarField > integralPDFxPow(const scalarField &x, const label e, const bool consistent=false) const
Return the integral of the PDF multiplied by an integer power of x.
Definition: unintegrable.C:445
virtual scalar sample() const
Sample the distribution.
Definition: unintegrable.C:416
static tmp< scalarField > integrate(const scalarField &x, const scalarField &y)
Integrate the values y with respect to the coordinates x.
Definition: unintegrable.C:34
unintegrable(const word &name, const unitConversion &units, const dictionary &dict, const label sampleQ, randomGenerator &&rndGen)
Construct from a dictionary.
Definition: unintegrable.C:353
virtual tmp< scalarField > plotPDF(const scalarField &x) const
Return values to plot the probability density function.
Definition: unintegrable.C:472
virtual void write(Ostream &os, const unitConversion &units) const
Write to a stream.
Definition: unintegrable.C:456
virtual ~unintegrable()
Destructor.
Definition: unintegrable.C:410
static tmp< scalarField > integrateX(const scalarField &x, const scalarField &y)
Integrate the values x*y with respect to the coordinates x.
Definition: unintegrable.C:54
const Pair< scalar > & Phi01() const
Access cached values of the un-normalised CDF at the minimum and.
Definition: unintegrable.C:340
virtual scalar mean() const
Return the mean value.
Definition: unintegrable.C:434
static scalar sampleInterval(const Pair< scalar > &x, const Pair< scalar > &Phi, const scalar s)
Sample an interval, given the interval's bounding x-coordinates,.
Definition: unintegrable.C:144
static tmp< scalarField > interpolateIntegrateXPow(const scalarField &xStar, const label e, const scalarField &yStar, const scalarField &x)
Integrate the values x^e*y with respect to the coordinates x,.
Definition: unintegrable.C:79
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:71
Quadratic equation of the form a*x^2 + b*x + c = 0.
Definition: quadraticEqn.H:52
Roots< 2 > roots(const bool real=false) const
Get the roots.
Definition: quadraticEqn.C:31
Random number generator.
A class for managing temporary objects.
Definition: tmp.H:55
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:197
Unit conversion structure. Contains the associated dimensions and the multiplier with which to conver...
A class for handling words, derived from string.
Definition: word.H:62
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
volScalarField & b
Definition: createFields.H:27
const dimensionedScalar c
Speed of light in a vacuum.
const doubleScalar e
Definition: doubleScalar.H:106
void writeEntryIfDifferent(Ostream &os, const word &entryName, const EntryType &value1, const EntryType &value2)
Helper function to write the keyword and entry only if the.
label log2(label i)
Return the log base 2 by successive bit-shifting of the given label.
Definition: label.H:79
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
dimensionedScalar y0(const dimensionedScalar &ds)
messageStream Info
scalar integerPow(const scalar x, const label e)
Compute the power of the number x to the integer e.
Definition: scalarI.H:30
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
dimensionedScalar log(const dimensionedScalar &ds)
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
const HashTable< unitConversion > & units()
Get the table of unit conversions.
dimensionedScalar y1(const dimensionedScalar &ds)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
void pow3(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
void sqrt(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:228
labelList f(nPoints)
dictionary dict
randomGenerator rndGen(653213)