ATLAS Offline Software
Loading...
Searching...
No Matches
AtRanluxGenSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "GaudiKernel/ISvcLocator.h"
6#include "GaudiKernel/IIncidentSvc.h"
7#include "GaudiKernel/Incident.h"
8#include "GaudiKernel/DataIncident.h"
9#include "GaudiKernel/ServiceHandle.h"
10
11#include "CLHEP/Random/Ranlux64Engine.h"
12#include "CLHEP/Random/RandGauss.h"
13
14#include "interpretSeeds.h"
15#include "AtRanluxGenSvc.h"
16#include "crc_combine.h"
17#include <cassert>
18#include <iostream>
19#include <algorithm>
20
21/*FIXME temporarily needed for old seeding scheme*/
23
24using namespace std;
25
26
27
29AtRanluxGenSvc::AtRanluxGenSvc(const std::string& name,ISvcLocator* svc)
30 : base_class(name,svc),
34{
35 // Set Default values
36 m_default_seed1 = 3591;
37 m_default_seed2 = 2309736;
38 m_PYTHIA_default_seed1 = 93453591;
42}
43
44
47{
48 engineIter i(m_engines.begin()), e(m_engines.end());
49 while (i != e) delete (i++)->second;
50}
51
52
53StatusCode
55{
57 ("Initializing " << name()
58 << "\n INITIALISING RANDOM NUMBER STREAMS. ");
59
61 ServiceHandle<IIncidentSvc> pIncSvc("IncidentSvc", name());
62
63 // set up the incident service:
64 ATH_CHECK( pIncSvc.retrieve() );
65
66 //start listening to "EndEvent"
67 static const int PRIORITY = 100;
68 pIncSvc->addListener(this, "EndEvent", PRIORITY);
69 pIncSvc->addListener(this, "AfterReseedIncident", PRIORITY);
70
71 //and to BeginEvent if we are reseeding
72 if (m_eventReseed) {
73 ATH_MSG_INFO ("will be reseeded for every event");
74 pIncSvc->addListener(this, "BeginEvent", PRIORITY);
75 pIncSvc->addListener(this, "ReseedIncident", PRIORITY);
76 }
77 pIncSvc.release().ignore();
78
79
80 //3 is not valid for ranlux, but whatever, that's what we had before...
82
83 if (m_read_from_file) {
84 // Read from a file
85 ifstream infile( m_file_to_read.value().c_str() );
86 if ( !infile ) {
87 ATH_MSG_ERROR (" Unable to open: " << m_file_to_read.value());
88 return StatusCode::FAILURE;
89 } else {
90 std::string buffer;
91 while (std::getline(infile, buffer)) {
92 string stream;
93 std::vector<uint32_t> seeds;
94 //split the space-separated string in 3 words:
95 if (interpretSeeds(buffer, stream, seeds)) {
96 msg (MSG::DEBUG)
97 << " INITIALISING " << stream << " stream with seeds ";
98 for (std::vector<uint32_t>::const_iterator i = seeds.begin(); i != seeds.end(); ++i){
99 // The state returned is a set of 32-bit numbers.
100 // On 64-bit platforms, though, the vector holds 64-bit ints.
101 // For the first word, one gets garbage in the high 32 bits.
102 // (This is because the crc32 routine used in clhep
103 // to hash the engine names doesn't mask down to 32 bits.)
104 // So mask off the garbage so that we get consistent results
105 // across platforms.
106 msg() << ((*i) & 0xffffffffu) << " ";
107 }
108 msg() << " read from file " << m_file_to_read.value() << endmsg;
109 if (CreateStream(seeds, stream)) {
110 msg(MSG::DEBUG)
111 << stream << " stream initialized succesfully" <<endmsg;
112 } else {
113 msg(MSG::ERROR)
114 << stream << " stream FAILED to initialize" <<endmsg;
115 return StatusCode::FAILURE;
116 }
117 } else {
118 msg(MSG::ERROR)
119 << "bad line\n" << buffer
120 << "\n in input file " << m_file_to_read.value() << endmsg;
121 return StatusCode::FAILURE;
122 }
123 }
124
125 }
126 }
127 // Create the various streams according to user's request
128 //for (VStrings::const_iterator i = m_streams_seeds.begin(); i != m_streams_seeds.end(); ++i) {
129 for (const auto& i : m_streams_seeds) {
130 string stream;
131 uint32_t seed1, seed2, offset(0);
132 //parse the stream property string
133 short ll(m_defaultLuxLevel); // temp copy so we don't overwrite default
134 if (interpretSeeds(i, stream, seed1, seed2, ll, offset)) {
135 ATH_MSG_VERBOSE("Seeds property: stream " << stream
136 << " seeds " << seed1 << ' ' << seed2
137 << ", luxury level " << ll
138 << ", reseeding offset " << offset);
139 } else {
140 ATH_MSG_ERROR("bad Seeds property\n" << i);
141 return StatusCode::FAILURE;
142 }
143
144 // Check if stream already generated (e.g. from reading a file)
145 bool not_found(true);
146 if ( number_of_streams() != 0 ) {
148 while (sf != end() && (not_found=((*sf).first != stream))) ++sf;
149 }
150
151 if (not_found) {
153 (" INITIALISING " << stream << " stream with seeds "
154 << seed1 << " " << seed2);
155 createStream(seed1, seed2, stream, ll);
156 if (m_eventReseed) {
157 m_reseedingOffsets.insert(std::make_pair(stream, offset));
158 // apply the offset we just inserted
159 ATH_MSG_DEBUG("Applying reseeding offset " << offset <<
160 " to stream " << stream);
161 this->setOnDefinedSeeds(seed1, seed2, stream);
162 }
163 }
164
165 }
166 return StatusCode::SUCCESS;
167}
168
169void
170AtRanluxGenSvc::handle(const Incident &inc) {
171 ATH_MSG_DEBUG (" Handle EndEvent ");
172
173 if ( inc.type() == "EndEvent" ||
174 inc.type() == "AfterReseedIncident" )
175 {
176
177 m_engines_copy.clear();
178 engineConstIter iE(begin()), eE(end());
179 while(iE != eE) {
180 CLHEP::HepRandomEngine* engine = GetEngine(iE->first);
181 std::vector<unsigned long> v = engine->put();
182 std::vector<uint32_t> tseeds(v.size());
183 for (size_t i=0; i<v.size(); ++i) {
184 // The state returned is a set of 32-bit numbers.
185 // On 64-bit platforms, though, the vector holds 64-bit ints.
186 // For the first word, one gets garbage in the high 32 bits.
187 // (This is because the crc32 routine used in clhep
188 // to hash the engine names doesn't mask down to 32 bits.)
189 // Mask off the garbage to get consistent results
190 // across platforms.
191 tseeds[i] = (v[i] & 0xffffffffu);
192 }
193 m_engines_copy.insert(std::make_pair(iE->first, tseeds));
194 ++iE;
195 }
196
197 print();
198 } else if (inc.type() == "BeginEvent") {
199 ATH_MSG_DEBUG (" Handle BeginEvent ");
200 EventContext context = inc.context();
201 const EventIDBase& ei = context.eventID();
202 //clear static RandGauss cache (generates two numbers per call to shoot()
203 CLHEP::RandGauss::setFlag(false);
204 //loop over generator streams, combining the stream name to the hash
205 vector<string>::const_iterator i(m_reseedStreamNames.begin());
206 vector<string>::const_iterator e(m_reseedStreamNames.end());
207 //by default (when no streams are specified in streamNames, seed all
208 //streams
209 if (i == e) {
210 if (!(this->setAllOnDefinedSeeds(ei.event_number(),
211 ei.run_number())))
212 throw GaudiException("can not reseed all streams ", name(), StatusCode::FAILURE);
213 } else {
214 while (i != e) {
215 const string& strName(*i++);
216 if (0 == this->setOnDefinedSeeds(ei.event_number(),
217 ei.run_number(),
218 strName)) {
219 throw GaudiException(string("can not reseed stream ") + strName,
220 name(), StatusCode::FAILURE);
221 } else {
222 msg() << MSG::VERBOSE << "Reseeded stream " << strName
223 << " for random service " << endmsg;
224 }
225 }
226 }
227 }
228 else if (inc.type() == "ReseedIncident") {
229 typedef ContextIncident<std::pair<unsigned,unsigned> > Ctxt;
230 const Ctxt* incident = dynamic_cast<const Ctxt*>(&inc);
231 if (!incident) {
232 throw GaudiException(string("can not cast to ContextIncident "),
233 name(), StatusCode::FAILURE);
234 }
235 const std::pair<unsigned,unsigned>& data = incident->tag();
236 //clear static RandGauss cache (generates two numbers per call to shoot()
237 CLHEP::RandGauss::setFlag(false);
238 //loop over generator streams, combining the stream name to the hash
239 vector<string>::const_iterator i(m_reseedStreamNames.begin());
240 vector<string>::const_iterator e(m_reseedStreamNames.end());
241 //by default (when no streams are specified in streamNames, seed all
242 //streams
243 if (i == e) {
244 if (!(this->setAllOnDefinedSeeds(data.first,
245 data.second)))
246 throw GaudiException("can not reseed all streams ", name(), StatusCode::FAILURE);
247 } else {
248 while (i != e) {
249 const string& strName(*i++);
250 if (0 == this->setOnDefinedSeeds(data.first,
251 data.second,
252 strName)) {
253 throw GaudiException(string("can not reseed stream ") + strName,
254 name(), StatusCode::FAILURE);
255 } else {
256 msg() << MSG::VERBOSE << "Reseeded stream " << strName
257 << " for random service " << endmsg;
258 }
259 }
260 }
261 }
262}
263
264StatusCode
266{
267 ATH_MSG_INFO (" FINALISING ");
268
269 if (m_save_to_file) {
270 // Write the status of the Service to file
271 std::ofstream outfile( m_file_to_write.value().c_str() );
272 if ( !outfile ) {
273 ATH_MSG_ERROR ("error: unable to open: " << m_file_to_write.value());
274 } else {
275 for (std::map<std::string, std::vector<uint32_t> >::const_iterator i = m_engines_copy.begin();
276 i != m_engines_copy.end();
277 ++i) {
278 outfile << (*i).first << " ";
279 for (std::vector<uint32_t>::const_iterator j = (*i).second.begin(); j !=(*i).second.end(); ++j){
280 outfile << (*j) << " ";
281 }
282 outfile << endl;
283 }
284 ATH_MSG_DEBUG (" wrote seeds to " << m_file_to_write.value() );
285
286 }
287 }
288 return StatusCode::SUCCESS;
289}
290
291CLHEP::HepRandomEngine*
292AtRanluxGenSvc::GetEngine ( const std::string& StreamName )
293{
294 engineConstIter citer = m_engines.find(StreamName);
295 if ( citer == m_engines.end() )
296 {
297 m_engines.insert( engineValType( StreamName, new CLHEP::Ranlux64Engine() ) );
298 SetStreamSeeds ( StreamName );
299 }
300
301 engineIter iter = m_engines.find(StreamName);
302 return (CLHEP::HepRandomEngine*)(*iter).second;
303}
304
305void
306AtRanluxGenSvc::CreateStream(uint32_t seed1, uint32_t seed2,
307 const std::string& streamName) {
308 createStream(seed1, seed2, streamName, m_defaultLuxLevel);
309}
310
311void
312AtRanluxGenSvc::createStream(uint32_t seed1, uint32_t seed2,
313 const std::string& streamName, short luxLevel )
314{
315 uint32_t seeds[2] = { seed1, seed2 };
316 const uint32_t* s = seeds;
317 engineConstIter citer = m_engines.find(streamName);
318 if ( citer == m_engines.end() )
319 m_engines.insert(engineValType(streamName,
320 new CLHEP::Ranlux64Engine(s[0], luxLevel)));
321 engineIter iter = m_engines.find(streamName);
322 ((*iter).second)->setSeed(s[0], luxLevel);
323}
324
325bool
326AtRanluxGenSvc::CreateStream(const std::vector<uint32_t>& seeds,
327 const std::string& streamName)
328{
329 engineConstIter citer = m_engines.find(streamName);
330 if ( citer == m_engines.end() )
331 m_engines.insert(engineValType(streamName,
332 new CLHEP::Ranlux64Engine() ) );
333 engineIter iter = m_engines.find(streamName);
334 std::vector<unsigned long> longSeeds(seeds.size());
335 for (size_t i=0; i<seeds.size(); ++i) longSeeds[i]=seeds[i];
336 return (((*iter).second)->getState( longSeeds ));
337}
338
339void
340AtRanluxGenSvc::SetStreamSeeds ( const std::string& StreamName )
341{
342 uint32_t seed1;
343 uint32_t seed2;
344 if (StreamName == "PYTHIA")
345 {
348 }
349 else if (StreamName == "HERWIG")
350 {
353 }
354 else
355 {
356 seed1 = m_default_seed1;
357 seed2 = m_default_seed2;
358 }
360 (" INITIALISING " << StreamName << " stream with DEFAULT seeds "
361 << seed1 << " " << seed2);
362
363 uint32_t seeds[2] = { seed1, seed2 };
364 const uint32_t* s = seeds;
365 engineIter iter = m_engines.find(StreamName);
366 ((*iter).second)->setSeed(s[0]); //FIXME no need to set luxLevel?
367}
368
369void
370AtRanluxGenSvc::print(const std::string& StreamName )
371{
372 engineConstIter citer = m_engines.find(StreamName);
373 if ( citer == m_engines.end() ) {
374 ATH_MSG_WARNING (" Stream = " << StreamName << " NOT FOUND");
375 } else {
376 std::vector<unsigned long> v = ((*citer).second)->put();
377 msg(MSG::INFO) << " Stream = " << StreamName << " ";
378 for (std::vector<unsigned long>::const_iterator i = v.begin(); i != v.end(); ++i){
379 // The state returned is a set of 32-bit numbers.
380 // On 64-bit platforms, though, the vector holds 64-bit ints.
381 // For the first word, one gets garbage in the high 32 bits.
382 // (This is because the crc32 routine used in clhep
383 // to hash the engine names doesn't mask down to 32 bits.)
384 // So mask off the garbage so that we get consistent results
385 // across platforms.
386 msg() << ((*i) & 0xffffffffu) << " ";
387 }
388 msg() << endmsg;
389 }
390}
391
392void
394{
395 for (engineConstIter i = m_engines.begin(); i != m_engines.end(); ++i)
396 print( (*i).first );
397}
398
399CLHEP::HepRandomEngine*
400AtRanluxGenSvc::setOnDefinedSeeds(uint32_t eventNumber, uint32_t runNumber,
401 const std::string& streamName)
402{
404 return oldSetOnDefinedSeeds(eventNumber, runNumber, streamName);
405 // do it properly
406 uint32_t theHash(eventNumber);
408 bool hasOffset(citer != m_reseedingOffsets.end() && 0 != citer->second);
409 if (hasOffset) theHash=crc_combine(theHash, citer->second);
410
411 theHash=crc_combine(theHash, runNumber);
412 ATH_MSG_VERBOSE( "Reseeding stream " << streamName
413 << " with eventNumber " << eventNumber
414 << " runNumber " << runNumber);
415 if (hasOffset) ATH_MSG_VERBOSE("Applied offset " << citer->second);
416 return this->setOnDefinedSeeds(theHash, streamName);
417}
418
419CLHEP::HepRandomEngine*
421 const std::string& streamName){
423 return oldSetOnDefinedSeeds(theSeed, streamName);
424 //do it propertly
425 engineConstIter citer = m_engines.find(streamName);
427 if ( citer == m_engines.end() )
428 m_engines.insert(engineValType(streamName,
429 new CLHEP::Ranlux64Engine() ) );
430
431 engineIter iter = m_engines.find(streamName);
432 theSeed=crc_combine(theSeed, streamName);
433 ATH_MSG_DEBUG("Reseeding stream " << streamName << " with " << theSeed);
434 CLHEP::Ranlux64Engine* eng = (*iter).second;
435 //Ranlux64 takes a long as seed and makes a test on the sign of the seed
436 //so let's make sure that our seed is presented to Ranlux64 as a 32 bit
437 //signed int
438 eng->setSeed( (int32_t)theSeed, eng->getLuxury() );
439 return eng;
440}
441
442
443CLHEP::HepRandomEngine*
444AtRanluxGenSvc::oldSetOnDefinedSeeds(uint32_t eventNumber, uint32_t runNumber,
445 const std::string& streamName)
446{
447 engineConstIter citer = m_engines.find(streamName);
448 if ( citer == m_engines.end() )
449 m_engines.insert( engineValType(streamName, new CLHEP::Ranlux64Engine() ) );
450 engineIter iter = m_engines.find(streamName);
451 int hashedStream(SG::simpleStringHash(streamName));
452 long seeds[2] = { (long)(1000*runNumber + hashedStream),
453 (long)eventNumber };
454 assert( seeds[0] > 0 );
455 assert( seeds[1] > 0 );
456 const long* s = seeds;
457 ((*iter).second)->setSeed( s[0], m_defaultLuxLevel);
458 return (CLHEP::HepRandomEngine*)(*iter).second;
459}
460
461CLHEP::HepRandomEngine*
463 const std::string& streamName){
464 engineConstIter citer = m_engines.find(streamName);
465 if ( citer == m_engines.end() )
466 m_engines.insert( engineValType(streamName, new CLHEP::Ranlux64Engine() ) );
467 engineIter iter = m_engines.find(streamName);
468 int hashedStream(SG::simpleStringHash(streamName));
469 long seeds[2] = { (long)(hashedStream % (theSeed+13)),
470 (long)theSeed };
471 assert( seeds[0] > 0 );
472 assert( seeds[1] > 0 );
473 const long* s = seeds;
474 ((*iter).second)->setSeed( s[0], m_defaultLuxLevel );
475 return (CLHEP::HepRandomEngine*)(*iter).second;
476}
477
478
479bool
480AtRanluxGenSvc::setAllOnDefinedSeeds(uint32_t eventNumber, uint32_t runNumber)
481{
482 bool allOK(true);
483 engineIter i(m_engines.begin()), e(m_engines.end());
484 while (i!=e &&
485 (allOK=(0 != this->setOnDefinedSeeds(eventNumber,
486 runNumber,
487 (*i++).first)))) {
488 /*empty*/
489 }
490 return allOK;
491}
492
493bool
495 bool allOK(true);
496 engineIter i(m_engines.begin()), e(m_engines.end());
497 while (i!=e &&
498 (allOK=(0 != this->setOnDefinedSeeds(theSeed, (*i++).first)))) {
499 /*empty*/
500 }
501 return allOK;
502}
#define endmsg
The default ATLAS random number engine manager, based on Ranlux64.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
uint32_t crc_combine(uint32_t seed, uint32_t v)
using crc32 for architecture independence in combining the seeds
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
uint32_t m_PYTHIA_default_seed2
uint32_t m_HERWIG_default_seed1
virtual void CreateStream(uint32_t seed1, uint32_t seed2, const std::string &streamName) override
void SetStreamSeeds(const std::string &streamName)
AtRanluxGenSvc(const std::string &name, ISvcLocator *svc)
Standard Gaudi Constructor.
unsigned int number_of_streams(void) const
engineConstIter end(void) const
std::map< std::string, uint32_t > m_reseedingOffsets
optional offsets to combine to run/evt no when reseeding.
short m_defaultLuxLevel
Ranlux luxury level to be used by default.
virtual ~AtRanluxGenSvc()
Standard Destructor.
Gaudi::Property< std::string > m_file_to_read
name of the file to read the engine status from
virtual bool setAllOnDefinedSeeds(uint32_t theSeed) override
seed all streams we manage, combining theSeed and the stream names
virtual StatusCode initialize() override
StringArrayProperty m_reseedStreamNames
streams to be reseeded for every event
void createStream(uint32_t seed1, uint32_t seed2, const std::string &streamName, short luxLevel)
allows to specify luxLevel
std::map< std::string, std::vector< uint32_t > > m_engines_copy
Random engine copy (for output to a file)
uint32_t m_default_seed1
engineConstIter begin(void) const
engineMap::iterator engineIter
CLHEP::HepRandomEngine * oldSetOnDefinedSeeds(uint32_t theSeed, const std::string &streamName)
broken, temporarily keep for backward compatibility
virtual StatusCode finalize() override
StringArrayProperty m_streams_seeds
seeds for the engines, this is a vector of strings of the form "EnginName Seed1 Seed2"
virtual CLHEP::HepRandomEngine * setOnDefinedSeeds(uint32_t theSeed, const std::string &streamName) override
uint32_t m_default_seed2
Gaudi::Property< bool > m_eventReseed
reseed for every event
Gaudi::Property< std::string > m_file_to_write
name of the file to save the engine status to.
engineMap::const_iterator engineConstIter
uint32_t m_HERWIG_default_seed2
virtual CLHEP::HepRandomEngine * GetEngine(const std::string &streamName) override
engineMap::value_type engineValType
Gaudi::Property< bool > m_read_from_file
read engine status from file
virtual void print(void) override
Gaudi::Property< bool > m_save_to_file
should current engine status be saved to file ?
engineMap m_engines
uint32_t m_PYTHIA_default_seed1
Gaudi::Property< bool > m_useOldBrokenSeeding
backward compatibility only, broken 32/64 bits
virtual void handle(const Incident &) override
IIncidentListener implementation. Handles EndEvent incident.
STL iterator class.
bool interpretSeeds(const std::string &buffer, std::string &stream, uint32_t &seed1, uint32_t &seed2, short &luxury, uint32_t &offset)
int simpleStringHash(const std::string &str, int maxInt=0xFFFF)
simple hash function derived from Sedgewick Algorithms in C++ 3rd ed
STL namespace.
MsgStream & msg
Definition testRead.cxx:32