general.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2019 OpenFOAM Foundation
9  Copyright (C) 2016-2021 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "general.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 namespace distributionModels
37 {
38  defineTypeNameAndDebug(general, 0);
39  addToRunTimeSelectionTable(distributionModel, general, dictionary);
40 }
41 }
42 
43 
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 
46 void Foam::distributionModels::general::initialise()
47 {
48  static scalar eps = ROOTVSMALL;
49 
50  integral_.setSize(nEntries_);
51 
52  // Fill out the integral table (x, P(x<=0)) and calculate mean
53  // For density function: P(x<=0) = int f(x) and mean = int x*f(x)
54  // For cumulative function: mean = int 1-P(x<=0) = maxValue_ - int P(x<=0)
55  integral_[0] = 0;
56 
57  for (label i = 1; i < nEntries_; ++i)
58  {
59  scalar k = (xy_[i][1] - xy_[i-1][1])/(xy_[i][0] - xy_[i-1][0] + eps);
60  scalar d = xy_[i-1][1] - k*xy_[i-1][0];
61  scalar y1 = xy_[i][0]*(0.5*k*xy_[i][0] + d);
62  scalar y0 = xy_[i-1][0]*(0.5*k*xy_[i-1][0] + d);
63  scalar area = y1 - y0;
64 
65  if (cumulative_)
66  {
67  integral_[i] = xy_[i][1];
68  meanValue_ += area;
69  }
70  else
71  {
72  integral_[i] = area + integral_[i-1];
73 
74  y1 = sqr(xy_[i][0])*(1.0/3.0*k*xy_[i][0] + 0.5*d);
75  y0 = sqr(xy_[i-1][0])*(1.0/3.0*k*xy_[i-1][0] + 0.5*d);
76  meanValue_ += y1 - y0;
77  }
78  }
79 
80  // normalize the distribution
81  const scalar sumArea = integral_.last();
82 
83  for (label i = 0; i < nEntries_; ++i)
84  {
85  xy_[i][1] /= sumArea + eps;
86  integral_[i] /= sumArea + eps;
87  }
88 
89  meanValue_ /= sumArea + eps;
90  meanValue_ = cumulative_ ? (maxValue_ - meanValue_) : meanValue_;
91 }
92 
93 
94 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
95 
97 (
98  const dictionary& dict,
99  Random& rndGen
100 )
101 :
102  distributionModel(typeName, dict, rndGen),
103  xy_(distributionModelDict_.lookup("distribution")),
104  nEntries_(xy_.size()),
105  meanValue_(0),
106  integral_(nEntries_),
107  cumulative_(distributionModelDict_.getOrDefault("cumulative", false))
108 {
109  minValue_ = xy_[0][0];
110  maxValue_ = xy_[nEntries_-1][0];
111 
112  check();
113 
114  // Additional sanity checks
115  if (cumulative_ && xy_[0][1] != 0)
116  {
118  << type() << "distribution: "
119  << "Elements in the second column for cumulative "
120  << "distribution functions must start from zero." << nl
121  << "First element = " << xy_[0][1]
122  << exit(FatalError);
123  }
124 
125  for (label i = 0; i < nEntries_; ++i)
126  {
127  if (i > 0 && xy_[i][0] <= xy_[i-1][0])
128  {
130  << type() << "distribution: "
131  << "Elements in the first column must "
132  << "be specified in an ascending order." << nl
133  << "Please see the row i = " << i << nl
134  << "xy[i-1] = " << xy_[i-1] << nl
135  << "xy[i] = " << xy_[i]
136  << exit(FatalError);
137  }
138 
139  if (xy_[i][0] < 0 || xy_[i][1] < 0)
140  {
142  << type() << "distribution: "
143  << "Input pairs cannot contain any negative element." << nl
144  << "Please see the row i = " << i << nl
145  << "xy[i] = " << xy_[i]
146  << exit(FatalError);
147  }
148 
149  if (cumulative_ && i > 0 && xy_[i][1] < xy_[i-1][1])
150  {
152  << type() << "distribution: "
153  << "Elements in the second column for cumulative "
154  << "distribution functions must be non-decreasing." << nl
155  << "Please see the row i = " << i << nl
156  << "xy[i-1] = " << xy_[i-1] << nl
157  << "xy[i] = " << xy_[i]
158  << exit(FatalError);
159  }
160  }
161 
162  initialise();
163 }
164 
165 
167 (
168  const UList<scalar>& sampleData,
169  const scalar binWidth,
170  Random& rndGen
171 )
172 :
173  distributionModel(typeName, dictionary::null, rndGen),
174  xy_(),
175  nEntries_(0),
176  meanValue_(0),
177  integral_(),
178  cumulative_(false)
179 {
180  minValue_ = GREAT;
181  maxValue_ = -GREAT;
182  forAll(sampleData, i)
183  {
184  minValue_ = min(minValue_, sampleData[i]);
185  maxValue_ = max(maxValue_, sampleData[i]);
186  }
187 
188  label bin0 = floor(minValue_/binWidth);
189  label bin1 = ceil(maxValue_/binWidth);
190  nEntries_ = bin1 - bin0;
191 
192  if (nEntries_ == 0)
193  {
195  << "Data cannot be binned - zero bins generated" << nl
196  << " Bin width : " << binWidth << nl
197  << " Sample data : " << sampleData
198  << endl;
199 
200  return;
201  }
202 
203  xy_.setSize(nEntries_);
204 
205  // Populate bin boundaries and initialise occurrences
206  for (label bini = 0; bini < nEntries_; ++bini)
207  {
208  xy_[bini][0] = (bin0 + bini)*binWidth;
209  xy_[bini][1] = 0;
210  }
211 
212  // Populate occurrences
213  forAll(sampleData, i)
214  {
215  label bini = floor(sampleData[i]/binWidth) - bin0;
216  xy_[bini][1]++;
217  }
218 
219  initialise();
220 }
221 
222 
224 :
226  xy_(p.xy_),
227  nEntries_(p.nEntries_),
228  meanValue_(p.meanValue_),
229  integral_(p.integral_),
230  cumulative_(p.cumulative_)
231 {}
232 
233 
234 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
235 
237 {
238  const scalar u = rndGen_.sample01<scalar>();
239 
240  // Find the interval where u is in the table
241  label n = 1;
242  while (integral_[n] <= u)
243  {
244  n++;
245  }
246 
247  const scalar k = (xy_[n][1] - xy_[n-1][1])/(xy_[n][0] - xy_[n-1][0]);
248  const scalar d = xy_[n-1][1] - k*xy_[n-1][0];
249 
250  if (cumulative_)
251  {
252  return (u - d)/k;
253  }
254 
255  const scalar alpha =
256  u + xy_[n-1][0]*(0.5*k*xy_[n-1][0] + d) - integral_[n-1];
257 
258  // If k is small it is a linear equation, otherwise it is of second order
259  if (mag(k) > SMALL)
260  {
261  const scalar p = 2.0*d/k;
262  const scalar q = -2.0*alpha/k;
263  const scalar sqrtEr = sqrt(0.25*p*p - q);
264 
265  const scalar x1 = -0.5*p + sqrtEr;
266  const scalar x2 = -0.5*p - sqrtEr;
267  if ((x1 >= xy_[n-1][0]) && (x1 <= xy_[n][0]))
268  {
269  return x1;
270  }
271  else
272  {
273  return x2;
274  }
275  }
276 
277  return alpha/d;
278 }
279 
282 {
283  return meanValue_;
284 }
285 
286 
288 {
289 // distributionModel::readData(is);
290  is >> xy_;
291  initialise();
292 }
293 
294 
296 {
297 // distributionModel::writeData(os);
298  os << xy_;
299 }
300 
301 
303 (
304  const word& dictName
305 ) const
306 {
307  // dictionary dict = distributionModel::writeDict(dictName);
309  dict.add("x", x());
310  dict.add("y", y());
311 
312  return dict;
313 }
314 
315 
317 {
318  // distributionModel::readDict(dict);
319  List<scalar> x(dict.lookup("x"));
320  List<scalar> y(dict.lookup("y"));
321 
322  xy_.setSize(x.size());
323  forAll(xy_, i)
324  {
325  xy_[i][0] = x[i];
326  xy_[i][1] = y[i];
327  }
328 
329  initialise();
330 }
331 
332 
335 {
336  auto tx = tmp<scalarField>::New(xy_.size());
337  auto& x = tx.ref();
338  forAll(xy_, i)
339  {
340  x[i] = xy_[i][0];
341  }
342 
343  return tx;
344 }
345 
346 
349 {
350  auto ty = tmp<scalarField>::New(xy_.size());
351  auto& y = ty.ref();
352  forAll(xy_, i)
353  {
354  y[i] = xy_[i][1];
355  }
356 
357  return ty;
358 }
359 
360 
361 Foam::Ostream& Foam::operator<<
362 (
363  Ostream& os,
364  const distributionModels::general& b
365 )
366 {
368 
369  b.writeData(os);
370  return os;
371 }
372 
373 
374 Foam::Istream& Foam::operator>>(Istream& is, distributionModels::general& b)
375 {
376  is.check(FUNCTION_NAME);
377 
378  b.readData(is);
379  return is;
380 }
381 
382 
383 // ************************************************************************* //
virtual scalar sample() const
Sample the distribution.
Definition: general.C:229
dictionary dict
scalar maxValue_
Maximum of the distribution.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
virtual bool check(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:45
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensionedSymmTensor sqr(const dimensionedVector &dv)
General relative velocity model.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Random rndGen
Definition: createFields.H:23
const word dictName("faMeshDefinition")
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
addToRunTimeSelectionTable(distributionModel, binned, dictionary)
dimensionedScalar y0(const dimensionedScalar &ds)
label k
Boltzmann constant.
Lookup type of boundary radiation properties.
Definition: lookup.H:57
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
scalar y
defineTypeNameAndDebug(binned, 0)
void setSize(const label n)
Alias for resize()
Definition: List.H:316
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
const wordList area
Standard area field types (scalar, vector, tensor, etc)
A class for handling words, derived from Foam::string.
Definition: word.H:63
virtual void check() const
Check that the distribution model is valid.
Istream & operator>>(Istream &, directionInfo &)
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
virtual scalar meanValue() const
Return the arithmetic mean of the distribution data.
Definition: general.C:274
scalar minValue_
Minimum of the distribution.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
dimensionedScalar y1(const dimensionedScalar &ds)
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
Random number generator.
Definition: Random.H:55
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
T & last()
Access last element of the list, position [size()-1].
Definition: UList.H:867
virtual tmp< scalarField > x() const
Bin boundaries.
Definition: general.C:327
virtual tmp< scalarField > y() const
Probabilities.
Definition: general.C:341
virtual void writeData(Ostream &os) const
Write data to stream.
Definition: general.C:288
general(const dictionary &dict, Random &rndGen)
Construct from components.
Definition: general.C:90
#define WarningInFunction
Report a warning using Foam::Warning.
virtual void readData(Istream &os)
Read data from stream.
Definition: general.C:280
A library of runtime-selectable doubly-truncated probability distribution models. Returns random samp...
label n
virtual dictionary writeDict(const word &dictName) const
Write data in dictionary format.
Definition: general.C:296
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
virtual void readDict(const dictionary &dict)
Read data from dictionary.
Definition: general.C:309
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
Namespace for OpenFOAM.