Documentation 6b54b78464
Loading...
Searching...
No Matches
random_toolbox.hpp
Go to the documentation of this file.
1/*!
2 * \file random_toolbox.hpp
3 * \brief Collection of utility functions for random number generation.
4 * \version 8.5.0 "Harrier"
5 *
6 * SU2 Project Website: https://su2code.github.io
7 *
8 * The SU2 Project is maintained by the SU2 Foundation
9 * (http://su2foundation.org)
10 *
11 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
12 *
13 * SU2 is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * SU2 is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27#pragma once
28#include <cstdint>
29#include "../option_structure.hpp"
30
31namespace RandomToolbox {
32/// \addtogroup RandomToolbox
33/// @{
34
35/*!
36 * \brief SplitMix64 hash function for 64-bit integers.
37 * \param[in] x Input value to hash.
38 * \return Hashed 64-bit output.
39 */
40static inline uint64_t splitmix64(uint64_t x) {
41 x += 0x9e3779b97f4a7c15ULL; // golden ratio offset
42 x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; // first mixing step
43 x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; // second mixing step
44 return x ^ (x >> 31); // final avalanche
45}
46
47/*!
48 * \brief Generate a deterministic 64-bit hash from three integers.
49 * \param[in] nodeIndex Global node index.
50 * \param[in] iDim Dimension index.
51 * \param[in] timeIter Current time iteration of the simulation.
52 * \return 64-bit hash value.
53 */
54inline uint64_t GetHash(unsigned long nodeIndex, unsigned short iDim, unsigned long timeIter) {
55 uint64_t x = nodeIndex;
56 x ^= splitmix64(iDim);
57 x ^= splitmix64(timeIter);
58 return splitmix64(x);
59}
60
61/*!
62 * \brief Convert a 64-bit hash into a uniform double in (0,1].
63 * Uses the top 53 bits of the hash to fill the mantissa of a double.
64 * Ensures the result is never zero, suitable for Box-Muller transform.
65 * \param[in] x 64-bit hash.
66 * \return Uniform double in the interval (0,1].
67 */
68inline double HashToUniform(uint64_t x) {
69 constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53
70 uint64_t uInt = x >> 11; // top 53 bits
71 return (uInt + 1) * inv53; // map to (0,1]
72}
73
74/*!
75 * \brief Generate a standard normal random number from a 64-bit hash.
76 * Uses two deterministic uniforms derived from the hash and its bitwise NOT
77 * as inputs to the Box-Muller transform.
78 * \param[in] x 64-bit hash.
79 * \return Standard normal random number (mean=0, stddev=1).
80 */
81inline double HashToNormal(uint64_t x) {
82 double u = HashToUniform(x); // first uniform
83 double v = HashToUniform(~x); // second uniform (bitwise NOT)
84 double r = sqrt(-2.0 * log(u));
85 double theta = 2.0 * PI_NUMBER * v;
86 return r * cos(theta); // one normal sample
87}
88
89/*!
90 * \brief Generate a deterministic standard normal number for a cell, dimension, and timestep.
91 *
92 * Combines hashing and Box-Muller in one function.
93 *
94 * \param[in] nodeIndex Global node index.
95 * \param[in] dim Dimension index.
96 * \param[in] timeIter Simulation timestep (1-based).
97 * \return Standard normal random number.
98 */
99inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned long timeIter) {
100 uint64_t hash = GetHash(nodeIndex, dim, timeIter);
101 return HashToNormal(hash);
102}
103
104/*!
105 * \brief Compute modified bessel function of first kind (order 0).
106 * \param[in] x Argument of Bessel funtion.
107 * \return Value of Bessel function.
108 */
109template <class T>
110inline T GetBesselZero(const T& x) {
111 T abx = fabs(x);
112
113 if (abx < 3.75) {
114 T t = abx / 3.75;
115 T p =
116 1.0 +
117 t * t *
118 (3.5156229 +
119 t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813)))));
120 return log(p);
121 } else {
122 T t = 3.75 / abx;
123
124 T poly =
125 0.39894228 +
126 t * (0.01328592 +
127 t * (0.00225319 +
128 t * (-0.00157565 +
129 t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377)))))));
130
131 T arg = sqrt(abx) * poly;
132 return abx - log(arg);
133 }
134}
135
136/*!
137 * \brief Compute integral involving the product of three modified Bessel functions.
138 * Useful for scaling the smoothed stochastic source terms in Langevin equations.
139 * \param[in] beta_x Argument in x-direction.
140 * \param[in] beta_y Argument in y-direction.
141 * \param[in] beta_z Argument in z-direction.
142 * \return Value of the integral.
143 */
144template <class T>
145inline T GetBesselIntegral(const T& beta_x, const T& beta_y, const T& beta_z) {
146 const T A = 1 + 2 * (beta_x + beta_y + beta_z);
147 const T Bx = 2 * beta_x;
148 const T By = 2 * beta_y;
149 const T Bz = 2 * beta_z;
150
151 const int N = 4000;
152 const T t_max = 20.0;
153 const T dt = t_max / N;
154
155 T sum = T(0.0);
156
157 for (int i = 1; i <= N; i++) {
158 T t = i * dt;
159
160 T lin = log(t) - A * t + GetBesselZero(T(Bx * t)) + GetBesselZero(T(By * t)) + GetBesselZero(T(Bz * t));
161
162 T integrand = exp(lin);
163
164 T weight = (i == N) ? 0.5 : 1.0;
165 sum += integrand * weight;
166 }
167
168 return sum * dt;
169}
170
171/// @}
172} // namespace RandomToolbox
#define A(I, J)
double HashToNormal(uint64_t x)
Generate a standard normal random number from a 64-bit hash. Uses two deterministic uniforms derived ...
Definition random_toolbox.hpp:81
uint64_t GetHash(unsigned long nodeIndex, unsigned short iDim, unsigned long timeIter)
Generate a deterministic 64-bit hash from three integers.
Definition random_toolbox.hpp:54
double HashToUniform(uint64_t x)
Convert a 64-bit hash into a uniform double in (0,1]. Uses the top 53 bits of the hash to fill the ma...
Definition random_toolbox.hpp:68
T GetBesselIntegral(const T &beta_x, const T &beta_y, const T &beta_z)
Compute integral involving the product of three modified Bessel functions. Useful for scaling the smo...
Definition random_toolbox.hpp:145
double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned long timeIter)
Generate a deterministic standard normal number for a cell, dimension, and timestep.
Definition random_toolbox.hpp:99
T GetBesselZero(const T &x)
Compute modified bessel function of first kind (order 0).
Definition random_toolbox.hpp:110
FORCEINLINE ARRAY_T exp(const ARRAY_T &x)
Definition special_vectorization.hpp:156
FORCEINLINE ARRAY_T sqrt(const ARRAY_T &x)
Definition special_vectorization.hpp:116
Definition random_toolbox.hpp:31
constexpr passivedouble PI_NUMBER
Pi number (not using M_PI to avoid Windows issues).
Definition option_structure.hpp:108