ParticleInjectorNEU/ParticleInjector.cc
Go to the documentation of this file.
1 #include <sstream>
2 #include <vector>
3 #include <iostream>
4 
5 #include <utl/config.h>
6 
7 #include <det/Detector.h>
8 
9 #include <sdet/SDetector.h>
10 #include <sdet/Station.h>
11 
12 #include <evt/Event.h>
13 
14 #include <fwk/CentralConfig.h>
15 #include <fwk/RandomEngineRegistry.h>
16 #include <io/CorsikaUtilities.h>
17 
18 #include <sevt/SEvent.h>
19 #include <sevt/Header.h>
20 #include <sevt/Station.h>
21 #include <sevt/StationSimData.h>
22 
23 #include <mevt/MEvent.h>
24 #include <mevt/Header.h>
25 
26 #include <utl/AugerCoordinateSystem.h>
27 #include <utl/AugerUnits.h>
28 #include <utl/Math.h>
29 #include <utl/MathConstants.h>
30 #include <utl/Particle.h>
31 #include <utl/NucleusProperties.h>
32 #include <utl/PhysicalConstants.h>
33 #include <utl/Point.h>
34 #include <utl/TimeStamp.h>
35 #include <utl/ErrorLogger.h>
36 #include <utl/RandomEngine.h>
37 #include <utl/Reader.h>
38 #include <utl/Vector.h>
39 #include <utl/TabulatedFunction.h>
40 #include <utl/RandomSamplerFromPDF.h>
41 #include <utl/Plane.h>
42 #include <utl/Line.h>
43 #include <utl/GeometryUtilities.h>
44 #include <utl/String.h>
45 #include <utl/StringCompare.h>
46 #include <utl/Test.h>
47 
48 #include <CLHEP/Random/Randomize.h>
49 
50 #include <TChain.h>
51 
52 #include "ParticleInjector.h"
53 
54 using namespace det;
55 using namespace evt;
56 using namespace fwk;
57 using namespace sevt;
58 using namespace utl;
59 using namespace std;
60 using CLHEP::RandFlat;
61 
62 
63 namespace ParticleInjectorNEU {
64 
65  const double ParticleInjector::fgFarAway2 = utl::Sqr(1000*utl::kilometer);
66 
67 
68  ParticleInjector::ParticleInjector() :
69  fRandomEngine(RandomEngineRegistry::GetInstance().Get(RandomEngineRegistry::eDetector).GetEngine())
70  { }
71 
72 
73  void
75  {
76  ostringstream config;
77 
78  config << '\n';
79  if (fCreateEvent)
80  config << " Will create SEvent with time" << fEventTime << '\n';
81  else
82  config << " Will not create SEvent\n";
83  if (fUseSingleTank)
84  config << " Injecting in station with id = " << fSingleTankID << '\n';
85  else
86  config << " Injecting in all available stations\n";
87 
88  config << " number of particles " << fParticles.size() << '\n';
89 
90  if (fPositionFlag == eFixed)
91  config << " position (" << fX << ", " << fY << ", " << fZ << ")";
92  else if (fPositionFlag == eSphere )
93  config << " Position will be set randomly over a sphere";
94  else if (fPositionFlag == eDisk )
95  config << " Position will be set randomly over a disk";
96  else if (fPositionFlag == ePDF )
97  config << " Position will be set randomly with selected PDF";
98 
99  INFO(config);
100  }
101 
102 
105  {
106  auto topB = CentralConfig::GetInstance()->GetTopBranch("ParticleInjector");
107 
108  auto eventTimeB = topB.GetChild("EventTime");
109 
110  if (eventTimeB) {
111  fCreateEvent = true;
112  eventTimeB.GetData(fEventTime);
113  }
114 
115  // get the station id we want to inject to.
116  auto stationIdB = topB.GetChild("StationId");
117 
118  if (stationIdB) {
119  fUseSingleTank = true;
120  stationIdB.GetData(fSingleTankID);
121  }
122 
123  // If no time information is provided all particles will have time set to zero.
124  auto timeB = topB.GetChild("Time");
125  if (timeB) {
126  auto discreteB = timeB.GetChild("Fixed");
127  if (discreteB)
128  discreteB.GetData(fDiscreteParticleTime);
129  } else
130  fDiscreteParticleTime.push_back(0);
131 
132  // get the number of particles to inject with the same information.
133  // This is mutualy exclusive with providing a flux.
134  {
135  auto numberOfParticlesB = topB.GetChild("NumberOfParticles");
136  fParticles.clear();
137  const auto numbers = numberOfParticlesB.GetChild("Number").Get<vector<int>>();
138  const auto types = numberOfParticlesB.GetChild("Type").Get<vector<int>>();
139  for (unsigned int i = 0, n = types.size(); i < n; ++i)
140  fParticles.resize(
141  fParticles.size() + numbers.at(i),
142  static_cast<utl::Particle::Type>(types[i])
143  );
144  }
145 
146  // The following things are not optional
147 
148  // Single Position. If this is provided there will be no randomization of position.
149  // Otherwise the particles will be injected at a sphere of given radius
150  auto positionB = topB.GetChild("Position");
151  auto fixedB = positionB.GetChild("Fixed");
152  if (fixedB) {
154  const auto position = fixedB.Get<vector<double>>();
155  fX = position.at(0);
156  fY = position.at(1);
157  fZ = position.at(2);
158  } else {
159  auto diskRadiusB = positionB.GetChild("DiskRadius");
160  if (diskRadiusB) {
162  diskRadiusB.GetData(fRadius);
163  positionB.GetChild("DiskHeight").GetData(fHeight);
164  } else {
165  auto sphereRadiusB = positionB.GetChild("SphereRadius");
166  if (sphereRadiusB) {
168  positionB.GetChild("SphereRadius").GetData(fRadius);
169  } else {
171  fXDistribution = LoadRandomSampler(positionB.GetChild("Xpos"));
172  fYDistribution = LoadRandomSampler(positionB.GetChild("Ypos"));
173  fZDistribution = LoadRandomSampler(positionB.GetChild("Zpos"));
174  }
175  }
176  }
177 
178  // Direction Branch
179  auto directionB = topB.GetChild("Direction");
180  fixedB = directionB.GetChild("Fixed");
181  if (fixedB) {
182  const auto direction = fixedB.Get<vector<double>>();
183  const double r = sqrt(Sqr(direction.at(0)) + Sqr(direction.at(1)) + Sqr(direction.at(2)));
184  fDiscreteZenith.push_back(acos(direction[2]/r));
185  fDiscreteAzimuth.push_back(atan2(direction[1], direction[0]));
186  } else {
187  fZenithDistribution = LoadRandomSampler(directionB.GetChild("Zenith"));
188  fAzimuthDistribution = LoadRandomSampler(directionB.GetChild("Azimuth"));
189  }
190 
191  // Energy Branch
192  auto energyB = topB.GetChild("Energy");
193  fixedB = energyB.GetChild("Fixed");
194  if (!fixedB)
196  else {
197  fixedB.GetData(fFixedEnergy);
198  if (fFixedEnergy.size() < fParticles.size()) {
199  INFO("Particles and energies must be equal size for <Fixed> option\n");
200  return eFailure;
201  }
202  }
203 
204  auto muonsB = energyB.GetChild("Muons");
205  if (muonsB)
207 
208  auto electronsB = energyB.GetChild("Electrons");
209  if (electronsB)
211 
212  auto gammasB = energyB.GetChild("Gammas");
213  if (gammasB)
215 
216  topB.GetChild("PropagateToTank").GetData(fPropagate);
217 
218  fRandomTree = new TChain("randomParticles");
219  auto randomParticlesB = topB.GetChild("RandomParticles");
220  if (randomParticlesB) {
221  const auto filename = randomParticlesB.GetChild("FileName").Get<string>();
222  fRandomTree->Add(filename.c_str());
223  fNumberOfEntries = fRandomTree->GetEntries();
224  if (!fNumberOfEntries) {
225  ostringstream err;
226  err << "The file " << filename << " contains 0 entries!";
227  ERROR(err);
228  return eFailure;
229  }
230 
231  const auto randomEntries = randomParticlesB.GetChild("RandomEntries").Get<string>();
232  fRandomEntries = StringEquivalent(randomEntries, "yes");
233  randomParticlesB.GetChild("MinMomentum").GetData(fMinMomentum);
234 
235  fRandomTree->SetBranchAddress("fSecondaryType", &fRandomParticle.fSecondaryId);
236  fRandomTree->SetBranchAddress("fPx", &fRandomParticle.fPx);
237  fRandomTree->SetBranchAddress("fPy", &fRandomParticle.fPy);
238  fRandomTree->SetBranchAddress("fPz", &fRandomParticle.fPz);
239  }
240 
241  if (topB.GetChild("DumpConfiguration"))
243 
244  return eSuccess;
245  }
246 
247 
250  {
251  auto& header = event.GetHeader();
252  header.SetTime(fEventTime);
253 
254  if (!event.HasSEvent() && fCreateEvent) {
255  event.MakeSEvent();
256  event.GetSEvent().GetHeader().SetTime(fEventTime);
257  det::Detector::GetInstance().Update(fEventTime);
258  }
259 
260  if (!event.HasMEvent() && fCreateEvent) {
261  event.MakeMEvent();
262  event.GetMEvent().GetHeader().SetTime(fEventTime);
263  det::Detector::GetInstance().Update(fEventTime);
264  }
265 
266  auto& sEvent = event.GetSEvent();
267 
268  if (fUseSingleTank) {
269 
270  if (!sEvent.HasStation(fSingleTankID)) {
271  // if I'm not allowed to create the event I'm not going to modify it either...
272  if (fCreateEvent)
273  sEvent.MakeStation(fSingleTankID);
274  else
275  return eSuccess;
276  }
277  InjectParticles(sEvent.GetStation(fSingleTankID));
278 
279  } else {
280 
281  for (auto& station : sEvent.StationsRange())
282  InjectParticles(station);
283 
284  }
285 
286  return eSuccess;
287  }
288 
289 
292  {
293  delete fXDistribution;
294  fXDistribution = nullptr;
295  delete fYDistribution;
296  fYDistribution = nullptr;
297  delete fZDistribution;
298  fZDistribution = nullptr;
299  delete fZenithDistribution;
300  fZenithDistribution = nullptr;
301  delete fAzimuthDistribution;
302  fAzimuthDistribution = nullptr;
304  fDefaultEnergyDistribution = nullptr;
306  fMuonEnergyDistribution = nullptr;
308  fElectronEnergyDistribution = nullptr;
310  fGammaEnergyDistribution = nullptr;
311  delete fRandomTree;
312  fRandomTree = nullptr;
313 
314  return eSuccess;
315  }
316 
317 
318  void
320  {
321  if (!station.HasSimData())
322  station.MakeSimData();
323 
324  static unsigned int totalSimulatedParticles = 0;
325 
326  const auto& detStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
327  const auto& stationCS = detStation.GetLocalCoordinateSystem();
328 
329  const int nParticles = fParticles.size();
330  for (int i = 0; i < nParticles; ++i) {
331 
332  double x, y, z;
333  GeneratePosition(x, y, z);
334 
335  const Point position(x, y, z, stationCS);
336  const TimeInterval time(GenerateTime());
337 
339  position, Vector(0,0,0, stationCS, Vector::kCartesian), time, 1);
340 
341  if (fRandomEntries) {
342 
343  const int maxTrials = 100;
344  for (unsigned int trialNumber = 0; trialNumber < maxTrials; ++trialNumber) {
345  const unsigned int entry = RandFlat::shoot(&fRandomEngine, 0, fNumberOfEntries);
346  fRandomTree->GetEntry(entry);
347  const int particleType = io::Corsika::CorsikaToPDG(fRandomParticle.fSecondaryId);
348 
349  if (particleType == utl::Particle::eUndefined ||
350  utl::NucleusProperties::IsNucleus(particleType))
351  continue;
352 
353  const Vector momentum(fRandomParticle.fPx*GeV,
356  stationCS, Vector::kCartesian);
357 
358  if (momentum.GetMag() < fMinMomentum)
359  continue;
360 
361  particle = Particle(particleType, utl::Particle::eBackground, position, momentum, time, 1);
362  break;
363  }
364 
365  } else {
366 
367  const double azimuth = GenerateAzimuth();
368  const double zenith = GenerateZenith();
369 
370  const Vector direction(1, zenith, azimuth, stationCS, Vector::kSpherical);
371 
372  const Particle::Type particleType = fParticles[i];
373 
374  const double energy = GenerateEnergy(particleType, i);
375  const Particle stdParticle(particleType, utl::Particle::eBackground,
376  position, direction, time, 1, energy);
377 
378  particle = stdParticle;
379 
380  }
381 
382  if (StringEquivalent(fPropagate, "yes") &&
383  !detStation.IsInsideStation(particle.GetPosition())) {
384 
385  Point hitPoint;
386  if (detStation.IsHit(particle.GetPosition(),
387  particle.GetDirection(),
388  hitPoint)) {
389  particle.SetPosition(hitPoint);
390  } else {
391  // if it does not intersect the tank re-inject
392  --i;
393  continue;
394  }
395  }
396  station.AddParticle(particle);
397  ++totalSimulatedParticles;
398  }
399 
400  ostringstream info;
401  info << "Injected " << nParticles << " particle" << String::Plural(nParticles) << ", "
402  "simulated " << totalSimulatedParticles << " particle" << String::Plural(totalSimulatedParticles);
403  INFO(info);
404  }
405 
406 
407  double
409  {
410  if (!fDiscreteAzimuth.empty()) {
411  const auto n = fDiscreteAzimuth.size();
412  const auto i = RandFlat::shootInt(&fRandomEngine, 0, n);
413  return fDiscreteAzimuth[i];
414  }
415 
417  }
418 
419 
420  double
422  {
423  if (!fDiscreteZenith.empty()) {
424  const auto n = fDiscreteZenith.size();
425  const auto i = RandFlat::shootInt(&fRandomEngine, 0, n);
426  return fDiscreteZenith[i];
427  }
428 
430  }
431 
432 
433  double
434  ParticleInjector::GenerateEnergy(const Particle::Type particleType, const int i)
435  {
436  if (!fFixedEnergy.empty())
437  return fFixedEnergy.at(i);
438 
439  switch (particleType) {
444  break;
449  break;
453  break;
454  default:
455  ostringstream msg;
456  msg << "Energy for particle type " << particleType << " was not provided. "
457  "Injection in ParticleInjector. Shooting default spectrum";
458  INFO(msg);
459  }
460 
462  }
463 
464 
465  double
467  {
468  const auto n = fDiscreteParticleTime.size();
469  const auto i = RandFlat::shootInt(&fRandomEngine, 0, n);
470  return fDiscreteParticleTime[i];
471  }
472 
473 
474  void
475  ParticleInjector::GeneratePosition(double& x, double& y, double& z)
476  {
477  if (fPositionFlag == eFixed) {
478 
479  x = fX;
480  y = fY;
481  z = fZ;
482 
483  } else if (fPositionFlag == eSphere) {
484 
485  // this was copied from the ParticleInjectorOG
486  const double theta = acos(RandFlat::shoot(&fRandomEngine, 0, 1));
487  const double phi = RandFlat::shoot(&fRandomEngine, 0, kTwoPi);
488  const double radiusSinTheta = fRadius * sin(theta);
489  x = radiusSinTheta * cos(phi);
490  y = radiusSinTheta * sin(phi);
491  z = fRadius * cos(theta);
492 
493  } else if (fPositionFlag == eDisk) {
494 
495  const double radius = sqrt(RandFlat::shoot(&fRandomEngine, 0, Sqr(fRadius)));
496  const double phi = RandFlat::shoot(&fRandomEngine, 0, kTwoPi);
497  x = radius * cos(phi);
498  y = radius * sin(phi);
499  z = fHeight;
500 
501  } else {
502 
506 
507  }
508  }
509 
510 
513  {
514  auto discreteB = branch.GetChild("Discrete");
515  if (discreteB) {
516 
517  const auto xx = discreteB.GetChild("x").Get<vector<double>>();
518  const auto weights = discreteB.GetChild("y").Get<vector<double>>();
519 
520  return new RandomSamplerFromPDF(xx, weights,
521  RandomSamplerFromPDF::eDiscrete);
522 
523  } else {
524 
525  auto pdfB = branch.GetChild("PDF");
526  if (pdfB) {
527 
528  const auto formula = pdfB.Get<string>();
529  const double min = branch.GetChild("Min").Get<double>();
530  const double max = branch.GetChild("Max").Get<double>();
531  return new RandomSamplerFromPDF(formula.c_str(), min, max);
532 
533  } else {
534 
535  auto xB = branch.GetChild("X");
536  if (xB) {
537  const auto fluxes = branch.GetChild("Y").Get<vector<double>>();
538  const auto xx = branch.GetChild("X").Get<vector<double>>();
539  return new RandomSamplerFromPDF(TabulatedFunction(xx, fluxes),
540  RandomSamplerFromPDF::eLinear);
541 
542  } else
543  ERROR("Unkown format of the distribution!");
544 
545  }
546  }
547 
548  return nullptr;
549  }
550 
551 }
constexpr T Sqr(const T &x)
Point object.
Definition: Point.h:32
bool HasMEvent() const
Report success to RunController.
Definition: VModule.h:62
void MakeSimData()
Make station simulated data object.
void SetPosition(const utl::Point &position)
Definition: Particle.h:111
Describes a particle for Simulation.
Definition: Particle.h:26
Class to hold collection (x,y) points and provide interpolation between them.
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
fwk::VModule::ResultFlag Run(evt::Event &theEvent)
Run: invoked once per event.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
Type
Particle types.
Definition: Particle.h:48
double shoot(HepEngine &engine) const
Method to shoot random values using a given engine by-passing the static generator.
double GetMag() const
Definition: Vector.h:58
bool StringEquivalent(const std::string &a, const std::string &b, Predicate p)
Utility to compare strings for equivalence. It takes a predicate to determine the equivalence of indi...
Definition: StringCompare.h:38
void GeneratePosition(double &x, double &y, double &z)
T Get() const
Definition: Branch.h:271
const char * Plural(const T n)
Definition: String.h:104
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
class to hold data at Station level
bool HasSimData() const
Check whether station simulated data exists.
utl::VRandomSampler * LoadRandomSampler(const utl::Branch &branch)
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
constexpr double kTwoPi
Definition: MathConstants.h:27
void AddParticle(const utl::Particle &particle)
double GenerateEnergy(const utl::Particle::Type particle, const int i)
A TimeInterval is used to represent time elapsed between two events.
Definition: TimeInterval.h:43
constexpr double GeV
Definition: AugerUnits.h:187
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
fwk::VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
Collection of pre-defined random engines.
int CorsikaToPDG(const int corsikaCode)
converters from CORSIKA to PDG particle codes
struct particle_info particle[80]
constexpr double kilometer
Definition: AugerUnits.h:93
Vector object.
Definition: Vector.h:30
const Point & GetPosition() const
Position of the particle.
Definition: Particle.h:110
Report failure to RunController, causing RunController to terminate execution.
Definition: VModule.h:64
utl::CoordinateSystemPtr Get(const std::string &id)
Get a well-known Coordinate System.
char * filename
Definition: dump1090.h:266
utl::RandomEngine::RandomEngineType & fRandomEngine
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
const Vector & GetDirection() const
Unit vector giving particle direction.
Definition: Particle.h:114
bool HasSEvent() const
Class to shoot random numbers given by a user-defined distribution function.
static bool IsNucleus(const int type)
Check if type code is a valid nucleus.

, generated on Tue Sep 26 2023.