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-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 
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 unitSet& 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, scalar>::New
64  (
65  word::null,
66  {defaultUnits, units::any},
67  dict
68  )
69  )
70 {
72  reader_->read({defaultUnits, units::any}, dict, "distribution");
73 
74  // Checks
75  if (values.first().second() != 0)
76  {
78  << typeName << ": The cumulative distribution function does not "
79  << "start at zero" << abort(FatalIOError);
80  }
81 
82  for (label i = 1; i < values.size(); ++ i)
83  {
84  if (values[i].first() - values[i - 1].first() < 0)
85  {
87  << typeName << ": The cumulative distribution function is not "
88  << "in order" << abort(FatalIOError);
89  }
90 
91  if (values[i].second() - values[i - 1].second() < 0)
92  {
94  << typeName << ": The cumulative distribution function is not "
95  << "monotonic" << abort(FatalIOError);
96  }
97  }
98 
99  // Copy the coordinates
100  x_.resize(values.size());
101  forAll(values, i)
102  {
103  x_[i] = values[i].first();
104  }
105 
106  // Set the CDF. Copy if q == 0. Re-integrated if q != 0.
107  CDF_.resize(values.size());
108  CDF_[0] = 0;
109  for (label i = 1; i < values.size(); ++ i)
110  {
111  CDF_[i] =
112  CDF_[i - 1]
113  + integerPow((x_[i] + x_[i - 1])/2, q())
114  *(values[i].second() - values[i - 1].second());
115  }
116  CDF_ /= CDF_.last();
117 
118  // Compute the PDF. Equals the gradient of the CDF. Associated with the
119  // intervals, so the field is one element shorter than the coordinates and
120  // the CDF.
121  PDF_.resize(values.size() - 1);
122  forAll(PDF_, i)
123  {
124  PDF_[i] = (CDF_[i + 1] - CDF_[i])/(x_[i + 1] - x_[i]);
125  }
126 
127  // More checks
128  validateBounds(dict);
129  if (q() != 0) validatePositive(dict);
130 }
131 
132 
134 (
135  const tabulatedCumulative& d,
136  const label sampleQ
137 )
138 :
140  reader_(d.reader_, false),
141  x_(d.x_),
142  PDF_(d.PDF_),
143  CDF_(d.CDF_)
144 {
145  // If Q is the same then a copy is sufficient
146  if (q() == d.q()) return;
147 
148  // Re-integrate the CDF
149  CDF_[0] = 0;
150  for (label i = 1; i < x_.size(); ++ i)
151  {
152  CDF_[i] =
153  CDF_[i - 1]
154  + integerPow((d.x_[i] + d.x_[i - 1])/2, q() - d.q())
155  *(d.CDF_[i] - d.CDF_[i - 1]);
156  }
157  CDF_ /= CDF_.last();
158 
159  // Re-compute the PDF
160  forAll(PDF_, i)
161  {
162  PDF_[i] = (CDF_[i + 1] - CDF_[i])/(x_[i + 1] - x_[i]);
163  }
164 }
165 
166 
167 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
168 
170 {}
171 
172 
173 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
174 
176 {
177  return unintegrable::sample(x_, CDF_, rndGen_.sample01<scalar>());
178 }
179 
180 
182 {
183  return x_.first();
184 }
185 
186 
188 {
189  return x_.last();
190 }
191 
192 
194 {
195  const scalarField x(this->plotX(-1));
196  return unintegrable::integrate(x, x*plotPDF(x))->last();
197 }
198 
199 
202 (
203  const scalarField& x,
204  const label e,
205  const bool
206 ) const
207 {
208  const scalarField& xStar = x_;
209  const scalarField& yStar = PDF_;
210 
211  tmp<scalarField> tResult(new scalarField(x.size()));
212  scalarField& result = tResult.ref();
213 
214  label i = 0;
215 
216  while (i < x.size() && x[i] < xStar[0])
217  {
218  result[i] = 0;
219  i ++;
220  }
221 
222  scalar integral_PDFxPowE_0_j = 0;
223 
224  for (label iStar = 0; iStar < xStar.size() - 1; ++ iStar)
225  {
226  const scalar xPowE1_j = integerPow(xStar[iStar], e + 1);
227 
228  auto integral_xPowE1_j_x = [&](const scalar x)
229  {
230  const scalar xPowE1_i = integerPow(x, e + 1);
231 
232  const scalar integral_xPowE_j_x =
233  e + 1 == 0
234  ? log(x/xStar[iStar])
235  : (xPowE1_i - xPowE1_j)/(e + 1);
236 
237  return yStar[iStar]*integral_xPowE_j_x;
238  };
239 
240  while (i < x.size() && x[i] < xStar[iStar + 1])
241  {
242  result[i] = integral_PDFxPowE_0_j + integral_xPowE1_j_x(x[i]);
243 
244  i ++;
245  }
246 
247  integral_PDFxPowE_0_j += integral_xPowE1_j_x(xStar[iStar + 1]);
248  }
249 
250  while (i < x.size())
251  {
252  result[i] = integral_PDFxPowE_0_j;
253  i ++;
254  }
255 
256  return tResult;
257 
258 }
259 
260 
262 (
263  Ostream& os,
264  const unitSet& units
265 ) const
266 {
268 
269  // Recover the CDF
270  scalarField CDF(CDF_.size());
271  CDF[0] = 0;
272  for (label i = 1; i < CDF_.size(); ++ i)
273  {
274  CDF[i] =
275  CDF[i - 1]
276  + integerPow((x_[i] + x_[i - 1])/2, -q())
277  *(CDF_[i] - CDF_[i - 1]);
278  }
279 
280  // Normalise the CDF
281  CDF /= CDF.last();
282 
283  // Construct and write the values
284  List<Tuple2<scalar, scalar>> values(CDF_.size());
285  forAll(values, i)
286  {
287  values[i].first() = x_[i];
288  values[i].second() = CDF[i];
289  }
290  reader_->write(os, {units, units::any}, values, "distribution");
291 }
292 
293 
296 {
297  const scalar x0 = min(), x1 = max(), d = 0.1*(x1 - x0);
298 
299  tmp<scalarField> tResult(new scalarField(2*x_.size() + 2));
300  scalarField& result = tResult.ref();
301 
302  result[0] = Foam::max(x0 - d, q() < 0 ? x0/2 : rootVSmall);
303 
304  forAll(x_, i)
305  {
306  result[2*i + 1] = result[2*i + 2] = x_[i];
307  }
308 
309  result[2*x_.size() + 1] = x1 + d;
310 
311  return tResult;
312 }
313 
314 
317 {
318  tmp<scalarField> tResult(new scalarField(2*PDF_.size() + 4));
319  scalarField& result = tResult.ref();
320 
321  result[0] = result[1] = 0;
322 
323  forAll(PDF_, i)
324  {
325  result[2*i + 2] = result[2*i + 3] = PDF_[i];
326  }
327 
328  result[2*PDF_.size() + 2] = result[2*PDF_.size() + 3] = 0;
329 
330  return tResult;
331 }
332 
333 
334 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
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.
tabulatedCumulative(const unitSet &units, const dictionary &dict, const label sampleQ, randomGenerator &&rndGen)
Construct from a dictionary.
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.
virtual tmp< scalarField > plotPDF(const scalarField &x) const
Return values to plot the probability density function.
virtual void write(Ostream &os, const unitSet &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
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
Unit conversion structure. Contains the associated dimensions and the multiplier with which to conver...
Definition: unitSet.H:68
A class for handling words, derived from string.
Definition: word.H:63
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
defineTypeNameAndDebug(exponential, 0)
addToRunTimeSelectionTable(distribution, exponential, dictionary)
const unitSet any
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
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
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
IOerror FatalIOError
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)
dictionary dict
randomGenerator rndGen(653213)