Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // 27 // 28 // G4UniformRandPool implementation 29 // 30 // Author: A.Dotti (SLAC) 31 // ------------------------------------------------------------ 32 33 #include "G4UniformRandPool.hh" 34 35 #include "G4AutoDelete.hh" 36 #include "G4Threading.hh" 37 #include "globals.hh" 38 39 #include <algorithm> 40 #include <climits> 41 #include <cstdlib> 42 #include <cstring> 43 44 // Not aligned memory 45 // 46 void create_pool(G4double*& buffer, G4int ps) { buffer = new G4double[ps]; } 47 48 void destroy_pool(G4double*& buffer) { delete[] buffer; } 49 50 #if defined(WIN32) || defined(__MINGW32__) 51 // No bother with WIN 52 void create_pool_align(G4double*& buffer, G4int ps) { create_pool(buffer, ps); } 53 void destroy_pool_align(G4double*& buffer) { destroy_pool(buffer); } 54 55 #else 56 57 // Align memory pools 58 // Assumption is: static_assert(sizeof(G4double)*CHAR_BIT==64) 59 // 60 void create_pool_align(G4double*& buffer, G4int ps) 61 { 62 // POSIX standard way 63 G4int errcode = posix_memalign((void**) &buffer, sizeof(G4double) * CHAR_BIT, 64 ps * sizeof(G4double)); 65 if(errcode != 0) 66 { 67 G4Exception("G4UniformRandPool::create_pool_align()", "InvalidCondition", 68 FatalException, "Cannot allocate aligned buffer"); 69 return; 70 } 71 return; 72 } 73 74 void destroy_pool_align(G4double*& buffer) { free(buffer); } 75 #endif 76 77 G4UniformRandPool::G4UniformRandPool() 78 { 79 if(sizeof(G4double) * CHAR_BIT == 64) 80 { 81 create_pool_align(buffer, size); 82 } 83 else 84 { 85 create_pool(buffer, size); 86 } 87 Fill(size); 88 } 89 90 G4UniformRandPool::G4UniformRandPool(G4int siz) 91 : size(siz) 92 { 93 if(sizeof(G4double) * CHAR_BIT == 64) 94 { 95 create_pool_align(buffer, size); 96 } 97 else 98 { 99 create_pool(buffer, size); 100 } 101 Fill(size); 102 } 103 104 G4UniformRandPool::~G4UniformRandPool() 105 { 106 if(sizeof(G4double) * CHAR_BIT == 64) 107 { 108 destroy_pool_align(buffer); 109 } 110 else 111 { 112 destroy_pool(buffer); 113 } 114 } 115 116 void G4UniformRandPool::Resize(/*PoolSize_t*/ G4int newSize) 117 { 118 if(newSize != size) 119 { 120 destroy_pool(buffer); 121 create_pool(buffer, newSize); 122 size = newSize; 123 currentIdx = 0; 124 } 125 currentIdx = 0; 126 } 127 128 void G4UniformRandPool::Fill(G4int howmany) 129 { 130 assert(howmany > 0 && howmany <= size); 131 132 // Fill buffer with random numbers 133 // 134 G4Random::getTheEngine()->flatArray(howmany, buffer); 135 currentIdx = 0; 136 } 137 138 void G4UniformRandPool::GetMany(G4double* rnds, G4int howmany) 139 { 140 assert(rnds != 0 && howmany > 0); 141 142 // if ( howmany <= 0 ) return; 143 // We generate at max "size" numbers at once, and 144 // We do not want to use recursive calls (expensive). 145 // We need to deal with the case howmany>size 146 // So: 147 // how many times I need to get "size" numbers? 148 149 const G4int maxcycles = howmany / size; 150 151 // This is the rest 152 // 153 const G4int peel = howmany % size; 154 assert(peel < size); 155 156 // Ok from now on I will get random numbers in group of "size" 157 // Note that if howmany<size maxcycles == 0 158 // 159 G4int cycle = 0; 160 161 // Consider the case howmany>size, then maxcycles>=1 162 // and we will request at least "size" rng, so 163 // let's start with a fresh buffer of numbers if needed 164 // 165 if(maxcycles > 0 && currentIdx > 0) 166 { 167 assert(currentIdx <= size); 168 Fill(currentIdx); //<size?currentIdx:size); 169 } 170 for(; cycle < maxcycles; ++cycle) 171 { 172 // We can use memcpy of std::copy, it turns out that the two are basically 173 // performance-wise equivalent (expected), since in my tests memcpy is a 174 // little bit faster, I use that 175 // 176 memcpy(rnds + (cycle * size), buffer, sizeof(G4double) * size); 177 // std::copy(buffer,buffer+size,rnds+(cycle*size)); 178 179 // Get a new set of numbers 180 // 181 Fill(size); // Now currentIdx is 0 again 182 } 183 184 // If maxcycles>0 last think we did was to call Fill(size) 185 // so currentIdx == 0 186 // and it is guaranteed that peel<size, we have enough fresh random numbers 187 // but if maxcycles==0 currentIdx can be whatever, let's make sure we have 188 // enough fresh numbers 189 // 190 if(currentIdx + peel >= size) 191 { 192 Fill(currentIdx < size ? currentIdx : size); 193 } 194 memcpy(rnds + (cycle * size), buffer + currentIdx, sizeof(G4double) * peel); 195 // std::copy(buffer+currentIdx,buffer+(currentIdx+peel), rnds+(cycle*size)); 196 197 // Advance index, we are done 198 // 199 currentIdx += peel; 200 assert(currentIdx <= size); 201 } 202 203 // Static interfaces implementing CLHEP methods 204 205 namespace 206 { 207 G4ThreadLocal G4UniformRandPool* rndpool = nullptr; 208 } 209 210 G4double G4UniformRandPool::flat() 211 { 212 if(rndpool == nullptr) 213 { 214 rndpool = new G4UniformRandPool; 215 G4AutoDelete::Register(rndpool); 216 } 217 return rndpool->GetOne(); 218 } 219 220 void G4UniformRandPool::flatArray(G4int howmany, G4double* rnds) 221 { 222 if(rndpool == nullptr) 223 { 224 rndpool = new G4UniformRandPool; 225 G4AutoDelete::Register(rndpool); 226 } 227 rndpool->GetMany(rnds, (unsigned int) howmany); 228 } 229