ATLAS Offline Software
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 
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 
35 void convert_to_HepMC(const ThePEG::Event & m_event, HepMC::GenEvent & evt, bool nocopies,ThePEG::Energy eunit, ThePEG::Length lunit);
36 
37 
38 // Constructor
39 Herwig7::Herwig7(const std::string& name, ISvcLocator* pSvcLocator) :
40  GenModule(name, pSvcLocator),
41  m_use_seed_from_generatetf(false),
42  m_seed_from_generatetf(0),
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 
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+"'");
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 
167 StatusCode 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
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]);
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 
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
plotBeamSpotCompare.x1
x1
Definition: plotBeamSpotCompare.py:215
Powheg_tt_mtop_common.PDF
PDF
Definition: Powheg_tt_mtop_common.py:110
Herwig7API::inputfile
virtual std::string inputfile() const
Name of the file to be read.
Definition: Herwig7.h:52
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
xAOD::EventInfo_v1::eventNumber
uint64_t eventNumber() const
The current event's event number.
Herwig7::m_pdfname_mpi
std::string m_pdfname_mpi
PS PDF name, stored for AMI capture at finalize.
Definition: Herwig7.h:187
Herwig7::m_xsscale
double m_xsscale
Scale integrated cross section by a factor for MetaData output.
Definition: Herwig7.h:193
Herwig7::m_pdfname_me
std::string m_pdfname_me
ME PDF name, stored for AMI capture at finalize.
Definition: Herwig7.h:181
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:67
plotBeamSpotCompare.x2
x2
Definition: plotBeamSpotCompare.py:217
JiveXML::Event
struct Event_t Event
Definition: ONCRPCServer.h:65
HepMC::GenPdfInfoPtr
HepMC::PdfInfo * GenPdfInfoPtr
Definition: PdfInfo.h:17
MM
@ MM
Definition: RegSelEnums.h:38
PathResolver::find_file_from_list
static std::string find_file_from_list(const std::string &logical_file_name, const std::string &search_list)
Definition: PathResolver.cxx:240
LArG4FSStartPointFilter.evt
evt
Definition: LArG4FSStartPointFilter.py:42
Herwig7::genFinalize
StatusCode genFinalize()
Close down the generator.
Definition: Herwig7.cxx:241
Herwig7::m_seed_from_generatetf
int m_seed_from_generatetf
Random number seed from Generate_tf.py.
Definition: Herwig7.h:178
Herwig7::genInitialize
StatusCode genInitialize()
Initialize the generator.
Definition: Herwig7.cxx:67
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
python.SystemOfUnits.millimeter
float millimeter
Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration # This software is distribute...
Definition: SystemOfUnits.py:62
GenModule::getRandomEngine
CLHEP::HepRandomEngine * getRandomEngine(const std::string &streamName, const EventContext &ctx) const
Definition: GenModule.cxx:34
python.SystemOfUnits.MeV
float MeV
Definition: SystemOfUnits.py:172
Herwig7::m_event
ThePEG::EventPtr m_event
ThePEG event object.
Definition: Herwig7.h:158
Herwig7::m_evtInfoKey
SG::ReadHandleKey< xAOD::EventInfo > m_evtInfoKey
Definition: Herwig7.h:198
Herwig7::m_dsid
int m_dsid
Gen_tf.py run args needed in interface.
Definition: Herwig7.h:196
GenModule
Base class for common behaviour of generator interfaces.
Definition: GenModule.h:39
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
id2
HWIdentifier id2
Definition: LArRodBlockPhysicsV0.cxx:562
python.html.AtlRunQueryDQSummary.datapath
datapath
Definition: AtlRunQueryDQSummary.py:1204
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Herwig7.h
Athena interface for the Herwig7 generator.
AthCommonDataStore< AthCommonMsg< Algorithm > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Definition: AthCommonDataStore.h:145
calibdata.exception
exception
Definition: calibdata.py:495
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
python.LArCalib_HVCorrConfig.seconds
seconds
Definition: LArCalib_HVCorrConfig.py:100
Herwig7::m_api
Herwig7API m_api
Herwig7 API object.
Definition: Herwig7.h:152
Herwig7::Herwig7
Herwig7(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition: Herwig7.cxx:39
PathResolver.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
Herwig7::m_gen
ThePEG::EGPtr m_gen
ThePEG generator object.
Definition: Herwig7.h:155
mc.generator
generator
Configure Herwig7 These are the commands corresponding to what would go into the regular Herwig infil...
Definition: mc.MGH7_FxFx_H71-DEFAULT_test.py:18
python.SystemOfUnits.nanobarn
float nanobarn
Definition: SystemOfUnits.py:88
SCT_ConditionsAlgorithms::CoveritySafe::getenv
std::string getenv(const std::string &variableName)
get an environment variable
Definition: SCT_ConditionsUtilities.cxx:17
Herwig7::m_runfile
std::string m_runfile
Name of run file.
Definition: Herwig7.h:168
Herwig7::callGenerator
StatusCode callGenerator()
Run the generator for one event.
Definition: Herwig7.cxx:152
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
GenModule::m_randomSeed
IntegerProperty m_randomSeed
Seed for random number engine.
Definition: GenModule.h:84
Herwig7::fillEvt
StatusCode fillEvt(HepMC::GenEvent *evt)
Convert the generated event into the HepMC format.
Definition: Herwig7.cxx:167
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
python.root_pickle.load
def load(f, use_proxy=1, key=None)
Definition: root_pickle.py:430
Herwig7::m_use_seed_from_generatetf
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
Herwig7API::seed
virtual int seed() const
The number of events to generate.
Definition: Herwig7.h:74
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
convert_to_HepMC
void convert_to_HepMC(const ThePEG::Event &m_event, HepMC::GenEvent &evt, bool nocopies, ThePEG::Energy eunit, ThePEG::Length lunit)
Definition: Herwig7HepMC.cxx:140
Herwig7::m_setupfile
std::string m_setupfile
Name of setup file.
Definition: Herwig7.h:171
GenModule::getRandomEngineDuringInitialize
CLHEP::HepRandomEngine * getRandomEngineDuringInitialize(const std::string &streamName, unsigned long int randomSeedOffset, unsigned int conditionsRun=1, unsigned int lbn=1) const
Definition: GenModule.cxx:53
HepMC::set_random_states
void set_random_states(GenEvent *e, std::vector< T > a)
Definition: GenEvent.h:648
Herwig7::m_cleanup_herwig_scratch
bool m_cleanup_herwig_scratch
Possibly remove Herwig-scratch folder after finishing the event generation.
Definition: Herwig7.h:190