Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_Random.H
Go to the documentation of this file.
1#ifndef AMREX_RAND_H
2#define AMREX_RAND_H
3#include <AMReX_Config.H>
4
5#include <AMReX.H>
9#include <limits>
10#include <cmath>
11#include <cstdint>
12
13namespace amrex
14{
16 namespace random_util {
17
23 Real one_to_zero (Real v) noexcept { return (v == Real(1)) ? Real(0) : v; }
24
29 Real zero_to_one (Real v) noexcept { return (v == Real(0)) ? Real(1) : v; }
30
38 Real clamp_below_one (Real v) noexcept
39 {
40 // The constexpr equivalent of std::nextafter(Real(1), Real(0)), which
41 // is not available in device code. That this really is the immediate
42 // predecessor of one follows from the two assertions below: it is less
43 // than one, and the midpoint between it and one already rounds to one,
44 // so no Real lies in between. Tests/Base/Random additionally checks it
45 // against std::nextafter itself on the host.
46 constexpr Real almost_one
47 = Real(1) - Real(0.5)*std::numeric_limits<Real>::epsilon();
48 constexpr Real midpoint
49 = Real(1) - Real(0.25)*std::numeric_limits<Real>::epsilon();
50 static_assert(almost_one < Real(1));
51 static_assert(midpoint == Real(1));
52 // No generator produces NaN, but note this maps it to almost_one
53 // rather than propagating it, since the comparison is false for NaN.
54 return (v < almost_one) ? v : almost_one;
55 }
56
57 }
59
76 Real Random ();
77
80 Real Random (RandomEngine const& random_engine)
81 {
82#if defined (__SYCL_DEVICE_ONLY__)
83 // clamped for the same reason as the host path: the documented [0,1)
84 // of the vendor generator is not a bound we want to depend on
85 mkl::rng::device::uniform<Real> distr;
86 return random_util::clamp_below_one(mkl::rng::device::generate(distr, *random_engine.engine));
87#else
88 // hiprand/curand draw from (0,1]. Relocating the single endpoint
89 // that is out of range converts that to the documented [0,1) exactly,
90 // with no arithmetic. Subtracting from one would also convert the
91 // interval, but not exactly: for a draw below half an ULP of one,
92 // `1 - draw` rounds back up to 1.0, and the subtraction additionally
93 // collapses every value below 0.5 onto a 2^-24 grid.
94#ifdef BL_USE_FLOAT
97 return random_util::one_to_zero(hiprand_uniform(random_engine.rand_state)); ,
98 return random_util::one_to_zero(curand_uniform(random_engine.rand_state));
99 )
100 ))
101#else
104 return random_util::one_to_zero(hiprand_uniform_double(random_engine.rand_state)); ,
105 return random_util::one_to_zero(curand_uniform_double(random_engine.rand_state));
106 )
107 ))
108#endif
110 amrex::ignore_unused(random_engine);
111 return Random();
112 ))
113#endif
114 }
115
171
174 Real RandomPositive (RandomEngine const& random_engine)
175 {
176#if defined (__SYCL_DEVICE_ONLY__)
177 // oneMKL draws from [0,1); relocating the zero endpoint converts that
178 // to (0,1] with no arithmetic, and stays correct even if the
179 // generator reaches its own upper bound, since 1.0 is in range here
180 mkl::rng::device::uniform<Real> distr;
181 return random_util::zero_to_one(mkl::rng::device::generate(distr, *random_engine.engine));
182#else
183 // (0,1] is the native interval of hiprand/curand, so unlike Random()
184 // this needs no endpoint relocated and no clamp: the draw is
185 // returned exactly as the generator produced it.
186#ifdef BL_USE_FLOAT
189 return hiprand_uniform(random_engine.rand_state); ,
190 return curand_uniform(random_engine.rand_state);
191 )
192 ))
193#else
196 return hiprand_uniform_double(random_engine.rand_state); ,
197 return curand_uniform_double(random_engine.rand_state);
198 )
199 ))
200#endif
202 amrex::ignore_unused(random_engine);
203 return RandomPositive();
204 ))
205#endif
206 }
207
216 Real RandomNormal (Real mean, Real stddev);
217
220 Real RandomNormal (Real mean, Real stddev, RandomEngine const& random_engine)
221 {
222#if defined (__SYCL_DEVICE_ONLY__)
223 mkl::rng::device::gaussian<Real> distr(mean, stddev);
224 return mkl::rng::device::generate(distr, *random_engine.engine);
225#else
226#ifdef BL_USE_FLOAT
229 return stddev * hiprand_normal(random_engine.rand_state) + mean; ,
230 return stddev * curand_normal(random_engine.rand_state) + mean;
231 )
232 ))
233#else
236 return stddev * hiprand_normal_double(random_engine.rand_state) + mean; ,
237 return stddev * curand_normal_double(random_engine.rand_state) + mean;
238 )
239 ))
240#endif
242 amrex::ignore_unused(random_engine);
243 return RandomNormal(mean, stddev);
244 ))
245#endif
246 }
247
258 unsigned int RandomPoisson (Real lambda);
259
262 unsigned int RandomPoisson (Real lambda, RandomEngine const& random_engine)
263 {
264#if defined (__SYCL_DEVICE_ONLY__)
265 mkl::rng::device::poisson<unsigned int> distr(lambda);
266 return mkl::rng::device::generate(distr, *random_engine.engine);
267#else
270 return hiprand_poisson(random_engine.rand_state, lambda); ,
271 return curand_poisson(random_engine.rand_state, lambda);
272 )
273 ))
275 amrex::ignore_unused(random_engine);
276 return RandomPoisson(lambda);
277 ))
278#endif
279 }
280
282 namespace random_util {
283
285 Real RandomGamma_alpha_ge_1 (Real alpha, Real beta, RandomEngine const& random_engine)
286 {
287 AMREX_ASSERT(alpha >= 1);
288 AMREX_ASSERT(beta > 0);
289
290 Real x, v, u;
291 Real d = alpha - 1.0_rt / 3.0_rt;
292 Real c = (1.0_rt / 3.0_rt) / std::sqrt(d);
293
294 while (true) {
295 do {
296 x = amrex::RandomNormal(0.0_rt, 1.0_rt, random_engine);
297 v = 1.0_rt + c * x;
298 } while (v <= 0.0_rt);
299
300 v = v * v * v;
301 u = amrex::RandomPositive(random_engine); // std::log(u) below
302
303 if (u < 1.0_rt - 0.0331_rt * x * x * x * x) {
304 break;
305 }
306
307 if (std::log(u) < 0.5_rt * x * x + d * (1.0_rt - v + std::log(v))) {
308 break;
309 }
310 }
311 return beta * d * v;
312 }
313 }
315
328 Real RandomGamma (Real alpha, Real beta);
329
332 Real RandomGamma (Real alpha, Real beta, RandomEngine const& random_engine)
333 {
334 AMREX_ASSERT(alpha > 0);
335 AMREX_ASSERT(beta > 0);
336
338 if (alpha < 1)
339 {
340 Real u = amrex::RandomPositive(random_engine); // std::pow(u, 1/alpha) below
341 return amrex::random_util::RandomGamma_alpha_ge_1(1.0_rt + alpha, beta, random_engine) * std::pow(u, 1.0_rt / alpha);
342 } else {
343 return amrex::random_util::RandomGamma_alpha_ge_1(alpha, beta, random_engine);
344 }
345 ))
346
348 amrex::ignore_unused(random_engine);
349 return RandomGamma(alpha, beta);
350 ))
351 }
352
362 unsigned int Random_int (unsigned int n); // [0,n-1]
363
366 unsigned int Random_int (unsigned int n, RandomEngine const& random_engine)
367 {
368 if (n == 0) { return 0;}
369#if defined(__SYCL_DEVICE_ONLY__)
370 mkl::rng::device::uniform<unsigned int> distr(0,n);
371 return mkl::rng::device::generate(distr, *random_engine.engine);
372#else
374 unsigned int rand;
375 constexpr unsigned int RAND_M = 4294967295; // 2**32-1
376 do {
377 AMREX_HIP_OR_CUDA( rand = hiprand(random_engine.rand_state);,
378 rand = curand(random_engine.rand_state) );
379 } while (rand >= (RAND_M - RAND_M % n));
380 return rand % n;
381 ))
383 amrex::ignore_unused(random_engine);
384 return Random_int(n);
385 ))
386#endif
387 }
388
398 ULong Random_long (ULong n); // [0,n-1]
399
408 void FillRandom (Real* p, Long N);
409
412 void FillRandomNormal (Real* p, Long N, Real mean, Real stddev);
413
415 namespace detail {
416 inline ULong DefaultGpuSeed () {
417 return ParallelDescriptor::MyProc()*1234567ULL + 12345ULL;
418 }
419 }
421
435 void InitRandom (ULong cpu_seed, int nprocs=ParallelDescriptor::NProcs(),
436 ULong gpu_seed = detail::DefaultGpuSeed());
437
439 void ResetRandomSeed (ULong cpu_seed, ULong gpu_seed = detail::DefaultGpuSeed());
440
449 void SaveRandomState (std::ostream& os);
450
458 void RestoreRandomState (std::istream& is, int nthreads_old, int nstep_old);
459
470 void UniqueRandomSubset (Vector<int> &uSet, int setSize, int poolSize,
471 bool printSet = false);
472
474}
475
476#endif
Runtime initialization/finalization helpers and global diagnostics.
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
#define AMREX_HIP_OR_CUDA(a, b)
Definition AMReX_GpuControl.H:17
#define AMREX_IF_ON_DEVICE(CODE)
Definition AMReX_GpuQualifiers.H:56
#define AMREX_IF_ON_HOST(CODE)
Definition AMReX_GpuQualifiers.H:58
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
GpuArray< Real, 3 > beta
Definition AMReX_MLEBNodeFDLaplacian.cpp:1099
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:80
amrex_ulong ULong
Unsigned integer type guaranteed to be wider than unsigned int.
Definition AMReX_INT.H:32
amrex_long Long
Definition AMReX_INT.H:30
int MyProc() noexcept
Definition AMReX_ParallelDescriptor.H:128
int NProcs() noexcept
Definition AMReX_ParallelDescriptor.H:255
void InitRandom(ULong cpu_seed, int nprocs, ULong gpu_seed)
Set the seed of the random number generator.
Definition AMReX_Random.cpp:112
unsigned int Random_int(unsigned int n)
Generates one pseudorandom unsigned integer which is uniformly distributed on [0,n-1]-interval for ea...
Definition AMReX_Random.cpp:186
Real Random()
Generate a psuedo-random real from uniform distribution.
Definition AMReX_Random.cpp:155
Real RandomPositive()
Generate a pseudo-random real from uniform distribution, excluding zero.
Definition AMReX_Random.cpp:162
Real RandomNormal(Real mean, Real stddev)
Generate a psuedo-random real from a normal distribution.
Definition AMReX_Random.cpp:139
ULong Random_long(ULong n)
Generates one pseudorandom unsigned long which is uniformly distributed on [0,n-1]-interval for each ...
Definition AMReX_Random.cpp:194
void ResetRandomSeed(ULong cpu_seed, ULong gpu_seed)
Definition AMReX_Random.cpp:263
void UniqueRandomSubset(Vector< int > &uSet, int setSize, int poolSize, bool printSet)
Create a unique subset of random numbers from a pool of integers in the range [0, poolSize - 1] the s...
Definition AMReX_Random.cpp:241
unsigned int RandomPoisson(Real lambda)
Generate a psuedo-random integer from a Poisson distribution.
Definition AMReX_Random.cpp:172
void SaveRandomState(std::ostream &os)
Save host random state.
Definition AMReX_Random.cpp:203
void RestoreRandomState(std::istream &is, int nthreads_old, int nstep_old)
Restore host random state saved by SaveRandomState.
Definition AMReX_Random.cpp:211
Real RandomGamma(Real alpha, Real beta)
Generate a psuedo-random floating point number from the Gamma distribution.
Definition AMReX_Random.cpp:179
Definition AMReX_Amr.cpp:50
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:259
void FillRandomNormal(MultiFab &mf, int scomp, int ncomp, Real mean, Real stddev)
Fill MultiFab with random numbers from normal distribution.
Definition AMReX_MultiFabUtil.cpp:1246
void FillRandom(MultiFab &mf, int scomp, int ncomp)
Fill MultiFab with random numbers from uniform distribution.
Definition AMReX_MultiFabUtil.cpp:1233
void DeallocateRandomSeedDevArray()
Definition AMReX_Random.cpp:269
Definition AMReX_RandomEngine.H:72
randState_t * rand_state
Definition AMReX_RandomEngine.H:73