GENIEGenerator
Loading...
Searching...
No Matches
NNBarOscPrimaryVtxGenerator.cxx
Go to the documentation of this file.
1//____________________________________________________________________________
2/*
3 Copyright (c) 2003-2025, The GENIE Collaboration
4 For the full text of the license visit http://copyright.genie-mc.org
5
6 Jeremy Hewes, Georgia Karagiorgi
7 University of Manchester
8*/
9//____________________________________________________________________________
10
31
32using namespace genie;
33
34//____________________________________________________________________________
36EventRecordVisitorI("genie::NNBarOscPrimaryVtxGenerator")
37{
38
39}
40//____________________________________________________________________________
42 string config) :
43EventRecordVisitorI("genie::NNBarOscPrimaryVtxGenerator",config)
44{
45
46}
47//____________________________________________________________________________
52//____________________________________________________________________________
54{
55 // spit out some output
56 Interaction * interaction = event->Summary();
57 fCurrInitStatePdg = interaction->InitState().Tgt().Pdg();
59
60 // spit out that info -j
61 LOG("NNBarOsc", pNOTICE)
62 << "Simulating decay " << genie::utils::nnbar_osc::AsString(fCurrDecayMode)
63 << " for an initial state with code: " << fCurrInitStatePdg;
64
65 // check if nucleon is bound
67 // can take this out for nnbar, nucleon is always bound!
68
69 // now call these four functions!
70 this->AddInitialState(event);
72 this->GenerateFermiMomentum(event);
73 this->GenerateDecayProducts(event);
74}
75//____________________________________________________________________________
77{
78
79// add initial state to event record
80
81// event record looks like this:
82// id: 0, nucleus (kIStInitialState)
83// |
84// |---> { id: 1, neutron (kIStDecayedState)
85// { id: 2, nucleon (kIStDecayedState)
86// { id: 3, remnant nucleus (kIStStableFinalState)
87//
88
89 TLorentzVector v4(0,0,0,0);
90
94
95 int ipdg = fCurrInitStatePdg;
96
97 // add initial nucleus
98 double Mi = PDGLibrary::Instance()->Find(ipdg)->Mass();
99 TLorentzVector p4i(0,0,0,Mi);
100 event->AddParticle(ipdg,stis,-1,-1,-1,-1, p4i, v4);
101
102 // add oscillating neutron
103 int neutpdg = kPdgNeutron;
104 double mneut = PDGLibrary::Instance()->Find(neutpdg)->Mass();
105 TLorentzVector p4neut(0,0,0,mneut);
106 event->AddParticle(neutpdg,stdc,0,-1,-1,-1, p4neut, v4);
107
108 // add annihilation nucleon
110 double mn = PDGLibrary::Instance()->Find(dpdg)->Mass();
111 TLorentzVector p4n(0,0,0,mn);
112 event->AddParticle(dpdg,stdc, 0,-1,-1,-1, p4n, v4);
113
114 // add nuclear remnant
115 int A = pdg::IonPdgCodeToA(ipdg);
116 int Z = pdg::IonPdgCodeToZ(ipdg);
117 A--; A--;
118 if(dpdg == kPdgProton) { Z--; }
119 int rpdg = pdg::IonPdgCode(A, Z);
120 double Mf = PDGLibrary::Instance()->Find(rpdg)->Mass();
121 TLorentzVector p4f(0,0,0,Mf);
122 event->AddParticle(rpdg,stfs,0,-1,-1,-1, p4f, v4);
123}
124//____________________________________________________________________________
126 GHepRecord * event) const
127{
128 GHepParticle * initial_nucleus = event->Particle(0);
129 int A = initial_nucleus->A();
130 if(A <= 2) {
131 return;
132 }
133
135
136 double R0 = 1.3;
137 double dA = (double)A;
138 double R = R0 * TMath::Power(dA, 1./3.);
139
140 LOG("NNBarOsc", pINFO)
141 << "Generating vertex according to a realistic nuclear density profile";
142
143 // get inputs to the rejection method
144 double ymax = -1;
145 double rmax = 3*R;
146 double dr = R/40.;
147 for(double r = 0; r < rmax; r+=dr) {
148 ymax = TMath::Max(ymax, r*r * utils::nuclear::Density(r,A));
149 }
150 ymax *= 1.2;
151
152 // select a vertex using the rejection method
153 TLorentzVector vtx(0,0,0,0);
154 unsigned int iter = 0;
155 while(1) {
156 iter++;
157
158 // throw an exception if it hasn't find a solution after many attempts
159 if(iter > controls::kRjMaxIterations) {
160 LOG("NNBarOsc", pWARN)
161 << "Couldn't generate a vertex position after " << iter << " iterations";
163 exception.SetReason("Couldn't generate vertex");
164 exception.SwitchOnFastForward();
165 throw exception;
166 }
167
168 double r = rmax * rnd->RndFsi().Rndm();
169 double t = ymax * rnd->RndFsi().Rndm();
170 double y = r*r * utils::nuclear::Density(r,A);
171 if(y > ymax) {
172 LOG("NNBarOsc", pERROR)
173 << "y = " << y << " > ymax = " << ymax << " for r = " << r << ", A = " << A;
174 }
175 bool accept = (t < y);
176 if(accept) {
177 double phi = 2*constants::kPi * rnd->RndFsi().Rndm();
178 double cosphi = TMath::Cos(phi);
179 double sinphi = TMath::Sin(phi);
180 double costheta = -1 + 2 * rnd->RndFsi().Rndm();
181 double sintheta = TMath::Sqrt(1-costheta*costheta);
182 vtx.SetX(r*sintheta*cosphi);
183 vtx.SetY(r*sintheta*sinphi);
184 vtx.SetZ(r*costheta);
185 vtx.SetT(0.);
186 break;
187 }
188 } // while 1
189
190 // giving position to oscillating neutron
191 GHepParticle * oscillating_neutron = event->Particle(1);
192 assert(oscillating_neutron);
193 oscillating_neutron->SetPosition(vtx);
194
195 // give same position to annihilation nucleon
196 GHepParticle * annihilation_nucleon = event->Particle(2);
197 assert(annihilation_nucleon);
198 annihilation_nucleon->SetPosition(vtx);
199}
200//____________________________________________________________________________
202 GHepRecord * event) const
203{
204 GHepParticle * initial_nucleus = event->Particle(0);
205 int A = initial_nucleus->A();
206 if(A <= 2) {
207 return;
208 }
209
210 GHepParticle * oscillating_neutron = event->Particle(1);
211 GHepParticle * annihilation_nucleon = event->Particle(2);
212 GHepParticle * remnant_nucleus = event->Particle(3);
213 assert(oscillating_neutron);
214 assert(annihilation_nucleon);
215 assert(remnant_nucleus);
216
217 // generate a Fermi momentum & removal energy
218 Target tgt(initial_nucleus->Pdg());
219
220 // start with oscillating neutron
222 // generate nuclear model & fermi momentum
223 fNuclModel->GenerateNucleon(tgt);
224 TVector3 p3 = fNuclModel->Momentum3();
225 double w = fNuclModel->RemovalEnergy();
226
227 // use mass & momentum to calculate energy
228 double mass = oscillating_neutron->Mass();
229 double energy = sqrt(pow(mass,2) + p3.Mag2()) - w;
230 // give new energy & momentum to particle
231 TLorentzVector p4(p3, energy);
232 oscillating_neutron->SetMomentum(p4);
233
234 LOG("NNBarOsc", pINFO)
235 << "Generated neutron momentum: ("
236 << p3.Px() << ", " << p3.Py() << ", " << p3.Pz() << "), "
237 << "|p| = " << p3.Mag();
238
239 // then rinse repeat for the annihilation nucleon
240 tgt.SetHitNucPdg(annihilation_nucleon->Pdg());
241 // use nuclear model to generate fermi momentum
242 fNuclModel->GenerateNucleon(tgt);
243 p3 = fNuclModel->Momentum3();
244 w = fNuclModel->RemovalEnergy();
245 // use mass & momentum to figure out energy
246 mass = annihilation_nucleon->Mass();
247 energy = sqrt(pow(mass,2) + p3.Mag2()) - w;
248 // give new energy & momentum to particle
249 p4 = TLorentzVector(p3, energy);
250 annihilation_nucleon->SetMomentum(p4);
251
252 LOG("NNBarOsc", pINFO)
253 << "Generated nucleon momentum: ("
254 << p3.Px() << ", " << p3.Py() << ", " << p3.Pz() << "), "
255 << "|p| = " << p3.Mag();
256
257 // now figure out momentum for the nuclear remnant
258 p3 = -1 * (oscillating_neutron->GetP4()->Vect() + annihilation_nucleon->GetP4()->Vect());
259 // figure out energy from mass & momentum
260 mass = remnant_nucleus->Mass();
261 energy = sqrt(pow(mass,2) + p3.Mag2());
262 // give new energy & momentum to remnant
263 p4 = TLorentzVector(p3, energy);
264 remnant_nucleus->SetMomentum(p4);
265}
266//____________________________________________________________________________
268 GHepRecord * event) const
269{
270 LOG("NNBarOsc", pINFO) << "Generating decay...";
271
273 LOG("NNBarOsc", pINFO) << "Decay product IDs: " << pdgv;
274 assert ( pdgv.size() > 1);
275
276 LOG("NNBarOsc", pINFO) << "Performing a phase space decay...";
277
278 // Get the decay product masses
279
280 vector<int>::const_iterator pdg_iter;
281 int idx = 0;
282 double * mass = new double[pdgv.size()];
283 double sum = 0;
284 for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
285 int pdgc = *pdg_iter;
286 double m = PDGLibrary::Instance()->Find(pdgc)->Mass();
287 mass[idx++] = m;
288 sum += m;
289 }
290
291 LOG("NNBarOsc", pINFO)
292 << "Decaying N = " << pdgv.size() << " particles / total mass = " << sum;
293 int initial_nucleus_id = 0;
294 int oscillating_neutron_id = 1;
295 int annihilation_nucleon_id = 2;
296
297 // get our annihilating nucleons
298 GHepParticle * initial_nucleus = event->Particle(initial_nucleus_id);
299 assert(initial_nucleus);
300 GHepParticle * oscillating_neutron = event->Particle(oscillating_neutron_id);
301 assert(oscillating_neutron);
302 GHepParticle * annihilation_nucleon = event->Particle(annihilation_nucleon_id);
303 assert(annihilation_nucleon);
304
305 Target tgt(initial_nucleus->Pdg());
307
308 // get their momentum 4-vectors and boost into rest frame
309 TLorentzVector * p4_1 = oscillating_neutron->GetP4();
310 TLorentzVector * p4_2 = annihilation_nucleon->GetP4();
311 TLorentzVector * p4d = new TLorentzVector(*p4_1 + *p4_2);
312 TVector3 boost = p4d->BoostVector();
313 p4d->Boost(-boost);
314
315 // get decay position
316 TLorentzVector * v4d = annihilation_nucleon->GetX4();
317
318 delete p4_1;
319 delete p4_2;
320
321 LOG("NNBarOsc", pINFO)
322 << "Decaying system p4 = " << utils::print::P4AsString(p4d);
323
324 // Set the decay
325 bool permitted = fPhaseSpaceGenerator.SetDecay(*p4d, pdgv.size(), mass);
326
327 // If the decay is not energetically allowed, select a new final state
328 while(!permitted) {
329
330 LOG("NNBarOsc", pINFO)
331 << "Not enough energy to generate decay products! Selecting a new final state.";
332
333 int mode = 0;
334
335 int initial_nucleus_pdg = initial_nucleus->Pdg();
336
337 std::string nucleus_pdg = std::to_string(static_cast<long long>(initial_nucleus_pdg));
338 if (nucleus_pdg.size() != 10) {
339 LOG("NNBarOsc", pERROR)
340 << "Expecting the nuclear PDG code to be a 10-digit integer, but it is " << nucleus_pdg << ", which is "
341 << nucleus_pdg.size() << " digits long. Drop me an email at jezhewes@gmail.com ; exiting...";
342 exit(1);
343 }
344
345 int n_nucleons = std::stoi(nucleus_pdg.substr(6,3)) - 1;
346 int n_protons = std::stoi(nucleus_pdg.substr(3,3));
347 double proton_frac = ((double)n_protons) / ((double) n_nucleons);
348 double neutron_frac = 1 - proton_frac;
349
350 // set branching ratios, taken from bubble chamber data
351 const int n_modes = 16;
352 double br [n_modes] = { 0.010, 0.080, 0.100, 0.220,
353 0.360, 0.160, 0.070, 0.020,
354 0.015, 0.065, 0.110, 0.280,
355 0.070, 0.240, 0.100, 0.100 };
356
357 for (int i = 0; i < n_modes; i++) {
358 // for first 7 branching ratios, multiply by relative proton density
359 if (i < 7)
360 br[i] *= proton_frac;
361 // for next 9, multiply by relative neutron density
362 else
363 br[i] *= neutron_frac;
364 }
365
366 // randomly generate a number between 1 and 0
368 rnd->SetSeed(0);
369 double p = rnd->RndNum().Rndm();
370
371 // loop through all modes, figure out which one our random number corresponds to
372 double threshold = 0;
373 for (int j = 0; j < n_modes; j++) {
374 threshold += br[j];
375 if (p < threshold) {
376 // once we've found our mode, stop looping
377 mode = j + 1;
378 break;
379 }
380 }
381
382 // create new event record with new final state
383 // TODO - I don't think Jeremy meant to make a _new_ record here; it
384 // shadows the one passed in...
385 // EventRecord * event = new EventRecord;
386 Interaction * interaction = Interaction::NOsc((int)fCurrInitStatePdg, mode);
387 event->AttachSummary(interaction);
388
389 fCurrDecayMode = (NNBarOscMode_t) interaction->ExclTag().DecayMode();
390
392 LOG("NNBarOsc", pINFO) << "Decay product IDs: " << pdgv;
393 assert ( pdgv.size() > 1);
394
395 // get the decay particles again
396 LOG("NNBarOsc", pINFO) << "Performing a phase space decay...";
397 idx = 0;
398 delete [] mass;
399 mass = new double[pdgv.size()];
400 sum = 0;
401 for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
402 int pdgc = *pdg_iter;
403 double m = PDGLibrary::Instance()->Find(pdgc)->Mass();
404 mass[idx++] = m;
405 sum += m;
406 }
407
408 LOG("NNBarOsc", pINFO)
409 << "Decaying N = " << pdgv.size() << " particles / total mass = " << sum;
410 LOG("NNBarOsc", pINFO)
411 << "Decaying system p4 = " << utils::print::P4AsString(p4d);
412
413 permitted = fPhaseSpaceGenerator.SetDecay(*p4d, pdgv.size(), mass);
414 }
415
416 if(!permitted) {
417 LOG("NNBarOsc", pERROR)
418 << " *** Phase space decay is not permitted \n"
419 << " Total particle mass = " << sum << "\n"
420 << " Decaying system p4 = " << utils::print::P4AsString(p4d);
421 // clean-up
422 delete [] mass;
423 delete p4d;
424 delete v4d;
425 // throw exception
427 exception.SetReason("Decay not permitted kinematically");
428 exception.SwitchOnFastForward();
429 throw exception;
430 }
431
432 // Get the maximum weight
433 //double wmax = fPhaseSpaceGenerator.GetWtMax();
434 double wmax = -1;
435 for(int i=0; i<200; i++) {
436 double w = fPhaseSpaceGenerator.Generate();
437 wmax = TMath::Max(wmax,w);
438 }
439 assert(wmax>0);
440 wmax *= 2;
441
442 LOG("NNBarOsc", pNOTICE)
443 << "Max phase space gen. weight @ current hadronic system: " << wmax;
444
445 // Generate an unweighted decay
447
448 bool accept_decay=false;
449 unsigned int itry=0;
450 while(!accept_decay)
451 {
452 itry++;
453
455 // report, clean-up and return
456 LOG("NNBarOsc", pWARN)
457 << "Couldn't generate an unweighted phase space decay after "
458 << itry << " attempts";
459 // clean up
460 delete [] mass;
461 delete p4d;
462 delete v4d;
463 // throw exception
465 exception.SetReason("Couldn't select decay after N attempts");
466 exception.SwitchOnFastForward();
467 throw exception;
468 }
469 double w = fPhaseSpaceGenerator.Generate();
470 if(w > wmax) {
471 LOG("NNBarOsc", pWARN)
472 << "Decay weight = " << w << " > max decay weight = " << wmax;
473 }
474 double gw = wmax * rnd->RndHadro().Rndm();
475 accept_decay = (gw<=w);
476
477 LOG("NNBarOsc", pINFO)
478 << "Decay weight = " << w << " / R = " << gw
479 << " - accepted: " << accept_decay;
480
481 } //!accept_decay
482
483 // Insert final state products into a TClonesArray of GHepParticle's
484 TLorentzVector v4(*v4d);
485 int idp = 0;
486 for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
487 int pdgc = *pdg_iter;
488 TLorentzVector * p4fin = fPhaseSpaceGenerator.GetDecay(idp);
489 GHepStatus_t ist =
491 p4fin->Boost(boost);
492 event->AddParticle(pdgc, ist, oscillating_neutron_id,-1,-1,-1, *p4fin, v4);
493 idp++;
494 }
495
496 // Clean-up
497 delete [] mass;
498 delete p4d;
499 delete v4d;
500}
501//___________________________________________________________________________
503{
504 Algorithm::Configure(config);
505 this->LoadConfig();
506}
507//___________________________________________________________________________
509{
510 Algorithm::Configure(config);
511 this->LoadConfig();
512}
513//___________________________________________________________________________
515{
516// AlgConfigPool * confp = AlgConfigPool::Instance();
517// const Registry * gc = confp->GlobalParameterList();
518
519 fNuclModel = 0;
520
521 RgKey nuclkey = "NuclearModel";
522 fNuclModel = dynamic_cast<const NuclearModelI *> (this->SubAlg(nuclkey));
523 assert(fNuclModel);
524}
525//___________________________________________________________________________
#define pNOTICE
Definition Messenger.h:61
#define pINFO
Definition Messenger.h:62
#define pERROR
Definition Messenger.h:59
#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.
string RgKey
virtual void Configure(const Registry &config)
Definition Algorithm.cxx:62
const Algorithm * SubAlg(const RgKey &registry_key) const
STDHEP-like event record entry that can fit a particle or a nucleus.
void SetPosition(const TLorentzVector &v4)
void SetMomentum(const TLorentzVector &p4)
TLorentzVector * GetP4(void) const
int Pdg(void) const
double Mass(void) const
Mass that corresponds to the PDG code.
TLorentzVector * GetX4(void) const
int A(void) const
GENIE's GHEP MC event record.
Definition GHepRecord.h:45
const Target & Tgt(void) const
Summary information for an interaction.
Definition Interaction.h:56
const XclsTag & ExclTag(void) const
Definition Interaction.h:72
static Interaction * NOsc(int tgt, int annihilation_mode=-1)
const InitialState & InitState(void) const
Definition Interaction.h:69
void GenerateFermiMomentum(GHepRecord *event) const
void GenerateDecayProducts(GHepRecord *event) const
void GenerateOscillatingNeutronPosition(GHepRecord *event) const
void ProcessEventRecord(GHepRecord *event) const
Pure abstract base class. Defines the NuclearModelI interface to be implemented by any physics model ...
A list of PDG codes.
Definition PDGCodeList.h:32
static PDGLibrary * Instance(void)
TParticlePDG * Find(int pdgc, bool must_exist=true)
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition RandomGen.h:29
TRandom3 & RndHadro(void) const
rnd number generator used by hadronization models
Definition RandomGen.h:53
static RandomGen * Instance()
Access instance.
Definition RandomGen.cxx:74
void SetSeed(long int seed)
Definition RandomGen.cxx:85
TRandom3 & RndFsi(void) const
rnd number generator used by intranuclear cascade monte carlos
Definition RandomGen.h:59
TRandom3 & RndNum(void) const
rnd number generator used by MC integrators & other numerical methods
Definition RandomGen.h:77
A registry. Provides the container for algorithm configuration parameters.
Definition Registry.h:65
A Neutrino Interaction Target. Is a transparent encapsulation of quite different physical systems suc...
Definition Target.h:40
void SetHitNucPdg(int pdgc)
Definition Target.cxx:171
int Pdg(void) const
Definition Target.h:71
int DecayMode(void) const
Definition XclsTag.h:70
An exception thrown by EventRecordVisitorI when the normal processing sequence has to be disrupted (f...
static const unsigned int kMaxUnweightDecayIterations
Definition Controls.h:61
static const unsigned int kRjMaxIterations
Definition Controls.h:26
int IonPdgCode(int A, int Z)
Definition PDGUtils.cxx:71
int IonPdgCodeToZ(int pdgc)
Definition PDGUtils.cxx:55
int IonPdgCodeToA(int pdgc)
Definition PDGUtils.cxx:63
GHepStatus_t DecayProductStatus(bool in_nucleus, int pdgc)
int AnnihilatingNucleonPdgCode(NNBarOscMode_t ndm)
PDGCodeList DecayProductList(NNBarOscMode_t ndm)
string AsString(NNBarOscMode_t ndm)
double Density(double r, int A, double ring=0.)
string P4AsString(const TLorentzVector *p)
THE MAIN GENIE PROJECT NAMESPACE
Definition AlgCmp.h:25
@ kIStStableFinalState
Definition GHepStatus.h:30
@ kIStDecayedState
Definition GHepStatus.h:32
@ kIStInitialState
Definition GHepStatus.h:29
enum genie::ENNBarOscMode NNBarOscMode_t
const int kPdgProton
Definition PDGCodes.h:81
const int kPdgNeutron
Definition PDGCodes.h:83
enum genie::EGHepStatus GHepStatus_t