ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
random.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2026 The ESPResSo project
3 *
4 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
5 * Max-Planck-Institute for Polymer Research, Theory Group
6 *
7 * This file is part of ESPResSo.
8 *
9 * ESPResSo is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * ESPResSo is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#pragma once
24
25/** \file
26 * Random number generation using Philox.
27 */
28
29#include <utils/Vector.hpp>
31#include <utils/u32_to_u64.hpp>
32#include <utils/uniform.hpp>
33
34#include <Random123/philox.h>
35
36#include <cstddef>
37#include <cstdint>
38#include <numbers>
39#include <random>
40#include <vector>
41
42/*
43 * @brief Salt for the RNGs
44 *
45 * This is to avoid correlations between the
46 * noise on the particle coupling and the fluid
47 * thermalization.
48 */
64
65namespace Random {
66/**
67 * @brief get 4 random uint 64 from the Philox RNG
68 *
69 * This uses the Philox PRNG, the state is controlled
70 * by the counter, the salt and two keys.
71 * If any of the keys and salt differ, the noise is
72 * not correlated between two calls along the same counter
73 * sequence.
74 */
75template <RNGSalt salt>
77 int key1, int key2 = 0) {
78
79 using rng_type = r123::Philox4x64;
80 using ctr_type = rng_type::ctr_type;
81 using key_type = rng_type::key_type;
82
83 const ctr_type c{{counter, 0u, 0u, 0u}};
84
85 auto const id1 = static_cast<uint32_t>(key1);
86 auto const id2 = static_cast<uint32_t>(key2);
87 const key_type k{{Utils::u32_to_u64(id1, id2),
88 Utils::u32_to_u64(static_cast<uint32_t>(salt), seed)}};
89
90 return rng_type{}(c, k);
91}
92
93/**
94 * @brief Generator for random uniform noise.
95 *
96 * Mean = 0, variance = 1 / 12.
97 * This uses the Philox PRNG, the state is controlled
98 * by the counter, the salt and two keys.
99 * If any of the keys and salt differ, the noise is
100 * not correlated between two calls along the same counter
101 * sequence.
102 *
103 * @tparam salt RNG salt
104 * @tparam N Size of the noise vector
105 * @param counter counter for random number generation
106 * @param seed seed for random number generation
107 * @param key1 key for random number generation
108 * @param key2 key for random number generation
109 *
110 * @return Vector of uniform random numbers.
111 */
112template <RNGSalt salt, std::size_t N = 3>
113 requires((N >= 1) and (N <= 4))
115 int key2 = 0) {
116 auto const integers = philox_4_uint64s<salt>(counter, seed, key1, key2);
118 for (std::size_t i = 0; i < N; ++i) {
119 noise[i] = Utils::uniform(integers[i]) - 0.5;
120 }
121 return noise;
122}
123
124/** @brief Generator for Gaussian noise.
125 *
126 * Mean = 0, standard deviation = 1.0.
127 * Based on the Philox RNG using 4x64 bits.
128 * The Box-Muller transform is used to convert from uniform to normal
129 * distribution. The transform is only valid, if the uniformly distributed
130 * random numbers are not zero (approx one in 2^64). To avoid this case,
131 * such numbers are replaced by std::numeric_limits<double>::min()
132 * This breaks statistics in rare cases but allows for consistent RNG
133 * counters across MPI ranks.
134 *
135 * @tparam salt decorrelates different thermostat types
136 * @param counter counter for random number generation
137 * @param seed seed for random number generation
138 * @param key1 key for random number generation
139 * @param key2 key for random number generation
140 *
141 * @return Vector of Gaussian random numbers.
142 */
143template <RNGSalt salt, std::size_t N = 3>
144 requires((N >= 1) and (N <= 4))
146 int key2 = 0) {
147
148 auto const integers = philox_4_uint64s<salt>(counter, seed, key1, key2);
149
150 constexpr std::size_t M = (N <= 2) ? 2 : 4;
151 constexpr auto epsilon = std::numeric_limits<double>::min();
153 for (std::size_t i = 0; i < M; ++i) {
154 auto res = Utils::uniform(integers[i]);
155 u[i] = (res < epsilon) ? epsilon : res;
156 }
157
158 // Box-Muller transform code adapted from
159 // https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
160 // optimizations: the modulo is cached (logarithms are expensive), the
161 // sin/cos are evaluated simultaneously by gcc or separately by Clang
163 {
164 auto const modulo = std::sqrt(-2. * std::log(u[0]));
165 auto const angle = 2. * std::numbers::pi * u[1];
166 noise[0] = modulo * std::cos(angle);
167 if (N > 1) {
168 noise[1] = modulo * std::sin(angle);
169 }
170 }
171 if (N > 2) {
172 auto const modulo = std::sqrt(-2. * log(u[2]));
173 auto const angle = 2. * std::numbers::pi * u[3];
174 noise[2] = modulo * std::cos(angle);
175 if (N > 3) {
176 noise[3] = modulo * std::sin(angle);
177 }
178 }
179 return noise;
180}
181
182/** Mersenne Twister with warmup.
183 * The first 100'000 values of Mersenne Twister generators are often heavily
184 * correlated @cite panneton06a. This utility function discards the first
185 * 1'000'000 values.
186 *
187 * @param seed RNG seed
188 */
189template <typename T> std::mt19937 mt19937(T &&seed) {
190 std::mt19937 generator(seed);
191 generator.discard(1'000'000);
192 return generator;
193}
194
195} // namespace Random
Vector implementation and trait types for boost qvm interoperability.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
#define DEVICE_QUALIFIER
DEVICE_QUALIFIER auto noise_uniform(uint64_t counter, uint32_t seed, int key1, int key2=0)
Generator for random uniform noise.
Definition random.hpp:114
DEVICE_QUALIFIER auto noise_gaussian(uint64_t counter, uint32_t seed, int key1, int key2=0)
Generator for Gaussian noise.
Definition random.hpp:145
DEVICE_QUALIFIER auto philox_4_uint64s(uint64_t counter, uint32_t seed, int key1, int key2=0)
get 4 random uint 64 from the Philox RNG
Definition random.hpp:76
std::mt19937 mt19937(T &&seed)
Mersenne Twister with warmup.
Definition random.hpp:189
DEVICE_QUALIFIER constexpr uint64_t u32_to_u64(uint32_t high, uint32_t low)
constexpr DEVICE_QUALIFIER double uniform(uint64_t in)
Uniformly map unsigned integer to double.
Definition uniform.hpp:37
RNGSalt
Definition random.hpp:49
@ BROWNIAN_INC
@ LANGEVIN_ROT
@ BROWNIAN_ROT_WALK
@ THERMAL_STONER_WOHLFARTH
@ BROWNIAN_WALK
@ BROWNIAN_ROT_INC
@ NPTISO_VOLUME
@ THERMALIZED_BOND
@ NPTISO_PARTICLE