ATLAS Offline Software
Loading...
Searching...
No Matches
Herwig7.cxx
Go to the documentation of this file.
1// -*- C++ -*-
2/*
3 Copyright (C) 2002-2026 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#include "Herwig/Utilities/HerwigStrategy.h"
28
29#include <cstdlib>
30#include <fstream>
31#include <thread>
32#include <chrono>
33#include <filesystem>
34#include <ranges>
35#include <system_error>
36
37void convert_to_HepMC(const ThePEG::Event & m_event, HepMC::GenEvent & evt, bool nocopies,ThePEG::Energy eunit, ThePEG::Length lunit);
38
39
40// Constructor
41Herwig7::Herwig7(const std::string& name, ISvcLocator* pSvcLocator) :
42 GenModule(name, pSvcLocator),
45 m_pdfname_me("UNKNOWN"), m_pdfname_mpi("UNKNOWN") // m_pdfname_ps("UNKONWN"),
46{
47 declareProperty("RunFile", m_runfile="Herwig7");
48 declareProperty("RunSettings", m_runSettings="");
49 declareProperty("Repository", m_repository="");
50 declareProperty("SetupFile", m_setupfile="");
51
52 declareProperty("UseRandomSeedFromGeneratetf", m_use_seed_from_generatetf);
53 declareProperty("RandomSeedFromGeneratetf", m_seed_from_generatetf);
54
55 declareProperty("PDFNameME", m_pdfname_me);
56 // declareProperty("PDFNamePS", m_pdfname_ps);
57 declareProperty("PDFNameMPI", m_pdfname_mpi);
58
59 declareProperty("CrossSectionScaleFactor", m_xsscale=1.0);
60
61 declareProperty("CleanupHerwigScratch", m_cleanup_herwig_scratch);
62
63 declareProperty("Dsid", m_dsid);
64}
65
72 ATH_MSG_INFO("Herwig7 initialising...");
73
74 ATH_CHECK(m_evtInfoKey.initialize());
75
76 // Get random number seeds from Atlas RNG service, and pass them as Hw7 RNG
77 // default seeds (they can be overridden with an explicit Hw7 set command in the JO)
78 CLHEP::HepRandomEngine* engine = this->getRandomEngineDuringInitialize("Herwig7", m_randomSeed); // conditionsRun=1, lbn=1
79 const long* seeds = engine->getSeeds();
80 // The RNG service supplies two seeds, but Hw7 only uses one. To avoid the situation
81 // where varying one seed has no effect (this already stung us in pre-production
82 // job transform tests), we multiply the two seeds and let them wrap around the long
83 // type MAX_SIZE:
84 int32_t combined_seed = std::abs(seeds[0] * seeds[1]);
85 // Represent the combined seed as a string, so the config system can parse it back to a long ;)
86 std::ostringstream ss_seed;
87 ss_seed << combined_seed;
88 // Configure the API and print the seed to the log
90 ATH_MSG_INFO("Using the random number seed " + std::to_string(m_seed_from_generatetf) + " provided via Generate_tf.py");
92 } else {
93 ATH_MSG_INFO("Using the random number seed " + ss_seed.str() + " provided by athena");
94 m_api.seed(combined_seed);
95 }
96
97 // Change repo log level and make sure that config errors result in a program exit
98 //ThePEG::Debug::level = 10000;
99 ThePEG::Repository::exitOnError() = 1;
100
101 // Use everything from $DATAPATH and $LD_LIBRARY_PATH:
102 const char* datapath = getenv( "DATAPATH" );
103 std::vector<std::string> datapaths;
104 if (datapath) {
105 std::string datapath_str(datapath);
106 for (auto part : std::views::split(datapath_str, ':')) {
107 datapaths.emplace_back(part.begin(), part.end());
108 }
109 }
110 for( const std::string& p : datapaths ) {
111 ThePEG::Repository::appendReadDir( p );
112 }
113 const char* ldpath = getenv( "LD_LIBRARY_PATH" );
114 std::vector<std::string> ldpaths;
115 if (ldpath) {
116 std::string ldpath_str(ldpath);
117 for (auto part : ldpath_str | std::views::split(':')) {
118 ldpaths.emplace_back(std::string(part.begin(), part.end()));
119 }
120 }
121 for( const std::string& p : ldpaths ) {
122 ThePEG::DynamicLoader::appendPath( p );
123 }
124
125 ATH_MSG_DEBUG("Num of library search paths = " << ThePEG::DynamicLoader::allPaths().size());
126
127 if (!m_runSettings.empty()) {
128 const std::filesystem::path repository_path(m_repository);
129 std::error_code repository_error;
130 if (repository_path.empty() ||
131 !std::filesystem::is_regular_file(repository_path, repository_error)) {
132 ATH_MSG_ERROR("Configured Herwig repository does not exist: '" <<
133 repository_path.string() << "'");
134 return StatusCode::FAILURE;
135 }
136
137 ATH_MSG_DEBUG("Using Herwig default repo from " << repository_path);
138 m_api.repository(repository_path.string());
139 ATH_CHECK(writeRunFileFromText(repository_path.parent_path().string()));
140 }
141
142 ATH_MSG_INFO("Setting runfile name '"+m_runfile+"'");
143 m_api.inputfile(m_runfile);
144
145 ATH_MSG_INFO("starting to prepare the run from runfile '"+m_runfile+"'...");
146
147 m_runinfo = std::make_shared<HepMC3::GenRunInfo>();
149 struct HepMC3::GenRunInfo::ToolInfo generator={std::string("Herwig7"), Herwig::HerwigStrategy::version, std::string("Used generator")};
150 m_runinfo->tools().push_back(std::move(generator));
151 // read in a Herwig runfile and obtain the event generator
152 m_gen = Herwig::API::prepareRun(m_api);
153 ATH_MSG_DEBUG("preparing the run...");
154
155 return StatusCode::SUCCESS;
156}
157
158
159StatusCode Herwig7::writeRunFileFromText(const std::string& share_path) {
160 if (m_runSettings.empty()) {
161 return StatusCode::SUCCESS;
162 }
163
164 std::string inputfile_name = m_runfile;
165 const std::string runfile_suffix = ".run";
166 const auto suffix_pos = inputfile_name.rfind(runfile_suffix);
167 if (suffix_pos != std::string::npos) {
168 inputfile_name.replace(suffix_pos, runfile_suffix.size(), ".in");
169 } else {
170 std::filesystem::path inputfile_path(m_runfile);
171 inputfile_path.replace_extension(".in");
172 inputfile_name = inputfile_path.string();
173 }
174
175 ATH_MSG_INFO("Writing CA infile text to '"+inputfile_name+"'");
176 std::ofstream infile_stream(inputfile_name);
177 infile_stream << m_runSettings;
178 infile_stream.close();
179 if (!infile_stream) {
180 ATH_MSG_ERROR("Failed to write CA infile text to '"+inputfile_name+"'");
181 return StatusCode::FAILURE;
182 }
183
184 if (share_path.empty()) {
185 ATH_MSG_ERROR("Could not determine the Herwig share path for CA infile materialisation");
186 return StatusCode::FAILURE;
187 }
188
189 ATH_MSG_INFO("Preparing Herwig runfile from CA infile '"+inputfile_name+"'");
190 m_api.prependReadDirectory(share_path);
191 m_api.inputfile(inputfile_name);
192 Herwig::API::read(m_api);
193 ATH_MSG_INFO("Finished materialising runfile '"+m_runfile+"'");
194 return StatusCode::SUCCESS;
195}
196
197
198
203 ATH_MSG_DEBUG("Herwig7 generating an event");
204 assert(m_gen);
205 m_event = m_gen->shoot();
206 return StatusCode::SUCCESS;
207}
208
209
210
218 // Convert the Herwig event into the HepMC GenEvent
219 ATH_MSG_DEBUG("Converting ThePEG::Event to HepMC::GenEvent");
220 if (!evt->run_info()) evt->set_run_info(m_runinfo);
221 evt->set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
222 convert_to_HepMC(*m_event, *evt, false, ThePEG::MeV, ThePEG::millimeter);
223 ATH_MSG_DEBUG("Converted ThePEG::Event to HepMC::GenEvent");
224
225 // Fill the event number into HepMC event record
227 evt->set_event_number(evtInfo->eventNumber());
228
229 // Fill event with random seeds from Atlas RNG service
230 const EventContext& ctx = Gaudi::Hive::currentContext();
231 const long* s = this->getRandomEngine("Herwig7", ctx)->getSeeds();
232 std::vector<long> seeds(s, s+2);
233 ATH_MSG_DEBUG("Random seeds: " << seeds[0] << ", " << seeds[1]);
234 HepMC::set_random_states(evt,seeds);
235
236 // Add a unit entry to the event weight vector if it's currently empty
237 if (evt->weights().empty()) {
238 evt->weights().push_back(m_event->weight());
239 }
240
241 // Add PDF info manually (for now, until natively supported in the ThePEG converter)
242 ATH_MSG_DEBUG("Adding PDF info to HepMC");
243 // IDs of the partons going into the primary sub process
244 ThePEG::tSubProPtr sub = m_event->primarySubProcess();
245 int id1 = sub->incoming().first ->id();
246 int id2 = sub->incoming().second->id();
247 // Get the event handler
248 ThePEG::tcEHPtr eh = ThePEG::dynamic_ptr_cast<ThePEG::tcEHPtr>(m_event->handler());
249 // Get the values of x
250 double x1 = eh->lastX1();
251 double x2 = eh->lastX2();
252 // Get the pdfs
253 std::pair<ThePEG::PDF,ThePEG::PDF> pdfs;
254 pdfs.first = eh->pdf<ThePEG::PDF>(sub->incoming().first);
255 pdfs.second = eh->pdf<ThePEG::PDF>(sub->incoming().second);
256 // Get the scale
257 ThePEG::Energy2 scale = eh->lastScale();
258 double Q = std::sqrt(scale/ThePEG::GeV2);
259 // Get the values of the pdfs
260 double pdf1 = pdfs.first.xfx(sub->incoming().first ->dataPtr(), scale, x1);
261 double pdf2 = pdfs.first.xfx(sub->incoming().second->dataPtr(), scale, x2);
262 // Create the PDFinfo object
263 HepMC3::GenPdfInfoPtr pdfi = std::make_shared<HepMC3::GenPdfInfo>();
264 pdfi->set(id1, id2, x1, x2, Q, pdf1, pdf2);
265 evt->set_pdf_info(std::move(pdfi));
266 ATH_MSG_DEBUG("Added PDF info to HepMC");
267
268//uncomment to list HepMC events
269// std::cout << " print::listing Herwig7 " << std::endl;
270// HepMC3::Print::listing(std::cout, *evt);
271
272 return StatusCode::SUCCESS;
273}
274
275
276
281 ATH_MSG_INFO("Herwig7 finalizing.");
282 assert(m_gen);
283 ATH_MSG_INFO( "MetaData: generator = Herwig7 " << HWVERSION );
284 ATH_MSG_INFO( std::scientific << std::setprecision(5) << "MetaData: cross-section (nb) = " << m_gen->eventHandler()->integratedXSec()*m_xsscale/ThePEG::nanobarn);
285 // ATH_MSG_INFO( "MetaData: PDF = " << m_pdfname_me << " (ME); " << m_pdfname_ps << " (shower); " << m_pdfname_mpi << " (MPI)" );
286 ATH_MSG_INFO("MetaData: PDF = " << m_pdfname_me << " (ME); " << m_pdfname_mpi << " (shower/MPI)");
287 m_gen->finalize();
288 ThePEG::Repository::cleanup();
289
290 // possibly tidy up working directory
291 if (m_cleanup_herwig_scratch && (std::filesystem::is_directory("Herwig-scratch") || std::filesystem::is_directory("Herwig-cache"))){
292
293 ATH_MSG_INFO("removing Herwig-scratch/Herwig-cache folder from "+std::filesystem::current_path().string());
294
295 // sleep for some time to allow all access to terminate
296 std::this_thread::sleep_for(std::chrono::seconds(5));
297
298 // in case the folder can't be deleted continue with warning
299 try {
300 (std::filesystem::remove_all("Herwig-scratch") || std::filesystem::remove_all("Herwig-cache"));
301 }
302 catch (const std::exception& e) {
303 ATH_MSG_WARNING("Failed to delete the folder 'Herwig-scratch': "+std::string(e.what()));
304 }
305
306 }
307
308 return StatusCode::SUCCESS;
309}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(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.
size_t size() const
Number of registered mappings.
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::shared_ptr< HepMC3::GenRunInfo > m_runinfo
The run info for HepMC3.
Definition GenModule.h:90
std::string m_pdfname_mpi
PS PDF name, stored for AMI capture at finalize.
Definition Herwig7.h:199
StatusCode callGenerator()
Run the generator for one event.
Definition Herwig7.cxx:202
SG::ReadHandleKey< xAOD::EventInfo > m_evtInfoKey
Definition Herwig7.h:210
StatusCode genFinalize()
Close down the generator.
Definition Herwig7.cxx:280
ThePEG::EventPtr m_event
ThePEG event object.
Definition Herwig7.h:163
std::string m_repository
Herwig/ThePEG repository used to materialise CA run settings.
Definition Herwig7.h:180
int m_seed_from_generatetf
Random number seed from Generate_tf.py.
Definition Herwig7.h:190
StatusCode writeRunFileFromText(const std::string &share_path)
Write the CA input text into a real Herwig runfile.
Definition Herwig7.cxx:159
std::string m_pdfname_me
ME PDF name, stored for AMI capture at finalize.
Definition Herwig7.h:193
bool m_cleanup_herwig_scratch
Possibly remove Herwig-scratch folder after finishing the event generation.
Definition Herwig7.h:202
Herwig7(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition Herwig7.cxx:41
double m_xsscale
Scale integrated cross section by a factor for MetaData output.
Definition Herwig7.h:205
std::string m_runSettings
In-memory run settings provided by CA fragments.
Definition Herwig7.h:177
StatusCode fillEvt(HepMC::GenEvent *evt)
Convert the generated event into the HepMC format.
Definition Herwig7.cxx:217
int m_dsid
Gen_tf.py run args needed in interface.
Definition Herwig7.h:208
ThePEG::EGPtr m_gen
ThePEG generator object.
Definition Herwig7.h:160
std::string m_runfile
Name of run file.
Definition Herwig7.h:173
StatusCode genInitialize()
Initialize the generator.
Definition Herwig7.cxx:71
Herwig7API m_api
Herwig7 API object.
Definition Herwig7.h:157
std::string m_setupfile
Name of setup file.
Definition Herwig7.h:183
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:187
void set_random_states(GenEvent *e, std::vector< long int > &a)
Definition GenEvent.h:588
HepMC3::GenEvent GenEvent
Definition GenEvent.h:39