CASToR  3.0
Tomographic Reconstruction (PET/SPECT/CT)
sRandomNumberGenerator.cc
Go to the documentation of this file.
1 /*
2 This file is part of CASToR.
3 
4  CASToR is free software: you can redistribute it and/or modify it under the
5  terms of the GNU General Public License as published by the Free Software
6  Foundation, either version 3 of the License, or (at your option) any later
7  version.
8 
9  CASToR is distributed in the hope that it will be useful, but WITHOUT ANY
10  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  details.
13 
14  You should have received a copy of the GNU General Public License along with
15  CASToR (in file GNU_GPL.TXT). If not, see <http://www.gnu.org/licenses/>.
16 
17 Copyright 2017-2019 all CASToR contributors listed below:
18 
19  --> Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Thibaut MERLIN, Mael MILLARDET, Simon STUTE, Valentin VIELZEUF
20 
21 This is CASToR version 3.0.
22 */
23 
33 
35 
36 // =====================================================================
37 // ---------------------------------------------------------------------
38 // ---------------------------------------------------------------------
39 // =====================================================================
44 {
45  mp_Instance = NULL;
46  m_verbose = 5;
47  mp_Engines.clear();
48  mp_extraEngines.clear();
49  m_seed = -1;
50 }
51 
52 
53 
54 // =====================================================================
55 // ---------------------------------------------------------------------
56 // ---------------------------------------------------------------------
57 // =====================================================================
58 /*
59  \brief Destructor of sRandomNumberGenerator. Do nothing by default
60 */
62 {
63 }
64 
65 
66 
67 // =====================================================================
68 // ---------------------------------------------------------------------
69 // ---------------------------------------------------------------------
70 // =====================================================================
71 
72 int sRandomNumberGenerator::Initialize(int a_nbThreads, int a_nbExtra)
73 {
74  if(m_verbose >=3) Cout("sRandomNumberGenerator::Initialize ..."<< endl);
75 
76  int64_t seed = -1;
77 
78  // call a real random generator, only once because this operating system
79  // random source might be limited in size and time
80  std::random_device rd;
81 
82  // save the initial seed
83  m_seed = rd();
84 
85  #ifdef CASTOR_MPI
86  int mpi_rank_temp = 0;
87  int mpi_size_temp = 0;
88  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank_temp);
89  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size_temp);
90 
91  // helper variable
92  int64_t temp_seed = -1;
93 
94  // if more than one MPI instance, generate seeds for each instance
95  // and dispatch them, otherwise keep the initial seed
96  if (mpi_size_temp>1)
97  {
98  if (mpi_rank_temp==0)
99  {
100  Engine mpi_generator(m_seed);
101  for (int p=0; p<mpi_size_temp; p++)
102  {
103  m_seed = mpi_generator();
104 
105  Cout("sRandomNumberGenerator::Seed for rank " << p << " is " << m_seed << endl);
106 
107  if (p==0)
108  temp_seed = m_seed;
109  else
110  MPI_Send(&m_seed, 1, MPI_LONG, p, 0, MPI_COMM_WORLD);
111  }
112  m_seed = temp_seed;
113  }
114  else
115  {
116  MPI_Status* status = NULL;
117  MPI_Recv(&m_seed, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD, status);
118  }
119  // wait for all the processes to have their seeds
120  MPI_Barrier(MPI_COMM_WORLD);
121  }
122  #endif
123 
124  // seed the initial temporary PRNG, which will generate seeds for actual PRNGs (threaded and non-threaded)
125  Engine initialGenerator(m_seed);
126 
127  for (int th=0; th<a_nbThreads; th++)
128  {
129  seed = initialGenerator();
130  if (m_verbose>=3) Cout("sRandomNumberGenerator::Initialize() -> Seed for thread " << th << " : " << seed << endl);
131  mp_Engines.push_back(Engine(seed));
132  }
133 
134  for(int ex=0; ex<a_nbExtra; ex++)
135  {
136  seed = initialGenerator();
137  if(m_verbose>=3) Cout("sRandomNumberGenerator::Initialize() - >Seed for additional nonthreaded generator "<<ex<<" : " << seed << endl);
138  mp_extraEngines.push_back(Engine(seed));
139  }
140 
141  return 0;
142 }
143 
144 
145 
146 // =====================================================================
147 // ---------------------------------------------------------------------
148 // ---------------------------------------------------------------------
149 // =====================================================================
150 
151 int sRandomNumberGenerator::Initialize(int64_t a_seed, int a_nbThreads, int a_nbExtra)
152 {
153  if(m_verbose >=3) Cout("sRandomNumberGenerator::Initialize with provided seed "<<a_seed<< endl);
154 
155  // temporary variable
156  int64_t seed = -1;
157 
158  if (a_seed<0)
159  {
160  Cout("***** sRandomNumberGenerator::Initialize()-> Error : seed for RNG should be >=0 !" << endl);
161  return 1;
162  }
163 
164  // save the initial seed
165  m_seed = a_seed;
166 
167  #ifdef CASTOR_MPI
168  int mpi_rank_temp = 0;
169  int mpi_size_temp = 0;
170  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank_temp);
171  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size_temp);
172 
173  // helper variable
174  int64_t temp_seed = -1;
175 
176  // if more than one MPI instance, generate seeds for each instance
177  // and dispatch them, otherwise keep the initial seed
178  if (mpi_size_temp>1)
179  {
180  if (mpi_rank_temp==0)
181  {
182  Engine mpi_generator(a_seed);
183  for (int p=0; p<mpi_size_temp; p++)
184  {
185  m_seed = mpi_generator();
186 
187  Cout("sRandomNumberGenerator::Seed for rank "<<p<<" is "<<m_seed<<""<< endl);
188 
189  if (p==0)
190  temp_seed = m_seed;
191  else
192  MPI_Send(&m_seed, 1, MPI_LONG, p, 0, MPI_COMM_WORLD);
193  }
194  m_seed = temp_seed;
195  }
196  else
197  {
198  MPI_Status* status = NULL;
199  MPI_Recv(&m_seed, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD, status);
200  }
201  MPI_Barrier(MPI_COMM_WORLD);
202  }
203  #endif
204 
205  // seed the initial temporary PRNG, which will generate seeds for actual PRNGs (threaded and non-threaded)
206  Engine initialGenerator(m_seed);
207 
208  for(int th=0; th<a_nbThreads; th++)
209  {
210  seed = initialGenerator();
211  mp_Engines.push_back(Engine(seed));
212  if (m_verbose>=3) Cout("sRandomNumberGenerator::Initialize() -> Seed for thread " << th << " : " << seed << endl);
213  }
214 
215  for(int ex=0; ex<a_nbExtra; ex++)
216  {
217  seed = initialGenerator();
218  mp_extraEngines.push_back(Engine(seed));
219  if (m_verbose>=3) Cout("sRandomNumberGenerator::Initialize() -> Seed for additional nonthreaded random generator "<<ex<< " : " << seed << endl);
220  }
221 
222  return 0;
223 }
224 
225 
226 
227 // =====================================================================
228 // ---------------------------------------------------------------------
229 // ---------------------------------------------------------------------
230 // =====================================================================
231 
233 {
234  #ifdef CASTOR_VERBOSE
235  if (m_verbose >=4) Cout("sRandomNumberGenerator::GenerateRdmNber..." << endl);
236  #endif
237 
238  int id=0;
239  #ifdef CASTOR_OMP
240  id = omp_get_thread_num();
241  #endif
242  return mp_Distribution(mp_Engines[id]);
243 }
244 
245 
246 
247 // =====================================================================
248 // ---------------------------------------------------------------------
249 // ---------------------------------------------------------------------
250 // =====================================================================
251 
253 {
254  #ifdef CASTOR_VERBOSE
255  if(m_verbose >=4) Cout("sRandomNumberGenerator::GenerateExtraRdmNber..."<< endl);
256  #endif
257 
258  return mp_Distribution(mp_extraEngines[a_nb]);
259 }
260 
261 
262 // =====================================================================
263 // ---------------------------------------------------------------------
264 // ---------------------------------------------------------------------
265 // =====================================================================
266 
268 {
269  #ifdef CASTOR_VERBOSE
270  if(m_verbose >=4) Cout("sRandomNumberGenerator::GetExtraGenerator..."<< endl);
271  #endif
272 
273  return mp_extraEngines[a_nb];
274 }
#define HPFLTNB
Definition: gVariables.hh:83
Engine & GetExtraGenerator(int a_nb=0)
Get the not thread safe additional random generator, for use various sequential parts of an otherwise...
HPFLTNB GenerateExtraRdmNber(int a_nb=0)
Generate a random number using the specified additional not thread safe random generator, for use in sequential parts of an otherwise multithreaded code.
int Initialize(int a_nbThreads, int a_nbExtra)
Instantiate pseudo random number generators, one per thread by default, and additional extra ones if ...
sRandomNumberGenerator()
Constructor of sRandomNumberGenerator. Do nothing by default as it is a singleton clasee...
HPFLTNB GenerateRdmNber()
Generate a random number for the thread which index is recovered from the OpenMP function.
Singleton class that generate a thread-safe random generator number for openMP As singleton...
Declaration of class sRandomNumberGenerator.
#define Cout(MESSAGE)
static sRandomNumberGenerator * mp_Instance
~sRandomNumberGenerator()
Destructor of sRandomNumberGenerator. Do nothing by default.