gambit is hosted by Hepforge, IPPP Durham
GAMBIT  v1.5.0-2191-ga4742ac
a Global And Modular Bsm Inference Tool
getPy8Collider.hpp
Go to the documentation of this file.
1 // GAMBIT: Global and Modular BSM Inference Tool
2 // *********************************************
37 
38 
40 
41 //#define COLLIDERBIT_DEBUG
42 #define DEBUG_PREFIX "DEBUG: OMP thread " << omp_get_thread_num() << ": "
43 
44 namespace Gambit
45 {
46 
47  namespace ColliderBit
48  {
49 
51  template<typename PythiaT, typename EventT, typename hepmc_writerT>
53  const MCLoopInfo& RunMC,
54  const SLHAstruct& slha,
55  const str model_suffix,
56  const int iteration,
57  void(*wrapup)(),
58  const Options& runOptions)
59  {
60  static bool first = true;
61  static str pythia_doc_path;
62  static double xsec_veto_fb;
63 
64  if (iteration == BASE_INIT)
65  {
66  // Setup the Pythia documentation path and print the banner once
67  if (first)
68  {
69  const str be = "Pythia" + model_suffix;
70  const str ver = Backends::backendInfo().default_version(be);
71  pythia_doc_path = Backends::backendInfo().path_dir(be, ver) + "/../share/Pythia8/xmldoc/";
72  result.banner(pythia_doc_path);
73  first = false;
74  }
75  }
76 
77  // To make sure that the Pythia instance on each OMP thread gets all the
78  // options it should, all the options parsing and initialisation happens in
79  // COLLIDER_INIT_OMP (OMP parallel) rather than COLLIDER_INIT (only thread 0).
80  // We may want to split this up, so that all the yaml options are parsed in
81  // COLLIDER_INIT (by thread 0), and used to initialize the 'result' instance
82  // of each thread within COLLIDER_INIT_OMP.
83  //
84  // else if (iteration == COLLIDER_INIT)
85  // {
86  // // Do the option parsing here?
87  // }
88 
89  else if (iteration == COLLIDER_INIT_OMP)
90  {
91 
92  std::vector<str> pythiaOptions;
93 
94  // By default we tell Pythia to be quiet. (Can be overridden from yaml settings)
95  pythiaOptions.push_back("Print:quiet = on");
96  pythiaOptions.push_back("SLHA:verbose = 0");
97 
98  // Get options from yaml file.
99  const double xsec_veto_default = 0.0;
100  const bool partonOnly_default = false;
101  const double antiktR_default = 0.4;
102  if (runOptions.hasKey(RunMC.current_collider()))
103  {
104  YAML::Node colNode = runOptions.getValue<YAML::Node>(RunMC.current_collider());
105  Options colOptions(colNode);
106  xsec_veto_fb = colOptions.getValueOrDef<double>(xsec_veto_default, "xsec_veto");
107  result.partonOnly = colOptions.getValueOrDef<bool>(partonOnly_default, "partonOnly");
108  result.antiktR = colOptions.getValueOrDef<double>(antiktR_default, "antiktR");
109  if (colOptions.hasKey("pythia_settings"))
110  {
111  std::vector<str> addPythiaOptions = colNode["pythia_settings"].as<std::vector<str> >();
112  pythiaOptions.insert(pythiaOptions.end(), addPythiaOptions.begin(), addPythiaOptions.end());
113  }
114  }
115  else
116  {
117  xsec_veto_fb = xsec_veto_default;
118  result.partonOnly = partonOnly_default;
119  result.antiktR = antiktR_default;
120  }
121 
122  // We need showProcesses for the xsec veto.
123  pythiaOptions.push_back("Init:showProcesses = on");
124 
125  // We need "SLHA:file = slhaea" for the SLHAea interface.
126  pythiaOptions.push_back("SLHA:file = slhaea");
127 
128  // Variables needed for the xsec veto
129  std::stringstream processLevelOutput;
130  str _junk, readline;
131  int code, nxsec;
132  double xsec, totalxsec;
133 
134  // Each thread needs an independent Pythia instance at the start
135  // of each event generation loop.
136  // Thus, the actual Pythia initialization is
137  // *after* COLLIDER_INIT, within omp parallel.
138 
139  result.clear();
140 
141  // Add the thread-specific seed to the Pythia options
142  str seed = std::to_string(int(Random::draw() * 899990000.));
143  pythiaOptions.push_back("Random:seed = " + seed);
144 
145  #ifdef COLLIDERBIT_DEBUG
146  cout << DEBUG_PREFIX << "getPythia"+model_suffix+": My Pythia seed is: " << seed << endl;
147  #endif
148 
149  try
150  {
151  result.init(pythia_doc_path, pythiaOptions, &slha, processLevelOutput);
152  }
154  {
155  // Append new seed to override the previous one
156  int newSeedBase = int(Random::draw() * 899990000.);
157  pythiaOptions.push_back("Random:seed = " + std::to_string(newSeedBase));
158  try
159  {
160  result.init(pythia_doc_path, pythiaOptions, &slha, processLevelOutput);
161  }
163  {
164  #ifdef COLLIDERBIT_DEBUG
165  cout << DEBUG_PREFIX << "Py8Collider::InitializationError caught in getPy8Collider. Will discard this point." << endl;
166  #endif
167  piped_invalid_point.request("Bad point: Pythia can't initialize");
168  wrapup();
169  return;
170  }
171  }
172 
173  // Should we apply the xsec veto and skip event generation?
174 
175  // - Get the upper limt xsec as estimated by Pythia
176  code = -1;
177  nxsec = 0;
178  totalxsec = 0.;
179  while(true)
180  {
181  std::getline(processLevelOutput, readline);
182  std::istringstream issPtr(readline);
183  issPtr.seekg(47, issPtr.beg);
184  issPtr >> code;
185  if (!issPtr.good() && nxsec > 0) break;
186  issPtr >> _junk >> xsec;
187  if (issPtr.good())
188  {
189  totalxsec += xsec;
190  nxsec++;
191  }
192  }
193 
194  #ifdef COLLIDERBIT_DEBUG
195  cout << DEBUG_PREFIX << "totalxsec [fb] = " << totalxsec * 1e12 << ", veto limit [fb] = " << xsec_veto_fb << endl;
196  #endif
197 
198  // - Check for NaN xsec
199  if (Utils::isnan(totalxsec))
200  {
201  #ifdef COLLIDERBIT_DEBUG
202  cout << DEBUG_PREFIX << "Got NaN cross-section estimate from Pythia." << endl;
203  #endif
204  piped_invalid_point.request("Got NaN cross-section estimate from Pythia.");
205  wrapup();
206  return;
207  }
208 
209  // - Wrap up loop if veto applies
210  if (totalxsec * 1e12 < xsec_veto_fb)
211  {
212  #ifdef COLLIDERBIT_DEBUG
213  cout << DEBUG_PREFIX << "Cross-section veto applies. Will now call Loop::wrapup() to skip event generation for this collider." << endl;
214  #endif
215  wrapup();
216  } else {
217 
218  // Create a dummy event to make Pythia fill its internal list of process codes
219  EventT dummy_pythia_event;
220  try
221  {
222  result.nextEvent(dummy_pythia_event);
223  }
225  {
226  piped_invalid_point.request("Failed to generate dummy test event. Will invalidate point.");
227 
228  #ifdef COLLIDERBIT_DEBUG
229  cout << DEBUG_PREFIX << "Failed to generate dummy test event during COLLIDER_INIT_OMP in getPy8Collider. Check the logs for event details." << endl;
230  #endif
231  #pragma omp critical (pythia_event_failure)
232  {
233  std::stringstream ss;
234  dummy_pythia_event.list(ss, 1);
235  logger() << LogTags::debug << "Failed to generate dummy test event during COLLIDER_INIT_OMP iteration in getPy8Collider. Pythia record for the event that failed:\n" << ss.str() << EOM;
236  }
237  }
238 
239  }
240 
241  }
242 
243  }
244 
245 
246  // Get SLHAea object with spectrum and decays for Pythia -- SUSY version
247  #define GET_SPECTRUM_AND_DECAYS_FOR_PYTHIA_SUSY(NAME, SPECTRUM) \
248  void NAME(SLHAstruct& result) \
249  { \
250  using namespace Pipes::NAME; \
251  static const int slha_version = runOptions->getValueOrDef<int>(2, "slha_version"); \
252  static const bool write_summary_to_log = \
253  runOptions->getValueOrDef<bool>(false, "write_summary_to_log"); \
254  \
255  if ((slha_version != 1) && (slha_version != 2)) \
256  { \
257  ColliderBit_error().raise(LOCAL_INFO, \
258  "The option 'slha_version' must be set to 1 or 2 (default)."); \
259  } \
260  result.clear(); \
261  /* Get decays */ \
262  result = Dep::decay_rates->getSLHAea(slha_version, false, *Dep::SLHA_pseudonyms); \
263  /* Get spectrum */ \
264  SLHAstruct slha_spectrum = Dep::SPECTRUM->getSLHAea(slha_version); \
265  result.insert(result.begin(), slha_spectrum.begin(), slha_spectrum.end()); \
266  /* Add MODSEL block if not found */ \
267  if(result.find("MODSEL") == result.end()) \
268  { \
269  SLHAea::Block block("MODSEL"); \
270  block.push_back("BLOCK MODSEL # Model selection"); \
271  SLHAea::Line line; \
272  line << 1 << 0 << "# Tell Pythia that this is a SUSY model."; \
273  block.push_back(line); \
274  result.push_front(block); \
275  } \
276  \
277  if (write_summary_to_log) \
278  { \
279  std::stringstream SLHA_log_output; \
280  SLHA_log_output << "SLHA" << slha_version << " input to Pythia:\n" << result.str() \
281  << "\n"; \
282  logger() << SLHA_log_output.str() << EOM; \
283  } \
284  }
285 
286 
287  // Get SLHAea object with spectrum and decays for Pythia -- non-SUSY version
288  #define GET_SPECTRUM_AND_DECAYS_FOR_PYTHIA_NONSUSY(NAME, SPECTRUM) \
289  void NAME(SLHAstruct& result) \
290  { \
291  using namespace Pipes::NAME; \
292  result.clear(); \
293  /* Get decays */ \
294  result = Dep::decay_rates->getSLHAea(2); \
295  /* Get spectrum */ \
296  SLHAstruct slha_spectrum = Dep::SPECTRUM->getSLHAea(2); \
297  result.insert(result.begin(), slha_spectrum.begin(), slha_spectrum.end()); \
298  }
299 
300 
302  #ifdef EXCLUDE_HEPMC
303  #define HEPMC_TYPE(PYTHIA_NS) void
304  #else
305  #define HEPMC_TYPE(PYTHIA_NS) PYTHIA_NS::Pythia8::GAMBIT_hepmc_writer
306  #endif
307 
309  #define GET_SPECIFIC_PYTHIA(NAME, PYTHIA_NS, MODEL_EXTENSION) \
310  void NAME(Py8Collider<PYTHIA_NS::Pythia8::Pythia, \
311  PYTHIA_NS::Pythia8::Event, \
312  HEPMC_TYPE(PYTHIA_NS)> &result) \
313  { \
314  using namespace Pipes::NAME; \
315  static SLHAstruct slha; \
316  \
317  if (*Loop::iteration == BASE_INIT) \
318  { \
319  /* SLHAea object constructed from dependencies on the spectrum and decays. */ \
320  slha.clear(); \
321  slha = *Dep::SpectrumAndDecaysForPythia; \
322  } \
323  \
324  getPy8Collider(result, *Dep::RunMC, slha, #MODEL_EXTENSION, \
325  *Loop::iteration, Loop::wrapup, *runOptions); \
326  }
327 
328 
331  #define GET_SPECIFIC_PYTHIA_SLHA(NAME, PYTHIA_NS, MODEL_EXTENSION) \
332  void NAME(Py8Collider<PYTHIA_NS::Pythia8::Pythia, \
333  PYTHIA_NS::Pythia8::Event, \
334  HEPMC_TYPE(PYTHIA_NS)> &result) \
335  { \
336  using namespace Pipes::NAME; \
337  static SLHAstruct slha; \
338  \
339  if (*Loop::iteration == COLLIDER_INIT) \
340  { \
341  const pair_str_SLHAstruct& filename_content_pair = *Dep::SLHAFileNameAndContent; \
342  if (filename_content_pair.first.empty()) \
343  { \
344  piped_invalid_point.request("Got empty SLHA filename. Will invalidate point."); \
345  } \
346  } \
347  \
348  getPy8Collider(result, *Dep::RunMC, Dep::SLHAFileNameAndContent->second, \
349  #MODEL_EXTENSION, *Loop::iteration, Loop::wrapup, *runOptions); \
350  }
351 
352 
354  #define GET_PYTHIA_AS_BASE_COLLIDER(NAME) \
355  void NAME(const BaseCollider* &result) \
356  { \
357  result = &(*Pipes::NAME::Dep::HardScatteringSim); \
358  } \
359 
360  }
361 
362 }
void clear()
Reset this instance for reuse, avoiding the need for "new" or "delete".
Definition: Py8Collider.hpp:94
bool partonOnly
Flag indicating if events from this collider should be processed as parton-only or full events...
void nextEvent(EventT &event) const
Event generation for any Pythia interface to Gambit.
double antiktR
The jet radius used for the anti-kt jet clustering.
void getPy8Collider(Py8Collider< PythiaT, EventT, hepmc_writerT > &result, const MCLoopInfo &RunMC, const SLHAstruct &slha, const str model_suffix, const int iteration, void(*wrapup)(), const Options &runOptions)
Retrieve a Pythia hard-scattering Monte Carlo simulation.
#define DEBUG_PREFIX
void banner(const std::string pythiaDocPath)
Create a useless Pythia instance just to print the banner.
Piped_invalid_point piped_invalid_point
Global instance of piped invalid point class.
Definition: exceptions.cpp:544
Declarations common to all ColliderBit event loop functions.
bool hasKey(const args &... keys) const
Getters for key/value pairs (which is all the options node should contain)
TYPE getValue(const args &... keys) const
An exception for when Pythia fails to initialize.
Definition: Py8Collider.hpp:63
void init()
Initialize with no settings (error): override version.
SLHAea::Coll SLHAstruct
Less confusing name for SLHAea container class.
static double draw()
Draw a single uniform random deviate from the interval (0,1) using the chosen RNG engine...
const str & current_collider() const
Get the current collider.
Definition: MCLoopInfo.cpp:127
const Logging::endofmessage EOM
Explicit const instance of the end of message struct in Gambit namespace.
Definition: logger.hpp:100
EXPORT_SYMBOLS Logging::LogMaster & logger()
Function to retrieve a reference to the Gambit global log object.
Definition: logger.cpp:95
std::string str
Shorthand for a standard string.
Definition: Analysis.hpp:35
DS5_MSPCTM DS_INTDOF int
An exception for when Pythia fails to generate events.
Definition: Py8Collider.hpp:71
A specializable, recyclable class interfacing ColliderBit and Pythia.
Definition: Py8Collider.hpp:36
void request(std::string message)
Request an exception.
Definition: exceptions.cpp:471
TODO: see if we can use this one:
Definition: Analysis.hpp:33
A small wrapper object for &#39;options&#39; nodes.
Container for event loop status data and settings.
Definition: MCLoopInfo.hpp:31