chombo-discharge
Loading...
Searching...
No Matches
CD_RandomImplem.H
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2021-2026 SINTEF Energy Research
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
13#ifndef CD_RANDOMIMPLEM_H
14#define CD_RANDOMIMPLEM_H
15
16// Std includes
17#include <chrono>
18#ifdef _OPENMP
19#include <omp.h>
20#endif
21
22// Chombo includes
23#include <SPMD.H>
24#include <CH_Timer.H>
25#include <ParmParse.H>
26
27// Our includes
28#include <CD_Random.H>
29#include <CD_NamespaceHeader.H>
30
31inline void
33{
34 if (!s_seeded) {
35 ParmParse pp("Random");
36
37 if (pp.contains("seed")) {
38 int seed;
39 pp.get("seed", seed);
40 if (seed < 0) {
42 }
43 else {
45 }
46 }
47 else {
49 }
50
51 s_seeded = true;
52 }
53}
54
55inline void
56Random::setSeed(const int a_seed)
57{
58#ifdef CH_MPI
59#ifdef _OPENMP
60#pragma omp parallel
61 {
62 const int seed = a_seed + procID() * omp_get_num_threads() + omp_get_thread_num();
63
64 s_rng = std::mt19937_64(seed);
65 }
66#else
67 const int seed = a_seed + procID();
68
69 s_rng = std::mt19937_64(seed);
70#endif
71#else
72#ifdef _OPENMP
73#pragma omp parallel
74 {
75 const int seed = a_seed + omp_get_thread_num();
76
77 s_rng = std::mt19937_64(seed);
78 }
79#else
80 const int seed = a_seed;
81
82 s_rng = std::mt19937_64(seed);
83#endif
84#endif
85
86 s_seeded = true;
87}
88
89inline void
91{
92 auto seed = static_cast<int>(std::chrono::system_clock::now().time_since_epoch().count());
93
94 // Special hook for MPI -- master rank broadcasts the seed and everyone increments by their processor ID.
95#ifdef CH_MPI
96 MPI_Bcast(&seed, 1, MPI_INT, 0, Chombo_MPI::comm);
97#endif
98
100}
101
102template <typename T, typename>
103inline T
104Random::getPoisson(const Real a_mean)
105{
106 CH_assert(s_seeded);
107
108 T ret = (T)0;
109
110 if (a_mean <= 0.0) {
111 return ret;
112 }
113
114 if (a_mean < 250.0) {
115 std::poisson_distribution<T> poisson(a_mean);
116
117 ret = poisson(s_rng);
118 }
119 else {
120 // Normal approximation for large means. The continuous draw is rounded to the nearest integer;
121 // truncating it would bias every sample by -1/2.
122 std::normal_distribution<Real> normal(a_mean, sqrt(a_mean));
123
124 ret = (T)llround(std::max(normal(s_rng), (Real)0.0));
125 }
126
127 return ret;
128}
129
130template <typename T, typename>
131inline T
132Random::getBinomial(const T a_N, const Real a_p) noexcept
133{
134
135 CH_assert(s_seeded);
136
137 T ret = 0;
138
139 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));
140
141 if (useNormalApprox) {
142 const Real mean = a_N * a_p;
143
144 std::normal_distribution<Real> normalDist(mean, mean * (1.0 - a_p));
145
146 ret = (T)std::max(normalDist(s_rng), (Real)0.0);
147 }
148 else {
149 std::binomial_distribution<T> binomDist(a_N, a_p);
150
151 ret = binomDist(s_rng);
152 }
153
154 return ret;
155}
156
157inline Real
159{
160 CH_assert(s_seeded);
161
162 return s_uniform01(s_rng);
163}
164
165inline Real
167{
168 CH_assert(s_seeded);
169
170 return s_uniform11(s_rng);
171}
172
173inline Real
175{
176 CH_assert(s_seeded);
177
178 return s_normal01(s_rng);
179}
180
181inline RealVect
183{
184 CH_assert(s_seeded);
185
186 constexpr Real safety = 1.E-12;
187
188#if CH_SPACEDIM == 2
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 return RealVect(x1, x2) / sqrt(r);
199#elif CH_SPACEDIM == 3
200 Real x1 = 2.0;
201 Real x2 = 2.0;
202 Real r = x1 * x1 + x2 * x2;
203 while (r >= 1.0 || r < safety) {
206 r = x1 * x1 + x2 * x2;
207 }
208
209 const Real x = 2 * x1 * sqrt(1 - r);
210 const Real y = 2 * x2 * sqrt(1 - r);
211 const Real z = 1 - 2 * r;
212
213 return RealVect(x, y, z);
214#endif
215}
216
217template <typename T>
218inline Real
219Random::get(T& a_distribution)
220{
221 CH_assert(s_seeded);
222
223 return a_distribution(s_rng);
224}
225
226template <typename T>
227inline size_t
228Random::getDiscrete(T& a_distribution)
229{
230 CH_assert(s_seeded);
231
232 return a_distribution(s_rng);
233}
234
235inline RealVect
236Random::randomPosition(const RealVect& a_cellPos,
237 const RealVect& a_lo,
238 const RealVect& a_hi,
239 const RealVect& a_bndryCentroid,
240 const RealVect& a_bndryNormal,
241 const Real a_dx,
242 const Real a_kappa) noexcept
243{
244
245 RealVect pos;
246
247 if (a_kappa < 1.0) { // Rejection sampling.
248 pos = Random::randomPosition(a_lo, a_hi, a_bndryCentroid, a_bndryNormal);
249 }
250 else { // Regular cell. Get a position.
251 pos = Random::randomPosition(a_lo, a_hi);
252 }
253
254 // Convert from unit cell coordinates to physical coordinates.
255 pos = a_cellPos + pos * a_dx;
256
257 return pos;
258}
259
260inline RealVect
261Random::randomPosition(const RealVect& a_lo,
262 const RealVect& a_hi,
263 const RealVect& a_bndryCentroid,
264 const RealVect& a_bndryNormal) noexcept
265{
266 constexpr int maxIter = 100;
267
268 RealVect pos = Random::randomPosition(a_lo, a_hi);
269 bool valid = (pos - a_bndryCentroid).dotProduct(a_bndryNormal) >= 0.0;
270
271 for (int iter = 0; !valid && iter < maxIter; ++iter) {
272 pos = Random::randomPosition(a_lo, a_hi);
273 valid = (pos - a_bndryCentroid).dotProduct(a_bndryNormal) >= 0.0;
274 }
275
276 // Fall back to the boundary centroid for degenerate cut-cells where the
277 // valid half-space and the bounding box do not overlap.
278 if (!valid) {
279 pos = a_bndryCentroid;
280 }
281
282 return pos;
283}
284
285inline RealVect
286Random::randomPosition(const RealVect& a_lo, const RealVect& a_hi) noexcept
287{
288
289 RealVect pos = RealVect::Zero;
290
291 for (int dir = 0; dir < SpaceDim; dir++) {
292 pos[dir] = a_lo[dir] + Random::getUniformReal01() * (a_hi[dir] - a_lo[dir]);
293 }
294
295 return pos;
296}
297
298#include <CD_NamespaceFooter.H>
299
300#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:219
static void setRandomSeed()
Set a random RNG seed.
Definition CD_RandomImplem.H:90
static RealVect getDirection()
Get a random direction in space.
Definition CD_RandomImplem.H:182
static Real getUniformReal11()
Get a uniform real number on the interval [-1,1].
Definition CD_RandomImplem.H:166
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:228
static Real getUniformReal01()
Get a uniform real number on the interval [0,1].
Definition CD_RandomImplem.H:158
static Real getNormal01()
Get a number from a normal distribution centered on zero and variance 1.
Definition CD_RandomImplem.H:174
static void seed()
Seed the RNG.
Definition CD_RandomImplem.H:32
static void setSeed(const int a_seed)
Set the RNG seed.
Definition CD_RandomImplem.H:56
static T getPoisson(const Real a_mean)
Get Poisson distributed number.
Definition CD_RandomImplem.H:104
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:286
static T getBinomial(const T a_N, const Real a_p) noexcept
Get Poisson distributed number.
Definition CD_RandomImplem.H:132