chombo-discharge
CD_RandomImplem.H
Go to the documentation of this file.
1 /* chombo-discharge
2  * Copyright © 2021 SINTEF Energy Research.
3  * Please refer to Copyright.txt and LICENSE in the chombo-discharge root directory.
4  */
5 
12 #ifndef CD_RandomImplem_H
13 #define CD_RandomImplem_H
14 
15 // Std includes
16 #include <chrono>
17 #include <omp.h>
18 
19 // Chombo includes
20 #include <SPMD.H>
21 #include <ParmParse.H>
22 
23 // Our includes
24 #include <CD_Random.H>
25 #include <CD_NamespaceHeader.H>
26 
27 inline void
29 {
30  if (!s_seeded) {
31  ParmParse pp("Random");
32 
33  if (pp.contains("seed")) {
34  int seed;
35  pp.get("seed", seed);
36  if (seed < 0) {
38  }
39  else {
41  }
42  }
43  else {
44  Random::setSeed(0);
45  }
46 
47  s_seeded = true;
48  }
49 }
50 
51 inline void
52 Random::setSeed(const int a_seed)
53 {
54 #ifdef CH_MPI
55 #ifdef _OPENMP
56 #pragma omp parallel
57  {
58  const int seed = a_seed + procID() * omp_get_num_threads() + omp_get_thread_num();
59 
60  s_rng = std::mt19937_64(seed);
61  }
62 #else
63  const int seed = a_seed + procID();
64 
65  s_rng = std::mt19937_64(seed);
66 #endif
67 #else
68 #ifdef _OPENMP
69 #pragma omp parallel
70  {
71  const int seed = a_seed + omp_get_thread_num();
72 
73  s_rng = std::mt19937_64(seed);
74  }
75 #else
76  const int seed = a_seed;
77 
78  s_rng = std::mt19937_64(seed);
79 #endif
80 #endif
81 
82  s_seeded = true;
83 }
84 
85 inline void
87 {
88  int seed = std::chrono::system_clock::now().time_since_epoch().count();
89 
90  // Special hook for MPI -- master rank broadcasts the seed and everyone increments by their processor ID.
91 #ifdef CH_MPI
92  MPI_Bcast(&seed, 1, MPI_INT, 0, Chombo_MPI::comm);
93 #endif
94 
96 }
97 
98 template <typename T, typename>
99 inline T
100 Random::getPoisson(const Real a_mean)
101 {
102  CH_assert(s_seeded);
103 
104  T ret = (T)0;
105 
106  if (a_mean < 250.0) {
107  std::poisson_distribution<T> poisson(a_mean);
108 
109  ret = poisson(s_rng);
110  }
111  else {
112  std::normal_distribution<Real> normal(a_mean, sqrt(a_mean));
113 
114  ret = (T)std::max(normal(s_rng), (Real)0.0);
115  }
116 
117  return ret;
118 }
119 
120 template <typename T, typename>
121 inline T
122 Random::getBinomial(const T a_N, const Real a_p) noexcept
123 {
124  CH_assert(s_seeded);
125 
126  T ret = 0;
127 
128  const bool useNormalApprox = (a_N > (T)9.0 * ((1.0 - a_p) / a_p)) && (a_N > (T)9.0 * a_p / (1.0 - a_p));
129 
130  if (useNormalApprox) {
131  const Real mean = a_N * a_p;
132 
133  std::normal_distribution<Real> normalDist(mean, mean * (1.0 - a_p));
134 
135  ret = (T)std::max(normalDist(s_rng), (Real)0.0);
136  }
137  else {
138  std::binomial_distribution<T> binomDist(a_N, a_p);
139 
140  ret = binomDist(s_rng);
141  }
142 
143  return ret;
144 }
145 
146 inline Real
148 {
149  CH_assert(s_seeded);
150 
151  return s_uniform01(s_rng);
152 }
153 
154 inline Real
156 {
157  CH_assert(s_seeded);
158 
159  return s_uniform11(s_rng);
160 }
161 
162 inline Real
164 {
165  CH_assert(s_seeded);
166 
167  return s_normal01(s_rng);
168 }
169 
170 inline RealVect
172 {
173  CH_assert(s_seeded);
174 
175  constexpr Real safety = 1.E-12;
176 
177 #if CH_SPACEDIM == 2
178  Real x1 = 2.0;
179  Real x2 = 2.0;
180  Real r = x1 * x1 + x2 * x2;
181  while (r >= 1.0 || r < safety) {
184  r = x1 * x1 + x2 * x2;
185  }
186 
187  return RealVect(x1, x2) / sqrt(r);
188 #elif CH_SPACEDIM == 3
189  Real x1 = 2.0;
190  Real x2 = 2.0;
191  Real r = x1 * x1 + x2 * x2;
192  while (r >= 1.0 || r < safety) {
195  r = x1 * x1 + x2 * x2;
196  }
197 
198  const Real x = 2 * x1 * sqrt(1 - r);
199  const Real y = 2 * x2 * sqrt(1 - r);
200  const Real z = 1 - 2 * r;
201 
202  return RealVect(x, y, z);
203 #endif
204 }
205 
206 template <typename T>
207 inline Real
208 Random::get(T& a_distribution)
209 {
210  CH_assert(s_seeded);
211 
212  return a_distribution(s_rng);
213 }
214 
215 template <typename T>
216 inline size_t
217 Random::getDiscrete(T& a_distribution)
218 {
219  CH_assert(s_seeded);
220 
221  return a_distribution(s_rng);
222 }
223 
224 inline RealVect
225 Random::randomPosition(const RealVect a_cellPos,
226  const RealVect a_lo,
227  const RealVect a_hi,
228  const RealVect a_bndryCentroid,
229  const RealVect a_bndryNormal,
230  const Real a_dx,
231  const Real a_kappa) noexcept
232 {
233 
234  RealVect pos;
235 
236  if (a_kappa < 1.0) { // Rejection sampling.
237  pos = Random::randomPosition(a_lo, a_hi, a_bndryCentroid, a_bndryNormal);
238  }
239  else { // Regular cell. Get a position.
240  pos = Random::randomPosition(a_lo, a_hi);
241  }
242 
243  // Convert from unit cell coordinates to physical coordinates.
244  pos = a_cellPos + pos * a_dx;
245 
246  return pos;
247 }
248 
249 inline RealVect
250 Random::randomPosition(const RealVect a_lo,
251  const RealVect a_hi,
252  const RealVect a_bndryCentroid,
253  const RealVect a_bndryNormal) noexcept
254 {
255 
256  // Draw a position.
257  RealVect pos = Random::randomPosition(a_lo, a_hi);
258  bool valid = (pos - a_bndryCentroid).dotProduct(a_bndryNormal) >= 0.0;
259 
260  // Rejectino sampling.
261  while (!valid) {
262  pos = Random::randomPosition(a_lo, a_hi);
263  valid = (pos - a_bndryCentroid).dotProduct(a_bndryNormal) >= 0.0;
264  }
265 
266  return pos;
267 }
268 
269 inline RealVect
270 Random::randomPosition(const RealVect a_lo, const RealVect a_hi) noexcept
271 {
272  RealVect pos = RealVect::Zero;
273 
274  for (int dir = 0; dir < SpaceDim; dir++) {
275  pos[dir] = a_lo[dir] + Random::getUniformReal01() * (a_hi[dir] - a_lo[dir]);
276  }
277 
278  return pos;
279 }
280 
281 #include <CD_NamespaceFooter.H>
282 
283 #endif
File containing some useful static methods related to random number generation.
static Real get(T &a_distribution)
For getting a random number from a user-supplied distribution. T must be a distribution for which we ...
Definition: CD_RandomImplem.H:208
static void setRandomSeed()
Set a random RNG seed.
Definition: CD_RandomImplem.H:86
static RealVect getDirection()
Get a random direction in space.
Definition: CD_RandomImplem.H:171
static Real getUniformReal11()
Get a uniform real number on the interval [-1,1].
Definition: CD_RandomImplem.H:155
static size_t getDiscrete(T &a_distribution)
For getting a random number from a user-supplied distribution. T must be a distribution for which we ...
Definition: CD_RandomImplem.H:217
static Real getUniformReal01()
Get a uniform real number on the interval [0,1].
Definition: CD_RandomImplem.H:147
static Real getNormal01()
Get a number from a normal distribution centered on zero and variance 1.
Definition: CD_RandomImplem.H:163
static void seed()
Seed the RNG.
Definition: CD_RandomImplem.H:28
static void setSeed(const int a_seed)
Set the RNG seed.
Definition: CD_RandomImplem.H:52
static T getPoisson(const Real a_mean)
Get Poisson distributed number.
Definition: CD_RandomImplem.H:100
static T getBinomial(const T a_N, const Real a_p) noexcept
Get Poisson distributed number.
Definition: CD_RandomImplem.H:122
static RealVect randomPosition(const RealVect a_lo, const RealVect a_hi) noexcept
Return a random position in the cube (a_lo, a_hi);.
Definition: CD_RandomImplem.H:270
Real max(const Real &a_input) noexcept
Get the maximum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition: CD_ParallelOpsImplem.H:176