Risetime1000LLL.cc
Go to the documentation of this file.
1 // File "Risetime1000LLL.cc"
2 //
3 // This module calculates the risetime for an event. Typically this
4 // is a value interpolated from a fit to the individual risetimes of
5 // each candidate station in the shower plane. An option to
6 // recalculate the risetime of each station is provided.
7 //
8 // D.Barnhill (August 10, 2005)
9 // Taking M. Healy's original code and modifying a few things to make
10 // it more simple and reliable
11 //
12 // M.Healy (Sep 18, 2006): Further modifing the code to allow the
13 // error parameterization from leeds. Also commenting out the linear
14 // fit for risetime to eliminate events that are on the cusp in terms
15 // of quality.
16 //
17 // M.Healy (Oct 9, 2006): Export the chi2 of the risetime fit for
18 // collection by subsiquent modules.
19 //
20 // M.Healy (Nov 21, 2006): Fixed a bug related to the inclusion of
21 // non-canidate stations from the event selection.
22 //
23 // M.Healy (Nov 29, 2006): Major upgrade to eliminate vestigial code
24 // and bring the module up to distribution quality standards. Version
25 // to be submitted to the offline SVN shortly.
26 //
27 // M.Healy (Dec 1, 2006): Used the major upgrade to add functionality
28 // that will interface with the ADST produced by Karlsruhe. This will
29 // allow browsing the fit results in the ADST viewer.
30 //
31 // M.Healy (Dec 14, 2006): Bug fixes, and changes to compile with
32 // version v2r2p3 of the offline.
33 //
34 // M.Healy (Jan 8, 2007): Strip out code to call RecShower->GetZenith()
35 // because it is not implimented. Reverted to old method for getting
36 // the shower zenith angle.
37 //
38 // M.Healy (Jan 17, 2007): Eliminated the streaming of the TF1 object
39 // in the fit results. This was not working with the ADST writer so
40 // resorted to the use of two doubles.
41 //
42 // M.Healy (May 15, 2007): The module is changed to use variables in
43 // the event now. This is intended to replace the static variables
44 // that are currently in use. For now I leave much of the old code as
45 // is so that the changes are incrimental. I don't want to break
46 // anything just before a release.
47 //
48 // Author: M.D.Healy, D.Barnhill
49 //
50 // C. Jarne (2014/02) New asymmetry correction.
51 // C. Jarne (2014/02) Modification in uncertanty estimation according
52 // to gap2013-079 (now correlation term included).
53 //
54 // Modified: Feb 2014, C. Jarne
55 // Created: Sep 24, 2004
56 // Modified: May 15, 2007
57 //********************************************************************
58 
59 // Standard c++ headers
60 #include <sstream>
61 #include <cmath>
62 #include <vector>
63 
64 // Offline headers
65 #include <fwk/CentralConfig.h>
66 
67 #include <evt/Event.h>
68 #include <evt/ShowerRecData.h>
69 #include <evt/ShowerSRecData.h>
70 
71 #include <sevt/SEvent.h>
72 #include <sevt/Header.h>
73 #include <sevt/Station.h>
74 #include <sevt/StationRecData.h>
75 #include <sevt/StationConstants.h>
76 #include <sevt/PMT.h>
77 #include <sevt/PMTRecData.h>
78 
79 #include <det/Detector.h>
80 
81 #include <utl/Reader.h>
82 #include <utl/AugerUnits.h>
83 #include <utl/ErrorLogger.h>
84 #include <utl/StringCompare.h>
85 #include <utl/Trace.h>
86 #include <utl/TraceAlgorithm.h>
87 
88 // ROOT headers
89 #include <TFormula.h>
90 #include <TMatrixD.h>
91 #include <TVirtualFitter.h>
92 
93 // Headers for this module
94 #include "Risetime1000LLL.h"
95 
96 using namespace std;
97 using namespace fwk;
98 using namespace utl;
99 using namespace Risetime1000;
100 using std::ostringstream;
101 using std::vector;
102 
103 
104 double Risetime1000LLL::fgRisetime = -1;
105 double Risetime1000LLL::fgRisetimeError = -1;
106 double Risetime1000LLL::fgRisetimeReducedChi2 = -1;
107 RisetimeResultsLLL* Risetime1000LLL::fgRisetimeResults = nullptr;
108 
109 
110 //#define DEBUG_Risetime1000LLL
111 
112 
113 Risetime1000LLL::~Risetime1000LLL()
114 {
115  delete fgRisetimeResults;
116  fgRisetimeResults = nullptr;
117 }
118 
119 
122 {
123  std::ostringstream info;
124  info << "Configuring the FADC Parameters module.\n"
125  "***************************************\n";
126  auto topB = CentralConfig::GetInstance()->GetTopBranch("Risetime1000");
127 
128  {
129  auto recalculateRiseTimeB = topB.GetChild("RecalculateRisetime");
130  recalculateRiseTimeB.GetChild("Recalculate").GetData(fForceRiseTimeRecalculation);
131  recalculateRiseTimeB.GetChild("RiseTimeStartFraction").GetData(fRiseTimeStartFraction);
132  recalculateRiseTimeB.GetChild("RiseTimeStopFraction").GetData(fRiseTimeStopFraction);
133  if (fForceRiseTimeRecalculation) {
134  info << "Going to recalculate risetimes for stations.\n"
135  "Pulse RiseTime defined as:\n"
136  << fRiseTimeStartFraction*100 << "% to " << fRiseTimeStopFraction*100
137  << "% of total signal.\n";
138  } else
139  info << "Using existing station risetimes (from SdCalibrator).\n";
140  }
141 
142  // Risetime Fit
143  {
144  info << "\nConfiguring the risetime fit routines.\n";
145  auto risetimeFitB = topB.GetChild("RisetimeFit");
146  risetimeFitB.GetChild("Fit").GetData(fDoRiseTimeFit);
147  if (fDoRiseTimeFit) {
148  info << "Fitting the risetime for the event is enabled.\n";
149  risetimeFitB.GetChild("MinimumSignal").GetData(fMinimumSignalForRiseTimeFit);
150  risetimeFitB.GetChild("MinimumDistance").GetData(fMinimumDistanceForRiseTimeFit);
151  risetimeFitB.GetChild("MaximumDistance").GetData(fMaximumDistanceForRiseTimeFit);
152  risetimeFitB.GetChild("RisetimeEvaluatedAt").GetData(fDistanceToInterpolateFitResult);
153  info << "\tMinimum Signal " << fMinimumSignalForRiseTimeFit << " VEM\n"
154  << "\tMinimum Distance " << fMinimumDistanceForRiseTimeFit/m << " m\n"
155  << "\tMaximum Distance " << fMaximumDistanceForRiseTimeFit/m << " m\n"
156  << "\tRisetime Distance " << fDistanceToInterpolateFitResult/m << " m\n";
157 
158  risetimeFitB.GetChild("IncludeSaturated").GetData(fIncludeSaturatedForRiseTimeFit);
159  if (fIncludeSaturatedForRiseTimeFit)
160  info << "\tIncluding saturated stations.\n";
161  else
162  info << "\tNot including saturated stations.\n";
163 
164  risetimeFitB.GetChild("WeightAsFunctionDistance").GetData(fRTWeightingFunction);
165  info << "\tWeighting Function: " << fRTWeightingFunction << '\n';
166  } else
167  info << "Fitting the risetime for the event is disabled.\n";
168 
169  fRTWeights = new TFormula("RiseTimeWeights", fRTWeightingFunction.c_str());
170  if (fRTWeights->IsZombie()) {
171  ostringstream err;
172  err << "Weight formula defined in Risetime1000LLL.xml contains an error!\n"
173  "Current formula is: weight=" << fRTWeightingFunction << "\n"
174  "This formula does not conform to the ROOT formula class guidelines.";
175  ERROR(err);
176  delete fRTWeights;
177  fRTWeights = nullptr;
178  return eFailure;
179  }
180  }
181 
182  topB.GetChild("UseDLECorrectedTrace").GetData(fUseDLECorrectedTrace);
183 
184  if (fUseDLECorrectedTrace)
186  else
187  fComponent = sevt::StationConstants::eTotal;
188 
189  info <<"***************************************\n"
190  "FADC Parameters module initialized.";
191  INFO(info);
192 
193  return eSuccess;
194 }
195 
196 
198 Risetime1000LLL::Run(evt::Event& event)
199 {
200  std::ostringstream info;
201 
202  fgRisetime = -1;
203  fgRisetimeError = -1;
204  fgRisetimeReducedChi2 = -1;
205  delete fgRisetimeResults;
206  fgRisetimeResults = nullptr;
207  fRejectedStations = 0;
208 
209  if (!event.HasSEvent()) {
210  info << "There is no SEvent";
211  INFO(info);
212  return eSuccess;
213  }
214 
215  if (event.HasRecShower() && event.GetRecShower().HasSRecShower()) {
216 
217  const auto& sRecShower = event.GetRecShower().GetSRecShower();
218 
219  const auto& baryCS = sRecShower.GetBarycenterCoordinateSystem();
220  const double sec = 1 / sRecShower.GetAxis().GetCosTheta(baryCS);
221 
222  // Added a correction to the MeanRiseTime for shower asymmetry as
223  // suggested by the Leeds group in a private communication.
224  // t1/2(correct) = t1/2 - g cos(zeta)
225  // g = alpha + gamma r^2
226  // alpha = -66.61 + 95.13 sec(theta) - 30.73 sec^2(theta)
227  // gamma = -0.0009721 + 0.001993 sec(theta) - 0.001259 sec^2(theta) + 0.0002546 sec^3(theta)
228  //
229  // r is the distance to the shower plane (meters), theta is the zenith angle,
230  // and zeta is the angle to a station with the zero direction defined
231  // to be under the shower axis.
232  // M.Healy August 8, 2006
233  //const double alpha = -66.61 + secZenith*(95.13 - 30.73*secZenith);
234  //const double gamma = -0.0009721 + secZenith*(0.001993 + secZenith*(-0.001259 + 0.0002546*secZenith));
235  // New asymmetry correction (2014/01 C. Jarne)
236  const double alpha = 96.73 + sec*(-282.40 + sec*(241.80 - sec*62.61));
237  const double gamma = -0.0009572 + sec*(0.002068 + sec*(-0.001362 + sec*0.0002861));
238 
239  fgRisetimeResults = new RisetimeResultsLLL;
240 
241  auto& sEvent = event.GetSEvent();
242 
243  for (auto& currentStation : sEvent.StationsRange()) {
244  if (!currentStation.HasVEMTrace(fComponent) || !currentStation.HasRecData())
245  continue;
246 
247  unsigned short rejectCode = 0;
248 
249  // Setting the above variables
250  auto& sRecData = currentStation.GetRecData();
251  double stationRisetime = sRecData.GetRiseTime();
252 
253  if (fForceRiseTimeRecalculation || stationRisetime <= 0)
254  stationRisetime = RecalculateRiseTime(currentStation);
255 
256  if (stationRisetime <= 0)
257  continue;
258 
259  const double stationDistance = sRecData.GetSPDistance();
260  const double stationDistanceError = sRecData.GetSPDistanceError();
261  const double g = alpha + gamma * Sqr(stationDistance);
262  // This gets the asymmetry angle as set by the reconstruction module.
263  // Beware of custom reconstructions that do not set this information.
264  const double zeta = sRecData.GetAzimuthShowerPlane();
265  stationRisetime -= g * std::cos(zeta);
266  const double signal =
267  fUseDLECorrectedTrace ? sRecData.GetTotalSignalCleaned() : sRecData.GetTotalSignal();
268  // slight mistake in error propagation here
269  const double stationRisetimeError = fRTWeights->Eval(stationDistance/m, sec, signal);
270 
271  if (signal < fMinimumSignalForRiseTimeFit)
272  rejectCode |= sevt::StationRecData::eLowSignal;
273  if (!currentStation.IsCandidate())
275  if (!fIncludeSaturatedForRiseTimeFit && currentStation.IsLowGainSaturation())
277  if (stationDistance < fMinimumDistanceForRiseTimeFit || stationDistance > fMaximumDistanceForRiseTimeFit)
278  rejectCode |= sevt::StationRecData::eNotInRing;
279 
280  if (rejectCode)
281  ++fRejectedStations;
282 
283  const auto currentStationRisetimeData = new StationRisetimeDataLLL;
284  currentStationRisetimeData->fStationId = currentStation.GetId();
285  currentStationRisetimeData->fCorrRisetime = stationRisetime;
286  currentStationRisetimeData->fCorrRisetimeError = stationRisetimeError;
287  currentStationRisetimeData->fDistance = stationDistance;
288  currentStationRisetimeData->fDistanceError = stationDistanceError;
289  currentStationRisetimeData->fRejectCode = rejectCode;
290 
291 #ifdef DEBUG_Risetime1000LLL
292  ostringstream info;
293  info << "Station Id: " << currentStationRisetimeData->fStationId << "\n"
294  "Risetime: " << currentStationRisetimeData->fCorrRisetime << "\n"
295  "Risetime Error: " << currentStationRisetimeData->fCorrRisetimeError << "\n"
296  "Distance: " << currentStationRisetimeData->fDistance << "\n"
297  "DistanceError: " << currentStationRisetimeData->fDistanceError << "\n"
298  "RejectCode: " << currentStationRisetimeData->fRejectCode;
299  INFO(info);
300 #endif
301 
302  fgRisetimeResults->fStationData.push_back(currentStationRisetimeData);
303  sRecData.SetCorrectedRiseTime(currentStationRisetimeData->fCorrRisetime,
304  currentStationRisetimeData->fCorrRisetimeError);
305  sRecData.SetRiseTimeRejectionCode(currentStationRisetimeData->fRejectCode);
306  }
307  } else {
308  info << "There is no surface reconstruction!\n"
309  "Need a core position and zenith angle before this module.";
310  INFO(info);
311  return eSuccess;
312  }
313 
314  if (fDoRiseTimeFit) {
315  FitEventRiseTime();
316 
317  ostringstream info;
318  info << "The RiseTime at " << fDistanceToInterpolateFitResult/km
319  << " km is " << fgRisetime
320  << " +- " << fgRisetimeError
321  << " ns";
322  INFO(info);
323 
324  if (event.HasRecShower() && event.GetRecShower().HasSRecShower()) {
325  auto& sRecData = event.GetRecShower().GetSRecShower();
326  if (!sRecData.HasRiseTime1000())
327  sRecData.MakeRiseTime1000();
328 
329  auto& risetime1000Data = sRecData.GetRiseTime1000();
330  risetime1000Data.SetRiseTime1000(fgRisetime, fgRisetimeError);
331  risetime1000Data.SetChi2Ndof(fgRisetimeResults->fRisetime1000Chi2,
332  fgRisetimeResults->fRisetime1000NDF);
333  risetime1000Data.SetAlphaBeta(fgRisetimeResults->fFitPar0,
334  fgRisetimeResults->fFitPar1);
335  risetime1000Data.SetXmax(fgRisetimeResults->fXmax,
336  fgRisetimeResults->fXmaxErrorUp,
337  fgRisetimeResults->fXmaxErrorDown);
338  }
339 
340  }
341 
342  return eSuccess;
343 }
344 
345 
357 double
358 Risetime1000LLL::FitEventRiseTime()
359 {
360  const unsigned int pointsInGraph = fgRisetimeResults->fStationData.size() - fRejectedStations;
361 
362  // If only 2 stations pass the cuts then we will ignore the event
363  // M. Healy (18 Sep 2006)
364  if (pointsInGraph <= 2) {
365  INFO("Event risetime uncalculated due to an insuffiecent number of acceptable stations.");
366  return -1;
367  }
368 
369  vector<double> distances(pointsInGraph);
370  vector<double> distancesError(pointsInGraph);
371  vector<double> risetimes(pointsInGraph);
372  vector<double> risetimesError(pointsInGraph);
373  unsigned int point = 0;
374 
375  for (const auto s : fgRisetimeResults->fStationData) {
376  const auto& currentStation = *s;
377  if (currentStation.fRejectCode)
378  continue;
379 
380  distances[point] = currentStation.fDistance / km;
381  distancesError[point] = currentStation.fDistanceError / km;
382  risetimes[point] = currentStation.fCorrRisetime / ns;
383  risetimesError[point] = currentStation.fCorrRisetimeError / ns;
384 
385  ostringstream info;
386  info << "Passed Cut: station " << currentStation.fStationId << ", "
387  "distance " << distances[point] << " km, "
388  "risetime " << risetimes[point] << " ns";
389  INFO(info);
390 
391  ++point;
392  }
393 
394  ostringstream info;
395  info << pointsInGraph << " stations passed the cuts.";
396  INFO(info);
397 
398  TGraphErrors riseTimeGraph(pointsInGraph, &distances.front(), &risetimes.front(), nullptr, &risetimesError.front());
399  riseTimeGraph.SetMarkerStyle(20);
400  riseTimeGraph.SetMarkerColor(2);
401  riseTimeGraph.SetLineColor(2);
402  riseTimeGraph.SetLineWidth(2);
403  TF1 risetimeFit("RisetimeFit", "40+[0]*x+[1]*x*x",
404  fMinimumDistanceForRiseTimeFit/km, fMaximumDistanceForRiseTimeFit/km);
405  risetimeFit.SetParLimits(0, 0, 10000);
406  risetimeFit.SetParLimits(1, 0, 10000);
407 
408  // Offline Modification in uncertanty estimation -2013 by C. Jarne (Before not correlation term included)
409  // Added to calculate the correct uncertainties considering the correlation
410  double risetime = -1;
411  double risetimeErr = -1;
412  double risetimeChi2 = -1;
413  double risetimeNDF = -1;
414  const int failed = riseTimeGraph.Fit(&risetimeFit, "Q", "", fMinimumDistanceForRiseTimeFit/km, fMaximumDistanceForRiseTimeFit/km);
415  if (!failed) {
416  risetime = risetimeFit.Eval(fDistanceToInterpolateFitResult/km);
417  const auto fitter = TVirtualFitter::GetFitter();
418  const int nPar = fitter->GetNumberTotalParameters();
419  const TMatrixD covar(nPar, nPar, fitter->GetCovarianceMatrix());
420  //covar.Print();
421  const double rtcov = covar[0][1];
422  const double rtcov2 = covar[1][1];
423  const double rtcov1 = covar[0][0];
424 
425  //risetimeerr = sqrt(pow(risetimeFit.GetParError(0), 2) + pow(risetimeFit.GetParError(1), 2));
426  // New estimation including the correlation term 2014/01 C. Jarne
427  risetimeErr = sqrt(rtcov2 + rtcov1 + 2*rtcov);
428 
429  risetimeChi2 = risetimeFit.GetChisquare();
430  risetimeNDF = risetimeFit.GetNDF();
431  }
432 
433  fgRisetime = risetime*ns;
434  fgRisetimeError = risetimeErr*ns;
435  fgRisetimeReducedChi2 = risetimeChi2 / risetimeNDF;
436 
437  fgRisetimeResults->fFitPar0 = risetimeFit.GetParameter(0) * m/km;
438  fgRisetimeResults->fFitPar1 = risetimeFit.GetParameter(1) * m/km * m/km;
439  fgRisetimeResults->fRisetime1000 = risetime*ns;
440  fgRisetimeResults->fRisetime1000Error = risetimeErr*ns;
441  fgRisetimeResults->fRisetime1000Chi2 = risetimeChi2;
442  fgRisetimeResults->fRisetime1000NDF = risetimeNDF;
443 
444  // This functionality not yet included
445  fgRisetimeResults->fXmax = -1;
446  fgRisetimeResults->fXmaxErrorUp = -1;
447  fgRisetimeResults->fXmaxErrorDown = -1;
448 
449  return risetime*ns;
450 }
451 
452 
453 double
454 Risetime1000LLL::RecalculateRiseTime(const sevt::Station& station)
455 {
456  const auto& recData = station.GetRecData();
457  int startBin = recData.GetSignalStartSlot() - 4;
458  const int stopBin = recData.GetSignalEndSlot();
459  if (startBin >= stopBin || startBin < 0 || startBin > 5000)
460  startBin = 0;
461 
462  int numPMTs = 0;
463  double totalRisetime = 0;
464  for (const auto& currentPMT : station.PMTsRange()) {
465  if (!currentPMT.HasRecData() || !currentPMT.GetRecData().HasVEMTrace(fComponent))
466  continue;
467 
468  ++numPMTs;
469  const auto& pmtRec = currentPMT.GetRecData();
470  const auto& vemTrace = pmtRec.GetVEMTrace(fComponent);
471  const double risetimeStart =
472  TraceAlgorithm::TimeAtRelativeSignalX(vemTrace, startBin, stopBin, 100*fRiseTimeStartFraction);
473  const double risetimeStop =
474  TraceAlgorithm::TimeAtRelativeSignalX(vemTrace, startBin, stopBin, 100*fRiseTimeStopFraction);
475 
476  const double diff = risetimeStop - risetimeStart;
477  totalRisetime += diff;
478  }
479 
480  if (!numPMTs) {
481  ERROR("Valid station, but no PMTRecData. Risetime recalculation failed!");
482  return -1;
483  } else
484  return totalRisetime / numPMTs;
485 }
constexpr T Sqr(const T &x)
total (shower and background)
bool HasRecShower() const
sevt::StationRecData & GetRecData()
Get station level reconstructed data.
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void Init()
Initialise the registry.
static const RiseTimeRejectionCode eNotCandidate
static const RiseTimeRejectionCode eLowSignal
class to hold data at Station level
constexpr double s
Definition: AugerUnits.h:163
static const RiseTimeRejectionCode eLowGainSaturated
const double ns
unsigned int GetSignalStartSlot() const
Start time of the signal in time slots from beginning of trace.
const double km
constexpr double g
Definition: AugerUnits.h:200
signal after subtracting direct light (includes all particle sources).
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
static const RiseTimeRejectionCode eNotInRing
const int nPar
Definition: GeomAsym.h:37
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
bool HasSEvent() const

, generated on Tue Sep 26 2023.