ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHSartre.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHSartre.cc
1 #include "PHSartre.h"
2 #include "PHSartreGenTrigger.h"
3 
4 #include <sartre/Enumerations.h> // for incoherent
5 #include <sartre/Event.h> // for Particle, Event
6 #include <sartre/EventGeneratorSettings.h> // for EventGeneratorSettings
7 
8 
9 #include <phhepmc/PHHepMCGenHelper.h> // for PHHepMCGenHelper
10 
12 #include <fun4all/SubsysReco.h> // for SubsysReco
13 
14 #include <sartre/Sartre.h>
15 
16 #include <TGenPhaseSpace.h>
17 #include <TLorentzVector.h> // for TLorentzVector
18 #include <TParticlePDG.h> // for TParticlePDG
19 
21 
22 #include <HepMC/GenEvent.h>
23 #include <HepMC/GenParticle.h> // for GenParticle
24 #include <HepMC/GenVertex.h> // for GenVertex
25 #include <HepMC/PdfInfo.h> // for PdfInfo
26 #include <HepMC/SimpleVector.h> // for FourVector
27 #include <HepMC/Units.h> // for GEV, MM
28 
29 #include <gsl/gsl_rng.h> // for gsl_rng_uniform
30 
31 #include <cfloat> // for FLT_EPSILON
32 #include <cmath> // for M_PI
33 #include <cstdlib> // for getenv
34 #include <iostream> // for operator<<, endl, basic_o...
35 #include <memory> // for allocator_traits<>::value...
36 
37 class PHHepMCGenEvent;
38 
39 using namespace std;
40 
41 PHSartre::PHSartre(const std::string &name)
42  : SubsysReco(name)
43  , _eventcount(0)
44  , _gencount(0)
45  , _registeredTriggers()
46  , _triggersOR(true)
47  , _triggersAND(false)
48  , _configFile("")
49  , _commands()
50  , _sartre(nullptr)
51  , settings(nullptr)
52  , decay(nullptr)
53  , daughterID(-1)
54  , daughterMasses{0., 0.}
55  , doPerformDecay(false)
56 {
57  char *charPath = getenv("SARTRE_DIR");
58  if (!charPath)
59  {
60  cout << "PHSartre::Could not find $SARTRE_DIR path!" << endl;
61  return;
62  }
63 
64  //
65  // Create the generator and initialize it.
66  // Once initialized you cannot (should not) change
67  // the settings w/o re-initialing sartre.
68  //
69  _sartre = new Sartre();
70 
71  PHHepMCGenHelper::set_embedding_id(1); // default embedding ID to 1
72 }
73 
75 {
76  delete _sartre;
77 }
78 
80 {
81  if (!_configFile.empty())
82  {
83  bool ok = _sartre->init(_configFile);
84  if (!ok)
85  {
86  cerr << "Initialization of sartre failed." << endl;
88  }
89  }
90  else
91  {
92  cerr << "Sartre configuration file must be specified" << endl;
94  }
95 
96  settings = _sartre->runSettings();
97  settings->list();
98 
99  create_node_tree(topNode);
100 
101  // event numbering will start from 1
102  _eventcount = 0;
103 
104  decay = new TGenPhaseSpace(); // for VM decays
105  daughterID = settings->userInt();
106  if (daughterID && (settings->vectorMesonId() != 22))
107  {
108  doPerformDecay = true;
109  daughterMasses[0] = settings->lookupPDG(daughterID)->Mass();
110  daughterMasses[1] = settings->lookupPDG(-daughterID)->Mass();
111  cout << "PHSartre: "
112  << "Will decay vector meson: ";
113  cout << "PHSartre: " << settings->lookupPDG(settings->vectorMesonId())->GetName();
114  cout << "PHSartre: "
115  << " -> ";
116  cout << "PHSartre: " << settings->lookupPDG(daughterID)->GetName();
117  cout << " ";
118  cout << "PHSartre: " << settings->lookupPDG(-daughterID)->GetName();
119  cout << endl;
120  }
121 
123 }
124 
126 {
127  if (Verbosity() > 1) cout << "PHSartre::End - I'm here!" << endl;
128 
129  cout << "PHSartre: "
130  << " Total cross-section: " << _sartre->totalCrossSection() << " nb" << endl;
131  _sartre->listStatus();
132 
133  cout << " *------- Begin PHSARTRE Trigger Statistics ----------------------"
134  << "-------------------------------------------------* " << endl;
135  cout << " | "
136  << " | " << endl;
137  cout << " PHSartre::End - " << _eventcount
138  << " events passed trigger" << endl;
139  cout << " Fraction passed: " << _eventcount
140  << "/" << _gencount
141  << " = " << _eventcount / float(_gencount) << endl;
142  cout << " *------- End PHSARTRE Trigger Statistics ------------------------"
143  << "-------------------------------------------------* " << endl;
144 
146 }
147 
148 //-* print pythia config info
150 {
151  settings->list();
152 }
153 
155 {
156  if (Verbosity() > 1) cout << "PHSartre::process_event - event: " << _eventcount << endl;
157 
158  bool passedTrigger = false;
159  Event *event = nullptr;
160 
161  TLorentzVector *eIn = nullptr;
162  TLorentzVector *pIn = nullptr;
163  TLorentzVector *eOut = nullptr;
164  TLorentzVector *gamma = nullptr;
165  TLorentzVector *vm = nullptr;
166  TLorentzVector *PomOut = nullptr;
167  TLorentzVector *pOut = nullptr;
168  TLorentzVector *vmDecay1 = nullptr;
169  TLorentzVector *vmDecay2 = nullptr;
170  unsigned int preVMDecaySize = 0;
171 
172  while (!passedTrigger)
173  {
174  ++_gencount;
175 
176  // Generate a Sartre event
177  event = _sartre->generateEvent();
178 
179  //
180  // If Sartre is run in UPC mode, half of the events needs to be
181  // rotated around and axis perpendicular to z:
182  // (only for symmetric events)
183  //
184  if (settings->UPC() and settings->A() == settings->UPCA())
185  {
186  randomlyReverseBeams(event);
187  }
188 
189  // for sPHENIX/RHIC p+Au
190  // (see comments in ReverseBeams)
191  // reverse when the proton emits the virtual photon
192 
193  if (settings->UPC() and settings->A() == 197)
194  {
195  ReverseBeams(event);
196  }
197 
198  // Set pointers to the parts of the event we will need:
199 
200  eIn = &event->particles[0].p;
201  pIn = &event->particles[1].p;
202  eOut = &event->particles[2].p;
203  gamma = &event->particles[3].p;
204  vm = &event->particles[4].p;
205  PomOut = &event->particles[5].p;
206  pOut = &event->particles[6].p;
207 
208  // To allow the triggering to work properly, we need to decay the vector meson here
209 
210  preVMDecaySize = event->particles.size();
211 
212  if (doPerformDecay)
213  {
214  if (decay->SetDecay(*vm, 2, daughterMasses))
215  {
216  double weight = decay->Generate(); // weight is always 1 here
217  if ((weight - 1) > FLT_EPSILON)
218  {
219  cout << "PHSartre: Warning decay weight != 1, weight = " << weight << endl;
220  }
221  TLorentzVector *vmDaughter1 = decay->GetDecay(0);
222  TLorentzVector *vmDaughter2 = decay->GetDecay(1);
223 
224  event->particles[4].status = 2; // set VM status
225 
226  Particle vmDC1;
227  vmDC1.index = event->particles.size();
228  vmDC1.pdgId = daughterID;
229  vmDC1.status = 1; // final state
230  vmDC1.p = *vmDaughter1;
231  vmDC1.parents.push_back(4);
232  event->particles.push_back(vmDC1);
233  vmDecay1 = &event->particles[event->particles.size() - 1].p;
234 
235  Particle vmDC2;
236  vmDC2.index = event->particles.size();
237  vmDC2.pdgId = -daughterID;
238  vmDC2.status = 1; // final state
239  vmDC2.p = *vmDaughter2;
240  vmDC2.parents.push_back(4);
241  event->particles.push_back(vmDC2);
242  vmDecay2 = &event->particles[event->particles.size() - 1].p;
243  }
244  else
245  {
246  cout << "PHSartre: WARNING: Kinematics of Vector Meson does not allow decay!" << endl;
247  }
248  }
249 
250  // test trigger logic
251 
252  bool andScoreKeeper = true;
253  if (Verbosity() > 2)
254  {
255  cout << "PHSartre::process_event - triggersize: " << _registeredTriggers.size() << endl;
256  }
257 
258  for (unsigned int tr = 0; tr < _registeredTriggers.size(); tr++)
259  {
260  bool trigResult = _registeredTriggers[tr]->Apply(event);
261 
262  if (Verbosity() > 2)
263  {
264  cout << "PHSartre::process_event trigger: "
265  << _registeredTriggers[tr]->GetName() << " " << trigResult << endl;
266  }
267 
268  if (_triggersOR && trigResult)
269  {
270  passedTrigger = true;
271  break;
272  }
273  else if (_triggersAND)
274  {
275  andScoreKeeper &= trigResult;
276  }
277 
278  if (Verbosity() > 2 && !passedTrigger)
279  {
280  cout << "PHSartre::process_event - failed trigger: "
281  << _registeredTriggers[tr]->GetName() << endl;
282  }
283  }
284 
285  if ((andScoreKeeper && _triggersAND) || (_registeredTriggers.size() == 0))
286  {
287  passedTrigger = true;
288  }
289  }
290 
291  // fill HepMC object with event
292 
293  HepMC::GenEvent *genevent = new HepMC::GenEvent(HepMC::Units::GEV, HepMC::Units::MM);
294 
295  // add some information to the event
296  genevent->set_event_number(_eventcount);
297 
298  // Set the PDF information
299  HepMC::PdfInfo pdfinfo;
300  pdfinfo.set_scalePDF(event->Q2);
301  genevent->set_pdf_info(pdfinfo);
302 
303  // We would also like to save:
304  //
305  // event->t;
306  // event->x;
307  // event->y;
308  // event->s;
309  // event->W;
310  // event->xpom;
311  // (event->polarization == transverse ? 0 : 1);
312  // (event->diffractiveMode == coherent ? 0 : 1);
313  //
314  // but there doesn't seem to be a good place to do so
315  // within the HepMC event information?
316  //
317  // t, W and Q^2 form a minial set of good variables for diffractive events
318  // Maybe what I do is record the input particles to the event at the HepMC
319  // vertices and reconstruct the kinematics from there?
320 
321  // Create HepMC vertices and add final state particles to them
322 
323  // First, the emitter(electron)-virtual photon vertex:
324 
325  HepMC::GenVertex *egammavtx = new HepMC::GenVertex(CLHEP::HepLorentzVector(0.0, 0.0, 0.0, 0.0));
326  genevent->add_vertex(egammavtx);
327 
328  egammavtx->add_particle_in(
329  new HepMC::GenParticle(CLHEP::HepLorentzVector(eIn->Px(),
330  eIn->Py(),
331  eIn->Pz(),
332  eIn->E()),
333  event->particles[0].pdgId,
334  3));
335 
336  HepMC::GenParticle *hgamma = new HepMC::GenParticle(CLHEP::HepLorentzVector(gamma->Px(),
337  gamma->Py(),
338  gamma->Pz(),
339  gamma->E()),
340  event->particles[3].pdgId,
341  3);
342 
343  egammavtx->add_particle_out(hgamma);
344 
345  egammavtx->add_particle_out(
346  new HepMC::GenParticle(CLHEP::HepLorentzVector(eOut->Px(),
347  eOut->Py(),
348  eOut->Pz(),
349  eOut->E()),
350  event->particles[2].pdgId,
351  1));
352 
353  // Next, the hadron-pomeron vertex:
354 
355  HepMC::GenVertex *ppomvtx = new HepMC::GenVertex(CLHEP::HepLorentzVector(0.0, 0.0, 0.0, 0.0));
356  genevent->add_vertex(ppomvtx);
357 
358  ppomvtx->add_particle_in(
359  new HepMC::GenParticle(CLHEP::HepLorentzVector(pIn->Px(),
360  pIn->Py(),
361  pIn->Pz(),
362  pIn->E()),
363  event->particles[1].pdgId,
364  3));
365 
366  HepMC::GenParticle *hPomOut = new HepMC::GenParticle(CLHEP::HepLorentzVector(PomOut->Px(),
367  PomOut->Py(),
368  PomOut->Pz(),
369  PomOut->E()),
370  event->particles[5].pdgId,
371  3);
372 
373  ppomvtx->add_particle_out(hPomOut);
374 
375  // If this is a nuclear breakup, add in the nuclear fragments
376  // Otherwise, add in the outgoing hadron
377 
378  //If the event is incoherent, and nuclear breakup is enabled, fill the remnants to the tree
379  if (settings->enableNuclearBreakup() and event->diffractiveMode == incoherent)
380  {
381  for (unsigned int iParticle = 7; iParticle < preVMDecaySize; iParticle++)
382  {
383  if (event->particles[iParticle].status == 1)
384  { // Final-state particle
385  const Particle &particle = event->particles[iParticle];
386  ppomvtx->add_particle_out(
387  new HepMC::GenParticle(CLHEP::HepLorentzVector(particle.p.Px(),
388  particle.p.Py(),
389  particle.p.Pz(),
390  particle.p.E()),
391  particle.pdgId,
392  1));
393  }
394  }
395  }
396  else
397  {
398  ppomvtx->add_particle_out(
399  new HepMC::GenParticle(CLHEP::HepLorentzVector(pOut->Px(),
400  pOut->Py(),
401  pOut->Pz(),
402  pOut->E()),
403  event->particles[6].pdgId,
404  1));
405  }
406 
407  // The Pomeron-Photon vertex
408 
409  HepMC::GenVertex *gammapomvtx = new HepMC::GenVertex(CLHEP::HepLorentzVector(0.0, 0.0, 0.0, 0.0));
410  genevent->add_vertex(gammapomvtx);
411 
412  gammapomvtx->add_particle_in(hgamma);
413  gammapomvtx->add_particle_in(hPomOut);
414 
415  int isVMFinal = 1;
416  if (doPerformDecay) isVMFinal = 2;
417 
418  HepMC::GenParticle *hvm = new HepMC::GenParticle(CLHEP::HepLorentzVector(vm->Px(),
419  vm->Py(),
420  vm->Pz(),
421  vm->E()),
422  event->particles[4].pdgId,
423  isVMFinal);
424 
425  gammapomvtx->add_particle_out(hvm);
426 
427  // Add the VM decay to the event
428 
429  if (doPerformDecay)
430  {
431  if (vmDecay1 && vmDecay2)
432  {
433  HepMC::GenVertex *fvtx = new HepMC::GenVertex(CLHEP::HepLorentzVector(0.0, 0.0, 0.0, 0.0));
434  genevent->add_vertex(fvtx);
435 
436  fvtx->add_particle_in(hvm);
437 
438  fvtx->add_particle_out(
439  new HepMC::GenParticle(CLHEP::HepLorentzVector(vmDecay1->Px(),
440  vmDecay1->Py(),
441  vmDecay1->Pz(),
442  vmDecay1->E()),
443  daughterID,
444  1));
445  fvtx->add_particle_out(
446  new HepMC::GenParticle(CLHEP::HepLorentzVector(vmDecay2->Px(),
447  vmDecay2->Py(),
448  vmDecay2->Pz(),
449  vmDecay2->E()),
450  -daughterID,
451  1));
452  }
453  else
454  {
455  cout << "PHSartre: WARNING: Kinematics of Vector Meson does not allow decay!" << endl;
456  }
457  }
458 
459  // pass HepMC to PHNode
460 
461  PHHepMCGenEvent *success = PHHepMCGenHelper::insert_event(genevent);
462  if (!success)
463  {
464  cout << "PHSartre::process_event - Failed to add event to HepMC record!" << endl;
466  }
467 
468  // print outs
469 
470  if (Verbosity() > 2) cout << "PHSartre::process_event - FINISHED WHOLE EVENT" << endl;
471 
472  ++_eventcount;
474 }
475 
476 
477 
479 {
481 }
482 
484 {
485  if (Verbosity() > 1) cout << "PHSartre::registerTrigger - trigger " << theTrigger->GetName() << " registered" << endl;
486  _registeredTriggers.push_back(theTrigger);
487 }
488 
489 // UPC only
491 {
492  if (gsl_rng_uniform(PHHepMCGenHelper::get_random_generator()) > 0.5)
493  {
494  for (unsigned int i = 0; i < myEvent->particles.size(); i++)
495  myEvent->particles.at(i).p.RotateX(M_PI);
496  }
497 }
498 
499 // Used to rotate into the sPHENIX/RHIC frame
500 // The photon emitting beam is always pz<0, and in sPHENIX this will be
501 // the ion direction. So what you want to run are two files with:
502 // A=1 UPCA=197 (no reversal, Au ion emits photon)
503 // A=197 UPCA=1 (reversal required, proton emits photon)
505 {
506  for (unsigned int i = 0; i < myEvent->particles.size(); i++)
507  myEvent->particles.at(i).p.RotateX(M_PI);
508 }