CMS 3D CMS Logo

Pythia6Hadronizer.cc
Go to the documentation of this file.
1 
2 // -*- C++ -*-
3 
4 #include "Pythia6Hadronizer.h"
5 
6 #include "HepMC/GenEvent.h"
7 #include "HepMC/PdfInfo.h"
8 #include "HepMC/PythiaWrapper6_4.h"
9 #include "HepMC/HEPEVT_Wrapper.h"
10 #include "HepMC/IO_HEPEVT.h"
11 
14 
17 
19 
21 
23 
24 HepMC::IO_HEPEVT pythia6_conv;
25 
26 #include "HepPID/ParticleIDTranslations.hh"
27 
28 // NOTE: here a number of Pythia6 routines are declared,
29 // plus some functionalities to pass around Pythia6 params
30 //
33 
34 #include <iomanip>
35 #include <memory>
36 
37 namespace gen {
38 
39  extern "C" {
40 
41  //
42  // these two are NOT part of Pythi6 core code but are "custom" add-ons
43  // we keep them interfaced here, rather than in GenExtensions, because
44  // they tweak not at the ME level, but a step further, at the framgmentation
45  //
46  // stop-hadrons
47  //
48  void pystrhad_(); // init stop-hadrons (id's, names, charges...)
49  void pystfr_(int&); // tweaks fragmentation, fragments the string near to a stop,
50  // to form stop-hadron by producing a new q-qbar pair
51  // gluino/r-hadrons
52  void pyglrhad_();
53  void pyglfr_(); // tweaks fragmentation, fragment the string near to a gluino,
54  // to form gluino-hadron, either by producing a new g-g pair,
55  // or two new q-qbar ones
56 
57  } // extern "C"
58 
60  public:
62 
63  private:
65 
66  void upEvnt() override {
70  }
71 
72  bool upVeto() override {
74  return false;
75 
77  return true;
78 
79  bool retValue = Pythia6Hadronizer::getJetMatching()->match(nullptr, nullptr);
80  // below is old code and a note of it
81  // NOTE: I'm passing NULL pointers, instead of HepMC::GenEvent, etc.
82  //retValur = Pythia6Hadronizer::getJetMatching()->match(0, 0, true);
83  return retValue;
84  }
85  };
86 
87  static struct {
88  int n, npad, k[5][pyjets_maxn];
89  double p[5][pyjets_maxn], v[5][pyjets_maxn];
90  } pyjets_local;
91 
92  JetMatching* Pythia6Hadronizer::fJetMatching = nullptr;
93 
96 
98  : BaseHadronizer(ps),
99  fPy6Service(new Pythia6ServiceWithCallback(ps)), // this will store py6 params for further settings
100  fInitialState(PP),
101  fCOMEnergy(ps.getParameter<double>("comEnergy")),
102  fHepMCVerbosity(ps.getUntrackedParameter<bool>("pythiaHepMCVerbosity", false)),
103  fMaxEventsToPrint(ps.getUntrackedParameter<int>("maxEventsToPrint", 0)),
104  fPythiaListVerbosity(ps.getUntrackedParameter<int>("pythiaPylistVerbosity", 0)),
105  fDisplayPythiaBanner(ps.getUntrackedParameter<bool>("displayPythiaBanner", false)),
106  fDisplayPythiaCards(ps.getUntrackedParameter<bool>("displayPythiaCards", false)) {
107  // J.Y.: the following 3 parameters are hacked "for a reason"
108  //
109  if (ps.exists("PPbarInitialState")) {
110  if (fInitialState == PP) {
112  edm::LogInfo("GeneratorInterface|Pythia6Interface")
113  << "Pythia6 will be initialized for PROTON-ANTIPROTON INITIAL STATE. "
114  << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
115  std::cout << "Pythia6 will be initialized for PROTON-ANTIPROTON INITIAL STATE." << std::endl;
116  std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
117  } else {
118  // probably need to throw on attempt to override ?
119  }
120  } else if (ps.exists("ElectronPositronInitialState")) {
121  if (fInitialState == PP) {
123  edm::LogInfo("GeneratorInterface|Pythia6Interface")
124  << "Pythia6 will be initialized for ELECTRON-POSITRON INITIAL STATE. "
125  << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
126  std::cout << "Pythia6 will be initialized for ELECTRON-POSITRON INITIAL STATE." << std::endl;
127  std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
128  } else {
129  // probably need to throw on attempt to override ?
130  }
131  } else if (ps.exists("ElectronProtonInitialState")) {
132  if (fInitialState == PP) {
134  fBeam1PZ =
135  (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("electronMomentum");
136  fBeam2PZ =
137  (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("protonMomentum");
138  edm::LogInfo("GeneratorInterface|Pythia6Interface")
139  << "Pythia6 will be initialized for ELECTRON-PROTON INITIAL STATE. "
140  << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
141  std::cout << "Pythia6 will be initialized for ELECTRON-PROTON INITIAL STATE." << std::endl;
142  std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
143  } else {
144  // probably need to throw on attempt to override ?
145  }
146  } else if (ps.exists("PositronProtonInitialState")) {
147  if (fInitialState == PP) {
149  fBeam1PZ =
150  (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("positronMomentum");
151  fBeam2PZ =
152  (ps.getParameter<edm::ParameterSet>("ElectronProtonInitialState")).getParameter<double>("protonMomentum");
153  edm::LogInfo("GeneratorInterface|Pythia6Interface")
154  << "Pythia6 will be initialized for POSITRON-PROTON INITIAL STATE. "
155  << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
156  std::cout << "Pythia6 will be initialized for POSITRON-PROTON INITIAL STATE." << std::endl;
157  std::cout << "This is a user-request change from the DEFAULT PROTON-PROTON initial state." << std::endl;
158  } else {
159  // throw on unknown initial state !
160  throw edm::Exception(edm::errors::Configuration, "Pythia6Interface")
161  << " UNKNOWN INITIAL STATE. \n The allowed initial states are: PP, PPbar, ElectronPositron, "
162  "ElectronProton, and PositronProton \n";
163  }
164  }
165 
166  // J.Y.: the following 4 params are "hacked", in the sense
167  // that they're tracked but get in optionally;
168  // this will be fixed once we update all applications
169  //
170 
171  fStopHadronsEnabled = false;
172  if (ps.exists("stopHadrons"))
173  fStopHadronsEnabled = ps.getParameter<bool>("stopHadrons");
174 
175  fGluinoHadronsEnabled = false;
176  if (ps.exists("gluinoHadrons"))
177  fGluinoHadronsEnabled = ps.getParameter<bool>("gluinoHadrons");
178 
179  fImposeProperTime = false;
180  if (ps.exists("imposeProperTime")) {
181  fImposeProperTime = ps.getParameter<bool>("imposeProperTime");
182  }
183 
184  fConvertToPDG = false;
185  if (ps.exists("doPDGConvert"))
186  fConvertToPDG = ps.getParameter<bool>("doPDGConvert");
187 
188  if (ps.exists("jetMatching")) {
189  edm::ParameterSet jmParams = ps.getUntrackedParameter<edm::ParameterSet>("jetMatching");
190 
191  fJetMatching = JetMatching::create(jmParams).release();
192  }
193 
194  // first of all, silence Pythia6 banner printout, unless display requested
195  //
196  if (!fDisplayPythiaBanner) {
197  if (!call_pygive("MSTU(12)=12345")) {
198  throw edm::Exception(edm::errors::Configuration, "PythiaError") << " Pythia did not accept MSTU(12)=12345";
199  }
200  }
201 
202  // silence printouts from PYGIVE, unless display requested
203  //
204  if (!fDisplayPythiaCards) {
205  if (!call_pygive("MSTU(13)=0")) {
206  throw edm::Exception(edm::errors::Configuration, "PythiaError") << " Pythia did not accept MSTU(13)=0";
207  }
208  }
209 
210  // tmp stuff to deal with EvtGen corrupting pyjets
211  // NPartsBeforeDecays = 0;
212  flushTmpStorage();
213  }
214 
216  if (fPy6Service != nullptr)
217  delete fPy6Service;
218  if (fJetMatching != nullptr)
219  delete fJetMatching;
220  }
221 
223 
225  pyjets_local.n = 0;
226  pyjets_local.npad = 0;
227  for (int ip = 0; ip < pyjets_maxn; ip++) {
228  for (int i = 0; i < 5; i++) {
229  pyjets_local.k[i][ip] = 0;
230  pyjets_local.p[i][ip] = 0.;
231  pyjets_local.v[i][ip] = 0.;
232  }
233  }
234  return;
235  }
236 
238  pyjets_local.n = pyjets.n;
239  pyjets_local.npad = pyjets.npad;
240  for (int ip = 0; ip < pyjets_maxn; ip++) {
241  for (int i = 0; i < 5; i++) {
242  pyjets_local.k[i][ip] = pyjets.k[i][ip];
243  pyjets_local.p[i][ip] = pyjets.p[i][ip];
244  pyjets_local.v[i][ip] = pyjets.v[i][ip];
245  }
246  }
247 
248  return;
249  }
250 
252  bool lhe = lheEvent() != nullptr;
253 
254  HepMC::PdfInfo pdf;
255 
256  // if we are in hadronizer mode, we can pass on information from
257  // the LHE input
258  if (lhe) {
259  lheEvent()->fillEventInfo(event().get());
260  lheEvent()->fillPdfInfo(&pdf);
261  } else {
262  // filling in factorization "Q scale" now! pthat moved to binningValues()
263  //
264 
265  if (event()->signal_process_id() <= 0)
266  event()->set_signal_process_id(pypars.msti[0]);
267  if (event()->event_scale() <= 0)
268  event()->set_event_scale(pypars.pari[22]);
269  if (event()->alphaQED() <= 0)
270  event()->set_alphaQED(pyint1.vint[56]);
271  if (event()->alphaQCD() <= 0)
272  event()->set_alphaQCD(pyint1.vint[57]);
273 
274  // get pdf info directly from Pythia6 and set it up into HepMC::GenEvent
275  // S. Mrenna: Prefer vint block
276  //
277  if (pdf.id1() <= 0)
278  pdf.set_id1(pyint1.mint[14] == 21 ? 0 : pyint1.mint[14]);
279  if (pdf.id2() <= 0)
280  pdf.set_id2(pyint1.mint[15] == 21 ? 0 : pyint1.mint[15]);
281  if (pdf.x1() <= 0)
282  pdf.set_x1(pyint1.vint[40]);
283  if (pdf.x2() <= 0)
284  pdf.set_x2(pyint1.vint[41]);
285  if (pdf.pdf1() <= 0)
286  pdf.set_pdf1(pyint1.vint[38] / pyint1.vint[40]);
287  if (pdf.pdf2() <= 0)
288  pdf.set_pdf2(pyint1.vint[39] / pyint1.vint[41]);
289  if (pdf.scalePDF() <= 0)
290  pdf.set_scalePDF(pyint1.vint[50]);
291  }
292 
293  /* 9/9/2010 - JVY: This is the old piece of code - I can't remember why we implemented it this way.
294  However, it's causing problems with pdf1 & pdf2 when processing LHE samples,
295  specifically, because both are set to -1, it tries to fill with Py6 numbers that
296  are NOT valid/right at this point !
297  In general, for LHE/ME event processing we should implement the correct calculation
298  of the pdf's, rather than using py6 ones.
299 
300  // filling in factorization "Q scale" now! pthat moved to binningValues()
301 
302  if (!lhe || event()->signal_process_id() < 0) event()->set_signal_process_id( pypars.msti[0] );
303  if (!lhe || event()->event_scale() < 0) event()->set_event_scale( pypars.pari[22] );
304  if (!lhe || event()->alphaQED() < 0) event()->set_alphaQED( pyint1.vint[56] );
305  if (!lhe || event()->alphaQCD() < 0) event()->set_alphaQCD( pyint1.vint[57] );
306 
307  // get pdf info directly from Pythia6 and set it up into HepMC::GenEvent
308  // S. Mrenna: Prefer vint block
309  //
310  if (!lhe || pdf.id1() < 0) pdf.set_id1( pyint1.mint[14] == 21 ? 0 : pyint1.mint[14] );
311  if (!lhe || pdf.id2() < 0) pdf.set_id2( pyint1.mint[15] == 21 ? 0 : pyint1.mint[15] );
312  if (!lhe || pdf.x1() < 0) pdf.set_x1( pyint1.vint[40] );
313  if (!lhe || pdf.x2() < 0) pdf.set_x2( pyint1.vint[41] );
314  if (!lhe || pdf.pdf1() < 0) pdf.set_pdf1( pyint1.vint[38] / pyint1.vint[40] );
315  if (!lhe || pdf.pdf2() < 0) pdf.set_pdf2( pyint1.vint[39] / pyint1.vint[41] );
316  if (!lhe || pdf.scalePDF() < 0) pdf.set_scalePDF( pyint1.vint[50] );
317 */
318 
319  event()->set_pdf_info(pdf);
320 
321  HepMC::GenCrossSection xsec;
322  double cs = pypars.pari[0]; // cross section in mb
323  cs *= 1.0e9; // translate to pb
324  double cserr = cs / sqrt(pypars.msti[4]);
325  xsec.set_cross_section(cs, cserr);
326  event()->set_cross_section(xsec);
327 
328  // this is "standard" Py6 event weight (corresponds to PYINT1/VINT(97)
329  //
330  if (lhe && std::abs(lheRunInfo()->getHEPRUP()->IDWTUP) == 4)
331  // translate mb to pb (CMS/Gen "convention" as of May 2009)
332  event()->weights().push_back(pyint1.vint[96] * 1.0e9);
333  else
334  event()->weights().push_back(pyint1.vint[96]);
335  //
336  // this is event weight as 1./VINT(99) (PYINT1/VINT(99) is returned by the PYEVWT)
337  //
338  event()->weights().push_back(1. / (pyint1.vint[98]));
339 
340  // now create the GenEventInfo product from the GenEvent and fill
341  // the missing pieces
342 
343  eventInfo() = std::make_unique<GenEventInfoProduct>(event().get());
344 
345  // in Pythia6 pthat is used to subdivide samples into different bins
346  // in LHE mode the binning is done by the external ME generator
347  // which is likely not pthat, so only filling it for Py6 internal mode
348  if (!lhe) {
349  eventInfo()->setBinningValues(std::vector<double>(1, pypars.pari[16]));
350  }
351 
352  // here we treat long-lived particles
353  //
354  if (fImposeProperTime || pydat1.mstj[21] == 3 || pydat1.mstj[21] == 4)
356 
357  // convert particle IDs Py6->PDG, if requested
358  if (fConvertToPDG) {
359  for (HepMC::GenEvent::particle_iterator part = event()->particles_begin(); part != event()->particles_end();
360  ++part) {
361  (*part)->set_pdg_id(HepPID::translatePythiatoPDT((*part)->pdg_id()));
362  }
363  }
364 
365  // service printouts, if requested
366  //
367  if (fMaxEventsToPrint > 0) {
371  if (fHepMCVerbosity) {
372  std::cout << "Event process = " << pypars.msti[0] << std::endl << "----------------------" << std::endl;
373  event()->print();
374  }
375  }
376 
377  // dump of all settings after all initializations
378  if (fDisplayPythiaCards) {
379  fDisplayPythiaCards = false;
380  call_pylist(12);
381  call_pylist(13);
382  std::cout << "\n PYPARS \n" << std::endl;
383  std::cout << std::setw(5) << std::fixed << "I" << std::setw(10) << std::fixed << "MSTP(I)" << std::setw(16)
384  << std::fixed << "PARP(I)" << std::setw(10) << std::fixed << "MSTI(I)" << std::setw(16) << std::fixed
385  << "PARI(I)" << std::endl;
386  for (unsigned int ind = 0; ind < 200; ind++) {
387  std::cout << std::setw(5) << std::fixed << ind + 1 << std::setw(10) << std::fixed << pypars.mstp[ind]
388  << std::setw(16) << std::fixed << pypars.parp[ind] << std::setw(10) << std::fixed << pypars.msti[ind]
389  << std::setw(16) << std::fixed << pypars.pari[ind] << std::endl;
390  }
391  }
392 
393  return;
394  }
395 
397  Pythia6Service::InstanceWrapper guard(fPy6Service); // grab Py6 instance
398 
400 
401  // generate event with Pythia6
402  //
403 
405  // call_pygive("MSTJ(1)=-1");
406  call_pygive("MSTJ(14)=-1");
407  }
408 
409  call_pyevnt();
410 
412  // call_pygive("MSTJ(1)=1");
413  call_pygive("MSTJ(14)=1");
414  int ierr = 0;
415  if (fStopHadronsEnabled) {
416  pystfr_(ierr);
417  if (ierr != 0) // skip failed events
418  {
419  event().reset();
420  return false;
421  }
422  }
424  pyglfr_();
425  }
426 
427  if (pyint1.mint[50] != 0) // skip event if py6 considers it bad
428  {
429  event().reset();
430  return false;
431  }
432 
433  call_pyhepc(1);
434  event().reset(pythia6_conv.read_next_event());
435 
436  // this is to deal with post-gen tools & residualDecay() that may reuse PYJETS
437  //
438  flushTmpStorage();
439  fillTmpStorage();
440 
441  return true;
442  }
443 
445  Pythia6Service::InstanceWrapper guard(fPy6Service); // grab Py6 instance
446 
449  if (fJetMatching) {
452  }
453 
454  // generate event with Pythia6
455  //
457  call_pygive("MSTJ(1)=-1");
458  call_pygive("MSTJ(14)=-1");
459  }
460 
461  call_pyevnt();
462 
463  if (FortranCallback::getInstance()->getIterationsPerEvent() > 1 || hepeup_.nup <= 0 || pypars.msti[0] == 1) {
464  // update LHE matching statistics
466 
467  event().reset();
468  return false;
469  }
470 
471  // update LHE matching statistics
472  //
474 
476  call_pygive("MSTJ(1)=1");
477  call_pygive("MSTJ(14)=1");
478  int ierr = 0;
479  if (fStopHadronsEnabled) {
480  pystfr_(ierr);
481  if (ierr != 0) // skip failed events
482  {
483  event().reset();
484  return false;
485  }
486  }
487 
489  pyglfr_();
490  }
491 
492  if (pyint1.mint[50] != 0) // skip event if py6 considers it bad
493  {
494  event().reset();
495  return false;
496  }
497 
498  call_pyhepc(1);
499  event().reset(pythia6_conv.read_next_event());
500 
501  // this is to deal with post-gen tools and/or residualDecay(), that may reuse PYJETS
502  //
503  flushTmpStorage();
504  fillTmpStorage();
505 
506  return true;
507  }
508 
509  bool Pythia6Hadronizer::decay() { return true; }
510 
512  // event().get()->print();
513 
514  Pythia6Service::InstanceWrapper guard(fPy6Service); // grab Py6 instance
515 
516  // int nDocLines = pypars.msti[3];
517 
518  int NPartsBeforeDecays = pyjets_local.n;
519  int NPartsAfterDecays = event().get()->particles_size();
520  int barcode = NPartsAfterDecays;
521 
522  // JVY: well, in principle, it's not a 100% fair to go up to NPartsBeforeDecays,
523  // because Photos will attach gamma's to existing vertexes, i.e. in the middle
524  // of the event rather than at the end; but this will only shift poiters down,
525  // so we'll be going again over a few "original" particle...
526  // in the alternative, we may go all the way up to the beginning of the event
527  // and re-check if anything remains to decay, that's fine even if it'll take
528  // some extra CPU...
529 
530  for (int ipart = NPartsAfterDecays; ipart > NPartsBeforeDecays; ipart--) {
531  HepMC::GenParticle* part = event().get()->barcode_to_particle(ipart);
532  int status = part->status();
533  if (status != 1)
534  continue; // check only "stable" particles,
535  // as some undecayed may still be marked as such
536  int pdgid = part->pdg_id();
537  int py6ptr = pycomp_(pdgid);
538  if (pydat3.mdcy[0][py6ptr - 1] != 1)
539  continue; // particle is not expected to decay
540  int py6id = HepPID::translatePDTtoPythia(pdgid);
541  //
542  // first, will need to zero out, then fill up PYJETS
543  // I better do it directly (by hands) rather than via py1ent
544  // - to avoid (additional) mass smearing
545  //
546  if (part->momentum().t() <= part->generated_mass()) {
547  continue; // e==m --> 0-momentum, nothing to decay...
548  } else {
549  pyjets.n = 0;
550  for (int i = 0; i < 5; i++) {
551  pyjets.k[i][0] = 0;
552  pyjets.p[i][0] = 0.;
553  pyjets.v[i][0] = 0.;
554  }
555  pyjets.k[0][0] = 1;
556  pyjets.k[1][0] = py6id;
557  pyjets.p[4][0] = part->generated_mass();
558  pyjets.p[3][0] = part->momentum().t();
559  pyjets.p[0][0] = part->momentum().x();
560  pyjets.p[1][0] = part->momentum().y();
561  pyjets.p[2][0] = part->momentum().z();
562  HepMC::GenVertex* prod_vtx = part->production_vertex();
563  if (!prod_vtx)
564  continue; // in principle, should never happen but...
565  pyjets.v[0][0] = prod_vtx->position().x();
566  pyjets.v[1][0] = prod_vtx->position().y();
567  pyjets.v[2][0] = prod_vtx->position().z();
568  pyjets.v[3][0] = prod_vtx->position().t();
569  pyjets.v[4][0] = 0.;
570  pyjets.n = 1;
571  pyjets.npad = pyjets_local.npad;
572  }
573 
574  // now call Py6 decay routine
575  //
576  int parent = 1; // since we always pass to Py6 a single particle
577  pydecy_(parent);
578 
579  // now attach decay products to mother
580  //
581  for (int iprt1 = 1; iprt1 < pyjets.n; iprt1++) {
582  part->set_status(2);
583 
584  HepMC::GenVertex* DecVtx = new HepMC::GenVertex(
585  HepMC::FourVector(pyjets.v[0][iprt1], pyjets.v[1][iprt1], pyjets.v[2][iprt1], pyjets.v[3][iprt1]));
586  DecVtx->add_particle_in(part); // this will cleanup end_vertex if exists, replace with the new one
587  // I presume (vtx) barcode will be given automatically
588 
589  HepMC::FourVector pmom(pyjets.p[0][iprt1], pyjets.p[1][iprt1], pyjets.p[2][iprt1], pyjets.p[3][iprt1]);
590 
591  int dstatus = 0;
592  if (pyjets.k[0][iprt1] >= 1 && pyjets.k[0][iprt1] <= 10) {
593  dstatus = 1;
594  } else if (pyjets.k[0][iprt1] >= 11 && pyjets.k[0][iprt1] <= 20) {
595  dstatus = 2;
596  } else if (pyjets.k[0][iprt1] >= 21 && pyjets.k[0][iprt1] <= 30) {
597  dstatus = 3;
598  } else if (pyjets.k[0][iprt1] >= 31 && pyjets.k[0][iprt1] <= 100) {
599  dstatus = pyjets.k[0][iprt1];
600  }
601  HepMC::GenParticle* daughter =
602  new HepMC::GenParticle(pmom, HepPID::translatePythiatoPDT(pyjets.k[1][iprt1]), dstatus);
603  barcode++;
604  daughter->suggest_barcode(barcode);
605  DecVtx->add_particle_out(daughter);
606 
607  int iprt2;
608  for (iprt2 = iprt1 + 1; iprt2 < pyjets.n; iprt2++) // the pointer is shifted by -1, c++ style
609  {
610  if (pyjets.k[2][iprt2] != parent) {
611  parent = pyjets.k[2][iprt2];
612  break; // another parent particle; reset & break the loop
613  }
614 
615  HepMC::FourVector pmomN(pyjets.p[0][iprt2], pyjets.p[1][iprt2], pyjets.p[2][iprt2], pyjets.p[3][iprt2]);
616 
617  dstatus = 0;
618  if (pyjets.k[0][iprt2] >= 1 && pyjets.k[0][iprt2] <= 10) {
619  dstatus = 1;
620  } else if (pyjets.k[0][iprt2] >= 11 && pyjets.k[0][iprt2] <= 20) {
621  dstatus = 2;
622  } else if (pyjets.k[0][iprt2] >= 21 && pyjets.k[0][iprt2] <= 30) {
623  dstatus = 3;
624  } else if (pyjets.k[0][iprt2] >= 31 && pyjets.k[0][iprt2] <= 100) {
625  dstatus = pyjets.k[0][iprt2];
626  }
627  HepMC::GenParticle* daughterN =
628  new HepMC::GenParticle(pmomN, HepPID::translatePythiatoPDT(pyjets.k[1][iprt2]), dstatus);
629  barcode++;
630  daughterN->suggest_barcode(barcode);
631  DecVtx->add_particle_out(daughterN);
632  }
633 
634  iprt1 = iprt2 - 1; // reset counter such that it doesn't go over the same child more than once
635  // don't forget to offset back into c++ counting, as it's already +1 forward
636 
637  event().get()->add_vertex(DecVtx);
638  }
639  }
640 
641  // now restore the very original Py6 event record
642  //
643  if (pyjets_local.n != pyjets.n) {
644  // restore pyjets to its state as it was before external decays -
645  // might have been jammed by action above or by py1ent calls in EvtGen
646  pyjets.n = pyjets_local.n;
647  pyjets.npad = pyjets_local.npad;
648  for (int ip = 0; ip < pyjets_local.n; ip++) {
649  for (int i = 0; i < 5; i++) {
650  pyjets.k[i][ip] = pyjets_local.k[i][ip];
651  pyjets.p[i][ip] = pyjets_local.p[i][ip];
652  pyjets.v[i][ip] = pyjets_local.v[i][ip];
653  }
654  }
655  }
656 
657  return true;
658  }
659 
661  Pythia6Service::InstanceWrapper guard(fPy6Service); // grab Py6 instance
662 
664  if (key == 0)
667 
668  return true;
669  }
670 
672  Pythia6Service::InstanceWrapper guard(fPy6Service); // grab Py6 instance
673 
674  // note: CSA mode is NOT supposed to work with external partons !!!
675 
676  // fPy6Service->setGeneralParams();
677 
679 
681 
682  if (fStopHadronsEnabled) {
683  // overwrite mstp(111), no matter what
684  call_pygive("MSTP(111)=0");
685  pystrhad_();
686  call_pygive("MWID(302)=0"); // I don't know if this is specific to processing ME/LHE only,
687  call_pygive("MDCY(302,1)=0"); // or this should also be the case for full event...
688  // anyway, this comes from experience of processing MG events
689  }
690 
691  if (fGluinoHadronsEnabled) {
692  // overwrite mstp(111), no matter what
693  call_pygive("MSTP(111)=0");
694  pyglrhad_();
695  //call_pygive("MWID(309)=0");
696  //call_pygive("MDCY(309,1)=0");
697  }
698 
699  call_pyinit("USER", "", "", 0.0);
700 
702 
703  std::vector<std::string> slha = lheRunInfo()->findHeader("slha");
704  if (!slha.empty()) {
705  edm::LogInfo("Generator|LHEInterface") << "Pythia6 hadronisation found an SLHA header, "
706  << "will be passed on to Pythia." << std::endl;
709  }
710 
711  if (fJetMatching) {
713  // FIXME: the jet matching routine might not be interested in PS callback
714  call_pygive("MSTP(143)=1");
715  }
716 
717  return true;
718  }
719 
721  Pythia6Service::InstanceWrapper guard(fPy6Service); // grab Py6 instance
722 
724 
725  if (fStopHadronsEnabled) {
726  // overwrite mstp(111), no matter what
727  call_pygive("MSTP(111)=0");
728  pystrhad_();
729  }
730 
731  if (fGluinoHadronsEnabled) {
732  // overwrite mstp(111), no matter what
733  call_pygive("MSTP(111)=0");
734  pyglrhad_();
735  }
736 
737  if (fInitialState == PP) // default
738  {
739  call_pyinit("CMS", "p", "p", fCOMEnergy);
740  } else if (fInitialState == PPbar) {
741  call_pyinit("CMS", "p", "pbar", fCOMEnergy);
742  } else if (fInitialState == ElectronPositron) {
743  call_pyinit("CMS", "e+", "e-", fCOMEnergy);
744  } else if (fInitialState == ElectronProton) {
745  // set p(1,i) & p(2,i) for the beams in pyjets !
746  pyjets.p[0][0] = 0.;
747  pyjets.p[1][0] = 0.;
748  pyjets.p[2][0] = fBeam1PZ;
749  pyjets.p[0][1] = 0.;
750  pyjets.p[1][1] = 0.;
751  pyjets.p[2][1] = fBeam2PZ;
752  // call "3mon" frame & 0.0 win
753  call_pyinit("3mom", "e-", "p", 0.0);
754  } else if (fInitialState == PositronProton) {
755  // set p(1,i) & p(2,i) for the beams in pyjets !
756  pyjets.p[0][0] = 0.;
757  pyjets.p[1][0] = 0.;
758  pyjets.p[2][0] = fBeam1PZ;
759  pyjets.p[0][1] = 0.;
760  pyjets.p[1][1] = 0.;
761  pyjets.p[2][1] = fBeam2PZ;
762  // call "3mon" frame & 0.0 win
763  call_pyinit("3mom", "e+", "p", 0.0);
764  } else {
765  // throw on unknown initial state !
766  throw edm::Exception(edm::errors::Configuration, "Pythia6Interface")
767  << " UNKNOWN INITIAL STATE. \n The allowed initial states are: PP, PPbar, ElectronPositron, ElectronProton, "
768  "and PositronProton \n";
769  }
770 
772 
774 
775  return true;
776  }
777 
778  bool Pythia6Hadronizer::declareStableParticles(const std::vector<int>& pdg) {
779  for (unsigned int i = 0; i < pdg.size(); i++) {
780  int PyID = HepPID::translatePDTtoPythia(pdg[i]);
781  // int PyID = pdg[i];
782  int pyCode = pycomp_(PyID);
783  if (pyCode > 0) {
784  std::ostringstream pyCard;
785  pyCard << "MDCY(" << pyCode << ",1)=0";
786  /* this is a test printout...
787  std::cout << "pdg= " << pdg[i] << " " << pyCard.str() << std::endl;
788 */
789  call_pygive(pyCard.str());
790  }
791  }
792 
793  return true;
794  }
795 
796  bool Pythia6Hadronizer::declareSpecialSettings(const std::vector<std::string>& settings) {
797  for (unsigned int iss = 0; iss < settings.size(); iss++) {
798  if (settings[iss].find("QED-brem-off") == std::string::npos)
799  continue;
800  size_t fnd1 = settings[iss].find(':');
801  if (fnd1 == std::string::npos)
802  continue;
803 
804  std::string value = settings[iss].substr(fnd1 + 1);
805 
806  if (value == "all") {
807  call_pygive("MSTJ(41)=3");
808  } else {
809  int number = atoi(value.c_str());
810  int PyID = HepPID::translatePDTtoPythia(number);
811  int pyCode = pycomp_(PyID);
812  if (pyCode > 0) {
813  // first of all, check if mstj(39) is 0 or if we're trying to override user's setting
814  // if so, throw an exception and stop, because otherwise the user will get behaviour
815  // that's different from what she/he expects !
816  if (pydat1_.mstj[38] > 0 && pydat1_.mstj[38] != pyCode) {
817  throw edm::Exception(edm::errors::Configuration, "Pythia6Interface")
818  << " Fatal conflict: \n mandatory internal directive to set MSTJ(39)=" << pyCode
819  << " overrides user setting MSTJ(39)=" << pydat1_.mstj[38]
820  << " - user will not get expected behaviour \n";
821  }
822  std::ostringstream pyCard;
823  pyCard << "MSTJ(39)=" << pyCode;
824  call_pygive(pyCard.str());
825  }
826  }
827  }
828 
829  return true;
830  }
831 
833  // this is practically a copy/paste of the original code by J.Alcaraz,
834  // taken directly from PythiaSource
835 
836  int dumm = 0;
837  HepMC::GenEvent::vertex_const_iterator vbegin = event()->vertices_begin();
838  HepMC::GenEvent::vertex_const_iterator vend = event()->vertices_end();
839  HepMC::GenEvent::vertex_const_iterator vitr = vbegin;
840  for (; vitr != vend; ++vitr) {
841  HepMC::GenVertex::particle_iterator pbegin = (*vitr)->particles_begin(HepMC::children);
842  HepMC::GenVertex::particle_iterator pend = (*vitr)->particles_end(HepMC::children);
843  HepMC::GenVertex::particle_iterator pitr = pbegin;
844  for (; pitr != pend; ++pitr) {
845  if ((*pitr)->end_vertex())
846  continue;
847  if ((*pitr)->status() != 1)
848  continue;
849 
850  int pdgcode = abs((*pitr)->pdg_id());
851  // Do nothing if the particle is not expected to decay
852  if (pydat3.mdcy[0][pycomp_(pdgcode) - 1] != 1)
853  continue;
854 
855  double ctau = pydat2.pmas[3][pycomp_(pdgcode) - 1];
856  HepMC::FourVector mom = (*pitr)->momentum();
857  HepMC::FourVector vin = (*vitr)->position();
858  double x = 0.;
859  double y = 0.;
860  double z = 0.;
861  double t = 0.;
862  bool decayInRange = false;
863  while (!decayInRange) {
864  double unif_rand = fPy6Service->call(pyr_, &dumm);
865  // Value of 0 is excluded, so following line is OK
866  double proper_length = -ctau * log(unif_rand);
867  double factor = proper_length / mom.m();
868  x = vin.x() + factor * mom.px();
869  y = vin.y() + factor * mom.py();
870  z = vin.z() + factor * mom.pz();
871  t = vin.t() + factor * mom.e();
872  // Decay must be happen outside a cylindrical region
873  if (pydat1.mstj[21] == 4) {
874  if (std::sqrt(x * x + y * y) > pydat1.parj[72] || fabs(z) > pydat1.parj[73])
875  decayInRange = true;
876  // Decay must be happen outside a given sphere
877  } else if (pydat1.mstj[21] == 3) {
878  if (std::sqrt(x * x + y * y + z * z) > pydat1.parj[71])
879  decayInRange = true;
880  }
881  // Decay is always OK otherwise
882  else {
883  decayInRange = true;
884  }
885  }
886 
887  HepMC::GenVertex* vdec = new HepMC::GenVertex(HepMC::FourVector(x, y, z, t));
888  event()->add_vertex(vdec);
889  vdec->add_particle_in((*pitr));
890  }
891  }
892 
893  return;
894  }
895 
897  if (!runInfo().internalXSec()) {
898  // set xsec if not already done (e.g. from LHE cross section collector)
899  double cs = pypars.pari[0]; // cross section in mb
900  cs *= 1.0e9; // translate to pb (CMS/Gen "convention" as of May 2009)
902  // FIXME: can we get the xsec statistical error somewhere?
903  }
904 
905  call_pystat(1);
906 
907  return;
908  }
909 
910  const char* Pythia6Hadronizer::classname() const { return "gen::Pythia6Hadronizer"; }
911 
912 } // namespace gen
#define pydat1
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
void call(void(&fn)())
unsigned int fPythiaListVerbosity
Pythia6ServiceWithCallback(const edm::ParameterSet &ps)
unsigned int fMaxEventsToPrint
double pyr_(int *idummy)
static JetMatching * getJetMatching()
struct HEPEUP_ hepeup_
bool exists(std::string const &parameterName) const
checks if a parameter exists
HepMC::IO_HEPEVT pythia6_conv
bool call_pygive(const std::string &line)
void setLHERunInfo(lhef::LHERunInfo *lheri)
void count(LHERunInfo::CountMode count, double weight=1.0, double matchWeight=1.0)
Definition: LHEEvent.cc:187
virtual void beforeHadronisation(const lhef::LHEEvent *event)
Definition: JetMatching.cc:23
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
void setInternalXSec(const XSec &xsec)
void pyglrhad_()
void doSetRandomEngine(CLHEP::HepRandomEngine *v) override
double v[5][pyjets_maxn]
virtual int match(const lhef::LHEEvent *partonLevel, const std::vector< fastjet::PseudoJet > *jetInput)=0
T getUntrackedParameter(std::string const &, T const &) const
static const std::string kPythia6
GenRunInfoProduct & runInfo()
double p[5][pyjets_maxn]
bool declareStableParticles(const std::vector< int > &)
void call_pylist(int mode)
void fillEventInfo(HepMC::GenEvent *hepmc) const
Definition: LHEEvent.cc:223
void resetMatchingStatus()
Definition: JetMatching.h:73
lhef::LHEEvent * lheEvent()
static const std::vector< std::string > theSharedResources
T sqrt(T t)
Definition: SSEVec.h:19
void setSLHAFromHeader(const std::vector< std::string > &lines)
std::vector< std::string > findHeader(const std::string &tag) const
Definition: LHERunInfo.cc:434
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
#define pyint1
void pydecy_(int &ip)
void setPYUPDAParams(bool afterPyinit)
void pystfr_(int &)
Definition: value.py:1
Pythia6Hadronizer(edm::ParameterSet const &ps)
std::unique_ptr< HepMC::GenEvent > & event()
static struct gen::@739 pyjets_local
lhef::LHERunInfo * lheRunInfo()
int k[5][pyjets_maxn]
Log< level::Info, false > LogInfo
static const std::string kFortranInstance
static FortranCallback * getInstance()
int pycomp_(int &)
Pythia6Service * fPy6Service
#define pypars
void fillPdfInfo(HepMC::PdfInfo *info) const
Definition: LHEEvent.cc:196
void setLHEEvent(lhef::LHEEvent *lhee)
const char * classname() const
part
Definition: HCALResponse.h:20
std::unique_ptr< GenEventInfoProduct > & eventInfo()
struct gen::@722 pydat1_
virtual void beforeHadronisationExec()
Definition: JetMatching.cc:25
void setRandomEngine(CLHEP::HepRandomEngine *v)
bool isMatchingDone()
Definition: JetMatching.h:74
void pyglfr_()
float x
bool declareSpecialSettings(const std::vector< std::string > &)
virtual void init(const lhef::LHERunInfo *runInfo)
Definition: JetMatching.cc:21
static std::unique_ptr< JetMatching > create(const edm::ParameterSet &params)
Definition: JetMatching.cc:34
void pystrhad_()
static JetMatching * fJetMatching