ATLAS Offline Software
Loading...
Searching...
No Matches
Sherpa_i.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "GaudiKernel/MsgStream.h"
9
10#include "Sherpa_i/Sherpa_i.h"
11
12
13#include "ATOOLS/Org/CXXFLAGS_PACKAGES.H"
14#ifdef HEPMC3
15#undef USING__HEPMC2
16#else
17#undef USING__HEPMC3
18#endif
19#include "SHERPA/Main/Sherpa.H"
20#include "SHERPA/Initialization/Initialization_Handler.H"
21#ifdef IS_SHERPA_3
22#include "ATOOLS/Phys/Variations.H"
23#else
24#include "SHERPA/Tools/Variations.H"
25#endif
26#include "ATOOLS/Org/Exception.H"
27#include "ATOOLS/Org/Run_Parameter.H"
28
29#include <utility> //std::ignore
30#include <cstdio>
31#include <cstring>
32#include <mutex>
33#include <signal.h>
34#include <stdlib.h>
35#include <sys/stat.h>
36#include "CLHEP/Random/RandFlat.h"
37
38CLHEP::HepRandomEngine* p_rndEngine{};
39
40Sherpa_i::Sherpa_i(const std::string& name, ISvcLocator* pSvcLocator)
41 : GenModule(name, pSvcLocator)
42{
43 #ifdef IS_SHERPA_3
44 declareProperty("BaseFragment", m_inputfiles["Base.yaml"] = "");
45 declareProperty("RunCard", m_inputfiles["Sherpa.yaml"] = "");
46 #endif
47}
48
49
50
52 if (m_plugincode != "") {
54 #ifndef IS_SHERPA_3
55 m_params.value().push_back("SHERPA_LDADD=Sherpa_iPlugin");
56 #endif
57 }
58
59 ATH_MSG_INFO("Sherpa initialising...");
60
61 #ifdef IS_SHERPA_3
62 for (auto& inputfile : m_inputfiles) {
63 // remove first line and last character containing '"'
64 // TODO fix Python/C++ string passing, to not contain " in first place
65 inputfile.second.erase(0, inputfile.second.find("\n") + 1);
66 inputfile.second.pop_back();
67 }
68 #endif
69
70 ATH_MSG_DEBUG("... compiling plugin code");
71 if (m_plugincode != "") {
73 #ifdef IS_SHERPA_3
74 m_inputfiles["Base.yaml"] += "SHERPA_LDADD: Sherpa_iPlugin \n";
75 #else
76 m_params.value().push_back("SHERPA_LDADD=Sherpa_iPlugin");
77 #endif
78 }
79
80 ATH_MSG_DEBUG("... seeding Athena random number generator");
81 p_rndEngine = getRandomEngineDuringInitialize("SHERPA", m_randomSeed, m_dsid); // NOT THREAD-SAFE
82
83 #ifdef IS_SHERPA_3
84 ATH_MSG_DEBUG("... adapting output level");
85 if( msg().level()==MSG::FATAL || msg().level()==MSG::ERROR || msg().level()==MSG::WARNING ){
86 m_inputfiles["Base.yaml"] += "\nEVT_OUTPUT: 0 \n";
87 }
88 else if(msg().level()==MSG::INFO){
89 m_inputfiles["Base.yaml"] += "\nEVT_OUTPUT: 2 \n";
90 }
91 else if(msg().level()==MSG::DEBUG){
92 m_inputfiles["Base.yaml"] += "\nEVT_OUTPUT: 15 \n";
93 }
94 else{
95 m_inputfiles["Base.yaml"] += "\nEVT_OUTPUT: 15 \n";
96 }
97
98 ATH_MSG_DEBUG("... writing input files to directory");
99 for (auto& inputfile : m_inputfiles) {
100 // write input content to file in working directory
101 FILE *file = fopen(inputfile.first.c_str(),"w");
102 if (!file) {
103 ATH_MSG_ERROR("Cannot open " << inputfile.first);
104 return StatusCode::FAILURE;
105 }
106 fputs(inputfile.second.c_str(),file);
107 fclose(file);
108 ATH_MSG_INFO("Sherpa_i using the following settings in "+inputfile.first);
109 ATH_MSG_INFO("\n"+inputfile.second+"\n");
110 }
111
112 ATH_MSG_DEBUG("... go Sherpa!");
113 int argc = 2;
114 char** argv = new char*[2];
115 argv[0] = new char[7];
116 argv[1] = new char[34];
117 strcpy(argv[0], "Sherpa");
118 strcpy(argv[1], "RUNDATA: [Base.yaml, Sherpa.yaml]");
119 p_sherpa = new SHERPA::Sherpa(argc, argv);
120 delete [] argv;
121 #else
122 p_sherpa = new SHERPA::Sherpa();
123 #endif
124
125
126 #ifdef IS_SHERPA_3
127
128 try {
129 p_sherpa->InitializeTheRun();
130 p_sherpa->InitializeTheEventHandler();
131 }
132 catch (const ATOOLS::normal_exit& exception) {
133 ATH_MSG_ERROR("Normal exit caught, this probably means:");
134 ATH_MSG_ERROR("Have to compile Amegic libraries");
135 ATH_MSG_ERROR("You probably want to run ./makelibs");
136 return StatusCode::FAILURE;
137 }
138 catch (const ATOOLS::Exception& exception) {
139 ATH_MSG_ERROR("Unwanted ATOOLS::exception caught.");
140 ATH_MSG_ERROR(exception);
141 return StatusCode::FAILURE;
142 }
143 #else
144
145 try {
146 int argc;
147 char** argv;
148 getParameters(argc, argv);
149 p_sherpa->InitializeTheRun(argc,(char **)argv);
150 delete [] argv;
151
152 p_sherpa->InitializeTheEventHandler();
153 }
154 catch (const ATOOLS::Exception& exception) {
155 if (exception.Class()=="Matrix_Element_Handler" && exception.Type()==ATOOLS::ex::normal_exit) {
156 ATH_MSG_ERROR("Have to compile Amegic libraries");
157 ATH_MSG_ERROR("You probably want to run ./makelibs");
158 }
159 else {
160 ATH_MSG_ERROR("Unwanted ATOOLS::exception caught.");
161 ATH_MSG_ERROR(exception);
162 }
163 return StatusCode::FAILURE;
164 }
165 #endif
166 catch (const std::exception& exception) {
167 ATH_MSG_ERROR("std::exception caught.");
168 return StatusCode::FAILURE;
169 }
170
171 #ifdef HEPMC3
172 m_runinfo = std::make_shared<HepMC3::GenRunInfo>();
174 struct HepMC3::GenRunInfo::ToolInfo generator = {
175 std::string("SHERPA"),
176 std::string(SHERPA_VERSION)+ "." + std::string(SHERPA_SUBVERSION),
177 std::string("Used generator")
178 };
179 m_runinfo->tools().push_back(std::move(generator));
180 #endif
181 return StatusCode::SUCCESS;
182}
183
184
186 ATH_MSG_DEBUG("Sherpa_i in callGenerator()");
187 //Re-seed the random number stream
188 long seeds[7];
189 const EventContext& ctx = Gaudi::Hive::currentContext();
190 ATHRNG::calculateSeedsMC21(seeds, "SHERPA", ctx.eventID().event_number(), m_dsid, m_randomSeed);
191 p_rndEngine->setSeeds(seeds, 0); // NOT THREAD-SAFE
192
193 do {
194 ATH_MSG_DEBUG("Trying to generate event with Sherpa");
195 } while (p_sherpa->GenerateOneEvent()==false);
196
197 const size_t genEvents = ATOOLS::rpa->gen.NumberOfGeneratedEvents();
198 if (genEvents%1000==0) {
199 ATH_MSG_INFO("Passed "<<genEvents<<" events.");
200 }
201
202 return StatusCode::SUCCESS;
203}
204
205StatusCode Sherpa_i::fillEvt(HepMC::GenEvent* event) {
206 ATH_MSG_DEBUG( "Sherpa_i Filling event");
207#ifdef HEPMC3
208 if (!event->run_info()) event->set_run_info(m_runinfo);
209#endif
210 p_sherpa->FillHepMCEvent(*event);
211
212
213#ifdef HEPMC3
214//Weight, MEWeight, WeightNormalisation, NTrials
215 if (event->weights().size()>2) {
216 double nominal = event->weight("Weight");
217 for (const auto& name: event->weight_names()) {
218 if (name == "WeightNormalisation") continue;
219 if (name == "NTrials") continue;
220 if (name == "Weight") continue;
221 if (name == "NTrials") continue;
222 if (std::abs(event->weight(name)) > m_variation_weight_cap*std::abs(nominal)) {
223 ATH_MSG_INFO("Capping variation" << name << " = " << event->weight(name)/nominal << "*nominal");
224 event->weight(name) *= m_variation_weight_cap*std::abs(nominal)/std::abs(event->weight(name));
225 }
226 ATH_MSG_DEBUG("Sherpa WEIGHT " << name << " value="<< event->weight(name));
227 }
228 }
229#else
230 if (event->weights().size()>2) {
231 for (size_t i=0; i<event->weights().size(); ++i) {
232 if (i>3) { // cap variation weights
233 // cap variation weights at m_variation_weight_cap*nominal to avoid spikes from numerical instability
234 if (std::abs(event->weights()[i]) > m_variation_weight_cap*std::abs(event->weights()[0])) {
235 ATH_MSG_INFO("Capping variation" << i << " = " << event->weights()[i]/event->weights()[0] << "*nominal");
236 event->weights()[i] *= m_variation_weight_cap*std::abs(event->weights()[0])/std::abs(event->weights()[i]);
237 }
238 }
239 ATH_MSG_DEBUG("Sherpa WEIGHT " << i << " value="<< event->weights()[i]);
240 }
241 }
242#endif
243
244#ifdef HEPMC3
245 event->set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
246#else
247 GeVToMeV(event); //unit check
248#endif
249
250
251 return StatusCode::SUCCESS;
252}
253
255
256 ATH_MSG_INFO("Sherpa_i finalize()");
257
258 std::cout << "MetaData: generator = Sherpa" << SHERPA_VERSION << "." << SHERPA_SUBVERSION << std::endl;
259 std::cout << "MetaData: cross-section (nb)= " << p_sherpa->TotalXS()/1000.0*m_xsscale << std::endl;
260
261 std::cout << "MetaData: PDF = " << p_sherpa->PDFInfo() << std::endl;
262
263 std::cout << "Named variations initialised by Sherpa:" << std::endl;
264 std::cout << *p_sherpa->GetInitHandler()->GetVariations() << std::endl;
265
266 p_sherpa->SummarizeRun();
267
268 if (m_cleanup) {
269 ATH_MSG_INFO("Deleting left-over files from working directory.");
270 system("rm -rf Results.db Process MIG_*.db MPI_*.dat libSherpa*.so libProc*.so");
271 }
272
273 return StatusCode::SUCCESS;
274}
275
276
277#ifndef IS_SHERPA_3
278void Sherpa_i::getParameters(int &argc, char** &argv) {
279 std::vector<std::string> params;
280
281 // set some ATLAS specific default values as a starting point
282 params.push_back("EXTERNAL_RNG=Atlas_RNG");
283
284 /***
285 Adopt Atlas Debug Level Scheme
286 ***/
287
288 std::string verbose_arg;
289 MsgStream log(msgSvc(), name());
290 if( log.level()==MSG::FATAL || log.level()==MSG::ERROR || log.level()==MSG::WARNING ){
291 params.push_back("OUTPUT=0");
292 }
293 else if(log.level()==MSG::INFO){
294 params.push_back("OUTPUT=2");
295 }
296 else if(log.level()==MSG::DEBUG){
297 params.push_back("OUTPUT=3");
298 }
299 else{
300 params.push_back("OUTPUT=15");
301 }
302
303 // disregard manual RUNDATA setting if run card given in JO
304 if (m_runcard != "") m_params.value().push_back("RUNDATA=Run.dat");
305
306 // allow to overwrite all parameters from JO file
307 params.insert(params.begin()+params.size(), m_params.begin(), m_params.end());
308
309 // create Run.dat file if runcard explicitely given
310 if (m_runcard != "") {
311 FILE *file = fopen("Run.dat","w");
312 if (!file) {
313 ATH_MSG_ERROR("Cannot open Run.dat");
314 }
315 else {
316 fputs(m_runcard.value().c_str(),file);
317 fclose(file);
318 }
319 }
320
321 /***
322 Convert into Sherpas argc/argv arguments
323 ***/
324 argc = 1+params.size();
325 argv = new char * [ 1+params.size() ];
326 argv[0] = new char[7];
327 strcpy(argv[0], "Sherpa");
328
329 ATH_MSG_INFO("Sherpa_i using the following Arguments");
331 for(size_t i=0; i<params.size(); i++) {
332 ATH_MSG_INFO(" [ " << params[i] << " ] ");
333 argv[i+1] = new char[params[i].size()+1];
334 strcpy(argv[i+1], params[i].c_str());
335 }
336 ATH_MSG_INFO("End Sherpa_i Argument List");
337 ATH_MSG_INFO("Further Sherpa initialisation output will be redirected to the LOG_FILE specified above.");
338
339}
340#endif
341
342void Sherpa_i::compilePlugin(const std::string& pluginCode) {
343 // TODO: not very pretty, should we eventually do this in Python instead (base fragment)
344 FILE *file = fopen("Sherpa_iPlugin.C","w");
345 if (!file) {
346 ATH_MSG_ERROR("Cannot open Sherpa_iPlugin.C");
347 }
348 else {
349 fputs(pluginCode.c_str(),file);
350 fclose(file);
351 }
352 std::string command;
353 // Python -> C++ string conversion seems to add quote character as first
354 // and last line if the string contains quotes (like always in a plugin)
355 // thus removing them here
356 command += "tail -n +2 Sherpa_iPlugin.C | head -n -1 > Sherpa_iPlugin.C.tmp; mv Sherpa_iPlugin.C.tmp Sherpa_iPlugin.C; ";
357 command += "g++ -shared -std=c++0x -g ";
358 command += "-I`Sherpa-config --incdir` ";
359 command += "`Sherpa-config --ldflags` ";
360 command += "-I$FASTJETPATH/include ";
361 command += "-fPIC -o libSherpa_iPlugin.so Sherpa_iPlugin.C";
362 ATH_MSG_INFO("Now compiling plugin library using: "+command);
363 if (system(command.c_str())!=0) {
364 ATH_MSG_ERROR("Error compiling plugin library.");
365 }
366}
367
371using namespace ATOOLS;
372
373Atlas_RNG::Atlas_RNG(CLHEP::HepRandomEngine* engine) :
374 External_RNG(), p_engine(engine), m_filename("Config.conf")
375{
376}
377
378Atlas_RNG::~Atlas_RNG() { std::ignore = std::remove(m_filename.c_str()); }
379
381
382 return CLHEP::RandFlat::shoot(p_engine);
383
384}
385
386const std::string Atlas_RNG::GenerateUID() const {
387 std::string result{""};
388 const int nMax = 26;
389 char alphabet[nMax] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
390 'h', 'i', 'j', 'k', 'l', 'm', 'n',
391 'o', 'p', 'q', 'r', 's', 't', 'u',
392 'v', 'w', 'x', 'y', 'z' };
393 for (size_t i = 0; i < 6; ++i) {
394 result += alphabet[rand() % nMax];
395 }
396 return result;
397}
398
400 // We set the file name first time the worker calls SaveStatus
401 std::call_once(m_once_flag_atlas_rng, [&](){
402 struct stat info;
403 if ( !stat("/dev/shm", &info)) {
404 m_filename = "/dev/shm/Config.conf.";
405 }
407 std::cout << "RNG state being saved to: " << m_filename << std::endl;
408 });
409 p_engine->saveStatus(m_filename.c_str());
410}
411
412void Atlas_RNG::RestoreStatus() { p_engine->restoreStatus(m_filename.c_str()); }
413
414// some getter magic to make this random number generator available to sherpa
415// DECLARE_GETTER doesn't compile with c++20 in Sherpa versions before 3.
416#ifdef IS_SHERPA_3
417DECLARE_GETTER(Atlas_RNG,"Atlas_RNG",External_RNG,RNG_Key);
418#else
419namespace ATOOLS {
420template <> class Getter<External_RNG,RNG_Key,Atlas_RNG,std::less<std::string>>:
421 public Getter_Function<External_RNG,RNG_Key,std::less<std::string>> {
422private:
424protected:
425 void PrintInfo(std::ostream &str,const size_t width) const;
426 Object_Type *operator()(const Parameter_Type &parameters) const;
427public:
428 Getter(const bool &d=true):
429 Getter_Function<External_RNG,RNG_Key,std::less<std::string>>("Atlas_RNG")
430 { SetDisplay(d); }
431};
432}
433ATOOLS::Getter<External_RNG,RNG_Key,Atlas_RNG>
434ATOOLS::Getter<External_RNG,RNG_Key,Atlas_RNG>::s_initializer(true);
435#endif
436
437External_RNG *ATOOLS::Getter<External_RNG,RNG_Key,Atlas_RNG>::operator()(const RNG_Key &) const
438{ return new Atlas_RNG(p_rndEngine); }
439
440void ATOOLS::Getter<External_RNG,RNG_Key,Atlas_RNG>::PrintInfo(std::ostream &str,const size_t) const
441{ str<<"Atlas RNG interface"; }
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
CLHEP::HepRandomEngine * p_rndEngine
Definition Sherpa_i.cxx:38
const double width
Object_Type * operator()(const Parameter_Type &parameters) const
void PrintInfo(std::ostream &str, const size_t width) const
static Getter< External_RNG, RNG_Key, Atlas_RNG, std::less< std::string > > s_initializer
Definition Sherpa_i.cxx:423
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Atlas_RNG(CLHEP::HepRandomEngine *)
Definition Sherpa_i.cxx:373
void SaveStatus()
Definition Sherpa_i.cxx:399
CLHEP::HepRandomEngine * p_engine
Definition Sherpa_i.h:78
double Get()
Definition Sherpa_i.cxx:380
void RestoreStatus()
Definition Sherpa_i.cxx:412
std::string m_filename
Definition Sherpa_i.h:79
std::once_flag m_once_flag_atlas_rng
Definition Sherpa_i.h:80
const std::string GenerateUID() const
Definition Sherpa_i.cxx:386
void GeVToMeV(HepMC::GenEvent *evt)
Scale event energies/momenta by x 1000.
Definition GenBase.cxx:58
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
StatusCode genFinalize()
For finalising the generator, if required.
Definition Sherpa_i.cxx:254
StringProperty m_runcard
FIXME unused?
Definition Sherpa_i.h:42
StatusCode genInitialize()
For initializing the generator, if required.
Definition Sherpa_i.cxx:51
SHERPA::Sherpa * p_sherpa
Definition Sherpa_i.h:32
StringProperty m_plugincode
Optional code for plugin library to compile and load at run time.
Definition Sherpa_i.h:61
StringArrayProperty m_params
List of additional Sherpa parameters beyond run card snippet (from JO file)
Definition Sherpa_i.h:45
BooleanProperty m_cleanup
Definition Sherpa_i.h:67
IntegerProperty m_dsid
Definition Sherpa_i.h:70
void compilePlugin(const std::string &)
Definition Sherpa_i.cxx:342
Sherpa_i(const std::string &name, ISvcLocator *pSvcLocator)
Definition Sherpa_i.cxx:40
StatusCode callGenerator()
For calling the generator on each iteration of the event loop.
Definition Sherpa_i.cxx:185
DoubleProperty m_variation_weight_cap
Variation weight cap factor.
Definition Sherpa_i.h:64
DoubleProperty m_xsscale
Definition Sherpa_i.h:66
StatusCode fillEvt(HepMC::GenEvent *evt)
For filling the HepMC event object.
Definition Sherpa_i.cxx:205
void getParameters(int &argc, char **&argv)
Definition Sherpa_i.cxx:278
STL class.
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.
STL namespace.
DataModel_detail::iterator< DVL > remove(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, const T &value)
Specialization of remove for DataVector/List.
MsgStream & msg
Definition testRead.cxx:32
TFile * file