GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/common/random.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 18 28 64.3%
Functions: 1 3 33.3%
Branches: 9 30 30.0%

Line Branch Exec Source
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 //
4 // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7 /*!
8 * \file
9 * \ingroup Core
10 * \brief Some tools for random number generation
11 */
12 #ifndef DUMUX_COMMON_RANDOM_HH
13 #define DUMUX_COMMON_RANDOM_HH
14
15 #include <random>
16 #include <type_traits>
17 #include <cstdint>
18
19 namespace Dumux {
20
21 /*!
22 * \brief A simple uniform distribution
23 * based on a biased uniform number generator
24 * \note Use this if you need a fast library implementation independent generator
25 * without strict requirements about the bias
26 * \note We try to stay close to https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution
27 */
28 template<class Scalar = double>
29 class SimpleUniformDistribution
30 {
31 struct Parameters
32 {
33 Parameters(Scalar a, Scalar b)
34 : a_(a), b_(b) {}
35
36 Scalar a() const { return a_; }
37 Scalar b() const { return b_; }
38 private:
39 Scalar a_, b_;
40 };
41 public:
42 using param_type = Parameters;
43 using result_type = Scalar;
44
45 explicit SimpleUniformDistribution(Scalar min, Scalar max = 1.0)
46 : offset_(min)
47
1/7
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
3 , size_(max-min)
48 {}
49
50 explicit SimpleUniformDistribution(const Parameters& p)
51 : SimpleUniformDistribution(p.a(), p.b())
52 {}
53
54 SimpleUniformDistribution()
55 : SimpleUniformDistribution(0.0)
56 {}
57
58 void param(const Parameters& p)
59 {
60 offset_ = p.a();
61 size_ = p.b()-p.a();
62 }
63
64 Parameters param() const
65 { return { offset_, offset_+size_ }; }
66
67 Scalar a() const { return offset_; }
68 Scalar b() const { return offset_ + size_; }
69
70 template<class Generator,
71 typename std::enable_if_t<std::is_same_v<typename Generator::result_type, std::uint_fast32_t>, int> = 0>
72 Scalar operator()(Generator& gen)
73
0/7
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
105 { return offset_ + size_*(0x1.0p-32 * gen()); }
74
75 private:
76 Scalar offset_;
77 Scalar size_;
78 };
79
80 /*!
81 * \brief A simple normal distribution
82 * based on a biased uniform number generator and the Box-Mueller transform
83 * \note Use this if you need a fast library implementation independent generator
84 * without strict requirements about the bias
85 * \note We try to stay close to https://en.cppreference.com/w/cpp/numeric/random/normal_distribution
86 */
87 template<class Scalar = double>
88 class SimpleNormalDistribution
89 {
90 struct Parameters
91 {
92 Parameters(Scalar m, Scalar s)
93 : m_(m), s_(s) {}
94
95 Scalar m() const { return m_; }
96 Scalar s() const { return s_; }
97 private:
98 Scalar m_, s_;
99 };
100 public:
101 using param_type = Parameters;
102 using result_type = Scalar;
103
104 8 explicit SimpleNormalDistribution(Scalar mean, Scalar stddev = 1.0)
105 : mean_(mean)
106 8 , stddev_(stddev)
107 {}
108
109 explicit SimpleNormalDistribution(const Parameters& p)
110 : SimpleNormalDistribution(p.m(), p.s())
111 {}
112
113 SimpleNormalDistribution()
114 : SimpleNormalDistribution(0.0)
115 {}
116
117 void param(const Parameters& p)
118 {
119 mean_ = p.m();
120 stddev_ = p.s();
121 }
122
123 Parameters param() const
124 { return { mean_, stddev_ }; }
125
126 Scalar m() const { return mean_; }
127 Scalar s() const { return stddev_; }
128
129 template<class Generator>
130 17989 Scalar operator()(Generator& gen)
131 {
132
2/2
✓ Branch 0 taken 8993 times.
✓ Branch 1 taken 8996 times.
17989 if (isCached_)
133 {
134 8993 isCached_ = false;
135 8993 return cachedValue_;
136 }
137
138 // Box-Mueller transform (https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform)
139 8996 const auto [u1, u2] = generateUniformPair_(gen);
140
141 using std::sqrt; using std::log;
142 using std::cos; using std::sin;
143 8996 constexpr Scalar twoPi = 2.0 * M_PI;
144
145 8996 const Scalar magnitude = stddev_ * sqrt(-2.0 * log(u1));
146 8996 const Scalar z0 = magnitude * cos(twoPi * u2) + mean_;
147 8996 const Scalar z1 = magnitude * sin(twoPi * u2) + mean_;
148 8996 cachedValue_ = z0;
149 8996 isCached_ = true;
150 8996 return z1;
151 }
152
153 private:
154 template<class Generator,
155 typename std::enable_if_t<std::is_same_v<typename Generator::result_type, std::uint_fast32_t>, int> = 0>
156 auto generateUniformPair_(Generator& gen)
157 {
158 // biased uniform number generator (0,1)
159 // https://www.pcg-random.org/posts/bounded-rands.html
160 constexpr Scalar eps = std::numeric_limits<Scalar>::epsilon();
161 Scalar u1 = 0.0, u2 = 0.0;
162 do {
163 u1 = 0x1.0p-32 * gen();
164 u2 = 0x1.0p-32 * gen();
165 } while (u1 <= eps);
166 return std::make_pair(u1, u2);
167 }
168
169 Scalar mean_;
170 Scalar stddev_;
171 bool isCached_ = false;
172 Scalar cachedValue_ = {};
173 };
174
175 /*!
176 * \brief A simple log-normal distribution
177 * \note Use this if you need a fast library implementation independent generator
178 * without strict requirements about the bias
179 * \note We try to stay close to https://en.cppreference.com/w/cpp/numeric/random/lognormal_distribution
180 */
181 template<class Scalar = double>
182 class SimpleLogNormalDistribution
183 {
184 using Parameters = typename SimpleNormalDistribution<Scalar>::param_type;
185 public:
186 using param_type = Parameters;
187 using result_type = Scalar;
188
189 explicit SimpleLogNormalDistribution(Scalar mean, Scalar stddev = 1.0)
190
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
8 : normal_(mean, stddev)
191 {}
192
193 explicit SimpleLogNormalDistribution(const Parameters& p)
194 : SimpleLogNormalDistribution(p.mean, p.stddev)
195 {}
196
197 SimpleLogNormalDistribution()
198 : SimpleLogNormalDistribution(0.0)
199 {}
200
201 void param(const Parameters& p)
202 { normal_.param(p); }
203
204 Parameters param() const
205 { return normal_.param(); }
206
207 Scalar m() const { return normal_.m(); }
208 Scalar s() const { return normal_.s(); }
209
210 template<class Generator>
211 Scalar operator()(Generator& gen)
212 {
213 using std::exp;
214
3/6
✓ Branch 1 taken 15396 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
17989 return exp(normal_(gen));
215 }
216
217 private:
218 SimpleNormalDistribution<Scalar> normal_;
219 };
220
221 } // end namespace Dumux
222
223 #endif
224