GENIEGenerator
Loading...
Searching...
No Matches
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
59using std::ostringstream;
60
61using namespace genie;
62using namespace genie::utils;
63using namespace genie::utils::intranuke;
64using namespace genie::constants;
65using namespace genie::controls;
66
67//___________________________________________________________________________
68HG4BertCascIntranuke::HG4BertCascIntranuke()
69: EventRecordVisitorI("genie::HG4BertCascIntranuke")
70{
71 InitG4Particles();
72}
73
74//___________________________________________________________________________
75HG4BertCascIntranuke::HG4BertCascIntranuke(string config)
76: EventRecordVisitorI("genie::HG4BertCascIntranuke", config)
77{
78 InitG4Particles();
79}
80//___________________________________________________________________________
81HG4BertCascIntranuke::~HG4BertCascIntranuke()
82{
83}
84//___________________________________________________________________________
85int 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//___________________________________________________________________________
226double 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
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//___________________________________________________________________________
244void 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//___________________________________________________________________________
273void 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//___________________________________________________________________________
305void 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
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//___________________________________________________________________________
351void 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//___________________________________________________________________________
367bool 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//___________________________________________________________________________
373void 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 }
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//____________________________________________________________________________
651bool 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//___________________________________________________________________________
659bool 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//___________________________________________________________________________
683bool 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//___________________________________________________________________________
700const 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//___________________________________________________________________________
723G4KineticTrackVector* 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//___________________________________________________________________________
751G4KineticTrackVector* 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//___________________________________________________________________________
787bool 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//___________________________________________________________________________
862void 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
906void HG4BertCascIntranuke::Configure(const Registry & config)
907{
909 LoadConfig();
910}
911
912//___________________________________________________________________________
913void HG4BertCascIntranuke::Configure(string param_set)
914{
915 Algorithm::Configure(param_set);
916 LoadConfig();
917}
918
919//___________________________________________________________________________
920#endif // __GENIE_GEANT4_INTERFACE_ENABLED__
#define pNOTICE
Definition Messenger.h:61
#define pINFO
Definition Messenger.h:62
#define pFATAL
Definition Messenger.h:56
#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.
virtual void Configure(const Registry &config)
Definition Algorithm.cxx:62
Defines the EventRecordVisitorI interface. Concrete implementations of this interface use the 'Visito...
STDHEP-like event record entry that can fit a particle or a nucleus.
int FirstMother(void) const
void SetPosition(const TLorentzVector &v4)
void SetLastDaughter(int d)
void SetRescatterCode(int code)
int Pdg(void) const
void SetFirstMother(int m)
double Vy(void) const
Get production y.
const TLorentzVector * P4(void) const
double Charge(void) const
Chrg that corresponds to the PDG code.
double Mass(void) const
Mass that corresponds to the PDG code.
const TLorentzVector * X4(void) const
int LastDaughter(void) const
void SetStatus(GHepStatus_t s)
double Px(void) const
Get Px.
int Z(void) const
double E(void) const
Get energy.
double Pz(void) const
Get Pz.
double Py(void) const
Get Py.
double Vz(void) const
Get production z.
double Energy(void) const
Get energy.
int RescatterCode(void) const
int A(void) const
void SetFirstDaughter(int d)
GHepStatus_t Status(void) const
double Vx(void) const
Get production x.
double Vt(void) const
Get production time.
int FirstDaughter(void) const
GENIE's GHEP MC event record.
Definition GHepRecord.h:45
virtual GHepParticle * Probe(void) const
virtual GHepParticle * TargetNucleus(void) const
GEvGenMode_t EventGenerationMode(void) const
virtual GHepParticle * RemnantNucleus(void) const
virtual void AddParticle(const GHepParticle &p)
virtual int RemnantNucleusPosition(void) const
virtual GHepParticle * Particle(int position) const
virtual GHepParticle * FinalStatePrimaryLepton(void) const
virtual GHepParticle * HitNucleon(void) const
static string AsString(INukeMode_t mode)
Definition INukeMode.h:41
Pure abstract base class. Defines the NuclearModelI interface to be implemented by any physics model ...
static PDGLibrary * Instance(void)
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 registry. Provides the container for algorithm configuration parameters.
Definition Registry.h:65
const double epsilon
int getA(int pdg)
Basic constants.
Misc GENIE control constants.
Utilities for improving the code readability when using PDG codes.
bool IsIon(int pdgc)
Definition PDGUtils.cxx:42
bool IsProton(int pdgc)
Definition PDGUtils.cxx:336
bool IsPseudoParticle(int pdgc)
Definition PDGUtils.cxx:27
bool IsNeutron(int pdgc)
Definition PDGUtils.cxx:341
static constexpr double MeV
Definition Units.h:129
Simple functions for loading and reading nucleus dependent keys from config files.
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)
void StepParticle(GHepParticle *p, double step, double nuclear_radius=-1.)
Step particle.
string Vec3AsString(const TVector3 *vec)
Root of GENIE utility namespaces.
THE MAIN GENIE PROJECT NAMESPACE
Definition AlgCmp.h:25
const int kPdgPiM
Definition PDGCodes.h:159
@ kIStIntermediateState
Definition GHepStatus.h:31
@ kIStHadronInTheNucleus
Definition GHepStatus.h:37
@ kIStFinalStateNuclearRemnant
Definition GHepStatus.h:38
@ kIStStableFinalState
Definition GHepStatus.h:30
const int kPdgSigma0
Definition PDGCodes.h:88
const int kPdgClusterNP
Definition PDGCodes.h:215
const int kPdgAntiProton
Definition PDGCodes.h:82
const int kPdgProton
Definition PDGCodes.h:81
const int kPdgSigmaP
Definition PDGCodes.h:87
const int kPdgPi0
Definition PDGCodes.h:160
@ kIMdHA
Definition INukeMode.h:33
const int kPdgK0L
Definition PDGCodes.h:176
const int kPdgKP
Definition PDGCodes.h:172
const int kPdgNeutron
Definition PDGCodes.h:83
const int kPdgClusterNN
Definition PDGCodes.h:214
@ kGMdLeptonNucleus
Definition GMode.h:26
@ kGMdHadronNucleus
Definition GMode.h:27
@ kGMdPhotonNucleus
Definition GMode.h:28
const int kPdgHadronicBlob
Definition PDGCodes.h:211
const int kPdgKM
Definition PDGCodes.h:173
const int kPdgPiP
Definition PDGCodes.h:158
const int kPdgLambda
Definition PDGCodes.h:85
const int kPdgSigmaM
Definition PDGCodes.h:89
const int kPdgXiM
Definition PDGCodes.h:94
const int kPdgXi0
Definition PDGCodes.h:93
const int kPdgClusterPP
Definition PDGCodes.h:216
const int kPdgK0
Definition PDGCodes.h:174