HAIntranuke2014.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: Steve Dytman <dytman+@pitt.edu>, Pittsburgh Univ.
8  Aaron Meyer <asm58@pitt.edu>, Pittsburgh Univ.
9  Alex Bell, Pittsburgh Univ.
10  Hugh Gallagher <gallag@minos.phy.tufts.edu>, Tufts Univ.
11  Costas Andreopoulos <costas.andreopoulos \at stfc.ac.uk>, Rutherford Lab.
12  September 20, 2005
13 
14  For the class documentation see the corresponding header file.
15 
16  Important revisions after version 2.0.0 :
17  @ Nov 30, 2007 - SD
18  Changed the hadron tracking algorithm to take into account the radial
19  nuclear density dependence. Using the somewhat empirical approach of
20  increasing the nuclear radius by a const (tunable) number times the tracked
21  particle's de Broglie wavelength as this helps getting the hadron+nucleus
22  cross sections right.
23  @ Mar 08, 2008 - CA
24  Fixed code retrieving the remnant nucleus which stopped working as soon as
25  simulation of nuclear de-excitation started pushing photons in the target
26  nucleus daughter list.
27  @ Jun 20, 2008 - CA
28  Fix a mem leak: The (clone of the) GHepParticle being re-scattered was not
29  deleted after it was added at the GHEP event record.
30  @ Jul 15, 2010 - AM
31  Major overhaul of the function of each interaction type. Absorption fates
32  changed to allow more than 6 particles at a time (up to 85 now). PiPro fates
33  now allow the pion to rescatter inside the nucleus, will be changed at a
34  later date. HAIntranuke class is now defined as derived from virtual class.
35  Intranuke.
36  @ Oct 10, 2011 - SD
37  Changes to keep reweighting alive. Add exception handling in ElasHA, InelasticHA,
38  and Inelastic.
39  @ Jan 24, 2012 - SD
40  Add option of doing K+.
41  @ Jan 9, 2015 - SD, NG, TG
42  Added 2014 version of INTRANUKE codes (new class) for independent development.
43  @ Aug 30, 2016 - SD
44  Memory leak fixes - Igor.
45 */
46 //____________________________________________________________________________
47 
48 #include <cstdlib>
49 #include <sstream>
50 #include <exception>
51 
52 #include <TMath.h>
53 
55 #include "Algorithm/AlgFactory.h"
56 #include "Conventions/GBuild.h"
57 #include "Conventions/Constants.h"
58 #include "Conventions/Controls.h"
60 #include "GHEP/GHepFlags.h"
61 #include "GHEP/GHepStatus.h"
62 #include "GHEP/GHepRecord.h"
63 #include "GHEP/GHepParticle.h"
70 #include "Messenger/Messenger.h"
71 #include "Numerical/RandomGen.h"
72 #include "Numerical/Spline.h"
73 #include "PDG/PDGLibrary.h"
74 #include "PDG/PDGCodes.h"
75 #include "PDG/PDGCodeList.h"
76 #include "PDG/PDGUtils.h"
77 #include "Utils/PrintUtils.h"
78 #include "Utils/NuclearUtils.h"
79 
80 using std::ostringstream;
81 
82 using namespace genie;
83 using namespace genie::utils;
84 using namespace genie::utils::intranuke2014;
85 using namespace genie::constants;
86 using namespace genie::controls;
87 
88 //___________________________________________________________________________
89 //___________________________________________________________________________
90 // Methods specific to INTRANUKE's HA-mode
91 //___________________________________________________________________________
92 //___________________________________________________________________________
94 Intranuke2014("genie::HAIntranuke2014")
95 {
96 
97 }
98 //___________________________________________________________________________
100 Intranuke2014("genie::HAIntranuke2014",config)
101 {
102 
103 }
104 //___________________________________________________________________________
106 {
107 
108 }
109 //___________________________________________________________________________
111 {
112  LOG("HAIntranuke2014", pNOTICE)
113  << "************ Running hA2014 MODE INTRANUKE ************";
114  GHepParticle * nuclearTarget = evrec -> TargetNucleus();
115  nuclA = nuclearTarget -> A();
116 
118 
119  LOG("HAIntranuke2014", pINFO) << "Done with this event";
120 }
121 //___________________________________________________________________________
123  GHepRecord* ev, GHepParticle* p) const
124 {
125 // Simulate a hadron interaction for the input particle p in HA mode
126 //
127  // check inputs
128  if(!p || !ev) {
129  LOG("HAIntranuke2014", pERROR) << "** Null input!";
130  return;
131  }
132 
133  // get particle code and check whether this particle can be handled
134  int pdgc = p->Pdg();
135  bool is_gamma = (pdgc==kPdgGamma);
136  bool is_pion = (pdgc==kPdgPiP || pdgc==kPdgPiM || pdgc==kPdgPi0);
137  bool is_kaon = (pdgc==kPdgKP || pdgc==kPdgKM);
138  bool is_baryon = (pdgc==kPdgProton || pdgc==kPdgNeutron);
139  bool is_handled = (is_baryon || is_pion || is_kaon || is_gamma);
140  if(!is_handled) {
141  LOG("HAIntranuke2014", pERROR) << "** Can not handle particle: " << p->Name();
142  return;
143  }
144 
145  // select a fate for the input particle
146  INukeFateHA_t fate = this->HadronFateHA(p);
147 
148  // store the fate
149  ev->Particle(p->FirstMother())->SetRescatterCode((int)fate);
150 
151  if(fate == kIHAFtUndefined) {
152  LOG("HAIntranuke2014", pERROR) << "** Couldn't select a fate";
154  ev->AddParticle(*p);
155  return;
156  }
157  LOG("HAIntranuke2014", pNOTICE)
158  << "Selected "<< p->Name() << " fate: "<< INukeHadroFates::AsString(fate);
159 
160  // try to generate kinematics - repeat till is done (should seldom need >2)
161  fNumIterations = 0;
163 }
164 //___________________________________________________________________________
166  GHepRecord* ev, GHepParticle* p) const
167 {
168  // get stored fate
169  INukeFateHA_t fate = (INukeFateHA_t)
170  ev->Particle(p->FirstMother())->RescatterCode();
171 
172  LOG("HAIntranuke2014", pINFO)
173  << "Generating kinematics for " << p->Name()
174  << " fate: "<< INukeHadroFates::AsString(fate);
175 
176  // try to generate kinematics for the selected fate
177 
178  try
179  {
180  fNumIterations++;
181  if (fate == kIHAFtElas)
182  {
183  this->ElasHA(ev,p,fate);
184  }
185  else
186  if (fate == kIHAFtInelas || fate == kIHAFtCEx)
187  {
188  this->InelasticHA(ev,p,fate);
189  }
190  else if (fate == kIHAFtAbs || fate == kIHAFtPiProd)
191  {
192  this->Inelastic(ev,p,fate);
193  }
194  }
196  {
197  LOG("HAIntranuke2014", pNOTICE)
198  << exception;
199  if(fNumIterations <= 100) {
200  LOG("HAIntranuke2014", pNOTICE)
201  << "Failed attempt to generate kinematics for "
202  << p->Name() << " fate: " << INukeHadroFates::AsString(fate)
203  << " - After " << fNumIterations << " tries, still retrying...";
205  } else {
206  LOG("HAIntranuke2014", pNOTICE)
207  << "Failed attempt to generate kinematics for "
208  << p->Name() << " fate: " << INukeHadroFates::AsString(fate)
209  << " after " << fNumIterations-1
210  << " attempts. Trying a new fate...";
211  this->SimulateHadronicFinalState(ev,p);
212  }
213  }
214 }
215 //___________________________________________________________________________
217 {
218 // Select a hadron fate in HA mode
219 //
220  RandomGen * rnd = RandomGen::Instance();
221 
222  // get pdgc code & kinetic energy in MeV
223  int pdgc = p->Pdg();
224  double ke = p->KinE() / units::MeV;
225 
226  LOG("HAIntranuke2014", pINFO)
227  << "Selecting hA fate for " << p->Name() << " with KE = " << ke << " MeV";
228 
229  // try to generate a hadron fate
230  unsigned int iter = 0;
231  while(iter++ < kRjMaxIterations) {
232 
233  // handle pions
234  //
235  if (pdgc==kPdgPiP || pdgc==kPdgPiM || pdgc==kPdgPi0) {
236 
237  double frac_cex = fHadroData2014->FracADep(pdgc, kIHAFtCEx, ke, nuclA);
238  double frac_elas = fHadroData2014->FracADep(pdgc, kIHAFtElas, ke, nuclA);
239  double frac_inel = fHadroData2014->FracADep(pdgc, kIHAFtInelas, ke, nuclA);
240  double frac_abs = fHadroData2014->FracADep(pdgc, kIHAFtAbs, ke, nuclA);
241  double frac_piprod = fHadroData2014->FracADep(pdgc, kIHAFtPiProd, ke, nuclA);
242  LOG("HAIntranuke2014", pDEBUG)
243  << "\n frac{" << INukeHadroFates::AsString(kIHAFtCEx) << "} = " << frac_cex
244  << "\n frac{" << INukeHadroFates::AsString(kIHAFtElas) << "} = " << frac_elas
245  << "\n frac{" << INukeHadroFates::AsString(kIHAFtInelas) << "} = " << frac_inel
246  << "\n frac{" << INukeHadroFates::AsString(kIHAFtAbs) << "} = " << frac_abs
247  << "\n frac{" << INukeHadroFates::AsString(kIHAFtPiProd) << "} = " << frac_piprod;
248 
249  // compute total fraction (can be <1 if fates have been switched off)
250  double tf = frac_cex +
251  frac_elas +
252  frac_inel +
253  frac_abs +
254  frac_piprod;
255 
256  double r = tf * rnd->RndFsi().Rndm();
257 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
258  LOG("HAIntranuke2014", pDEBUG) << "r = " << r << " (max = " << tf << ")";
259 #endif
260  double cf=0; // current fraction
261  if(r < (cf += frac_cex )) return kIHAFtCEx; // cex
262  if(r < (cf += frac_elas )) return kIHAFtElas; // elas
263  if(r < (cf += frac_inel )) return kIHAFtInelas; // inelas
264  if(r < (cf += frac_abs )) return kIHAFtAbs; // abs
265  if(r < (cf += frac_piprod )) return kIHAFtPiProd; // pi prod
266 
267  LOG("HAIntranuke2014", pWARN)
268  << "No selection after going through all fates! "
269  << "Total fraction = " << tf << " (r = " << r << ")";
270  }
271 
272  // handle nucleons
273  else if (pdgc==kPdgProton || pdgc==kPdgNeutron) {
274  double frac_cex = fHadroData2014->FracAIndep(pdgc, kIHAFtCEx, ke);
275  double frac_elas = fHadroData2014->FracAIndep(pdgc, kIHAFtElas, ke);
276  double frac_inel = fHadroData2014->FracAIndep(pdgc, kIHAFtInelas, ke);
277  double frac_abs = fHadroData2014->FracAIndep(pdgc, kIHAFtAbs, ke);
278  double frac_pipro = fHadroData2014->FracAIndep(pdgc, kIHAFtPiProd, ke);
279 
280  LOG("HAIntranuke2014", pDEBUG)
281  << "\n frac{" << INukeHadroFates::AsString(kIHAFtCEx) << "} = " << frac_cex
282  << "\n frac{" << INukeHadroFates::AsString(kIHAFtElas) << "} = " << frac_elas
283  << "\n frac{" << INukeHadroFates::AsString(kIHAFtInelas) << "} = " << frac_inel
284  << "\n frac{" << INukeHadroFates::AsString(kIHAFtAbs) << "} = " << frac_abs
285  << "\n frac{" << INukeHadroFates::AsString(kIHAFtPiProd) << "} = " << frac_pipro;
286 
287  // compute total fraction (can be <1 if fates have been switched off)
288  double tf = frac_cex +
289  frac_elas +
290  frac_inel +
291  frac_abs +
292  frac_pipro;
293 
294  double r = tf * rnd->RndFsi().Rndm();
295 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
296  LOG("HAIntranuke2014", pDEBUG) << "r = " << r << " (max = " << tf << ")";
297 #endif
298  double cf=0; // current fraction
299  if(r < (cf += frac_cex )) return kIHAFtCEx; // cex
300  if(r < (cf += frac_elas )) return kIHAFtElas; // elas
301  if(r < (cf += frac_inel )) return kIHAFtInelas; // inelas
302  if(r < (cf += frac_abs )) return kIHAFtAbs; // abs
303  if(r < (cf += frac_pipro )) return kIHAFtPiProd; // pi prod
304 
305  LOG("HAIntranuke2014", pWARN)
306  << "No selection after going through all fates! "
307  << "Total fraction = " << tf << " (r = " << r << ")";
308  }
309  // handle kaons
310  else if (pdgc==kPdgKP || pdgc==kPdgKM) {
311  double frac_inel = fHadroData2014->FracAIndep(pdgc, kIHAFtInelas, ke);
312  double frac_abs = fHadroData2014->FracAIndep(pdgc, kIHAFtAbs, ke);
313 
314  LOG("HAIntranuke2014", pDEBUG)
315  << "\n frac{" << INukeHadroFates::AsString(kIHAFtInelas) << "} = " << frac_inel
316  << "\n frac{" << INukeHadroFates::AsString(kIHAFtAbs) << "} = " << frac_abs;
317  // compute total fraction (can be <1 if fates have been switched off)
318  double tf = frac_inel +
319  frac_abs;
320  double r = tf * rnd->RndFsi().Rndm();
321 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
322  LOG("HAIntranuke2014", pDEBUG) << "r = " << r << " (max = " << tf << ")";
323 #endif
324  double cf=0; // current fraction
325  if(r < (cf += frac_inel )) return kIHAFtInelas; // inelas
326  if(r < (cf += frac_abs )) return kIHAFtAbs; // abs
327  }
328  }//iterations
329 
330  return kIHAFtUndefined;
331 }
332 //___________________________________________________________________________
333 double HAIntranuke2014::PiBounce(void) const
334 {
335 // [adapted from neugen3 intranuke_bounce.F]
336 // [is a fortran stub / difficult to understand - needs to be improved]
337 //
338 // Generates theta in radians for elastic pion-nucleus scattering/
339 // Lookup table is based on Fig 17 of Freedman, Miller and Henley, Nucl.Phys.
340 // A389, 457 (1982)
341 //
342  const int nprob = 25;
343  double dintor = 0.0174533;
344  double denom = 47979.453;
345  double rprob[nprob] = {
346  5000., 4200., 3000., 2600., 2100., 1800., 1200., 750., 500., 230., 120.,
347  35., 9., 3., 11., 18., 29., 27., 20., 14., 10., 6., 2., 0.14, 0.19 };
348 
349  double angles[nprob];
350  for(int i=0; i<nprob; i++) angles[i] = 2.5*i;
351 
352  RandomGen * rnd = RandomGen::Instance();
353  double r = rnd->RndFsi().Rndm();
354 
355  double xsum = 0.;
356  double theta = 0.;
357  double binl = 0.;
358  double binh = 0.;
359  int tj = 0;
360  for(int i=0; i<60; i++) {
361  theta = i+0.5;
362  for(int j=0; j < nprob-1; j++) {
363  binl = angles[j];
364  binh = angles[j+1];
365  tj=j;
366  if(binl<=theta && binh>=theta) break;
367  tj=0;
368  }//j
369  int itj = tj;
370  double tfract = (theta-binl)/2.5;
371  double delp = rprob[itj+1] - rprob[itj];
372  xsum += (rprob[itj] + tfract*delp)/denom;
373  if(xsum>r) break;
374  theta = 0.;
375  }//i
376 
377  theta *= dintor;
378 
379  LOG("HAIntranuke2014", pNOTICE)
380  << "Generated pi+A elastic scattering angle = " << theta << " radians";
381 
382  return theta;
383 }
384 //___________________________________________________________________________
385 double HAIntranuke2014::PnBounce(void) const
386 {
387 // [adapted from neugen3 intranuke_pnbounce.F]
388 // [is a fortran stub / difficult to understand - needs to be improved]
389 //
390 // Generates theta in radians for elastic nucleon-nucleus scattering.
391 // Use 800 MeV p+O16 as template in same (highly simplified) spirit as pi+A
392 // from table in Adams et al., PRL 1979. Guess value at 0-2 deg based on Ni
393 // data.
394 //
395  const int nprob = 20;
396  double dintor = 0.0174533;
397  double denom = 11967.0;
398  double rprob[nprob] = {
399  2400., 2350., 2200., 2000., 1728., 1261., 713., 312., 106., 35.,
400  6., 5., 10., 12., 11., 9., 6., 1., 1., 1. };
401 
402  double angles[nprob];
403  for(int i=0; i<nprob; i++) angles[i] = 1.0*i;
404 
405  RandomGen * rnd = RandomGen::Instance();
406  double r = rnd->RndFsi().Rndm();
407 
408  double xsum = 0.;
409  double theta = 0.;
410  double binl = 0.;
411  double binh = 0.;
412  int tj = 0;
413  for(int i=0; i< nprob; i++) {
414  theta = i+0.5;
415  for(int j=0; j < nprob-1; j++) {
416  binl = angles[j];
417  binh = angles[j+1];
418  tj=j;
419  if(binl<=theta && binh>=theta) break;
420  tj=0;
421  }//j
422  int itj = tj;
423  double tfract = (theta-binl)/2.5;
424  double delp = rprob[itj+1] - rprob[itj];
425  xsum += (rprob[itj] + tfract*delp)/denom;
426  if(xsum>r) break;
427  theta = 0.;
428  }//i
429 
430  theta *= dintor;
431 
432  LOG("HAIntranuke2014", pNOTICE)
433  << "Generated N+A elastic scattering angle = " << theta << " radians";
434 
435  return theta;
436 }
437 //___________________________________________________________________________
439  GHepRecord* ev, GHepParticle* p, INukeFateHA_t fate) const
440 {
441  // scatters particle within nucleus, copy of hN code meant to run only once
442  // in hA mode
443 
444 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
445  LOG("HAIntranuke2014", pDEBUG)
446  << "ElasHA() is invoked for a : " << p->Name()
447  << " whose fate is : " << INukeHadroFates::AsString(fate);
448 #endif
449 
450  if(fate!=kIHAFtElas)
451  {
452  LOG("HAIntranuke2014", pWARN)
453  << "ElasHA() cannot handle fate: " << INukeHadroFates::AsString(fate);
454  return;
455  }
456 
457  // check remnants
458  if(fRemnA<0 || fRemnZ<0) // best to stop it here and not try again.
459  {
460  LOG("HAIntranuke2014", pWARN) << "Invalid Nucleus! : (A,Z) = ("<<fRemnA<<','<<fRemnZ<<')';
462  ev->AddParticle(*p);
463  return;
464  }
465 
466  // vars for incoming particle, target, and scattered pdg codes
467  int pcode = p->Pdg();
468  double Mp = p->Mass();
469  double Mt = 0.;
470  if (ev->TargetNucleus()->A()==fRemnA)
471  { Mt = PDGLibrary::Instance()->Find(ev->TargetNucleus()->Pdg())->Mass(); }
472  else
473  {
474  Mt = fRemnP4.M();
475  }
476  TLorentzVector t4PpL = *p->P4();
477  TLorentzVector t4PtL = fRemnP4;
478  double C3CM = 0.0;
479 
480  // calculate scattering angle
481  if(pcode==kPdgNeutron||pcode==kPdgProton) C3CM = TMath::Cos(this->PnBounce());
482  else C3CM = TMath::Cos(this->PiBounce());
483 
484  // calculate final 4 momentum of probe
485  TLorentzVector t4P3L, t4P4L;
486 
487  if (!utils::intranuke2014::TwoBodyKinematics(Mp,Mt,t4PpL,t4PtL,t4P3L,t4P4L,C3CM,fRemnP4))
488  {
489  LOG("HAIntranuke2014", pNOTICE) << "ElasHA() failed";
491  exception.SetReason("TwoBodyKinematics failed in ElasHA");
492  throw exception;
493  }
494 
495  // Update probe particle
496  p->SetMomentum(t4P3L);
498 
499  // Update Remnant nucleus
500  fRemnP4 = t4P4L;
501  LOG("HAIntranuke2014",pINFO)
502  << "C3cm = " << C3CM;
503  LOG("HAIntranuke2014",pINFO)
504  << "|p3| = " << t4P3L.Vect().Mag() << ", E3 = " << t4P3L.E() << ",Mp = " << Mp;
505  LOG("HAIntranuke2014",pINFO)
506  << "|p4| = " << fRemnP4.Vect().Mag() << ", E4 = " << fRemnP4.E() << ",Mt = " << Mt;
507 
508  ev->AddParticle(*p);
509 
510 }
511 //___________________________________________________________________________
513  GHepRecord* ev, GHepParticle* p, INukeFateHA_t fate) const
514 {
515  // charge exch and inelastic - scatters particle within nucleus, hA version
516  // each are treated as quasielastic, particle scatters off single nucleon
517 
518 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
519  LOG("HAIntranuke2014", pDEBUG)
520  << "InelasticHA() is invoked for a : " << p->Name()
521  << " whose fate is : " << INukeHadroFates::AsString(fate);
522 #endif
523  if(ev->Probe() ) {
524  LOG("HAIntranuke2014", pINFO) << " probe KE = " << ev->Probe()->KinE();
525  }
526  if(fate!=kIHAFtCEx && fate!=kIHAFtInelas)
527  {
528  LOG("HAIntranuke2014", pWARN)
529  << "InelasticHA() cannot handle fate: " << INukeHadroFates::AsString(fate);
530  return;
531  }
532 
533  // Random number generator
534  RandomGen * rnd = RandomGen::Instance();
535 
536  // vars for incoming particle, target, and scattered pdg codes
537  int pcode = p->Pdg();
538  int tcode, scode, s2code;
539  double ppcnt = (double) fRemnZ / (double) fRemnA; // % of protons
540 
541  // Select a hadron fate in HN mode
542  INukeFateHN_t h_fate;
543  if (fate == kIHAFtCEx) h_fate = kIHNFtCEx;
544  else h_fate = kIHNFtElas;
545 
546  // Select a target randomly, weighted to #
547  // -- Unless, of course, the fate is CEx,
548  // -- in which case the target may be deterministic
549  // Also assign scattered particle code
550  if(fate==kIHAFtCEx)
551  {
552  if(pcode==kPdgPiP) {tcode = kPdgNeutron; scode = kPdgPi0; s2code = kPdgProton;}
553  else if(pcode==kPdgPiM) {tcode = kPdgProton; scode = kPdgPi0; s2code = kPdgNeutron;}
554  else if(pcode==kPdgPi0)
555  {
556  // for pi0
557  tcode = (rnd->RndFsi().Rndm()<=ppcnt)?(kPdgProton) :(kPdgNeutron);
558  scode = (tcode == kPdgProton) ?(kPdgPiP) :(kPdgPiM);
559  s2code = (tcode == kPdgProton) ?(kPdgNeutron):(kPdgProton);
560  }
561  else if(pcode==kPdgProton) {tcode = kPdgNeutron; scode = kPdgNeutron; s2code = kPdgProton;}
562  else if(pcode==kPdgNeutron){tcode = kPdgProton; scode = kPdgProton; s2code = kPdgNeutron;}
563  else
564  { LOG("HAIntranuke2014", pWARN) << "InelasticHA() cannot handle fate: "
566  << " for particle " << p->Name();
567  return;
568  }
569  }
570  else
571  {
572  tcode = (rnd->RndFsi().Rndm()<=ppcnt)?(kPdgProton):(kPdgNeutron);
573  // if(pcode == kPdgKP || pcode == kPdgKM) tcode = kPdgProton;
574  scode = pcode;
575  s2code = tcode;
576  }
577 
578  // check remnants
579  if ( fRemnA < 1 ) //we've blown nucleus apart, no need to retry anything - exit
580  {
581  LOG("HAIntranuke2014",pNOTICE) << "InelasticHA() stops : not enough nucleons";
583  ev->AddParticle(*p);
584  return;
585  }
586  else if ( fRemnZ + (((pcode==kPdgProton)||(pcode==kPdgPiP))?1:0) - (pcode==kPdgPiM?1:0)
587  < ((( scode==kPdgProton)||( scode==kPdgPiP)) ?1:0) - (scode ==kPdgPiM ?1:0)
588  + (((s2code==kPdgProton)||(s2code==kPdgPiP)) ?1:0) - (s2code==kPdgPiM ?1:0) )
589  {
590  LOG("HAIntranuke2014",pWARN) << "InelasticHA() failed : too few protons in nucleus";
592  ev->AddParticle(*p);
593  return; // another extreme case, best strategy is to exit and go to next event
594  }
595 
596  GHepParticle t(*p);
597  t.SetPdgCode(tcode);
598 
599  // set up fermi target
600  Target target(ev->TargetNucleus()->Pdg());
601  double tM = t.Mass();
602 
603  // handle fermi momentum
604  if(fDoFermi)
605  {
606  target.SetHitNucPdg(tcode);
608  TVector3 tP3 = fFermiFac * fNuclmodel->Momentum3();
609  double tE = TMath::Sqrt(tP3.Mag2()+ tM*tM);
610  t.SetMomentum(TLorentzVector(tP3,tE));
611  }
612  else
613  {
614  t.SetMomentum(0,0,0,tM);
615  }
616 
617  GHepParticle * cl = new GHepParticle(*p); // clone particle, to run IntBounce at proper energy
618  // calculate energy and momentum using invariant mass
619  double pM = p->Mass();
620  double E_p = ((*p->P4() + *t.P4()).Mag2() - tM*tM - pM*pM)/(2.0*tM);
621  double P_p = TMath::Sqrt(E_p*E_p - pM*pM);
622  cl->SetMomentum(TLorentzVector(P_p,0,0,E_p));
623  // momentum doesn't have to be in right direction, only magnitude
624  double C3CM = fHadroData2014->IntBounce(cl,tcode,scode,h_fate);
625  delete cl;
626  if (C3CM<-1.) // hope this doesn't occur too often - unphysical but we just pass it on
627  {
628  LOG("HAIntranuke2014", pWARN) << "unphysical angle chosen in InelasicHA - put particle outside nucleus";
630  ev->AddParticle(*p);
631  return;
632  }
633  double KE1L = p->KinE();
634  double KE2L = t.KinE();
635  LOG("HAIntranuke2014",pINFO)
636  << " KE1L = " << KE1L << " " << KE1L << " KE2L = " << KE2L;
637  GHepParticle cl1(*p);
638  GHepParticle cl2(t);
639  bool success = utils::intranuke2014::TwoBodyCollision(ev,pcode,tcode,scode,s2code,C3CM,
640  &cl1,&cl2,fRemnA,fRemnZ,fRemnP4,kIMdHA);
641  if(success)
642  {
643  double P3L = TMath::Sqrt(cl1.Px()*cl1.Px() + cl1.Py()*cl1.Py() + cl1.Pz()*cl1.Pz());
644  double P4L = TMath::Sqrt(cl2.Px()*cl2.Px() + cl2.Py()*cl2.Py() + cl2.Pz()*cl2.Pz());
645  double E3L = cl1.KinE();
646  double E4L = cl2.KinE();
647  LOG ("HAIntranuke2014",pINFO) << "Successful quasielastic scattering or charge exchange";
648  LOG("HAIntranuke",pINFO)
649  << "C3CM = " << C3CM << "\n P3L, E3L = "
650  << P3L << " " << E3L << " P4L, E4L = "<< P4L << " " << E4L ;
651  if(ev->Probe() ) { LOG("HAIntranuke",pINFO)
652  << "P4L = " << P4L << " ;E4L= " << E4L << "\n probe KE = " << ev->Probe()->KinE() << "\n";
653  }
654  if (ev->Probe() && (E3L>ev->Probe()->E()||E4L>ev->Probe()->E())) //is this redundant?
655  {
657  exception.SetReason("TwoBodyCollison gives KE> probe KE in hA simulation");
658  throw exception;
659  }
660  ev->AddParticle(cl1);
661  ev->AddParticle(cl2);
662 
663  LOG("HAIntranuke2014", pDEBUG) << "Nucleus : (A,Z) = ("<<fRemnA<<','<<fRemnZ<<')';
664  } else
665  {
667  exception.SetReason("TwoBodyCollison failed in hA simulation");
668  throw exception;
669  }
670 
671 }
672 //___________________________________________________________________________
674  GHepRecord* ev, GHepParticle* p, INukeFateHA_t fate) const
675 {
676 
677  // Aaron Meyer (05/25/10)
678  //
679  // Called to handle all absorption and pi production reactions
680  //
681  // Nucleons -> Reaction approximated by exponential decay in p+n (sum) space,
682  // gaussian in p-n (difference) space
683  // -fit to hN simulations p C, Fe, Pb at 200, 800 MeV
684  // -get n from isospin, np-nn smaller by 2
685  // Pions -> Reaction approximated with a modified gaussian in p+n space,
686  // normal gaussian in p-n space
687  // -based on fits to multiplicity distributions of hN model
688  // for pi+ C, Fe, Pb at 250, 500 MeV
689  // -fit sum and diff of nn, np to Gaussian
690  // -get pi0 from isospin, np-nn smaller by 2
691  // -get pi- from isospin, np-nn smaller by 4
692  // -add 2-body absorption to better match McKeown data
693  // Kaons -> no guidance, use same code as pions.
694  //
695  // Normally distributed random number generated using Box-Muller transformation
696  //
697  // Pion production reactions rescatter pions in nucleus, otherwise unchanged from
698  // older versions of GENIE
699  //
700 
701 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
702  LOG("HAIntranuke2014", pDEBUG)
703  << "Inelastic() is invoked for a : " << p->Name()
704  << " whose fate is : " << INukeHadroFates::AsString(fate);
705 #endif
706 
707  bool allow_dup = true;
708  PDGCodeList list(allow_dup); // list of final state particles
709 
710  // only absorption/pipro fates allowed
711  if (fate == kIHAFtPiProd) {
712 
713  GHepParticle s1(*p);
714  GHepParticle s2(*p);
715  GHepParticle s3(*p);
716 
719 
720  if (success){
721  LOG ("HAIntranuke2014",pINFO) << " successful pion production fate";
722  // set status of particles and conserve charge/baryon number
723  s1.SetStatus(kIStStableFinalState); //should be redundant
724  // if (pdg::IsPion(s2->Pdg())) s2->SetStatus(kIStHadronInTheNucleus);
726  // if (pdg::IsPion(s3->Pdg())) s3->SetStatus(kIStHadronInTheNucleus);
728 
729  ev->AddParticle(s1);
730  ev->AddParticle(s2);
731  ev->AddParticle(s3);
732 
733  return;
734  }
735  else {
736  LOG("HAIntranuke2014", pNOTICE) << "Error: could not create pion production final state";
738  exception.SetReason("PionProduction kinematics failed - retry kinematics");
739  throw exception;
740  }
741  }
742 
743  else if (fate==kIHAFtAbs)
744 // tuned for pions - mixture of 2-body and many-body
745 // use same for kaons as there is no guidance
746  {
747  // Instances for reference
748  PDGLibrary * pLib = PDGLibrary::Instance();
749  RandomGen * rnd = RandomGen::Instance();
750 
751  double ke = p->KinE() / units::MeV;
752  int pdgc = p->Pdg();
753 
754  if (fRemnA<2)
755  {
756  LOG("HAIntranuke2014", pNOTICE) << "stop propagation - could not create absorption final state: too few particles";
758  ev->AddParticle(*p);
759  return;
760  }
761  if (fRemnZ<1 && (pdgc==kPdgPiM || pdgc==kPdgKM))
762  {
763  LOG("HAIntranuke2014", pNOTICE) << "stop propagation - could not create absorption final state: Pi- or K- cannot be absorbed by only neutrons";
765  ev->AddParticle(*p);
766  return;
767  }
768  if (fRemnA-fRemnZ<1 && (pdgc==kPdgPiP || pdgc==kPdgKP))
769  {
770  LOG("HAIntranuke2014", pINFO) << "stop propagation - could not create absorption final state: Pi+ or K+ cannot be absorbed by only protons";
772  ev->AddParticle(*p);
773  return;
774  }
775 
776  // for now, empirical split between multi-nucleon absorption and pi d -> N N
777  //
778  // added 03/21/11 - Aaron Meyer
779  //
780  if (pdg::IsPion(pdgc) && rnd->RndFsi().Rndm()<1.14*(.903-0.00189*fRemnA)*(1.35-0.00467*ke))
781  { // pi d -> N N, probability determined empirically with McKeown data
782 
783  INukeFateHN_t fate_hN=kIHNFtAbs;
784  int t1code,t2code,scode,s2code;
785  double ppcnt = (double) fRemnZ / (double) fRemnA; // % of protons
786 
787  // choose target nucleon
788  // -- fates weighted by values from Engel, Mosel...
789  if (pdgc==kPdgPiP) {
790  double Prob_pipd_pp=2.*ppcnt*(1.-ppcnt);
791  double Prob_pipnn_pn=.083*(1.-ppcnt)*(1.-ppcnt);
792  if (rnd->RndFsi().Rndm()*(Prob_pipd_pp+Prob_pipnn_pn)<Prob_pipd_pp){
793  t1code=kPdgNeutron; t2code=kPdgProton;
794  scode=kPdgProton; s2code=kPdgProton;}
795  else{
796  t1code=kPdgNeutron; t2code=kPdgNeutron;
797  scode=kPdgProton; s2code=kPdgNeutron;}
798  }
799  if (pdgc==kPdgPiM) {
800  double Prob_pimd_nn=2.*ppcnt*(1.-ppcnt);
801  double Prob_pimpp_pn=.083*ppcnt*ppcnt;
802  if (rnd->RndFsi().Rndm()*(Prob_pimd_nn+Prob_pimpp_pn)<Prob_pimd_nn){
803  t1code=kPdgProton; t2code=kPdgNeutron;
804  scode=kPdgNeutron; s2code=kPdgNeutron; }
805  else{
806  t1code=kPdgProton; t2code=kPdgProton;
807  scode=kPdgProton; s2code=kPdgNeutron;}
808  }
809  else { // pi0
810  double Prob_pi0d_pn=0.88*ppcnt*(1.-ppcnt); // 2 * .44
811  double Prob_pi0pp_pp=.14*ppcnt*ppcnt;
812  double Prob_pi0nn_nn=.14*(1.-ppcnt)*(1.-ppcnt);
813  if (rnd->RndFsi().Rndm()*(Prob_pi0d_pn+Prob_pi0pp_pp+Prob_pi0nn_nn)<Prob_pi0d_pn){
814  t1code=kPdgNeutron; t2code=kPdgProton;
815  scode=kPdgNeutron; s2code=kPdgProton; }
816  else if (rnd->RndFsi().Rndm()*(Prob_pi0d_pn+Prob_pi0pp_pp+Prob_pi0nn_nn)<(Prob_pi0d_pn+Prob_pi0pp_pp)){
817  t1code=kPdgProton; t2code=kPdgProton;
818  scode=kPdgProton; s2code=kPdgProton; }
819  else {
820  t1code=kPdgNeutron; t2code=kPdgNeutron;
821  scode=kPdgNeutron; s2code=kPdgNeutron; }
822  }
823  LOG("HAIntranuke2014",pINFO) << "choose 2 body absorption, probe, fs = " << pdgc <<" "<< scode <<" "<<s2code;
824  // assign proper masses
825  //double M1 = pLib->Find(pdgc) ->Mass();
826  double M2_1 = pLib->Find(t1code)->Mass();
827  double M2_2 = pLib->Find(t2code)->Mass();
828  //double M2 = M2_1 + M2_2;
829  double M3 = pLib->Find(scode) ->Mass();
830  double M4 = pLib->Find(s2code)->Mass();
831 
832  // handle fermi momentum
833  double E2_1L, E2_2L;
834  TVector3 tP2_1L, tP2_2L;
835  //TLorentzVector dNucl_P4;
836  Target target(ev->TargetNucleus()->Pdg());
837  if(fDoFermi)
838  {
839  target.SetHitNucPdg(t1code);
841  tP2_1L=fFermiFac * fNuclmodel->Momentum3();
842  E2_1L = TMath::Sqrt(tP2_1L.Mag2() + M2_1*M2_1);
843 
844  target.SetHitNucPdg(t2code);
846  tP2_2L=fFermiFac * fNuclmodel->Momentum3();
847  E2_2L = TMath::Sqrt(tP2_2L.Mag2() + M2_2*M2_2);
848 
849  //dNucl_P4=TLorentzVector(tP2_1L+tP2_2L,E2_1L+E2_2L);
850  }
851  else
852  {
853  tP2_1L.SetXYZ(0.0, 0.0, 0.0);
854  E2_1L = M2_1;
855 
856  tP2_2L.SetXYZ(0.0, 0.0, 0.0);
857  E2_2L = M2_2;
858  }
859  TLorentzVector dNucl_P4=TLorentzVector(tP2_1L+tP2_2L,E2_1L+E2_2L);
860 
861  double E2L = E2_1L + E2_2L;
862 
863  // adjust p to reflect scattering
864  // get random scattering angle
865  double C3CM = fHadroData2014->IntBounce(p,t1code,scode,fate_hN);
866  if (C3CM<-1.)
867  {
868  LOG("HAIntranuke2014", pWARN) << "Inelastic() failed: IntBounce returned bad angle - try again";
870  exception.SetReason("unphysical angle for hN scattering");
871  throw exception;
872  return;
873  }
874 
875  TLorentzVector t4P1L,t4P2L,t4P3L,t4P4L;
876  t4P1L=*p->P4();
877  t4P2L=TLorentzVector(TVector3(tP2_1L+tP2_2L),E2L);
878  double bindE=0.075; // set to fit McKeown data
879  //double bindE=0.0;
880  if (utils::intranuke2014::TwoBodyKinematics(M3,M4,t4P1L,t4P2L,t4P3L,t4P4L,C3CM,fRemnP4,bindE))
881  {
882  if (pdgc==kPdgPiP || pdgc==kPdgKP) fRemnZ++;
883  if (pdgc==kPdgPiM || pdgc==kPdgKM) fRemnZ--;
884  if (t1code==kPdgProton) fRemnZ--;
885  if (t2code==kPdgProton) fRemnZ--;
886  fRemnA-=2;
887 
888  fRemnP4-=dNucl_P4;
889 
890  // create t particles w/ appropriate momenta, code, and status
891  // Set target's mom to be the mom of the hadron that was cloned
892  GHepParticle* t1 = new GHepParticle(*p);
893  GHepParticle* t2 = new GHepParticle(*p);
894  t1->SetFirstMother(p->FirstMother());
895  t1->SetLastMother(p->LastMother());
896  t2->SetFirstMother(p->FirstMother());
897  t2->SetLastMother(p->LastMother());
898 
899  // adjust p to reflect scattering
900  t1->SetPdgCode(scode);
901  t1->SetMomentum(t4P3L);
902 
903  t2->SetPdgCode(s2code);
904  t2->SetMomentum(t4P4L);
905 
908 
909  ev->AddParticle(*t1);
910  ev->AddParticle(*t2);
911 
912  return;
913  }
914  else
915  {
916  LOG("HAIntranuke2014", pNOTICE) << "Inelastic in hA failed calling TwoBodyKineamtics";
918  exception.SetReason("Pion absorption kinematics through TwoBodyKinematics failed");
919  throw exception;
920 
921  }
922 
923  } // end pi d -> N N
924  else // multi-nucleon
925  {
926 
927  // declare some parameters for double gaussian and determine values chosen
928  // parameters for proton and pi+, others come from isospin transformations
929 
930  double ns0=0; // mean - sum of nucleons
931  double nd0=0; // mean - difference of nucleons
932  double Sig_ns=0; // std dev - sum
933  double Sig_nd=0; // std dev - diff
934  double gam_ns=0; // exponential decay rate (for nucleons)
935 
936  if ( pdg::IsNeutronOrProton (pdgc) ) // nucleon probe
937  {
938  // antisymmetric about Z=N
939  if (fRemnA-fRemnZ > fRemnZ)
940  nd0 = 135.227 * TMath::Exp(-7.124*(fRemnA-fRemnZ)/double(fRemnA)) - 2.762;
941  else
942  nd0 = -135.227 * TMath::Exp(-7.124* fRemnZ /double(fRemnA)) + 4.914;
943 
944  Sig_nd = 2.034 + fRemnA * 0.007846;
945 
946  double c1 = 0.041 + ke * 0.0001525;
947  double c2 = -0.003444 - ke * 0.00002324;
948 //change last factor from 30 to 15 so that gam_ns always larger than 0
949 //add check to be certain
950  double c3 = 0.064 - ke * 0.000015;
951  gam_ns = c1 * TMath::Exp(c2*fRemnA) + c3;
952  if(gam_ns<0.002) gam_ns = 0.002;
953  //gam_ns = 10.;
954  LOG("HAIntranuke2014", pINFO) << "nucleon absorption";
955  LOG("HAIntranuke2014", pINFO) << "--> mean diff distr = " << nd0 << ", stand dev = " << Sig_nd;
956  // LOG("HAIntranuke2014", pINFO) << "--> mean sum distr = " << ns0 << ", Stand dev = " << Sig_ns;
957  LOG("HAIntranuke2014", pINFO) << "--> gam_ns = " << gam_ns;
958  }
959  else if ( pdgc==kPdgPiP || pdgc==kPdgPi0 || pdgc==kPdgPiM) //pion probe
960  {
961  ns0 = .0001*(1.+ke/250.) * (fRemnA-10)*(fRemnA-10) + 3.5;
962  nd0 = (1.+ke/250.) - ((fRemnA/200.)*(1. + 2.*ke/250.));
963  Sig_ns = (10. + 4. * ke/250.)*TMath::Power(fRemnA/250.,0.9); //(1. - TMath::Exp(-0.02*fRemnA));
964  Sig_nd = 4*(1 - TMath::Exp(-0.03*ke));
965  LOG("HAIntranuke2014", pINFO) << "pion absorption";
966  LOG("HAIntranuke2014", pINFO) << "--> mean diff distr = " << nd0 << ", stand dev = " << Sig_nd;
967  LOG("HAIntranuke2014", pINFO) << "--> mean sum distr = " << ns0 << ", Stand dev = " << Sig_ns;
968  }
969  else if (pdgc==kPdgKP || pdgc==kPdgKM) // kaon probe
970  {
971  ns0 = (rnd->RndFsi().Rndm()>0.5?3:2);
972  nd0 = 1.;
973  Sig_ns = 0.1;
974  Sig_nd = 0.1;
975  LOG("HAIntranuke2014", pINFO) << "kaon absorption - set ns, nd later";
976  // LOG("HAIntranuke2014", pINFO) << "--> mean diff distr = " << nd0 << ", stand dev = " << Sig_nd;
977  // LOG("HAIntranuke2014", pINFO) << "--> mean sum distr = " << ns0 << ", Stand dev = " << Sig_ns;
978  }
979  else
980  {
981  LOG("HAIntranuke2014", pWARN) << "Inelastic() cannot handle absorption reaction for " << p->Name();
982  }
983 
984  // account for different isospin
985  if (pdgc==kPdgPi0 || pdgc==kPdgNeutron) nd0-=2.;
986  if (pdgc==kPdgPiM) nd0-=4.;
987 
988  int iter=0; // counter
989  int np=0,nn=0; // # of p, # of n
990  bool not_done=true;
991  double u1 = 0, u2 = 0;
992 
993  while (not_done)
994  {
995  // infinite loop check
996  if (iter>=100) {
997  LOG("HAIntranuke2014", pNOTICE) << "Error: could not choose absorption final state";
998  LOG("HAIntranuke2014", pNOTICE) << "--> mean diff distr = " << nd0 << ", stand dev = " << Sig_nd;
999  LOG("HAIntranuke2014", pNOTICE) << "--> mean sum distr = " << ns0 << ", Stand dev = " << Sig_ns;
1000  LOG("HAIntranuke2014", pNOTICE) << "--> gam_ns = " << gam_ns;
1001  LOG("HAIntranuke2014", pNOTICE) << "--> A = " << fRemnA << ", Z = " << fRemnZ << ", Energy = " << ke;
1003  exception.SetReason("Absorption choice of # of p,n failed");
1004  throw exception;
1005  }
1006  //here??
1007 
1008  // Box-Muller transform
1009  // Takes two uniform distribution random variables on (0,1]
1010  // Creates two normally distributed random variables on (0,inf)
1011 
1012  u1 = rnd->RndFsi().Rndm(); // uniform random variable 1
1013  u2 = rnd->RndFsi().Rndm(); // " " 2
1014  if (u1==0) u1 = rnd->RndFsi().Rndm();
1015  if (u2==0) u2 = rnd->RndFsi().Rndm(); // Just in case
1016 
1017  // normally distributed random variable
1018  double x2 = TMath::Sqrt(-2*TMath::Log(u1))*TMath::Sin(2*kPi*u2);
1019 
1020  double ns = 0;
1021 
1022  if ( pdg::IsNeutronOrProton (pdgc) ) //nucleon probe
1023  {
1024  ns = -TMath::Log(rnd->RndFsi().Rndm())/gam_ns; // exponential random variable
1025  }
1026  if ( pdg::IsKaon (pdgc) ) //charged kaon probe - either 2 or 3 nucleons to stay simple
1027  {
1028  ns = (rnd->RndFsi().Rndm()<0.5?2:3);
1029  }
1030  else if ( pdgc==kPdgPiP || pdgc==kPdgPi0 || pdgc==kPdgPiM) //pion probe
1031  {
1032  // Pion fit for sum takes for xs*exp((xs-x0)^2 / 2*sig_xs0)
1033  // Find random variable by first finding gaussian random variable
1034  // then throwing the value against a linear P.D.F.
1035  //
1036  // max is the maximum value allowed for the random variable (10 std + mean)
1037  // minimum allowed value is 0
1038 
1039  double max = ns0 + Sig_ns * 10;
1040  if(max>fRemnA) max=fRemnA;
1041  double x1 = 0;
1042  bool not_found = true;
1043  int iter2 = 0;
1044 
1045  while (not_found)
1046  {
1047  // infinite loop check
1048  if (iter2>=100)
1049  {
1050  LOG("HAIntranuke2014", pNOTICE) << "Error: stuck in random variable loop for ns";
1051  LOG("HAIntranuke2014", pNOTICE) << "--> mean of sum parent distr = " << ns0 << ", Stand dev = " << Sig_ns;
1052  LOG("HAIntranuke2014", pNOTICE) << "--> A = " << fRemnA << ", Z = " << fRemnZ << ", Energy = " << ke;
1053 
1055  exception.SetReason("Random number generator for choice of #p,n final state failed - unusual - redo kinematics");
1056  throw exception;
1057  }
1058 
1059  // calculate exponential random variable
1060  u1 = rnd->RndFsi().Rndm();
1061  u2 = rnd->RndFsi().Rndm();
1062  if (u1==0) u1 = rnd->RndFsi().Rndm();
1063  if (u2==0) u2 = rnd->RndFsi().Rndm();
1064  x1 = TMath::Sqrt(-2*TMath::Log(u1))*TMath::Cos(2*kPi*u2);
1065 
1066  ns = ns0 + Sig_ns * x1;
1067  if ( ns>max || ns<0 ) {iter2++; continue;}
1068  else if ( rnd->RndFsi().Rndm() > (ns/max) ) {iter2++; continue;}
1069  else {
1070  // accept this sum value
1071  not_found=false;
1072  }
1073  } //while(not_found)
1074  }//else pion
1075 
1076  double nd = nd0 + Sig_nd * x2; // difference (p-n) for both pion, nucleon probe
1077  if (pdgc==kPdgKP) // special for KP
1078  { if (ns==2) nd=0;
1079  if (ns>2) nd=1; }
1080 
1081  np = int((ns+nd)/2.+.5); // Addition of .5 for rounding correction
1082  nn = int((ns-nd)/2.+.5);
1083 
1084  LOG("HAIntranuke2014", pINFO) << "ns = "<<ns<<", nd = "<<nd<<", np = "<<np<<", nn = "<<nn;
1085  //LOG("HAIntranuke2014", pNOTICE) << "RemA = "<<fRemnA<<", RemZ = "<<fRemnZ<<", probe = "<<pdgc;
1086 
1087  /*if ((ns+nd)/2. < 0 || (ns-nd)/2. < 0) {iter++; continue;}
1088  else */
1089  //check for problems befor executing phase space 'decay'
1090  if (np < 0 || nn < 0 ) {iter++; continue;}
1091  else if (np + nn < 2. ) {iter++; continue;}
1092  else if ((np + nn == 2.) && pdg::IsNeutronOrProton (pdgc)) {iter++; continue;}
1093  else if (np > fRemnZ + ((pdg::IsProton(pdgc) || pdgc==kPdgPiP || pdgc==kPdgKP)?1:0)
1094  - ((pdgc==kPdgPiM || pdgc==kPdgKM)?1:0)) {iter++; continue;}
1095  else if (nn > fRemnA-fRemnZ + ((pdg::IsNeutron(pdgc)||pdgc==kPdgPiM||pdgc==kPdgKM)?1:0)
1096  - ((pdgc==kPdgPiP||pdgc==kPdgKP)?1:0)) {iter++; continue;}
1097  else {
1098  not_done=false; //success
1099  LOG("HAIntranuke2014",pINFO) << "success, iter = " << iter << " np, nn = " << np << " " << nn;
1100  if (np+nn>86) // too many particles, scale down
1101  {
1102  double frac = 85./double(np+nn);
1103  np = int(np*frac);
1104  nn = int(nn*frac);
1105  }
1106 
1107  if ( (np==fRemnZ +((pdg::IsProton (pdgc)||pdgc==kPdgPiP||pdgc==kPdgKP)?1:0)-(pdgc==kPdgPiM||pdgc==kPdgKM?1:0))
1108  &&(nn==fRemnA-fRemnZ+((pdg::IsNeutron(pdgc)||pdgc==kPdgPiM||pdgc==kPdgKM)?1:0)-(pdgc==kPdgPiP||pdgc==kPdgKP?1:0)) )
1109  { // leave at least one nucleon in the nucleus to prevent excess momentum
1110  if (rnd->RndFsi().Rndm()<np/(double)(np+nn)) np--;
1111  else nn--;
1112  }
1113 
1114  LOG("HAIntranuke2014", pNOTICE) << "Final state chosen; # protons : "
1115  << np << ", # neutrons : " << nn;
1116  }
1117  } //while(not_done)
1118 
1119  // change remnants to reflect probe
1120  if ( pdgc==kPdgProton || pdgc==kPdgPiP || pdgc==kPdgKP) fRemnZ++;
1121  if ( pdgc==kPdgPiM || pdgc==kPdgKM) fRemnZ--;
1122  if ( pdg::IsNeutronOrProton (pdgc) ) fRemnA++;
1123 
1124  // PhaseSpaceDecay forbids anything over 18 particles
1125  //
1126  // If over 18 particles, split into 5 groups and perform decay on each group
1127  // Anything over 85 particles reduced to 85 in previous step
1128  //
1129  // 4 of the nucleons are used as "probes" as well as original probe,
1130  // with each one sharing 1/5 of the total incident momentum
1131  //
1132  // Note: choosing 5 groups and distributing momentum evenly was arbitrary
1133  // Needs to be revised later
1134 
1135  if ((np+nn)>18)
1136  {
1137  // code lists
1138  PDGCodeList list0(allow_dup);
1139  PDGCodeList list1(allow_dup);
1140  PDGCodeList list2(allow_dup);
1141  PDGCodeList list3(allow_dup);
1142  PDGCodeList list4(allow_dup);
1143  PDGCodeList* listar[5] = {&list0, &list1, &list2, &list3, &list4};
1144 
1145  //set up HadronClusters
1146  // simple for now, each (of 5) hadron cluster has 1/5 of mom and KE
1147 
1148  double probM = pLib->Find(pdgc) ->Mass();
1149  TVector3 pP3 = p->P4()->Vect() * (1./5.);
1150  double probKE = p->P4()->E() -probM;
1151  double clusKE = probKE * (1./5.);
1152  TLorentzVector clusP4(pP3,clusKE); //no mass
1153 
1154  TLorentzVector X4(*p->X4());
1156 
1157  int mom = p->FirstMother();
1158 
1159  GHepParticle * p0 = new GHepParticle(kPdgCompNuclCluster,ist, mom,-1,-1,-1,clusP4,X4);
1160  GHepParticle * p1 = new GHepParticle(kPdgCompNuclCluster,ist, mom,-1,-1,-1,clusP4,X4);
1161  GHepParticle * p2 = new GHepParticle(kPdgCompNuclCluster,ist, mom,-1,-1,-1,clusP4,X4);
1162  GHepParticle * p3 = new GHepParticle(kPdgCompNuclCluster,ist, mom,-1,-1,-1,clusP4,X4);
1163  GHepParticle * p4 = new GHepParticle(kPdgCompNuclCluster,ist, mom,-1,-1,-1,clusP4,X4);
1164 
1165  // To conserve 4-momenta
1166  // fRemnP4 -= probP4 + protP4*np_p + neutP4*(4-np_p) - *p->P4();
1167  fRemnP4 -= 5.*clusP4 - *p->P4();
1168 
1169  for (int i=0;i<(np+nn);i++)
1170  {
1171  if (i<np)
1172  {
1173  listar[i%5]->push_back(kPdgProton);
1174  fRemnZ--;
1175  }
1176  else listar[i%5]->push_back(kPdgNeutron);
1177  fRemnA--;
1178  }
1179  for (int i=0;i<5;i++)
1180  {
1181  LOG("HAIntranuke2014", pINFO) << "List" << i << " size: " << listar[i]->size();
1182  if (listar[i]->size() <2)
1183  {
1185  exception.SetReason("too few particles for Phase Space decay - try again");
1186  throw exception;
1187  }
1188  }
1189 
1190  // commented out to better fit with absorption reactions
1191  // Add the fermi energy of the nucleons to the phase space
1192  /*if(fDoFermi)
1193  {
1194  GHepParticle* p_ar[5] = {cl, p1, p2, p3, p4};
1195  for (int i=0;i<5;i++)
1196  {
1197  Target target(ev->TargetNucleus()->Pdg());
1198  TVector3 pBuf = p_ar[i]->P4()->Vect();
1199  double mBuf = p_ar[i]->Mass();
1200  double eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
1201  TLorentzVector tSum(pBuf,eBuf);
1202  double mSum = 0.0;
1203  vector<int>::const_iterator pdg_iter;
1204  for(pdg_iter=++(listar[i]->begin());pdg_iter!=listar[i]->end();++pdg_iter)
1205  {
1206  target.SetHitNucPdg(*pdg_iter);
1207  fNuclmodel->GenerateNucleon(target);
1208  mBuf = pLib->Find(*pdg_iter)->Mass();
1209  mSum += mBuf;
1210  pBuf = fFermiFac * fNuclmodel->Momentum3();
1211  eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
1212  tSum += TLorentzVector(pBuf,eBuf);
1213  fRemnP4 -= TLorentzVector(pBuf,eBuf-mBuf);
1214  }
1215  TLorentzVector dP4 = tSum + TLorentzVector(TVector3(0,0,0),-mSum);
1216  p_ar[i]->SetMomentum(dP4);
1217  }
1218  }*/
1219 
1220  bool success1 = utils::intranuke2014::PhaseSpaceDecay(ev,p0,*listar[0],fRemnP4,fNucRmvE,kIMdHA);
1221  bool success2 = utils::intranuke2014::PhaseSpaceDecay(ev,p1,*listar[1],fRemnP4,fNucRmvE,kIMdHA);
1222  bool success3 = utils::intranuke2014::PhaseSpaceDecay(ev,p2,*listar[2],fRemnP4,fNucRmvE,kIMdHA);
1223  bool success4 = utils::intranuke2014::PhaseSpaceDecay(ev,p3,*listar[3],fRemnP4,fNucRmvE,kIMdHA);
1224  bool success5 = utils::intranuke2014::PhaseSpaceDecay(ev,p4,*listar[4],fRemnP4,fNucRmvE,kIMdHA);
1225  if(success1 && success2 && success3 && success4 && success5)
1226  {
1227  LOG("HAIntranuke2014", pINFO)<<"Successful many-body absorption - n>=18";
1228  }
1229  else
1230  {
1231  // try to recover
1232  LOG("HAIntranuke2014", pWARN) << "PhaseSpace decay fails for HadrCluster- recovery likely incorrect - rethrow event";
1234  ev->AddParticle(*p);
1235  fRemnA+=np+nn;
1236  fRemnZ+=np;
1237  if ( pdgc==kPdgProton || pdgc==kPdgPiP ) fRemnZ--;
1238  if ( pdgc==kPdgPiM ) fRemnZ++;
1239  if ( pdg::IsNeutronOrProton (pdgc) ) fRemnA--;
1240  /* exceptions::INukeException exception;
1241  exception.SetReason("Phase space generation of absorption final state failed");
1242  throw exception;
1243  */
1244  }
1245 
1246  // delete cl;
1247  delete p0;
1248  delete p1;
1249  delete p2;
1250  delete p3;
1251  delete p4;
1252 
1253  }
1254  else // less than 18 particles pion
1255  {
1256  if (pdgc==kPdgKP) list.push_back(kPdgKP); //normally conserve strangeness
1257  if (pdgc==kPdgKM) list.push_back(kPdgKM);
1258  for (int i=0;i<np;i++)
1259  {
1260  list.push_back(kPdgProton);
1261  fRemnA--;
1262  fRemnZ--;
1263  }
1264  for (int i=0;i<nn;i++)
1265  {
1266  list.push_back(kPdgNeutron);
1267  fRemnA--;
1268  }
1269 
1270  // Library instance for reference
1271  //PDGLibrary * pLib = PDGLibrary::Instance();
1272 
1273  // commented out to better fit with absorption reactions
1274  // Add the fermi energy of the nucleons to the phase space
1275  /*if(fDoFermi)
1276  {
1277  Target target(ev->TargetNucleus()->Pdg());
1278  TVector3 pBuf = p->P4()->Vect();
1279  double mBuf = p->Mass();
1280  double eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
1281  TLorentzVector tSum(pBuf,eBuf);
1282  double mSum = 0.0;
1283  vector<int>::const_iterator pdg_iter;
1284  for(pdg_iter=++(list.begin());pdg_iter!=list.end();++pdg_iter)
1285  {
1286  target.SetHitNucPdg(*pdg_iter);
1287  fNuclmodel->GenerateNucleon(target);
1288  mBuf = pLib->Find(*pdg_iter)->Mass();
1289  mSum += mBuf;
1290  pBuf = fFermiFac * fNuclmodel->Momentum3();
1291  eBuf = TMath::Sqrt(pBuf.Mag2() + mBuf*mBuf);
1292  tSum += TLorentzVector(pBuf,eBuf);
1293  fRemnP4 -= TLorentzVector(pBuf,eBuf-mBuf);
1294  }
1295  TLorentzVector dP4 = tSum + TLorentzVector(TVector3(0,0,0),-mSum);
1296  p->SetMomentum(dP4);
1297  }*/
1298 
1299  LOG("HAIntranuke2014", pDEBUG)
1300  << "Remnant nucleus (A,Z) = (" << fRemnA << ", " << fRemnZ << ")";
1301  LOG("HAIntranuke2014", pINFO) << " list size: " << np+nn;
1302  if (np+nn <2)
1303  {
1305  exception.SetReason("too few particles for Phase Space decay - try again");
1306  throw exception;
1307  }
1308  // GHepParticle * cl = new GHepParticle(*p);
1309  // cl->SetPdgCode(kPdgDecayNuclCluster);
1311  if (success)
1312  {
1313  LOG ("HAIntranuke2014",pINFO) << "Successful many-body absorption, n<=18";
1314  }
1315  else {
1316  // recover
1318  ev->AddParticle(*p);
1319  fRemnA+=np+nn;
1320  fRemnZ+=np;
1321  if ( pdgc==kPdgProton || pdgc==kPdgPiP ) fRemnZ--;
1322  if ( pdgc==kPdgPiM ) fRemnZ++;
1323  if ( pdg::IsNeutronOrProton (pdgc) ) fRemnA--;
1325  exception.SetReason("Phase space generation of absorption final state failed");
1326  throw exception;
1327  }
1328  }
1329  } // end multi-nucleon FS
1330  }
1331  else // not absorption/pipro
1332  {
1333  LOG("HAIntranuke2014", pWARN)
1334  << "Inelastic() can not handle fate: " << INukeHadroFates::AsString(fate);
1335  return;
1336  }
1337 }
1338 //___________________________________________________________________________
1340  GHepRecord* /*ev*/, GHepParticle* /*p*/, int /*mom*/) const
1341 {
1342  // only relevant for hN mode
1343  return false;
1344 }
1345 //___________________________________________________________________________
1347 {
1348 
1350  const Registry * gc = confp->GlobalParameterList();
1351 
1352  // load hadronic cross sections
1354 
1355  // fermi momentum setup
1357  fNuclmodel = dynamic_cast<const NuclearModelI *>
1358  (fAlgf->GetAlgorithm("genie::FGMBodekRitchie","Default"));
1359 
1360  // other intranuke config params
1361  fR0 = fConfig->GetDoubleDef ("R0", gc->GetDouble("NUCL-R0")); // fm
1362  fNR = fConfig->GetDoubleDef ("NR", gc->GetDouble("NUCL-NR"));
1363  fNucRmvE = fConfig->GetDoubleDef ("NucRmvE", gc->GetDouble("INUKE-NucRemovalE")); // GeV
1364  fDelRPion = fConfig->GetDoubleDef ("DelRPion", gc->GetDouble("HAINUKE-DelRPion"));
1365  fDelRNucleon = fConfig->GetDoubleDef ("DelRNucleon", gc->GetDouble("HAINUKE-DelRNucleon"));
1366  fHadStep = fConfig->GetDoubleDef ("HadStep", gc->GetDouble("INUKE-HadStep")); // fm
1367  fEPreEq = fConfig->GetDoubleDef ("EPreEq", gc->GetDouble("INUKE-Energy_Pre_Eq"));
1368  fNucAbsFac = fConfig->GetDoubleDef ("NucAbsFac", gc->GetDouble("INUKE-NucAbsFac"));
1369  fNucCEXFac = fConfig->GetDoubleDef ("NucCEXFac", gc->GetDouble("INUKE-NucCEXFac"));
1370  fFermiFac = fConfig->GetDoubleDef ("FermiFac", gc->GetDouble("INUKE-FermiFac"));
1371  fFermiMomentum = fConfig->GetDoubleDef ("FermiMomentum",gc->GetDouble("INUKE-FermiMomentum"));
1372  fDoFermi = fConfig->GetBoolDef ("DoFermi", gc->GetBool("INUKE-DoFermi"));
1373  fFreeStep = fConfig->GetDoubleDef ("FreeStep", gc->GetDouble("INUKE-FreeStep"));
1374  fDoCompoundNucleus = fConfig->GetBoolDef ("DoCompoundNucleus", gc->GetBool("INUKE-DoCompoundNucleus"));
1375 
1376  // report
1377  LOG("HAIntranuke2014", pINFO) << "Settings for INTRANUKE mode: " << INukeMode::AsString(kIMdHA);
1378  LOG("HAIntranuke2014", pINFO) << "R0 = " << fR0 << " fermi";
1379  LOG("HAIntranuke2014", pINFO) << "NR = " << fNR;
1380  LOG("HAIntranuke2014", pINFO) << "DelRPion = " << fDelRPion;
1381  LOG("HAIntranuke2014", pINFO) << "DelRNucleon = " << fDelRNucleon;
1382  LOG("HAIntranuke2014", pINFO) << "HadStep = " << fHadStep << " fermi";
1383  LOG("HAIntranuke2014", pINFO) << "EPreEq = " << fHadStep << " fermi";
1384  LOG("HAIntranuke2014", pINFO) << "NucAbsFac = " << fNucAbsFac;
1385  LOG("HAIntranuke2014", pINFO) << "NucCEXFac = " << fNucCEXFac;
1386  LOG("HAIntranuke2014", pINFO) << "FermiFac = " << fFermiFac;
1387  LOG("HAIntranuke2014", pINFO) << "FreeStep = " << fFreeStep; // free step in fm
1388  LOG("HAIntranuke2014", pINFO) << "FermiMomtm = " << fFermiMomentum;
1389  LOG("HAIntranuke2014", pINFO) << "DoFermi? = " << ((fDoFermi)?(true):(false));
1390  LOG("HAIntranuke2014", pINFO) << "DoCmpndNuc? = " << ((fDoCompoundNucleus)?(true):(false));
1391 }
1392 //___________________________________________________________________________
enum genie::EINukeFateHA_t INukeFateHA_t
static string AsString(INukeMode_t mode)
Definition: INukeMode.h:41
RgDbl GetDoubleDef(RgKey key, RgDbl def_opt, bool set_def=true)
Definition: Registry.cxx:549
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 GHepParticle * Particle(int position) const
Definition: GHepRecord.cxx:148
TRandom3 & RndFsi(void) const
rnd number generator used by intranuclear cascade monte carlos
Definition: RandomGen.h:60
#include "Numerical/GSFunc.h"
Definition: AlgCmp.h:26
AlgFactory * fAlgf
algorithm factory instance
Definition: Intranuke2014.h:94
#define pERROR
Definition: Messenger.h:50
double fNR
param multiplying the nuclear radius, determining how far to track hadrons beyond the "nuclear bounda...
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.
double E(void) const
Get energy.
Definition: GHepParticle.h:90
double FracADep(int hpdgc, INukeFateHA_t fate, double ke, int targA) const
static RandomGen * Instance()
Access instance.
Definition: RandomGen.cxx:79
static const double ns
Definition: Units.h:102
enum genie::EGHepStatus GHepStatus_t
A singleton class holding all configuration registries built while parsing all loaded XML configurati...
Definition: AlgConfigPool.h:41
double fEPreEq
threshold for pre-equilibrium reaction
static const double MeV
Definition: Units.h:130
double fR0
effective nuclear size param
int fRemnZ
remnant nucleus Z
Definition: Intranuke2014.h:97
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)
INukeHadroData2014 * fHadroData2014
a collection of h+N,h+A data & calculations
Definition: Intranuke2014.h:93
void SimulateHadronicFinalState(GHepRecord *ev, GHepParticle *p) const
void SetMomentum(const TLorentzVector &p4)
bool IsKaon(int pdgc)
Definition: PDGUtils.cxx:301
double Mass(void) const
Mass that corresponds to the PDG code.
RgDbl GetDouble(RgKey key) const
Definition: Registry.cxx:488
double fFermiMomentum
whether or not particle collision is pauli blocked
Definition: tf_graph.h:23
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
virtual void ProcessEventRecord(GHepRecord *event_rec) const
A list of PDG codes.
Definition: PDGCodeList.h:33
double Px(void) const
Get Px.
Definition: GHepParticle.h:87
bool TwoBodyKinematics(double M3, double M4, TLorentzVector tP1L, TLorentzVector tP2L, TLorentzVector &tP3L, TLorentzVector &tP4L, double C3CM, TLorentzVector &RemnP4, double bindE=0)
virtual GHepParticle * Probe(void) const
Definition: GHepRecord.cxx:314
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.
int fRemnA
remnant nucleus A
Definition: Intranuke2014.h:96
bool IsNeutron(int pdgc)
Definition: PDGUtils.cxx:311
const int kPdgCompNuclCluster
Definition: PDGCodes.h:188
double fDelRPion
factor by which Pion Compton wavelength gets multiplied to become nuclear size enhancement ...
double fFreeStep
produced particle free stem, in fm
double PiBounce(void) const
const NuclearModelI * fNuclmodel
nuclear model used to generate fermi momentum
Definition: Intranuke2014.h:95
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
void ProcessEventRecord(GHepRecord *event_rec) const
void InelasticHA(GHepRecord *ev, GHepParticle *p, INukeFateHA_t fate) const
const int kPdgKM
Definition: PDGCodes.h:147
const int kPdgGamma
Definition: PDGCodes.h:163
A Neutrino Interaction Target. Is a transparent encapsulation of quite different physical systems suc...
Definition: Target.h:41
const Algorithm * GetAlgorithm(const AlgId &algid)
Definition: AlgFactory.cxx:86
const int kPdgKP
Definition: PDGCodes.h:146
const int kPdgPiP
Definition: PDGCodes.h:132
const int kPdgPi0
Definition: PDGCodes.h:134
virtual GHepParticle * TargetNucleus(void) const
Definition: GHepRecord.cxx:323
#define pINFO
Definition: Messenger.h:53
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)
Misc GENIE control constants.
INukeFateHA_t HadronFateHA(const GHepParticle *p) const
enum genie::EINukeFateHN_t INukeFateHN_t
void ElasHA(GHepRecord *ev, GHepParticle *p, INukeFateHA_t fate) const
Registry * GlobalParameterList(void) const
#define pWARN
Definition: Messenger.h:51
int nuclA
value of A for the target nucleus in hA mode
double fFermiFac
testing parameter to modify fermi momentum
p
Definition: test.py:228
double fNucCEXFac
charge exchange xsec correction factor (hN Mode)
double fNucRmvE
binding energy to subtract from cascade nucleons
static const double A
Definition: Units.h:82
double PnBounce(void) const
bool fDoCompoundNucleus
whether or not to do compound nucleus considerations
double KinE(bool mass_from_pdg=false) const
Get kinetic energy.
static PDGLibrary * Instance(void)
Definition: PDGLibrary.cxx:45
bool PhaseSpaceDecay(GHepRecord *ev, GHepParticle *p, const PDGCodeList &pdgv, TLorentzVector &RemnP4, double NucRmvE, EINukeMode mode=kIMdHA)
general phase space decay method
static AlgFactory * Instance()
Definition: AlgFactory.cxx:75
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 SetStatus(GHepStatus_t s)
Definition: GHepParticle.h:125
virtual TVector3 Momentum3(void) const
Definition: NuclearModelI.h:59
static string AsString(INukeFateHN_t fate)
A registry. Provides the container for algorithm configuration parameters.
Definition: Registry.h:66
bool IsNeutronOrProton(int pdgc)
Definition: PDGUtils.cxx:321
TParticlePDG * Find(int pdgc)
Definition: PDGLibrary.cxx:63
RgBool GetBool(RgKey key) const
Definition: Registry.cxx:474
const int kPdgPiM
Definition: PDGCodes.h:133
virtual bool GenerateNucleon(const Target &) const =0
Registry * fConfig
config. (either owned or pointing to config pool)
Definition: Algorithm.h:122
virtual void AddParticle(const GHepParticle &p)
Definition: GHepRecord.cxx:526
double FracAIndep(int hpdgc, INukeFateHA_t fate, double ke) const
double fDelRNucleon
factor by which Nucleon Compton wavelength gets multiplied to become nuclear size enhancement ...
const int kPdgProton
Definition: PDGCodes.h:62
int A(void) const
#define pNOTICE
Definition: Messenger.h:52
static const unsigned int kRjMaxIterations
Definition: Controls.h:27
int HandleCompoundNucleus(GHepRecord *ev, GHepParticle *p, int mom) const
TLorentzVector * P4(void) const
Definition: GHepParticle.h:79
void Inelastic(GHepRecord *ev, GHepParticle *p, INukeFateHA_t fate) const
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
RgBool GetBoolDef(RgKey key, RgBool def_opt, bool set_def=true)
Definition: Registry.cxx:539
double fNucAbsFac
absorption xsec correction factor (hN Mode)
double fHadStep
step size for intranuclear hadron transport
void SimulateHadronicFinalStateKinematics(GHepRecord *ev, GHepParticle *p) const
TLorentzVector fRemnP4
P4 of remnant system.
Definition: Intranuke2014.h:98
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
unsigned int fNumIterations
static AlgConfigPool * Instance()
static INukeHadroData2014 * Instance(void)
double IntBounce(const GHepParticle *p, int target, int s1, INukeFateHN_t fate)
#define pDEBUG
Definition: Messenger.h:54
void SetPdgCode(int c)
double Py(void) const
Get Py.
Definition: GHepParticle.h:88
bool fDoFermi
whether or not to do fermi mom.