ATLAS Offline Software
Loading...
Searching...
No Matches
AtDSFMTGenSvc.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 "interpretSeeds.h"
12#include "AtDSFMTGenSvc.h"
13#include "crc_combine.h"
14
16#include "CLHEP/Random/RandGauss.h"
17
18#include <cassert>
19#include <iostream>
20
21/*FIXME temporarily needed for old seeding scheme*/
23
24using namespace std;
25
27AtDSFMTGenSvc::AtDSFMTGenSvc(const std::string& name,ISvcLocator* svc)
28 : base_class(name,svc),
31 // Set Default values
32 m_default_seed1 = 3591;
33 m_default_seed2 = 2309736;
34 m_PYTHIA_default_seed1 = 93453591;
38}
39
40
43{
44 engineIter i(m_engines.begin()), e(m_engines.end());
45 while (i != e) delete (i++)->second;
46}
47
49{
51 ("Initializing " << name() << "\n INITIALISING RANDOM NUMBER STREAMS. ");
52
54 ServiceHandle<IIncidentSvc> pIncSvc("IncidentSvc", name());
55
56 // set up the incident service:
57 ATH_CHECK( pIncSvc.retrieve() );
58
59 //start listening to "EndEvent"
60 static const int PRIORITY = 100;
61 pIncSvc->addListener(this, "EndEvent", PRIORITY);
62 pIncSvc->addListener(this, "AfterReseedIncident", PRIORITY);
63
64 //and to BeginEvent if we are reseeding
65 if (m_eventReseed) {
66 ATH_MSG_INFO ("will be reseeded for every event");
67 pIncSvc->addListener(this, "BeginEvent", PRIORITY);
68 pIncSvc->addListener(this, "ReseedIncident", PRIORITY);
69 }
70 pIncSvc.release().ignore();
71
72 if (m_read_from_file) {
73 // Read from a file
74 ifstream infile( m_file_to_read.value().c_str() );
75 if ( !infile ) {
76 ATH_MSG_ERROR (" Unable to open: " << m_file_to_read.value());
77 return StatusCode::FAILURE;
78 } else {
79 std::string buffer;
80 while (std::getline(infile, buffer)) {
81 string stream;
82 std::vector<uint32_t> seeds;
83 //split the space-separated string in 3 words:
84 if (interpretSeeds(buffer, stream, seeds)) {
85 msg (MSG::DEBUG)
86 << " INITIALISING " << stream << " stream with seeds ";
87 for (std::vector<uint32_t>::const_iterator i = seeds.begin(); i != seeds.end(); ++i){
88 // The state returned is a set of 32-bit numbers.
89 // On 64-bit platforms, though, the vector holds 64-bit ints.
90 // For the first word, one gets garbage in the high 32 bits.
91 // (This is because the crc32 routine used in clhep
92 // to hash the engine names doesn't mask down to 32 bits.)
93 // So mask off the garbage so that we get consistent results
94 // across platforms.
95 msg() << ((*i) & 0xffffffffu) << " ";
96 }
97 msg() << " read from file " << m_file_to_read.value() << endmsg;
98 if (CreateStream(seeds, stream)) {
99 msg(MSG::DEBUG)
100 << stream << " stream initialized succesfully" <<endmsg;
101 } else {
102 msg(MSG::ERROR)
103 << stream << " stream FAILED to initialize" <<endmsg;
104 return StatusCode::FAILURE;
105 }
106 } else {
107 msg(MSG::ERROR)
108 << "bad line\n" << buffer
109 << "\n in input file " << m_file_to_read.value() << endmsg;
110 return StatusCode::FAILURE;
111 }
112 }
113
114 }
115 }
116 // Create the various streams according to user's request
117 for (const auto& i : m_streams_seeds.value()) {
118 string stream;
119 uint32_t seed1, seed2, offset(0);
120 //parse the stream property string
121 if (interpretSeeds(i, stream, seed1, seed2, offset)) {
122 ATH_MSG_VERBOSE("Seeds property: stream " << stream
123 << " seeds " << seed1 << ' ' << seed2
124 << ", reseeding offset " << offset);
125 } else {
126 ATH_MSG_ERROR("bad Seeds property\n" << i);
127 return StatusCode::FAILURE;
128 }
129
130 // Check if stream already generated (e.g. from reading a file)
131 bool not_found(true);
132 if ( number_of_streams() != 0 ) {
134 while (sf != end() && (not_found=((*sf).first != stream))) ++sf;
135 }
136
137 if (not_found) {
139 (" INITIALISING " << stream << " stream with seeds "
140 << seed1 << " " << seed2);
141 CreateStream(seed1, seed2, stream);
142 if (m_eventReseed) {
143 m_reseedingOffsets.insert(std::make_pair(stream, offset));
144 // apply the offset we just inserted
145 ATH_MSG_DEBUG("Applying reseeding offset " << offset <<
146 " to stream " << stream);
147 this->setOnDefinedSeeds(seed1, seed2, stream);
148 }
149 }
150
151 }
152 return StatusCode::SUCCESS;
153}
154
155void AtDSFMTGenSvc::handle(const Incident &inc) {
156 ATH_MSG_DEBUG (" Handle EndEvent ");
157
158 if ( inc.type() == "EndEvent" ||
159 inc.type() == "AfterReseedIncident" )
160 {
161 m_engines_copy.clear();
162 engineConstIter iE(begin()), eE(end());
163 while(iE != eE) {
164 CLHEP::HepRandomEngine* engine = GetEngine(iE->first);
165 std::vector<unsigned long> v = engine->put();
166 std::vector<uint32_t> tseeds(v.size());
167 for (size_t i=0; i<v.size(); ++i) {
168 // The state returned is a set of 32-bit numbers.
169 // On 64-bit platforms, though, the vector holds 64-bit ints.
170 // For the first word, one gets garbage in the high 32 bits.
171 // (This is because the crc32 routine used in clhep
172 // to hash the engine names doesn't mask down to 32 bits.)
173 // Mask off the garbage to get consistent results
174 // across platforms.
175 tseeds[i] = (v[i] & 0xffffffffu);
176 }
177 m_engines_copy.insert(std::make_pair(iE->first, tseeds));
178 ++iE;
179 }
180
181 print();
182 } else if (inc.type() == "BeginEvent") {
183 ATH_MSG_DEBUG (" Handle BeginEvent ");
184 EventContext context = inc.context();
185 const EventIDBase& ei = context.eventID();
186 //clear static RandGauss cache (generates two numbers per call to shoot()
187 CLHEP::RandGauss::setFlag(false);
188 //loop over generator streams, combining the stream name to the hash
189 vector<string>::const_iterator i(m_reseedStreamNames.begin());
190 vector<string>::const_iterator e(m_reseedStreamNames.end());
191 //by default (when no streams are specified in streamNames, seed all
192 //streams
193 if (i == e) {
194 if (!(this->setAllOnDefinedSeeds(ei.event_number(),
195 ei.run_number())))
196 throw GaudiException("can not reseed all streams ", name(), StatusCode::FAILURE);
197 } else {
198 while (i != e) {
199 const string& strName(*i++);
200 if (0 == this->setOnDefinedSeeds(ei.event_number(),
201 ei.run_number(),
202 strName)) {
203 throw GaudiException(string("can not reseed stream ") + strName,
204 name(), StatusCode::FAILURE);
205 } else {
206 msg() << MSG::VERBOSE << "Reseeded stream " << strName
207 << " for random service " << endmsg;
208 }
209 }
210 }
211 }
212 else if (inc.type() == "ReseedIncident") {
213 typedef ContextIncident<std::pair<unsigned,unsigned> > Ctxt;
214 const Ctxt* incident = dynamic_cast<const Ctxt*>(&inc);
215 if (!incident) {
216 throw GaudiException(string("can not cast to ContextIncident "),
217 name(), StatusCode::FAILURE);
218 }
219 const std::pair<unsigned,unsigned>& data = incident->tag();
220 //clear static RandGauss cache (generates two numbers per call to shoot()
221 CLHEP::RandGauss::setFlag(false);
222 //loop over generator streams, combining the stream name to the hash
223 vector<string>::const_iterator i(m_reseedStreamNames.begin());
224 vector<string>::const_iterator e(m_reseedStreamNames.end());
225 //by default (when no streams are specified in streamNames, seed all
226 //streams
227 if (i == e) {
228 if (!(this->setAllOnDefinedSeeds(data.first,
229 data.second)))
230 throw GaudiException("can not reseed all streams ", name(), StatusCode::FAILURE);
231 } else {
232 while (i != e) {
233 const string& strName(*i++);
234 if (0 == this->setOnDefinedSeeds(data.first,
235 data.second,
236 strName)) {
237 throw GaudiException(string("can not reseed stream ") + strName,
238 name(), StatusCode::FAILURE);
239 } else {
240 msg() << MSG::VERBOSE << "Reseeded stream " << strName
241 << " for random service " << endmsg;
242 }
243 }
244 }
245 }
246}
247
249{
250 ATH_MSG_INFO (" FINALISING ");
251
252 if (m_save_to_file) {
253 // Write the status of the Service to file
254 std::ofstream outfile( m_file_to_write.value().c_str() );
255 if ( !outfile ) {
256 ATH_MSG_ERROR ("error: unable to open: " << m_file_to_write.value());
257 } else {
258 for (std::map<std::string, std::vector<uint32_t> >::const_iterator i = m_engines_copy.begin();
259 i != m_engines_copy.end();
260 ++i) {
261 outfile << (*i).first << " ";
262 for (std::vector<uint32_t>::const_iterator j = (*i).second.begin(); j !=(*i).second.end(); ++j){
263 outfile << (*j) << " ";
264 }
265 outfile << endl;
266 }
267 ATH_MSG_DEBUG (" wrote seeds to " << m_file_to_write.value() );
268 }
269 }
270 return StatusCode::SUCCESS;
271}
272
273CLHEP::HepRandomEngine* AtDSFMTGenSvc::GetEngine ( const std::string& streamName )
274{
275 engineConstIter citer = m_engines.find(streamName);
276 if ( citer == m_engines.end() )
277 {
278 m_engines.insert( engineValType( streamName, new CLHEP::dSFMTEngine() ) );
279 SetStreamSeeds( streamName );
280 }
281
282 engineIter iter = m_engines.find(streamName);
283 return (CLHEP::HepRandomEngine*)(*iter).second;
284}
285
286void AtDSFMTGenSvc::CreateStream(uint32_t seed1, uint32_t seed2, const std::string& streamName )
287{
288 long seeds[3] = { (long)seed1, (long)seed2, 0 };
289 const long* s = seeds;
290 engineConstIter citer = m_engines.find(streamName);
291 if ( citer == m_engines.end() )
292 m_engines.insert(engineValType(streamName, new CLHEP::dSFMTEngine(s)));
293 engineIter iter = m_engines.find(streamName);
294 ((*iter).second)->setSeeds(s, 0);
295}
296
297bool AtDSFMTGenSvc::CreateStream(const std::vector<uint32_t>& seeds, const std::string& streamName)
298{
299 engineConstIter citer = m_engines.find(streamName);
300 if ( citer == m_engines.end() ) m_engines.insert(engineValType(streamName, new CLHEP::dSFMTEngine() ) );
301 engineIter iter = m_engines.find(streamName);
302 std::vector<unsigned long> longSeeds(seeds.size());
303 for (size_t i=0; i<seeds.size(); ++i) longSeeds[i]=seeds[i];
304 return (((*iter).second)->getState( longSeeds ));
305}
306
307void AtDSFMTGenSvc::SetStreamSeeds( const std::string& StreamName )
308{
309 uint32_t seed1;
310 uint32_t seed2;
311 if (StreamName == "PYTHIA")
312 {
315 }
316 else if (StreamName == "HERWIG")
317 {
320 }
321 else
322 {
323 seed1 = m_default_seed1;
324 seed2 = m_default_seed2;
325 }
327 (" INITIALISING " << StreamName << " stream with DEFAULT seeds "
328 << seed1 << " " << seed2);
329
330 long seeds[3] = { (long)seed1, (long)seed2, 0 };
331 const long* s = seeds;
332 engineIter iter = m_engines.find(StreamName);
333 ((*iter).second)->setSeeds(s,0);
334}
335
336void AtDSFMTGenSvc::print(const std::string& StreamName )
337{
338 engineConstIter citer = m_engines.find(StreamName);
339 if ( citer == m_engines.end() ) {
340 ATH_MSG_WARNING (" Stream = " << StreamName << " NOT FOUND");
341 } else {
342 std::vector<unsigned long> v = ((*citer).second)->put();
343 msg(MSG::DEBUG) << " Stream = " << StreamName << " ";
344 for (std::vector<unsigned long>::const_iterator i = v.begin(); i != v.end(); ++i){
345 // The state returned is a set of 32-bit numbers.
346 // On 64-bit platforms, though, the vector holds 64-bit ints.
347 // For the first word, one gets garbage in the high 32 bits.
348 // (This is because the crc32 routine used in clhep
349 // to hash the engine names doesn't mask down to 32 bits.)
350 // So mask off the garbage so that we get consistent results
351 // across platforms.
352 msg() << ((*i) & 0xffffffffu) << " ";
353 }
354 msg() << endmsg;
355 }
356}
357
359{
360 for (engineConstIter i = m_engines.begin(); i != m_engines.end(); ++i)
361 print( (*i).first );
362}
363
364CLHEP::HepRandomEngine* AtDSFMTGenSvc::setOnDefinedSeeds(uint32_t eventNumber, uint32_t runNumber,
365 const std::string& streamName)
366{
367 uint32_t theHash(eventNumber);
369 bool hasOffset(citer != m_reseedingOffsets.end() && 0 != citer->second);
370 if (hasOffset) theHash=crc_combine(theHash, citer->second);
371
372 theHash=crc_combine(theHash, runNumber);
373 ATH_MSG_VERBOSE( "Reseeding stream " << streamName
374 << " with eventNumber " << eventNumber
375 << " runNumber " << runNumber);
376 if (hasOffset) ATH_MSG_VERBOSE("Applied offset " << citer->second);
377 return this->setOnDefinedSeeds(theHash, streamName);
378}
379
380CLHEP::HepRandomEngine* AtDSFMTGenSvc::setOnDefinedSeeds(uint32_t theSeed,
381 const std::string& streamName){
382 engineConstIter citer = m_engines.find(streamName);
384 if ( citer == m_engines.end() )
385 m_engines.insert(engineValType(streamName, new CLHEP::dSFMTEngine() ) );
386
387 engineIter iter = m_engines.find(streamName);
388 theSeed=crc_combine(theSeed, streamName);
389 ATH_MSG_DEBUG("Reseeding stream " << streamName << " with " << theSeed);
390 CLHEP::HepRandomEngine* eng = (*iter).second;
391 eng->setSeed( theSeed, 0 );
392 return eng;
393}
394
395bool
396AtDSFMTGenSvc::setAllOnDefinedSeeds(uint32_t eventNumber, uint32_t runNumber)
397{
398 bool allOK(true);
399 engineIter i(m_engines.begin()), e(m_engines.end());
400 while (i!=e &&
401 (allOK=(0 != this->setOnDefinedSeeds(eventNumber,
402 runNumber,
403 (*i++).first)))) {
404 /*empty*/
405 }
406
407 return allOK;
408}
409
410bool
412 bool allOK(true);
413 engineIter i(m_engines.begin()), e(m_engines.end());
414 while (i!=e &&
415 (allOK=(0 != this->setOnDefinedSeeds(theSeed, (*i++).first)))) {
416 /*empty*/
417 }
418 return allOK;
419}
#define endmsg
A random number engine manager, based on dSFMT.
#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
void SetStreamSeeds(const std::string &StreamName)
Gaudi::Property< std::string > m_file_to_write
name of the file to save the engine status to.
virtual void handle(const Incident &) override
IIncidentListener implementation. Handles EndEvent incident.
engineConstIter end(void) const
unsigned int number_of_streams(void) const
long m_PYTHIA_default_seed1
virtual StatusCode initialize() override
engineMap::const_iterator engineConstIter
virtual void print(void) override
engineMap::value_type engineValType
Gaudi::Property< bool > m_eventReseed
reseed for every event
virtual void CreateStream(uint32_t seed1, uint32_t seed2, const std::string &streamName) override
long m_PYTHIA_default_seed2
virtual CLHEP::HepRandomEngine * setOnDefinedSeeds(uint32_t theSeed, const std::string &streamName) override
virtual ~AtDSFMTGenSvc()
Standard Destructor.
virtual bool setAllOnDefinedSeeds(uint32_t theSeed) override
seed all streams we manage, combining theSeed and the stream names
std::map< std::string, uint32_t > m_reseedingOffsets
optional offsets to combine to run/evt no when reseeding.
virtual StatusCode finalize() override
engineMap m_engines
Gaudi::Property< bool > m_read_from_file
read engine status from file
Gaudi::Property< bool > m_save_to_file
should current engine status be saved to file ?
virtual CLHEP::HepRandomEngine * GetEngine(const std::string &streamName) override
engineMap::iterator engineIter
long m_HERWIG_default_seed2
StringArrayProperty m_reseedStreamNames
streams to be reseeded for every event
engineConstIter begin(void) const
std::map< std::string, std::vector< uint32_t > > m_engines_copy
Random engine copy (for output to a file)
StringArrayProperty m_streams_seeds
seeds for the engines, this is a vector of strings of the form "EnginName Seed1 Seed2"
Gaudi::Property< std::string > m_file_to_read
name of the file to read the engine status from
long m_HERWIG_default_seed1
AtDSFMTGenSvc(const std::string &name, ISvcLocator *svc)
Standard Constructor.
STL iterator class.
bool interpretSeeds(const std::string &buffer, std::string &stream, uint32_t &seed1, uint32_t &seed2, short &luxury, uint32_t &offset)
STL namespace.
MsgStream & msg
Definition testRead.cxx:32