ATLAS Offline Software
Loading...
Searching...
No Matches
Herwig7.cxx
Go to the documentation of this file.
1// -*- C++ -*-
2/*
3 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
4*/
5
6
11
12#include "Herwig7_i/Herwig7.h"
13
14#include "ThePEG/Repository/EventGenerator.h"
15#include "ThePEG/Repository/Repository.h"
16#include "ThePEG/Persistency/PersistentIStream.h"
17#include "ThePEG/Utilities/DynamicLoader.h"
18#include "ThePEG/Utilities/Debug.h"
19#include "ThePEG/EventRecord/Event.h"
20#include "ThePEG/EventRecord/SubProcess.h"
21#include "ThePEG/Handlers/XComb.h"
22#include "ThePEG/Handlers/EventHandler.h"
23#include "ThePEG/PDF/PartonExtractor.h"
24#include "ThePEG/PDF/PDF.h"
25
26#include "Herwig/API/HerwigAPI.h"
27
29
30#include <thread>
31#include <chrono>
32#include <filesystem>
33#include <ranges>
34
35void convert_to_HepMC(const ThePEG::Event & m_event, HepMC::GenEvent & evt, bool nocopies,ThePEG::Energy eunit, ThePEG::Length lunit);
36
37
38// Constructor
39Herwig7::Herwig7(const std::string& name, ISvcLocator* pSvcLocator) :
40 GenModule(name, pSvcLocator),
43 m_pdfname_me("UNKNOWN"), m_pdfname_mpi("UNKNOWN") // m_pdfname_ps("UNKONWN"),
44{
45 declareProperty("RunFile", m_runfile="Herwig7");
46 declareProperty("SetupFile", m_setupfile="");
47
48 declareProperty("UseRandomSeedFromGeneratetf", m_use_seed_from_generatetf);
49 declareProperty("RandomSeedFromGeneratetf", m_seed_from_generatetf);
50
51 declareProperty("PDFNameME", m_pdfname_me);
52 // declareProperty("PDFNamePS", m_pdfname_ps);
53 declareProperty("PDFNameMPI", m_pdfname_mpi);
54
55 declareProperty("CrossSectionScaleFactor", m_xsscale=1.0);
56
57 declareProperty("CleanupHerwigScratch", m_cleanup_herwig_scratch);
58
59 declareProperty("Dsid", m_dsid);
60}
61
68 ATH_MSG_INFO("Herwig7 initialising...");
69
70 ATH_CHECK(m_evtInfoKey.initialize());
71
72 // Get random number seeds from Atlas RNG service, and pass them as Hw7 RNG
73 // default seeds (they can be overridden with an explicit Hw7 set command in the JO)
74 CLHEP::HepRandomEngine* engine = this->getRandomEngineDuringInitialize("Herwig7", m_randomSeed); // conditionsRun=1, lbn=1
75 const long* seeds = engine->getSeeds();
76 // The RNG service supplies two seeds, but Hw7 only uses one. To avoid the situation
77 // where varying one seed has no effect (this already stung us in pre-production
78 // job transform tests), we multiply the two seeds and let them wrap around the long
79 // type MAX_SIZE:
80 int32_t combined_seed = std::abs(seeds[0] * seeds[1]);
81 // Represent the combined seed as a string, so the config system can parse it back to a long ;)
82 std::ostringstream ss_seed;
83 ss_seed << combined_seed;
84 // Configure the API and print the seed to the log
86 ATH_MSG_INFO("Using the random number seed " + std::to_string(m_seed_from_generatetf) + " provided via Generate_tf.py");
88 } else {
89 ATH_MSG_INFO("Using the random number seed " + ss_seed.str() + " provided by athena");
90 m_api.seed(combined_seed);
91 }
92
93 // Change repo log level and make sure that config errors result in a program exit
94 //ThePEG::Debug::level = 10000;
95 ThePEG::Repository::exitOnError() = 1;
96
97 // Use everything from $DATAPATH and $LD_LIBRARY_PATH:
98 const char* datapath = getenv( "DATAPATH" );
99 std::vector<std::string> datapaths;
100 if (datapath) {
101 std::string datapath_str(datapath);
102 for (auto part : std::views::split(datapath_str, ':')) {
103 datapaths.emplace_back(part.begin(), part.end());
104 }
105 }
106 for( const std::string& p : datapaths ) {
107 ThePEG::Repository::appendReadDir( p );
108 }
109 const char* ldpath = getenv( "LD_LIBRARY_PATH" );
110 std::vector<std::string> ldpaths;
111 if (ldpath) {
112 std::string ldpath_str(ldpath);
113 for (auto part : ldpath_str | std::views::split(':')) {
114 ldpaths.emplace_back(std::string(part.begin(), part.end()));
115 }
116 }
117 for( const std::string& p : ldpaths ) {
118 ThePEG::DynamicLoader::appendPath( p );
119 }
120
121 ATH_MSG_DEBUG("Num of library search paths = " << ThePEG::DynamicLoader::allPaths().size());
122
123 // Use PathResolver to find default Hw7 ThePEG repository file.
124 const std::string repopath = PathResolver::find_file_from_list("HerwigDefaults.rpo", datapath);
125 ATH_MSG_DEBUG("Loading Herwig default repo from " << repopath);
126 ThePEG::Repository::load(std::move(repopath));
127 ATH_MSG_DEBUG("Successfully loaded Herwig default repository");
128
129 ATH_MSG_INFO("Setting runfile name '"+m_runfile+"'");
130 m_api.inputfile(m_runfile);
131
132 ATH_MSG_INFO("starting to prepare the run from runfile '"+m_runfile+"'...");
133
134#ifdef HEPMC3
135 m_runinfo = std::make_shared<HepMC3::GenRunInfo>();
137 struct HepMC3::GenRunInfo::ToolInfo generator={std::string("Herwig7"), std::string("7"), std::string("Used generator")};
138 m_runinfo->tools().push_back(std::move(generator));
139#endif
140 // read in a Herwig runfile and obtain the event generator
141 m_gen = Herwig::API::prepareRun(m_api);
142 ATH_MSG_DEBUG("preparing the run...");
143
144 return StatusCode::SUCCESS;
145}
146
147
148
153 ATH_MSG_DEBUG("Herwig7 generating an event");
154 assert(m_gen);
155 m_event = m_gen->shoot();
156 return StatusCode::SUCCESS;
157}
158
159
160
167StatusCode Herwig7::fillEvt(HepMC::GenEvent* evt) {
168 // Convert the Herwig event into the HepMC GenEvent
169 ATH_MSG_DEBUG("Converting ThePEG::Event to HepMC::GenEvent");
170#ifdef HEPMC3
171 if (!evt->run_info()) evt->set_run_info(m_runinfo);
172 evt->set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
173#endif
174 convert_to_HepMC(*m_event, *evt, false, ThePEG::MeV, ThePEG::millimeter);
175 ATH_MSG_DEBUG("Converted ThePEG::Event to HepMC::GenEvent");
176
177 // Fill the event number into HepMC event record
179 evt->set_event_number(evtInfo->eventNumber());
180
181 // Fill event with random seeds from Atlas RNG service
182 const EventContext& ctx = Gaudi::Hive::currentContext();
183 const long* s = this->getRandomEngine("Herwig7", ctx)->getSeeds();
184 std::vector<long> seeds(s, s+2);
185 ATH_MSG_DEBUG("Random seeds: " << seeds[0] << ", " << seeds[1]);
186 HepMC::set_random_states(evt,seeds);
187
188 // Add a unit entry to the event weight vector if it's currently empty
189 if (evt->weights().empty()) {
190 evt->weights().push_back(m_event->weight());
191 }
192
193 // Add PDF info manually (for now, until natively supported in the ThePEG converter)
194 ATH_MSG_DEBUG("Adding PDF info to HepMC");
195 // IDs of the partons going into the primary sub process
196 ThePEG::tSubProPtr sub = m_event->primarySubProcess();
197 int id1 = sub->incoming().first ->id();
198 int id2 = sub->incoming().second->id();
199 // Get the event handler
200 ThePEG::tcEHPtr eh = ThePEG::dynamic_ptr_cast<ThePEG::tcEHPtr>(m_event->handler());
201 // Get the values of x
202 double x1 = eh->lastX1();
203 double x2 = eh->lastX2();
204 // Get the pdfs
205 std::pair<ThePEG::PDF,ThePEG::PDF> pdfs;
206 pdfs.first = eh->pdf<ThePEG::PDF>(sub->incoming().first);
207 pdfs.second = eh->pdf<ThePEG::PDF>(sub->incoming().second);
208 // Get the scale
209 ThePEG::Energy2 scale = eh->lastScale();
210 double Q = std::sqrt(scale/ThePEG::GeV2);
211 // Get the values of the pdfs
212 double pdf1 = pdfs.first.xfx(sub->incoming().first ->dataPtr(), scale, x1);
213 double pdf2 = pdfs.first.xfx(sub->incoming().second->dataPtr(), scale, x2);
214 // Create the PDFinfo object
215#ifdef HEPMC3
216 HepMC3::GenPdfInfoPtr pdfi = std::make_shared<HepMC3::GenPdfInfo>();
217 pdfi->set(id1, id2, x1, x2, Q, pdf1, pdf2);
218#else
219 HepMC::PdfInfo pdfi(id1, id2, x1, x2, Q, pdf1, pdf2);
220#endif
221 evt->set_pdf_info(std::move(pdfi));
222 ATH_MSG_DEBUG("Added PDF info to HepMC");
223
224//uncomment to list HepMC events
225//#ifdef HEPMC3
226// std::cout << " print::listing Herwig7 " << std::endl;
227// HepMC3::Print::listing(std::cout, *evt);
228//#else
229// std::cout << " print::printing Herwig7 " << std::endl;
230// evt->print();
231//#endif
232
233 return StatusCode::SUCCESS;
234}
235
236
237
242 ATH_MSG_INFO("Herwig7 finalizing.");
243 assert(m_gen);
244 ATH_MSG_INFO( "MetaData: generator = Herwig7 " << HWVERSION );
245 ATH_MSG_INFO( std::scientific << std::setprecision(5) << "MetaData: cross-section (nb) = " << m_gen->eventHandler()->integratedXSec()*m_xsscale/ThePEG::nanobarn);
246 // ATH_MSG_INFO( "MetaData: PDF = " << m_pdfname_me << " (ME); " << m_pdfname_ps << " (shower); " << m_pdfname_mpi << " (MPI)" );
247 ATH_MSG_INFO("MetaData: PDF = " << m_pdfname_me << " (ME); " << m_pdfname_mpi << " (shower/MPI)");
248 m_gen->finalize();
249 ThePEG::Repository::cleanup();
250
251 // possibly tidy up working directory
252 if (m_cleanup_herwig_scratch && (std::filesystem::is_directory("Herwig-scratch") || std::filesystem::is_directory("Herwig-cache"))){
253
254 ATH_MSG_INFO("removing Herwig-scratch/Herwig-cache folder from "+std::filesystem::current_path().string());
255
256 // sleep for some time to allow all access to terminate
257 std::this_thread::sleep_for(std::chrono::seconds(5));
258
259 // in case the folder can't be deleted continue with warning
260 try {
261 (std::filesystem::remove_all("Herwig-scratch") || std::filesystem::remove_all("Herwig-cache"));
262 }
263 catch (const std::exception& e) {
264 ATH_MSG_WARNING("Failed to delete the folder 'Herwig-scratch': "+std::string(e.what()));
265 }
266
267 }
268
269 return StatusCode::SUCCESS;
270}
271
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
void convert_to_HepMC(const ThePEG::Event &m_event, HepMC::GenEvent &evt, bool nocopies, ThePEG::Energy eunit, ThePEG::Length lunit)
Athena interface for the Herwig7 generator.
HWIdentifier id2
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
GenModule(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition GenModule.cxx:14
CLHEP::HepRandomEngine * getRandomEngine(const std::string &streamName, const EventContext &ctx) const
Definition GenModule.cxx:34
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
std::string m_pdfname_mpi
PS PDF name, stored for AMI capture at finalize.
Definition Herwig7.h:187
StatusCode callGenerator()
Run the generator for one event.
Definition Herwig7.cxx:152
SG::ReadHandleKey< xAOD::EventInfo > m_evtInfoKey
Definition Herwig7.h:198
StatusCode genFinalize()
Close down the generator.
Definition Herwig7.cxx:241
ThePEG::EventPtr m_event
ThePEG event object.
Definition Herwig7.h:158
int m_seed_from_generatetf
Random number seed from Generate_tf.py.
Definition Herwig7.h:178
std::string m_pdfname_me
ME PDF name, stored for AMI capture at finalize.
Definition Herwig7.h:181
bool m_cleanup_herwig_scratch
Possibly remove Herwig-scratch folder after finishing the event generation.
Definition Herwig7.h:190
Herwig7(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition Herwig7.cxx:39
double m_xsscale
Scale integrated cross section by a factor for MetaData output.
Definition Herwig7.h:193
StatusCode fillEvt(HepMC::GenEvent *evt)
Convert the generated event into the HepMC format.
Definition Herwig7.cxx:167
int m_dsid
Gen_tf.py run args needed in interface.
Definition Herwig7.h:196
ThePEG::EGPtr m_gen
ThePEG generator object.
Definition Herwig7.h:155
std::string m_runfile
Name of run file.
Definition Herwig7.h:168
StatusCode genInitialize()
Initialize the generator.
Definition Herwig7.cxx:67
Herwig7API m_api
Herwig7 API object.
Definition Herwig7.h:152
std::string m_setupfile
Name of setup file.
Definition Herwig7.h:171
bool m_use_seed_from_generatetf
Ignore random number seed provided by athena and use the one from Generate_tf.py instead.
Definition Herwig7.h:175
static std::string find_file_from_list(const std::string &logical_file_name, const std::string &search_list)
void set_random_states(GenEvent *e, std::vector< T > a)
Definition GenEvent.h:649