tabulatedCumulative.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-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 "tabulatedCumulative.H"
27 #include "unintegrable.H"
28 #include "SubField.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35 namespace distributions
36 {
39 }
40 }
41 
42 
43 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
44 
46 (
47  const unitConversion& defaultUnits,
48  const dictionary& dict,
49  const label sampleQ,
51 )
52 :
54  (
55  typeName,
56  defaultUnits,
57  dict,
58  sampleQ,
59  std::move(rndGen)
60  ),
61  reader_
62  (
63  TableReader<scalar>::New(word::null, {defaultUnits, unitAny}, dict)
64  )
65 {
67  reader_->read({defaultUnits, unitAny}, dict, "distribution");
68 
69  // Checks
70  if (values.first().second() != 0)
71  {
73  << typeName << ": The cumulative distribution function does not "
74  << "start at zero" << abort(FatalIOError);
75  }
76 
77  for (label i = 1; i < values.size(); ++ i)
78  {
79  if (values[i].first() - values[i - 1].first() < 0)
80  {
82  << typeName << ": The cumulative distribution function is not "
83  << "in order" << abort(FatalIOError);
84  }
85 
86  if (values[i].second() - values[i - 1].second() < 0)
87  {
89  << typeName << ": The cumulative distribution function is not "
90  << "monotonic" << abort(FatalIOError);
91  }
92  }
93 
94  // Copy the coordinates
95  x_.resize(values.size());
96  forAll(values, i)
97  {
98  x_[i] = values[i].first();
99  }
100 
101  // Set the CDF. Copy if q == 0. Re-integrated if q != 0.
102  CDF_.resize(values.size());
103  CDF_[0] = 0;
104  for (label i = 1; i < values.size(); ++ i)
105  {
106  CDF_[i] =
107  CDF_[i - 1]
108  + integerPow((x_[i] + x_[i - 1])/2, q())
109  *(values[i].second() - values[i - 1].second());
110  }
111  CDF_ /= CDF_.last();
112 
113  // Compute the PDF. Equals the gradient of the CDF. Associated with the
114  // intervals, so the field is one element shorter than the coordinates and
115  // the CDF.
116  PDF_.resize(values.size() - 1);
117  forAll(PDF_, i)
118  {
119  PDF_[i] = (CDF_[i + 1] - CDF_[i])/(x_[i + 1] - x_[i]);
120  }
121 
122  // More checks
123  validateBounds(dict);
124  if (q() != 0) validatePositive(dict);
125 }
126 
127 
129 (
130  const tabulatedCumulative& d,
131  const label sampleQ
132 )
133 :
135  reader_(d.reader_, false),
136  x_(d.x_),
137  PDF_(d.PDF_),
138  CDF_(d.CDF_)
139 {
140  // If Q is the same then a copy is sufficient
141  if (q() == d.q()) return;
142 
143  // Re-integrate the CDF
144  CDF_[0] = 0;
145  for (label i = 1; i < x_.size(); ++ i)
146  {
147  CDF_[i] =
148  CDF_[i - 1]
149  + integerPow((d.x_[i] + d.x_[i - 1])/2, q() - d.q())
150  *(d.CDF_[i] - d.CDF_[i - 1]);
151  }
152  CDF_ /= CDF_.last();
153 
154  // Re-compute the PDF
155  forAll(PDF_, i)
156  {
157  PDF_[i] = (CDF_[i + 1] - CDF_[i])/(x_[i + 1] - x_[i]);
158  }
159 }
160 
161 
162 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
163 
165 {}
166 
167 
168 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
169 
171 {
172  return unintegrable::sample(x_, CDF_, rndGen_.sample01<scalar>());
173 }
174 
175 
177 {
178  return x_.first();
179 }
180 
181 
183 {
184  return x_.last();
185 }
186 
187 
189 {
190  const scalarField x(this->plotX(-1));
191  return unintegrable::integrate(x, x*plotPDF(x))->last();
192 }
193 
194 
197 (
198  const scalarField& x,
199  const label e,
200  const bool
201 ) const
202 {
203  const scalarField& xStar = x_;
204  const scalarField& yStar = PDF_;
205 
206  tmp<scalarField> tResult(new scalarField(x.size()));
207  scalarField& result = tResult.ref();
208 
209  label i = 0;
210 
211  while (i < x.size() && x[i] < xStar[0])
212  {
213  result[i] = 0;
214  i ++;
215  }
216 
217  scalar integral_PDFxPowE_0_j = 0;
218 
219  for (label iStar = 0; iStar < xStar.size() - 1; ++ iStar)
220  {
221  const scalar xPowE1_j = integerPow(xStar[iStar], e + 1);
222 
223  auto integral_xPowE1_j_x = [&](const scalar x)
224  {
225  const scalar xPowE1_i = integerPow(x, e + 1);
226 
227  const scalar integral_xPowE_j_x =
228  e + 1 == 0
229  ? log(x/xStar[iStar])
230  : (xPowE1_i - xPowE1_j)/(e + 1);
231 
232  return yStar[iStar]*integral_xPowE_j_x;
233  };
234 
235  while (i < x.size() && x[i] < xStar[iStar + 1])
236  {
237  result[i] = integral_PDFxPowE_0_j + integral_xPowE1_j_x(x[i]);
238 
239  i ++;
240  }
241 
242  integral_PDFxPowE_0_j += integral_xPowE1_j_x(xStar[iStar + 1]);
243  }
244 
245  while (i < x.size())
246  {
247  result[i] = integral_PDFxPowE_0_j;
248  i ++;
249  }
250 
251  return tResult;
252 
253 }
254 
255 
257 (
258  Ostream& os,
259  const unitConversion& units
260 ) const
261 {
263 
264  // Recover the CDF
265  scalarField CDF(CDF_.size());
266  CDF[0] = 0;
267  for (label i = 1; i < CDF_.size(); ++ i)
268  {
269  CDF[i] =
270  CDF[i - 1]
271  + integerPow((x_[i] + x_[i - 1])/2, -q())
272  *(CDF_[i] - CDF_[i - 1]);
273  }
274 
275  // Normalise the CDF
276  CDF /= CDF.last();
277 
278  // Construct and write the values
279  List<Tuple2<scalar, scalar>> values(CDF_.size());
280  forAll(values, i)
281  {
282  values[i].first() = x_[i];
283  values[i].second() = CDF[i];
284  }
285  reader_->write(os, {units, unitAny}, values, "distribution");
286 }
287 
288 
291 {
292  const scalar x0 = min(), x1 = max(), d = 0.1*(x1 - x0);
293 
294  tmp<scalarField> tResult(new scalarField(2*x_.size() + 2));
295  scalarField& result = tResult.ref();
296 
297  result[0] = Foam::max(x0 - d, q() < 0 ? x0/2 : rootVSmall);
298 
299  forAll(x_, i)
300  {
301  result[2*i + 1] = result[2*i + 2] = x_[i];
302  }
303 
304  result[2*x_.size() + 1] = x1 + d;
305 
306  return tResult;
307 }
308 
309 
312 {
313  tmp<scalarField> tResult(new scalarField(2*PDF_.size() + 4));
314  scalarField& result = tResult.ref();
315 
316  result[0] = result[1] = 0;
317 
318  forAll(PDF_, i)
319  {
320  result[2*i + 2] = result[2*i + 3] = PDF_[i];
321  }
322 
323  result[2*PDF_.size() + 2] = result[2*PDF_.size() + 3] = 0;
324 
325  return tResult;
326 }
327 
328 
329 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
Macros for easy insertion into run-time selection tables.
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
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
Base class to read table data for tables.
Definition: TableReader.H:51
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
Distribution in which the cumulative distribution function is given as a table of values.
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.
virtual scalar min() const
Return the minimum value.
virtual scalar sample() const
Sample the distribution.
tabulatedCumulative(const unitConversion &units, const dictionary &dict, const label sampleQ, randomGenerator &&rndGen)
Construct from a dictionary.
virtual tmp< scalarField > plotPDF(const scalarField &x) const
Return values to plot the probability density function.
virtual void write(Ostream &os, const unitConversion &units) const
Write to a stream.
virtual scalar max() const
Return the maximum value.
virtual scalar mean() const
Return the mean value.
virtual tmp< scalarField > plotX(const label n) const
Return coordinates to plot across the range of the distribution.
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
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
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
autoPtr< CompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const viscosity &viscosity)
defineTypeNameAndDebug(exponential, 0)
addToRunTimeSelectionTable(distribution, exponential, dictionary)
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
Namespace for OpenFOAM.
const doubleScalar e
Definition: doubleScalar.H:106
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
const unitConversion unitAny
errorManip< error > abort(error &err)
Definition: errorManip.H:131
scalar integerPow(const scalar x, const label e)
Compute the power of the number x to the integer e.
Definition: scalarI.H:30
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
dimensionedScalar log(const dimensionedScalar &ds)
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
const HashTable< unitConversion > & units()
Get the table of unit conversions.
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
IOerror FatalIOError
dictionary dict
randomGenerator rndGen(653213)