CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
testThreaded.cc
Go to the documentation of this file.
1#include "CLHEP/Random/DualRand.h"
2#include "CLHEP/Random/Hurd160Engine.h"
3#include "CLHEP/Random/Hurd288Engine.h"
4#include "CLHEP/Random/JamesRandom.h"
5#include "CLHEP/Random/MixMaxRng.h"
6#include "CLHEP/Random/MTwistEngine.h"
7#include "CLHEP/Random/RandEngine.h"
8#include "CLHEP/Random/RanecuEngine.h"
9#include "CLHEP/Random/Ranlux64Engine.h"
10#include "CLHEP/Random/RanluxEngine.h"
11#include "CLHEP/Random/RanluxppEngine.h"
12#include "CLHEP/Random/RanshiEngine.h"
13#include "CLHEP/Random/TripleRand.h"
14
15#include "CLHEP/Random/RandBinomial.h"
16#include "CLHEP/Random/RandChiSquare.h"
17#include "CLHEP/Random/RandGauss.h"
18#include "CLHEP/Random/RandGamma.h"
19#include "CLHEP/Random/RandGaussZiggurat.h"
20#include "CLHEP/Random/RandExpZiggurat.h"
21#include "CLHEP/Utility/atomic_int.h"
22#include <cmath>
23#include <iostream>
24#include <vector>
25
26// Some logic to only run the test if the compiler supports
27// threading
28#if __cplusplus >= 201103L
29
30 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)
31 #define CLHEP_RUN_THREADED_TESTS 1
32 #include <thread>
33 #elif __clang__
34 #if __has_feature(cxx_thread_local) && __has_feature(c_atomic)
35 #define CLHEP_RUN_THREADED_TESTS 1
36 #include <thread>
37 #else
38 #define CLHEP_RUN_THREADED_TESTS 0
39 #endif
40 #else
41 #define CLHEP_RUN_THREADED_TESTS 0
42 #endif
43
44#else
45 #define CLHEP_RUN_THREADED_TESTS 0
46#endif
47
48void testRandGauss(std::vector<double> const& reference, bool& result) {
49
50 // Check that the fire and two shoot methods all give the same
51 // random number sequence. The output of the fire method is passed
52 // in. fire does not use thread local variables, but instead
53 // nonstatic class data members for the caching. shoot should
54 // be using thread local variables for the caching. Random
55 // numbers are generated in pairs and on a subsequent call
56 // the second number is used. Note it is important that an
57 // odd number of random numbers are generated for this test,
58 // because that causes there to be a number in the cache from
59 // the first thread when the second thread executes. It proves
60 // that the second thread is using a different cache when it
61 // does not use that cached value.
62
63 long seedL1 = 100;
64 CLHEP::HepJamesRandom engine(seedL1);
65 CLHEP::RandGauss dist(engine);
66
67 result = true;
68
69 std::vector<double> v;
70 v.push_back(dist.fire());
71 v.push_back(dist.fire());
72 v.push_back(dist.fire());
73 v.push_back(dist.fire());
74 v.push_back(dist.fire());
75
76 // Just a sanity check first. The fire method reproduces
77 // itself.
78 if (reference[0] != v[0] ||
79 reference[1] != v[1] ||
80 reference[2] != v[2] ||
81 reference[3] != v[3] ||
82 reference[4] != v[4]) {
83 result = false;
84 }
85
86 // check the shoot method where we pass in an engine
87 CLHEP::HepJamesRandom engine1(seedL1);
88
89 v.clear();
90 v.push_back(CLHEP::RandGauss::shoot(&engine1));
91 v.push_back(CLHEP::RandGauss::shoot(&engine1));
92 v.push_back(CLHEP::RandGauss::shoot(&engine1));
93 v.push_back(CLHEP::RandGauss::shoot(&engine1));
94 v.push_back(CLHEP::RandGauss::shoot(&engine1));
95
96 if (reference[0] != v[0] ||
97 reference[1] != v[1] ||
98 reference[2] != v[2] ||
99 reference[3] != v[3] ||
100 reference[4] != v[4]) {
101 result = false;
102 }
103
104 // check the shoot method using the CLHEP thread local
105 // engine
106 CLHEP::HepJamesRandom engine2(seedL1);
109 // setFlag causes it to not use the cached value
110 // and generate a new pair of random numbers
112
113 v.clear();
114 v.push_back(CLHEP::RandGauss::shoot());
115 v.push_back(CLHEP::RandGauss::shoot());
116 v.push_back(CLHEP::RandGauss::shoot());
117 v.push_back(CLHEP::RandGauss::shoot());
118 v.push_back(CLHEP::RandGauss::shoot());
119
120 if (reference[0] != v[0] ||
121 reference[1] != v[1] ||
122 reference[2] != v[2] ||
123 reference[3] != v[3] ||
124 reference[4] != v[4]) {
125 result = false;
126 }
128}
129
130#if defined __GNUC__
131 #if __GNUC__ > 3 && __GNUC_MINOR__ > 6
132 #pragma GCC diagnostic push
133 #pragma GCC diagnostic ignored "-Wshadow"
134 #endif
135 #if __GNUC__ > 4
136 #pragma GCC diagnostic push
137 #pragma GCC diagnostic ignored "-Wshadow"
138 #endif
139#endif
140#if defined __INTEL_COMPILER
141 #pragma warning push
142 #pragma warning disable 1599
143#endif
144#ifdef __clang__
145 #pragma clang diagnostic push
146 #pragma clang diagnostic ignored "-Wshadow"
147#endif
148
149int main() {
150
151 std::ofstream output("testThreaded.cout");
152
153#if CLHEP_RUN_THREADED_TESTS == 0
154 output << "Not running testThreaded.cc tests because compiler does not support needed features.\n";
155 return 0;
156#else
157 output << "Running testThreaded.cc tests.\n";
158
159 long seedL = 100;
160 CLHEP::HepJamesRandom engine(seedL);
161 CLHEP::RandGauss dist(engine);
162 std::vector<double> generatedNumbers;
163
164 generatedNumbers.push_back(dist.fire());
165 generatedNumbers.push_back(dist.fire());
166 generatedNumbers.push_back(dist.fire());
167 generatedNumbers.push_back(dist.fire());
168 generatedNumbers.push_back(dist.fire());
169
170 bool result1 = true;
171 // First test that the fire and shoot methods give consistent results
172 std::thread t1(testRandGauss, std::cref(generatedNumbers), std::ref(result1));
173 t1.join();
174 if(!result1) {
175 output << "testRandGauss failed on thread 1. fire and 2 shoot functions do not give the same results.\n";
176 return 1;
177 }
178
179 bool result2 = true;
180 // RandGauss generates numbers in pairs and caches the second, using the
181 // second on a subsequent call instead of generating another. The following
182 // will fail if the cache is not thread local because the first random
183 // number generated will be the cached one from the previous thread instead
184 // of a new one.
185 std::thread t2(testRandGauss, std::cref(generatedNumbers), std::ref(result2));
186 t2.join();
187 if(!result2) {
188 output << "testRandGauss failed on thread 2. This might mean the cache in RandGauss is not really thread local.\n";
189 output << "Maybe a problem in the macro logic in CLHEP/Utility/thread_local.h.\n";
190 return 1;
191 }
192
193 output << "Verified that CLHEP_THREAD_LOCAL types are really thread local\n";
194
195 CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
196 if(numberOfEngines.load() == 0) {
197 output << "If this is printing, it means CLHEP_ATOMIC_INT_TYPE really has type atomic<int>\n";
198 }
199
200 // The default seed values for the engines are not supposed
201 // to change nor are the initial random numbers from a sequence.
202 // I empirically determined the values before the threading code
203 // changes and test that they are still the same.
204 double epsilon = 0.0001;
205 {
206 CLHEP::DualRand engine1;
207 CLHEP::DualRand engine2;
208 CLHEP::DualRand engine3;
209 if(std::fabs(engine1.flat() - 0.412678) > epsilon ||
210 std::fabs(engine2.flat() - 0.112937) > epsilon ||
211 std::fabs(engine3.flat() - 0.998563) > epsilon) {
212 output << "Error, default seeds changed for DualRand random engine.\n";
213 return 1;
214 }
215 }
216 {
217 CLHEP::Hurd160Engine engine1;
218 CLHEP::Hurd160Engine engine2;
219 CLHEP::Hurd160Engine engine3;
220 if(std::fabs(engine1.flat() - 0.104097) > epsilon ||
221 std::fabs(engine2.flat() - 0.392414) > epsilon ||
222 std::fabs(engine3.flat() - 0.7008) > epsilon) {
223 output << "Error, default seeds changed for Hurd160Engine random engine.\n";
224 return 1;
225 }
226 }
227 {
228 CLHEP::Hurd288Engine engine1;
229 CLHEP::Hurd288Engine engine2;
230 CLHEP::Hurd288Engine engine3;
231 if(std::fabs(engine1.flat() - 0.942396) > epsilon ||
232 std::fabs(engine2.flat() - 0.422952) > epsilon ||
233 std::fabs(engine3.flat() - 0.528602) > epsilon) {
234 output << "Error, default seeds changed for Hurd288Engine random engine.\n";
235 return 1;
236 }
237 }
238 {
239 // Actually engines 3, 4, and 5 because each thread above created
240 // a default HepJamesRandom engine. The default one whose creation
241 // was triggered in the CLHEP::HepRandom::setTheEngine call.
242 CLHEP::HepJamesRandom engine3;
243 CLHEP::HepJamesRandom engine4;
244 CLHEP::HepJamesRandom engine5;
245 if(std::fabs(engine3.flat() - 0.286072) > epsilon ||
246 std::fabs(engine4.flat() - 0.233610) > epsilon ||
247 std::fabs(engine5.flat() - 0.837788) > epsilon) {
248 output << "Error, default seeds changed for HepJamesRandom random engine.\n";
249 return 1;
250 }
251 }
252 {
253 CLHEP::MixMaxRng engine1;
254 CLHEP::MixMaxRng engine2;
255 CLHEP::MixMaxRng engine3;
256 if(std::fabs(engine1.flat() - 0.840834) > epsilon ||
257 std::fabs(engine2.flat() - 0.338951) > epsilon ||
258 std::fabs(engine3.flat() - 0.840794) > epsilon) {
259 output << "Error, default seeds changed for MixMaxRng random engine.\n";
260 return 1;
261 }
262 }
263 {
264 CLHEP::MTwistEngine engine1;
265 CLHEP::MTwistEngine engine2;
266 CLHEP::MTwistEngine engine3;
267 if(std::fabs(engine1.flat() - 0.350114) > epsilon ||
268 std::fabs(engine2.flat() - 0.575236) > epsilon ||
269 std::fabs(engine3.flat() - 0.143409) > epsilon) {
270 output << "Error, default seeds changed for MTwistEngine random engine.\n";
271 return 1;
272 }
273 }
274 {
275 CLHEP::RanecuEngine engine1;
276 CLHEP::RanecuEngine engine2;
277 CLHEP::RanecuEngine engine3;
278 if(std::fabs(engine1.flat() - 0.154707) > epsilon ||
279 std::fabs(engine2.flat() - 0.417668) > epsilon ||
280 std::fabs(engine3.flat() - 0.350542) > epsilon) {
281 output << "Error, default seeds changed for RanecuEngine random engine.\n";
282 return 1;
283 }
284 }
285 {
286 CLHEP::Ranlux64Engine engine1;
287 CLHEP::Ranlux64Engine engine2;
288 CLHEP::Ranlux64Engine engine3;
289 if(std::fabs(engine1.flat() - 0.943338) > epsilon ||
290 std::fabs(engine2.flat() - 0.175414) > epsilon ||
291 std::fabs(engine3.flat() - 0.965602) > epsilon) {
292 output << "Error, default seeds changed for Ranlux64Engine random engine.\n";
293 return 1;
294 }
295 }
296 {
297 CLHEP::RanluxEngine engine1;
298 CLHEP::RanluxEngine engine2;
299 CLHEP::RanluxEngine engine3;
300 if(std::fabs(engine1.flat() - 0.117402) > epsilon ||
301 std::fabs(engine2.flat() - 0.856504) > epsilon ||
302 std::fabs(engine3.flat() - 0.68177) > epsilon) {
303 output << "Error, default seeds changed for RanluxEngine random engine.\n";
304 return 1;
305 }
306 }
307 {
308 CLHEP::RanluxppEngine engine1;
309 CLHEP::RanluxppEngine engine2;
310 CLHEP::RanluxppEngine engine3;
311 if(std::fabs(engine1.flat() - 0.239639) > epsilon ||
312 std::fabs(engine2.flat() - 0.566275) > epsilon ||
313 std::fabs(engine3.flat() - 0.958136) > epsilon) {
314 output << "Error, default seeds changed for RanluxppEngine random engine.\n";
315 return 1;
316 }
317 }
318 {
319 CLHEP::RanshiEngine engine1;
320 CLHEP::RanshiEngine engine2;
321 CLHEP::RanshiEngine engine3;
322 if(std::fabs(engine1.flat() - 0.989873) > epsilon ||
323 std::fabs(engine2.flat() - 0.548671) > epsilon ||
324 std::fabs(engine3.flat() - 0.917996) > epsilon) {
325 output << "Error, default seeds changed for RanshiEngine random engine.\n";
326 return 1;
327 }
328 }
329 {
330 CLHEP::TripleRand engine1;
331 CLHEP::TripleRand engine2;
332 CLHEP::TripleRand engine3;
333 if(std::fabs(engine1.flat() - 0.838579) > epsilon ||
334 std::fabs(engine2.flat() - 0.212374) > epsilon ||
335 std::fabs(engine3.flat() - 0.84029) > epsilon) {
336 output << "Error, default seeds changed for TripleRand random engine.\n";
337 return 1;
338 }
339 }
340
341 // Test to reference values determined by running this code once
342 // Results should be reproducible so they should not change.
343 {
344 long seedL2 = 100;
345 CLHEP::HepJamesRandom engine(seedL2);
346 if(CLHEP::RandBinomial::shoot(&engine, 50, 0.2) != 12) {
347 output << "Error, results changed for RandBinomial.\n";
348 return 1;
349 }
350 }
351 {
352 long seedL3 = 100;
353 CLHEP::HepJamesRandom engine(seedL3);
354 if(std::fabs(CLHEP::RandChiSquare::shoot(&engine) - 0.031799) > epsilon) {
355 output << "Error, results changed for RandChiSquared.\n";
356 return 1;
357 }
358 }
359 {
360 long seedL4 = 100;
361 CLHEP::HepJamesRandom engine(seedL4);
362 if(std::fabs(CLHEP::RandExpZiggurat::shoot(&engine) - 1.59601) > epsilon) {
363 output << "Error, results changed for RandExpZiggurat.\n";
364 return 1;
365 }
366 }
367 {
368 long seedL5 = 100;
369 CLHEP::HepJamesRandom engine(seedL5);
370 if(std::fabs(CLHEP::RandGamma::shoot(&engine) - 1.25744) > epsilon) {
371 output << "Error, results changed for RandGamma.\n";
372 return 1;
373 }
374 }
375 {
376 long seedL6 = 100;
377 CLHEP::HepJamesRandom engine(seedL6);
378 if(std::fabs(CLHEP::RandGaussZiggurat::shoot(&engine) - (-0.138855)) > epsilon) {
379 output << "Error, results changed for RandGaussZiggurat.\n";
380 return 1;
381 }
382 }
383 return 0;
384#endif
385}
386#if defined __GNUC__
387 #if __GNUC__ > 3 && __GNUC_MINOR__ > 6
388 #pragma GCC diagnostic pop
389 #endif
390 #if __GNUC__ > 4
391 #pragma GCC diagnostic pop
392 #endif
393#endif
394#if defined __INTEL_COMPILER
395 #pragma warning pop
396#endif
397#ifdef __clang__
398 #pragma clang diagnostic pop
399#endif
#define CLHEP_ATOMIC_INT_TYPE
Definition: atomic_int.h:25
double flat()
Definition: DualRand.cc:117
static HepRandomEngine * getTheEngine()
Definition: Random.cc:270
static void setTheEngine(HepRandomEngine *theNewEngine)
Definition: Random.cc:275
double flat()
Definition: MixMaxRng.h:67
static double shoot()
static double shoot()
static double shoot()
static double shoot()
Definition: RandGauss.cc:64
static void setFlag(bool val)
Definition: RandGauss.cc:178
double flat() override
std::ofstream output("ranRestoreTest.cout")
uint testRandGauss()
int main()