NuEScatterGen_module.cc
Go to the documentation of this file.
1 #include <string>
2 #include <iostream>
3 #include <sstream>
4 #include <fstream>
5 
10 #include "cetlib_except/exception.h"
11 #include "cetlib/search_path.h"
12 
13 #include "TLorentzVector.h"
14 #include "TRandom3.h"
15 #include "TDatabasePDG.h"
16 #include "TFile.h"
17 #include "TF1.h"
18 
23 
24 namespace evgen {
25  class NuEScatterGen;
26 }
27 
29 public:
30  explicit NuEScatterGen(fhicl::ParameterSet const & p);
31  virtual ~NuEScatterGen();
32 
33  void produce(art::Event & e) override;
34  void beginJob() override;
35  void beginRun(art::Run & run) override;
36  void reconfigure(fhicl::ParameterSet const & p) ;
37 
38  std::vector<simb::MCParticle> GenerateEventKinematics(bool isNewNu);
39 
40 private:
41 
42  // Energies are in GeV, throughout
43  double fMinEnu;
44  double fMaxEnu;
45 
46  //dla double fGF; // Fermi constant in GeV^-2
47  double fWMA; // sin^2 (Weak mixing angle)
48 
49  // Detector coordinates, in cm
50  double fMinX;
51  double fMaxX;
52  double fMinY;
53  double fMaxY;
54  double fMinZ;
55  double fMaxZ;
56  double fMinT;
57  double fMaxT;
58 
60 
62  int fNNu; // number of neutrinos to generate per supernova
63 
64  // Event rate distributions in energy for each flavor
65  TF1 *fNueE;
66  TF1 *fNumuE;
67  TF1 *fNutauE;
68  TF1 *fNuebarE;
69  TF1 *fNumubarE;
70  TF1 *fNutaubarE;
71 
72  // The neutrino direction, which may be the same for multiple neutrinos
73  TVector3 fNuDir;
74 
75  // Handels the cross section calculation, as a function of outgoing e mom.
76  // Depends on ga, gv, the electron mass, and neutrino energy
77  TF1 *fdsigdT;
78 
79  TRandom3 *fRand;
80 };
81 
82 //------------------------------------------------------------------------------
84 {
85  this->reconfigure(p);
86 
87  produces< std::vector<simb::MCTruth> >();
88  produces< sumdata::RunData, art::InRun >();
89 
90  // There's a prefactor, too, ignoring since I'll just be pulling from dist
91  // [0] = gv [1] = ga [2] = Enu [3] = eMass
92  // ga and gv depend on neutrino flavor
93  fdsigdT = new TF1("xsecform","TMath::Power([0] + [1],2) + TMath::Power([0] - [1],2) * TMath::Power(1-x/[2],2) - ([1]*[1] - [0]*[0] * TMath::Power([3]/[2],2))*x");
94 }
95 
96 //------------------------------------------------------------------------------
98 {
99 }
100 
101 //------------------------------------------------------------------------------
103 {
104  TFile* eventrates = TFile::Open(fEventRateFileName.c_str());
105  eventrates->cd();
106 
107  fNueE = (TF1*)eventrates->Get("NueE");
108  fNumuE = (TF1*)eventrates->Get("NumuE");
109  fNutauE = (TF1*)eventrates->Get("NutauE");
110  fNuebarE = (TF1*)eventrates->Get("NuebarE");
111  fNumubarE = (TF1*)eventrates->Get("NumubarE");
112  fNutaubarE = (TF1*)eventrates->Get("NutaubarE");
113 
114  fRand = new TRandom3(0);
115 }
116 
117 //------------------------------------------------------------------------------
119 {
120  // grab the geometry object to see what geometry we are using
122  std::unique_ptr<sumdata::RunData> runcol(new sumdata::RunData(geo->DetectorName()));
123 
124  run.put(std::move(runcol));
125 
126  return;
127  }
128 
129 //------------------------------------------------------------------------------
131 {
132  // Set up a vector of ptrs to eventually put into the event
133  std::unique_ptr< std::vector<simb::MCTruth> > truthcol(new std::vector<simb::MCTruth>);
134  // And we'll fill one
135  simb::MCTruth truth;
136 
137  bool isNewNu = (e.event()%fNNu == 0);
138  std::vector<simb::MCParticle> parts = GenerateEventKinematics(isNewNu);
139 
140  assert(parts.size()==2);
141  truth.Add(parts[0]);
142  truth.Add(parts[1]);
143 
144  truthcol->push_back(truth);
145 
146  e.put(std::move(truthcol));
147 
148  return;
149 }
150 
151 //------------------------------------------------------------------------------
153 {
154  fMinEnu = p.get<double>("MinEnu");
155  fMaxEnu = p.get<double>("MaxEnu");
156 
157  fWMA = p.get<double>("WMA");
158 
159  fMinX = p.get<double>("MinX");
160  fMaxX = p.get<double>("MaxX");
161  fMinY = p.get<double>("MinY");
162  fMaxY = p.get<double>("MaxY");
163  fMinZ = p.get<double>("MinZ");
164  fMaxZ = p.get<double>("MaxZ");
165  fMinT = p.get<double>("MinT");
166  fMaxT = p.get<double>("MaxT");
167 
168  fIsSupernova = p.get<bool>("IsSupernova");
169  fNNu = p.get<int>("NNu");
170 
171  fEventRateFileName = p.get<std::string>("EventRateFileName");
172 
173  return;
174 }
175 
176 std::vector<simb::MCParticle> evgen::NuEScatterGen::GenerateEventKinematics(bool isNewNu)
177 {
178  // First, need to choose a flavor and energy for our interacting neutrino
179  int flav = 0;
180  double Enu = 0;
181 
182  double totNueE = fNueE ->Integral(fMinEnu,fMaxEnu,1e-2);
183  double totNumuE = fNumuE ->Integral(fMinEnu,fMaxEnu,1e-2);
184  double totNutauE = fNutauE->Integral(fMinEnu,fMaxEnu,1e-2);
185  double totNuebarE = fNuebarE ->Integral(fMinEnu,fMaxEnu,1e-2);
186  double totNumubarE = fNumubarE ->Integral(fMinEnu,fMaxEnu,1e-2);
187  double totNutaubarE = fNutaubarE->Integral(fMinEnu,fMaxEnu,1e-2);
188  double tot = totNueE + totNumuE + totNutauE +
189  totNuebarE + totNumubarE + totNutaubarE;
190 
191  double randflav = fRand->Uniform(0,1);
192  if (randflav < totNueE/tot){
193  flav = 12;
194  Enu = fNueE->GetRandom(fMinEnu,fMaxEnu);
195  }
196  else if (randflav < (totNueE+totNumuE)/tot){
197  flav = 14;
198  Enu = fNumuE->GetRandom(fMinEnu,fMaxEnu);
199  }
200  else if (randflav < (totNueE+totNumuE+totNutauE)/tot){
201  flav = 16;
202  Enu = fNutauE->GetRandom(fMinEnu,fMaxEnu);
203  }
204  else if (randflav < (totNueE+totNumuE+totNutauE+totNuebarE)/tot){
205  flav = -12;
206  Enu = fNuebarE->GetRandom(fMinEnu,fMaxEnu);
207  }
208  else if (randflav < (totNueE+totNumuE+totNutauE+totNuebarE+totNumubarE)/tot){
209  flav = -14;
210  Enu = fNumubarE->GetRandom(fMinEnu,fMaxEnu);
211  }
212  else{
213  flav = -16;
214  Enu = fNutaubarE->GetRandom(fMinEnu,fMaxEnu);
215  }
216 
217  // Throw a random neutrino direction if we're not generating events for
218  // a supernova. Then, generate a neutrino direction only once / supernova
219  if (fNuDir.Mag() == 0 || !fIsSupernova || isNewNu){
220  double nuCos = fRand->Uniform(-1,1);
221  double nuPhi = fRand->Uniform(0,2*TMath::Pi());
222  fNuDir.SetX(sqrt(1-nuCos*nuCos)*sin(nuPhi));
223  fNuDir.SetY(sqrt(1-nuCos*nuCos)*cos(nuPhi));
224  fNuDir.SetZ(nuCos);
225  }
226 
227  // Pull out the electron mass - needed for dif xsec formulat
228  int ePDG = 11;
229  static TDatabasePDG pdg;
230  TParticlePDG* pdgp = pdg.GetParticle(ePDG);
231  double eMass = 0;
232  if (pdgp) eMass = pdgp->Mass();
233 
234  // ga, gv depend on whether we're scattering nue-e or numu/nutau-e
235  double ga = abs(flav)==12 ? 0.5 : -0.5;
236  double gv = abs(flav)==12 ? 2*fWMA+0.5 : 2*fWMA-0.5;
237  fdsigdT->SetParameter(0,gv);
238  fdsigdT->SetParameter(1,ga);
239  fdsigdT->SetParameter(2,Enu);
240  fdsigdT->SetParameter(3,eMass);
241  fdsigdT->SetMinimum(0);
242 
243  double tmax = 2*eMass / (TMath::Power(1+eMass/Enu,2) - 1);
244  double eKE = fdsigdT->GetRandom(0,tmax);
245  double eMom = sqrt(eKE*eKE+2*eMass*eKE);
246  std::cout << "Throwing a neutrino of energy " << Enu << " with a maximum electron energy " << tmax << " from cross section " << fdsigdT->GetExpFormula() << ", and got " << eKE << std::endl;
247 
248  // Now, pull a direction for your electron
249  TVector3 eDir;
250  double ECos =
251  TMath::Sqrt( (eKE*TMath::Power(1+(eMass/Enu),2) ) / ( 2*eMass + eKE));
252  double EPhi = fRand->Uniform(0,2*TMath::Pi());
253  eDir.SetX(sqrt(1-ECos*ECos)*sin(EPhi));
254  eDir.SetY(sqrt(1-ECos*ECos)*cos(EPhi));
255  eDir.SetZ(ECos);
256  // But, that's relative to the z-axis move to relative the nu direction
257  TVector3 zaxis(0,0,1);
258  TVector3 rotationAxis = zaxis.Cross(fNuDir);
259  double rotationAngle = zaxis.Angle(fNuDir);
260  eDir.Rotate(rotationAngle,rotationAxis);
261 
262  TVector3 e = eMom * eDir;;
263  TVector3 nu = Enu * fNuDir;;
264 
265  TLorentzVector e4d(e,eMass+eKE);
266  TLorentzVector nu4d(nu,Enu);
267 
268  double vtxx = fRand->Uniform(fMinX,fMaxX);
269  double vtxy = fRand->Uniform(fMinY,fMaxY);
270  double vtxz = fRand->Uniform(fMinZ,fMaxZ);
271  double vtxt = fRand->Uniform(fMinT,fMaxT);
272  TLorentzVector vtx(vtxx,vtxy,vtxz,vtxt);
273 
274  // arguments are particle#, pdg code, process, mother, mass, status
275  // status must be 1 to tel GEANT to propogate
276  simb::MCParticle mcNu(0, flav, "primary", 0, 0, 1);
277  mcNu.AddTrajectoryPoint(vtx, nu4d);
278  simb::MCParticle mcE(1, 11, "primary", 0, eMass, 1);
279  mcE.AddTrajectoryPoint(vtx, e4d);
280 
281  std::vector<simb::MCParticle> ret;
282  ret.push_back(mcNu);
283  ret.push_back(mcE);
284 
285  return ret;
286 }
287 
288 
EventNumber_t event() const
Definition: DataViewImpl.cc:85
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
Definition: MCParticle.h:257
std::string string
Definition: nybbler.cc:12
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
NuEScatterGen(fhicl::ParameterSet const &p)
std::vector< simb::MCParticle > GenerateEventKinematics()
Particle class.
art framework interface to geometry description
Definition: Run.h:17
void reconfigure(fhicl::ParameterSet const &p)
void produce(art::Event &e) override
T abs(T value)
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
std::string DetectorName() const
Returns a string with the name of the detector, as configured.
def move(depos, offset)
Definition: depos.py:107
T get(std::string const &key) const
Definition: ParameterSet.h:271
p
Definition: test.py:223
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
void Add(simb::MCParticle const &part)
Definition: MCTruth.h:80
void beginRun(art::Run &run) override
Event generator information.
Definition: MCTruth.h:32
LArSoft geometry interface.
Definition: ChannelGeo.h:16
Event Generation using GENIE, cosmics or single particles.
QTextStream & endl(QTextStream &s)