INukeUtils2015.cxx
Go to the documentation of this file.
1 //____________________________________________________________________________
2 /*
3  Copyright (c) 2003-2017, GENIE Neutrino MC Generator Collaboration
4  For the full text of the license visit http://copyright.genie-mc.org
5  or see $GENIE/LICENSE
6 
7  Author: Jim Dobson <j.dobson07 \at imperial.ac.uk>
8  Imperial College London
9 
10  Costas Andreopoulos <costas.andreopoulos \at stfc.ac.uk>
11  University of Liverpool & STFC Rutherford Appleton Lab
12 
13  Aaron Meyer <asm58 \at pitt.edu>
14  Pittsburgh University
15 
16  For documentation see the corresponding header file.
17 
18  Important revisions after version 2.0.0 :
19  @ Mar 04, 2009 - JD
20  Was first added in v2.5.1. Adapted from the T2K GENIE reweighting tool.
21  @ Mar 05, 2009 - CA
22  Modified ReconstructHadronFateHA() to work with hadron+A event files in
23  addition to neutrino event files.
24  @ Sep 10, 2009 - CA
25  Added MeanFreePath(), Dist2Exit(), Dist2ExitMFP()
26  @ Sep 30, 2009 - CA
27  Added StepParticle() from Intranuke.cxx
28  @ Oct 02, 2009 - CA
29  Added test MeanFreePath_Delta().
30  @ Jul 15, 2010 - AM
31  Added common utility functions used by both hA and hN mode. Updated
32  MeanFreePath to separate proton and neutron cross sections. Added general
33  utility functions.
34  @ Jan 9, 2015 - SD, NG, TG
35  Added 2014 version of INTRANUKE codes for v2.9.0. Uses INukeHadroData2014,
36  but no changes to mean free path.
37 */
38 //____________________________________________________________________________
39 
40 #include <TLorentzVector.h>
41 #include <TMath.h>
42 #include <TSystem.h>
43 
45 #include "Conventions/Constants.h"
46 #include "Conventions/Controls.h"
47 #include "Conventions/Units.h"
48 #include "Conventions/GBuild.h"
50 #include "GHEP/GHepRecord.h"
51 #include "GHEP/GHepParticle.h"
55 #include "Messenger/Messenger.h"
56 #include "Numerical/RandomGen.h"
57 #include "Numerical/Spline.h"
58 #include "PDG/PDGLibrary.h"
59 #include "PDG/PDGUtils.h"
60 #include "PDG/PDGCodes.h"
61 #include "PDG/PDGCodeList.h"
62 #include "PDG/PDGUtils.h"
63 #include "Registry/Registry.h"
64 #include "Utils/NuclearUtils.h"
65 #include "Utils/PrintUtils.h"
69 #include "TComplex.h"
70 
71 using std::ostringstream;
72 using namespace genie;
73 using namespace genie::utils;
74 using namespace genie::constants;
75 using namespace genie::controls;
76 
77 //____________________________________________________________________________
79  int pdgc, const TLorentzVector & x4, const TLorentzVector & p4,
80  double A, double Z, double nRpi, double nRnuc, const bool useOset, const bool altOset, const bool xsecNNCorr, string INukeMode)
81 {
82 // Calculate the mean free path (in fm) for a pions and nucleons in a nucleus
83 //
84 // Inputs
85 // pdgc : Hadron PDG code
86 // x4 : Hadron 4-position in the nucleus coordinate system (units: fm)
87 // p4 : Hadron 4-momentum (units: GeV)
88 // A : Nucleus atomic mass number
89 // nRpi : Controls the pion ring size in terms of de-Broglie wavelengths
90 // nRnuc: Controls the nuclepn ring size in terms of de-Broglie wavelengths
91 //
92  bool is_pion = pdgc == kPdgPiP || pdgc == kPdgPi0 || pdgc == kPdgPiM;
93  bool is_nucleon = pdgc == kPdgProton || pdgc == kPdgNeutron;
94  bool is_kaon = pdgc == kPdgKP;
95  bool is_gamma = pdgc == kPdgGamma;
96 
97  if(!is_pion && !is_nucleon && !is_kaon && !is_gamma) return 0.;
98 
99  // before getting the nuclear density at the current position
100  // check whether the nucleus has to become larger by const times the
101  // de Broglie wavelength -- that is somewhat empirical, but this
102  // is what is needed to get piA total cross sections right.
103  // The ring size is different for light nuclei (using gaus density) /
104  // heavy nuclei (using woods-saxon density).
105  // The ring size is different for pions / nucleons.
106  //
107  double momentum = p4.Vect().Mag(); // hadron momentum in GeV
108  double ring = (momentum>0) ? 1.240/momentum : 0; // de-Broglie wavelength
109 
110  if(A<=20) { ring /= 2.; }
111 
112  /*
113  if (is_pion ) { ring *= nRpi; }
114  else if (is_nucleon ) { ring *= nRnuc; }
115  else if (is_gamma || is_kaon || useOset) { ring = 0.; }
116  */
117  if(INukeMode=="hN2015")
118  {
119  if (is_pion ) { ring *= nRpi; }
120  else if (is_nucleon ) { ring *= nRnuc; }
121  else if (is_gamma || is_kaon || useOset) { ring = 0.;}
122  }
123  else
124  {
125  if (is_pion || is_kaon ) { ring *= nRpi; }
126  else if (is_nucleon ) { ring *= nRnuc; }
127  else if (is_gamma ) { ring = 0.; }
128  }
129 
130  // get the nuclear density at the current position
131  double rnow = x4.Vect().Mag();
132  double rho = A * utils::nuclear::Density(rnow,(int) A,ring);
133 
134  // the hadron+nucleon cross section will be evaluated within the range
135  // of the input spline and assumed to be const outside that range
136  //
137  double ke = (p4.Energy() - p4.M()) / units::MeV; // kinetic energy in MeV
138  ke = TMath::Max(INukeHadroData2015::fMinKinEnergy, ke);
139  ke = TMath::Min(INukeHadroData2015::fMaxKinEnergyHN, ke);
140 
141  // get total xsection for the incident hadron at its current
142  // kinetic energy
143  double sigtot = 0;
144  double ppcnt = (double) Z/ (double) A; // % of protons remaining
146 
147  if (is_pion and (INukeMode == "hN2015") and useOset and ke < 350.0)
148  sigtot = sigmaTotalOset (ke, rho, pdgc, ppcnt, altOset);
149  else if (pdgc == kPdgPiP)
150  { sigtot = fHadroData2015 -> XSecPipp_Tot() -> Evaluate(ke)*ppcnt;
151  sigtot+= fHadroData2015 -> XSecPipn_Tot() -> Evaluate(ke)*(1-ppcnt);}
152  else if (pdgc == kPdgPi0)
153  { sigtot = fHadroData2015 -> XSecPi0p_Tot() -> Evaluate(ke)*ppcnt;
154  sigtot+= fHadroData2015 -> XSecPi0n_Tot() -> Evaluate(ke)*(1-ppcnt);}
155  else if (pdgc == kPdgPiM)
156  { sigtot = fHadroData2015 -> XSecPipn_Tot() -> Evaluate(ke)*ppcnt;
157  sigtot+= fHadroData2015 -> XSecPipp_Tot() -> Evaluate(ke)*(1-ppcnt);}
158  else if (pdgc == kPdgProton)
159  {
160  sigtot = fHadroData2015 -> XSecPp_Tot() -> Evaluate(ke)*ppcnt;
161  //sigtot+= fHadroData2015 -> XSecPn_Tot() -> Evaluate(ke)*(1-ppcnt);
162 
163  PDGLibrary * pLib = PDGLibrary::Instance();
164  double hc = 197.327;
165  double R0 = 1.25 * TMath::Power(A,1./3.) + 2.0 * 0.65; // should all be in units of fm
166  double Mp = pLib->Find(2212)->Mass();
167  double M = pLib->Find(pdgc)->Mass();
168  //double E = (p4.Energy() - Mp) * 1000.; // Convert GeV to MeV.
169  double E = ke;
170  if (Z*hc/137./x4.Vect().Mag() > E) // Coulomb correction (Cohen, Concepts of Nuclear Physics, pg. 259-260)
171  {
172  double z = 1.0; // charge for single proton
173  double Bc = z*Z*hc/137./R0;
174  double x = E/Bc;
175  double f = TMath::ACos(TMath::Power(x,0.5)) - TMath::Power(x*(1-x),0.5);
176  double B = 0.63*z*Z*TMath::Power((M/Mp)/E,0.5);
177  double Pc = TMath::Exp(-B*f);
178  sigtot *= Pc;
179  }
180  sigtot+= fHadroData2015 -> XSecPn_Tot() -> Evaluate(ke)*(1-ppcnt);
181 
182  double E0 = TMath::Power(A,0.2)*12.;
183  if (INukeMode=="hN2015"){if(ke<E0){sigtot=0.0;}} //empirical - needed to cut off large number of low energy nucleons
184  }
185  else if (pdgc == kPdgNeutron)
186  {
187  sigtot = fHadroData2015 -> XSecPn_Tot() -> Evaluate(ke)*ppcnt;
188  sigtot+= fHadroData2015 -> XSecNn_Tot() -> Evaluate(ke)*(1-ppcnt);
189  double E0 = TMath::Power(A,0.2)*12.;
190  if (INukeMode=="hN2015"){if(ke<E0){sigtot=0.0;}} //empirical - needed to cut off large number of low energy nucleons
191  }
192  else if (pdgc == kPdgKP)
193  { sigtot = fHadroData2015 -> XSecKpN_Tot() -> Evaluate(ke);
194  sigtot*=1.1;}
195  else if (pdgc == kPdgGamma)
196  { sigtot = fHadroData2015 -> XSecGamp_fs() -> Evaluate(ke)*ppcnt;
197  sigtot+= fHadroData2015 -> XSecGamn_fs() -> Evaluate(ke)*(1-ppcnt);}
198  else {
199  return 0;
200  }
201 
202  // the xsection splines in INukeHadroData return the hadron x-section in
203  // mb -> convert to fm^2
204  sigtot *= (units::mb / units::fm2);
205 
206  // avoid defective error handling
207  //if(sigtot<1E-6){sigtot=1E-6;}
208 
209  if (xsecNNCorr and is_nucleon)
210  sigtot *= INukeNucleonCorr::getInstance()->
211  getAvgCorrection (rho, A, p4.E() - PDGLibrary::Instance()->Find(pdgc)->Mass()); //uses lookup tables
212 
213  // avoid defective error handling
214  if(sigtot<1E-6){sigtot=1E-6;}
215 
216  // compute the mean free path
217  double lamda = 1. / (rho * sigtot);
218 
219  // exits if lamda is InF (if cross section is 0)
220  if( ! TMath::Finite(lamda) ) {
221  return -1;
222  }
223 
224 /*
225  LOG("INukeUtils", pDEBUG)
226  << "sig_total = " << sigtot << " fm^2, rho = " << rho
227  << " fm^-3 => mfp = " << lamda << " fm.";
228 */
229  return lamda;
230 }
231 //____________________________________________________________________________
233  int pdgc, const TLorentzVector & x4, const TLorentzVector & p4, double A)
234 {
235 //
236 // **test**
237 //
238 
239 // Calculate the mean free path (in fm) for Delta's in a nucleus
240 //
241 // Inputs
242 // pdgc : Hadron PDG code
243 // x4 : Hadron 4-position in the nucleus coordinate system (units: fm)
244 // p4 : Hadron 4-momentum (units: GeV)
245 // A : Nucleus atomic mass number
246 //
247  bool is_deltapp = (pdgc==kPdgP33m1232_DeltaPP);
248  if(!is_deltapp) return 0.;
249 
250  // get the nuclear density at the current position
251  double rnow = x4.Vect().Mag();
252  double rho = A * utils::nuclear::Density(rnow,(int) A);
253 
254  // the Delta+N->N+N cross section will be evaluated within the range
255  // of the input spline and assumed to be const outside that range
256  double ke = (p4.Energy() - p4.M()) / units::MeV; // kinetic energy in MeV
257  ke = TMath::Max(1500., ke);
258  ke = TMath::Min( 0., ke);
259 
260  // get the Delta+N->N+N cross section
261  double sig = 0;
262  if (ke< 500) sig=20;
263  else if (ke<1000) sig=40;
264  else sig=30;
265 
266  // value is in mb -> convert to fm^2
267  sig *= (units::mb / units::fm2);
268 
269  // compute the mean free path
270  double lamda = 1. / (rho * sig);
271 
272  // exits if lamda is InF (if cross section is 0)
273  if( ! TMath::Finite(lamda) ) {
274  return -1;
275  }
276 
277  return lamda;
278 }
279 //____________________________________________________________________________
281  int pdgc, const TLorentzVector & x4, const TLorentzVector & p4, double A, double Z,
282  double mfp_scale_factor, double nRpi, double nRnuc, double NR, double R0)
283 {
284 // Calculate the survival probability for a hadron inside a nucleus
285 //
286 // Inputs
287 // pdgc : Hadron PDG code
288 // x4 : Hadron 4-position in the nucleus coordinate system (units: fm)
289 // p4 : Hadron 4-momentum (units: GeV)
290 // A : Nucleus atomic mass number
291 // mfp_scale_factor: Tweaks the mean free path (mfp -> mfp*scale). Def: 1.0
292 // nRpi: Controls the pion ring size in terms of de-Broglie wavelengths
293 // nRnuc: Controls the nuclepn ring size in terms of de-Broglie wavelengths
294 // NR: How far away to track the hadron, in terms of the corresponding
295 // nuclear radius. Def: 3
296 // R0: R0 in R=R0*A^1/3 (units:fm). Def. 1.4
297 
298  double prob = 1.0;
299 
300  double step = 0.05; // fermi
301  double R = NR * R0 * TMath::Power(A, 1./3.);
302 
303  TVector3 dr3 = p4.Vect().Unit(); // unit vector along its direction
304  TLorentzVector dr4(dr3,0);
305 
306  LOG("INukeUtils", pDEBUG)
307  << "Calculating survival probability for hadron with PDG code = " << pdgc
308  << " and momentum = " << p4.P() << " GeV";
309  LOG("INukeUtils", pDEBUG)
310  << "mfp scale = " << mfp_scale_factor
311  << ", nRpi = " << nRpi << ", nRnuc = " << nRnuc << ", NR = " << NR
312  << ", R0 = " << R0 << " fm";
313 
314  TLorentzVector x4_curr(x4); // current position
315 
316  while(1) {
317  double rnow = x4_curr.Vect().Mag();
318  if (rnow > (R+step)) break;
319 
320  x4_curr += (step*dr4);
321  rnow = x4_curr.Vect().Mag();
322  double mfp =
323  genie::utils::intranuke2015::MeanFreePath(pdgc,x4_curr,p4,A,Z,nRpi,nRnuc);
324  double mfp_twk = mfp * mfp_scale_factor;
325 
326  double dprob = (mfp_twk>0) ? TMath::Exp(-step/mfp_twk) : 0.;
327  prob*=dprob;
328 /*
329  LOG("INukeUtils", pDEBUG)
330  << "+ step size = " << step << " fm, |r| = " << rnow << " fm, "
331  << "mfp = " << mfp_twk << "fm (nominal mfp = " << mfp << " fm): "
332  << "dPsurv = " << dprob << ", current Psurv = " << prob;
333 */
334  }
335 
336  LOG("INukeUtils", pDEBUG) << "Psurv = " << prob;
337 
338  return prob;
339 }
340 //____________________________________________________________________________
342  const TLorentzVector & x4, const TLorentzVector & p4,
343  double A, double NR, double R0)
344 {
345 // Calculate distance within a nucleus (units: fm) before we stop tracking
346 // the hadron.
347 // See previous functions for a description of inputs.
348 //
349  double R = NR * R0 * TMath::Power(A, 1./3.);
350  double step = 0.05; // fermi
351 
352  TVector3 dr3 = p4.Vect().Unit(); // unit vector along its direction
353  TLorentzVector dr4(dr3,0);
354 
355  TLorentzVector x4_curr(x4); // current position
356 
357  double d=0;
358  while(1) {
359  double rnow = x4_curr.Vect().Mag();
360  x4_curr += (step*dr4);
361  d+=step;
362  rnow = x4_curr.Vect().Mag();
363  if (rnow > R) break;
364  }
365  return d;
366 }
367 //____________________________________________________________________________
369  int pdgc, const TLorentzVector & x4, const TLorentzVector & p4,
370  double A, double Z, double NR, double R0)
371 {
372 // Calculate distance within a nucleus (expressed in terms of 'mean free
373 // paths') before we stop tracking the hadron.
374 // See previous functions for a description of inputs.
375 //
376 
377 // distance before exiting in mean free path lengths
378 //
379  double R = NR * R0 * TMath::Power(A, 1./3.);
380  double step = 0.05; // fermi
381 
382  TVector3 dr3 = p4.Vect().Unit(); // unit vector along its direction
383  TLorentzVector dr4(dr3,0);
384 
385  TLorentzVector x4_curr(x4); // current position
386 
387  double d=0;
388  double d_mfp=0;
389  while(1) {
390  double rnow = x4_curr.Vect().Mag();
391  x4_curr += (step*dr4);
392  d+=step;
393  rnow = x4_curr.Vect().Mag();
394 
395  double lambda = genie::utils::intranuke2015::MeanFreePath(pdgc,x4_curr,p4,A,Z);
396  d_mfp += (step/lambda);
397 
398  if (rnow > R) break;
399  }
400  return d_mfp;
401 }
402 //____________________________________________________________________________
404  GHepParticle * p, double step, double nuclear_radius)
405 {
406 // Steps a particle starting from its current position (in fm) and moving
407 // along the direction of its current momentum by the input step (in fm).
408 // The particle is stepped in a straight line.
409 // If a nuclear radius is set then the following check is performed:
410 // If the step is too large and takes the the particle far away from the
411 // nucleus then its position is scaled back so that the escaped particles are
412 // always within a ~1fm from the "outer nucleus surface"
413 
414 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
415  LOG("INukeUtils", pDEBUG)
416  << "Stepping particle [" << p->Name() << "] by dr = " << step << " fm";
417 #endif
418 
419  // Step particle
420  TVector3 dr = p->P4()->Vect().Unit(); // unit vector along its direction
421  dr.SetMag(step); // spatial step size
422  double dt = 0; // temporal step:
423  TLorentzVector dx4(dr,dt); // 4-vector step
424  TLorentzVector x4new = *(p->X4()) + dx4; // new position
425 
426  if(nuclear_radius > 0.) {
427  // Check position against nuclear boundary. If the particle was stepped
428  // too far away outside the nuclear boundary bring it back to within
429  // 1fm from that boundary
430  double epsilon = 1; // fm
431  double r = x4new.Vect().Mag(); // fm
432  double rmax = nuclear_radius+epsilon;
433  if(r > rmax) {
434  LOG("INukeUtils", pINFO)
435  << "Particle was stepped too far away (r = " << r << " fm)";
436  LOG("INukeUtils", pINFO)
437  << "Placing it " << epsilon
438  << " fm outside the nucleus (r' = " << rmax << " fm)";
439  double scale = rmax/r;
440  x4new *= scale;
441  }//r>rmax
442  }//nucl radius set
443 
444 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
445  LOG("INukeUtils", pDEBUG)
446  << "\n Init direction = " << print::Vec3AsString(&dr)
447  << "\n Init position (in fm,nsec) = " << print::X4AsString(p->X4())
448  << "\n Fin position (in fm,nsec) = " << print::X4AsString(&x4new);
449 #endif
450 
451  p->SetPosition(x4new);
452 }
453 //___________________________________________________________________________
454 // Method to handle compound nucleus considerations, preequilibrium
455 // and equilibrium
456 // Alex Bell -- 6/17/2008
458  GHepRecord * ev, GHepParticle * p, int &RemnA, int &RemnZ, TLorentzVector &RemnP4,
459  bool DoFermi, double FermiFac, const NuclearModelI* Nuclmodel, double NucRmvE, EINukeMode mode)
460 {
461 
462 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
463  LOG("INukeUtils", pDEBUG)
464  << "PreEquilibrium() is invoked for a : " << p->Name()
465  << " whose kinetic energy is : " << p->KinE();
466 #endif
467 
468  // Random number generator
469  RandomGen * rnd = RandomGen::Instance();
470  PDGLibrary * pLib = PDGLibrary::Instance();
471 
472  bool allow_dup = true;
473  PDGCodeList list(allow_dup); // list of final state particles
474 
475  double ppcnt = (double) RemnZ / (double) RemnA; // % of protons left
476 
477 
478  // build the new clusters:
479  double pKE = p->KinE();
480  double c = 1 + (0.08 / pKE);
481  TVector3 pP3_2 = p->P4()->Vect() * c;
482  TVector3 pP3_1 = p->P4()->Vect() - pP3_2;
483 
484  TLorentzVector clusP4_1( pP3_1, 0.080);
485  TLorentzVector clusP4_2( pP3_2, pKE - 0.080 );
486 
487  TLorentzVector clusX4(*p->X4());
489  int mom = p->FirstMother();
490 
491  GHepParticle * p1 = new GHepParticle(kPdgCompNuclCluster, ist, mom, -1, -1, -1, clusP4_1, clusX4); // make sure this is the right constructor
492  GHepParticle * p2 = new GHepParticle(kPdgCompNuclCluster, ist, mom, -1, -1, -1, clusP4_2, clusX4);
493 
494  LOG("INukeUtils",pDEBUG) << "cluster formation check";
495  LOG("INukeUtils",pDEBUG) << "particle p0: E = " << p->E() << " , px = " << p->Px() << " , py = " << p->Py() << " , pz = " << p->Pz();
496  LOG("INukeUtils",pDEBUG) << "particle p1: E = " << p1->E() << " , px = " << p1->Px() << " , py = " << p1->Py() << " , pz = " << p1->Pz();
497  LOG("INukeUtils",pDEBUG) << "particle p2: E = " << p2->E() << " , px = " << p2->Px() << " , py = " << p2->Py() << " , pz = " << p2->Pz();
498  LOG("INukeUtils",pDEBUG) << "conservation: dE = " << p->E()-p1->E()-p2->E() << " dpx = " << p->Px()-p1->Px()-p2->Px() << " dpy = " << p->Py()-p1->Py()-p2->Py() << " dpz = " << p->Pz()-p1->Pz()-p2->Pz() ;
499 
500  RemnP4 -= clusP4_1 + clusP4_2 - *p->P4(); // extra statement to conserve 4-momenta
501 
502 
503  // figure out the final state conditions
504 
505  if(p->Pdg()==kPdgProton) list.push_back(kPdgProton);
506  else if(p->Pdg()==kPdgNeutron) list.push_back(kPdgNeutron);
507 
508  /*
509  for(int i=0;i<3;i++)
510  {
511  if(rnd->RndFsi().Rndm()<ppcnt)
512  {
513  list.push_back(kPdgProton);
514  RemnZ--;
515  }
516  else list.push_back(kPdgNeutron);
517 
518  RemnA--;
519 
520  ppcnt = (double) RemnZ / (double) RemnA;
521  }
522  */
523  for(int i=0;i<4;i++) // changed from 3 to 4. Want to divide energy among 4 + 1 = 5 particles
524  {
525  if(rnd->RndFsi().Rndm()<ppcnt)
526  {
527  list.push_back(kPdgProton);
528  RemnZ--;
529  }
530  else list.push_back(kPdgNeutron);
531 
532  RemnA--;
533 
534  ppcnt = (double) RemnZ / (double) RemnA;
535  }
536 
537  // Add the fermi energy of the three nucleons to the phase space
538  if(DoFermi)
539  {
540  Target target(ev->TargetNucleus()->Pdg());
541  TVector3 pBuf = p->P4()->Vect();
542  double mBuf = p->Mass();
543  double eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
544  TLorentzVector tSum(pBuf,eBuf);
545  double mSum = 0.0;
547  for(pdg_iter=++(list.begin());pdg_iter!=list.end();++pdg_iter)
548  {
549  target.SetHitNucPdg(*pdg_iter);
550  Nuclmodel->GenerateNucleon(target);
551  mBuf = pLib->Find(*pdg_iter)->Mass();
552  mSum += mBuf;
553  pBuf = FermiFac * Nuclmodel->Momentum3();
554  eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
555  tSum += TLorentzVector(pBuf,eBuf);
556  RemnP4 -= TLorentzVector(pBuf,eBuf-mBuf);
557  }
558  TLorentzVector dP4 = tSum + TLorentzVector(TVector3(0,0,0),-mSum);
559  p->SetMomentum(dP4);
560  }
561 
562  // do the phase space decay & save all f/s particles to the event record
563  //bool success = genie::utils::intranuke2015::PhaseSpaceDecay(ev,p,list,RemnP4,NucRmvE,mode);
564  bool success = genie::utils::intranuke2015::PhaseSpaceDecay(ev,p1,list,RemnP4,NucRmvE,mode);
565  if(success) LOG("INukeUtils",pINFO) << "Successful phase space decay for pre-equilibrium nucleus FSI event";
566  else
567  {
569  exception.SetReason("Phase space generation of pre-equilibrium nucleus final state failed, details above");
570  throw exception;
571  }
572 
573  /*
574  int p_loc = 0;
575  while(p_loc<ev->GetEntries()) // this sets p_loc to being the index of the probe particle (or whatever particle has the same pdg, status, and momentum)
576  {
577  GHepParticle * p_ref = ev->Particle(p_loc);
578  if(!p->ComparePdgCodes(p_ref)) p_loc++;
579  else
580  {
581  if(!p->CompareStatusCodes(p_ref)) p_loc++;
582  else
583  {
584  if(!p->CompareMomentum(p_ref)) p_loc++;
585  else break;
586  }
587  }
588  }
589 
590 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
591  LOG("INukeUtils", pDEBUG)
592  << "Particle at: " << p_loc;
593 #endif
594 
595  // find the appropriate daughter
596  vector<int> * descendants = ev->GetStableDescendants(p_loc);
597 
598  int loc = p_loc + 1;
599  int f_loc = p_loc + 1;
600  double energy = ev->Particle(loc)->E();
601  */
602 
603 /* // (1) least energetic
604  double min_en = energy;
605 
606  for(unsigned int j=0;j<descendants->size();j++)
607  {
608  loc = (*descendants)[j];
609  energy = ev->Particle(loc)->E();
610  if(energy<min_en)
611  {
612  f_loc = loc;
613  min_en = energy;
614  }
615  }
616 */
617 
618 /*
619  // (2) most energetic
620  double max_en = energy;
621 
622  for(unsigned int j=0;j<descendants->size();j++)
623  {
624  loc = (*descendants)[j];
625  energy = ev->Particle(loc)->E();
626  if(energy>max_en)
627  {
628  f_loc = loc;
629  max_en = energy;
630  }
631  }
632 
633  // (3) 1st particle
634  // ...just use the defaulted f_loc
635 
636  delete descendants;
637 
638 */ //no longer selecting most energetic product for second phase space decay
639 
640  /*
641  // change particle status for decaying particle
642  ev->Particle(f_loc)->SetStatus(kIStIntermediateState);
643  // decay a clone particle
644  GHepParticle * t = new GHepParticle(*(ev->Particle(f_loc)));
645  t->SetFirstMother(f_loc);
646  genie::utils::intranuke2015::Equilibrium(ev,t,RemnA,RemnZ,RemnP4,DoFermi,FermiFac,Nuclmodel,NucRmvE,mode);
647  */
648 
649  // still decaying a clone (?)
650  GHepParticle * t = new GHepParticle(*p2);
651  // may still need to set first mother
652  genie::utils::intranuke2015::Equilibrium(ev,t,RemnA,RemnZ,RemnP4,DoFermi,FermiFac,Nuclmodel,NucRmvE,mode);
653 
654  delete t;
655 }
656 //___________________________________________________________________________
657 // Method to handle Equilibrium reaction
658 // Alex Bell -- 6/17/2008
660  GHepRecord * ev, GHepParticle * p, int &RemnA, int &RemnZ, TLorentzVector &RemnP4,
661  bool DoFermi, double FermiFac, const NuclearModelI* Nuclmodel, double NucRmvE, EINukeMode mode)
662 {
663 
664 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
665  LOG("INukeUtils", pDEBUG)
666  << "Equilibrium() is invoked for a : " << p->Name()
667  << " whose kinetic energy is : " << p->KinE();
668 #endif
669 
670  // Random number generator
671  RandomGen * rnd = RandomGen::Instance();
672  PDGLibrary * pLib = PDGLibrary::Instance();
673 
674  bool allow_dup = true;
675  PDGCodeList list(allow_dup); // list of final state particles
676 
677  // % of protons left
678  double ppcnt = (double) RemnZ / (double) RemnA;
679 
680  // figure out the final state conditions
681 
682  if(p->Pdg()==kPdgProton) list.push_back(kPdgProton);
683  else if(p->Pdg()==kPdgNeutron) list.push_back(kPdgNeutron);
684 
685  //add additonal particles to stack
686  for(int i=0;i<2;i++)
687  {
688  if(rnd->RndFsi().Rndm()<ppcnt)
689  {
690  list.push_back(kPdgProton);
691  RemnZ--;
692  }
693  else list.push_back(kPdgNeutron);
694 
695  RemnA--;
696 
697  ppcnt = (double) RemnZ / (double) RemnA;
698  }
699 
700 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
701  LOG("INukeUtils", pDEBUG)
702  << "Remnant nucleus (A,Z) = (" << RemnA << ", " << RemnZ << ")";
703 #endif
704 
705  // Add the fermi energy of the three nucleons to the phase space
706  if(DoFermi)
707  {
708  Target target(ev->TargetNucleus()->Pdg());
709  TVector3 pBuf = p->P4()->Vect();
710  double mBuf = p->Mass();
711  double eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
712  TLorentzVector tSum(pBuf,eBuf);
713  double mSum = 0.0;
715  for(pdg_iter=++(list.begin());pdg_iter!=list.end();++pdg_iter)
716  {
717  target.SetHitNucPdg(*pdg_iter);
718  Nuclmodel->GenerateNucleon(target);
719  mBuf = pLib->Find(*pdg_iter)->Mass();
720  mSum += mBuf;
721  pBuf = FermiFac * Nuclmodel->Momentum3();
722  eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
723  tSum += TLorentzVector(pBuf,eBuf);
724  RemnP4 -= TLorentzVector(pBuf,eBuf-mBuf);
725  }
726  TLorentzVector dP4 = tSum + TLorentzVector(TVector3(0,0,0),-mSum);
727  p->SetMomentum(dP4);
728  }
729 
730  // do the phase space decay & save all f/s particles to the record
731  bool success = genie::utils::intranuke2015::PhaseSpaceDecay(ev,p,list,RemnP4,NucRmvE,mode);
732  if (success) LOG("INukeUtils",pINFO) << "successful pre-equilibrium interaction";
733  else
734  {
736  exception.SetReason("Phase space generation of compound nucleus final state failed, details above");
737  throw exception;
738  }
739 
740 }
741 //___________________________________________________________________________
743  GHepRecord* ev, int pcode, int tcode, int scode, int s2code, double C3CM,
744  GHepParticle* p, GHepParticle* t, int &RemnA, int &RemnZ, TLorentzVector &RemnP4, EINukeMode mode)
745 {
746  // Aaron Meyer (10/29/09)
747  // Adapted from kinematics in other function calls
748  //
749  // C3CM is the cosine of the scattering angle, calculated before calling
750  // p and t are the output particles, must be allocated before calling
751  // pcode,tcode,scode,s2code are initial and final particle PDG codes in scattering
752  // return value used for error checking
753 
754  // Kinematic variables
755 
756  double M1, M2, M3, M4; // rest energies, in GeV
757  double E3L, P3L, E4L, P4L;
758  TVector3 tP1L, tPtot, tbeta, tbetadir, tTrans, tVect;
759  TVector3 tP1zCM, tP2zCM, tP3L, tP4L;
760 
761  // Library instance for reference
762  PDGLibrary * pLib = PDGLibrary::Instance();
763 
764  // random number generator
765  //RandomGen * rnd = RandomGen::Instance();
766 
767  // handle fermi target
768  Target target(ev->TargetNucleus()->Pdg());
769 
770  // get mass for particles
771  M1 = pLib->Find(pcode)->Mass();
772  M2 = pLib->Find(tcode)->Mass();
773  M3 = pLib->Find(scode)->Mass();
774  M4 = pLib->Find(s2code)->Mass();
775 
776  // get lab energy and momenta and assign to 4 vectors
777  TLorentzVector t4P1L = *p->P4();
778  TLorentzVector t4P2L = *t->P4();
779 
780  // binding energy
781  double bindE = 0.025; // empirical choice, might need to be improved
782  //double bindE = 0.0;
783 
784  LOG("TwoBodyCollision",pNOTICE) << "M1 = " << t4P1L.M() << " , M2 = " << t4P2L.M();
785  LOG("TwoBodyCollision",pNOTICE) << "E1 = " << t4P1L.E() << " , E2 = " << t4P2L.E();
786 
787  if ( (p->Energy()-p->Mass()) < bindE ){bindE = 0.;} // if the probe's energy is less than the binding energy, set the binding energy to 0.
788 
789  // don't use BE unless kinetic energy >> BE.
790  if((pcode==2112||pcode==2212)&&(t4P1L.E()-M1)<.1) bindE = 0.0;
791  if((pcode==211||pcode==-211||pcode==111)&&(t4P1L.E()-M1)<.08) bindE = 0.0;
792  if((pcode==321)&&(t4P1L.E()-M1)<.1) bindE = 0.0;
793 
794  // carry out scattering
795  TLorentzVector t4P3L, t4P4L;
796  if (!TwoBodyKinematics(M3,M4,t4P1L,t4P2L,t4P3L,t4P4L,C3CM,RemnP4,bindE))
797  {
798  P3L = t4P3L.Vect().Mag();
799  P4L = t4P4L.Vect().Mag();
800  E3L = t4P3L.E();
801  E4L = t4P4L.E();
802 
803  LOG("TwoBodyCollision",pNOTICE)
804  << "TwoBodyKinematics fails: C3CM, P3 = " << C3CM << " "
805  << P3L << " " << E3L << "\n" << " P4 = "
806  << P4L << " " << E4L ;
807  return false; //covers all possiblities for now
808  }
809 
810  // error checking
811  P3L = t4P3L.Vect().Mag();
812  P4L = t4P4L.Vect().Mag();
813  E3L = t4P3L.E();
814  E4L = t4P4L.E();
815  LOG("INukeUtils",pINFO)
816  << "C3CM, P3 = " << C3CM << " "
817  << P3L << " " << E3L << "\n" << " P4 = "
818  << P4L << " " << E4L ;
819 
820  // handle very low momentum particles
821  if(!(TMath::Finite(P3L)) || P3L<.001)
822  {
823  LOG("INukeUtils",pINFO)
824  << "Particle 3 momentum small or non-finite: " << P3L
825  << "\n" << "--> Assigning .001 as new momentum";
826  P3L = .001;
827  E3L = TMath::Sqrt(P3L*P3L + M3*M3);
828  }
829  if(!(TMath::Finite(P4L)) || P4L<.001)
830  {
831  LOG("INukeUtils",pINFO)
832  << "Particle 4 momentum small or non-finite: " << P4L
833  << "\n" << "--> Assigning .001 as new momentum";
834  P4L = .001;
835  E4L = TMath::Sqrt(P4L*P4L + M4*M4);
836  }
837 
838  // if this is going to be on in the future, remember to not apply PB for Oset
839  /*// pauli blocking turn off for now to better match data
840  // if(P3L<fFermiMomentum && pdg::IsNeutronOrProton(scode) ||
841  // P4L<fFermiMomentum && pdg::IsNeutronOrProton(s2code) )
842  if(P3L<.25 && pdg::IsNeutronOrProton(scode) ||
843  P4L<.25 && pdg::IsNeutronOrProton(s2code) )
844  {
845  LOG("INukeUtils",pNOTICE)<< "TwoBodyCollision failed: Pauli blocking";
846  p->SetStatus(kIStHadronInTheNucleus);
847  RemnP4 -= TLorentzVector(0,0,0,bindE);
848  return false;
849  }*/
850 
851  // update remnant nucleus
852  RemnP4 -= t4P2L;
853  LOG("INukeUtils",pINFO)
854  << "t4P2L= " << t4P2L.E() << " " << t4P2L.Z()
855  << " RemnP4= " << RemnP4.E() << " " << RemnP4.Z() ;
856  if (tcode==kPdgProton) {RemnZ--;RemnA--;}
857  else if(tcode==kPdgNeutron) RemnA--;
858 
859  // create t particle w/ appropriate momenta, code, and status
860  // Set target's mom to be the mom of the hadron that was cloned
861  t->SetFirstMother(p->FirstMother());
862  t->SetLastMother(p->LastMother());
863 
864  // adjust p to reflect scattering
865  p->SetPdgCode(scode);
866  p->SetMomentum(t4P3L);
867 
868  t->SetPdgCode(s2code);
869  t->SetMomentum(t4P4L);
870 
871  if (mode==kIMdHN)
872  {
875  }
876  else
877  {
880  }
881  LOG("INukeUtils",pINFO) << "Successful 2 body collision";
882  return true;
883 
884 }
885 //___________________________________________________________________________
887  double M3, double M4, TLorentzVector t4P1L, TLorentzVector t4P2L,
888  TLorentzVector &t4P3L, TLorentzVector &t4P4L, double C3CM, TLorentzVector &RemnP4, double bindE)
889 {
890  // Aaron Meyer (05/17/10)
891  // Adapted from kinematics in other function calls
892  //
893  // Outgoing particle masses M3,M4
894  // Scatters particles according to normal two body collisions
895  //
896  // bindE is the binding energy (GeV) of a particle removed from the nucleus (default 0)
897  // For nonzero binding energy, remove the binding energy from the total energy,
898  // then put both of the particles back on mass shell by shifting momentum/energy
899  // of target
900  // Momentum only shifted in the direction parallel to the probe's motion
901  //
902  // Rotates final transverse component of momentum by a random angle from 0->2pi
903  // Return value for error checking
904  // Gives outgoing 4-momenta of particles 3 and 4 (t4P3L, t4P4L respectively)
905  //
906  // All 4-momenta should be on mass shell
907 
908  double E1L, E2L, P1L, P2L, E3L, P3L;
909  double beta, gm; // speed and gamma for CM frame in Lab
910  double S3CM; // sin of scattering angle
911  double PHI3;
912  double E1CM, E2CM, E3CM, P3CM;//, E4CM, P4CM;
913  double P3zL, P3tL;//, P4zL, P4tL;
914  double Et;
915  double theta1, theta2, theta5, P1zL, P2zL, P1tL, P2tL;
916  TVector3 tbeta, tbetadir, tTrans, tVect;
917  TVector3 tP1zCM, tP2zCM, vP3L;
918  TLorentzVector t4P1buf, t4P2buf, t4Ptot;
919 
920  // Library instance for reference
921  //PDGLibrary * pLib = PDGLibrary::Instance();
922 
923  // random number generator
924  RandomGen * rnd = RandomGen::Instance();
925 
926  // error checking
927  if (C3CM < -1. || C3CM > 1.) return false;
928 
929  // calculate sine from scattering angle
930  S3CM = TMath::Sqrt(1.0 - C3CM*C3CM);
931 
932  // fill buffers
933  t4P1buf = t4P1L;
934  t4P2buf = t4P2L;
935 
936  // get lab energy and momenta
937  E1L = t4P1buf.E();
938  P1L = t4P1buf.P();
939  E2L = t4P2buf.E();
940  P2L = t4P2buf.P();
941  t4Ptot = t4P1buf + t4P2buf;
942 
943  LOG("INukeUtils",pINFO) <<"M1 "<<t4P1L.M()<< ", M2 "<<t4P2L.M();
944  LOG("INukeUtils",pINFO) <<"E1L "<<E1L<< ", E1CM "<<E1CM;
945  LOG("INukeUtils",pINFO) <<"bindE = " << bindE;
946 
947  // binding energy
948  if (bindE!=0)
949  {
950 
951  E1L -= bindE;
952 
953  if (E1L+E2L < M3+M4)
954  {
955  LOG("INukeUtils",pNOTICE) <<"TwoBodyKinematics Failed: Forbidden by binding energy";
956  LOG("INukeUtils",pNOTICE) <<"E1L, E2L, M3, M4 : "<< E1L <<", "<< E2L <<", "<< M3 <<", "<< M4;
957  t4P3L.SetPxPyPzE(0,0,0,0);
958  t4P4L.SetPxPyPzE(0,0,0,0);
959  return false;
960  }
961  }
962 
963  // calculate beta and gamma
964  tbeta = t4Ptot.Vect() * (1.0 / (E1L + E2L));
965  tbetadir = tbeta.Unit();
966  beta = tbeta.Mag();
967  gm = 1.0 / TMath::Sqrt(1.0 - beta*beta);
968 
969  // get angle and component info
970  theta1 = t4P1buf.Angle(tbeta);
971  theta2 = t4P2buf.Angle(tbeta);
972  P1zL = P1L*TMath::Cos(theta1);
973  P2zL = P2L*TMath::Cos(theta2);
974  P1tL = TMath::Sqrt(P1L*P1L - P1zL*P1zL);
975  P2tL = -TMath::Sqrt(P2L*P2L - P2zL*P2zL);
976  tVect.SetXYZ(1,0,0);
977  if(TMath::Abs((tVect - tbetadir).Mag())<.01) tVect.SetXYZ(0,1,0);
978  theta5 = tVect.Angle(tbetadir);
979  tTrans = (tVect - TMath::Cos(theta5)*tbetadir).Unit();
980 
981  // boost to CM frame to get scattered particle momenta
982  E1CM = gm*E1L - gm*beta*P1zL;
983  tP1zCM = gm*P1zL*tbetadir - gm*tbeta*E1L;
984  E2CM = gm*E2L - gm*beta*P2zL;
985  tP2zCM = gm*P2zL*tbetadir - gm*tbeta*E2L;
986  Et = E1CM + E2CM;
987 //-------
988 
989  LOG("INukeUtils",pINFO) <<"M1 "<<t4P1L.M()<< ", M2 "<<t4P2L.M();
990  LOG("INukeUtils",pINFO) <<"E1L "<<E1L<< ", E1CM "<<E1CM;
991  LOG("INukeUtils",pINFO) <<"P1zL "<<P1zL<<", P1zCM "<<tP1zCM.Mag()<<", P1tL "<<P1tL;
992  LOG("INukeUtils",pINFO) <<"E2L "<<E2L<< ", E2CM "<<E2CM;
993  LOG("INukeUtils",pINFO) <<"P2zL "<<P2zL<<", P2zCM "<<tP2zCM.Mag()<<", P2tL "<<P2tL;
994  LOG("INukeUtils",pINFO) <<"C3CM "<<C3CM;
995 
996 //-------
997  E3CM = (Et*Et + M3*M3 - M4*M4) / (2.0 * Et);
998 
999  // check to see if decay is viable
1000  if(E3CM*E3CM - M3*M3<0 || E3CM<0 || Et<0)
1001  {
1002  if (Et<0) LOG("INukeUtils",pNOTICE) <<"TwoBodyKinematics Failed: Total energy is negative";
1003  if (E3CM<M3) LOG("INukeUtils",pNOTICE) <<"TwoBodyKinematics Failed: Scattered Particle 3 CM energy is too small";
1004  if (E3CM*E3CM - M3*M3<0) LOG("INukeUtils",pNOTICE) <<"TwoBodyKinematics Failed: Scattered Particle 3 CM momentum is nonreal";
1005  t4P3L.SetPxPyPzE(0,0,0,0);
1006  t4P4L.SetPxPyPzE(0,0,0,0);
1007  return false;
1008  }
1009  P3CM = TMath::Sqrt(E3CM*E3CM - M3*M3);
1010 
1011  // boost back to lab
1012  P3zL = gm*beta*E3CM + gm*P3CM*C3CM;
1013  P3tL = P3CM*S3CM;
1014 
1015  P3L = TMath::Sqrt(P3zL*P3zL + P3tL*P3tL);
1016  E3L = TMath::Sqrt(P3L*P3L + M3*M3);
1017 
1018  //-------
1019 
1020  double E4CM = Et-E3CM;
1021  double P4zL = gm*beta*E4CM - gm*P3CM*C3CM;
1022  double P4tL = -1.*P3tL;
1023  double P4L = TMath::Sqrt(P4zL*P4zL + P4tL*P4tL);
1024  double E4L = TMath::Sqrt(P4L*P4L + M4*M4);
1025 
1026  LOG("INukeUtils",pINFO) <<"M3 "<< M3 << ", M4 "<< M4;
1027  LOG("INukeUtils",pINFO) <<"E3L "<<E3L<< ", E3CM "<<E3CM;
1028  LOG("INukeUtils",pINFO) <<"P3zL "<<P3zL<<", P3tL "<<P3tL;
1029  LOG("INukeUtils",pINFO) <<"C3L "<<P3zL/P3L;
1030  LOG("INukeUtils",pINFO) <<"Check:";
1031  LOG("INukeUtils",pINFO) <<"E4L "<<E4L<< ", E4CM "<<E4CM;
1032  LOG("INukeUtils",pINFO) <<"P4zL "<<P4zL<<", P4tL "<<P4tL;
1033  LOG("INukeUtils",pINFO) <<"P4L "<<P4L;
1034  LOG("INukeUtils",pINFO) <<"C4L "<<P4zL/P4L;
1035 
1036  double echeck = E1L + E2L - (E3L + E4L);
1037  double pzcheck = P1zL+ P2zL - (P3zL + P4zL);
1038  double ptcheck = P1tL+ P2tL - (P3tL + P4tL);
1039 
1040  LOG("INukeUtils",pINFO) <<"Check 4-momentum conservation - Energy "<<echeck<<", z momentum "<<pzcheck << ", transverse momentum " << ptcheck ;
1041 
1042  // -------
1043 
1044  // handle very low momentum particles
1045  if(!(TMath::Finite(P3L)) || P3L<.001)
1046  {
1047  LOG("INukeUtils",pINFO)
1048  << "Particle 3 momentum small or non-finite: " << P3L
1049  << "\n" << "--> Assigning .001 as new momentum";
1050  P3tL = 0;
1051  P3zL = .001;
1052  P3L = .001;
1053  E3L = TMath::Sqrt(P3L*P3L + M3*M3);
1054  }
1055 
1056  // get random phi angle, distributed uniformally in 360 deg
1057  PHI3 = 2 * kPi * rnd->RndFsi().Rndm();
1058 
1059  vP3L = P3zL*tbetadir + P3tL*tTrans;
1060  vP3L.Rotate(PHI3,tbetadir);
1061 
1062  t4P3L.SetVect(vP3L);
1063  t4P3L.SetE(E3L);
1064 
1065  t4P4L = t4P1buf + t4P2buf - t4P3L;
1066  t4P4L-= TLorentzVector(0,0,0,bindE);
1067  /*LOG("INukeUtils",pINFO) <<"GENIE:";
1068  LOG("INukeUtils",pINFO) <<"E4L "<<t4P4L.E();
1069  LOG("INukeUtils",pINFO) <<"P4zL "<<t4P4L.Vect()*tbetadir<<", P4tL "<<-1.*TMath::Sqrt(t4P4L.Vect().Mag2()-TMath::Power(t4P4L.Vect()*tbetadir,2.));
1070  LOG("INukeUtils",pINFO) <<"P4L "<<t4P4L.Vect().Mag();
1071  LOG("INukeUtils",pINFO) <<"C4L "<<t4P4L.Vect()*tbetadir/t4P4L.Vect().Mag(); */
1072 
1073  if(t4P4L.Mag2()<0 || t4P4L.E()<0)
1074  {
1075  LOG("INukeUtils",pNOTICE)<<"TwoBodyKinematics Failed: Target mass or energy is negative";
1076  t4P3L.SetPxPyPzE(0,0,0,0);
1077  t4P4L.SetPxPyPzE(0,0,0,0);
1078  return false;
1079  }
1080 
1081  if (bindE!=0) RemnP4 += TLorentzVector(0,0,0,bindE);
1082  return true;
1083 }
1084 //___________________________________________________________________________
1086  GHepRecord* ev, GHepParticle* p, int tcode, GHepParticle* s1, GHepParticle* s2, GHepParticle* s3,
1087  bool DoFermi, double FermiFac, double FermiMomentum, const NuclearModelI* Nuclmodel)
1088 {
1089 
1090  // Aaron Meyer (7/15/10)
1091  //
1092  // Kinematics used in utils::intranuke2015::PionProduction
1093  // Handles the kinematics of three body scattering
1094  //
1095  // s1,s2,and s3 are pointers to particles with the PDG code that needs to be scattered
1096  // the last four variables are for Fermi momentum and pauli blocking, default will use none of them
1097 
1098  // kinematic variables
1099  double M1, M2, M3, M4, M5; // rest energies, in GeV
1100  double P1L, P2L, P3L, P4L, P5L;
1101  double E1L, E2L, E3L, E4L, E5L;
1102  double E1CM, E2CM, P3tL;
1103  double PizL, PitL, PiL, EiL;
1104  double EiCM, P4CM2, E4CM2, E5CM2, P3CM, E3CM;
1105  double beta, gm, beta2, gm2;
1106  double P3zL, P4zL, P4tL, P5zL, P5tL;
1107  double Et, M, theta1, theta2;
1108  double P1zL, P2zL;
1109  double theta3, theta4, phi3, phi4, theta5;
1110  TVector3 tP2L, tP1L, tPtot, tbeta, tbetadir, tTrans, tP4L, tP5L;
1111  TVector3 tP1zCM, tP2zCM, tP3L, tPiL, tbeta2, tbetadir2, tVect, tTrans2;
1112 
1113  // Library instance for reference
1114  PDGLibrary * pLib = PDGLibrary::Instance();
1115 
1116  // random number generator
1117  RandomGen * rnd = RandomGen::Instance();
1118 
1119  M1 = pLib->Find(p->Pdg())->Mass();
1120  M2 = pLib->Find(tcode)->Mass();
1121  M3 = pLib->Find(s1->Pdg())->Mass();
1122  M4 = pLib->Find(s2->Pdg())->Mass();
1123  M5 = pLib->Find(s3->Pdg())->Mass();
1124 
1125  // set up fermi target
1126  Target target(ev->TargetNucleus()->Pdg());
1127 
1128  // handle fermi momentum
1129  if(DoFermi)
1130  {
1131  target.SetHitNucPdg(tcode);
1132  Nuclmodel->GenerateNucleon(target);
1133  tP2L = FermiFac * Nuclmodel->Momentum3();
1134  P2L = tP2L.Mag();
1135  E2L = TMath::Sqrt(tP2L.Mag2() + M2*M2);
1136  }
1137  else
1138  {
1139  tP2L.SetXYZ(0.0, 0.0, 0.0);
1140  P2L = 0;
1141  E2L = M2;
1142  }
1143 
1144  // first sequence, handle 4th and 5th products as composite
1145  E1L = p->E();
1146 
1147  P1L = TMath::Sqrt(E1L*E1L - M1*M1);
1148  tP1L = p->P4()->Vect();
1149  tPtot = tP1L + tP2L;
1150 
1151  tbeta = tPtot * (1.0 / (E1L + E2L));
1152  tbetadir = tbeta.Unit();
1153  beta = tbeta.Mag();
1154  gm = 1.0 / TMath::Sqrt(1.0 - beta*beta);
1155 
1156  theta1 = tP1L.Angle(tbeta);
1157  theta2 = tP2L.Angle(tbeta);
1158  P1zL = P1L*TMath::Cos(theta1);
1159  P2zL = P2L*TMath::Cos(theta2);
1160  tVect.SetXYZ(1,0,0);
1161  if(TMath::Abs((tVect - tbetadir).Mag())<.01) tVect.SetXYZ(0,1,0);
1162  theta5 = tVect.Angle(tbetadir);
1163  tTrans = (tVect - TMath::Cos(theta5)*tbetadir).Unit();
1164 
1165  E1CM = gm*E1L - gm*beta*P1zL;
1166  tP1zCM = gm*P1zL*tbetadir - gm*tbeta*E1L;
1167  E2CM = gm*E2L - gm*beta*P2zL;
1168  tP2zCM = gm*P2zL*tbetadir - gm*tbeta*E2L;
1169  Et = E1CM + E2CM;
1170  M = (rnd->RndFsi().Rndm()*(Et - M3 - M4 - M5)) + (M4 + M5);
1171  E3CM = (Et*Et + M3*M3 - M*M)/(2*Et);
1172  EiCM = Et - E3CM;
1173  if(E3CM*E3CM - M3*M3<0)
1174  {
1175  LOG("INukeUtils",pNOTICE)
1176  << "PionProduction P3 has non-real momentum - retry kinematics";
1177  LOG("INukeUtils",pNOTICE) << "Energy, masses of 3 fs particales:"
1178  << E3CM << " " << M3 << " " << " " << M4 << " " << M5;
1180  exception.SetReason("PionProduction particle 3 has non-real momentum");
1181  throw exception;
1182  return false;
1183  }
1184  P3CM = TMath::Sqrt(E3CM*E3CM - M3*M3);
1185 
1186  theta3 = kPi * rnd->RndFsi().Rndm();
1187  theta4 = kPi * rnd->RndFsi().Rndm();
1188  phi3 = 2*kPi * rnd->RndFsi().Rndm();
1189  phi4 = 2*kPi * rnd->RndFsi().Rndm();
1190 
1191  P3zL = gm*beta*E3CM + gm*P3CM*TMath::Cos(theta3);
1192  P3tL = P3CM*TMath::Sin(theta3);
1193  PizL = gm*beta*EiCM - gm*P3CM*TMath::Cos(theta3);
1194  PitL = -P3CM*TMath::Sin(theta3);
1195 
1196  P3L = TMath::Sqrt(P3zL*P3zL + P3tL*P3tL);
1197  PiL = TMath::Sqrt(PizL*PizL + PitL*PitL);
1198  E3L = TMath::Sqrt(P3L*P3L + M3*M3);
1199  EiL = TMath::Sqrt(PiL*PiL + M*M);
1200 
1201  // handle very low momentum particles
1202  if(!(TMath::Finite(P3L)) || P3L < .001)
1203  {
1204  LOG("INukeUtils",pINFO)
1205  << "Particle 3 " << M3 << " momentum small or non-finite: " << P3L
1206  << "\n" << "--> Assigning .001 as new momentum";
1207  P3tL = 0;
1208  P3zL = .001;
1209  P3L = .001;
1210  E3L = TMath::Sqrt(P3L*P3L + M3*M3);
1211  }
1212 
1213  tP3L = P3zL*tbetadir + P3tL*tTrans;
1214  tPiL = PizL*tbetadir + PitL*tTrans;
1215  tP3L.Rotate(phi3,tbetadir);
1216  tPiL.Rotate(phi3,tbetadir);
1217 
1218  // second sequence, handle formally composite particles 4 and 5
1219  tbeta2 = tPiL * (1.0 / EiL);
1220  tbetadir2 = tbeta2.Unit();
1221  beta2 = tbeta2.Mag();
1222  gm2 = 1.0 / TMath::Sqrt(1.0 - beta2*beta2);
1223 
1224  E4CM2 = (M*M + M4*M4 - M5*M5) / (2*M);
1225  E5CM2 = M - E4CM2;
1226  P4CM2 = TMath::Sqrt(E4CM2*E4CM2 - M4*M4);
1227 
1228  tVect.SetXYZ(1,0,0);
1229  if(TMath::Abs((tVect - tbetadir2).Mag())<.01) tVect.SetXYZ(0,1,0);
1230  theta5 = tVect.Angle(tbetadir2);
1231  tTrans2 = (tVect - TMath::Cos(theta5)*tbetadir2).Unit();
1232 
1233  P4zL = gm2*beta2*E4CM2 + gm2*P4CM2*TMath::Cos(theta4);
1234  P4tL = P4CM2*TMath::Sin(theta4);
1235  P5zL = gm2*beta2*E5CM2 - gm2*P4CM2*TMath::Cos(theta4);
1236  P5tL = - P4tL;
1237 
1238  P4L = TMath::Sqrt(P4zL*P4zL + P4tL*P4tL);
1239  P5L = TMath::Sqrt(P5zL*P5zL + P5tL*P5tL);
1240  E4L = TMath::Sqrt(P4L*P4L + M4*M4);
1241  E5L = TMath::Sqrt(P5L*P5L + M5*M5);
1242 
1243  // handle very low momentum particles
1244  if(!(TMath::Finite(P4L)) || P4L < .001)
1245  {
1246  LOG("INukeUtils",pINFO)
1247  << "Particle 4 " << M4 << " momentum small or non-finite: " << P4L
1248  << "\n" << "--> Assigning .001 as new momentum";
1249  P4tL = 0;
1250  P4zL = .001;
1251  P4L = .001;
1252  E4L = TMath::Sqrt(P4L*P4L + M4*M4);
1253  }
1254  if(!(TMath::Finite(P5L)) || P5L < .001)
1255  {
1256  LOG("INukeUtils",pINFO)
1257  << "Particle 5 " << M5 << " momentum small or non-finite: " << P5L
1258  << "\n" << "--> Assigning .001 as new momentum";
1259  P5tL = 0;
1260  P5zL = .001;
1261  P5L = .001;
1262  E5L = TMath::Sqrt(P5L*P5L + M5*M5);
1263  }
1264 
1265  tP4L = P4zL*tbetadir2 + P4tL*tTrans2;
1266  tP5L = P5zL*tbetadir2 + P5tL*tTrans2;
1267  tP4L.Rotate(phi4,tbetadir2);
1268  tP5L.Rotate(phi4,tbetadir2);
1269 
1270  // pauli blocking
1271  if(P3L < FermiMomentum || ( pdg::IsNeutronOrProton(s2->Pdg()) && P4L < FermiMomentum ) )
1272  {
1273  LOG("INukeUtils",pNOTICE)
1274  << "PionProduction fails because of Pauli blocking - retry kinematics";
1276  exception.SetReason("PionProduction final state not determined");
1277  throw exception;
1278  return false;
1279  }
1280 
1281  // create scattered particles w/ appropriate momenta, code, and status
1282  // Set moms to be the moms of the hadron that was cloned
1283  s1->SetFirstMother(p->FirstMother());
1284  s2->SetFirstMother(p->FirstMother());
1285  s3->SetFirstMother(p->FirstMother());
1286  s1->SetLastMother(p->LastMother());
1287  s2->SetLastMother(p->LastMother());
1288  s3->SetLastMother(p->LastMother());
1289 
1290  TLorentzVector(tP3L,E3L);
1291  TLorentzVector(tP4L,E4L);
1292  TLorentzVector(tP5L,E5L);
1293 
1294  s1->SetMomentum(TLorentzVector(tP3L,E3L));
1295  s2->SetMomentum(TLorentzVector(tP4L,E4L));
1296  s3->SetMomentum(TLorentzVector(tP5L,E5L));
1297  int mode = kIMdHA;
1298  LOG ("INukeUtils",pDEBUG) << "in Pi Prod, mode = " << mode;
1299  if (mode==kIMdHN)
1300  {
1304  }
1305  else
1306  {
1310  }
1311  return true;
1312 }
1313 //___________________________________________________________________________
1315  GHepRecord* ev, GHepParticle* p, GHepParticle* s1, GHepParticle* s2, GHepParticle* s3, int &RemnA, int &RemnZ,
1316  TLorentzVector &RemnP4, bool DoFermi, double FermiFac, double FermiMomentum, const NuclearModelI* Nuclmodel)
1317 {
1318  // Aaron Meyer (7/15/2010)
1319  //
1320  // Handles pion production reactions in both hA and hN mode
1321  // Calculates fundamental cross sections from fit functions
1322  // Uses isospin relations to determine the rest of cross sections
1323  //
1324  // p is the probe particle
1325  // s1, s2, and s3 are the particles produced in the reaction
1326  // must set the status and add particles to the event record after returning from this method
1327  // return value for error checking
1328 
1329 
1330  // random number generator
1331  RandomGen * rnd = RandomGen::Instance();
1332 
1333  // library reference
1334  PDGLibrary * pLib = PDGLibrary::Instance();
1335 
1336  bool ptarg = false;
1337  int pcode = p->Pdg();
1338 
1339  int p1code = p->Pdg();
1340  // Randomly determine target and 1st product baryons
1341  int p3code = 0, p4code = 0, p5code = 0;
1342 
1343  //
1344  // Uses a fit curve log(sigma) = a - b/(T_pi - c) for pions
1345  // Fit parameters determined by Roman Tacik (4/3/09)
1346  // pi- & p cross sections are assumed to be the same as pi+ & n
1347  //
1348  // Fit curve for nucleons:
1349  // sigma = a*(1+b*e^(-c*(eta-d)^2))*(1-e^(-(f*eta)^g))*(1-e^(-h/eta^2))
1350  // 7 parameters (a,b,c,d,f,g,h)
1351  // eta is maximum kinematically allowed momentum of the pion, normalized by the mass
1352  // Uses isotopic spin decomposition of total cross sections
1353  //
1354 
1355  if ((p1code==kPdgPi0)||(p1code==kPdgPiP)||(p1code==kPdgPiM)) {
1356 
1357  double kine = 1000*p->KinE();
1358 
1359  // Determine cross sections
1360 
1361  // pion
1362  // pi- & p
1363  // -> pi0 & pi0 & n
1364  // a = 8.82; b = 573.2; c = 107.3;
1365  double xsec2pi0n = TMath::Max(0.,TMath::Exp(8.82 - (573.2/(kine-107.3))));
1366  // -> pi- & pi+ & n
1367  // a = 11.06; b = 985.9; c = 88.2;
1368  double xsecpippimn = TMath::Max(0.,TMath::Exp(11.06 - (985.9/(kine-88.2))));
1369  // -> pi- & pi0 & p
1370  // a = 9.58; b = 1229.4; c = 60.5;
1371  double xsecpimpi0p = TMath::Max(0.,TMath::Exp(9.58 - (1229.4/(kine-60.5))));
1372  double totpimp = xsec2pi0n + xsecpippimn + xsecpimpi0p;
1373 
1374 
1375  // pi+ & p
1376  // -> pi+ & pi+ & n
1377  // a = 5.64; b = 222.6; c = 150.0;
1378  double xsec2pipn = TMath::Max(0.,TMath::Exp(5.64 - (222.6/(kine-150.))));
1379  // -> pi+ & pi0 & p
1380  // a = 7.95; b = 852.6; c = 77.8;
1381  double xsecpippi0p = TMath::Max(0.,TMath::Exp(7.95 - (852.6/(kine-77.8))));
1382  double totpipp = xsec2pipn + xsecpippi0p;
1383 
1384  if (totpimp<=0 && totpipp<=0) {
1385  LOG("INukeUtils",pNOTICE) << "InelasticHN called below threshold energy";
1387  ev->AddParticle(*p);
1388  return false;
1389  }
1390 
1391  double xsecp, xsecn;
1392  switch (p1code) {
1393  case kPdgPi0: xsecp = 0.5 * (totpimp + totpipp); xsecn = xsecp; break;
1394  case kPdgPiP: xsecp = totpipp; xsecn = totpimp; break;
1395  case kPdgPiM: xsecp = totpimp; xsecn = totpipp; break;
1396  default:
1397  LOG("INukeUtils",pWARN) << "InelasticHN cannot handle probe: "
1398  << PDGLibrary::Instance()->Find(p1code)->GetName();
1400  exception.SetReason("PionProduction final state not determined");
1401  throw exception;
1402  return false;
1403  break;
1404  }
1405 
1406  // Normalize cross sections by Z or A-Z
1407 
1408  xsecp *= RemnZ;
1409  xsecn *= RemnA-RemnZ;
1410 
1411  // determine target
1412 
1413  double rand = rnd->RndFsi().Rndm() * (xsecp + xsecn);
1414  if (rand < xsecp) // proton target
1415  { rand /= RemnZ; ptarg = true;}
1416  else // neutron target
1417  { rand -= xsecp; rand /= RemnA-RemnZ; ptarg = false;}
1418 
1419 
1420  // determine final state
1421 
1422  if (((ptarg==true)&&(p1code==kPdgPiP))
1423  || ((ptarg==false)&&(p1code==kPdgPiM)))
1424  {
1425  if (rand < xsec2pipn) // pi+ & pi+ & n final state
1426  {
1427  p3code = (ptarg ? kPdgNeutron : kPdgProton);
1428  p4code = p1code;
1429  p5code = p4code;
1430  }
1431  else { // pi+ & pi0 & p final state
1432  p3code = (ptarg ? kPdgProton : kPdgNeutron);
1433  p4code = p1code;
1434  p5code = kPdgPi0;
1435  }
1436  }
1437  else if (((ptarg==false)&&(p1code==kPdgPiP))
1438  || ((ptarg==true)&&(p1code==kPdgPiM)))
1439  {
1440  if (rand < xsec2pi0n) // pi0 & pi0 & n final state
1441  {
1442  p3code = (ptarg ? kPdgNeutron : kPdgProton);
1443  p4code = kPdgPi0;
1444  p5code = p4code;
1445  }
1446  else if (rand < (xsec2pi0n + xsecpippimn)) // pi+ & pi- & n final state
1447  {
1448  p3code = (ptarg ? kPdgNeutron : kPdgProton);
1449  p4code = p1code;
1450  p5code = ((p1code==kPdgPiP) ? kPdgPiM : kPdgPiP);
1451  }
1452  else // pi0 & pi- & p final state
1453  {
1454  p3code = (ptarg ? kPdgProton : kPdgNeutron);
1455  p4code = p1code;
1456  p5code = kPdgPi0;
1457  }
1458  }
1459  else if (p1code==kPdgPi0)
1460  {
1461  rand = rnd->RndFsi().Rndm();
1462  if (rand < 191./270.)
1463  { // pi+ & pi- & p final state
1464  p3code = (ptarg ? kPdgProton : kPdgNeutron);
1465  p4code = kPdgPiP;
1466  p5code = kPdgPiM;
1467  }
1468  else if (rand < 7./135.)
1469  { // pi0 & pi0 & p final state
1470  p3code = (ptarg ? kPdgProton : kPdgNeutron);
1471  p4code = kPdgPi0;
1472  p5code = p4code;
1473  }
1474  else
1475  { // pi+ & pi0 & n final state
1476  p3code = (ptarg ? kPdgNeutron : kPdgProton);
1477  p4code = (ptarg ? kPdgPiP : kPdgPiM);
1478  p5code = kPdgPi0;
1479  }
1480  }
1481  else // unhandled
1482  {
1483  LOG("INukeUtils",pNOTICE) << "Pi production final state unable to be determined, picode, ptarg = " <<PDGLibrary::Instance()->Find(p1code)->GetName() << " " << PDGLibrary::Instance()->Find(ptarg)->GetName();
1485  exception.SetReason("PionProduction final state not determined");
1486  throw exception;
1487  return false;
1488  }
1489 
1490  } else if(p1code==kPdgProton||p1code==kPdgNeutron) //nucleon probes
1491  {
1492 
1493  double tote = p->Energy();
1494  double pMass = pLib->Find(2212)->Mass();
1495  double nMass = pLib->Find(2112)->Mass();
1496  double etapp2ppPi0 =
1497  utils::intranuke2015::CalculateEta(pMass,tote,pMass,pMass+pMass,pLib->Find(111)->Mass());
1498  double etapp2pnPip =
1499  utils::intranuke2015::CalculateEta(pLib->Find(p1code)->Mass(),tote,((p1code==kPdgProton)?pMass:nMass),
1500  pMass+nMass,pLib->Find(211)->Mass());
1501  double etapn2nnPip =
1502  utils::intranuke2015::CalculateEta(pMass,tote,nMass,nMass+nMass,pLib->Find(211)->Mass());
1503  double etapn2ppPim =
1504  utils::intranuke2015::CalculateEta(pMass,tote,nMass,pMass+pMass,pLib->Find(211)->Mass());
1505 
1506  if ((etapp2ppPi0<=0.)&&(etapp2pnPip<=0.)&&(etapn2nnPip<=0.)&&(etapn2ppPim<=0.)) { // below threshold
1507  LOG("INukeUtils",pNOTICE) << "PionProduction() called below threshold energy";
1509  exception.SetReason("PionProduction final state not possible - below threshold");
1510  throw exception;
1511  return false;
1512  }
1513 
1514  // calculate cross sections
1515  double xsecppPi0=0,xsecpnPiP=0,xsecnnPiP=0,xsecppPiM=0;
1516  if (etapp2ppPi0>0){
1517  xsecppPi0 = 4511*(1-.91*TMath::Exp(-TMath::Power((etapp2ppPi0-.705),2)));
1518  xsecppPi0 *= (1-TMath::Exp(-TMath::Power((.556*etapp2ppPi0),3.5)));
1519  xsecppPi0 *= (1-TMath::Exp(-56.897/(etapp2ppPi0*etapp2ppPi0)));
1520  xsecppPi0 = TMath::Max(0.,xsecppPi0);}
1521 
1522  if (etapp2pnPip>0){
1523  xsecpnPiP = 18840*(1-.808*TMath::Exp(-TMath::Power((etapp2pnPip-.371),2)));
1524  xsecpnPiP *= (1-TMath::Exp(-TMath::Power((.568*etapp2pnPip),3.2)));
1525  xsecpnPiP *= (1-TMath::Exp(-39.818/(etapp2pnPip*etapp2pnPip)));
1526  xsecpnPiP = TMath::Max(0.,xsecpnPiP);}
1527 
1528  if (etapn2nnPip>0){
1529  xsecnnPiP = 7670*(1-.479*TMath::Exp(-TMath::Power((etapn2nnPip-.947),2)));
1530  xsecnnPiP *= (1-TMath::Exp(-TMath::Power((.35*etapn2nnPip),3.2)));
1531  xsecnnPiP *= (1-TMath::Exp(-71.53/(etapn2nnPip*etapn2nnPip)));
1532  xsecnnPiP = TMath::Max(0.,xsecnnPiP);}
1533 
1534  if (etapn2ppPim>0){
1535  xsecppPiM = 7670*(1-.479*TMath::Exp(-TMath::Power((etapn2ppPim-.947),2)));
1536  xsecppPiM *= (1-TMath::Exp(-TMath::Power((.35*etapn2ppPim),3.2)));
1537  xsecppPiM *= (1-TMath::Exp(-71.53/(etapn2ppPim*etapn2ppPim)));
1538  xsecppPiM = TMath::Max(0.,xsecppPiM);}
1539 
1540  // double sigma11 = xsecppPi0;
1541  double sigma10 = TMath::Max(0.,xsecpnPiP - xsecppPi0); // Fundamental cross sections
1542  double sigma01 = TMath::Max(0.,xsecppPiM + xsecnnPiP - xsecppPi0);
1543 
1544  double xsecpnPi0 = .5*(sigma10 + sigma01);
1545  xsecpnPi0 = TMath::Max(xsecpnPi0,0.);
1546 
1547  LOG("INukeUtils",pDEBUG) << '\n' << "Cross section values: "<<'\n'
1548  << xsecppPi0 << " PP pi0" <<'\n'
1549  << xsecpnPiP << " PN pi+" <<'\n'
1550  << xsecnnPiP << " NN pi+" <<'\n'
1551  << xsecpnPi0 << " PN pi0";
1552 
1553  double xsecp=0,xsecn=0;
1554  switch (p1code) {
1555  case kPdgProton: xsecp=xsecppPi0+xsecpnPiP; xsecn=xsecppPiM+xsecnnPiP+xsecpnPi0; break;
1556  case kPdgNeutron: xsecp=xsecppPiM+xsecnnPiP+xsecpnPi0; xsecn=xsecppPi0+xsecpnPiP; break;
1557  default:
1558  LOG("INukeUtils",pWARN) << "InelasticHN cannot handle probe: "
1559  << PDGLibrary::Instance()->Find(p1code)->GetName();
1560  return false;
1561  break;
1562  }
1563 
1564  // Normalize cross sections by Z or (A-Z)
1565 
1566  xsecp *= RemnZ;
1567  xsecn *= RemnA-RemnZ;
1568 
1569  // determine target
1570 
1571  double rand = rnd->RndFsi().Rndm() * (xsecp + xsecn);
1572  if (rand < xsecp) // proton target
1573  { rand /= RemnZ; ptarg = true;}
1574  else // neutron target
1575  { rand -= xsecp; rand /= RemnA-RemnZ; ptarg = false;}
1576 
1577  if(p1code==kPdgProton) // Cross sections not explicitly given are calculated from isospin relations
1578  {
1579  if(ptarg)
1580  {
1581  if (rand<xsecppPi0) {p3code=kPdgProton; p4code=kPdgProton; p5code=kPdgPi0;}
1582  else {p3code=kPdgProton; p4code=kPdgNeutron; p5code=kPdgPiP;}
1583  }
1584  else
1585  {
1586  if (rand<xsecnnPiP) {p3code=kPdgNeutron; p4code=kPdgNeutron; p5code=kPdgPiP;}
1587  else if (rand<xsecppPiM+xsecnnPiP) {p3code=kPdgProton; p4code=kPdgProton; p5code=kPdgPiM;}
1588  else {p3code=kPdgProton; p4code=kPdgNeutron; p5code=kPdgPi0;}
1589  }
1590  }
1591  else if(p1code==kPdgNeutron)
1592  {
1593  if(ptarg)
1594  {
1595  if (rand<xsecnnPiP) {p3code=kPdgNeutron; p4code=kPdgNeutron; p5code=kPdgPiP;}
1596  else if (rand<xsecppPiM+xsecnnPiP) {p3code=kPdgProton; p4code=kPdgProton; p5code=kPdgPiM;}
1597  else {p3code=kPdgProton; p4code=kPdgNeutron; p5code=kPdgPi0;}
1598  }
1599  else
1600  {
1601  if (rand<xsecpnPiP) {p3code=kPdgNeutron; p4code=kPdgProton; p5code=kPdgPiM;}
1602  else {p3code=kPdgNeutron; p4code=kPdgNeutron; p5code=kPdgPi0;}
1603  }
1604  }
1605  }
1606  else
1607  {
1608  LOG("INukeUtils",pWARN)
1609  << "Unable to handle probe (=" << p1code << ") in InelasticHN()";
1610  return false;
1611  }
1612 
1613  // determine if reaction is allowed
1614  if ( RemnA < 1 )
1615  {
1616  LOG("INukeUtils",pNOTICE) << "PionProduction() failed : no nucleons to produce pions";
1617  return false;
1618  }
1619  else if ( RemnZ + ((pcode==kPdgProton || pcode==kPdgPiP)?1:0) - ((pcode==kPdgPiM)?1:0)
1620  < ((p3code==kPdgProton || p3code==kPdgPiP)?1:0) - ((p3code==kPdgPiM)?1:0)
1621  + ((p4code==kPdgProton || p4code==kPdgPiP)?1:0) - ((p4code==kPdgPiM)?1:0)
1622  + ((p5code==kPdgProton || p5code==kPdgPiP)?1:0) - ((p5code==kPdgPiM)?1:0) )
1623  {
1624  LOG("INukeUtils",pNOTICE) << "PionProduction() failed : too few protons in nucleus";
1626  exception.SetReason("PionProduction fails - too few protons available");
1627  throw exception;
1628  return false;
1629  }
1630 
1631  s1->SetPdgCode(p3code);
1632  s2->SetPdgCode(p4code);
1633  s3->SetPdgCode(p5code);
1634 
1636  ev,p,(ptarg?kPdgProton:kPdgNeutron),s1,s2,s3,DoFermi,FermiFac,FermiMomentum,Nuclmodel))
1637  {
1638  // okay, handle remnants and return true
1639  // assumes first particle is always the nucleon,
1640  // second can be either nucleon or pion
1641  // last always pion
1642  if (pcode==kPdgProton || pcode==kPdgPiP) RemnZ++;
1643  if (pcode==kPdgPiM) RemnZ--;
1644  if (pdg::IsPion(pcode)) RemnA--;
1645  if (pdg::IsProton(p3code)) RemnZ--;
1646  if (pdg::IsNeutronOrProton(p4code)) RemnA--;
1647  if (p4code==kPdgPiP || p4code==kPdgProton) RemnZ--;
1648  if (p4code==kPdgPiM) RemnZ++;
1649  if (p5code==kPdgPiP) RemnZ--;
1650  if (p5code==kPdgPiM) RemnZ++;
1651 
1652  LOG("INukeUtils",pDEBUG) << "Remnant (A,Z) = (" <<RemnA<<','<<RemnZ<<')';
1653 
1654  RemnP4 -= *s1->P4() + *s2->P4() + *s3->P4() - *p->P4();
1655  return true;
1656  }
1657  else {
1659  exception.SetReason("PionProduction final state not determined");
1660  throw exception;
1661  return false;
1662  }
1663 }
1664 //___________________________________________________________________________
1665 double genie::utils::intranuke2015::CalculateEta(double Minc, double nrg, double Mtarg,
1666  double Mtwopart, double Mpi)
1667 {
1668  //Aaron Meyer (1/20/2010)
1669 
1670  //Used to calculate the maximum kinematically allowed CM frame pion momentum
1671  // ke in MeV, eta normalized by pion mass
1672  // approximated by taking two ejected nucleons to be one particle of the same mass
1673  //For pion cross sections, in utils::intranuke2015::PionProduction
1674 
1675  //LOG("INukeUtils",pDEBUG) << "Input values: "<<Minc<<' '<<nrg<<' '<<Mtarg<<' '<<Mtwopart<<' '<<Mpi;
1676  double Scm = Minc*Minc + Mtarg*Mtarg + 2*Mtarg*nrg;
1677  double eta = 0;
1678  eta= TMath::Power(Scm,2) + TMath::Power(Mtwopart,4) + TMath::Power(Mpi,4);
1679  eta-= 2*TMath::Power(Mtwopart*Mpi,2);
1680  eta-= 2*Scm*TMath::Power(Mtwopart,2);
1681  eta-= 2*Scm*TMath::Power(Mpi,2);
1682  eta = TMath::Power(eta/Scm,1./2.);
1683  eta/= (2*Mpi);
1684 
1685  eta=TMath::Max(eta,0.);
1686  return eta;
1687 }
1688 //___________________________________________________________________________
1689 // Generic Phase Space Decay methods
1690 //___________________________________________________________________________
1692  GHepRecord* ev, GHepParticle* p, const PDGCodeList & pdgv,
1693  TLorentzVector &RemnP4, double NucRmvE, EINukeMode mode)
1694 {
1695 // General method decaying the input particle system 'pdgv' with available 4-p
1696 // given by 'pd'. The decayed system is used to populate the input TMCParticle
1697 // array starting from the slot 'offset'.
1698 //
1699  LOG("INukeUtils", pINFO) << "*** Performing a Phase Space Decay";
1700  assert(pdgv.size() > 1);
1701 
1702  LOG("INukeUtils",pINFO) << "probe mass: M = " << p->Mass();
1703 
1704  // Get the decay product masses & names
1705 
1706  ostringstream state_sstream;
1707  state_sstream << "( ";
1708  vector<int>::const_iterator pdg_iter;
1709  int i = 0;
1710  double * mass = new double[pdgv.size()];
1711  double mass_sum = 0;
1712  for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
1713  int pdgc = *pdg_iter;
1714  double m = PDGLibrary::Instance()->Find(pdgc)->Mass();
1715  string nm = PDGLibrary::Instance()->Find(pdgc)->GetName();
1716  mass[i++] = m;
1717  mass_sum += m;
1718  state_sstream << nm << " ";
1719  }
1720  state_sstream << ")";
1721 
1722  TLorentzVector * pd = p->GetP4(); // incident particle 4p
1723 
1724  bool is_nuc = pdg::IsNeutronOrProton(p->Pdg());
1725  bool is_kaon = p->Pdg()==kPdgKP || p->Pdg()==kPdgKM;
1726  //unused// bool is_pion = p->Pdg()==kPdgPiP || p->Pdg()==kPdgPi0 || p->Pdg()==kPdgPiM;
1727  // update available energy -> init (mass + kinetic) + sum of f/s masses
1728  // for pion only. Probe mass not available for nucleon, kaon
1729  double availE = pd->Energy() + mass_sum;
1730  if(is_nuc||is_kaon) availE -= p->Mass();
1731  pd->SetE(availE);
1732 
1733  LOG("INukeUtils",pNOTICE)
1734  << "size, mass_sum, availE, pd mass, energy = " << pdgv.size() << " "
1735  << mass_sum << " " << availE << " " << p->Mass() << " " << p->Energy() ;
1736 
1737  // compute the 4p transfer to the hadronic blob
1738  double dE = mass_sum;
1739  if(is_nuc||is_kaon) dE -= p->Mass();
1740  TLorentzVector premnsub(0,0,0,dE);
1741  RemnP4 -= premnsub;
1742 
1743  LOG("INukeUtils", pINFO)
1744  << "Final state = " << state_sstream.str() << " has N = " << pdgv.size()
1745  << " particles / total mass = " << mass_sum;
1746  LOG("INukeUtils", pINFO)
1747  << "Composite system p4 = " << utils::print::P4AsString(pd);
1748 
1749  // Set the decay
1750  TGenPhaseSpace GenPhaseSpace;
1751  bool permitted = GenPhaseSpace.SetDecay(*pd, pdgv.size(), mass);
1752  if(!permitted) {
1753  LOG("INukeUtils", pERROR)
1754  << " *** Phase space decay is not permitted \n"
1755  << " Total particle mass = " << mass_sum << "\n"
1756  << " Decaying system p4 = " << utils::print::P4AsString(pd);
1757 
1758  // clean-up and return
1759  RemnP4 += premnsub;
1760  delete [] mass;
1761  delete pd;
1762  return false;
1763  }
1764 
1765  // The decay is permitted - add the incident particle at the event record
1766  // and mark is as 'Nucleon Cluster Target' (used to be confusing 'Decayed State')
1767  p->SetStatus(kIStNucleonClusterTarget); //kIStDecayedState);
1769  ev->AddParticle(*p);
1770  // Get the maximum weight
1771  double wmax = -1;
1772  for(int k=0; k<200; k++) {
1773  double w = GenPhaseSpace.Generate();
1774  wmax = TMath::Max(wmax,w);
1775  }
1776  assert(wmax>0);
1777 
1778  LOG("INukeUtils", pINFO)
1779  << "Max phase space gen. weight @ current hadronic interaction: " << wmax;
1780 
1781  // Generate an unweighted decay
1782 
1783  RandomGen * rnd = RandomGen::Instance();
1784  wmax *= 1.2;
1785 
1786  bool accept_decay=false;
1787  unsigned int itry=0;
1788 
1789  while(!accept_decay)
1790  {
1791  itry++;
1792 
1793  if(itry>kMaxUnweightDecayIterations) {
1794  // report, clean-up and return
1795  LOG("INukeUtils", pNOTICE)
1796  << "Couldn't generate an unweighted phase space decay after "
1797  << itry << " attempts";
1798  delete [] mass;
1799  delete pd;
1800  return false;
1801  }
1802 
1803  double w = GenPhaseSpace.Generate();
1804  double gw = wmax * rnd->RndFsi().Rndm();
1805 
1806  if(w > wmax) {
1807  LOG("INukeUtils", pNOTICE)
1808  << "Decay weight = " << w << " > max decay weight = " << wmax;
1809  }
1810 
1811  LOG("INukeUtils", pNOTICE) << "Decay weight = " << w << " / R = " << gw;
1812  accept_decay = (gw<=w);
1813  }
1814 
1815  // Insert final state products into the event record
1816  // - the particles are added as daughters of the decayed state
1817  // - the particles are marked as final stable state (in hA mode)
1818  i=0;
1819  int mom = ev->ParticlePosition(p);
1820  LOG("INukeUtils", pNOTICE) << "mother index = " << mom;
1823 
1824  TLorentzVector * v4 = p->GetX4();
1825 
1826  double checkpx = p->Px();
1827  double checkpy = p->Py();
1828  double checkpz = p->Pz();
1829  double checkE = p->E();
1830 
1831  //LOG("INukeUtils", PNOTICE)
1832 
1833  for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
1834 
1835  //-- current PDG code
1836  int pdgc = *pdg_iter;
1837  bool isnuc = pdg::IsNeutronOrProton(pdgc);
1838 
1839  //-- get the 4-momentum of the i-th final state particle
1840  TLorentzVector * p4fin = GenPhaseSpace.GetDecay(i++);
1841 
1842  //-- intranuke no longer throws "bindinos" but adds all the energy
1843  // not going at a simulated f/s particle at a "hadronic blob"
1844  // representing the remnant system: do the binding energy subtraction
1845  // here & update the remnant hadronic system 4p
1846  double M = PDGLibrary::Instance()->Find(pdgc)->Mass();
1847  double En = p4fin->Energy();
1848 
1849  double KE = En-M;
1850 
1851  //double KE = En;
1852  //if(is_pion) KE -= M;
1853 
1854  double dE_leftover = TMath::Min(NucRmvE, KE);
1855  KE -= dE_leftover;
1856  En = KE+M;
1857  double pmag_old = p4fin->P();
1858  double pmag_new = TMath::Sqrt(TMath::Max(0.,En*En-M*M));
1859  double scale = pmag_new / pmag_old;
1860  double pxn = scale * p4fin->Px();
1861  double pyn = scale * p4fin->Py();
1862  double pzn = scale * p4fin->Pz();
1863 
1864  TLorentzVector p4n(pxn,pyn,pzn,En);
1865  // LOG("INukeUtils", pNOTICE) << "Px = " << pxn << " Py = " << pyn
1866  // << " Pz = " << pzn << " E = " << KE;
1867  checkpx -= pxn;
1868  checkpy -= pyn;
1869  checkpz -= pzn;
1870  checkE -= KE;
1871 
1872  if (mode==kIMdHA &&
1873  (pdgc==kPdgPiP || pdgc==kPdgPi0 || pdgc==kPdgPiM) )
1874  {
1875  if (p4n.Vect().Mag()>=0.001)
1876  {
1877  GHepParticle new_particle(pdgc, ist_pi, mom,-1,-1,-1, p4n, *v4);
1878  ev->AddParticle(new_particle);
1879  }
1880  else
1881  {
1882  // Momentum too small, assign a non-zero momentum to the particle
1883  // Conserve momentum with the remnant nucleus
1884 
1885  LOG("INukeUtils", pINFO)<<"Momentum too small; assigning 0.001 as new momentum";
1886 
1887  double phi = 2*kPi*rnd->RndFsi().Rndm();
1888  double omega = 2*rnd->RndFsi().Rndm();
1889  // throw number against solid angle for uniform distribution
1890 
1891  double E4n = TMath::Sqrt(0.001*0.001+M*M);
1892  p4n.SetPxPyPzE(0.001,0,0,E4n);
1893  p4n.Rotate(TMath::ACos(1-omega),TVector3(0,0,1));
1894  p4n.Rotate(phi,TVector3(1,0,0));
1895 
1896  RemnP4 -= (p4n - TLorentzVector(0,0,0,M));
1897 
1898  GHepParticle new_particle(pdgc, ist, mom,-1,-1,-1, p4n, *v4);
1899  ev->AddParticle(new_particle);
1900  }
1901  }
1902  else
1903  {
1904  GHepParticle new_particle(pdgc, ist, mom,-1,-1,-1, p4n, *v4);
1905 
1906  if(isnuc) new_particle.SetRemovalEnergy(0.);
1907  ev->AddParticle(new_particle);
1908  }
1909 
1910  double dpx = (1-scale)*p4fin->Px();
1911  double dpy = (1-scale)*p4fin->Py();
1912  double dpz = (1-scale)*p4fin->Pz();
1913  TLorentzVector premnadd(dpx,dpy,dpz,dE_leftover);
1914  RemnP4 += premnadd;
1915  }
1916  //LOG("INukeUtils", pNOTICE) << "TEST: " << p->Mass();
1917  LOG("INukeUtils", pNOTICE) << "check conservation: Px = " << checkpx << " Py = " << checkpy
1918  << " Pz = " << checkpz << " E = " << checkE;
1919 
1920  // Clean-up
1921  delete [] mass;
1922  delete pd;
1923  delete v4;
1924 
1925  return true;
1926 }
1927 
1929  const double &pionKineticEnergy,
1930  const double &density,
1931  const int &pionPDG,
1932  const double &protonFraction,
1933  const bool &isTableChosen
1934  )
1935 {
1936  // ------ OsetCrossSection init (only first time function is called) ------ //
1937  static INukeOset *iNukeOset = NULL;
1938 
1939  if (iNukeOset == NULL)
1940  {
1941  if (isTableChosen)
1942  {
1943  // set directory with data on first call
1944  static const std::string dataDir = (gSystem->Getenv("GINUKEHADRONDATA")) ?
1945  string(gSystem->Getenv("GINUKEHADRONDATA")) :
1946  string(gSystem->Getenv("GENIE")) +
1947  string("/data/evgen/intranuke/");
1948  // set file with Oset table on first call
1949  static const std::string dataFile = dataDir + "tot_xsec/"
1950  "intranuke-xsection-pi+N-Oset.dat";
1951  // initialize OsetCrossSection on first call
1952  iNukeOset = new INukeOsetTable (dataFile.c_str());
1953  }
1954  else iNukeOset = new INukeOsetFormula();
1955  }
1956  // ------ OsetCrossSection init (only first time function is called) ------ //
1957 
1958  // set up Oset class (assign pion Tk, nuclear density etc)
1959  iNukeOset->setupOset (density, pionKineticEnergy, pionPDG, protonFraction);
1960 
1961  return iNukeOset->getTotalCrossSection();
1962 
1963 }
1964 
const int kPdgP33m1232_DeltaPP
Definition: PDGCodes.h:88
static const double m
Definition: Units.h:79
double MeanFreePath_Delta(int pdgc, const TLorentzVector &x4, const TLorentzVector &p4, double A)
Mean free path (Delta++ test)
An exception thrown by SimulateHadronState for kinematics problems. TwoBodyCollision/Kinematics used ...
void SetFirstMother(int m)
Definition: GHepParticle.h:131
bool IsPion(int pdgc)
Definition: PDGUtils.cxx:296
Basic constants.
virtual int ParticlePosition(int pdg, GHepStatus_t i, int start=0) const
Definition: GHepRecord.cxx:181
TLorentzVector * GetX4(void) const
TRandom3 & RndFsi(void) const
rnd number generator used by intranuclear cascade monte carlos
Definition: RandomGen.h:60
static INukeNucleonCorr * getInstance()
get single instance of INukeNucleonCorr; create if necessary
#include "Numerical/GSFunc.h"
Definition: AlgCmp.h:26
#define pERROR
Definition: Messenger.h:50
static INukeHadroData2015 * Instance(void)
double E(void) const
Get energy.
Definition: GHepParticle.h:90
static RandomGen * Instance()
Access instance.
Definition: RandomGen.cxx:79
double Density(double r, int A, double ring=0.)
std::string string
Definition: nybbler.cc:12
Table-based implementation of Oset model.
enum genie::EGHepStatus GHepStatus_t
static const double MeV
Definition: Units.h:130
bool TwoBodyKinematics(double M3, double M4, TLorentzVector tP1L, TLorentzVector tP2L, TLorentzVector &tP3L, TLorentzVector &tP4L, double C3CM, TLorentzVector &RemnP4, double bindE=0)
bool ThreeBodyKinematics(GHepRecord *ev, GHepParticle *p, int tcode, GHepParticle *s1, GHepParticle *s2, GHepParticle *s3, bool DoFermi=false, double FermiFac=0, double FermiMomentum=0, const NuclearModelI *Nuclmodel=(const NuclearModelI *) 0)
string P4AsString(const TLorentzVector *p)
Definition: PrintUtils.cxx:34
static const unsigned int kMaxUnweightDecayIterations
Definition: Controls.h:61
Pure abstract base class. Defines the NuclearModelI interface to be implemented by any physics model ...
Definition: NuclearModelI.h:42
double Mass(Resonance_t res)
resonance mass (GeV)
EINukeMode
Definition: INukeMode.h:29
void SetMomentum(const TLorentzVector &p4)
double Mass(void) const
Mass that corresponds to the PDG code.
double MeanFreePath(int pdgc, const TLorentzVector &x4, const TLorentzVector &p4, double A, double Z, double nRpi=0.5, double nRnuc=1.0, const bool useOset=false, const bool altOset=false, const bool xsecNNCorr=false, string INukeMode="XX2015")
Mean free path (pions, nucleons)
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition: RandomGen.h:30
double Pz(void) const
Get Pz.
Definition: GHepParticle.h:89
double Energy(void) const
Get energy.
Definition: GHepParticle.h:91
bool PhaseSpaceDecay(GHepRecord *ev, GHepParticle *p, const PDGCodeList &pdgv, TLorentzVector &RemnP4, double NucRmvE, EINukeMode mode=kIMdHA)
general phase space decay method
A list of PDG codes.
Definition: PDGCodeList.h:33
double Px(void) const
Get Px.
Definition: GHepParticle.h:87
int LastMother(void) const
Definition: GHepParticle.h:68
int Pdg(void) const
Definition: GHepParticle.h:64
int FirstMother(void) const
Definition: GHepParticle.h:67
string Name(void) const
Name that corresponds to the PDG code.
void PreEquilibrium(GHepRecord *ev, GHepParticle *p, int &RemnA, int &RemnZ, TLorentzVector &RemnP4, bool DoFermi, double FermiFac, const NuclearModelI *Nuclmodel, double NucRmvE, EINukeMode mode=kIMdHN)
const int kPdgCompNuclCluster
Definition: PDGCodes.h:188
void SetPosition(const TLorentzVector &v4)
double getTotalCrossSection() const
return total = (qel+cex+abs) cross section
Definition: INukeOset.h:35
bool IsProton(int pdgc)
Definition: PDGUtils.cxx:306
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
Definition: Messenger.h:87
intermediate_table::const_iterator const_iterator
const int kPdgKM
Definition: PDGCodes.h:147
const int kPdgGamma
Definition: PDGCodes.h:163
TLorentzVector * GetP4(void) const
A Neutrino Interaction Target. Is a transparent encapsulation of quite different physical systems suc...
Definition: Target.h:41
double z
const int kPdgKP
Definition: PDGCodes.h:146
bool TwoBodyKinematics(double M3, double M4, TLorentzVector tP1L, TLorentzVector tP2L, TLorentzVector &tP3L, TLorentzVector &tP4L, double C3CM, TLorentzVector &RemnP4, double bindE=0)
Definition: INukeUtils.cxx:753
const int kPdgPiP
Definition: PDGCodes.h:132
void StepParticle(GHepParticle *p, double step, double nuclear_radius=-1.)
Step particle.
const int kPdgPi0
Definition: PDGCodes.h:134
bool PionProduction(GHepRecord *ev, GHepParticle *p, GHepParticle *s1, GHepParticle *s2, GHepParticle *s3, int &RemnA, int &RemnZ, TLorentzVector &RemnP4, bool DoFermi, double FermiFac, double FermiMomentum, const NuclearModelI *Nuclmodel)
virtual GHepParticle * TargetNucleus(void) const
Definition: GHepRecord.cxx:323
#define pINFO
Definition: Messenger.h:53
Misc GENIE control constants.
double ProbSurvival(int pdgc, const TLorentzVector &x4, const TLorentzVector &p4, double A, double Z, double mfp_scale_factor=1.0, double nRpi=0.5, double nRnuc=1.0, double NR=3, double R0=1.4)
Hadron survival probability.
#define pWARN
Definition: Messenger.h:51
virtual void setupOset(const double &density, const double &pionTk, const int &pionPDG, const double &protonFraction)=0
use to set up Oset class (assign pion Tk, nuclear density etc)
double sigmaTotalOset(const double &pionKineticEnergy, const double &density, const int &pionPDG, const double &protonFraction, const bool &isTableChosen=true)
double CalculateEta(double Minc, double ke, double Mtarg, double Mtwopart, double Mpi)
p
Definition: test.py:228
void SetRemovalEnergy(double Erm)
static const double A
Definition: Units.h:82
double KinE(bool mass_from_pdg=false) const
Get kinetic energy.
static PDGLibrary * Instance(void)
Definition: PDGLibrary.cxx:45
double Dist2Exit(const TLorentzVector &x4, const TLorentzVector &p4, double A, double NR=3, double R0=1.4)
Distance to exit.
void SetLastMother(int m)
Definition: GHepParticle.h:132
Singleton class to load & serve a TDatabasePDG.
Definition: PDGLibrary.h:27
TLorentzVector * X4(void) const
Definition: GHepParticle.h:80
void Equilibrium(GHepRecord *ev, GHepParticle *p, int &RemnA, int &RemnZ, TLorentzVector &RemnP4, bool DoFermi, double FermiFac, const NuclearModelI *Nuclmodel, double NucRmvE, EINukeMode mode=kIMdHN)
void SetStatus(GHepStatus_t s)
Definition: GHepParticle.h:125
virtual TVector3 Momentum3(void) const
Definition: NuclearModelI.h:59
bool IsNeutronOrProton(int pdgc)
Definition: PDGUtils.cxx:321
TParticlePDG * Find(int pdgc)
Definition: PDGLibrary.cxx:63
const int kPdgPiM
Definition: PDGCodes.h:133
virtual bool GenerateNucleon(const Target &) const =0
static const double fm2
Definition: Units.h:84
virtual void AddParticle(const GHepParticle &p)
Definition: GHepRecord.cxx:526
double Dist2ExitMFP(int pdgc, const TLorentzVector &x4, const TLorentzVector &p4, double A, double Z, double NR=3, double R0=1.4)
Distance to exit.
const int kPdgProton
Definition: PDGCodes.h:62
bool TwoBodyCollision(GHepRecord *ev, int pcode, int tcode, int scode, int s2code, double C3CM, GHepParticle *p, GHepParticle *t, int &RemnA, int &RemnZ, TLorentzVector &RemnP4, EINukeMode mode=kIMdHA)
Intranuke utility functions.
#define pNOTICE
Definition: Messenger.h:52
string X4AsString(const TLorentzVector *x)
Definition: PrintUtils.cxx:64
TLorentzVector * P4(void) const
Definition: GHepParticle.h:79
static const double mb
Definition: Units.h:87
const int kPdgNeutron
Definition: PDGCodes.h:64
GENIE&#39;s GHEP MC event record.
Definition: GHepRecord.h:46
static const double kPi
Definition: Constants.h:38
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils...
STDHEP-like event record entry that can fit a particle or a nucleus.
Definition: GHepParticle.h:40
string Vec3AsString(const TVector3 *vec)
Definition: PrintUtils.cxx:87
Root of GENIE utility namespaces.
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
void push_back(int pdg_code)
Definition: PDGCodeList.cxx:67
#define pDEBUG
Definition: Messenger.h:54
void SetPdgCode(int c)
double Py(void) const
Get Py.
Definition: GHepParticle.h:88
Formula-based implementation of Oset model.