File indexing completed on 2025-01-18 10:13:54
0001
0002
0003
0004 #ifndef VECGEOM_BASE_RNG_H_
0005 #define VECGEOM_BASE_RNG_H_
0006
0007 #include "VecGeom/base/Global.h"
0008
0009 #ifdef VECCORE_CUDA
0010 #include <cuda.h>
0011 #include <curand_kernel.h>
0012 #else
0013 #include <random>
0014 #endif
0015
0016 namespace vecgeom {
0017 inline namespace VECGEOM_IMPL_NAMESPACE {
0018
0019 #ifdef VECCORE_CUDA
0020 class RNG;
0021
0022
0023 namespace RNGvar {
0024 extern VECCORE_ATT_DEVICE unsigned long gMaxInstance;
0025 extern VECCORE_ATT_DEVICE RNG **gInstances;
0026 }
0027 #endif
0028
0029
0030
0031
0032 class RNG {
0033
0034 private:
0035 #ifdef VECCORE_CUDA
0036
0037 #ifdef __CUDA_ARCH__
0038 curandState fState;
0039 #else
0040
0041 #endif
0042
0043 VECCORE_ATT_HOST_DEVICE
0044 VECGEOM_FORCE_INLINE
0045 Precision GetUniform()
0046 {
0047 #ifdef __CUDA_ARCH__
0048 return curand_uniform(&fState);
0049 #else
0050 return (Precision)rand() / RAND_MAX;
0051 #endif
0052 }
0053
0054 #else
0055
0056 std::mt19937 rng;
0057 std::uniform_real_distribution<> uniform_dist;
0058
0059 VECGEOM_FORCE_INLINE
0060 Precision GetUniform() { return uniform_dist(rng); }
0061
0062 #endif
0063
0064 public:
0065 #ifdef VECCORE_CUDA
0066
0067 VECCORE_ATT_HOST_DEVICE
0068 RNG()
0069 {
0070 #ifdef __CUDA_ARCH__
0071 curand_init(0 , 0 , 0 , &fState);
0072 #else
0073
0074 #endif
0075 }
0076 #else
0077 RNG() : rng(0), uniform_dist(0, 1) {}
0078 #endif
0079
0080 public:
0081
0082
0083
0084 #ifdef __CUDA_ARCH__
0085 VECCORE_ATT_DEVICE
0086 static void InitInstances(unsigned long nthreads)
0087 {
0088 unsigned int tid = (threadIdx.x + blockIdx.x * blockDim.x);
0089
0090 if (tid == 0) {
0091 RNGvar::gMaxInstance = nthreads;
0092 RNGvar::gInstances = new RNG *[nthreads];
0093 }
0094 __syncthreads();
0095
0096 for (int i = tid; i < nthreads; i += blockDim.x * gridDim.x) {
0097 RNGvar::gInstances[i] = new RNG;
0098 }
0099 }
0100 #endif
0101
0102 #ifndef VECCORE_CUDA
0103 void seed(unsigned long seed_val) { rng.seed(seed_val); }
0104 #endif
0105
0106
0107
0108 VECCORE_ATT_HOST_DEVICE
0109 static RNG &Instance()
0110 {
0111 #ifdef __CUDA_ARCH__
0112 unsigned int tid = (threadIdx.x + blockIdx.x * blockDim.x);
0113 if (tid < RNGvar::gMaxInstance)
0114 return *(RNGvar::gInstances[tid]);
0115 else
0116 return *(new RNG);
0117 #else
0118 static RNG instance;
0119 return instance;
0120 #endif
0121 }
0122
0123
0124
0125
0126
0127 VECCORE_ATT_HOST_DEVICE
0128 VECGEOM_FORCE_INLINE
0129 Precision uniform(const Precision min = 0., const Precision max = 1.) { return min + (max - min) * GetUniform(); }
0130
0131 VECCORE_ATT_HOST_DEVICE
0132 VECGEOM_FORCE_INLINE
0133 int Poisson(const Precision lambda)
0134 {
0135 int k = 0;
0136 const Precision target = exp(-lambda);
0137 Precision p = GetUniform();
0138 while (p < target) {
0139 p *= GetUniform();
0140 ++k;
0141 }
0142 return k;
0143 }
0144
0145
0146 VECCORE_ATT_HOST_DEVICE
0147 VECGEOM_FORCE_INLINE
0148 Precision Gaus(Precision ave = 0.0, Precision sig = 1.0) { return Gauss(ave, sig); }
0149
0150 VECCORE_ATT_HOST_DEVICE
0151 VECGEOM_FORCE_INLINE
0152 Precision Gauss(Precision ave = 0.0, Precision sig = 1.0)
0153 {
0154 Precision x1, x2, w;
0155
0156 do {
0157 x1 = 2.0 * GetUniform() - 1.0;
0158 x2 = 2.0 * GetUniform() - 1.0;
0159 w = x1 * x1 + x2 * x2;
0160 } while (w >= 1.0);
0161
0162 w = std::sqrt((-2.0 * std::log(w)) / w);
0163 return ave + (x1 * w * sig);
0164 }
0165
0166
0167
0168
0169
0170 VECCORE_ATT_HOST_DEVICE
0171 VECGEOM_FORCE_INLINE
0172 void uniform_array(size_t n, Precision *array, const Precision min = 0., const Precision max = 1.)
0173 {
0174 for (size_t i = 0; i < n; ++i) {
0175 array[i] = min + (max - min) * GetUniform();
0176 }
0177 }
0178
0179 private:
0180 RNG(RNG const &);
0181 RNG &operator=(RNG const &);
0182 };
0183 }
0184 }
0185
0186 #endif