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