GENIEGenerator
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
HG4BertCascIntranuke.cxx
Go to the documentation of this file.
1 #include "Framework/Conventions/GBuild.h"
2 #ifdef __GENIE_GEANT4_INTERFACE_ENABLED__
3 //____________________________________________________________________________
4 /*
5 
6  Author: Dennis Wright <dwright@slac.stanford.edu>
7  31 January 2017
8 
9  See header file for class documentation.
10 
11 */
12 //____________________________________________________________________________
13 
14 #include <cstdlib>
15 #include <sstream>
16 #include <exception>
17 
18 #include "TMath.h"
19 
35 
36 
37 // Geant4 headers
38 #include "Geant4/G4ParticleTypes.hh"
39 #include "Geant4/G4ParticleTable.hh"
40 #include "Geant4/G4IonTable.hh"
41 #include "Geant4/G4LeptonConstructor.hh"
42 #include "Geant4/G4MesonConstructor.hh"
43 #include "Geant4/G4BaryonConstructor.hh"
44 #include "Geant4/G4GenericIon.hh"
45 #include "Geant4/G4ProcessManager.hh"
46 #include "Geant4/G4SystemOfUnits.hh"
47 #include "Geant4/G4ThreeVector.hh"
48 #include "Geant4/G4Fancy3DNucleus.hh"
49 #include "Geant4/G4InuclParticle.hh"
50 #include "Geant4/G4InuclCollider.hh"
51 #include "Geant4/G4InuclElementaryParticle.hh"
52 #include "Geant4/G4InuclNuclei.hh"
53 #include "Geant4/G4KineticTrackVector.hh"
54 #include "Geant4/G4Diproton.hh"
55 #include "Geant4/G4Dineutron.hh"
56 #include "Geant4/G4UnboundPN.hh"
57 
58 
59 using std::ostringstream;
60 
61 using namespace genie;
62 using namespace genie::utils;
63 using namespace genie::utils::intranuke;
64 using namespace genie::constants;
65 using namespace genie::controls;
66 
67 //___________________________________________________________________________
68 HG4BertCascIntranuke::HG4BertCascIntranuke()
69 : EventRecordVisitorI("genie::HG4BertCascIntranuke")
70 {
71  InitG4Particles();
72 }
73 
74 //___________________________________________________________________________
75 HG4BertCascIntranuke::HG4BertCascIntranuke(string config)
76 : EventRecordVisitorI("genie::HG4BertCascIntranuke", config)
77 {
78  InitG4Particles();
79 }
80 //___________________________________________________________________________
81 HG4BertCascIntranuke::~HG4BertCascIntranuke()
82 {
83 }
84 //___________________________________________________________________________
85 int HG4BertCascIntranuke::G4BertCascade(GHepRecord * evrec) const{
86  GHepParticle* probe = evrec->Probe(); // incoming particle
87  GHepParticle* tgtNucl = evrec->TargetNucleus(); // target
88 
89 
90  const G4ParticleDefinition* incidentDef = PDGtoG4Particle(probe->Pdg() );
91 
92  int Zinit = tgtNucl->Z();
93  int Ainit = tgtNucl->A();
94 
95  G4InuclNuclei *theNucleus = new G4InuclNuclei(Ainit,Zinit);
96 
97 
98  const G4ThreeVector tgtmomentum(0.,0.,0.);
99  const G4double tgtEnergy =tgtNucl->Energy()*1000;
100  G4LorentzVector tgt4momentum(tgtmomentum,tgtEnergy);
101 
102  //
103  TLorentzVector *p4Genie = probe->P4();
104  //
105 
106  G4ThreeVector incidentDir(p4Genie->Vect().Unit().Px(),p4Genie->Vect().Unit().Py(),p4Genie->Vect().Unit().Pz());
107 
108  double dynamicMass = std::sqrt(p4Genie->M2() );
109  double incidentKE = p4Genie->E() - dynamicMass;
110  const G4DynamicParticle p(incidentDef, incidentDir, incidentKE/units::MeV, dynamicMass/units::MeV);
111  G4InuclElementaryParticle* incident = new G4InuclElementaryParticle(p,G4InuclParticle::bullet);
112 
113 
114  this->SetTrackingRadius(tgtNucl);
115  this->GenerateVertex(evrec);
116  fRemnA=Ainit;
117  fRemnZ=Zinit;
118 
119  GHepParticle * sp = new GHepParticle(*probe);
120  bool has_interacted = false;
121  while ( this-> IsInNucleus(sp) ) {
122  // advance the hadron by a step
124 
125  // check whether it interacts
126  double d = this->GenerateStep(evrec,sp);
127  has_interacted = (d<fHadStep);
128  if(has_interacted) break;
129  } //stepping
130 
131  if ( has_interacted ) {
132 
133  // Set up output and start the cascade
134  G4CollisionOutput cascadeOutput;
135  G4InuclCollider bertCollider;
136  bertCollider.useCascadeDeexcitation();
137  //collide
138  bertCollider.collide(incident,theNucleus,cascadeOutput);
139 
140  delete incident;
141  delete theNucleus;
142 
143  //
144  // Add Geant4 generated particles to the event record
145  //
146  TLorentzVector remX(0.,0.,0.,0.);
147  int Nfrag = cascadeOutput.numberOfOutgoingNuclei();
148  const std::vector<G4InuclNuclei>& outgoingFragments =
149  cascadeOutput.getOutgoingNuclei();
150  int npdg = 0;
151  fRemnZ = 0;
152  fRemnA = 0;
153 
154 
155  // Now the single hadrons
156  int Nhad = cascadeOutput.numberOfOutgoingParticles();
157  const std::vector<G4InuclElementaryParticle>& outgoingHadrons =
158  cascadeOutput.getOutgoingParticles();
159  for (int l = 0; l < Nhad; l++) {
160  npdg = outgoingHadrons[l].getDefinition()->GetPDGEncoding();
161  G4LorentzVector hadP = outgoingHadrons[l].getMomentum();
162  TLorentzVector tempP(hadP.px(), hadP.py(), hadP.pz(), hadP.e() );
163  GHepParticle new_particle(npdg, kIStStableFinalState, 0, 1,-1,-1,tempP, remX);
164  evrec->AddParticle(new_particle);
165  }
166 
167  if (Nfrag > 0) {
168  // Get largest nuclear fragment in output and call it the remnant
169  int maxA = 0;
170  int rem_index = 0;
171  for (int j = 0; j < Nfrag; j++) {
172  if (outgoingFragments[j].getA() > maxA) {
173  maxA = outgoingFragments[j].getA();
174  rem_index = j;
175  }
176  }
177 
178  fRemnZ = outgoingFragments[rem_index].getZ();
179  fRemnA = outgoingFragments[rem_index].getA();
180 
181  // Get remnant momentum from cascade
182  G4LorentzVector nucP = outgoingFragments[rem_index].getMomentum();
183  TLorentzVector remP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
184  npdg = outgoingFragments[rem_index].getDefinition()->GetPDGEncoding();
185  //Checks if the remnant is present i PDGLibrary
186  TParticlePDG * pdgRemn=PDGLibrary::Instance()->Find(npdg,false);
187 
188  if(!pdgRemn)
189  {
190  LOG("HG4BertCascIntranuke", pINFO)
191  << "NO Particle with pdg = " << npdg << " in PDGLibrary!";
192  // Add the particle with status id=15 and change it to HadroBlob
194  1,0,-1,-1, remP, remX);
195  evrec->AddParticle(largest_Fragment);
196  }
197  else
198  {
199  GHepParticle largest_Fragment(npdg, kIStStableFinalState,1,-1,-1,-1, remP, remX);
200  evrec->AddParticle(largest_Fragment);
201  }
202  // If any nuclear fragments left, add them to the event
203  for (G4int k = 0; k < Nfrag; k++) {
204  if (k != rem_index) {
205  npdg = outgoingFragments[k].getDefinition()->GetPDGEncoding();
206  nucP = outgoingFragments[k].getMomentum(); // need to boost by fRemnP4
207  TLorentzVector tempP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
208  GHepParticle nuclear_Fragment(npdg, kIStStableFinalState, 0, 1,-1,-1, tempP, remX);
209  evrec->AddParticle(nuclear_Fragment);
210  }
211  }
212  } // Nfrag > 0
213 
214  } else { // transparent event
215 
216  TLorentzVector p4h (0.,0.,probe->Pz(),probe->E());
217  TLorentzVector x4null(0.,0.,0.,0.);
218  TLorentzVector p4tgt (0.,0.,0.,tgtNucl->Mass());
219  evrec->AddParticle(probe->Pdg(), kIStStableFinalState, 0,-1,-1,-1, p4h,x4null);
220  evrec->AddParticle(tgtNucl->Pdg(), kIStStableFinalState, 1,-1,-1,-1,p4tgt,x4null);
221  }
222  delete sp;
223  return 0;
224 }
225 //___________________________________________________________________________
226 double HG4BertCascIntranuke::GenerateStep(GHepRecord* /*evrec*/, GHepParticle* p) const {
227  // Generate a step (in fermis) for particle p in the input event.
228  // Computes the mean free path L and generate an 'interaction' distance d
229  // from an exp(-d/L) distribution
230 
231  RandomGen * rnd = RandomGen::Instance();
232 
233  double LL = utils::intranuke2018::MeanFreePath(p->Pdg(), *p->X4(), *p->P4(),
234  fRemnA, fRemnZ,
235  fDelRPion, fDelRNucleon,
236  fUseOset, fAltOset,
237  fXsecNNCorr);
238 
239  double d = -1.*LL * TMath::Log(rnd->RndFsi().Rndm());
240 
241  return d;
242 }
243 //___________________________________________________________________________
244 void HG4BertCascIntranuke::ProcessEventRecord(GHepRecord* evrec) const
245 {
246  // Check the event generation mode: should be lepton-nucleus
247  fGMode = evrec->EventGenerationMode();
248  if ( fGMode== kGMdLeptonNucleus) {
249  LOG("HG4BertCascIntranuke", pINFO) << " Lepton-nucleus event generation mode ";
250  GHepParticle* nucltgt = evrec->TargetNucleus();
251  if (nucltgt) {
252  // Decide tracking radius for the current nucleus (few * R0 * A^1/3)
253  SetTrackingRadius(nucltgt);
254  } else {
255  LOG("HG4BertCascIntranuke", pINFO) << "No nuclear target found - exit ";
256  return;
257  }
258 
259  // Collect hadrons from initial interaction and track them through the
260  // nucleus using Bertini cascade
261  TransportHadrons(evrec);
262  } else if(fGMode == kGMdHadronNucleus || fGMode == kGMdPhotonNucleus){
263  G4BertCascade(evrec);
264  } else{
265  LOG("HG4BertCascIntranuke", pINFO) << " Inappropriate event generation mode - exit ";
266  return;
267  }
268 
269  LOG("HG4BertCascIntranuke", pINFO) << "Done with this event";
270 }
271 
272 //___________________________________________________________________________
273 void HG4BertCascIntranuke::InitG4Particles() const
274 {
275  G4LeptonConstructor::ConstructParticle();
276  G4MesonConstructor::ConstructParticle();
277  G4BaryonConstructor::ConstructParticle();
278  G4He3::He3();
279  G4Gamma::Gamma();
280  G4ParticleTable* pTable = G4ParticleTable::GetParticleTable();
281  pTable->SetReadiness(true);
282  G4GenericIon* gIon = G4GenericIon::Definition();
283  gIon->SetProcessManager(new G4ProcessManager(gIon) );
284 
285  // testing
286  const G4ParticleDefinition* electron = PDGtoG4Particle(11);
287  const G4ParticleDefinition* proton = PDGtoG4Particle(2212);
288  const G4ParticleDefinition* neutron = PDGtoG4Particle(2112);
289  const G4ParticleDefinition* piplus = PDGtoG4Particle(211);
290  LOG("HG4BertCascIntranuke", pINFO)
291  << "testing initialization of G4 particles \n"
292  << " e 0x" << electron << "\n"
293  << " p 0x" << proton << "\n"
294  << " n 0x" << neutron << "\n"
295  << " pi+ 0x" << piplus << "\n"
296  << "...InitG4Particles complete";
297  if ( electron == 0 || proton == 0 || neutron == 0 || piplus == 0 ) {
298  LOG("HG4BertCascIntranuke", pFATAL)
299  << "something is seriously wrong with g4 particle lookup";
300  exit(42);
301  }
302 }
303 
304 //___________________________________________________________________________
305 void HG4BertCascIntranuke::GenerateVertex(GHepRecord * evrec) const
306 {
307  // Sets a vertex in the nucleus periphery
308  // Called onlt in hadron/photon-nucleus interactions.
309 
310  GHepParticle * nucltgt = evrec->TargetNucleus();
311  assert(nucltgt);
312 
313  RandomGen * rnd = RandomGen::Instance();
314  TVector3 vtx(999999.,999999.,999999.);
315 
316  // *** For h+A events (test mode):
317  // Assume a hadron beam with uniform intensity across an area,
318  // so we need to choose events uniformly within that area.
319  double x=999999., y=999999., epsilon = 0.001;
320  double R2 = TMath::Power(fTrackingRadius,2.);
321  double rp2 = TMath::Power(x,2.) + TMath::Power(y,2.);
322  while(rp2 > R2-epsilon) {
323  x = (fTrackingRadius-epsilon) * rnd->RndFsi().Rndm();
324  y = -fTrackingRadius + 2*fTrackingRadius * rnd->RndFsi().Rndm();
325  y -= ((y>0) ? epsilon : -epsilon);
326  rp2 = TMath::Power(x,2.) + TMath::Power(y,2.);
327  }
328  vtx.SetXYZ(x,y, -1.*TMath::Sqrt(TMath::Max(0.,R2-rp2)) + epsilon);
329 
330  // get the actual unit vector along the incoming hadron direction
331  TVector3 direction = evrec->Probe()->P4()->Vect().Unit();
332 
333  // rotate the vtx position
334  vtx.RotateUz(direction);
335 
336  LOG("HG4BertCascIntranuke", pNOTICE)
337  << "Generated vtx @ R = " << vtx.Mag() << " fm / "
338  << print::Vec3AsString(&vtx);
339 
340  TObjArrayIter piter(evrec);
341  GHepParticle * p = 0;
342  while( (p = (GHepParticle *) piter.Next()) ) {
343  if ( pdg::IsPseudoParticle(p->Pdg()) ) continue;
344  if ( pdg::IsIon(p->Pdg()) ) continue;
345 
346  p->SetPosition(vtx.x(), vtx.y(), vtx.z(), 0.);
347  }
348 }
349 
350 //___________________________________________________________________________
351 void HG4BertCascIntranuke::SetTrackingRadius(const GHepParticle * p) const
352 {
353  assert(p && pdg::IsIon(p->Pdg()));
354  double A = p->A();
355  fTrackingRadius = fR0*TMath::Power(A, 1./3.);
356 
357  // multiply that by some input factor so that hadrons are tracked
358  // beyond the nuclear 'boundary' since the nuclear density distribution
359  // is not zero there
360  fTrackingRadius *= fNR;
361 
362  LOG("HG4BertCascIntranuke", pNOTICE)
363  << "Setting tracking radius to R = " << fTrackingRadius;
364 }
365 
366 //___________________________________________________________________________
367 bool HG4BertCascIntranuke::IsInNucleus(const GHepParticle * p) const
368 {
369  // check whether the input particle is still within the nucleus
370  return (p->X4()->Vect().Mag() < fTrackingRadius + fHadStep);
371 }
372 //___________________________________________________________________________
373 void HG4BertCascIntranuke::TransportHadrons(GHepRecord * evrec) const
374 {
375  // Set up nucleus through which hadrons will be propagated
376  // In frozen nucleus approximation it is the remnant nucleus corrected for
377  // final state lepton charge
378 
379  GHepParticle* tgtNucl = evrec->TargetNucleus();
380  GHepParticle* remNucl = evrec->RemnantNucleus();
381  GHepParticle* struckNucleon = evrec->HitNucleon();
382 
383  int inucl = evrec->RemnantNucleusPosition();
384 
385  // double sepEnergy = tgtNucl->Mass() - remNucl->Mass() - struckNucleon->Mass();
386  // std::cout << " sepEnergy = " << sepEnergy << std::endl;
387 
388  GHepParticle* p = 0;
389  const G4ParticleDefinition* incidentDef = 0;
390  GHepParticle* incidentBaryon = 0;
391  TObjArrayIter piter(evrec);
392  TObjArrayIter pitter(evrec);
393  TObjArrayIter pittter(evrec);
394  int icurr =-1;
395  bool has_incidentBaryon(false), has_secondaries(false);
396  bool has_remnant(false), has_incidentparticle(false);
397 
398  fRemnA=remNucl->A();
399  fRemnZ=remNucl->Z();
400 
401  while( (p = (GHepParticle*) piter.Next()) ) {
402  icurr++;
403  bool has_interacted(false);
404  if ( ! this->NeedsRescattering(p) ) continue;
405 
406  GHepParticle * sp = new GHepParticle(*p);
407  sp->SetFirstMother(icurr);
408 
409  if ( ! this->CanRescatter(sp) ) {
411  evrec->AddParticle(*sp);
412  evrec->Particle(sp->FirstMother())->SetRescatterCode(1);
413  delete sp;
414  continue;
415  }
416 
417  while ( this-> IsInNucleus(sp) ) {
418  // advance the hadron by a step
420  double d = this->GenerateStep(evrec,sp);
421  has_interacted = (d<fHadStep);
422  if ( has_interacted ) {
423  has_secondaries=true;
424  break;
425  }
426  } //stepping
427  if ( ! has_interacted ) {
429  evrec->AddParticle(*sp);
430  evrec->Particle(sp->FirstMother())->SetRescatterCode(1);
431  //rwh-unused//transparents=true;
432  }
433  if ( ! has_incidentBaryon && sp->Status() == kIStHadronInTheNucleus ) {
434  if ( IsBaryon(sp) ) {
435  incidentBaryon = new GHepParticle(*sp);
436  incidentDef = PDGtoG4Particle(sp->Pdg() );
437  has_incidentBaryon=true;
438  } else {
439  if (sp->Pdg() == kPdgProton ||
440  sp->Pdg() == kPdgNeutron||
441  sp->Pdg() == kPdgLambda ||
442  sp->Pdg() == kPdgSigmaP ||
443  sp->Pdg() == kPdgSigma0 ||
444  sp->Pdg() == kPdgSigmaM ) {
445  LOG("G4BertCascInterface::TransportHadrons", pWARN)
446  << "IsBaryon failed to tag " << *sp;
447  }
448  }
449  }
450  delete sp;
451  }
452 
453  int Nsec(0);
454  std::vector<int> Postion_evrec;
455  if ( has_secondaries ) {
456  if ( ! incidentBaryon ) LOG("G4BertCascInterface::TransportHadrons", pINFO)
457  << "Unrecognized baryon in nucleus";
458 
459  delete incidentBaryon;
460  G4Fancy3DNucleus* g4Nucleus = new G4Fancy3DNucleus();
461 
462  TLorentzVector pIncident;
463 
464  g4Nucleus->Init(remNucl->A(),remNucl->Z());
465  double EE = struckNucleon->E() - tgtNucl->Mass() + g4Nucleus->GetMass()*units::MeV;
466  TLorentzVector struckMomentum(struckNucleon->Px(), struckNucleon->Py(), struckNucleon->Pz(), EE);
467  Double_t PxI(0),PyI(0),PzI(0),EEI(0), Q(0), P(0), N(0);
468  int icccur=-1;
469  int pos_in_evrec(0);
470  while( (p = (GHepParticle*) pitter.Next()) ) {
471  icccur++;
472  if (p->Status() == kIStHadronInTheNucleus && this->CanRescatter(p) && p->RescatterCode()!=1) {
473  PxI+=p->P4()->Px();
474  PyI+=p->P4()->Py();
475  PzI+=p->P4()->Pz();
476  EEI+=p->P4()->E();
477  Q+=p->Charge()/3;
478  if ( pos_in_evrec==0 ) pos_in_evrec = icccur;
479  Postion_evrec.push_back(icccur);
480  if (genie::pdg::IsProton(p->Pdg())) P++;
481  if (genie::pdg::IsNeutron(p->Pdg())) N++;
482  if ( pos_in_evrec==0 ) pos_in_evrec = icccur;
483  if ( ! has_incidentparticle ) { // take the baryon as incident particle
484  if ( IsBaryon(p) ) {
485  incidentDef = PDGtoG4Particle(p->Pdg() );
486  has_incidentparticle=true;
487  }
488  }
489  }
490  }
491  if ( ! has_incidentparticle) {
492  GHepParticle * pinN = evrec->Particle(pos_in_evrec);
493  incidentDef=PDGtoG4Particle(pinN->Pdg()); // if no baryon among the secondaries
494  }
495  if (P == 2) incidentDef = PDGtoG4Particle(kPdgClusterPP);
496  else if (N == 2) incidentDef = PDGtoG4Particle(kPdgClusterNN);
497  else if (P == 1 && N == 1) incidentDef = PDGtoG4Particle(kPdgClusterNP);
498 
499 
500  pIncident.SetPxPyPzE(PxI,PyI,PzI,EEI);
501 
502 
503  G4ThreeVector incidentDir(pIncident.Vect().Unit().Px(),
504  pIncident.Vect().Unit().Py(),
505  pIncident.Vect().Unit().Pz());
506 
507  double dynamicMass = std::sqrt(pIncident.M2() );
508  double incidentKE = pIncident.E() - dynamicMass;
509  // Create pseudo-particle to supply Bertini collider with bullet
510 
511  G4DynamicParticle dp(incidentDef, incidentDir, incidentKE/units::MeV, dynamicMass/units::MeV);
512  dp.SetCharge(Q);
513 
514  G4InuclElementaryParticle* incident = new G4InuclElementaryParticle(dp,G4InuclParticle::bullet);
515 
516  // Get hadronic secondaries and convert them to G4KineticTracks
517 
518  G4KineticTrackVector* g4secondaries = ConvertGenieSecondariesToG4(evrec);
519 
520  Nsec = g4secondaries->size();
521 
522  // Set up output and start the cascade
523  G4CollisionOutput cascadeOutput;
524  G4InuclCollider bertCollider;
525  bertCollider.useCascadeDeexcitation();
526  // bertCollider.setVerboseLevel(3);
527  bertCollider.rescatter(incident, g4secondaries, g4Nucleus, cascadeOutput);
528  delete incident;
529  delete g4Nucleus;
530  for (int n = 0; n < Nsec; n++) delete (*g4secondaries)[n];
531  delete g4secondaries;
532 
533  //
534  // Add Geant4 generated particles to the event record
535  //
536  TLorentzVector remX(tgtNucl->Vx(), tgtNucl->Vy(), tgtNucl->Vz(), tgtNucl->Vt() );
537 
538  int rem_nucl = evrec->RemnantNucleusPosition(); // position in array
539  int Nfrag = cascadeOutput.numberOfOutgoingNuclei();
540  const std::vector<G4InuclNuclei>& outgoingFragments = cascadeOutput.getOutgoingNuclei();
541  int npdg = 0;
542  fRemnZ = 0;
543  fRemnA = 0;
544 
545 
546  // Now the single hadrons
547  int Nhad = cascadeOutput.numberOfOutgoingParticles();
548  const std::vector<G4InuclElementaryParticle>& outgoingHadrons = cascadeOutput.getOutgoingParticles();
549 
550  int mother1=Postion_evrec.at(0);
551  int mother2(0);
552  if(Nsec==1)mother2=-1;
553  else if(Nsec>1)mother2=Postion_evrec.at(Nsec-1);
554  for (int l = 0; l < Nhad; l++) {
555  npdg = outgoingHadrons[l].getDefinition()->GetPDGEncoding();
556 
557  G4LorentzVector hadP = outgoingHadrons[l].getMomentum();
558  TLorentzVector tempP(hadP.px(), hadP.py(), hadP.pz(), hadP.e() );
559 
560  GHepParticle new_particle(npdg, kIStStableFinalState,mother1, mother2,-1,-1,tempP, remX);
561  evrec->AddParticle(new_particle);
562  }
563 
564  if (Nfrag > 0) {
565  int maxA = 0;
566  int rem_index = 0;
567  for (int j = 0; j < Nfrag; j++) {
568  if (outgoingFragments[j].getA() > maxA) {
569  maxA = outgoingFragments[j].getA();
570  rem_index = j;
571  }
572  }
573 
574  fRemnZ = outgoingFragments[rem_index].getZ();
575  fRemnA = outgoingFragments[rem_index].getA();
576 
577  // Get remnant momentum from cascade
578  G4LorentzVector nucP = outgoingFragments[rem_index].getMomentum();
579  TLorentzVector remP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
580 
581  // If any nuclear fragments left, add them to the event
582  for (G4int k = 0; k < Nfrag; k++) {
583  if (k != rem_index) {
584  npdg = outgoingFragments[k].getDefinition()->GetPDGEncoding();
585  nucP = outgoingFragments[k].getMomentum(); // need to boost by fRemnP4
586  TLorentzVector tempP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
587 
588  GHepParticle nuclear_Fragment(npdg, kIStStableFinalState, rem_nucl,-1,-1,-1,tempP, remX);
589  evrec->AddParticle(nuclear_Fragment);
590  }
591  }
592 
593  // Get largest nuclear fragment in output and call it the remnant
594  npdg = outgoingFragments[rem_index].getDefinition()->GetPDGEncoding();
595  remP.SetPx(remP.Px()+remNucl->P4()->Px());
596  remP.SetPy(remP.Py()+remNucl->P4()->Py());
597  remP.SetPz(remP.Pz()+remNucl->P4()->Pz());
598 
599  //Checks if the remnant is present i PDGLibrary
600  TParticlePDG * pdgRemn=PDGLibrary::Instance()->Find(npdg,false);
601  if(!pdgRemn)
602  {
603  LOG("HG4BertCascIntranuke", pINFO)
604  << "NO Particle with pdg = " << npdg << " in PDGLibrary!";
605  // Add the particle with status id=15 and change it to HadroBlob
607  rem_nucl,-1,-1,-1, remP, remX);
608  evrec->AddParticle(largest_Fragment);
609  }
610  else
611  {
612  GHepParticle largest_Fragment(npdg, kIStStableFinalState,rem_nucl,-1,-1,-1, remP, remX);
613  evrec->AddParticle(largest_Fragment);
614  }
615  } // Nfrag > 0
616  has_remnant=true;
617  }
618  // Mark the initial remnant nucleus as an intermediate state
619  if(!has_remnant){
620  GHepParticle * sp = new GHepParticle(*evrec->Particle(inucl));
621  sp->SetFirstMother(inucl);
623  evrec->AddParticle(*sp);
624  delete sp;
625  }
626  evrec->Particle(inucl)->SetStatus(kIStIntermediateState);
627  // Tests
628  int dau1(0), dau2(0);
629  if(Nsec>1){
630  GHepParticle * pinN = evrec->Particle(Postion_evrec.at(0));
631  dau1=pinN->FirstDaughter();
632  dau2=pinN->LastDaughter();
633  for(int ii=1;ii<Nsec;ii++){
634  evrec->Particle(Postion_evrec.at(ii))->SetFirstDaughter(dau1);
635  evrec->Particle(Postion_evrec.at(ii))->SetLastDaughter(dau2);
636  }
637  }
638 
639 
640  // Geant4 conservation test
641  // this probably isn't configured right ... skip it for now
642  /*
643  if ( Conserve4Momentum(evrec) ) {
644  std::cout << " Energy conservation test " << std::endl;
645  }
646  */
647 
648 }
649 
650 //____________________________________________________________________________
651 bool HG4BertCascIntranuke::NeedsRescattering(const GHepParticle * p) const {
652  // checks whether the particle should be rescattered
653  assert(p);
654  // attempt to rescatter anything marked as 'hadron in the nucleus' (14)
655  return ( p->Status() == kIStHadronInTheNucleus );
656 }
657 
658 //___________________________________________________________________________
659 bool HG4BertCascIntranuke::CanRescatter(const GHepParticle * p) const
660 {
661  assert(p);
662  return ( p->Pdg() == kPdgPiP ||
663  p->Pdg() == kPdgPiM ||
664  p->Pdg() == kPdgPi0 ||
665  p->Pdg() == kPdgProton ||
666  p->Pdg() == kPdgAntiProton ||
667  p->Pdg() == kPdgNeutron ||
668  p->Pdg() == kPdgKP ||
669  p->Pdg() == kPdgKM ||
670  p->Pdg() == kPdgK0 ||
671  p->Pdg() == kPdgK0L ||
672  p->Pdg() == kPdgSigma0 ||
673  p->Pdg() == kPdgSigmaM ||
674  p->Pdg() == kPdgSigmaP ||
675  //p->Pdg() == kPdgSigmaPPc ||
676  p->Pdg() == kPdgXiM ||
677  p->Pdg() == kPdgXi0 ||
678  p->Pdg() == kPdgLambda
679  );
680 }
681 
682 //___________________________________________________________________________
683 bool HG4BertCascIntranuke::IsBaryon(const GHepParticle * p) const
684 {
685  // use PDGLibrary to determine if the particle is baryon
686  assert(p);
687 
688  TParticlePDG * ppdg = PDGLibrary::Instance()->Find(p->Pdg());
689  if ( ! ppdg ) {
690  LOG("G4BertCascInterface", pWARN)
691  << "no entry for PDG " << p->Pdg() << " in PDGLibrary";
692  } else {
693  if ( std::string(ppdg->ParticleClass()) == std::string("Baryon") ) {
694  return true;
695  }
696  }
697  return false;
698 }
699 //___________________________________________________________________________
700 const G4ParticleDefinition* HG4BertCascIntranuke::PDGtoG4Particle(int pdg) const
701 {
702  const G4ParticleDefinition* pDef = 0;
703 
704  if (pdg == kPdgClusterPP) return G4Diproton::Diproton();
705  if (pdg == kPdgClusterNN) return G4Dineutron::Dineutron();
706  if (pdg == kPdgClusterNP) return G4UnboundPN::UnboundPN();
707 
708  if ( abs(pdg) < 1000000000 ) {
709  pDef = G4ParticleTable::GetParticleTable()->FindParticle(pdg);
710  } else if ( pdg < 2000000000 ) {
711  pDef = G4IonTable::GetIonTable()->GetIon(pdg);
712  }
713 
714  if ( ! pDef ) {
715  LOG("HG4BertCascIntranuke", pWARN)
716  << "Unrecognized Bertini particle type: " << pdg;
717  }
718 
719  return pDef;
720 }
721 
722 //___________________________________________________________________________
723 G4KineticTrackVector* HG4BertCascIntranuke::ConvertGenieSecondariesToG4(std::vector<GHepParticle> partList) const
724 {
725  static double GeToG4length = 2.81967*1.0e-12*1.2/1.4;
726 
727  GHepParticle* p = 0;
728  const G4ParticleDefinition* pDef = 0;
729  G4KineticTrackVector* g4secondaries = new G4KineticTrackVector;
730  G4KineticTrack* kt = 0;
731 
732  for (size_t it=0 ; it<partList.size(); it++) {
733  p= &partList.at(it);
734  pDef = PDGtoG4Particle(p->Pdg() );
735  double formationTime = p->Vt();
736  G4ThreeVector formationPosition(p->Vx()*GeToG4length,
737  p->Vy()*GeToG4length,
738  p->Vz()*GeToG4length);
739  G4LorentzVector formationMomentum(p->Px()/units::MeV, p->Py()/units::MeV,
740  p->Pz()/units::MeV, p->E()/units::MeV );
741  kt = new G4KineticTrack(pDef, formationTime, formationPosition, formationMomentum);
742  kt->SetDefinition(pDef); // defeat reset to K0L/K0S in ctor
743  kt->SetState(G4KineticTrack::inside);
744  g4secondaries->push_back(kt);
745  }
746 
747  return g4secondaries;
748 }
749 
750 //___________________________________________________________________________
751 G4KineticTrackVector* HG4BertCascIntranuke::ConvertGenieSecondariesToG4(GHepRecord* evrec) const {
752  // Get hadronic secondaries from event record and convert them to
753  // G4KineticTracks for use in cascade
754 
755  // distance units: Geant4 mm = 1.0, GENIE fermi = 1.0 => conversion 1e-12
756  // nuclear radius parameter R0: Geant4 2.81967*1.2, GENIE = 1.4 => conversion 2.41686
757  static double GeToG4length = 2.81967*1.0e-12*1.2/1.4;
758 
759  TObjArrayIter piter(evrec);
760  GHepParticle* p = 0;
761  const G4ParticleDefinition* pDef = 0;
762  G4KineticTrackVector* g4secondaries = new G4KineticTrackVector;
763  G4KineticTrack* kt = 0;
764 
765  while( (p = (GHepParticle*) piter.Next()) ) {
766  if ( p->Status() == kIStHadronInTheNucleus &&
767  this->CanRescatter(p) && ( p->RescatterCode() != 1) ) {
768  pDef = PDGtoG4Particle(p->Pdg() );
769  double formationTime = p->Vt();
770  G4ThreeVector formationPosition(p->Vx()*GeToG4length,
771  p->Vy()*GeToG4length,
772  p->Vz()*GeToG4length);
773  G4LorentzVector formationMomentum(p->Px()/units::MeV, p->Py()/units::MeV,
774  p->Pz()/units::MeV, p->E()/units::MeV );
775  kt = new G4KineticTrack(pDef, formationTime,
776  formationPosition, formationMomentum);
777  kt->SetDefinition(pDef); // defeat reset to K0L/K0S in ctor
778  kt->SetState(G4KineticTrack::inside);
779  g4secondaries->push_back(kt);
780  }
781  }
782 
783  return g4secondaries;
784 }
785 
786 //___________________________________________________________________________
787 bool HG4BertCascIntranuke::Conserve4Momentum(GHepRecord* evrec) const
788 {
789  bool failed = false;
790 
791  GHepParticle* probe = evrec->Probe(); // incoming neutrino
792  GHepParticle* targetNucleus = evrec->TargetNucleus();
793  GHepParticle* finalLepton = evrec->FinalStatePrimaryLepton();
794 
795  int Nentries = evrec->GetEntries();
796 
797  // Collect 4-momenta of final state particles
798  GHepParticle* p = 0;
799  TLorentzVector sum4mom(0.0, 0.0, 0.0, 0.0);
800  for (int j = 0; j < Nentries; j++) {
801  p = (GHepParticle*) (*evrec)[j];
802  if (p->FirstMother() == evrec->RemnantNucleusPosition() ) {
803  sum4mom += *(p->P4() );
804  LOG("HG4BertCascIntranuke", pINFO)
805  << " Final state 4-momentum = ("
806  << p->P4()->Px() << ", " << p->P4()->Py() << ", "
807  << p->P4()->Pz() << ", " << p->P4()->E() << ") ";
808  }
809  }
810  sum4mom += *(finalLepton->P4() );
811 
812  TLorentzVector initial4mom = *(targetNucleus->P4() ) + *(probe->P4() );
813 
814  TLorentzVector diff = initial4mom - sum4mom;
815  // rwh need some threshold for acceptable differences
816  const double maxdiff = 1.0e-9; // set crazy small for now
817  double diffE = diff.E();
818  TVector3 diffp3 = diff.Vect();
819  double diffpmag = diffp3.Mag();
820  if ( TMath::Abs(diffE) > maxdiff || diffpmag > maxdiff ) {
821  failed = true;
822  LOG("HG4BertCascIntranuke", pWARN)
823  << "final state - initial state differs by > " << maxdiff << "\n"
824  << " dE = " << diffE << ", d|p3| = " << diffpmag;
825 
826  LOG("HG4BertCascIntranuke", pWARN)
827  << " Total Final state 4-momentum = (" << sum4mom.Px()
828  << ", " << sum4mom.Py()
829  << ", " << sum4mom.Pz()
830  << ", " << sum4mom.E() << ") ";
831  LOG("HG4BertCascIntranuke", pWARN)
832  << " Total Initial state 4-momentum = (" << initial4mom.Px()
833  << ", " << initial4mom.Py()
834  << ", " << initial4mom.Pz()
835  << ", " << initial4mom.E() << ") ";
836  }
837 
838  // Charge conservation
839  double Qinit = targetNucleus->Charge();
840  double Qfinal = finalLepton->Charge();
841 
842  for (int j = 0; j < Nentries; j++) {
843  p = (GHepParticle*) (*evrec)[j];
844  if ( p->FirstMother() == evrec->RemnantNucleusPosition() ) {
845  Qfinal += p->Charge();
846  }
847  }
848 
849  if (Qinit != Qfinal) {
850  failed = true;
851  LOG("HG4BertCascIntranuke", pWARN)
852  << " Charge not conserved: \n"
853  << " Qfinal = " << Qfinal
854  << " Qinit = " << Qinit;
855  }
856 
857  return ( ! failed );
858 }
859 
860 
861 //___________________________________________________________________________
862 void HG4BertCascIntranuke::LoadConfig(void)
863 {
864  // fermi momentum setup
865  // this is specifically set in Intranuke2018::Configure(string)
866  fNuclmodel = dynamic_cast<const NuclearModelI *>( this -> SubAlg("NuclearModel") ) ;
867 
868  // other intranuke config params
869  GetParam( "NUCL-R0", fR0 ); // fm
870  GetParam( "NUCL-NR", fNR );
871 
872  GetParam( "INUKE-NucRemovalE", fNucRmvE ); // GeV
873  GetParam( "INUKE-HadStep", fHadStep ) ;
874  GetParam( "INUKE-NucAbsFac", fNucAbsFac ) ;
875  GetParam( "INUKE-NucCEXFac", fNucCEXFac ) ;
876  GetParam( "INUKE-Energy_Pre_Eq", fEPreEq ) ;
877  GetParam( "INUKE-FermiFac", fFermiFac ) ;
878  GetParam( "INUKE-FermiMomentum", fFermiMomentum ) ;
879  GetParam( "INUKE-DoFermi", fDoFermi ) ;
880  GetParam( "INUKE-XsecNNCorr", fXsecNNCorr ) ;
881  GetParamDef( "UseOset", fUseOset, false ) ;
882  GetParamDef( "AltOset", fAltOset, false ) ;
883  GetParam( "HNINUKE-DelRPion", fDelRPion ) ;
884  GetParam( "HNINUKE-DelRNucleon", fDelRNucleon ) ;
885 
886  // report
887  LOG("HG4BertCascIntranuke", pNOTICE)
888  << "Settings for INTRANUKE mode: " << INukeMode::AsString(kIMdHA) << "\n"
889  << "R0 = " << fR0 << " fermi" << "\n"
890  << "NR = " << fNR << "\n"
891  << "DelRPion = " << fDelRPion << "\n"
892  << "DelRNucleon = " << fDelRNucleon << "\n"
893  << "HadStep = " << fHadStep << " fermi" << "\n"
894  << "EPreEq = " << fHadStep << " fermi" << "\n"
895  << "NucAbsFac = " << fNucAbsFac << "\n"
896  << "NucCEXFac = " << fNucCEXFac << "\n"
897  << "FermiFac = " << fFermiFac << "\n"
898  << "FermiMomtm = " << fFermiMomentum << "\n"
899  << "DoFermi? = " << ((fDoFermi)?(true):(false)) << "\n"
900  << "XsecNNCorr? = " << ((fXsecNNCorr)?(true):(false));
901 
902 }
903 
904 //___________________________________________________________________________
905 
906 void HG4BertCascIntranuke::Configure(const Registry & config)
907 {
908  Algorithm::Configure(config);
909  LoadConfig();
910 }
911 
912 //___________________________________________________________________________
913 void HG4BertCascIntranuke::Configure(string param_set)
914 {
915  Algorithm::Configure(param_set);
916  LoadConfig();
917 }
918 
919 //___________________________________________________________________________
920 #endif // __GENIE_GEANT4_INTERFACE_ENABLED__
static string AsString(INukeMode_t mode)
Definition: INukeMode.h:41
int Z(void) const
void SetFirstMother(int m)
Definition: GHepParticle.h:132
int RescatterCode(void) const
Definition: GHepParticle.h:65
virtual GHepParticle * Particle(int position) const
Definition: GHepRecord.cxx:104
TRandom3 & RndFsi(void) const
rnd number generator used by intranuclear cascade monte carlos
Definition: RandomGen.h:59
const int kPdgXi0
Definition: PDGCodes.h:93
double E(void) const
Get energy.
Definition: GHepParticle.h:91
const int kPdgLambda
Definition: PDGCodes.h:85
static RandomGen * Instance()
Access instance.
Definition: RandomGen.cxx:71
const TLorentzVector * P4(void) const
Definition: GHepParticle.h:78
Defines the EventRecordVisitorI interface. Concrete implementations of this interface use the &#39;Visito...
int FirstDaughter(void) const
Definition: GHepParticle.h:68
const int kPdgHadronicBlob
Definition: PDGCodes.h:211
virtual int RemnantNucleusPosition(void) const
Definition: GHepRecord.cxx:397
const int kPdgClusterNP
Definition: PDGCodes.h:215
void StepParticle(GHepParticle *p, double step, double nuclear_radius=-1.)
Step particle.
#define pFATAL
Definition: Messenger.h:56
const int kPdgSigma0
Definition: PDGCodes.h:88
Pure abstract base class. Defines the NuclearModelI interface to be implemented by any physics model ...
Definition: NuclearModelI.h:46
double Mass(void) const
Mass that corresponds to the PDG code.
static constexpr double MeV
Definition: Units.h:129
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition: RandomGen.h:29
double Pz(void) const
Get Pz.
Definition: GHepParticle.h:90
GHepStatus_t Status(void) const
Definition: GHepParticle.h:64
double Energy(void) const
Get energy.
Definition: GHepParticle.h:92
const int kPdgClusterNN
Definition: PDGCodes.h:214
double Px(void) const
Get Px.
Definition: GHepParticle.h:88
const double epsilon
virtual GHepParticle * Probe(void) const
Definition: GHepRecord.cxx:284
const int kPdgK0
Definition: PDGCodes.h:174
double Vt(void) const
Get production time.
Definition: GHepParticle.h:97
int Pdg(void) const
Definition: GHepParticle.h:63
int FirstMother(void) const
Definition: GHepParticle.h:66
bool IsNeutron(int pdgc)
Definition: PDGUtils.cxx:341
void SetPosition(const TLorentzVector &v4)
int LastDaughter(void) const
Definition: GHepParticle.h:69
bool IsProton(int pdgc)
Definition: PDGUtils.cxx:336
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
Definition: Messenger.h:96
static constexpr double A
Definition: Units.h:74
const int kPdgKM
Definition: PDGCodes.h:173
virtual GHepParticle * FinalStatePrimaryLepton(void) const
Definition: GHepRecord.cxx:333
virtual void Configure(const Registry &config)
Definition: Algorithm.cxx:62
GEvGenMode_t EventGenerationMode(void) const
Definition: GHepRecord.cxx:209
const int kPdgKP
Definition: PDGCodes.h:172
const int kPdgPiP
Definition: PDGCodes.h:158
const int kPdgPi0
Definition: PDGCodes.h:160
double Charge(void) const
Chrg that corresponds to the PDG code.
virtual GHepParticle * TargetNucleus(void) const
Definition: GHepRecord.cxx:293
#define pINFO
Definition: Messenger.h:62
const int kPdgK0L
Definition: PDGCodes.h:176
double MeanFreePath(int pdgc, const TLorentzVector &x4, const TLorentzVector &p4, double A, double Z, double nRpi=0.5, double nRnuc=1.0, const bool useOset=false, const bool altOset=false, const bool xsecNNCorr=false, string INukeMode="XX2018")
Mean free path (pions, nucleons)
#define pWARN
Definition: Messenger.h:60
const int kPdgSigmaM
Definition: PDGCodes.h:89
static PDGLibrary * Instance(void)
Definition: PDGLibrary.cxx:68
const int kPdgXiM
Definition: PDGCodes.h:94
bool IsIon(int pdgc)
Definition: PDGUtils.cxx:42
double Vz(void) const
Get production z.
Definition: GHepParticle.h:96
const TLorentzVector * X4(void) const
Definition: GHepParticle.h:79
void SetStatus(GHepStatus_t s)
Definition: GHepParticle.h:126
A registry. Provides the container for algorithm configuration parameters.
Definition: Registry.h:65
bool IsPseudoParticle(int pdgc)
Definition: PDGUtils.cxx:27
virtual GHepParticle * HitNucleon(void) const
Definition: GHepRecord.cxx:313
void Configure(string mesg)
Definition: gEvServ.cxx:196
int getA(int pdg)
virtual GHepParticle * RemnantNucleus(void) const
Definition: GHepRecord.cxx:303
const int kPdgAntiProton
Definition: PDGCodes.h:82
const int kPdgPiM
Definition: PDGCodes.h:159
const int kPdgSigmaP
Definition: PDGCodes.h:87
virtual void AddParticle(const GHepParticle &p)
Definition: GHepRecord.cxx:499
const int kPdgProton
Definition: PDGCodes.h:81
TParticlePDG * Find(int pdgc, bool must_exist=true)
Definition: PDGLibrary.cxx:86
double Vy(void) const
Get production y.
Definition: GHepParticle.h:95
int A(void) const
#define pNOTICE
Definition: Messenger.h:61
const int kPdgNeutron
Definition: PDGCodes.h:83
GENIE&#39;s GHEP MC event record.
Definition: GHepRecord.h:45
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:39
string Vec3AsString(const TVector3 *vec)
Definition: PrintUtils.cxx:80
double Vx(void) const
Get production x.
Definition: GHepParticle.h:94
const int kPdgClusterPP
Definition: PDGCodes.h:216
double Py(void) const
Get Py.
Definition: GHepParticle.h:89