CachedShowerRegeneratorOG/CachedShowerRegenerator.cc
Go to the documentation of this file.
1 
10 #include <utl/config.h>
11 
13 #include "LogGaussSmearing.h"
14 
15 #include <fwk/CentralConfig.h>
16 #include <fwk/CoordinateSystemRegistry.h>
17 #include <fwk/RandomEngineRegistry.h>
18 
19 #include <evt/Event.h>
20 #include <evt/ShowerSimData.h>
21 
22 #include <sevt/SEvent.h>
23 #include <sevt/Station.h>
24 #include <sevt/StationSimData.h>
25 
26 #include <det/Detector.h>
27 #include <sdet/SDetector.h>
28 #include <sdet/Station.h>
29 #include <sdet/Scintillator.h>
30 
31 #include <mdet/MDetector.h>
32 
33 #include <cdet/CDetector.h>
34 #include <cdet/Station.h>
35 
36 #include <utl/ErrorLogger.h>
37 #include <utl/GeometryUtilities.h>
38 #include <utl/MathConstants.h>
39 #include <utl/Particle.h>
40 #include <utl/ParticleCases.h>
41 #include <utl/PhysicalConstants.h>
42 #include <utl/Point.h>
43 #include <utl/RandomEngine.h>
44 #include <utl/TimeStamp.h>
45 #include <utl/Math.h>
46 #include <utl/Reader.h>
47 #include <utl/TabularStream.h>
48 #include <utl/TabulatedFunction.h>
49 
50 #include <CLHEP/Random/RandFlat.h>
51 #include <CLHEP/Random/RandPoisson.h>
52 
53 #include <cmath>
54 #include <sstream>
55 #include <vector>
56 #include <limits>
57 
58 using namespace CachedShowerRegeneratorOG;
59 using namespace fwk;
60 using namespace evt;
61 using namespace sevt;
62 using namespace utl;
63 using namespace std;
64 
65 using CLHEP::RandFlat;
66 using CLHEP::RandPoisson;
67 
68 
69 //#define DUMP_PARTICLES
70 
71 
73 
74 #ifdef DUMP_PARTICLES
75  ShadowPtr<ofstream> gParticleDump;
76 
77 
78  inline
79  double
80  RadiusXY(const Vector& v, const CoordinateSystemPtr& cs)
81  {
82  return sqrt(Sqr(v.GetX(cs)) + Sqr(v.GetY(cs)));
83  }
84 
85 
86 # define DUMP(_pStationDistance_, _pStationDistanceXY_, _timeShift_, _injectionZ_) \
87  *gParticleDump \
88  << sId << ' ' \
89  << Point(0,0,0, dStationCS).GetX(showerCS) << ' ' \
90  << Point(0,0,0, dStationCS).GetY(showerCS) << ' ' \
91  << RadiusXY(corePosition - Point(0,0,0, dStationCS), showerCS) / meter << ' ' \
92  << particle.GetType() << ' ' \
93  << particle.GetKineticEnergy() / GeV << ' ' \
94  << pWeight << ' ' \
95  << avgN << ' ' \
96  << n << ' ' \
97  << pPosition.GetX(showerCS) << ' ' \
98  << pPosition.GetY(showerCS) << ' ' \
99  << sqrt(exp(pLnR2)) / meter << ' ' \
100  << (_pStationDistance_) / meter << ' ' \
101  << (_pStationDistanceXY_) / meter << ' ' \
102  << (_timeShift_) / nanosecond << ' ' \
103  << (_injectionZ_) / meter \
104  << '\n'
105 # define DUMP_REJECT DUMP(0, 0, 0, 0)
106 
107 #else
108 
109 # define DUMP(_pStationDistance_, _pStationDistanceXY_, _timeShift_, _injectionZ_)
110 # define DUMP_REJECT
111 
112 #endif
113 
114 
115  template<typename Map, typename T>
116  inline
117  void
118  InsertValue(Map& map, const int sId, const T& value)
119  {
120  const auto sIt = map.find(sId);
121  if (sIt != map.end())
122  sIt->second(value);
123  else
124  map.insert(make_pair(sId, typename Map::mapped_type(value)));
125  }
126 
127 
128  inline
129  double
130  Round(const double div, const double val)
131  {
132  return round(div * val) / div;
133  }
134 
135 
137 
148  inline
149  double
150  PlaneFrontTime(const CoordinateSystemPtr& showerCS, const Point& corePosition,
151  const Point& position)
152  {
153  // assuming t_c iz zero
154  return (corePosition.GetZ(showerCS) - position.GetZ(showerCS)) / kSpeedOfLight;
155  }
156 
157 
158  inline
159  bool
161  {
162  return
163  p.GetType() == utl::Particle::eMuon ||
167  }
168 
169 
172  {
173  Branch topB = CentralConfig::GetInstance()->GetTopBranch("CachedShowerRegenerator");
174 
175  const unsigned int maxUI = numeric_limits<unsigned int>::max();
176 
177  topB.GetChild("LimitParticlesPerCycle").GetData(fLimitParticlesPerCycle);
178  fParticlesPerCycle = maxUI;
179  if (fLimitParticlesPerCycle)
180  topB.GetChild("ParticlesPerCycle").GetData(fParticlesPerCycle);
181 
182  topB.GetChild("UseWeightedStationSimulation").GetData(fUseWeightedStationSimulation);
183  fWeightedStationSimulationParticleLimit = maxUI;
184  if (fUseWeightedStationSimulation) {
185  topB.GetChild("WeightedStationSimulationParticleLimit").GetData(fWeightedStationSimulationParticleLimit);
186  Branch wtFactorB = topB.GetChild("WeightedStationSimulationThinningFactor");
187  if (wtFactorB)
188  wtFactorB.GetData(fWeightedStationSimulationThinningFactor);
189  }
190 
191  if (fParticlesPerCycle != maxUI && fWeightedStationSimulationParticleLimit != maxUI) {
192  ERROR("The <LimitParticlesPerCycle> and <UseWeightedStationSimulation> options are incompatible, "
193  "only one should be enabled.");
194  return eFailure;
195  }
196 
197  Branch distanceCutsB = topB.GetChild("DistanceCuts");
198  fInnerRadiusCut = 0;
199  const AttributeMap useAtt({{ "use", "yes" }});
200  Branch ircB = distanceCutsB.GetChild("InnerRadiusCut", useAtt);
201  if (ircB)
202  ircB.GetData(fInnerRadiusCut);
203 
204  fOuterRadiusCut = 1e6*km;
205  Branch orcB = distanceCutsB.GetChild("OuterRadiusCut", useAtt);
206  if (orcB)
207  orcB.GetData(fOuterRadiusCut);
208 
209  Branch energyCutsB = topB.GetChild("EnergyCuts");
210  energyCutsB.GetChild("ElectronEnergyCut").GetData(fElectronEnergyCut);
211  energyCutsB.GetChild("MuonEnergyCut").GetData(fMuonEnergyCut);
212  energyCutsB.GetChild("PhotonEnergyCut").GetData(fPhotonEnergyCut);
213  energyCutsB.GetChild("HadronEnergyCut").GetData(fHadronEnergyCut);
214  energyCutsB.GetChild("MesonEnergyCut").GetData(fMesonEnergyCut);
215 
216  Branch algoB = topB.GetChild("AlgorithmParameters");
217  algoB.GetChild("DeltaROverR").GetData(fDeltaROverR);
218  algoB.GetChild("DeltaPhi").GetData(fDeltaPhi);
219  algoB.GetChild("HorizontalParticleCosThetaCut").GetData(fHorizontalParticleCut);
220  fHorizontalParticleCut = std::abs(fHorizontalParticleCut);
221  algoB.GetChild("UseStationPositionMatrix").GetData(fUseStationPositionMatrix);
222  algoB.GetChild("PhiGranularity").GetData(fPhiGranularity);
223  algoB.GetChild("RGranularity").GetData(fRGranularity);
224  algoB.GetChild("LogGaussSmearingWidth").GetData(fLogGaussSmearingWidth);
225  algoB.GetChild("UseWeightDependentResamplingArea").GetData(fUseWeightDependentResamplingArea);
226 
227  fMuonWeightScale = 1;
228  Branch muonWeightScaleB = topB.GetChild("MuonWeightScale");
229  if (muonWeightScaleB)
230  muonWeightScaleB.GetData(fMuonWeightScale);
231 
232  fSimulateUMD = false;
233  Branch umdB = topB.GetChild("UMD");
234  if (umdB) {
235  umdB.GetChild("Simulate").GetData(fSimulateUMD);
236  umdB.GetChild("TightRadius").GetData(fUMDTightRadius);
237  umdB.GetChild("MaxRadius").GetData(fUMDMaxRadius);
238  if (fSimulateUMD) {
239  INFO("UMD tank+ground G4 simulation has been activated");
240  if (fUseWeightedStationSimulation)
241  WARNING("UMD does not handle weighted particles. The LimitParticlesPerCycle option should be used instead.");
242  }
243  }
244 
245  fSimulateMARTA = false;
246  Branch martaB = topB.GetChild("MARTA");
247  if (martaB) {
248  martaB.GetChild("Simulate").GetData(fSimulateMARTA);
249  martaB.GetChild("Radius").GetData(fMARTARadius);
250  if (fSimulateMARTA)
251  INFO("MARTA tank+RPC G4 simulation has been activated");
252  }
253 
254  fRandomEngine = &RandomEngineRegistry::GetInstance().Get(RandomEngineRegistry::eDetector).GetEngine();
255 
256  if (!fUseStationPositionMatrix)
257  WARNING("Not using StationPositionMatrix. "
258  "All stations will be searched for injection.");
259 
260  #ifdef DUMP_PARTICLES
261  gParticleDump =
262  new ofstream("CachedShowerRegenerator-particle_dump-"
263  "wdr" + to_string(int(fUseWeightDependentResamplingArea)) +
264  ".dat");
265  #endif
266 
267  return eSuccess;
268  }
269 
270 
271  inline
272  bool
274  const double energy)
275  const
276  {
277  switch (type) {
278  case OFFLINE_PHOTON:
279  return energy < fPhotonEnergyCut;
280  case OFFLINE_ELECTRONS:
281  return energy < fElectronEnergyCut;
282  case OFFLINE_MUONS:
283  return energy < fMuonEnergyCut;
284  case OFFLINE_BARYONS:
285  return energy < fHadronEnergyCut;
286  case OFFLINE_MESONS:
287  return energy < fMesonEnergyCut;
288  default:
289  return true;
290  }
291  }
292 
293 
294  void
296  {
297  fShowerData = new ShowerData(StationPositionMatrix(fPhiGranularity, fRGranularity));
298 
299  fShowerData->fWeightCounterMap.clear();
300 
301  if (fLogGaussSmearingWidth)
302  fShowerData->fLogGauss =
303  new LogGaussSmearing(fLogGaussSmearingWidth, fRandomEngine);
304 
305  auto& simShower = event.GetSimShower();
306  simShower.SetMuonWeightScale(fMuonWeightScale);
307 
308  if (simShower.GetMinRadiusCut() < fInnerRadiusCut) {
309  ostringstream msg;
310  msg << "Setting new value for fMinRadiusCut: " << fInnerRadiusCut;
311  INFO(msg);
312  simShower.SetMinRadiusCut(fInnerRadiusCut);
313  }
314 
315  fShowerData->fParticleIt = simShower.GroundParticlesBegin();
316  fShowerData->fParticlesEnd = simShower.GroundParticlesEnd();
317 
318  const auto localCS = simShower.GetLocalCoordinateSystem();
319  const double showerZenith = (-simShower.GetDirection()).GetTheta(localCS);
320  // area = pi (r1^2 - r2^2) (2 dPhi) / (2 pi). the 2 dPhi since its +- dPhi
321  const double samplingAreaFactor = fDeltaPhi / cos(showerZenith);
322 
323  if (!event.HasSEvent())
324  event.MakeSEvent();
325  auto& sEvent = event.GetSEvent();
326 
327  const auto showerCS = simShower.GetShowerCoordinateSystem();
328  const auto& corePosition = simShower.GetPosition();
329  const auto& coreTime = simShower.GetTimeStamp();
330  const auto& sDetector = det::Detector::GetInstance().GetSDetector();
331 
332  int nStations = 0;
333  int nInner = 0;
334  int nOuter = 0;
335 
336  for (const auto& sd : sDetector.StationsRange()) {
337 
338  ++nStations;
339 
340  const int sId = sd.GetId();
341 
342  if (!sEvent.HasStation(sId))
343  sEvent.MakeStation(sId);
344 
345  auto& station = sEvent.GetStation(sId);
346 
347  // clear particle lists for the station. The stuff above
348  // presumably only needs to be called once per shower, but
349  // particle clearing has to happen each time through.
350  if (!station.HasSimData())
351  station.MakeSimData();
352  auto& sSim = station.GetSimData();
353  if (station.HasScintillator() && !station.GetScintillator().HasSimData())
354  station.GetScintillator().MakeSimData();
355 
356  sSim.SetMaxNParticles(fWeightedStationSimulationParticleLimit);
357  sSim.SetThinningFactor(fWeightedStationSimulationThinningFactor);
358 
359  const auto& sPosition = sd.GetPosition();
360 
361  const TimeStamp planeTime =
362  coreTime + TimeInterval(PlaneFrontTime(showerCS, corePosition, sPosition));
363  sSim.SetPlaneFrontTime(planeTime);
364 
365  const double sR = sPosition.GetRho(showerCS);
366 
367  if (sR < fInnerRadiusCut) {
368  ++nInner;
369  sSim.SetIsInsideMinRadius();
370  continue;
371  }
372 
373  if (sR > fOuterRadiusCut) {
374  ++nOuter;
375  continue;
376  }
377 
378  // it is best to create station matrix based on log(r^2), see Reference Manual
379  const double r1 = max(sR*(1 - fDeltaROverR), fInnerRadiusCut);
380  const double r2 = min(sR*(1 + fDeltaROverR), fOuterRadiusCut);
381  const double lnSqrR1 = 2 * log(r1/meter);
382  const double lnSqrR2 = 2 * log(r2/meter);
383 
384  // DV: Particle weights are calculated by the shower simulation according
385  // to the particle densities as measured in the ground-particle plane.
386  // Thus all reweighting area ratios calculated in the resampler have to
387  // have area values expressed in the corresponding ground-particle plane
388  // projections, ie if there is a small missalignement of the tank vertical
389  // and the ground-particle plane vertical, it has to be taken into account
390  // with appropriate cosine of this small angle.
391  // First calculate the ground-particle area of the resampling pie
392  // section of a station:
393  const double samplingArea = samplingAreaFactor * (Sqr(r2) - Sqr(r1));
394 
395  fShowerData->fStationMatrix.PushBack(sd, station,
396  sPosition.GetPhi(showerCS), fDeltaPhi,
397  sR, lnSqrR1, lnSqrR2,
398  samplingArea);
399 
400  }
401 
402  fShowerData->fStationMatrix.CreateMatrix(fUseStationPositionMatrix);
403  fShowerData->fMinSqrR = exp(fShowerData->fStationMatrix.GetMinLnSqrR())*meter2;
404 
405  ostringstream info;
406  info << "Out of " << nStations << " stations: inner cut " << nInner << ", outer " << nOuter;
407  INFO(info);
408  }
409 
410 
413  {
414  if (!event.HasSimShower()) {
415  ERROR("Current event does not have a simulated shower.");
416  return eFailure;
417  }
418 
419  const auto& simShower = event.GetSimShower();
420 
421  // sim event finished ?
422  if (fShowerData && fShowerData->fParticleIt == fShowerData->fParticlesEnd) {
423  fShowerData = nullptr;
424  // break inner loop
425  return eBreakLoop;
426  }
427 
428  if (!fShowerData)
429  InitNewShower(event);
430 
431  const unsigned int maxUI = numeric_limits<unsigned int>::max();
432 
433  if (fParticlesPerCycle < maxUI) {
434  ostringstream info;
435  info << "Regenerating batch of " << fParticlesPerCycle << " particles.";
436  INFO(info);
437  }
438 
439  if (fWeightedStationSimulationParticleLimit < maxUI) {
440  ostringstream info;
441  info << "Will use weighted simulation for more than " << fWeightedStationSimulationParticleLimit
442  << " particles per station.";
443  INFO(info);
444  }
445 
446  const auto& sDetector = det::Detector::GetInstance().GetSDetector();
447  auto& sEvent = event.GetSEvent();
448 
449  // clear particle list for the stations
450  for (const auto& sd : sDetector.StationsRange())
451  sEvent.GetStation(sd.GetId()).GetSimData().ClearParticleList();
452 
453  const auto showerCS = simShower.GetShowerCoordinateSystem();
454  const auto& corePosition = simShower.GetPosition();
455  const auto grParticleCS = simShower.GetLocalCoordinateSystem();
456 
457  // Based on the cuts read in for the outer and inner radius in Init(), we
458  // build the list of stations that lie within the region of interest in
459  // the shower plane. We then loop only over these stations, since anything
460  // outside the limits defined by the outer and inner radius cuts will never
461  // receive any regenerated particles anyway.
462 
463  // keep count to avoid excessive memory consumption
464  unsigned int nParticlesInjected = 0;
465 
466  auto& particleIt = fShowerData->fParticleIt;
467  for (auto pEnd = fShowerData->fParticlesEnd; particleIt != pEnd; ++particleIt) {
468 
469  // over the cache limit?
470  if (fParticlesPerCycle && nParticlesInjected >= fParticlesPerCycle) {
471  ostringstream info;
472  info << nParticlesInjected << " particles processed.";
473  INFO(info);
474  return eSuccess;
475  }
476 
477  const auto& particle = *particleIt;
478 
479  const auto& pPosition = particle.GetPosition();
480  const double pR2ShowerFrame = pPosition.GetRho2(showerCS);
481 
482  if (pR2ShowerFrame <= fShowerData->fMinSqrR)
483  continue;
484 
485  if (IsParticleEnergyLow(particle.GetType(), particle.GetKineticEnergy()))
486  continue;
487 
488  const double pPhi = pPosition.GetPhi(showerCS);
489  const double pLnSqrR = log(pR2ShowerFrame);
490 
491  const auto& sList =
492  fShowerData->fStationMatrix.GetInjectionStations(pPhi, pLnSqrR);
493 
494  if (sList.empty())
495  continue;
496 
497  // particle time relative to the core time
498  const double pTime = particle.GetTime().GetInterval();
499 
500  // due to a bug in CORSIKA (version 6.900) when simulating upward going particles (option UPWARD)
501  // a few particles per shower get negative delays w.r.t. to the plane front, they behave like tachyons.
502  // see http://www-ik.fzk.de/~maurel/corsika_negative_particle_delays for a list
503  // of "superluminal" particles in a library simulated using the UPWARD option.
504  // Negative delays on the order of 0.01 ns are possible due to roundoff errors,
505  // only particles with a delay smaller than -0.1 ns are rejected here.
506  const double pPlaneFrontDelay = pTime - PlaneFrontTime(showerCS, corePosition, pPosition);
507  if (pPlaneFrontDelay < -0.1*ns)
508  continue;
509 
510  Particle newParticle = particle;
511  newParticle.SetWeight(1);
512 
513  for (const auto sInfo : sList) {
514 
515  const auto& dStation = sInfo->GetDetStation();
516  const auto stationCS = dStation.GetLocalCoordinateSystem();
517  const unsigned int sId = dStation.GetId();
518  const auto& pDirection = newParticle.GetDirection();
519 
520  // positive for down-going particles
521  const double pStationCosine = -pDirection.GetZ(stationCS);
522  // skip upward-going particles
523  if (pStationCosine <= 0) {
524  ++fShowerData->fUpwardSideParticles[sId];
525  continue;
526  }
527 
528  // positive for down-going particles
529  const double pPlaneCosine = -pDirection.GetZ(grParticleCS);
530  // skip horizontal particles
531  if (pPlaneCosine < fHorizontalParticleCut) {
532  ++fShowerData->fNHorizontalParticles;
533  continue;
534  }
535 
536  const double sThickness = dStation.GetThickness();
537  const double sRadius = dStation.GetRadius() + sThickness;
538  const double sHeight = dStation.GetHeight() + 2*sThickness;
539 
540  double injectionRadius = sRadius;
541  double injectionHeight = sHeight;
542 
543  // if MARTA simulation is enabled the tank is raised by the precast total height and so should the injection height
544  if (fSimulateMARTA) {
545  const auto& cStation =
546  det::Detector::GetInstance().GetCDetector().GetStation(sId);
547  injectionHeight +=
548  cStation.GetTankSupportTopSlabDimensions()[2] +
549  cStation.GetTankSupportCentralFootDimensions()[2] +
550  cStation.GetTankSupportCentralFootBaseDimensions()[2];
551  injectionRadius = max(injectionRadius, fMARTARadius);
552  }
553 
554  if (dStation.HasScintillator()) {
555  // Check if scintillator requires larger injection cylinder
556  const double scintRadius = dStation.GetScintillator().GetMaxRadius();
557  const double scintHeight = dStation.GetScintillator().GetMaxHeight();
558  injectionRadius = max(injectionRadius, scintRadius);
559  injectionHeight = max(injectionHeight, scintHeight);
560  }
561 
562  if (fSimulateUMD && dStation.ExistsAssociatedCounter()) {
563  const auto& mDet = det::Detector::GetInstance().GetMDetector();
564  const auto& dCounter = mDet.GetCounter(dStation.GetAssociatedCounterId());
565  const auto& mod = *dCounter.ModulesBegin();
566  const auto& modPos = mod.GetPosition();
567  const double depth = -modPos.GetZ(stationCS);
568  const double pPlaneSine = pDirection.GetRho(grParticleCS);
569  // increase radius for inclined particles so that shadow always hits UMD + depth * tan(theta)
570  const double umdRadius = fUMDTightRadius + depth * pPlaneSine/pPlaneCosine;
571  injectionRadius = min(fUMDMaxRadius, max(injectionRadius, umdRadius));
572  }
573 
574  const double pStationSine = pDirection.GetRho(stationCS);
575 
576  // "eff" here stands for effective areas as seen from the particle standpoint
577  const double effAreaTop = kPi * Sqr(injectionRadius) * pStationCosine;
578  const double effAreaSide = 2 * injectionRadius * injectionHeight * pStationSine;
579  const double effArea = effAreaTop + effAreaSide; // total
580 
581  const double pWeight = IsMuonic(particle) ?
582  fMuonWeightScale * particle.GetWeight() : particle.GetWeight();
583 
584  const double effResArea = sInfo->GetResamplingArea() * pPlaneCosine;
585 
586  // all particle positions within the resampling area are equivalent, define
587  // "weight density", ie the probability to find a particle with such properties
588  // within some area
589  const double avgN = pWeight * effArea / effResArea;
590 
591  unsigned int n = 0;
592  if (fUseWeightDependentResamplingArea && avgN < 1) {
593  // see GAP-2015-086 for details
594  if (!sInfo->IsInScaledArea(avgN, pPhi, pLnSqrR)) {
595  DUMP_REJECT;
596  continue;
597  }
598  // direct injection
599  InsertValue(fShowerData->fWeightStat, sId, 1);
600  n = 1;
601  } else {
602  // cloning
603  InsertValue(fShowerData->fWeightStat, sId, avgN);
604  n = RandPoisson::shoot(fRandomEngine, avgN);
605  }
606 
607  auto& station = sInfo->GetEvtStation();
608 
609  for (unsigned int i = 0; i < n; ++i) {
610 
611  if (RandFlat::shoot(fRandomEngine, 0, effArea) < effAreaTop) {
612  // top injection
613  const double r = injectionRadius * sqrt(RandFlat::shoot(fRandomEngine, 0, 1));
614  const double phi = RandFlat::shoot(fRandomEngine, 0, kTwoPi);
615  newParticle.SetPosition(Point(r, phi, injectionHeight, stationCS, Point::kCylindrical));
616  ++fShowerData->fTopParticles[sId];
617  } else {
618  // side injection
619  const double pPhi = pDirection.GetPhi(stationCS) + kPiOnTwo;
620  // For the X and Y component we need to find the angle made between
621  // the injection cylinder's X-Y axis and the incoming particle direction,
622  // then add an angle sampled from a cosine distribution.
623  const double phi = pPhi + acos(RandFlat::shoot(fRandomEngine, -1, 1));
624  const double z = RandFlat::shoot(fRandomEngine, 0, injectionHeight);
625  newParticle.SetPosition(Point(injectionRadius, phi, z, stationCS, Point::kCylindrical));
626  ++fShowerData->fSideParticles[sId];
627  }
628 
629  // Shift the time to account for differences in position between the
630  // hit tank and the position the particle was placed at the ground
631  // by the shower simulation. Also, include a shift for multiple
632  // particle entries from regeneration of one weighted particle. So far,
633  // no one has provided any real justification for what distribution
634  // should be used for the energy shifting.
635  // see P. Billoir, Astroparticle Physics 30 (2008) 270-285
636  const auto& pShiftedPosition = newParticle.GetPosition();
637  double pShiftedTime = pTime + PlaneFrontTime(showerCS, pPosition, pShiftedPosition);
638  if (i && fShowerData->fLogGauss) {
639  const double planeFrontTime = PlaneFrontTime(showerCS, corePosition, pShiftedPosition);
640  pShiftedTime = fShowerData->fLogGauss->GetSmearedTime(planeFrontTime, pShiftedTime);
641  }
642  newParticle.SetTime(pShiftedTime);
643 
644  InsertValue(fShowerData->fTimeStat, sId, pShiftedTime);
645  station.AddParticle(newParticle);
646 
647  DUMP(
648  (pPosition - Point(0,0,0, dStationCS)).GetMag(),
649  RadiusXY(pPosition - Point(0,0,0, dStationCS), showerCS),
650  pShiftedTime - pTime,
651  newParticle.GetPosition().GetZ(dStationCS)
652  );
653 
654  }
655 
656  nParticlesInjected += n;
657 
658  }
659 
660  }
661 
662  ostringstream info;
663  info << nParticlesInjected << " particles processed.";
664  INFO(info);
665 
666  if (fShowerData->fParticleIt == fShowerData->fParticlesEnd)
667  OutputStats(event);
668 
669  #ifdef DUMP_PARTICLES
670  *gParticleDump << "\n\n\n---\n\n\n" << endl;
671  #endif
672 
673  return eSuccess;
674  }
675 
676 
677  void
679  {
680  const auto& sList = fShowerData->fStationMatrix.GetStationList();
681 
682  int nStations = 0;
683 
684  {
685  INFO("\nStation particle statistics:");
686 
687  TabularStream tab("r|.|r|r|r|.|.|.|l");
688  tab << endc << "Rho" << endc << endc << endc << endc
689  << "wght" << endc << "wght" << endc << "wght" << endc << "station"
690  << endr
691  << "station" << endc << "[km]" << endc << "top" << endc << "side" << endc << "up" << endc
692  << "min" << endc << "avg" << endc << "max" << endc << "thinning"
693  << endr << hline;
694 
695  for (const auto& s : sList) {
696 
697  const unsigned sId = s.GetDetStation().GetId();
698 
699  if (fShowerData->fTopParticles[sId] ||
700  fShowerData->fSideParticles[sId] ||
701  fShowerData->fUpwardSideParticles[sId]) {
702 
703  const auto& w = *fShowerData->fWeightStat.find(sId);
704  tab << sId << ' ' << endc
705  << setprecision(4) << s.GetR()/km << endc
706  << ' ' << fShowerData->fTopParticles[sId] << ' ' << endc
707  << ' ' << fShowerData->fSideParticles[sId] << ' ' << endc
708  << ' ' << fShowerData->fUpwardSideParticles[sId] << ' ' << endc
709  << ' ' << setprecision(4) << w.second.GetMin() << endc
710  << ' ' << setprecision(4) << w.second.GetAverage() << endc
711  << ' ' << setprecision(4) << w.second.GetMax() << endc
712  << s.GetEvtStation().GetSimData().GetThinning()
713  << endr;
714  ++nStations;
715  }
716 
717  }
718 
719  tab << delr;
720 
721  if (nStations)
722  cerr << tab << endl;
723  else
724  cerr << "No stations were hit." << endl;
725  }
726 
727  {
728  INFO("\nStation timing statistics:\n"
729  "abs = absolute time difference to core time\n"
730  "rel = relative time to station plane-front arrival");
731  TabularStream tab("r|.|.|.|.|.");
732  tab << endc << "Rho" << endc << "min abs" << endc << "max abs" << endc
733  << "min rel" << endc << "max rel" << endr
734 
735  << "station" << endc << "[km]" << endc << "time [ns]" << endc << "time [ns]" << endc
736  << "time [ns]" << endc << "time [ns]" << endr << hline;
737 
738  const auto& simShower = event.GetSimShower();
739  const auto& coreTime = simShower.GetTimeStamp();
740 
741  for (const auto& s : sList) {
742 
743  const unsigned sId = s.GetDetStation().GetId();
744 
745  if (fShowerData->fTopParticles[sId] ||
746  fShowerData->fSideParticles[sId] ||
747  fShowerData->fUpwardSideParticles[sId]) {
748 
749  const TimeInterval sTime =
750  s.GetEvtStation().GetSimData().GetPlaneFrontTime() - coreTime;
751 
752  const auto& mm = *fShowerData->fTimeStat.find(sId);
753  tab << sId << ' ' << endc
754  << setprecision(4) << s.GetR()/km << endc
755  << ' ' << Round(10, mm.second.GetMin().GetInterval()/ns) << endc
756  << ' ' << Round(10, mm.second.GetMax().GetInterval()/ns) << endc
757  << ' ' << Round(10, (mm.second.GetMin() - sTime).GetInterval()/ns) << endc
758  << ' ' << Round(10, (mm.second.GetMax() - sTime).GetInterval()/ns) << endr;
759 
760  }
761 
762  }
763 
764  tab << delr;
765 
766  if (nStations)
767  cerr << tab << endl;
768  }
769 
770  if (nStations) {
771  ostringstream info;
772  info << fShowerData->fNHorizontalParticles << " horizontal particles rejected.";
773  INFO(info);
774  }
775  }
776 
777 }
void SetTime(const TimeInterval &time)
Definition: Particle.h:123
Branch GetTopBranch() const
Definition: Branch.cc:63
pointer with built-in initialization, deletion, deep copying
Definition: ShadowPtr.h:163
constexpr double mm
Definition: AugerUnits.h:113
constexpr T Sqr(const T &x)
Point object.
Definition: Point.h:32
void SetPosition(const utl::Point &position)
Definition: Particle.h:111
Describes a particle for Simulation.
Definition: Particle.h:26
bool HasSimShower() const
std::map< std::string, std::string > AttributeMap
Definition: Branch.h:24
VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
const double meter
Definition: GalacticUnits.h:29
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
double Round(const double div, const double val)
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
constexpr double s
Definition: AugerUnits.h:163
const double meter2
Definition: GalacticUnits.h:30
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
const double ns
constexpr double kPi
Definition: MathConstants.h:24
double abs(const SVector< n, T > &v)
const EndRow endr
const int tab
Definition: SdInspector.cc:35
constexpr double kTwoPi
Definition: MathConstants.h:27
constexpr double kPiOnTwo
Definition: MathConstants.h:25
const double km
void SetWeight(const double weight)
Definition: Particle.h:127
class to format data in tabular form
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
void InsertValue(Map &map, const int sId, const T &value)
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
constexpr double kSpeedOfLight
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
const DeleteRow delr
Regenerate thinned MC showers.
Source GetSource() const
Source of the particle (eg. shower or background)
Definition: Particle.h:107
struct particle_info particle[80]
Vector object.
Definition: Vector.h:30
int GetType() const
Definition: Particle.h:101
const Point & GetPosition() const
Position of the particle.
Definition: Particle.h:110
VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
double mod(const double d, const double periode)
#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
const HLine hline('-')
#define DUMP(_pStationDistance_, _pStationDistanceXY_, _timeShift_, _injectionZ_)
const EndColumn endc
bool HasSEvent() const
double PlaneFrontTime(const CoordinateSystemPtr &showerCS, const Point &corePosition, const Point &position)
Calculate time of arrival of the plane front at point position x.

, generated on Tue Sep 26 2023.