RdPreWaveFitter.cc
Go to the documentation of this file.
1 #include "RdPreWaveFitter.h"
2 
3 #include <fwk/CentralConfig.h>
4 #include <fwk/LocalCoordinateSystem.h>
5 
6 #include <det/Detector.h>
7 #include <rdet/RDetector.h>
8 
9 #include <utl/Math.h>
10 #include <utl/FFTDataContainerAlgorithm.h>
11 #include <utl/AnalyticCoordinateTransformator.h>
12 #include <utl/TraceAlgorithm.h>
13 #include <utl/Trace.h>
14 
15 #include <evt/Event.h>
16 #include <evt/ShowerRecData.h>
17 #include <evt/ShowerRRecData.h>
18 
19 #include <revt/REvent.h>
20 #include <revt/Station.h>
21 #include <revt/Channel.h>
22 #include <revt/StationRecData.h>
23 
24 #include <Minuit2/Minuit2Minimizer.h>
25 
26 
27 using namespace std;
28 using namespace revt;
29 using namespace evt;
30 using namespace fwk;
31 using namespace utl;
32 
33 
34 namespace RdPreWaveFitter {
35 
36  template<typename G>
37  inline
38  string
39  ToString(const G& g, const CoordinateSystemPtr cs)
40  {
41  ostringstream os;
42  os << '(' << g.GetX(cs) / meter << ", " << g.GetY(cs) / meter << ", " << g.GetZ(cs) / meter
43  << ") [m]";
44  return os.str();
45  }
46 
47 
50  {
51  Branch topBranch = CentralConfig::GetInstance()->GetTopBranch("RdPreWaveFitter");
52 
53  topBranch.GetChild("InfoLevel").GetData(fInfoLevel);
54  topBranch.GetChild("minNumberOfStations").GetData(fMinNumberOfStations);
55  topBranch.GetChild("thetaMax").GetData(fThetaMax);
56  topBranch.GetChild("nInitsTheta").GetData(fNInitsTheta);
57  topBranch.GetChild("nInitsPhi").GetData(fNInitsPhi);
58  topBranch.GetChild("maxOnComboTrace").GetData(fMaxOnComboTrace);
59  topBranch.GetChild("RMSOnBestTrace").GetData(fRMSonBestTrace);
60  topBranch.GetChild("computeRMS").GetData(fComputeRMS);
61  topBranch.GetChild("SNRCut").GetData(fSNRCut);
62  topBranch.GetChild("continueAfterFailedFit").GetData(fcontinueAfterFailedFit);
63 
64  ChiPWF = new Chi2ForPlaneWaveFit();
65 
66  return eSuccess;
67  }
68 
69 
71  RdPreWaveFitter::Run(Event& event)
72  {
73  // nothing to do if there is no REvent
74  if (!event.HasREvent()) {
75  WARNING("eContinueLoop: No REvent, so no reconstruction");
76  return eContinueLoop;
77  }
78 
79  REvent& rEvent = event.GetREvent();
80 
81  // this will point to the final result
82  FitParameters sFitResults;
83 
84  if (!event.HasRecShower()) {
85  event.MakeRecShower();
86  }
87  if (!event.GetRecShower().HasRRecShower()) {
88  event.GetRecShower().MakeRRecShower();
89  }
90  ShowerRRecData& showerrrec = event.GetRecShower().GetRRecShower();
91 
92  // retrieve the coordinate origin from the ParameterStorage
93  try {
94  fCoordinateOrigin = showerrrec.GetCoordinateOrigin();
95  fLocalCS = LocalCoordinateSystem::Create(fCoordinateOrigin);
96  } catch (NonExistentComponentException& e) {
97  ostringstream err;
98  err << "Problem when getting coordinate origin. Did you call the RdEventInitializer?"
99  << " Caught utl::NonExistentComponentException : " << e.what()
100  << " Will Break loop";
101  ERROR(err);
102  return eBreakLoop;
103  }
104 
105  // search for signal position and compute RMS
106  if (fComputeRMS) {
107  ComputeRMS(rEvent);
108  }
109  ComputeSignalPosition(rEvent, true);
110 
111  if (fNumberOfStations < fMinNumberOfStations) {
112  INFO("eContinueLoop: Not enough stations.");
113  return eContinueLoop;
114  }
115 
116  // for using a different fit algorithm only change the following line
117  // Call Plane Wave Fit
118  VModule::ResultFlag result = ScanPWF(rEvent, sFitResults);
119 
120  // save fit results, break loop if the fit was not successful and set RecStage to 0
121  if (result != eSuccess) {
122  ++fNFails;
123 
124  if (fcontinueAfterFailedFit) {
125  WARNING("PreWaveFit was not sucessful. Continuing with EField reconstruction anyway (warning: no Rd shower axis set).");
126  return eSuccess;
127  } else {
128  WARNING("Skipping event, because PreWaveFit was not sucessful. This default behaviour can be overwritten in XML config (be careful!).");
129  return eContinueLoop;
130  }
131  }
132 
134  const Vector axis(1, sFitResults.theta, sFitResults.phi, fLocalCS, Vector::kSpherical);
135  showerrrec.SetParameter(ePreFitShowerAxisX, axis.GetX(fLocalCS));
136  showerrrec.SetParameter(ePreFitShowerAxisY, axis.GetY(fLocalCS));
137  showerrrec.SetParameter(ePreFitShowerAxisZ, axis.GetZ(fLocalCS));
138 
139  // save Covariance matrix
140  double tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(
141  0, 0, sFitResults.r, sFitResults.theta, sFitResults.phi, sFitResults.c00, sFitResults.c11,
142  sFitResults.c22, sFitResults.c01, sFitResults.c02, sFitResults.c12);
143 
144  showerrrec.SetParameterCovariance(ePreFitShowerAxisX, ePreFitShowerAxisX, tempCov);
145  tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(1, 1,
146  sFitResults.r,
147  sFitResults.theta,
148  sFitResults.phi,
149  sFitResults.c00,
150  sFitResults.c11,
151  sFitResults.c22,
152  sFitResults.c01,
153  sFitResults.c02,
154  sFitResults.c12);
155  showerrrec.SetParameterCovariance(ePreFitShowerAxisY, ePreFitShowerAxisY, tempCov);
156  tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(2, 2,
157  sFitResults.r,
158  sFitResults.theta,
159  sFitResults.phi,
160  sFitResults.c00,
161  sFitResults.c11,
162  sFitResults.c22,
163  sFitResults.c01,
164  sFitResults.c02,
165  sFitResults.c12);
166  showerrrec.SetParameterCovariance(ePreFitShowerAxisZ, ePreFitShowerAxisZ, tempCov);
167  tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(0, 1,
168  sFitResults.r,
169  sFitResults.theta,
170  sFitResults.phi,
171  sFitResults.c00,
172  sFitResults.c11,
173  sFitResults.c22,
174  sFitResults.c01,
175  sFitResults.c02,
176  sFitResults.c12);
177  showerrrec.SetParameterCovariance(ePreFitShowerAxisX, ePreFitShowerAxisY, tempCov);
178  tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(0, 2,
179  sFitResults.r,
180  sFitResults.theta,
181  sFitResults.phi,
182  sFitResults.c00,
183  sFitResults.c11,
184  sFitResults.c22,
185  sFitResults.c01,
186  sFitResults.c02,
187  sFitResults.c12);
188  showerrrec.SetParameterCovariance(ePreFitShowerAxisX, ePreFitShowerAxisZ, tempCov);
189  tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(1, 2,
190  sFitResults.r,
191  sFitResults.theta,
192  sFitResults.phi,
193  sFitResults.c00,
194  sFitResults.c11,
195  sFitResults.c22,
196  sFitResults.c01,
197  sFitResults.c02,
198  sFitResults.c12);
199  showerrrec.SetParameterCovariance(ePreFitShowerAxisY, ePreFitShowerAxisZ, tempCov);
200 
201  showerrrec.SetParameter(eShowerAxisX, axis.GetX(fLocalCS), false);
202  showerrrec.SetParameter(eShowerAxisY, axis.GetY(fLocalCS), false);
203  showerrrec.SetParameter(eShowerAxisZ, axis.GetZ(fLocalCS), false);
204 
205  showerrrec.SetParameter(ePreFitChi2, sFitResults.minChi);
206  showerrrec.SetParameter(ePreFitNDF, sFitResults.NDF);
207 
208  // set signal arrival direction for individual stations
209  // For a plane wave fit the direction is of course the same for all station, but
210  // for some applications the RdAntennaChannelToStationConverter has to know the individual
211  // arrival directions. So the values have to be set.
212  for (auto& station : rEvent.StationsRange()) {
213  station.GetRecData().SetParameter(eSignalArrivalDirectionX, axis.GetX(fLocalCS), false);
214  station.GetRecData().SetParameter(eSignalArrivalDirectionY, axis.GetY(fLocalCS), false);
215  station.GetRecData().SetParameter(eSignalArrivalDirectionZ, axis.GetZ(fLocalCS), false);
216  }
217 
218  showerrrec.SetParameter(eFitSuccess, 1, false);
219 
220  ostringstream info;
221  info << "Final fit results with " << fNumberOfStations << " stations:"
222  << "\n\ttheta = " << sFitResults.theta / degree << " +/- " << sFitResults.thetaError / degree
223  << "\n\tphi = " << sFitResults.phi / degree << " +/- " << sFitResults.phiError / degree
224  << "\n\tChi2/NDF = " << sFitResults.minChi << "/" << sFitResults.NDF;
225  INFOFinal(info);
226 
227  return eSuccess;
228  }
229 
230 
232  RdPreWaveFitter::Finish()
233  {
234  ostringstream info;
235  info << "PreWaveFit fit failed for " << fNFails << " times but continued anyway, "
236  << nSNRCut << " stations were rejected because of bad SNR ratio";
237  INFOFinal(info);
238 
239  delete ChiPWF;
240 
241  return eSuccess;
242  }
243 
244 
246  RdPreWaveFitter::PlaneWaveFit(const REvent& rEvent, FitParameters& fit,
247  int type) const
248  {
249  if (fNumberOfStations < 3) {
250  WARNING("ERROR: At least 3 Stations are needed for a plane wave fit.");
251  return eContinueLoop;
252  }
253 
254  ROOT::Minuit2::Minuit2Minimizer* minimizer = nullptr;
255  if (type == 0) {
256  minimizer = new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kMigrad);
257  } else if (type == 1) {
258  minimizer = new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kSimplex);
259  } else if (type == 2) {
260  minimizer = new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kCombined);
261  } else if (type == 3) {
262  minimizer = new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kScan);
263  }
264 
265  const rdet::RDetector& rDetector = det::Detector::GetInstance().GetRDetector();
266 
267  vector<Vector> AntennaPositions;
268  vector<double> AntennaTimes;
269  vector<double> AntennaTimesError;
270 
271  //loop over all stations
272  for (const auto& station : rEvent.CandidateStationsRange()) {
273  const Vector sPos = rDetector.GetStation(station).GetPosition() - fCoordinateOrigin;
274  const StationRecData& sRec = station.GetRecData();
275  if (sRec.GetPulseFound()) {
276  AntennaPositions.push_back(sPos);
277  const double t = sRec.GetParameter(eSignalTime);
278  AntennaTimes.push_back(t);
279  AntennaTimesError.push_back(sRec.GetParameterError(eSignalTime));
280  }
281  }
282 
283  // Give the Antenna Positions and Times to objective function
284  ChiPWF->Set(AntennaPositions, AntennaTimes, AntennaTimesError, fLocalCS);
285  minimizer->SetFunction(*ChiPWF);
286 
287  // Set variables
288  minimizer->SetLimitedVariable(0, "theta", fit.theta, 0.1, 0., fThetaMax);
289  minimizer->SetVariable(1, "phi", fit.phi, 0.1);
290 
291  // THE FIT:
292  minimizer->SetPrintLevel(0);
293  if(fInfoLevel >= 3) {
294  minimizer->SetPrintLevel(4);
295  }
296  if (!minimizer->Minimize()) {
297  fit.status = minimizer->Status();
298  return eContinueLoop;
299  }
300 
301  // Save Results
302  fit.status = minimizer->Status();
303  fit.phi = NormalizeAngleMinusPiPi(minimizer->X()[1]);
304  fit.theta = NormalizeAngleMinusPiPi(minimizer->X()[0]);
305  fit.phiError = minimizer->Errors()[1];
306  fit.thetaError = minimizer->Errors()[0];
307 
308  // set radius to 1 (was not fitted)
309  fit.r = 1;
310 
311  // save covariance matrix
312  fit.c00 = 0;
313  fit.c11 = minimizer->CovMatrix(0, 0);
314  fit.c22 = minimizer->CovMatrix(1, 1);
315  fit.c01 = 0;
316  fit.c02 = 0;
317  fit.c12 = minimizer->CovMatrix(0, 1);
318 
319  fit.nCalls = minimizer->NCalls();
320  fit.minChi = minimizer->MinValue();
321 
322  fit.NDF = fNumberOfStations - 3;
323 
324  ostringstream info;
325  info << "fit result in mode " << type << ": phi = " << fit.phi / deg << " theta = " << fit.theta / deg;
326  INFOIntermediate(info);
327 
328  /* the plane wave fit can be performed with just 3 stations. The number of degrees
329  * of freedom is 0, though. To be able to compute chiSquare/NDF the NDF is set to 1.
330  */
331  if (fNumberOfStations < 4) {
332  fit.chiSquareNDF = minimizer->MinValue() / (fNumberOfStations - 2);
333  } else {
334  fit.chiSquareNDF = minimizer->MinValue() / (fNumberOfStations - 3);
335  }
336 
337  delete minimizer;
338 
339  return eSuccess;
340  }
341 
342 
344  RdPreWaveFitter::ScanPWF(const REvent& rEvent, FitParameters& sFitResults) const
345  {
346  // this will store init & intermediate Parameters
347  FitParameters sFitParameters;
348 
349  // necessary to save standard values Radius and Gamma
350  sFitParameters = sFitResults;
351 
352  /* necessary to abort if fit fails for all initial values and therefore the
353  status flag was not set to sFitResults */
354  sFitResults.status = 1;
355 
356  // set initial fit parameters
357  const double stepTheta = 90 / (fNInitsTheta + 1) * degree;
358  const double stepPhi = 360 / (fNInitsPhi) * degree;
359  double theta = 0;
360  double phi = -180 * degree;
361 
362  ostringstream info;
363  info << "Stepwidth for initial values: stepTheta = " << stepTheta / deg
364  << ", stepPhi = " << stepPhi / deg;
365  INFOIntermediate(info);
366 
367  // call PlaneWaveFit for different init values
368  bool first_fit = true;
369  for (int iTheta = 0; iTheta < fNInitsTheta; ++iTheta) {
370  theta = stepTheta * (iTheta + 1);
371 
372  for (int iPhi = 0; iPhi < fNInitsPhi; ++iPhi) {
373  phi = -180 * degree + stepPhi * iPhi;
374 
375  info.str("");
376  info << "Current start values: theta = " << theta / deg
377  << " deg, phi = " << phi / deg << " deg";
378  INFOIntermediate(info);
379 
380  sFitParameters.theta = theta;
381  sFitParameters.phi = phi;
382 
383  // call Fit in kSimplex mode
384  if (PlaneWaveFit(rEvent, sFitParameters, 1) != eSuccess) {
385  INFOIntermediate("PlaneWaveFit in kSimplex was not successful: skip to next initial value");
386  continue;
387  }
388 
389  // call Fit in kMigrad mode
390  if (PlaneWaveFit(rEvent, sFitParameters, 0) != eSuccess) {
391  INFOIntermediate("PlaneWaveFit in kMigrad was not successful: skip to next initial value");
392  continue;
393  }
394 
395  // save Fit Results if better as previous fit or if its the first fit
396  if (sFitParameters.minChi < sFitResults.minChi || first_fit) {
397  first_fit = false;
398  sFitResults = sFitParameters;
399  }
400  }
401  }
402 
403  // break Function if reconstruction is not sucessfull
404  if (sFitResults.status != 0) {
405  WARNING("ERROR: reconstruction was not successful");
406  return eContinueLoop;
407  }
408 
409  sFitResults.corrected = false;
410 
411  // flip minimum about horizon, check for better minimum
412  if (sFitResults.theta > TMath::Pi() / 2.) {
413  sFitParameters = sFitResults; // buffer best result, so that this result won't be lost due to the new fit
414 
415  sFitParameters.theta = TMath::Pi() - sFitParameters.theta;
416 
417  // call Fit in kSimplex mode
418  if (PlaneWaveFit(rEvent, sFitParameters, 1) != eSuccess) {
419  info.str("");
420  info << "Horizon Correction: PlaneWaveFit for theta = " << sFitParameters.theta
421  << " in kSimplex was not successful: calling again in kMigrad mode";
422  INFOIntermediate(info);
423  }
424 
425  // call Fit in kMigrad mode
426  if (PlaneWaveFit(rEvent, sFitParameters, 0) == eSuccess) {
427  if (sFitParameters.minChi < sFitResults.minChi) {
428  info.str("");
429  info << "Horizon corrected! New theta = " << sFitParameters.theta / deg;
430  INFOIntermediate(info);
431 
432  sFitParameters.corrected = true;
433  sFitResults = sFitParameters;
434  }
435  } else {
436  info.str("");
437  info << "Horizon Correction: PlaneWaveFit for theta "
438  << sFitParameters.theta / deg << " in kMigrad was not successful";
439  INFOIntermediate(info);
440  }
441  }
442 
443  return eSuccess;
444  }
445 
446 
448  RdPreWaveFitter::CallPlaneWaveFit(const REvent& rEvent, FitParameters& sFitResults,
449  bool reuseFit) const
450  {
451  if (fNumberOfStations < 3) {
452  WARNING("Not enough Stations");
453  return eContinueLoop;
454  }
455 
457 
458  // for the first time
459  if (!reuseFit) {
460  return ScanPWF(rEvent, sFitResults);
461  } else {
462  // call first in kSimplex
463  result = PlaneWaveFit(rEvent, sFitResults, 1);
464  if (result != eSuccess) {
465  WARNING("reuse plane wave fit in kSimplex mode was not successful");
466  return result;
467  }
468 
469  // call in kMigrad
470  result = PlaneWaveFit(rEvent, sFitResults, 0);
471  return result;
472  }
473  }
474 
475 
477  RdPreWaveFitter::ComputeRMS(REvent& rEvent)
478  {
479  ostringstream info;
480 
481  for (auto& station : rEvent.CandidateStationsRange()) {
482  if (!station.HasRecData()) {
483  station.MakeRecData();
484  }
485 
486  const double NoiseSearchWindowStart = station.GetRecData().GetParameter(eNoiseWindowStart);
487  const double NoiseSearchWindowStop = station.GetRecData().GetParameter(eNoiseWindowStop);
488  const double SignalSearchWindowStart = station.GetRecData().GetParameter(eSignalSearchWindowStart);
489  const double SignalSearchWindowStop = station.GetRecData().GetParameter(eSignalSearchWindowStart);
490 
491  double rms = 0;
492 
493  // identify active channels
494  vector<Channel> usableChannels;
495  for (auto& channel : station.ChannelsRange())
496  if (channel.IsActive())
497  usableChannels.push_back(channel);
498 
499  // remove station if it has no channels (no data) - should actually be done beforehand, but just to be sure
500  if (usableChannels.size() == 0) {
501  info.str("");
502  info << "Station " << station.GetId()
503  << " does not have any channels, removing it! Should treat this case beforehand, e.g. in RdChannelSelector.";
504  WARNING(info);
505 
506  continue;
507  }
508 
509  if (usableChannels.size() != 2) {
510  if (usableChannels.size() == 3) {
511  info.str("");
512  info << "Station " << station.GetId()
513  << " does have three active channels! The PreWaveFitter does only support two active channel for the moment."
514  << " The first two active channels will be used.";
515  WARNING(info);
516  } else {
517  info.str("");
518  info << "Station " << station.GetId()
519  << " does not have exactly two active channels! Have you forgotten to include the RdChannelSelector?";
520  ERROR(info);
522  "RdPreWaveFitter does not support stations with number of Channels != 2 or != 3.");
523  }
524  }
525 
526  const Channel& channel1 = usableChannels.at(0);
527  const Channel& channel2 = usableChannels.at(1);
528 
529  if (fRMSonBestTrace) {
530  double RMS[2] = { 0, 0 };
531  double MaxAmp[2] = { 0, 0 };
532 
533  // loop over the two active channels
534  for (int i = 0; i <= 1; ++i) {
535  const Channel& channel = usableChannels.at(i);
536  const ChannelTimeSeries& channelTrace = channel.GetChannelTimeSeries();
537  const int binning = channelTrace.GetBinning();
538  unsigned int start = NoiseSearchWindowStart / binning;
539  unsigned int stop = NoiseSearchWindowStop / binning;
540  unsigned int startSignal = SignalSearchWindowStart / binning;
541  unsigned int stopSignal = SignalSearchWindowStop / binning;
542 
543  // test if start stop lies in correct bounds
544  if (start > channelTrace.GetSize()) {
545  WARNING("start of Noise Search Window is greater than the length of the trace, RMS could not be calculated");
546  return eFailure;
547  }
548  info << "NoiseSearchWindowStop = " << stop << endl;
549  stop = min(static_cast<int>(stop), static_cast<int>(channelTrace.GetSize()));
550 
551  // stop - 1 because RootMeanSquare function loops from i=start to i<=stop
552  RMS[i] = TraceAlgorithm::RootMeanSquare(channelTrace, start, stop - 1);
553 
554  MaxAmp[i] = max(TraceAlgorithm::Max(channelTrace, startSignal, stopSignal),
555  fabs(TraceAlgorithm::Min(channelTrace, startSignal, stopSignal)));
556  info.str("");
557  info << "Channel " << i + 1 << ": RMS = " << RMS[i] << "\tMaxAmp = " << MaxAmp[i] << endl;
558  }
559 
560  info << "maxamp = " << MaxAmp[0] << ", " << MaxAmp[1] << endl;
561  if (MaxAmp[0] > MaxAmp[1]) {
562  rms = RMS[0];
563  } else {
564  rms = RMS[1];
565  }
566  info << "RMS = " << rms << endl;
567  INFODebug(info);
568  } else {
569  const ChannelTimeSeries& channelTrace1 = channel1.GetChannelTimeSeries();
570  const ChannelTimeSeries& channelTrace2 = channel2.GetChannelTimeSeries();
571 
572  // get signal window
573  unsigned int start = NoiseSearchWindowStart / channelTrace1.GetBinning();
574  unsigned int stop = NoiseSearchWindowStop / channelTrace1.GetBinning();
575 
576  if (start > channelTrace1.GetSize()) {
577  if (fInfoLevel >= 1) {
578  WARNING(
579  "start of Noise Search Window is greater than the length of the trace, RMS could not be calculated");
580  }
581  return eFailure;
582  }
583  info << "NoiseSearchWindowStart = " << start << "\tNoiseSearchWindowStop = " << stop
584  << "\tsize of channeltrace1 = " << channelTrace1.GetSize()
585  << "\tsize of channeltrace2 = " << channelTrace2.GetSize() << endl;
586  INFOIntermediate(info);
587 
588  stop = min(static_cast<int>(stop), static_cast<int>(channelTrace1.GetSize()));
589 
590  unsigned int N = 0;
591  for (unsigned int i = start; i < stop; ++i) {
592  rms += ((channelTrace1[i] * channelTrace1[i]) + (channelTrace2[i] * channelTrace2[i]));
593  ++N;
594  }
595  rms = sqrt(rms / N);
596  }
597 
598  station.GetRecData().SetParameter(eNoise, rms, false);
599  }
600 
601  return eSuccess;
602  }
603 
604 
606  RdPreWaveFitter::ComputeSignalPosition(REvent& rEvent, bool hilbert)
607  {
608  int nStations = 0;
609  ostringstream info;
610 
611  for (auto& station : rEvent.CandidateStationsRange()) {
612  if (!station.HasRecData()) {
613  station.MakeRecData();
614  }
615 
616  double SignalSearchWindowStart = station.GetRecData().GetParameter(eSignalSearchWindowStart);
617  double SignalSearchWindowStop = station.GetRecData().GetParameter(eSignalSearchWindowStop);
618 
619  double maxPeakTime = 0;
620  double tMaxAmp = 0;
621 
622  // identify active channels
623  vector<Channel> usableChannels;
624  for (auto& channel : station.ChannelsRange())
625  if (channel.IsActive())
626  usableChannels.push_back(channel);
627 
628  // remove station if it has no channels (no data) - should actually be done beforehand, but just to be sure
629  if (usableChannels.size() == 0) {
630  info.str("");
631  info << "Station " << station.GetId()
632  << " does not have any channels, removing it! Should treat this case beforehand, e.g. in RdChannelSelector.";
633  WARNING(info);
634  continue;
635  }
636 
637  if (usableChannels.size() != 2) {
638  if (usableChannels.size() == 3) {
639  info.str("");
640  info << "Station " << station.GetId()
641  << " does have three active channels! The PreWaveFitter does only support two active channel for the moment."
642  << " The first two active channels will be used.";
643  WARNING(info);
644  } else {
645  info.str("");
646  info << "Station " << station.GetId()
647  << " does not have exactly two active channels! Have you forgotten to include the RdChannelSelector?";
648  ERROR(info);
650  "RdPreWaveFitter does not support stations with number of Channels != 2 or != 3.");
651  }
652  }
653 
654  const Channel& channel1 = usableChannels.at(0);
655  const Channel& channel2 = usableChannels.at(1);
656 
657  if (fMaxOnComboTrace) {
658  // get fft data container of active channel 1 and 2
659  ChannelFFTDataContainer channelData1 = channel1.GetFFTDataContainer();
660  ChannelFFTDataContainer channelData2 = channel2.GetFFTDataContainer();
661 
662  // do Hilbert transformation
663  if (hilbert) {
664  FFTDataContainerAlgorithm::HilbertEnvelope(channelData1);
665  FFTDataContainerAlgorithm::HilbertEnvelope(channelData2);
666  }
667 
668  const ChannelTimeSeries& channelTrace1 = channelData1.GetConstTimeSeries();
669  const ChannelTimeSeries& channelTrace2 = channelData2.GetConstTimeSeries();
670 
671  // get signal window
672  const int binning = channelTrace1.GetBinning();
673  unsigned int start = SignalSearchWindowStart / binning;
674  unsigned int stop = SignalSearchWindowStop / binning;
675 
676  double tPeakAmplitude2 = 0.0;
677  double tPeakTime = 0.0;
678  for (unsigned int i = start; i < stop; ++i) {
679  double amp2 = Sqr(channelTrace1[i]) + Sqr(channelTrace2[i]);
680 
681  if (amp2 > tPeakAmplitude2) {
682  tPeakAmplitude2 = amp2;
683  tPeakTime = i * binning;
684  }
685  }
686  maxPeakTime = tPeakTime;
687  tMaxAmp = sqrt(tPeakAmplitude2);
688  } else {
689 
690  vector<double> peakAmplitude;
691  vector<double> peakTime;
692 
693  // loop over the two active channels
694  for (int i = 0; i <= 1; ++i) {
695  const Channel& channel = usableChannels.at(i);
696 
697  ChannelFFTDataContainer channelData = channel.GetFFTDataContainer();
698  // when we are using the envelope timeseries
699  if (hilbert)
700  FFTDataContainerAlgorithm::HilbertEnvelope(channelData);
701  const ChannelTimeSeries& channelTrace = channelData.GetConstTimeSeries();
702 
703  const int binning = channelTrace.GetBinning();
704  double tPeakAmplitude = 0.0;
705  double tPeakTime = 0.0;
706  unsigned int start = SignalSearchWindowStart / binning;
707  unsigned int stop = SignalSearchWindowStop / binning;
708  for (unsigned int i = start; i < stop; ++i) {
709  if (abs(channelTrace[i]) > tPeakAmplitude) {
710  tPeakAmplitude = channelTrace[i];
711  tPeakTime = i * binning;
712  }
713  }
714  peakAmplitude.push_back(tPeakAmplitude);
715  peakTime.push_back(tPeakTime);
716  }
717 
718  for (unsigned int i = 0; i < peakTime.size(); ++i) {
719  if (peakAmplitude[i] > tMaxAmp) {
720  tMaxAmp = peakAmplitude[i];
721  maxPeakTime = peakTime[i];
722  }
723  }
724  info.str("");
725  info << "PeakTime (ch1, ch2, maxPeakTime) = " << peakTime[0] << ", " << peakTime[1]
726  << ", " << maxPeakTime;
727  INFODebug(info);
728  }
729 
730  // all times relative to the event time!
731  double traceStartTime = station.GetRecData().GetParameter(eTraceStartTime);
732  station.GetRecData().SetParameter(eSignalTime, maxPeakTime + traceStartTime, false);
733 
734  info.str("");
735  info << "setting signal time to " << maxPeakTime + traceStartTime;
736  INFODebug(info);
737 
738  const Trace<double> timeseries = channel1.GetChannelTimeSeries();
739  double binTimeError = timeseries.GetBinning()/sqrt(12);
740  double timeUncertainty = sqrt(
741  station.GetRecData().GetParameterError(eTraceStartTime)
742  * station.GetRecData().GetParameterError(eTraceStartTime)
743  + binTimeError * binTimeError);
744  station.GetRecData().SetParameterError(eSignalTime, timeUncertainty, false);
745  station.GetRecData().SetPulseFound(true);
746 
747  ++nStations; // count number of stations with pulse found
748  station.GetRecData().SetParameter(eSignal, tMaxAmp, false);
749  station.SetSignal(); // so we can use RdPlaneFit etc, will be overwritten in RdStationSignalReconstructor
750 
751  if (fComputeRMS) {
752  if (!station.GetRecData().HasParameter(eNoise)) {
753  WARNING("RMS was not calculated. SNR can not be determined.");
754  } else {
755  const double rms = station.GetRecData().GetParameter(eNoise);
756  const double SNR = Sqr(tMaxAmp) / Sqr(rms);
757  station.GetRecData().SetParameter(eSignalToNoise, SNR, false);
758 
759  info.str("");
760  info << "rms = " << rms << "\t signal= " << tMaxAmp << "\t SNR = " << SNR;
761  INFODebug(info);
762 
763  // set pulse found to false if the SNR is not sufficient
764  if (fSNRCut > SNR) {
765  info.str("");
766  info << "SNR condition not fulfilled, " << SNR << " < min SNR of " << fSNRCut << ".";
767  INFOIntermediate(info);
768 
769  ++nSNRCut;
770  station.GetRecData().SetPulseFound(false);
771  --nStations; // remove station from those with pulse found
772  station.SetRejectedReason(eLargeTimeResidual);
773  }
774  }
775  }
776 
777  fNumberOfStations = nStations;
778  }
779 
780  return eSuccess;
781  }
782 
783 }
ChannelFFTDataContainer & GetFFTDataContainer()
retrieve Channel FFTDataContainer (write access)
Branch GetTopBranch() const
Definition: Branch.cc:63
Class to access station level reconstructed data.
void SetParameter(Parameter i, double value, bool lock=true)
double NormalizeAngleMinusPiPi(const double x)
Normalize angle to lie between -pi and pi (-180 and 180 deg)
const double degree
constexpr T Sqr(const T &x)
bool HasRecShower() const
Interface class to access to the Radio part of an event.
Definition: REvent.h:42
ShowerRecData & GetRecShower()
Interface class to access to the RD Reconstruction of a Shower.
double GetParameterError(const Parameter i) const
double GetBinning() const
size of one slot
Definition: Trace.h:138
const double meter
Definition: GalacticUnits.h:29
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
string ToString(const G &g, const CoordinateSystemPtr cs)
void Init()
Initialise the registry.
Base class for exceptions trying to access non-existing components.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
bool HasREvent() const
ChannelTimeSeries & GetChannelTimeSeries()
retrieve Channel Time Series (write access, only use this if you intend to change the data) ...
Detector description interface for RDetector-related data.
Definition: RDetector.h:46
constexpr double deg
Definition: AugerUnits.h:140
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
#define INFOIntermediate(y)
Definition: VModule.h:162
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
utl::Point GetCoordinateOrigin() const
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
double abs(const SVector< n, T > &v)
const Data result[]
bool HasRRecShower() const
constexpr double g
Definition: AugerUnits.h:200
SizeType GetSize() const
Definition: Trace.h:156
#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
Base class for inconsistency/illogicality exceptions.
#define INFODebug(y)
Definition: VModule.h:163
double GetParameter(const Parameter i) const
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
Vector object.
Definition: Vector.h:30
Class that holds the data associated to an individual radio channel.
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
utl::Point GetPosition() const
Tank position in Site Cartesian Coordinates.
#define INFOFinal(y)
Definition: VModule.h:161
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
const Station & GetStation(const int stationId) const
Get station by Station Id.
Definition: RDetector.cc:141
void SetParameterCovariance(Parameter i1, Parameter i2, double value, bool lock=true)
const char * what() const
std::exception will print this on crash

, generated on Tue Sep 26 2023.