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