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