FastTankSimulator.cc
Go to the documentation of this file.
1 
9 #include "FastTankSimulator.h"
10 
11 #include <fwk/CentralConfig.h>
12 #include <fwk/RandomEngineRegistry.h>
13 
14 #include <det/Detector.h>
15 
16 #include <evt/Event.h>
17 
18 #include <sdet/SDetector.h>
19 #include <sdet/Station.h>
20 
21 #include <sevt/PMT.h>
22 #include <sevt/PMTSimData.h>
23 #include <sevt/SEvent.h>
24 #include <sevt/Station.h>
25 #include <sevt/StationSimData.h>
26 
27 #include <utl/AugerUnits.h>
28 #include <utl/ErrorLogger.h>
29 #include <utl/Particle.h>
30 #include <utl/PhysicalConstants.h>
31 #include <utl/Point.h>
32 #include <utl/RandomEngine.h>
33 #include <utl/TimeDistribution.h>
34 #include <utl/Math.h>
35 #include <utl/Reader.h>
36 
37 #include <CLHEP/Random/RandFlat.h>
38 #include <CLHEP/Random/RandPoisson.h>
39 
40 using namespace FastTankSimulatorOG;
41 using namespace fwk;
42 using namespace det;
43 using namespace evt;
44 using namespace sdet;
45 using namespace sevt;
46 using namespace utl;
47 using namespace std;
48 
49 
50 using CLHEP::RandFlat;
51 using CLHEP::RandPoisson;
52 
53 
55  fInitialParticle(
56  utl::Particle::eUndefined,
57  utl::Particle::eShower,
58  utl::Point(0, 0, 0, CoordinateSystem::GetRootCoordinateSystem()),
59  utl::Vector(0, 0, 0, CoordinateSystem::GetRootCoordinateSystem()),
60  utl::TimeInterval(0),
61  0
62  )
63 { }
64 
65 
68 {
69  Branch topBranch =
70  CentralConfig::GetInstance()->GetTopBranch("FastTankSimulator");
71 
72  topBranch.GetChild("dEdXMuon").GetData(fdEdXMuon);
73  topBranch.GetChild("dEdXElectron").GetData(fdEdXElectron);
74  topBranch.GetChild("CerenkovMinMuon").GetData(fCerenkovMinMuon);
75  topBranch.GetChild("CerenkovMinElectron").GetData(fCerenkovMinElectron);
76  topBranch.GetChild("EMinPhoton").GetData(fEMinPhoton);
77  topBranch.GetChild("PhotoElectronRate").GetData(fPhotoElectronRate);
78  topBranch.GetChild("WaterRIndex").GetData(fWaterRIndex);
79  topBranch.GetChild("PECumulativeProb").GetData(fPECumulativeProbability);
80 
81  vector<double> photonInteractionLength;
82  topBranch.GetChild("PhotonInteractionLength").GetData(photonInteractionLength);
83  vector<double> pairProductionProbability;
84  topBranch.GetChild("PairProductionProbability").GetData(pairProductionProbability);
85  vector<double> energyTable;
86  topBranch.GetChild("EnergyTable").GetData(energyTable);
87 
89  utl::TabulatedFunction(energyTable, pairProductionProbability);
91  utl::TabulatedFunction(energyTable, photonInteractionLength);
92 
93  fRandomEngine = &RandomEngineRegistry::GetInstance().Get(RandomEngineRegistry::eDetector);
94 
95  return eSuccess;
96 }
97 
98 
101 {
102  if (!theEvent.HasSEvent()) {
103  ERROR("Non-existent SEvent.");
104  return eFailure;
105  }
106 
107  sevt::SEvent& theSEvent = theEvent.GetSEvent();
108 
109  const sdet::SDetector& theSDetector =
110  det::Detector::GetInstance().GetSDetector();
111 
112  for (sevt::SEvent::StationIterator sIt = theSEvent.StationsBegin();
113  sIt != theSEvent.StationsEnd(); ++sIt)
114 
115  if (sIt->HasSimData()) {
116 
117  sevt::StationSimData& simData = sIt->GetSimData();
118  simData.SetSimulatorSignature("FastTankSimulatorOG"); // should this necessarily be same as module name?
119  fCurrentEventStation = &(*sIt);
120 
121  fCurrentDetectorStation = &theSDetector.GetStation(sIt->GetId());
122 
124 
125  const double tankRadius = fCurrentDetectorStation->GetRadius();
126 
127  fTankRadiusSquared = Sqr(tankRadius);
128 
129  const unsigned long numParticles =
130  simData.ParticlesEnd() - simData.ParticlesBegin();
131 
132  /*
133  * Counting the number of particles that are actually simulated (post
134  * station-level thinning). Due to resampling simulation option that
135  * uses cycles with maximum particle number per cycle, we always check
136  * if particles have already been simulated.
137  */
138  const unsigned int nParticlesAlreadySimulated = simData.GetTotalSimParticleCount();
139  if (!nParticlesAlreadySimulated)
140  simData.SetTotalSimParticleCount(numParticles);
141  else
142  simData.SetTotalSimParticleCount(nParticlesAlreadySimulated + numParticles);
143 
144  for (sevt::StationSimData::ParticleIterator pIt = sIt->GetSimData().ParticlesBegin();
145  pIt != sIt->GetSimData().ParticlesEnd(); ++pIt) {
146 
147  fInitialParticle = *pIt;
148 
149  switch (fInitialParticle.GetType()) {
153  break;
156  break;
160  break;
161  }
162 
163  }
164 
165  }
166 
167  return eSuccess;
168 }
169 
170 
173 {
174  return eSuccess;
175 }
176 
177 
178 double
180 {
181  const CoordinateSystemPtr cs =
183 
184  double x, y, z;
185  boost::tie(x, y, z) = particle.GetPosition().GetCoordinates(cs);
186  double pX, pY, pZ;
187  boost::tie(pX, pY, pZ) = particle.GetDirection().GetCoordinates(cs);
188 
189  const double a = particle.GetDirection().GetRho(cs);
190  const double b = x*pX + y*pY;
191  const double b2 = Sqr(b);
192  const double c = particle.GetPosition().GetRho2(cs) - fTankRadiusSquared;
193  const double ac = a*c;
194 
195  // Vertical component
196  const double vertDistance = (pZ < 0) ? -z/pZ : (fTankHeight - z)/pZ;
197 
198  // Horizontal component
199  if (a) {
200  const double horizDistance = (b2 >= ac) ? (-b + sqrt(b2 - ac))/a : 0;
201  return min(vertDistance, horizDistance);
202  }
203 
204  return vertDistance;
205 }
206 
207 
208 double
210  const double energyLoss)
211 {
212  double ratio;
213  double mass;
214 
215  switch (particle.GetType()) {
216 
219  mass = utl::kElectronMass;
221  break;
222 
225  mass = utl::kMuonMass;
227  break;
228 
229  default:
230  return 0;
231 
232  }
233 
234  const double energy = particle.GetKineticEnergy();
235  const double energyDifference = energy - energyLoss;
236 
237  if (energyDifference > 0)
238  return ratio*energyDifference *
239  (1 - (mass/(2*energyDifference*(Sqr(fWaterRIndex) - 1))) *
240  log((energy/energyLoss) *
241  (energyLoss + 2*mass)/(energy + 2*mass)));
242 
243  return 0;
244 }
245 
246 
247 void
249  const double cerenkovRate)
250 {
252  pmtIt != fCurrentEventStation->PMTsEnd(); ++pmtIt) {
253 
254  if (!pmtIt->HasSimData())
255  pmtIt->MakeSimData();
256 
257  sevt::PMTSimData& thePMTSimData = pmtIt->GetSimData();
258 
259  const unsigned int numberPhotoElectrons =
260  RandPoisson::shoot(&fRandomEngine->GetEngine(), cerenkovRate);
261 
262  for (unsigned int countPE = 0; countPE < numberPhotoElectrons; ++countPE) {
263 
264  // For each PE, choose a time slot according to the
265  // tabulated probability
266 
267  const double randNum =
268  RandFlat::shoot(&fRandomEngine->GetEngine(), 0, 1);
269 
270  // Guaranteed to terminate
271  int j;
272  for (j = 0; randNum > fPECumulativeProbability[j]; ++j)
273  ;
274 
275  const double time = particle.GetTime().GetInterval() + j*ns;
276 
277  if (!thePMTSimData.HasPETimeDistribution())
278  thePMTSimData.MakePETimeDistribution();
279 
280  pmtIt->GetSimData().GetPETimeDistribution().AddTime(time);
281 
283 
284  switch (fInitialParticle.GetType()) {
288  break;
291  break;
294  component = sevt::StationConstants::eMuon;
295  break;
296  }
297 
298  if (component != sevt::StationConstants::eTotal) {
299  if (!thePMTSimData.HasPETimeDistribution(component))
300  thePMTSimData.MakePETimeDistribution(component);
301  thePMTSimData.GetPETimeDistribution(component).AddTime(time);
302  }
303 
304  }
305 
306  }
307 
308 }
309 
310 
311 void
313 {
314  const double energy = particle.GetKineticEnergy();
315 
316  if (energy < fCerenkovMinElectron)
317  return;
318 
319  const double distance = CalculateDistanceInTank(particle);
320 
321  const double energyLoss =
322  max(energy - fdEdXElectron*distance, fCerenkovMinElectron);
323 
324  const double rate = CalculateIntegratedCerenkovRate(particle, energyLoss);
325  CalculatePhotoElectrons(particle, rate);
326 }
327 
328 
329 void
331 {
332  const double energy = particle.GetKineticEnergy();
333 
334  if (energy < fCerenkovMinMuon)
335  return;
336 
337  const double distance = CalculateDistanceInTank(particle);
338 
339  const double energyLoss =
340  max(energy - fdEdXMuon*distance, fCerenkovMinMuon);
341 
342  const double rate = CalculateIntegratedCerenkovRate(particle, energyLoss);
343  CalculatePhotoElectrons(particle, rate);
344 }
345 
346 
347 void
349 {
350  const double energy = particle.GetKineticEnergy();
351 
352  // If energy is below 100 keV, return without any further simulation. The old
353  // way of calculating the index into the table caused problems on Bruce's
354  // laptop. It was a retarded, and un-safe, way of calculating the proper
355  // index into the interaction length table, anyway. So, we now use a
356  // pre-calculated energy table, and have some tighter sanity checks before
357  // continuing with the photon simulation.
358 
359  if (energy < fPhotonInteractionLength.GetX(0))
360  return;
361 
362  //if (energy < fEnergyTable.front())
363  //return;
364 
365  //unsigned int index = 0;
366 
367  //for ( ; index < fEnergyTable.size(); ++index)
368  //if (energy <= fEnergyTable.at(index))
369  //break;
370 
371  //const unsigned int index = min(max(0, int(lookupValue)), int(fPhotonInteractionLength.size() - 1));
372 
373  // We assume that if the energy is greater than 10 GeV, the interaction
374  // length, and pair production probability are constant, and set at the
375  // values obtained for 10 GeV
376 
377  // Use this for both the interaction length and production probability size
378  // since they are over the same size energy table
379 
380  const unsigned int nPoints = fPhotonInteractionLength.GetNPoints();
381 
382  const double interactionLength =
383  (energy > fPhotonInteractionLength.GetX(nPoints-1)) ?
385 
386  const double pathLength =
387  -log(RandFlat::shoot(&fRandomEngine->GetEngine(), 0, 1)) *
388  interactionLength;
389 
390  const double distanceInTank = CalculateDistanceInTank(particle);
391 
392  if (pathLength < distanceInTank) {
393 
394  const Point pos =
395  particle.GetPosition() + pathLength*particle.GetDirection();
396 
397  const TimeInterval time =
398  particle.GetTime() + utl::TimeInterval(pathLength/kSpeedOfLight);
399 
400  const Particle newParticle(
401  particle.GetType(),
402  particle.GetSource(),
403  pos,
404  particle.GetDirection(),
405  time,
406  particle.GetWeight(),
407  energy
408  );
409 
410  const double randNum = RandFlat::shoot(&fRandomEngine->GetEngine(), 0, 1);
411 
412  const double productionProbability =
413  (energy > fPairProductionProbability.GetX(nPoints-1)) ?
415 
416  if (randNum < productionProbability)
417  SimulatePairProduction(newParticle);
418  else
419  SimulateComptonScattering(newParticle);
420 
421  }
422 }
423 
424 
425 void
427 {
428  utl::Particle newElectron(
430  particle.GetSource(),
431  particle.GetPosition(),
432  particle.GetDirection(),
433  particle.GetTime(),
434  particle.GetWeight(),
435  particle.GetKineticEnergy()
436  );
437 
438  utl::Particle newPositron(
440  particle.GetSource(),
441  particle.GetPosition(),
442  particle.GetDirection(),
443  particle.GetTime(),
444  particle.GetWeight(),
445  particle.GetKineticEnergy()
446  );
447 
448  const double maxKineticEnergy = particle.GetKineticEnergy() - 2*kElectronMass;
449  const double kineticEnergy =
450  RandFlat::shoot(&fRandomEngine->GetEngine(), 0, maxKineticEnergy);
451 
452  newElectron.SetKineticEnergy(kineticEnergy);
453  newPositron.SetKineticEnergy(maxKineticEnergy - kineticEnergy);
454 
455  SimulateElectrons(newElectron);
456  SimulateElectrons(newPositron);
457 }
458 
459 
460 void
462 {
463  const double energy = particle.GetKineticEnergy();
464 
465  // Minimum energy for final photon
466  const double energyMin = 1/(1/energy + 2/kElectronMass);
467 
468  // Simplified KN distribution with rejection
469  const double b = energyMin/energy + energy/energyMin;
470  double energyFinal;
471  double a;
472 
473  do {
474 
475  energyFinal =
476  RandFlat::shoot(&fRandomEngine->GetEngine(), energyMin, energy);
477 
478  a = energyFinal/energy + energy/energyFinal;
479 
480  } while (RandFlat::shoot(&fRandomEngine->GetEngine(), 0, 1) > a/b);
481 
482  // Scattering angles (final photon wrt initial photon)
483  const double cosTheta = 1 + kElectronMass * (1/energy - 1/energyFinal);
484  const double sinTheta = sqrt(1 - Sqr(cosTheta));
485 
486  const double phi =
487  RandFlat::shoot(&fRandomEngine->GetEngine(), 0, kTwoPi);
488  const double cosPhi = cos(phi);
489  const double sinPhi = sin(phi);
490 
491  // Construct two unit vectors perpendicular to the initial photon
492  const CoordinateSystemPtr cs =
494 
495  const Vector dir = particle.GetDirection();
496 
497  double pX, pY, pZ;
498  boost::tie(pX, pY, pZ) = dir.GetCoordinates(cs);
499 
500  const double uR = dir.GetRho(cs);
501 
502  double vX, vY;
503  double wX, wY, wZ;
504 
505  if (uR > 0) {
506 
507  vX = -pY/uR;
508  vY = pX/uR;
509  wX = -pZ*vY;
510  wY = pZ*vX;
511  wZ = pX*vY - pY*vX;
512 
513  } else {
514 
515  vX = 1;
516  vY = 0;
517  wX = 0;
518  wY = 1;
519  wZ = 0;
520 
521  }
522 
523  const Vector u = cosTheta * dir +
524  sinTheta * Vector(cosPhi*vX+sinPhi*wX, cosPhi*vY+sinPhi*wY, sinPhi*wZ, cs);
525 
526  Vector v = energy * dir - energyFinal * u;
527 
528  v.Normalize();
529 
530  // This is the final photon
531  utl::Particle newPhoton(
533  particle.GetSource(),
534  particle.GetPosition(),
535  u,
536  particle.GetTime(),
537  particle.GetWeight(),
538  energyFinal
539  );
540 
541  // This is the final electron
542  const double electronEnergy = energy - energyFinal;
543  utl::Particle newElectron(
545  particle.GetSource(),
546  particle.GetPosition(),
547  v,
548  particle.GetTime(),
549  particle.GetWeight(),
550  electronEnergy
551  );
552 
553  // Do the simulation
554  SimulateElectrons(newElectron);
555  SimulatePhotons(newPhoton);
556 }
Branch GetTopBranch() const
Definition: Branch.cc:63
unsigned int GetNPoints() const
Station Level Simulated Data
StationIterator StationsEnd()
End of all stations.
Definition: SEvent.h:59
void Normalize()
Definition: Vector.h:64
constexpr T Sqr(const T &x)
Point object.
Definition: Point.h:32
const TimeInterval & GetTime() const
Arrival time delay at the ground.
Definition: Particle.h:122
Report success to RunController.
Definition: VModule.h:62
total (shower and background)
constexpr double kElectronMass
RandomEngineType & GetEngine()
Definition: RandomEngine.h:32
void CalculatePhotoElectrons(const utl::Particle &p, const double)
Interface class to access to the SD part of an event.
Definition: SEvent.h:39
Describes a particle for Simulation.
Definition: Particle.h:26
PMTIterator PMTsBegin(const sdet::PMTConstants::PMTType type=sdet::PMTConstants::eWaterCherenkovLarge)
begin PMT iterator for read/write
Class to hold collection (x,y) points and provide interpolation between them.
void SimulatePhotons(const utl::Particle &p)
Constructors for Transformer classes.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
boost::filter_iterator< PMTFilter, InternalPMTIterator > PMTIterator
Iterator over station for read/write.
void SetSimulatorSignature(const std::string &name)
Set name of the tank simulator module used to simulate this station.
bool HasPETimeDistribution(const StationConstants::SignalComponent source=StationConstants::eTotal) const
Check if a PE release time distribution exists (optionally for a given source)
Definition: PMTSimData.h:65
void SimulateComptonScattering(const utl::Particle &p)
ParticleVector::iterator ParticleIterator
VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
electrons and positrons from shower
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
void SimulatePairProduction(const utl::Particle &p)
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
const double ns
void SimulateElectrons(const utl::Particle &p)
VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
constexpr double kTwoPi
Definition: MathConstants.h:27
utl::CoordinateSystemPtr GetLocalCoordinateSystem() const
Get the Auger reference system centered on the tank.
double GetRadius() const
Radius of the tank (water only)
double GetHeight() const
Height of the tank (water only)
PMTIterator PMTsEnd(const sdet::PMTConstants::PMTType type=sdet::PMTConstants::eWaterCherenkovLarge)
end PMT iterator for read/write
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
const double & GetY(const unsigned int idx) const
double GetInterval() const
Get the time interval as a double (in Auger base units)
Definition: TimeInterval.h:69
double GetRho(const CoordinateSystemPtr &coordinateSystem) const
radius r in cylindrical coordinates (distance to z axis)
Definition: BasicVector.h:263
ParticleIterator ParticlesBegin()
Beginning of simulated particles entering the station.
double CalculateDistanceInTank(const utl::Particle &p)
double GetKineticEnergy() const
Get kinetic energy of the particle.
Definition: Particle.h:130
VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
void SimulateMuons(const utl::Particle &p)
constexpr double kMuonMass
constexpr double kSpeedOfLight
const sdet::Station * fCurrentDetectorStation
A TimeInterval is used to represent time elapsed between two events.
Definition: TimeInterval.h:43
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
double GetWeight() const
Particle weight (assigned by shower generator thinning algorithms)
Definition: Particle.h:126
unsigned int GetTotalSimParticleCount() const
Get the total number of particles that were actually simulated (after thinning)
void SetTotalSimParticleCount(const unsigned int n)
StationIterator StationsBegin()
Beginning of all stations.
Definition: SEvent.h:57
Source GetSource() const
Source of the particle (eg. shower or background)
Definition: Particle.h:107
Class to hold simulated data at PMT level.
Definition: PMTSimData.h:40
struct particle_info particle[80]
Vector object.
Definition: Vector.h:30
const double & GetX(const unsigned int idx) const
double GetRho2(const CoordinateSystemPtr &coordinateSystem) const
radius r^2 in cylindrical coordinates (distance to z axis)^2
Definition: BasicVector.h:266
int GetType() const
Definition: Particle.h:101
Detector description interface for SDetector-related data.
Definition: SDetector.h:42
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
double CalculateIntegratedCerenkovRate(const utl::Particle &p, const double)
boost::indirect_iterator< InternalStationIterator, Station & > StationIterator
Iterator over all stations.
Definition: SEvent.h:52
utl::TabulatedFunction fPairProductionProbability
utl::TimeDistributionI & GetPETimeDistribution(const StationConstants::SignalComponent source=StationConstants::eTotal)
Simulated photoelectron time distribution.
Definition: PMTSimData.h:54
const Station & GetStation(const int stationId) const
Get station by Station Id.
Definition: SDetector.cc:192
double Y(const double x) const
Get or interpolate the Y value that corresponds to parameter x.
utl::TabulatedFunction fPhotonInteractionLength
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
ParticleIterator ParticlesEnd()
End of simulated particles entering the station.
const Vector & GetDirection() const
Unit vector giving particle direction.
Definition: Particle.h:114
void AddTime(const double time, const T weight=T(1))
Add an entry (optionally weighted) for the given time. Slot will be computed.
std::vector< double > fPECumulativeProbability
sevt::SEvent & GetSEvent()
mu+ and mu- (including signal from mu decay electrons) from shower
bool HasSEvent() const
void MakePETimeDistribution(const StationConstants::SignalComponent source=StationConstants::eTotal)
Create a PE release time distribution (optionally for given source)
Definition: PMTSimData.cc:12

, generated on Tue Sep 26 2023.