1 #include "Framework/Conventions/GBuild.h" 2 #ifdef __GENIE_GEANT4_INTERFACE_ENABLED__ 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" 56 using std::ostringstream;
58 using namespace genie;
65 HG4BertCascIntranuke::HG4BertCascIntranuke()
72 HG4BertCascIntranuke::HG4BertCascIntranuke(
string config)
78 HG4BertCascIntranuke::~HG4BertCascIntranuke()
82 int HG4BertCascIntranuke::G4BertCascade(
GHepRecord * evrec)
const{
87 const G4ParticleDefinition* incidentDef = PDGtoG4Particle(probe->
Pdg() );
89 int Zinit = tgtNucl->
Z();
90 int Ainit = tgtNucl->
A();
92 G4InuclNuclei *theNucleus =
new G4InuclNuclei(Ainit,Zinit);
95 const G4ThreeVector tgtmomentum(0.,0.,0.);
96 const G4double tgtEnergy =tgtNucl->
Energy()*1000;
97 G4LorentzVector tgt4momentum(tgtmomentum,tgtEnergy);
100 TLorentzVector *p4Genie = probe->
P4();
103 G4ThreeVector incidentDir(p4Genie->Vect().Unit().Px(),p4Genie->Vect().Unit().Py(),p4Genie->Vect().Unit().Pz());
105 double dynamicMass = std::sqrt(p4Genie->M2() );
106 double incidentKE = p4Genie->E() - dynamicMass;
108 G4InuclElementaryParticle* incident =
new G4InuclElementaryParticle(
p,G4InuclParticle::bullet);
117 bool has_interacted =
false;
125 if(has_interacted)
break;
128 if ( has_interacted ) {
131 G4CollisionOutput cascadeOutput;
132 G4InuclCollider bertCollider;
133 bertCollider.useCascadeDeexcitation();
135 bertCollider.collide(incident,theNucleus,cascadeOutput);
143 TLorentzVector remX(0.,0.,0.,0.);
144 int Nfrag = cascadeOutput.numberOfOutgoingNuclei();
145 const std::vector<G4InuclNuclei>& outgoingFragments =
146 cascadeOutput.getOutgoingNuclei();
153 int Nhad = cascadeOutput.numberOfOutgoingParticles();
154 const std::vector<G4InuclElementaryParticle>& outgoingHadrons =
155 cascadeOutput.getOutgoingParticles();
156 for (
int l = 0;
l < Nhad;
l++) {
157 npdg = outgoingHadrons[
l].getDefinition()->GetPDGEncoding();
158 G4LorentzVector hadP = outgoingHadrons[
l].getMomentum();
159 TLorentzVector tempP(hadP.px(), hadP.py(), hadP.pz(), hadP.e() );
161 0, 1,-1,-1,tempP, remX);
169 for (
int j = 0; j < Nfrag; j++) {
170 if (outgoingFragments[j].
getA() > maxA) {
171 maxA = outgoingFragments[j].getA();
176 fRemnZ = outgoingFragments[rem_index].getZ();
177 fRemnA = outgoingFragments[rem_index].getA();
180 G4LorentzVector nucP = outgoingFragments[rem_index].getMomentum();
181 TLorentzVector remP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
182 npdg = outgoingFragments[rem_index].getDefinition()->GetPDGEncoding();
184 1,0,-1,-1, remP, remX);
188 for (G4int
k = 0;
k < Nfrag;
k++) {
189 if (
k != rem_index) {
190 npdg = outgoingFragments[
k].getDefinition()->GetPDGEncoding();
191 nucP = outgoingFragments[
k].getMomentum();
192 TLorentzVector tempP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
202 TLorentzVector p4h (0.,0.,probe->
Pz(),probe->
E());
203 TLorentzVector x4null(0.,0.,0.,0.);
204 TLorentzVector p4tgt (0.,0.,0.,tgtNucl->
Mass());
206 0,-1,-1,-1, p4h,x4null);
208 1,-1,-1,-1,p4tgt,x4null);
214 double HG4BertCascIntranuke::GenerateStep(
GHepRecord* ,
228 double d = -1.*LL * TMath::Log(rnd->
RndFsi().Rndm());
233 void HG4BertCascIntranuke::ProcessEventRecord(
GHepRecord* evrec)
const 239 <<
" Lepton-nucleus event generation mode ";
245 LOG(
"HG4BertCascIntranuke",
pINFO) <<
"No nuclear target found - exit ";
254 G4BertCascade(evrec);
257 <<
" Inappropriate event generation mode - exit ";
261 LOG(
"HG4BertCascIntranuke",
pINFO) <<
"Done with this event";
265 void HG4BertCascIntranuke::InitG4Particles()
const 267 G4LeptonConstructor::ConstructParticle();
268 G4MesonConstructor::ConstructParticle();
269 G4BaryonConstructor::ConstructParticle();
272 G4ParticleTable* pTable = G4ParticleTable::GetParticleTable();
273 pTable->SetReadiness(
true);
274 G4GenericIon* gIon = G4GenericIon::Definition();
275 gIon->SetProcessManager(
new G4ProcessManager(gIon) );
278 const G4ParticleDefinition* electron = PDGtoG4Particle(11);
279 const G4ParticleDefinition* proton = PDGtoG4Particle(2212);
280 const G4ParticleDefinition* neutron = PDGtoG4Particle(2112);
281 const G4ParticleDefinition* piplus = PDGtoG4Particle(211);
283 <<
"testing initialization of G4 particles \n" 284 <<
" e 0x" << electron <<
"\n" 285 <<
" p 0x" << proton <<
"\n" 286 <<
" n 0x" << neutron <<
"\n" 287 <<
" pi+ 0x" << piplus <<
"\n" 288 <<
"...InitG4Particles complete";
289 if ( electron == 0 || proton == 0 || neutron == 0 || piplus == 0 ) {
291 <<
"something is seriously wrong with g4 particle lookup";
297 void HG4BertCascIntranuke::GenerateVertex(
GHepRecord * evrec)
const 306 TVector3 vtx(999999.,999999.,999999.);
311 double x=999999.,
y=999999., epsilon = 0.001;
313 double rp2 = TMath::Power(x,2.) + TMath::Power(
y,2.);
314 while(rp2 > R2-epsilon) {
317 y -= ((
y>0) ? epsilon : -epsilon);
318 rp2 = TMath::Power(x,2.) + TMath::Power(
y,2.);
320 vtx.SetXYZ(x,
y, -1.*TMath::Sqrt(TMath::Max(0.,R2-rp2)) + epsilon);
326 vtx.RotateUz(direction);
329 <<
"Generated vtx @ R = " << vtx.Mag() <<
" fm / " 332 TObjArrayIter piter(evrec);
343 void HG4BertCascIntranuke::SetTrackingRadius(
const GHepParticle * p)
const 359 bool HG4BertCascIntranuke::IsInNucleus(
const GHepParticle * p)
const 365 void HG4BertCascIntranuke::TransportHadrons(
GHepRecord * evrec)
const 383 const G4ParticleDefinition* incidentDef = 0;
385 TObjArrayIter piter(evrec);
386 TObjArrayIter pitter(evrec);
388 bool has_incidentBaryon(
false), has_secondaries(
false);
390 bool has_remnant(
false), has_incidentparticle(
false);
397 bool has_interacted(
false);
416 if ( has_interacted ) {
417 has_secondaries=
true;
421 if ( ! has_interacted ) {
436 if ( IsBaryon(sp) ) {
438 incidentDef = PDGtoG4Particle(sp->
Pdg() );
439 has_incidentBaryon=
true;
447 LOG(
"G4BertCascInterface::TransportHadrons",
pWARN)
448 <<
"IsBaryon failed to tag " << *sp;
455 if ( has_secondaries ) {
456 if ( ! incidentBaryon )
LOG(
"G4BertCascInterface::TransportHadrons",
pINFO)
457 <<
"Unrecognized baryon in nucleus";
459 int Zinit = remNucl->
Z() - outLept->
Charge()/3;
460 if (incidentBaryon) {
461 Zinit += (struckNucleon->
Charge() - incidentBaryon->
Charge() )/3;
470 G4Fancy3DNucleus* g4Nucleus =
new G4Fancy3DNucleus();
472 TLorentzVector pIncident;
474 g4Nucleus->Init(remNucl->
A(),remNucl->
Z());
475 double EE = struckNucleon->
E() - tgtNucl->
Mass() + g4Nucleus->GetMass()*
units::MeV;
476 TLorentzVector struckMomentum(struckNucleon->
Px(), struckNucleon->
Py(), struckNucleon->
Pz(),
EE);
477 Double_t PxI(0),PyI(0),PzI(0),EEI(0);
487 if ( pos_in_evrec==0 ) pos_in_evrec = icccur;
488 if ( ! has_incidentparticle ) {
498 incidentDef = PDGtoG4Particle(p->
Pdg() );
499 has_incidentparticle=
true;
505 if ( ! has_incidentparticle) {
506 incidentDef=PDGtoG4Particle(pinN->
Pdg());
508 pIncident.SetPxPyPzE(PxI,PyI,PzI,EEI);
511 G4ThreeVector incidentDir(pIncident.Vect().Unit().Px(),
512 pIncident.Vect().Unit().Py(),
513 pIncident.Vect().Unit().Pz());
515 double dynamicMass = std::sqrt(pIncident.M2() );
516 double incidentKE = pIncident.
E() - dynamicMass;
521 G4InuclElementaryParticle* incident =
new G4InuclElementaryParticle(dp,G4InuclParticle::bullet);
525 G4KineticTrackVector* g4secondaries = ConvertGenieSecondariesToG4(evrec);
527 int Nsec = g4secondaries->size();
529 G4CollisionOutput cascadeOutput;
530 G4InuclCollider bertCollider;
531 bertCollider.useCascadeDeexcitation();
533 bertCollider.rescatter(incident, g4secondaries, g4Nucleus, cascadeOutput);
536 for (
int n = 0;
n < Nsec;
n++)
delete (*g4secondaries)[
n];
537 delete g4secondaries;
542 TLorentzVector remX(tgtNucl->
Vx(), tgtNucl->
Vy(), tgtNucl->
Vz(), tgtNucl->
Vt() );
545 int Nfrag = cascadeOutput.numberOfOutgoingNuclei();
546 const std::vector<G4InuclNuclei>& outgoingFragments = cascadeOutput.getOutgoingNuclei();
553 int Nhad = cascadeOutput.numberOfOutgoingParticles();
554 const std::vector<G4InuclElementaryParticle>& outgoingHadrons = cascadeOutput.getOutgoingParticles();
555 for (
int l = 0;
l < Nhad;
l++) {
556 npdg = outgoingHadrons[
l].getDefinition()->GetPDGEncoding();
558 G4LorentzVector hadP = outgoingHadrons[
l].getMomentum();
559 TLorentzVector tempP(hadP.px(), hadP.py(), hadP.pz(), hadP.e() );
568 for (
int j = 0; j < Nfrag; j++) {
569 if (outgoingFragments[j].
getA() > maxA) {
570 maxA = outgoingFragments[j].getA();
575 fRemnZ = outgoingFragments[rem_index].getZ();
576 fRemnA = outgoingFragments[rem_index].getA();
579 G4LorentzVector nucP = outgoingFragments[rem_index].getMomentum();
580 TLorentzVector remP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
583 for (G4int
k = 0;
k < Nfrag;
k++) {
584 if (
k != rem_index) {
585 npdg = outgoingFragments[
k].getDefinition()->GetPDGEncoding();
586 nucP = outgoingFragments[
k].getMomentum();
587 TLorentzVector tempP(nucP.px(), nucP.py(), nucP.pz(), nucP.e() );
595 npdg = outgoingFragments[rem_index].getDefinition()->GetPDGEncoding();
596 remP.SetPx(remP.Px()+remNucl->
P4()->Px());
597 remP.SetPy(remP.Py()+remNucl->
P4()->Py());
598 remP.SetPz(remP.Pz()+remNucl->
P4()->Pz());
626 bool HG4BertCascIntranuke::NeedsRescattering(
const GHepParticle * p)
const {
634 bool HG4BertCascIntranuke::CanRescatter(
const GHepParticle * p)
const 658 bool HG4BertCascIntranuke::IsBaryon(
const GHepParticle * p)
const 666 <<
"no entry for PDG " << p->
Pdg() <<
" in PDGLibrary";
675 const G4ParticleDefinition* HG4BertCascIntranuke::PDGtoG4Particle(
int pdg)
const 677 const G4ParticleDefinition* pDef = 0;
679 if (
abs(pdg) < 1000000000 ) {
680 pDef = G4ParticleTable::GetParticleTable()->FindParticle(pdg);
681 }
else if ( pdg < 2000000000 ) {
682 pDef = G4IonTable::GetIonTable()->GetIon(pdg);
687 <<
"Unrecognized Bertini particle type: " <<
pdg;
694 G4KineticTrackVector* HG4BertCascIntranuke::ConvertGenieSecondariesToG4(std::vector<GHepParticle> partList)
const 696 static double GeToG4length = 2.81967*1.0e-12*1.2/1.4;
699 const G4ParticleDefinition* pDef = 0;
700 G4KineticTrackVector* g4secondaries =
new G4KineticTrackVector;
701 G4KineticTrack* kt = 0;
703 for (
size_t it=0 ; it<partList.size(); it++) {
705 pDef = PDGtoG4Particle(p->
Pdg() );
706 double formationTime = p->
Vt();
707 G4ThreeVector formationPosition(p->
Vx()*GeToG4length,
708 p->
Vy()*GeToG4length,
709 p->
Vz()*GeToG4length);
712 kt =
new G4KineticTrack(pDef, formationTime, formationPosition, formationMomentum);
713 kt->SetDefinition(pDef);
714 kt->SetState(G4KineticTrack::inside);
715 g4secondaries->push_back(kt);
718 return g4secondaries;
722 G4KineticTrackVector* HG4BertCascIntranuke::ConvertGenieSecondariesToG4(
GHepRecord* evrec)
const {
728 static double GeToG4length = 2.81967*1.0e-12*1.2/1.4;
730 TObjArrayIter piter(evrec);
732 const G4ParticleDefinition* pDef = 0;
733 G4KineticTrackVector* g4secondaries =
new G4KineticTrackVector;
734 G4KineticTrack* kt = 0;
739 pDef = PDGtoG4Particle(p->
Pdg() );
740 double formationTime = p->
Vt();
741 G4ThreeVector formationPosition(p->
Vx()*GeToG4length,
742 p->
Vy()*GeToG4length,
743 p->
Vz()*GeToG4length);
746 kt =
new G4KineticTrack(pDef, formationTime,
747 formationPosition, formationMomentum);
748 kt->SetDefinition(pDef);
749 kt->SetState(G4KineticTrack::inside);
750 g4secondaries->push_back(kt);
754 return g4secondaries;
758 bool HG4BertCascIntranuke::Conserve4Momentum(
GHepRecord* evrec)
const 766 int Nentries = evrec->GetEntries();
770 TLorentzVector sum4mom(0.0, 0.0, 0.0, 0.0);
771 for (
int j = 0; j < Nentries; j++) {
774 sum4mom += *(p->
P4() );
783 sum4mom += *(finalLepton->
P4() );
785 TLorentzVector initial4mom = *(targetNucleus->
P4() ) + *(probe->
P4() );
787 TLorentzVector diff = initial4mom - sum4mom;
789 const double maxdiff = 1.0e-9;
790 double diffE = diff.
E();
791 TVector3 diffp3 = diff.Vect();
792 double diffpmag = diffp3.Mag();
793 if ( TMath::Abs(diffE) > maxdiff || diffpmag > maxdiff ) {
796 <<
"final state - initial state differs by > " << maxdiff <<
"\n" 797 <<
" dE = " << diffE <<
", d|p3| = " << diffpmag;
800 <<
" Total Final state 4-momentum = (" << sum4mom.Px()
801 <<
", " << sum4mom.Py()
802 <<
", " << sum4mom.Pz()
803 <<
", " << sum4mom.E() <<
") ";
805 <<
" Total Initial state 4-momentum = (" << initial4mom.Px()
806 <<
", " << initial4mom.Py()
807 <<
", " << initial4mom.Pz()
808 <<
", " << initial4mom.E() <<
") ";
812 double Qinit = targetNucleus->
Charge();
813 double Qfinal = finalLepton->
Charge();
815 for (
int j = 0; j < Nentries; j++) {
822 if (Qinit != Qfinal) {
825 <<
" Charge not conserved: \n" 826 <<
" Qfinal = " << Qfinal
827 <<
" Qinit = " << Qinit;
835 void HG4BertCascIntranuke::LoadConfig(
void)
856 GetParam(
"HNINUKE-DelRPion", fDelRPion ) ;
857 GetParam(
"HNINUKE-DelRNucleon", fDelRNucleon ) ;
862 <<
"R0 = " <<
fR0 <<
" fermi" <<
"\n" 863 <<
"NR = " <<
fNR <<
"\n" 864 <<
"DelRPion = " << fDelRPion <<
"\n" 865 <<
"DelRNucleon = " << fDelRNucleon <<
"\n" 866 <<
"HadStep = " <<
fHadStep <<
" fermi" <<
"\n" 867 <<
"EPreEq = " <<
fHadStep <<
" fermi" <<
"\n" 872 <<
"DoFermi? = " << ((
fDoFermi)?(
true):(false)) <<
"\n" 873 <<
"XsecNNCorr? = " << ((
fXsecNNCorr)?(true):(false));
893 #endif // __GENIE_GEANT4_INTERFACE_ENABLED__ static string AsString(INukeMode_t mode)
void SetFirstMother(int m)
int RescatterCode(void) const
virtual GHepParticle * Particle(int position) const
TRandom3 & RndFsi(void) const
rnd number generator used by intranuclear cascade monte carlos
double fFermiMomentum
whether or not particle collision is pauli blocked
THE MAIN GENIE PROJECT NAMESPACE
double E(void) const
Get energy.
static RandomGen * Instance()
Access instance.
const TLorentzVector * P4(void) const
Defines the EventRecordVisitorI interface. Concrete implementations of this interface use the 'Visito...
double fDelRPion
factor by which Pion Compton wavelength gets multiplied to become nuclear size enhancement ...
double fEPreEq
threshold for pre-equilibrium reaction
virtual int RemnantNucleusPosition(void) const
double fNR
param multiplying the nuclear radius, determining how far to track hadrons beyond the "nuclear bounda...
void StepParticle(GHepParticle *p, double step, double nuclear_radius=-1.)
Step particle.
double fFermiFac
testing parameter to modify fermi momentum
int fRemnA
remnant nucleus A
Pure abstract base class. Defines the NuclearModelI interface to be implemented by any physics model ...
bool fXsecNNCorr
use nuclear medium correction for NN cross section
bool IsInNucleus(const GHepParticle *p) const
double Mass(void) const
Mass that corresponds to the PDG code.
static constexpr double MeV
bool CanRescatter(const GHepParticle *p) const
double fNucAbsFac
absorption xsec correction factor (hN Mode)
A singleton holding random number generator classes. All random number generation in GENIE should tak...
double Pz(void) const
Get Pz.
GHepStatus_t Status(void) const
GEvGenMode_t fGMode
event generation mode (lepton+A, hadron+A, ...)
const NuclearModelI * fNuclmodel
nuclear model used to generate fermi momentum
double Energy(void) const
Get energy.
double Px(void) const
Get Px.
virtual GHepParticle * Probe(void) const
double Vt(void) const
Get production time.
int FirstMother(void) const
void SetPosition(const TLorentzVector &v4)
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
virtual GHepParticle * FinalStatePrimaryLepton(void) const
virtual void Configure(const Registry &config)
GEvGenMode_t EventGenerationMode(void) const
bool NeedsRescattering(const GHepParticle *p) const
double Charge(void) const
Chrg that corresponds to the PDG code.
virtual GHepParticle * TargetNucleus(void) const
bool fDoFermi
whether or not to do fermi mom.
void SetTrackingRadius(const GHepParticle *p) const
double fNucCEXFac
charge exchange xsec correction factor (hN Mode)
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)
Misc GENIE control constants.
void GenerateVertex(GHepRecord *ev) const
double fR0
effective nuclear size param
double GenerateStep(GHepRecord *ev, GHepParticle *p) const
static PDGLibrary * Instance(void)
double Vz(void) const
Get production z.
const TLorentzVector * X4(void) const
void SetStatus(GHepStatus_t s)
bool fAltOset
NuWro's table-based implementation (not recommended)
A registry. Provides the container for algorithm configuration parameters.
bool IsPseudoParticle(int pdgc)
virtual GHepParticle * HitNucleon(void) const
void Configure(string mesg)
double fDelRNucleon
factor by which Nucleon Compton wavelength gets multiplied to become nuclear size enhancement ...
double fHadStep
step size for intranuclear hadron transport
virtual GHepParticle * RemnantNucleus(void) const
virtual void AddParticle(const GHepParticle &p)
void TransportHadrons(GHepRecord *ev) const
TParticlePDG * Find(int pdgc, bool must_exist=true)
double Vy(void) const
Get production y.
bool GetParamDef(const RgKey &name, T &p, const T &def) const
bool GetParam(const RgKey &name, T &p, bool is_top_call=true) const
double fTrackingRadius
tracking radius for the nucleus in the current event
double fNucRmvE
binding energy to subtract from cascade nucleons
GENIE's GHEP MC event record.
bool fUseOset
Oset model for low energy pion in hN.
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.
string Vec3AsString(const TVector3 *vec)
Root of GENIE utility namespaces.
double Vx(void) const
Get production x.
int fRemnZ
remnant nucleus Z
double Py(void) const
Get Py.
const Algorithm * SubAlg(const RgKey ®istry_key) const