StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ShowerMEsMadgraph.h
1 // ShowerMEsMadgraph.h is a part of the PYTHIA event generator.
2 // Copyright (C) 2020 Peter Skands, Stefan Prestel, Philip Ilten, Torbjorn
3 // Sjostrand.
4 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
5 // Please respect the MCnet Guidelines, see GUIDELINES for details.
6 
7 // This file contains the Madgraph parton shower ME plugin class which
8 // interfaces with matrix elements generated with the
9 // PY8Kernels/MG5MES plugin to MadGraph 5.
10 
11 #ifndef Pythia8_ShowerMEsMadgraph_H
12 #define Pythia8_ShowerMEsMadgraph_H
13 
14 // Include Pythia headers.
15 #include "Pythia8/ShowerMEs.h"
16 
17 // Include Madgraph PY8MEs plugin headers.
18 #include "PY8ME.h"
19 #include "PY8MEs.h"
20 
21 namespace Pythia8 {
22 
23 //==========================================================================
24 
25 
26 class ShowerMEsMadgraph : public ShowerMEs {
27 
28 public:
29 
30  // Constructor.
31  ShowerMEsMadgraph() {isInitPtr = false; isInit = false;
32  libPtr = nullptr; modelPtr = nullptr;}
33 
34  // Destructor.
35  ~ShowerMEsMadgraph() {if (libPtr != nullptr) delete libPtr;
36  if (modelPtr != nullptr) delete modelPtr;}
37 
38  // VINCIA methods.
39  // Initialise the Madgraph model, parameters, and couplings.
40  bool initVincia() override;
41  // Get the matrix element squared for a particle state.
42  double me2Vincia(vector<Particle> state, int nIn) override;
43  // Check if the process is available.
44  bool hasProcessVincia(vector<int> idIn, vector<int> idOut,
45  set<int> sChan) override;
46 
47  // Dire methods.
48  bool initDire(Info*, string card) override;
49  bool isAvailableMEDire(vector <int> in, vector<int> out) override;
50  bool isAvailableMEDire(const Pythia8::Event& event) override;
51  double calcMEDire(const Pythia8::Event& event) override;
52 
53  // Common methods.
54  // Get pointer to matrix element, e.g. to check if process exists in
55  // library.
56  PY8MEs_namespace::PY8ME* getProcess(vector<int> idIn, vector<int> idOut,
57  set<int> sChan);
58 
59 private:
60 
61  PY8MEs_namespace::PY8MEs* libPtr;
62  PARS* modelPtr;
63 
64 };
65 
66 //--------------------------------------------------------------------------
67 
68 // Initialise the Madgraph model, parameters, and couplings.
69 
70 bool ShowerMEsMadgraph::initVincia() {
71 
72  // Check if pointers initialized.
73  verbose = settingsPtr->mode("Vincia:verbose");
74  if (verbose > normal) printOut("ShowerMEsMadgraph::init", "...");
75  if (!isInitPtr) {
76  printOut("ShowerMEsMadgraph::init",
77  "Cannot initialize, pointers not set.");
78  return false;
79  }
80  isInit = true;
81 
82  // Set colour depth (TODO: via "Vincia:matchingFullColour").
83  colourDepth = 1;
84 
85  // Create new model instance.
86  if (verbose >= quiteloud) printOut("ShowerMEsMadgraph::init",
87  " setting MG C++ masses, widths, couplings...");
88  if (modelPtr != nullptr) delete modelPtr;
89  modelPtr = new PARS();
90  modelPtr->setIndependentParameters(particleDataPtr,coupSMPtr,slhaPtr);
91  modelPtr->setIndependentCouplings();
92  if (verbose >= quiteloud) {
93  modelPtr->printIndependentParameters();
94  modelPtr->printIndependentCouplings();
95  }
96 
97  // In the VINCIA context, alphaS_MGME = 1/4pi (- > gS = 1; we
98  // control the running separately). Thus, even the Madgraph "dependent"
99  // parameters only need to be set once.
100 
101  // Alternatively, we could evaluate the QCD coupling at MZ but should
102  // then use a coupling definition from a Vincia parameter list rather
103  // than PYTHIA's couplings.
104  // double muDefME = 91.2;
105  // double alpS = coupSMPtr->alphaS(pow2(muDefME));
106 
107  // The following is equivalent to
108  // PY8MEs::updateModelDependentCouplingsWithPY8(...)
109  double alpS = 1.0 / ( 4 * M_PI );
110  modelPtr->setDependentParameters(particleDataPtr, coupSMPtr, slhaPtr,
111  alpS);
112  modelPtr->setDependentCouplings();
113 
114  // Construct Madgraph process library.
115  if (verbose >= superdebug) printOut("ShowerMEsMadgraph::init()",
116  " attempting to construct lib");
117  if (libPtr != nullptr) delete libPtr;
118  libPtr = new PY8MEs_namespace::PY8MEs(modelPtr);
119  return true;
120 
121 }
122 
123 //--------------------------------------------------------------------------
124 
125 // Check if the process is available.
126 
127 bool ShowerMEsMadgraph::hasProcessVincia(vector<int> idIn, vector<int> idOut,
128  set<int> sChan) {return getProcess(idIn, idOut, sChan) != nullptr;}
129 
130 //--------------------------------------------------------------------------
131 
132 // Get pointer to matrix element, e.g. to check if process exists in
133 // library.
134 
135 PY8MEs_namespace::PY8ME* ShowerMEsMadgraph::getProcess(
136  vector<int> idIn, vector<int> idOut, set<int> sChan) {
137  if (verbose >= superdebug) {
138  cout << " ShowerMEsMadgraph::getProcess(): checking for process";
139  for (int i = 0; i < (int)idIn.size(); ++i) cout << " " << idIn[i];
140  cout << " > ";
141  for (int i = 0; i < (int)idOut.size(); ++i) cout << " " << idOut[i];
142  cout << endl;
143  }
144  if (libPtr != nullptr && libPtr != 0)
145  return libPtr->getProcess(idIn, idOut, sChan);
146  cout << " returning NULL" << endl;
147  return nullptr;
148 }
149 
150 //--------------------------------------------------------------------------
151 
152 // Get the matrix element squared for a particle state.
153 
154 double ShowerMEsMadgraph::me2Vincia(vector<Particle> state, int nIn) {
155 
156  // Prepare vector of incoming ID codes.
157  if (nIn <= 0) return -1;
158  else if (state.size() - nIn < 1) return -1;
159  vector<int> idIn, helOrg, col, acol;
160  vector<Vec4> momenta;
161  idIn.push_back(state[0].id());
162  momenta.push_back(state[0].p());
163  helOrg.push_back(state[0].pol());
164  col.push_back(state[0].col());
165  acol.push_back(state[0].acol());
166  if (nIn == 2) {
167  idIn.push_back(state[1].id());
168  momenta.push_back(state[1].p());
169  helOrg.push_back(state[1].pol());
170  col.push_back(state[1].col());
171  acol.push_back(state[1].acol());
172  }
173  // Prepare vector of outgoing ID codes.
174  vector<int> idOut;
175  for (int i=nIn; i<(int)state.size(); ++i) {
176  idOut.push_back(state[i].id());
177  momenta.push_back(state[i].p());
178  helOrg.push_back(state[i].pol());
179  col.push_back(state[i].col());
180  acol.push_back(state[i].acol());
181  }
182  // Currently not using the option to request specific s-channels.
183  set<int> sChannels;
184 
185  // Access the process.
186  PY8MEs_namespace::process_specifier proc_spec =
187  libPtr->getProcessSpecifier(idIn, idOut, sChannels);
188  PY8MEs_namespace::process_accessor proc_handle =
189  libPtr->getProcess(proc_spec);
190 
191  // Return right away if unavailable.
192  if (proc_handle.second.second < 0) return -1;
193 
194  // Convert momenta and colours to Madgraph format (energy first entry).
195  vector< vector<double> > momentaMG5;
196  vector< int > colacolMG5;
197  for (int i = 0; i < (int)momenta.size(); ++i) {
198  vector<double> pNow;
199  pNow.push_back(momenta[i].e());
200  pNow.push_back(momenta[i].px());
201  pNow.push_back(momenta[i].py());
202  pNow.push_back(momenta[i].pz());
203  momentaMG5.push_back(pNow);
204  colacolMG5.push_back(col[i]);
205  colacolMG5.push_back(acol[i]);
206  }
207 
208  vector<int> i9;
209  // Check if we are doing a (partial) helicity sum.
210  for (int i = 0; i < (int)helOrg.size(); ++i) {
211  // Save indices of unpolarised partons.
212  if (helOrg[i] == 9) i9.push_back(i);
213  }
214 
215  // Explicitly sum over any hel = 9 helicities.
216  vector< vector<int> > helConf;
217  helConf.push_back(helOrg);
218  while (i9.size() > 0) {
219  int i = i9.back();
220  int id = (i < nIn) ? idIn[i] : idOut[i-nIn];
221  // How many spin states.
222  int nS = particleDataPtr->spinType(id);
223  // Massless particles max have max 2 (physical) spin states.
224  if (particleDataPtr->m0(id) == 0.0) nS=min(nS,2);
225  // Create nS copies of helConf, one for each spin state.
226  int helConfSizeNow = helConf.size();
227  for (int iCopy = 1; iCopy <= nS; ++iCopy) {
228  // Set hel for this particle in this copy.
229  // Start from -1, then 1, then 0 (if 3 states).
230  int h = -1;
231  if (nS == 1) h = 0;
232  else if (iCopy == 2) h = 1;
233  else if (iCopy == 3) h = 0;
234  else if (iCopy == 4) h = -2;
235  else if (iCopy == 5) h = 2;
236  for (int iHelConf=0; iHelConf<helConfSizeNow; ++iHelConf) {
237  vector<int> helNow = helConf[iHelConf];
238  helNow[i] = h;
239  // First copy: use existing.
240  if (iCopy == 1) helConf[iHelConf] = helNow;
241  // Subsequent copies: create new.
242  else helConf.push_back(helNow);
243  }
244  }
245  // Remove the particle whose helicities have been summed over.
246  i9.pop_back();
247  }
248  if (verbose >= superdebug) {
249  cout << " in = ";
250  for (int i = 0; i < (int)idIn.size(); ++i) cout << idIn[i] << " ";
251  cout << " out = ";
252  for (int i = 0; i < (int)idOut.size(); ++i) cout << idOut[i] << " ";
253  cout << endl;
254  cout << " number of helicity configurations = " << helConf.size() << endl;
255  for (int i = 0; i < (int)helConf.size(); ++i) {
256  cout << " helConf " << i;
257  for (int j = 0; j < (int)helConf[i].size(); ++j)
258  cout << " " << helConf[i][j];
259  cout << endl;
260  }
261  }
262 
263  // Set properties and return ME2 value.
264  PY8MEs_namespace::PY8ME* proc_ptr = proc_handle.first;
265  vector<int> perms = proc_handle.second.first;
266  int proc_ID = proc_handle.second.second;
267  proc_ptr->setMomenta(momentaMG5);
268  proc_ptr->setProcID(proc_ID);
269  proc_ptr->setPermutation(perms);
270  proc_ptr->setColors(colacolMG5);
271 
272  // Compute helicity sum (and save helicity components if needed later).
273  double me2 = 0.0;
274  me2hel.clear();
275  for (int iHC=0; iHC<(int)helConf.size(); ++iHC) {
276 
277  // Note. could check here if the helConf is physical (consistent
278  // with spins of particles and conserving angular momentum).
279  proc_ptr->setHelicities(helConf[iHC]);
280  double me2now = proc_ptr->sigmaKin();
281  // MG may produce inf/nan for unphysical hel combinations.
282  if ( !isnan(me2now) && !isinf(me2now) ) {
283  // Save helicity matrix element for possible later use.
284  me2hel[helConf[iHC]] = me2now;
285  // Add this helicity ME to me2
286  me2 += me2now;
287  }
288  }
289  me2 *= double(proc_ptr->getSymmetryFactor());
290  return me2;
291 
292 }
293 
294 //--------------------------------------------------------------------------
295 
296 bool ShowerMEsMadgraph::initDire(Info*, string card) {
297 
298  // Redirect output so that Dire can print MG5 initialization.
299  std::streambuf *old = cout.rdbuf();
300  stringstream ss;
301  cout.rdbuf (ss.rdbuf());
302  if (libPtr != nullptr) delete libPtr;
303  libPtr = new PY8MEs_namespace::PY8MEs(card);
304  libPtr->seProcessesIncludeSymmetryFactors(false);
305  libPtr->seProcessesIncludeHelicityAveragingFactors(false);
306  libPtr->seProcessesIncludeColorAveragingFactors(false);
307  libPtr->setProcessesExternalMassesMode(1);
308  // Restore print-out.
309  cout.rdbuf (old);
310 
311  return true;
312 
313 }
314 
315 //--------------------------------------------------------------------------
316 
317 // Check if a matrix element is available.
318 
319 bool ShowerMEsMadgraph::isAvailableMEDire(vector <int> in, vector<int> out) {
320  set<int> req_s_channels;
321  PY8MEs_namespace::PY8ME * query
322  = libPtr->getProcess(in, out, req_s_channels);
323  return (query != 0);
324 }
325 
326 //--------------------------------------------------------------------------
327 
328 // Check if a matrix element is available.
329 
330 bool ShowerMEsMadgraph::isAvailableMEDire(const Pythia8::Event& event) {
331 
332  vector <int> in, out;
333  fillIds(event, in, out);
334  set<int> req_s_channels;
335 
336  PY8MEs_namespace::PY8ME* query
337  = libPtr->getProcess(in, out, req_s_channels);
338  return (query != 0);
339 }
340 
341 //--------------------------------------------------------------------------
342 
343 // Calcuate the matrix element.
344 
345 double ShowerMEsMadgraph::calcMEDire(const Pythia8::Event& event) {
346 
347  vector <int> in, out;
348  fillIds(event, in, out);
349  vector<int> cols;
350  fillCols(event, cols);
351  vector< vector<double> > pvec = fillMoms(event);
352  set<int> req_s_channels;
353  vector<int> helicities;
354 
355  bool success = true;
356  pair < double, bool > res;
357  try {
358  res = libPtr->calculateME(in, out, pvec, req_s_channels, cols,
359  helicities);
360  } catch (const std::exception& e) {
361  success = false;
362  }
363  if (!success) return 0.0;
364  if (res.second) {
365  double me = res.first;
366  PY8MEs_namespace::PY8ME* query
367  = libPtr->getProcess(in, out, req_s_channels);
368  me *= 1./query->getHelicityAveragingFactor();
369  me *= 1./query->getColorAveragingFactor();
370  return me;
371  }
372  // Done
373  return 0.0;
374 
375 }
376 
377 //--------------------------------------------------------------------------
378 
379 // Define external handles to the plugin for dynamic loading.
380 
381 extern "C" {
382 
383  ShowerMEsMadgraph* newShowerMEs() {return new ShowerMEsMadgraph();}
384 
385  void deleteShowerMEs(ShowerMEsMadgraph* mes) {delete mes;}
386 
387 }
388 
389 //==========================================================================
390 
391 } // end namespace Pythia8
392 
393 #endif // end Pythia8_ShowerMEsMadgraph_H