ATLAS Offline Software
Loading...
Searching...
No Matches
Pythia8_i.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
8
10#include <ranges>
11#include <charconv>
12
13// calls to fortran routines
16
17#include <sstream>
18// For limits
19#include <limits>
20
21
22namespace {
23 // Name of random number stream
24 std::string s_pythia_stream{"PYTHIA8_INIT"};
25}
26
27
28// fix Pythia8 shower weights change in conventions
29#define PYTHIA8_NWEIGHTS nWeights
30#define PYTHIA8_WEIGHT weight
31#define PYTHIA8_WLABEL weightLabel
32#define PYTHIA8_CONVERSION 1.0
33
34#ifdef PYTHIA_VERSION_INTEGER
35 #undef PYTHIA8_NWEIGHTS
36 #undef PYTHIA8_WEIGHT
37 #undef PYTHIA8_WLABEL
38 #if PYTHIA_VERSION_INTEGER > 8303
39 #define PYTHIA8_NWEIGHTS nWeightGroups
40 #else
41 #define PYTHIA8_NWEIGHTS nVariationGroups
42 #endif
43 #define PYTHIA8_WEIGHT getGroupWeight
44 #define PYTHIA8_WLABEL getGroupName
45#endif
46
50
51namespace {
52
53std::string py8version()
54{
55 static const std::string incdir (PY8INCLUDE_DIR);
56 std::string::size_type pos = incdir.find ("/pythia8/");
57 if (pos == std::string::npos) return "";
58 pos += 9;
59 std::string::size_type pos2 = incdir.find ("/", pos);
60 if (pos2 == std::string::npos) pos2 = incdir.size();
61 return incdir.substr (pos, pos2-pos);
62}
63
64
65}
66
68Pythia8_i::Pythia8_i(const std::string &name, ISvcLocator *pSvcLocator)
69: GenModule(name, pSvcLocator)
70{
71 m_particleIDs["PROTON"] = PROTON;
72 m_particleIDs["ANTIPROTON"] = ANTIPROTON;
73 m_particleIDs["ELECTRON"] = ELECTRON;
74 m_particleIDs["POSITRON"] = POSITRON;
75 m_particleIDs["NEUTRON"] = NEUTRON;
76 m_particleIDs["ANTINEUTRON"] = ANTINEUTRON;
77 m_particleIDs["MUON"] = MUON;
78 m_particleIDs["ANTIMUON"] = ANTIMUON;
79 m_particleIDs["LEAD"] = LEAD;
80 m_particleIDs["OXYGEN"] = OXYGEN;
81 m_particleIDs["HELIUM"] = HELIUM;
82
83}
84
87
88 #ifndef PYTHIA8_3SERIES
89// if(m_userHookPtr != 0) delete m_userHookPtr;
90
91// for(UserHooksPtrType ptr: m_userHooksPtrs){
92// delete ptr;
93// }
94 #endif
95}
96
99
100 ATH_MSG_DEBUG("Pythia8_i from genInitialize()");
101
102 ATH_MSG_INFO("XML Path is " + xmlpath());
103 m_pythia = std::make_unique<Pythia8::Pythia> (xmlpath());
104#ifdef HEPMC3
105 m_runinfo = std::make_shared<HepMC3::GenRunInfo>();
107 struct HepMC3::GenRunInfo::ToolInfo generator={std::string("Pythia8"),py8version(),std::string("Used generator")};
108 m_runinfo->tools().push_back(std::move(generator));
109#endif
110
111 bool canInit = true;
112
113 m_version = m_pythia->settings.parm("Pythia:versionNumber");
114
115 s_pythia_stream = "PYTHIA8_INIT";
116
117 // By default add "nominal" to the list of shower weight names
119 m_showerWeightNames.insert(m_showerWeightNames.begin(), "nominal");
120
121 // We do explicitly set tune 4C, since it is the starting point for many other tunes
122 // Tune 4C for pp collisions
123 m_pythia->readString("Tune:pp = 5");
124
125 // also use CTEQ6L1 from LHAPDF 6 by default
126 // can be over-written using JO
127 m_pythia->readString("PDF:pSet= LHAPDF6:cteq6l1");
128
129 // switch off verbose event print out
130 m_pythia->readString("Next:numberShowEvent = 0");
131
132 // Add flag to switch off from JO the Pythia8ToHepMC::print_inconsistency internal variable
133 m_pythia->settings.addFlag("AthenaPythia8ToHepMC:print_inconsistency",true);
134
135 // Revert the recoil strategy to the old default of 1, ie. 'recoil to color'
136 // In 8.314, the default option was changed to 0, 'recoil to top' and we
137 // revert it back unless 'recoil to top'
138 // is explicitly needed for the samples
139 if (m_version > 8.313) m_pythia->readString("TimeShower:recoilStrategyRF = 1");
140
141 // Add UserHooks first because these potentially add new settings that must exist prior to parsing commands
142
143 for(const auto &hook: m_userHooks){
144 ATH_MSG_INFO("Adding user hook " + hook + ".");
145 bool canSetHook = true;
146 if (hook == "SuppressSmallPT") {
147 m_SuppressSmallPT = new Pythia8::SuppressSmallPT(m_pt0timesMPI,m_numberAlphaS,m_sameAlphaSAsMPI);
148 canSetHook=m_pythia->setUserHooksPtr(PYTHIA8_PTRWRAP(m_SuppressSmallPT));
149}
150 else {
152 canSetHook = m_pythia->addUserHooksPtr(m_userHooksPtrs.back());
153}
154 if(!canSetHook){
155 ATH_MSG_ERROR("Unable to set requested user hook.");
156 ATH_MSG_ERROR("Pythia 8 initialisation will FAIL!");
157 canInit=false;
158 }
159 }
160
161 for(const std::pair<const std::string, double> &param : Pythia8_UserHooks::UserHooksFactory::userSettings<double>()){
162 m_pythia->settings.addParm(param.first, param.second, false, false, 0., 0.);
163 }
164
165 for(const std::pair<const std::string, int> &param : Pythia8_UserHooks::UserHooksFactory::userSettings<int>()){
166 m_pythia->settings.addMode(param.first, param.second, false, false, 0., 0.);
167 }
168
169 for(const std::pair<const std::string, bool> &param : Pythia8_UserHooks::UserHooksFactory::userSettings<bool>()){
170 m_pythia->settings.addFlag(param.first, param.second);
171 }
172
173 for(const std::pair<const std::string, std::string> &param : Pythia8_UserHooks::UserHooksFactory::userSettings<std::string>()){
174 m_pythia->settings.addWord(param.first, param.second);
175 }
176
177 if( ! m_athenaTool.empty() ){
178 if(m_athenaTool.retrieve().isFailure()){
179 ATH_MSG_ERROR("Unable to retrieve Athena Tool for custom Pythia processing");
180 return StatusCode::FAILURE;
181 }
182 else {
183 StatusCode status = m_athenaTool->InitializePythiaInfo(*m_pythia);
184 if(status != StatusCode::SUCCESS) return status;
185 }
186 }
187
188 // Now apply the settings from the JO
189 for(const std::string &cmd : m_commands){
190
191 if(cmd.compare("")==0) continue;
192 else if (cmd.find("Beams:id") != std::string::npos ) {
193 ATH_MSG_ERROR("With command '" << cmd << "' you are trying to set a beam different from p: please use the Beam1/Beam2 properties instead:");
194 ATH_MSG_ERROR(" example: genSeq.Pythia8.Beam1 = 'LEAD'");
195 ATH_MSG_ERROR(" genSeq.Pythia8.Beam2 = 'ANTINEUTRON'");
196 return StatusCode::FAILURE;
197 }
198 else if (cmd.find("Beams:frameType") != std::string::npos ) {
200 ATH_MSG_WARNING(" Found an explicit 'Beams:frameType' command: this will override transform beams momenta/energy parameters, regardless of its requested value. ");
201 }
202
203 bool read = m_pythia->readString(cmd);
204
205 if(!read){
206 ATH_MSG_ERROR("Pythia could not understand the command '"<< cmd<<"'");
207 return StatusCode::FAILURE;
208 }
209 }
210
211 PDGID beam1 = m_particleIDs[m_beam1];
212 PDGID beam2 = m_particleIDs[m_beam2];
213
214 ATH_MSG_INFO("Beam1 = "<<beam1);
215 ATH_MSG_INFO("Beam2 = "<<beam2);
216
217 if(beam1 == 0 || beam2 == 0){
218 ATH_MSG_ERROR("Invalid beam particle!");
219 return StatusCode::FAILURE;
220 }
221
222
223
224 if(m_useRndmGenSvc){
225
226 ATH_MSG_INFO(" !!!!!!!!!!!! WARNING ON PYTHIA RANDOM NUMBERS !!!!!!!!!! ");
227 ATH_MSG_INFO(" THE ATHENA SERVICE AthRNGenSvc IS USED.");
228 ATH_MSG_INFO(" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ");
229
230 m_atlasRndmEngine = std::make_shared<customRndm>();
231 CLHEP::HepRandomEngine* rndmEngine = getRandomEngineDuringInitialize(s_pythia_stream, m_randomSeed, m_dsid); // NOT THREAD-SAFE
232 m_atlasRndmEngine->init(rndmEngine);
233#if PYTHIA_VERSION_INTEGER >= 8310
234 m_pythia->setRndmEnginePtr(m_atlasRndmEngine);
235#else
236 m_pythia->setRndmEnginePtr(m_atlasRndmEngine.get());
237#endif
238 s_pythia_stream = "PYTHIA8";
239 }else{
240 ATH_MSG_INFO(" !!!!!!!!!!!! WARNING ON PYTHIA RANDOM NUMBERS !!!!!!!!!! ");
241 ATH_MSG_INFO(" THE STANDARD PYTHIA8 RANDOM NUMBER SERVICE IS USED.");
242 ATH_MSG_INFO(" THE ATHENA SERVICE AthRNGSvc IS ***NOT*** USED.");
243 ATH_MSG_INFO(" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ");
244 }
245
246 if(m_userProcess != ""){
248 }
249
250
251
252 if(m_userResonances.value() != ""){
253
254 std::vector<std::string> resonanceArgs;
255
256 for (auto&& part : std::views::split(m_userResonances.value(), ':')) resonanceArgs.emplace_back(part.begin(), part.end());
257 if(resonanceArgs.size() != 2){
258 ATH_MSG_ERROR("Cannot Understand UserResonance job option!");
259 ATH_MSG_ERROR("You should specify it as a 'name:id1,id2,id3...'");
260 ATH_MSG_ERROR("Where name is the name of your UserResonance, and id1,id2,id3 are a comma separated list of PDG IDs to which it is applied");
261 canInit = false;
262 }
263 std::vector<std::string> resonanceIds;
264 for (auto&& part : std::views::split(resonanceArgs.back(), ',')) resonanceIds.emplace_back(part.begin(), part.end());
265 if(resonanceIds.size()==0){
266 ATH_MSG_ERROR("You did not specifiy any PDG ids to which your user resonance width should be applied!");
267 ATH_MSG_ERROR("You should specify a list as 'name:id1,id2,id3...'");
268 ATH_MSG_ERROR("Where name is the name of your UserResonance, and id1,id2,id3 are a comma separated list of PDG IDs to which it is applied");
269 canInit=false;
270 }
271
272 for(std::vector<std::string>::const_iterator sId = resonanceIds.begin();
273 sId != resonanceIds.end(); ++sId){
274 int idResIn = 0;
275 auto result = std::from_chars(sId->data(), sId->data() + sId->size(), idResIn);
276 if (result.ec != std::errc()) {
277 ATH_MSG_ERROR("Invalid resonance ID: " + *sId);
278 }
279 m_userResonancePtrs.push_back(Pythia8_UserResonance::UserResonanceFactory::create(resonanceArgs.front(), idResIn));
280 }
281
282 for(std::shared_ptr<Pythia8::ResonanceWidths>& resonance : m_userResonancePtrs) {
283#if PYTHIA_VERSION_INTEGER >= 8310
284 m_pythia->setResonancePtr(resonance);
285#else
286 m_pythia->setResonancePtr(resonance.get());
287#endif
288 }
289
290 }
291
292 if(m_particleDataFile != "") {
293 if(!m_pythia->particleData.reInit(m_particleDataFile, true)){
294 ATH_MSG_ERROR("Unable to read requested particle data table: " + m_particleDataFile + " !!");
295 ATH_MSG_ERROR("Pythia 8 initialisation will FAIL!");
296 canInit = false;
297 }
298 }
299
300 if(m_lheFile != ""){
301 if(m_procPtr){
302 ATH_MSG_ERROR("Both LHE file and user process have been specified");
303 ATH_MSG_ERROR("LHE input does not make sense with a user process!");
304 canInit = false;
305 }
306
307 canInit = canInit && m_pythia->readString("Beams:frameType = 4");
308 canInit = canInit && m_pythia->readString("Beams:LHEF = " + m_lheFile);
309 if(!canInit){
310 ATH_MSG_ERROR("Unable to read requested LHE file: " + m_lheFile + " !");
311 ATH_MSG_ERROR("Pythia 8 initialisation will FAIL!");
312 }
313 }else{
315 canInit = canInit && m_pythia->readString("Beams:frameType = 1");
316 canInit = canInit && m_pythia->readString("Beams:eCM = " + std::to_string(m_collisionEnergy));
317 }
318 canInit = canInit && m_pythia->readString("Beams:idA = " + std::to_string(beam1));
319 canInit = canInit && m_pythia->readString("Beams:idB = " + std::to_string(beam2));
320 }
321
322 if(m_procPtr){
323#if PYTHIA_VERSION_INTEGER >= 8310
324 if(!m_pythia->setSigmaPtr(m_procPtr))
325#else
326 if(!m_pythia->setSigmaPtr(m_procPtr.get()))
327#endif
328 {
329 ATH_MSG_ERROR("Unable to set requested user process: " + m_userProcess + " !!");
330 ATH_MSG_ERROR("Pythia 8 initialisation will FAIL!");
331 canInit = false;
332 }
333 }
334
335 StatusCode returnCode = StatusCode::SUCCESS;
336
337 m_pythia->particleData.listXML(m_outputParticleDataFile.value().substr(0,m_outputParticleDataFile.value().find("xml"))+"orig.xml");
338 m_pythia->settings.writeFile("Settings_before.log",true);
339
340 if(canInit){
341 canInit = m_pythia->init();
342 }
343
344 if(!canInit){
345 returnCode = StatusCode::FAILURE;
346 ATH_MSG_ERROR(" *** Unable to initialise Pythia !! ***");
347 }
348
349 m_pythia->particleData.listXML(m_outputParticleDataFile);
350 m_pythia->settings.writeFile("Settings_after.log",true);
351
352 //counter for event failures;
353 m_failureCount = 0;
354
356
357 // Set set_print_inconsistency to Athena corresponding flag (allowing to change it from JO)
358 m_pythiaToHepMC.set_print_inconsistency( m_pythia->settings.flag("AthenaPythia8ToHepMC:print_inconsistency") );
359
360 m_pythiaToHepMC.set_store_pdf(true);
361 m_pythiaToHepMC.set_store_weights(false);
362
363 return returnCode;
364}
365
368
369 ATH_MSG_DEBUG(">>> Pythia8_i from callGenerator");
371 //Re-seed the random number stream
372 long seeds[7];
373 const EventContext& ctx = Gaudi::Hive::currentContext();
374 ATHRNG::calculateSeedsMC21(seeds, s_pythia_stream, ctx.eventID().event_number(), m_dsid, m_randomSeed);
375 m_atlasRndmEngine->getEngine()->setSeeds(seeds, 0); // NOT THREAD-SAFE
376 m_seeds.clear();
377 m_seeds.push_back(seeds[0]);
378 m_seeds.push_back(seeds[1]);
379 }
380
381 bool status = m_pythia->next();
382
383 StatusCode returnCode = StatusCode::SUCCESS;
384
385 if(!status){
388 ATH_MSG_ERROR("Exceeded the max number of consecutive event failures.");
389 returnCode = StatusCode::FAILURE;
390 }else{
391 ATH_MSG_INFO("Event generation failed - re-trying.");
392 returnCode = this->callGenerator();
393 }
394 }
395
396 ATH_MSG_DEBUG("Now checking with Tool.empty() second time");
397 if( ! m_athenaTool.empty() ){
398 StatusCode stat = m_athenaTool->ModifyPythiaEvent(*m_pythia);
399 if(stat != StatusCode::SUCCESS) returnCode = stat;
400 }
401
402 m_failureCount = 0;
403
404 m_nAccepted += 1.;
405 // some CKKWL merged events have zero weight (or unfilled event).
406 // start again with such events
407
408 double eventWeight = m_pythia->info.mergingWeight()*m_pythia->info.weight();
409
410
411 if(returnCode != StatusCode::FAILURE &&
412 // Here this is a double, but it may be converted into float at some point downstream
413 (std::abs(eventWeight) < std::numeric_limits<float>::min() ||
414 m_pythia->event.size() < 2)){
415
416 returnCode = this->callGenerator();
417 } else if ( std::abs(eventWeight) < std::numeric_limits<float>::min() &&
418 std::abs(eventWeight) > std::numeric_limits<double>::min() ){
419 ATH_MSG_WARNING("Found event weight " << eventWeight << " between the float and double precision limits. Rejecting event.");
420 } else {
421 m_nMerged += eventWeight;
423
424 // For FxFx cross section:
425 m_sigmaTotal+=m_pythia->info.weight();
426 }
427
428 return returnCode;
429}
430
432StatusCode Pythia8_i::fillEvt(HepMC::GenEvent *evt){
433
434 ATH_MSG_DEBUG(">>> Pythia8_i from fillEvt");
435
436 evt->set_event_number(m_internal_event_number);
437
438 // if using "getGroupWeight" and | lhastrategy | = 4, then need to convert mb to pb ( done otherwise when calling info.weight(), [...] )
439 if( m_internal_event_number == 1 && std::abs(m_pythia->info.lhaStrategy()) == 4 ) {
440 m_conversion = ( (double) PYTHIA8_CONVERSION);
441 ATH_MSG_DEBUG(" LHA strategy needs a conversion to fix Pythia8 shower weights bug(s) equal to " << m_conversion);
442 }
443
444
445 if(m_pythia->event.size() < 2){
446 ATH_MSG_ERROR("Something wrong with this event - it contains fewer than 2 particles!");
447 ATH_MSG_ERROR("internal event number is "<<m_internal_event_number);
448 return StatusCode::FAILURE;
449 }
450
451 m_pythiaToHepMC.fill_next_event(*m_pythia, evt, m_internal_event_number);
452
453 // In case we're asked, save the LHE event as an attribute. This only works in HEPMC3.
454 if(m_saveLHE){
455#ifdef HEPMC3
456 auto evtlhe = std::make_shared<HepMC::GenEvent>();
457 m_pythiaToHepMC.fill_next_event(m_pythia->process, evtlhe.get(), m_internal_event_number, &m_pythia->info, &m_pythia->settings);
458 auto extra = std::make_shared<HepMC::ShortEventAttribute>(evtlhe.get());
459 evt->add_attribute("LHERecord", extra);
460#else
461 ATH_MSG_WARNING("LHE record saving requested, but not implemented with HEPMC2 functionality.");
462#endif
463 }
464
465 // in debug mode you can check whether the pdf information is stored
466 if(evt->pdf_info()){
467#ifdef HEPMC3
468 ATH_MSG_DEBUG("PDFinfo id1:" << evt->pdf_info()->parton_id[0]);
469 ATH_MSG_DEBUG("PDFinfo id2:" << evt->pdf_info()->parton_id[1]);
470 ATH_MSG_DEBUG("PDFinfo x1:" << evt->pdf_info()->x[0]);
471 ATH_MSG_DEBUG("PDFinfo x2:" << evt->pdf_info()->x[1]);
472 ATH_MSG_DEBUG("PDFinfo scalePDF:" << evt->pdf_info()->scale);
473 ATH_MSG_DEBUG("PDFinfo pdf1:" << evt->pdf_info()->pdf_id[0]);
474 ATH_MSG_DEBUG("PDFinfo pdf2:" << evt->pdf_info()->pdf_id[1]);
475#else
476 ATH_MSG_DEBUG("PDFinfo id1:" << evt->pdf_info()->id1());
477 ATH_MSG_DEBUG("PDFinfo id2:" << evt->pdf_info()->id2());
478 ATH_MSG_DEBUG("PDFinfo x1:" << evt->pdf_info()->x1());
479 ATH_MSG_DEBUG("PDFinfo x2:" << evt->pdf_info()->x2());
480 ATH_MSG_DEBUG("PDFinfo scalePDF:" << evt->pdf_info()->scalePDF());
481 ATH_MSG_DEBUG("PDFinfo pdf1:" << evt->pdf_info()->pdf1());
482 ATH_MSG_DEBUG("PDFinfo pdf2:" << evt->pdf_info()->pdf2());
483#endif
484 }
485 else
486 ATH_MSG_DEBUG("No PDF information available in HepMC::GenEvent!");
487
488 // set the randomseeds
490
491 // fill weights
493
494 return StatusCode::SUCCESS;
495}
496
498StatusCode Pythia8_i::fillWeights(HepMC::GenEvent *evt){
499
500 // reset
501 m_mergingWeight = m_pythia->info.mergingWeightNLO(); // first initialisation, good for the nominal weight in any case (see Merging:includeWeightInXsection).
502 m_enhanceWeight = 1.0; // better to keep the enhancement from UserHooks in a separate variable, to keep the code clear
503
504#ifndef PYTHIA8_304SERIES
505 // include Enhance userhook weight
506 for(const auto &hook: m_userHooksPtrs) {
507 if (hook->canEnhanceEmission()) {
508 m_enhanceWeight *= hook->getEnhancedEventWeight();
509 }
510 }
511#endif // not PYTHIA8_304SERIES
512
513 // DO NOT try to distinguish between phase space and merging contributions: only their product contains both, so always multiply them in order to be robust
514 double eventWeight = m_pythia->info.weight() * m_mergingWeight * m_enhanceWeight;
515
516 std::map<std::string,double> fWeights; // temporary weight vector, needed while managing hepmc2 and 3 simultaneously
517
518 // save as Default the usual pythia8 weight, including enhancements
519 // NB: info.weight() is built upon info.eventWeightLHEF (but includes shower "decorations"), not from the rwgt LHE vector.
520 size_t atlas_specific_weights = 1;
521 fWeights["Default"]=eventWeight;
522 if(m_internal_event_number == 1) {
523 ATH_MSG_INFO("found LHEF version "<< m_pythia->info.LHEFversion() );
524 if (m_pythia->info.LHEFversion() > 1) m_doLHE3Weights = true;
525 m_weightIDs.clear();
526 m_weightIDs.push_back("Default"); // notice that we are assigning a weightname = weightID
527 }
528
529 // Now systematic weights: a) generator and b) shower variations
530 // merging implies reading from lhe files (while the opposite is not true, ok, but still works)
531 if (m_lheFile!="") {
532 // remember that the true merging component can be disentangled only when there are LHE input events
533
534 // make sure to get the merging weight correctly: this is needed -only- for systematic weights (generator and parton shower variations)
535 // NB: most robust way, regardless of the specific value of Merging:includeWeightInXsection (if on, info.mergingWeight() is always 1.0 ! )
536 m_mergingWeight *= ( m_pythia->info.weight() / m_pythia->info.eventWeightLHEF ); // this is the actual merging component, regardless of conventions,
537 // needed by systematic variation weights
538 // this includes rare compensation or selection-biased weights
539 }
540
541
542 ATH_MSG_DEBUG("Event weights: enhancing weight, merging weight, total weight = "<<m_enhanceWeight<<", "<<m_mergingWeight<<", "<<eventWeight);
543
544 // we already filled the "Default" weight
545 std::vector<std::string>::const_iterator id = m_weightIDs.begin()+atlas_specific_weights;
546
547 // a) fill generator weights
548 if(m_pythia->info.getWeightsDetailedSize() != 0){
549 for(std::map<std::string, Pythia8::LHAwgt>::const_iterator wgt = m_pythia->info.rwgt->wgts.begin();
550 wgt != m_pythia->info.rwgt->wgts.end(); ++wgt){
551
553 m_weightIDs.push_back(wgt->first);
554 }else{
555 if(*id != wgt->first){
556 ATH_MSG_ERROR("Mismatch in LHE3 weight id. Found "<<wgt->first<<", expected "<<*id);
557 return StatusCode::FAILURE;
558 }
559 ++id;
560 }
561
562 std::map<std::string, Pythia8::LHAweight>::const_iterator weightName = m_pythia->info.init_weights->find(wgt->first);
563 if(weightName != m_pythia->info.init_weights->end()){
564 fWeights[weightName->second.contents] = m_mergingWeight * m_enhanceWeight * wgt->second.contents;
565 }else{
566 // if no name was assigned/found, assign a weightname = weightid
567 fWeights[wgt->first] = m_mergingWeight * m_enhanceWeight * wgt->second.contents;
568 }
569
570 }
571 }
572
573 // b) shower weight variations
574 // always start from second shower weight: the first was saved already as "Default"
575
576 for(int iw = 1; iw < m_pythia->info.PYTHIA8_NWEIGHTS(); ++iw){
577
578 std::string wtName = ((int)m_showerWeightNames.size() == m_pythia->info.PYTHIA8_NWEIGHTS())? m_showerWeightNames[iw]: "ShowerWt_" +std::to_string(iw);
579
580 fWeights[wtName] = m_mergingWeight * m_enhanceWeight * m_pythia->info.PYTHIA8_WEIGHT(iw)*m_conversion;
581
582 if(m_internal_event_number == 1) {
583 m_weightIDs.push_back(wtName);
584 ATH_MSG_DEBUG("Shower weight name, value, conversion: "<<wtName<<", "<< fWeights[wtName] <<","<<m_conversion );
585 }
586 }
587
588 // Now save, as a backup, also the LHEF weight without enhancements (useful for possible, rare, non-default cases)
589 // to make clear that it should not be used in analyses, save it always with a -10 factor (so that its goal is clear even if not checking its name)
590 if (m_lheFile!="")
591 {
592 fWeights["EXTRA_bare_LHE_weight"]=(-10.0)*m_pythia->info.eventWeightLHEF;
593 if(m_internal_event_number == 1) m_weightIDs.push_back("EXTRA_bare_LHE_weight");
594 }
595
596 // Sad, but needed: create a string vector with acceptable order of weight names
598 m_weightNames.clear();
599 for(const std::string &id : m_weightIDs){
600 if(m_doLHE3Weights) {
601 std::map<std::string, Pythia8::LHAweight>::const_iterator weight = m_pythia->info.init_weights->find(id);
602 if(weight != m_pythia->info.init_weights->end()) m_weightNames.push_back(weight->second.contents);
603 else m_weightNames.push_back(id);
604 }
605 else {
606 m_weightNames.push_back(id);
607 }
608 }
609 if (m_weightNames.size() != fWeights.size() ) {
610 ATH_MSG_ERROR("Something wrong when building list of weight names: " << m_weightNames.size() << " vs "<< fWeights.size() << ", exiting ...");
611 return StatusCode::FAILURE;
612 }
613 }
614
615 // The following depends on the specific hepmc2/3 implementation
616#ifdef HEPMC3
617 if (!evt->run_info()) {
618 evt->set_run_info(m_runinfo);
619 }
620 evt->run_info()->set_weight_names(m_weightNames);
621
622 // for the first event, weight EXTRA_bare_LHE_weight is not present in evt->weights(), so we need to book a place for it by hand
623 if (m_internal_event_number == 1 && evt->run_info()->weight_names().size() == evt->weights().size()+1 ) {
624 evt->weights().push_back(1.0);
625 }
626
627 // added conversion GeV -> MeV to ensure correct units
628 evt->set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
629
630 evt->weights().resize(fWeights.size(), 1.0);
631 for (const auto & w: fWeights) {
632 evt->weight(w.first)=w.second;
633 }
634
635 auto beams=evt->beams();
636 ATH_MSG_DEBUG( " Energy of the beams " << beams[0]->momentum().e() );
637
638//uncomment to list HepMC events
639// std::cout << " print::listing Pythia8 " << std::endl;
640// HepMC3::Print::listing(std::cout, *evt);
641
642#else
643 evt->weights().clear();
644 for (const auto& w: m_weightNames ) {evt->weights()[w]=fWeights[w];}
645 auto beams=evt->beam_particles();
646 ATH_MSG_DEBUG( " Energy of the beams " << beams.first->momentum().e() );
647
648//uncomment to list HepMC events
649// std::cout << " print::listing Pythia8 " << std::endl;
650// evt->print();
651#endif
652
653 return StatusCode::SUCCESS;
654}
655
658
659 ATH_MSG_INFO(">>> Pythia8_i from genFinalize");
660 m_pythia->stat();
661
662 Pythia8::Info info = m_pythia->info;
663 double xs = info.sigmaGen(); // in mb
664
666 const double accfactor = m_nMerged / info.nAccepted();
667 ATH_MSG_DEBUG("Multiplying cross-section by CKKWL merging acceptance of "<<m_nMerged <<"/" <<info.nAccepted() << " = " << accfactor
668 << ": " << xs << " -> " << xs*accfactor);
669 xs *= accfactor;
670 }
671
672 if(m_doFxFxXS){
673 ATH_MSG_DEBUG("Using FxFx cross section recipe: xs = "<< m_sigmaTotal << " / " << 1e9*info.nTried());
674 xs = m_sigmaTotal / (1e9*info.nTried());
675 std::cout << "Using FxFx cross section recipe: xs = "<< m_sigmaTotal << " / " << 1e9*info.nTried() << std::endl;
676 }
677
678 if( ! m_athenaTool.empty()){
679 double xsmod = m_athenaTool->CrossSectionScaleFactor();
680 ATH_MSG_DEBUG("Multiplying cross-section by Pythia Modifier tool factor " << xsmod );
681 xs *= xsmod;
682 }
683
684 xs *= 1000. * 1000.;//convert to nb
685
686 std::cout << "MetaData: cross-section (nb)= " << xs <<std::endl;
687 std::cout << "MetaData: generator= Pythia 8." << std::string(py8version()) <<std::endl;
688
689 if(m_doLHE3Weights || m_weightIDs.size()>1 ){
690 std::cout<<"MetaData: weights = ";
691 for (const auto& w : m_weightNames ) std::cout<< w <<" | ";
692 std::cout<<std::endl;
693 }
694
696 if (info.nTried()>0) ATH_MSG_INFO("Pythia8 efficiency (nAccepted/nTried %) = " << info.nAccepted()*100./info.nTried());
697 else ATH_MSG_INFO("Pythia8 efficiency cannot be computed, nTried <=0");
698 }
699
701 ATH_MSG_INFO("Number of random numbers produced " << m_atlasRndmEngine->getRNCalls());
702 if (m_useReseed) ATH_MSG_INFO("Each event was reseeded ");
703 else ATH_MSG_INFO("Events were not reseeded ");
704}
705
706 return StatusCode::SUCCESS;
707}
708
711 return m_version;
712}
713
715const std::string& Pythia8_i::pythia_stream() {
716 return s_pythia_stream;
717}
718
720std::string Pythia8_i::xmlpath(){
721
722
723 std::string foundpath = "";
724
725// Try to find the xmldoc directory using PathResolver:
726 foundpath = PathResolverFindCalibDirectory( "Pythia8/xmldoc" );
727
728 return foundpath;
729}
730
732
733// fix Pythia8 shower weights change in conventions
734#ifdef PYTHIA8_NWEIGHTS
735 #undef PYTHIA8_NWEIGHTS
736 #undef PYTHIA8_WEIGHT
737 #undef PYTHIA8_WLABEL
738 #undef PYTHIA8_CONVERSION
739#endif
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::string PathResolverFindCalibDirectory(const std::string &logical_file_name)
#define PYTHIA8_CONVERSION
Definition Pythia8_i.cxx:32
#define PYTHIA8_PTRWRAP(A)
GenModule(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition GenModule.cxx:14
CLHEP::HepRandomEngine * getRandomEngineDuringInitialize(const std::string &streamName, unsigned long int randomSeedOffset, unsigned int conditionsRun=1, unsigned int lbn=1) const
Definition GenModule.cxx:53
IntegerProperty m_randomSeed
Seed for random number engine.
Definition GenModule.h:84
static std::map< std::string, T > & userSettings()
static UserHooks * create(const std::string &hookName)
static std::shared_ptr< Sigma2Process > create(const std::string &procName)
static std::shared_ptr< ResonanceWidths > create(const std::string &name, int pdgid)
Call this with the name of the ResonanceWidth and PDG ID to which it will be applied e....
bool m_override_transform_beamenergy
Definition Pythia8_i.h:127
virtual StatusCode genInitialize()
For initializing the generator, if required.
Definition Pythia8_i.cxx:98
IntegerProperty m_dsid
Definition Pythia8_i.h:101
BooleanProperty m_sameAlphaSAsMPI
Definition Pythia8_i.h:106
virtual StatusCode fillWeights(HepMC::GenEvent *evt)
virtual StatusCode fillEvt(HepMC::GenEvent *evt)
For filling the HepMC event object.
StringProperty m_userProcess
Definition Pythia8_i.h:145
BooleanProperty m_useReseed
Definition Pythia8_i.h:99
static std::string xmlpath()
DoubleProperty m_numberAlphaS
Definition Pythia8_i.h:105
Pythia8::SuppressSmallPT * m_SuppressSmallPT
Definition Pythia8_i.h:176
double m_nAccepted
Definition Pythia8_i.h:134
unsigned int m_failureCount
Definition Pythia8_i.h:139
bool m_doLHE3Weights
Definition Pythia8_i.h:165
DoubleProperty m_collisionEnergy
Definition Pythia8_i.h:122
StringProperty m_lheFile
Definition Pythia8_i.h:129
StringProperty m_beam1
Definition Pythia8_i.h:125
BooleanProperty m_computeEfficiency
Definition Pythia8_i.h:133
std::vector< std::shared_ptr< Pythia8::ResonanceWidths > > m_userResonancePtrs
Definition Pythia8_i.h:154
std::shared_ptr< Pythia8::Sigma2Process > m_procPtr
Definition Pythia8_i.h:148
double m_sigmaTotal
Definition Pythia8_i.h:136
BooleanProperty m_saveLHE
Definition Pythia8_i.h:172
HepMC::Pythia8ToHepMC m_pythiaToHepMC
Definition Pythia8_i.h:93
double m_nMerged
Definition Pythia8_i.h:135
PublicToolHandle< IPythia8Custom > m_athenaTool
Definition Pythia8_i.h:170
StringProperty m_userResonances
Definition Pythia8_i.h:152
virtual StatusCode callGenerator()
For calling the generator on each iteration of the event loop.
BooleanProperty m_doFxFxXS
Definition Pythia8_i.h:132
std::vector< long int > m_seeds
Definition Pythia8_i.h:143
std::vector< std::string > m_showerWeightNames
Definition Pythia8_i.h:167
std::vector< std::string > m_weightIDs
Definition Pythia8_i.h:163
DoubleProperty m_pt0timesMPI
Definition Pythia8_i.h:104
std::vector< std::string > m_weightNames
Definition Pythia8_i.h:164
int m_internal_event_number
Definition Pythia8_i.h:112
static const std::string & pythia_stream()
std::shared_ptr< customRndm > m_atlasRndmEngine
Definition Pythia8_i.h:97
double pythiaVersion() const
StringArrayProperty m_userHooks
Definition Pythia8_i.h:102
StringProperty m_beam2
Definition Pythia8_i.h:126
virtual StatusCode genFinalize()
For finalising the generator, if required.
std::unique_ptr< Pythia8::Pythia > m_pythia
Definition Pythia8_i.h:92
double m_enhanceWeight
Definition Pythia8_i.h:162
double m_version
Definition Pythia8_i.h:114
double m_conversion
Definition Pythia8_i.h:137
std::map< std::string, PDGID > m_particleIDs
Definition Pythia8_i.h:141
BooleanProperty m_doCKKWLAcceptance
Definition Pythia8_i.h:131
double m_mergingWeight
Definition Pythia8_i.h:161
UnsignedIntegerProperty m_maxFailures
Definition Pythia8_i.h:94
BooleanProperty m_useRndmGenSvc
Definition Pythia8_i.h:96
StringProperty m_particleDataFile
Definition Pythia8_i.h:158
std::vector< UserHooksPtrType > m_userHooksPtrs
Definition Pythia8_i.h:150
StringArrayProperty m_showerWeightNamesProp
Definition Pythia8_i.h:168
StringProperty m_outputParticleDataFile
Definition Pythia8_i.h:159
StringArrayProperty m_commands
Definition Pythia8_i.h:116
Pythia8_i(const std::string &name, ISvcLocator *pSvcLocator)
Definition Pythia8_i.cxx:68
void calculateSeedsMC21(long *seeds, const std::string &algName, uint64_t ev, uint64_t run, uint64_t offset=0)
Set the random seed using a string (e.g.
void set_random_states(GenEvent *e, std::vector< T > a)
Definition GenEvent.h:649
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)