RdStationSignalInterpolator.cc
Go to the documentation of this file.
2 
3 #include <fwk/CentralConfig.h>
4 #include <utl/ErrorLogger.h>
5 
6 #include <utl/AugerUnits.h>
7 #include <utl/CoordinateSystem.h>
8 #include <utl/FFTDataContainer.h>
9 #include <utl/Point.h>
10 #include <utl/RadioGeometryUtilities.h>
11 #include <utl/StringCompare.h>
12 #include <utl/TimeStamp.h>
13 #include <utl/UTCDateTime.h>
14 
15 #include <evt/Event.h>
16 #include <evt/RadioSimulation.h>
17 #include <evt/ShowerSimData.h>
18 #include <evt/ShowerRecData.h>
19 #include <evt/ShowerRRecData.h>
20 #include <evt/ShowerRRecDataQuantities.h>
21 
22 #include <revt/REvent.h>
23 #include <revt/EventTrigger.h>
24 #include <revt/Station.h>
25 #include <revt/Header.h>
26 
27 #include <sevt/SEvent.h>
28 #include <sevt/Station.h>
29 #include <sevt/EventTrigger.h>
30 
31 #include <rdet/RDetector.h>
32 #include <rdet/Station.h>
33 
34 #include <atm/AerosolDB.h>
35 #include <atm/AerosolZone.h>
36 #include <atm/ProfileResult.h>
37 #include <atm/MonthlyAvgDBProfileModel.h>
38 #include <atm/InclinedAtmosphericProfile.h>
39 
40 using namespace std;
41 using namespace evt;
42 using namespace det;
43 using namespace utl;
44 using namespace fwk;
45 using namespace revt;
46 
47 
49 
52  {
53  Branch topBranch = CentralConfig::GetInstance()->GetTopBranch("RdStationSignalInterpolator");
54  topBranch.GetChild("InfoLevel").GetData(fInfoLevel);
55 
56  topBranch.GetChild("MinimumStationEnergy").GetData(fMinimumEnergy);
57 
58  fUseEarlyLate =
59  utl::StringEquivalent(topBranch.GetChild("UseEarlyLateCorrection").Get<string>(), "yes");
60 
61  // FS:
62  if (fUseEarlyLate)
63  ERROR("Early Late Correction will not be used within in the interpolation of "
64  "the signals (even if configured). It is not properly implemented.");
65 
66  fRequireSDStationTrigger = utl::StringEquivalent(topBranch.GetChild("RequireSDStationTrigger").Get<string>(), "yes");
67 
68  topBranch.GetChild("InterpolationMethod").GetData(fInterpolationMethod);
69 
70  ostringstream info;
71  info << "\n\t Interpolate only stations with energy fluence above " << fMinimumEnergy << " eV."
72  "\n\t Interpolation method is " << fInterpolationMethod << "; (0: nearest neighbour, 1: bilinear interpolation,"
73  " 2: bicubic interpolation)"
74  "\n\t Require SD T2 trigger: " << fRequireSDStationTrigger << "\n";
75  INFO(info);
76 
77  return eSuccess;
78  }
79 
80 
82  RdStationSignalInterpolator::Run(evt::Event& event)
83  {
84  INFOFinal("");
85 
86  evt::ShowerSimData& simshow = event.GetSimShower();
87  Detector& det = Detector::GetInstance();
88  const rdet::RDetector& radioDet = det.GetRDetector();
89 
90  // At the moment: created Station IDs at StarShape station positions (not the actual Antenna Positions!) start at 10 000
91  const int maxStationID = 9999;
92 
93  REvent& rEvent = event.GetREvent();
94  ShowerRRecData& showerrrec = event.GetRecShower().GetRRecShower();
95 
96  const Vector simShowerAxis = -simshow.GetDirection();
97  const Vector magneticField = showerrrec.GetMagneticFieldVector();
98  const utl::CoordinateSystemPtr corsys = simshow.GetLocalCoordinateSystem();
99  RadioGeometryUtilities transformation = RadioGeometryUtilities(simShowerAxis, corsys, magneticField);
100 
101  // Init some stuff needed:
102  vector<StarShapeEntry> starShapeStations;
103  set<double> radiusValues;
104  set<double> azimuthValues;
105  set<double> azimuthValuesStarShape;
106  set<double> altitudeValues;
107 
108  // TODO: Better selection criterium for StarShape pattern identification possible.
109  // Careful: it is possible for all arms not to have the same amount of stations!
110 
111  ostringstream info;
112  // Loop over all star-shaped grid stations -> fill Vector
113  int sstationcount = 0;
114  for (auto rdIt = rEvent.CandidateStationsBegin(); rdIt != rEvent.CandidateStationsEnd(); ++rdIt) {
115  const int statID = rdIt->GetId();
116  if (statID < maxStationID)
117  continue;
118 
119  Station& station = *rdIt;
120  const Point position = radioDet.GetStation(station).GetPosition();
121 
122  // due to the choice of coordinate system the station position will be evaluated relative to the core position
123  double x_vxB = 0;
124  double y_vxB = 0;
125  double z_vxB = 0;
126  transformation.GetVectorInShowerPlaneVxB(x_vxB, y_vxB, z_vxB, position);
127 
128  if (!station.HasRecData()) {
129  WARNING("Station has no RecData! Please call RdEventInitializer first!");
130  return eFailure;
131  }
132 
133  if (!station.GetRecData().HasParameter(eSignalEnergyFluenceMag)) {
134  info.str("");
135  info << "Station doesn't have rec. signal..skip. ID: " << statID;
136  INFOIntermediate(info);
137  continue;
138  }
139 
140  const double radius = sqrt(pow(x_vxB, 2) + pow(y_vxB, 2));
141  const double azimuth = atan2(y_vxB, x_vxB);
142  const double altitude = position.GetZ(corsys);
143  const unsigned int sizeAzi = azimuthValues.size();
144 
145  starShapeStations.emplace_back(radius, azimuth, statID);
146  radiusValues.insert(round(radius * 10) / 10); // store rounded radius value
147  azimuthValues.insert(round(azimuth * 10000) / 10000);
148  altitudeValues.insert(round(altitude)); // store rounded altitude value
149 
150  if (azimuthValues.size() == sizeAzi)
151  azimuthValuesStarShape.insert(round(azimuth * 1000) / 1000);
152 
153  ++sstationcount;
154  }
155 
156  if (starShapeStations.empty()) {
157  ERROR("No antennas on a star. Skip...");
158  return eContinueLoop;
159  }
160 
161  info.str("");
162  info << "Simulation has " << radiusValues.size() << " rings, " << azimuthValuesStarShape.size()
163  << " angle bins [" << azimuthValues.size() << " angles in total],and spans heights from " << (*altitudeValues.begin()) / meter
164  << " m to " << (*altitudeValues.rbegin()) / meter << " m above core.";
165  INFOIntermediate(info);
166 
167  if (azimuthValuesStarShape.size() != 8) {
168  if (azimuthValues.size() == 8) {
169  azimuthValuesStarShape = azimuthValues;
170  } else {
171  WARNING("RdStationInterpolatorStarShape: Simulation does not have 8 arms. Aborting ...");
172  return eContinueLoop;
173  }
174  }
175  info.str("");
176  info << "Number of star shaped stations: " << sstationcount;
177  INFOIntermediate(info);
178 
179  //if (fUseEarlyLate) {
180  // // The following is needed for the early late correction:
181  // // Early late correction is applied when transforming to the shower-plane coordinate system and it is inversely
182  // // applied after the interpolation process.
183  // // Needed for early late correction:
184  // const auto& gh = simshow.GetGHParameters();
185  // const double shower_xmax = gh.GetXMax();
186 
187  // Point simCore = simshow.GetPosition(); // MC core
188  // const atm::Atmosphere& theAtm = Det.GetAtmosphere();
189 
190  // theAtm.InitSlantProfileModel(simCore, simShowerAxis, 5.*g/cm2);
191  // const atm::ProfileResult& distanceVsdepth = theAtm.EvaluateDistanceVsSlantDepth();
192  // // shower maximum
193  // const double distance_to_xmax = abs(distanceVsdepth.Y(shower_xmax));
194  // const Point showerMax = simCore + simShowerAxis * distance_to_xmax;
195  // info.str("");
196  // info << "Applying the early late correction (on energy fluence and distance to axis)"
197  // << "\nDepth of Xmax: " << shower_xmax / (g / cm2)
198  // << "\nDistance of Xmax: " << distance_to_xmax / meter
199  // << "\nDistance of Xmax (sim event): " << simshow.GetDistanceOfShowerMaximum() / meter;
200  // INFOIntermediate(info);
201  // }
202 
203  // The following enums are interpolated. After that, SNR is calculated based on the formula in the StationSignalReconstructor
204  std::vector<StationRRecDataQuantities> eNumNames = {
205  eSignalEnergyFluenceMag,
206  eSignalEnergyFluenceVxB,
207  eSignalEnergyFluenceVxVxB,
208  eNoiseEnergyFluenceMag,
209  eNoiseEnergyFluenceVxB,
210  eNoiseEnergyFluenceVxVxB,
211  eSignal,
212  eNoise,
213  eSignalTime,
214  eSignalToNoise
215  };
216 
217  std::vector<StationRRecDataQuantities> eNumNamesError = {
218  eSignalEnergyFluenceMag,
219  eSignalEnergyFluenceVxB,
220  eSignalEnergyFluenceVxVxB,
221  eSignal,
222  eNoise,
223  eSignalTime,
224  eSignalToNoise
225  };
226 
227  // sort the list of StarShapeStations in arms with same azimuth first, and after with increasing radius
228  sort(starShapeStations.begin(), starShapeStations.end());
229 
230  // now loop over radio (upgrade) detector stations and interpolate them from the virtual stations.
231  unsigned int n_interpolated_stations = 0;
232  for (auto rdIt = radioDet.StationsBegin(); rdIt != radioDet.StationsEnd(); ++rdIt) {
233 
234  const Point pos = rdIt->GetPosition();
235  const int statID = rdIt->GetId();
236 
237  if (!rEvent.HasStation(statID))
238  rEvent.MakeStation(statID); // Create a new Station, already checks if the station exists
239 
240  revt::Station& revtStation = rEvent.GetStation(statID);
241 
242  // skip station on star
243  if (statID >= maxStationID) {
245  continue;
246  }
247 
248  double x_vxB = 0;
249  double y_vxB = 0;
250  double z_vxB = 0;
251  transformation.GetVectorInShowerPlaneVxB(x_vxB, y_vxB, z_vxB, pos);
252 
253  //double earlyLateCorrectionFactor = 1;
254  //if (fUseEarlyLate){
255  // // checked with distance_to_xmax / (distance_to_xmax + Z_VxB);
256  // const double earlyLateCorrectionFactor =
257  // RadioGeometryUtilities::GetEarlyLateCorrectionFactor(simCore, Pos, showerMax, simShowerAxis);
258  // info.str("");
259  // info << "c early late: " << c_early_late << endl;
260  // INFOIntermediate(info);
261  //}
262 
263  // Early Late correction (distance)
264  //x_vxB /= earlyLateCorrectionFactor;
265  //y_vxB /= earlyLateCorrectionFactor;
266 
267  const double stationRadius = sqrt(pow(x_vxB, 2) + pow(y_vxB, 2));
268  const double stationAzimuth = atan2(y_vxB, x_vxB);
269 
270  // skip stations outside the star
271  if (stationRadius > *radiusValues.rbegin()) {
273  continue;
274  }
275 
276  // skip stations inside the innermost ring.. TODO: Fix Interpolation in innermost ring.
277  if (stationRadius <= *radiusValues.begin()) {
279  continue;
280  }
281 
282  info.str("");
283  info << "StationID: " << statID << ", Station position: r = "
284  << stationRadius << ", phi = " << stationAzimuth;
285  INFODebug(info);
286 
287  // FS: Comment following line because it seems redundant
288  //sort(StarShapeStations.begin(), StarShapeStations.end());
289 
290  // create data structures
291  if (!revtStation.HasGPSData())
292  revtStation.MakeGPSData();
293  if (!revtStation.HasTriggerData())
294  revtStation.MakeTriggerData();
295  if (!revtStation.HasSimData())
296  revtStation.MakeSimData();
297  if (!revtStation.HasRecData())
298  revtStation.MakeRecData();
299 
300  vector<double> interpolatedValues;
301  vector<double> interpolatedValuesError;
302  if (fInterpolationMethod == eNN) {
303  interpolatedValues =
304  NearestNeighbourInterpolation(stationRadius, stationAzimuth, azimuthValuesStarShape,
305  starShapeStations, eNumNames, rEvent, false);
306  interpolatedValuesError =
307  NearestNeighbourInterpolation(stationRadius, stationAzimuth, azimuthValuesStarShape,
308  starShapeStations, eNumNamesError, rEvent, true);
309  } else if (fInterpolationMethod == eBilinear) {
310  interpolatedValues =
311  BilinearInterpolation(stationRadius, stationAzimuth, azimuthValuesStarShape,
312  starShapeStations, eNumNames, rEvent, false);
313  interpolatedValuesError =
314  BilinearInterpolation(stationRadius, stationAzimuth, azimuthValuesStarShape,
315  starShapeStations, eNumNamesError, rEvent, true);
316  } else if (fInterpolationMethod == eBicubic) {
317  interpolatedValues =
318  BicubicInterpolation(stationRadius, stationAzimuth, azimuthValuesStarShape,
319  starShapeStations, eNumNames, rEvent, false);
320  interpolatedValuesError =
321  BicubicInterpolation(stationRadius, stationAzimuth, azimuthValuesStarShape,
322  starShapeStations, eNumNamesError, rEvent, true);
323  }
324 
325  if (fRequireSDStationTrigger) {
326 
327  if (!event.HasSEvent()) {
328  ERROR("SEvent not available but required!");
329  return eFailure;
330  }
331 
332  const sevt::SEvent& sEvent = event.GetSEvent();
333 
334  info.str("");
335  info << "SD station " << statID;
336  if (sEvent.HasStation(statID)) {
337  info << " is in the SEvent, ";
338  if (sEvent.GetStation(statID).HasTriggerData()) {
339  const sevt::StationTriggerData& trig = sEvent.GetStation(statID).GetTriggerData();
340  if (trig.IsT2() || trig.IsT1()){
341  info << " and has trigger (T1 or T2). Continue interpolation.";
342  } else {
343  info << " but doesn't have T1 or T2 trigger data. skip.";
345  INFOIntermediate(info);
346  continue;
347  }
348  } else {
349  info << " but doesn't have any trigger data. skip.";
351  INFOIntermediate(info);
352  continue;
353  }
354  } else {
355  info << " is not in the SEvent. skip.";
357  INFOIntermediate(info);
358  continue;
359  }
360  INFOIntermediate(info);
361 
362  }
363 
364  info.str("");
365  if (interpolatedValues[0] > fMinimumEnergy && interpolatedValues[0] < std::numeric_limits<double>::max()) {
366  info << "Station " << statID << ", station radius: " << stationRadius
367  << ", station azimuth: " << stationAzimuth << "--> EnergyFluence: "
368  << interpolatedValues[0] << " +/- " << interpolatedValuesError[0];
369  INFOIntermediate(info);
370 
371  // check if there is data already and throw a warning... This should not happen.
372  if (revtStation.GetStationTimeSeries().GetSize())
373  WARNING("RDStationSignalInterpolator: StationTimeSeries not empty!");
374 
375  info.str("");
376  int i = 0;
377  for (vector<double>::const_iterator it = interpolatedValues.begin(); it != interpolatedValues.end(); ++it, ++i) {
378  info << "Interpolated Value: " << *it << ", enum: " << eNumNames[i] << '\n';
379  const double intVal = *it;
380  //if (fUseEarlyLate)
381  // intVal /= pow(EnergyFluenceCorrectionEarlyLateEffect, 2);
382  revtStation.GetRecData().SetParameter(eNumNames[i], intVal);
383  }
384 
385  i = 0;
386  for (vector<double>::const_iterator it = interpolatedValuesError.begin(); it != interpolatedValuesError.end(); ++it, ++i) {
387  info << "Interpolated Value Error: " << *it << ", enum: " << eNumNamesError[i] << '\n';
388  revtStation.GetRecData().SetParameterError(eNumNamesError[i], *it);
389  }
390  revtStation.SetSignal();
391  revtStation.GetRecData().SetPulseFound(true);
392 
393  info << "Station will be used for Reconstruction. ID is " << statID;
394  INFODebug(info);
395  } else {
396  //revtStation.SetSignal();
397  revtStation.SetRejectedReason(eBadSNR);
398  info << "Interpolated Energy Fluence of Station " << statID << " is too low(" << interpolatedValues[0] << ") -> skip\n"
399  << "RejectionStatus, badSNR: " << revtStation.GetRejectedReason();
400  INFODebug(info);
401  continue;
402  }
403 
404  // calculating SNR and Errors (10% on the value, copied from StationSignalReconstructor
405  const double peakAmplitude = revtStation.GetRecData().GetParameter(eSignal);
406  const double rmsNoise = revtStation.GetRecData().GetParameter(eNoise);
407  const double signalToNoise = peakAmplitude / rmsNoise;
408  info.str("");
409  //info << "interpolated SNR: " << revtStation.GetRecData().GetParameter(eSignalToNoise) << ", ";
410  info << "Calculated Signal to Noise ratio: " << Sqr(signalToNoise);
411  //info << "interpolatedrrors: " << revtStation.GetRecData().GetParameterError(eSignalToNoise)
412  //<< ", now calculate it from Signal and Noise: "
413  //<< 0.1*Sqr(SignalToNoise) << ", " << endl;
414  revtStation.GetRecData().SetParameter(eSignalToNoise, Sqr(signalToNoise));
415  revtStation.GetRecData().SetParameterError(eSignalToNoise, 0.1 * Sqr(signalToNoise));
416  // hard coded 10%, defined like this in the StationSignalReconstructor
417  INFOIntermediate(info);
418 
419  ++n_interpolated_stations;
420  }
421 
422  info.str("");
423  info << "Interpolated (and accepted) " << n_interpolated_stations << " signals to a corresponding station on a regular grid.";
424  INFOFinal(info);
425 
426  return eSuccess;
427  }
428 
429 
431  RdStationSignalInterpolator::Finish()
432  {
433  // Put any termination or cleanup code here.
434  // This method is called once at the end of the run.
435 
436  INFO("RdStationSignalInterpolator::Finish()");
437 
438  return eSuccess;
439  }
440 
441 
442  double
443  RdStationSignalInterpolator::PolarDistance(const double r1, const double phi1, const double r2, const double phi2)
444  {
445  return sqrt(pow(r1, 2) + pow(r2, 2) - 2*r1*r2*cos(phi1 - phi2));
446  }
447 
448 
449  void
450  RdStationSignalInterpolator::MoveItemToBack(std::vector<StarShapeEntry>& v, const size_t itemIndex)
451  {
452  const auto it = v.begin() + itemIndex;
453  std::rotate(it, it + 1, v.end());
454  }
455 
456 
457  vector<StarShapeEntry>
458  RdStationSignalInterpolator::SortForInterpolation(const std::vector<StarShapeEntry>& list)
459  {
460  auto starShapeList = list; // copy
461  /*ostringstream debug;
462  debug.str("");
463  debug << starShapeList[0].fObserverAzimuthAngle
464  << ", " << starShapeList[4].fObserverAzimuthAngle
465  << ", " << starShapeList[8].fObserverAzimuthAngle
466  << ", " << starShapeList[12].fObserverAzimuthAngle;*/
467  const double az1 = starShapeList[0].fObserverAzimuthAngle;
468  const double az2 = starShapeList[4].fObserverAzimuthAngle;
469  const double az3 = starShapeList[8].fObserverAzimuthAngle;
470  const double az4 = starShapeList[12].fObserverAzimuthAngle;
471  //vector<StarShapeEntry> manipulatedStarShapeList = starShapeList;
472  const double d1 = az2 - az1;
473  const double d2 = az3 - az2;
474  const double d3 = az4 - az3;
475  //const double d4 = az1 - az4;
476  //debug << "\ndistance: \n" << d1 << endl << d2 << endl << d3 << endl << d4 << endl;
477 
478  // find the jump from +Pi to -Pi:
479  if (fabs(d1) > M_PI*2/7) {
480  //debug << "jump between 1 and 2: " << az1 << ", " << az2;
481  for (unsigned int i = 0; i < 4; ++i) {
482  MoveItemToBack(starShapeList, 0);
483  }
484  //debug << "Azi, Radius: " << endl;
485  /*for (vector<StarShapeEntry>::const_iterator it = starShapeList.begin(); it != starShapeList.end(); ++it) {
486  debug << it->fObserverAzimuthAngle << ", " << it ->fDistanceFromShowerAxis << endl;
487  }*/
488  }
489  if (fabs(d2) > M_PI*2/7) {
490  //debug << "jump between 2 and 3: " << az2 << ", " << az3;
491  for (unsigned int i = 0; i < 8; ++i) {
492  MoveItemToBack(starShapeList, 0);
493  }
494  //debug << "Azi, Radius: " << endl;
495  /*for (vector<StarShapeEntry>::const_iterator it = starShapeList.begin(); it != starShapeList.end(); ++it) {
496  debug << it->fObserverAzimuthAngle << ", " << it ->fDistanceFromShowerAxis << endl;
497  }*/
498  }
499  if (fabs(d3) > M_PI*2/7) {
500  //debug << "jump between 3 and 4: " << az3 << ", " << az4;
501  for (unsigned int i = 0; i < 12; ++i) {
502  MoveItemToBack(starShapeList, 0);
503  }
504  /*debug << "Azi, Radius: " << endl;
505  for(vector<StarShapeEntry>::const_iterator it = StarShapeList.begin(); it != StarShapeList.end(); it++) {
506  debug << it->fObserverAzimuthAngle << ", " << it ->fDistanceFromShowerAxis << endl;
507  }*/
508  }
509  /*if (fabs(d4) > M_PI*2/7) {
510  debug << "all good.." << endl;
511  }*/
512  //INFODebug(debug);
513  return starShapeList;
514  }
515 
516 
517  // returns the summand for the cubic interpolation in one dimension. X being the desired position between the xi. vi are the value at the positions xi!
518  double
519  RdStationSignalInterpolator::LagrangianFactorCubic(const double X,
520  const double x1, const double x2, const double x3, const double x4,
521  const double v1, const double v2, const double v3, const double v4)
522  {
523  const double value =
524  (X - x2) / (x1 - x2) * (X - x3) / (x1 - x3) * (X - x4) / (x1 - x4) * v1 +
525  (X - x1) / (x2 - x1) * (X - x3) / (x2 - x3) * (X - x4) / (x2 - x4) * v2 +
526  (X - x1) / (x3 - x1) * (X - x2) / (x3 - x2) * (X - x4) / (x3 - x4) * v3 +
527  (X - x1) / (x4 - x1) * (X - x2) / (x4 - x2) * (X - x3) / (x4 - x2) * v4;
528  /*ostringstream debug;
529  debug << "interpolated value: " << value << endl;
530  INFODebug(debug);*/
531  return value;
532  }
533 
534 
535  // definition of findIndexOfSurroundingNN, this gives the indices of the four closest stations (or rather: the two closest stations for the two closest azimuth angles)
536  vector<int>
537  RdStationSignalInterpolator::FindIndexOfSurroundingNN(const double radius, const double azimuth,
538  const std::set<double>& azimuthListStarShape,
539  const std::vector<StarShapeEntry>& starShapeList)
540  {
541  //ostringstream debug;
542  bool ok = true;
543  double highAzi = -10;
544  double lowAzi = -10;
545  double roundedAzi;
546  vector<int> listNN;
547  for (unsigned int tmppul = 0; tmppul < starShapeList.size()-1; ++tmppul) {
548  roundedAzi = round(starShapeList.at(tmppul).fObserverAzimuthAngle*1000) / 1000;
549  if (azimuthListStarShape.find(roundedAzi) == azimuthListStarShape.end())
550  continue;
551  if (azimuth > roundedAzi)
552  lowAzi = roundedAzi;
553  else {
554  highAzi = roundedAzi;
555  break;
556  }
557  } // for loop: find the Azimuth angle of the arm on the right (HighAzi) and the left (LowAzi) of the starshaped station list.
558 
559  //debug << "Higher Azimuth:" << HighAzi << ", Lower Azimuth: " << LowAzi << endl;
560  if (azimuth < *azimuthListStarShape.begin() || azimuth > *azimuthListStarShape.rbegin()) {
561  lowAzi = *azimuthListStarShape.rbegin();
562  highAzi = *azimuthListStarShape.begin();
563  }
564  if (azimuthListStarShape.size() > 8 || lowAzi == -10 || highAzi == -10)
565  return { -1 };
566  //debug << "Higher Azimuth:" << HighAzi << ", Lower Azimuth: " << LowAzi << endl;
567  //INFODebug(debug);
568  int indexHighHigh = -1;
569  int indexHighLow = -1;
570  int indexLowHigh = -1;
571  int indexLowLow = -1;
572  for (unsigned int tmppul = 0; tmppul < starShapeList.size()-1; ++tmppul) { // find closest radii of lower Azimuth
573  if ((fabs(lowAzi - starShapeList.at(tmppul).fObserverAzimuthAngle) >= 0.01) ||
574  (fabs(lowAzi - starShapeList.at(tmppul+1).fObserverAzimuthAngle) >= 0.01))
575  continue;
576 
577  if (starShapeList.at(tmppul).fDistanceFromShowerAxis < radius &&
578  starShapeList.at(tmppul+1).fDistanceFromShowerAxis > radius) {
579  indexLowLow = tmppul;
580  indexLowHigh = tmppul+1;
581  break;
582  }
583  if (tmppul == starShapeList.size()-1)
584  ok = false; //No Pulses with lower Azi with according radii
585  }
586  if (!ok || indexLowHigh == -1)
587  return { -1 };
588  for (unsigned int tmppul = 0; tmppul < starShapeList.size()-1; ++tmppul) { // find closest radii of higher Azimuth
589  if ((fabs(highAzi - starShapeList.at(tmppul).fObserverAzimuthAngle) >= 0.01) ||
590  (fabs(highAzi - starShapeList.at(tmppul+1).fObserverAzimuthAngle) >= 0.01))
591  continue;
592 
593  if (starShapeList.at(tmppul).fDistanceFromShowerAxis < radius &&
594  starShapeList.at(tmppul+1).fDistanceFromShowerAxis > radius) {
595  indexHighLow = tmppul;
596  indexHighHigh = tmppul+1;
597  break;
598  }
599  if (tmppul == starShapeList.size()-1)
600  ok = false; //No Pulses with higher Azi with according radii
601  }
602  if (!ok || indexHighHigh == -1)
603  return { -1 };
604  listNN = { indexHighHigh, indexHighLow, indexLowHigh, indexLowLow };
605  return listNN;
606  }
607 
608 
609  vector<double>
610  RdStationSignalInterpolator::NearestNeighbourInterpolation(const double radius, const double azimuth,
611  const std::set<double>& azimuthListStarShape,
612  const std::vector<StarShapeEntry>& starShapeList,
613  const std::vector<StationRRecDataQuantities>& eNumNames,
614  REvent& rEvent, const bool errors)
615  {
616  //ostringstream final, debug;
617  double r0 = radius;
618  double phi0 = azimuth;
619  vector<int> nn = FindIndexOfSurroundingNN(radius, azimuth, azimuthListStarShape, starShapeList);
620  vector <double> interpolatedValues;
621  //debug << "NN-Size: " << NN.size() << endl;
622  if (nn.size() != 4 || eNumNames.size() == 0)
623  return { 0 };
624 
625  double tmpDist = PolarDistance(starShapeList.at(nn[0]).fDistanceFromShowerAxis,
626  starShapeList.at(nn[0]).fObserverAzimuthAngle, r0, phi0);
627  int nnStationID = starShapeList.at(nn[0]).fStationID;
628  for (unsigned int i = 0; i < nn.size(); ++i) {
629  if (nn[i] == -1)
630  return { 0 };
631  if (PolarDistance(starShapeList.at(nn[i]).fDistanceFromShowerAxis,
632  starShapeList.at(nn[i]).fObserverAzimuthAngle, r0, phi0) < tmpDist) {
633  tmpDist = PolarDistance(starShapeList.at(nn[i]).fDistanceFromShowerAxis,
634  starShapeList.at(nn[i]).fObserverAzimuthAngle, r0, phi0);
635  nnStationID = starShapeList.at(nn[i]).fStationID;
636  }
637  //debug << "nn ID: " << nnStationID << endl;
638  }
639  //debug << "nn Station ID: " << nnStationID << endl;
640  //INFODebug(debug);
641  if (errors) {
642  for (vector<StationRRecDataQuantities>::const_iterator it = eNumNames.begin(); it != eNumNames.end(); ++it) {
643  if (rEvent.GetStation(nnStationID).GetRecData().HasParameterError(*it))
644  interpolatedValues.push_back(rEvent.GetStation(nnStationID).GetRecData().GetParameterError(*it));
645  else {
646  /*final << "eNum Error for " << *it << " not set, skip interpolation for Station" << endl;
647  INFOFinal(final);*/
648  return { 0 };
649  }
650  }
651  } else {
652  for (vector<StationRRecDataQuantities>::const_iterator it = eNumNames.begin(); it != eNumNames.end(); ++it) {
653  if (rEvent.GetStation(nnStationID).GetRecData().HasParameter(*it))
654  interpolatedValues.push_back(rEvent.GetStation(nnStationID).GetRecData().GetParameter(*it));
655  else {
656  /*final << "eNum for " << *it << " not set, skip interpolation for Station" << endl;
657  INFOFinal(final);*/
658  return { 0 };
659  }
660  }
661  }
662  return interpolatedValues;
663  }
664 
665 
666  vector<double>
667  RdStationSignalInterpolator::BilinearInterpolation(const double radius, const double azimuth,
668  const std::set<double>& azimuthListStarShape,
669  const std::vector<StarShapeEntry>& starShapeList,
670  const std::vector<StationRRecDataQuantities>& eNumNames,
671  REvent& rEvent, const bool errors)
672  {
673  //ostringstream final,debug;
674  double r0 = radius;
675  double phi0 = azimuth;
676  vector<int> nn = FindIndexOfSurroundingNN(radius, azimuth, azimuthListStarShape, starShapeList);
677  vector<int> nStationID;
678  vector <double> interpolatedValues;
679  //debug << "nn-Size: " << nn.size() << endl;
680  if (nn.size() != 4 || eNumNames.size() == 0)
681  return { 0 };
682  for (unsigned int i = 0; i < nn.size(); ++i) {
683  if (nn[i] == -1)
684  return { 0 };
685  nStationID.push_back(starShapeList.at(nn[i]).fStationID);
686  //debug << "nn: " <<nn[i] << endl;
687  }
688  //INFODebug(debug);
689  double r1 = starShapeList.at(nn[0]).fDistanceFromShowerAxis;
690  double r2 = starShapeList.at(nn[1]).fDistanceFromShowerAxis;
691  double r3 = starShapeList.at(nn[2]).fDistanceFromShowerAxis;
692  double r4 = starShapeList.at(nn[3]).fDistanceFromShowerAxis;
693  double phi1 = starShapeList.at(nn[0]).fObserverAzimuthAngle;
694  double phi2 = starShapeList.at(nn[2]).fObserverAzimuthAngle;
695  if (phi1 < phi2) {
696  phi1 += 2*M_PI;
697  if (phi0 < 0)
698  phi0 += 2*M_PI;
699  }
700  if (errors) {
701  for (vector<StationRRecDataQuantities>::const_iterator it = eNumNames.begin(); it != eNumNames.end(); ++it) {
702  if (rEvent.GetStation(nStationID[0]).GetRecData().HasParameterError(*it) &&
703  rEvent.GetStation(nStationID[1]).GetRecData().HasParameterError(*it) &&
704  rEvent.GetStation(nStationID[2]).GetRecData().HasParameterError(*it) &&
705  rEvent.GetStation(nStationID[3]).GetRecData().HasParameterError(*it)) {
706  double par1 = rEvent.GetStation(nStationID[0]).GetRecData().GetParameterError(*it);
707  double par2 = rEvent.GetStation(nStationID[1]).GetRecData().GetParameterError(*it);
708  double par3 = rEvent.GetStation(nStationID[2]).GetRecData().GetParameterError(*it);
709  double par4 = rEvent.GetStation(nStationID[3]).GetRecData().GetParameterError(*it);
710  interpolatedValues.push_back((phi2 - phi0) / (phi2 - phi1) * ((r2 - r0) / (r2-r1) * par1 + (r0 - r1) / (r2 - r1) * par2) +
711  ((phi0 - phi1) / (phi2 - phi1) * ((r4 - r0) / (r4 - r3)*par3 + (r0 - r3) / (r4 - r3)*par4)));
712  } else {
713  /*final << "eNum Error for " << *it << " not set, skip interpolation for Station" << endl;
714  INFOFinal(final);*/
715  return { 0 };
716  }
717  }
718  } else {
719  for (vector<StationRRecDataQuantities>::const_iterator it = eNumNames.begin(); it != eNumNames.end(); ++it) {
720  if (rEvent.GetStation(nStationID[0]).GetRecData().HasParameter(*it) &&
721  rEvent.GetStation(nStationID[1]).GetRecData().HasParameter(*it) &&
722  rEvent.GetStation(nStationID[2]).GetRecData().HasParameter(*it) &&
723  rEvent.GetStation(nStationID[3]).GetRecData().HasParameter(*it)) {
724  double par1 = rEvent.GetStation(nStationID[0]).GetRecData().GetParameter(*it);
725  double par2 = rEvent.GetStation(nStationID[1]).GetRecData().GetParameter(*it);
726  double par3 = rEvent.GetStation(nStationID[2]).GetRecData().GetParameter(*it);
727  double par4 = rEvent.GetStation(nStationID[3]).GetRecData().GetParameter(*it);
728  interpolatedValues.push_back((phi2 - phi0) / (phi2 - phi1) * (( r2 - r0) / (r2 - r1) * par1 + (r0 - r1) / (r2 - r1) * par2)
729  + ((phi0 - phi1) / (phi2 - phi1) * ((r4 - r0) / (r4 - r3) * par3 + (r0 - r3) / (r4 - r3) * par4)));
730  } else {
731  /*final << "eNum for " << *it << " not set, skip interpolation for Station" << endl;
732  INFOFinal(final);*/
733  return { 0 };
734  }
735  }
736  }
737  return interpolatedValues;
738  }
739 
740 
741  // bicubic interpolation at the station position
742  vector<double>
743  RdStationSignalInterpolator::BicubicInterpolation(const double radius, const double azimuth,
744  const std::set<double>& azimuthListStarShape,
745  const std::vector<StarShapeEntry>& starShapeList,
746  const std::vector<StationRRecDataQuantities>& eNumNames,
747  REvent& rEvent, const bool errors)
748  {
749  ostringstream intermediate;
750  ostringstream debug;
751  double r0 = radius;
752  double phi0 = azimuth;
753  vector<StarShapeEntry> interpolationStationList;
754  vector<int> tmpNN = FindIndexOfSurroundingNN(radius, azimuth, azimuthListStarShape, starShapeList);
755  vector<int> nStationID;
756  if (tmpNN.size() != 4 || eNumNames.size() == 0)
757  return { 0 };
758  for (unsigned int i = 0; i < tmpNN.size(); ++i) {
759  if (tmpNN[i] == -1)
760  return { 0 };
761  nStationID.push_back(starShapeList.at(tmpNN[i]).fStationID);
762  //debug << "NN: " <<tmpNN[i] << endl;
763  }
764  double r1 = starShapeList.at(tmpNN[0]).fDistanceFromShowerAxis;
765  double r2 = starShapeList.at(tmpNN[1]).fDistanceFromShowerAxis;
766  double r3 = starShapeList.at(tmpNN[2]).fDistanceFromShowerAxis;
767  double r4 = starShapeList.at(tmpNN[3]).fDistanceFromShowerAxis;
768  double phi1 = starShapeList.at(tmpNN[0]).fObserverAzimuthAngle;
769  double phi2 = starShapeList.at(tmpNN[1]).fObserverAzimuthAngle;
770  double phi3 = starShapeList.at(tmpNN[2]).fObserverAzimuthAngle;
771  double phi4 = starShapeList.at(tmpNN[3]).fObserverAzimuthAngle;
772  //debug << "radius 1-4: " << r1 << ", " << r2 << ", " << r3 << ", " << r4 << endl;
773  //debug << "phi 1-4: " << phi1 << ", " << phi2 << ", " << phi3 << ", " << phi4 << endl;
774 
775  // get the 16 closest stations
776  vector<int> nnuu = FindIndexOfSurroundingNN(r1+10, phi1+0.1, azimuthListStarShape, starShapeList);
777  vector<int> nnud = FindIndexOfSurroundingNN(r2-10, phi2+0.1, azimuthListStarShape, starShapeList);
778  vector<int> nndu = FindIndexOfSurroundingNN(r3+10, phi3-0.1, azimuthListStarShape, starShapeList);
779  vector<int> nndd = FindIndexOfSurroundingNN(r4-10, phi4-0.1, azimuthListStarShape, starShapeList);
780  /*for (int i = 0; i < 4; ++i) {
781  debug << "tmpNN: " << tmpNN[i] << ", " << "UU: " << NNuu[i] << ", " << "UD: "
782  << NNud[i] << ", " << "DU: " << NNdu[i] << ", " << "DD: " << NNdd[i] << endl;
783  }*/
784  if (nnuu[1] == nnud[0] || nnuu[1] == nnud[1]) {
785  nnuu = FindIndexOfSurroundingNN(r1+30, phi1+0.1, azimuthListStarShape, starShapeList);
786  nnud = FindIndexOfSurroundingNN(r2-30, phi2+0.1, azimuthListStarShape, starShapeList);
787  //debug << "No perfect star shape => nnuu and nnud changed!" << endl;
788  if (nnuu[1] == nnud[0] || nnuu[1] == nnud[1]) {
789  /*debug << "... but it didn't work." << endl;
790  INFODebug(debug);*/
791  return { -1 };
792  }
793  }
794  if (nndd[2] == nndu[3] || nndd[3] == nndu[3]) {
795  nndd = FindIndexOfSurroundingNN(r3+30, phi3-0.1, azimuthListStarShape, starShapeList);
796  nndu = FindIndexOfSurroundingNN(r4-30, phi4-0.1, azimuthListStarShape, starShapeList);
797  debug << "No perfect star shape => NNdd and NNdu changed!" << endl;
798  if (nndd[3] == nndu[2] || nndd[3] == nndu[3]){
799  debug << "... but it didn't work." << endl;
800  INFODebug(debug);
801  return{-1};
802  }
803  }
804 
805  nStationID = { };
806  if (nnuu.size() != 4 || nnud.size() != 4 || nndu.size() != 4 || nndd.size() != 4)
807  return { 0 };
808  for (unsigned int i = 0; i < nnuu.size(); ++i) { // fill in grid of 16 stations
809  if (nnuu[i] == -1 || nnud[i] == -1 || nndu[i] == -1 || nndd[i] == -1)
810  return { 0 };
811  nStationID.push_back(starShapeList.at(tmpNN[i]).fStationID);
812  interpolationStationList.push_back(starShapeList.at(nnuu[i]));
813  interpolationStationList.push_back(starShapeList.at(nnud[i]));
814  interpolationStationList.push_back(starShapeList.at(nndu[i]));
815  interpolationStationList.push_back(starShapeList.at(nndd[i]));
816  //debug << StarShapeList.at(tmpNN[i]).fStationID << " ";
817  }
818  sort(interpolationStationList.begin(), interpolationStationList.end());
819 
820  // now manipulate:
821  vector<StarShapeEntry> interpolationStationListOrdered = SortForInterpolation(interpolationStationList);
822 
823  // now begin interpolation:
824  // if first azimuth is positive, then the "sortForInterpolation" might have put the lowest angles at the end of the vector.
825  // Therefor 2Pi must be added to them to account for correct "skipping" from 2Pi to -2Pi.
826 
827  phi1 = interpolationStationListOrdered[0].fObserverAzimuthAngle;
828  phi2 = interpolationStationListOrdered[4].fObserverAzimuthAngle;
829  phi3 = interpolationStationListOrdered[8].fObserverAzimuthAngle;
830  phi4 = interpolationStationListOrdered[12].fObserverAzimuthAngle;
831  if (interpolationStationListOrdered[0].fObserverAzimuthAngle > 0) {
832  if (phi0 < 0)
833  phi0 += 2*M_PI;
834  if (phi2 < 0)
835  phi2 += 2*M_PI;
836  if (phi3 < 0)
837  phi3 += 2*M_PI;
838  if (phi4 < 0)
839  phi4 += 2*M_PI;
840  }
841 
842  //debug << "check azimuth differences: " << phi2-phi1 << ", " << phi3-phi2 << ", " << phi4-phi3 << ", " << phi1-phi4 << endl;
843  //debug << "azimuth: " << phi0 << ", phis: " << phi1 << ", " << phi2 << ", " << phi3 << ", " << phi4 << endl;
844  //INFODebug(debug);
845  // now the bicubic interpolation starts:
846  double rTmp[16]; // store the radius values of all 16 positions (correctly ordered azimuth!)
847  double bicTmpValues[4]; // calculated lagrangian factors
848  vector <double> interpolatedValues;
849  if (errors) {
850  for (vector<StationRRecDataQuantities>::const_iterator it = eNumNames.begin(); it != eNumNames.end(); ++it) {
851  for (unsigned int i = 0; i < 16; ++i) {
852  rTmp[i] = interpolationStationListOrdered[i].fDistanceFromShowerAxis;
853  if (!rEvent.GetStation(interpolationStationListOrdered[i].fStationID).GetRecData().HasParameterError(*it)) {
854  intermediate << "eNum Error for " << *it << " not set for at least one simulated position, skip interpolation for Station" << endl;
855  INFOIntermediate(intermediate);
856  return { 0 };
857  }
858  }
859  for (unsigned int i = 0; i < 4; ++i) {
860  bicTmpValues[i] =
861  LagrangianFactorCubic(r0, rTmp[4*i], rTmp[4*i+1], rTmp[4*i+2], rTmp[4*i+3],
862  rEvent.GetStation(interpolationStationListOrdered[4*i].fStationID).GetRecData().GetParameterError(*it),
863  rEvent.GetStation(interpolationStationListOrdered[4*i+1].fStationID).GetRecData().GetParameterError(*it),
864  rEvent.GetStation(interpolationStationListOrdered[4*i+2].fStationID).GetRecData().GetParameterError(*it),
865  rEvent.GetStation(interpolationStationListOrdered[4*i+3].fStationID).GetRecData().GetParameterError(*it));
866  }
867  double iValue = LagrangianFactorCubic(phi0, phi1, phi2, phi3, phi4, bicTmpValues[0], bicTmpValues[1], bicTmpValues[2], bicTmpValues[3]);
868  interpolatedValues.push_back(iValue);
869  }
870  } else {
871  for (vector<StationRRecDataQuantities>::const_iterator it = eNumNames.begin(); it != eNumNames.end(); ++it) {
872  for (unsigned int i = 0; i < 16; ++i) {
873  rTmp[i] = interpolationStationListOrdered[i].fDistanceFromShowerAxis;
874  if (!rEvent.GetStation(interpolationStationListOrdered[i].fStationID).GetRecData().HasParameter(*it)) {
875  intermediate << "eNum for " << *it << " not set for at least one simulated position, skip interpolation for Station" << endl;
876  INFOIntermediate(intermediate);
877  return { 0 };
878  }
879  }
880  for (unsigned int i = 0; i < 4; ++i) {
881  bicTmpValues[i] =
882  LagrangianFactorCubic(r0, rTmp[4*i], rTmp[4*i+1], rTmp[4*i+2], rTmp[4*i+3],
883  rEvent.GetStation(interpolationStationListOrdered[4*i].fStationID).GetRecData().GetParameter(*it),
884  rEvent.GetStation(interpolationStationListOrdered[4*i+1].fStationID).GetRecData().GetParameter(*it),
885  rEvent.GetStation(interpolationStationListOrdered[4*i+2].fStationID).GetRecData().GetParameter(*it),
886  rEvent.GetStation(interpolationStationListOrdered[4*i+3].fStationID).GetRecData().GetParameter(*it));
887  }
888  double iValue = LagrangianFactorCubic(phi0, phi1, phi2, phi3, phi4, bicTmpValues[0], bicTmpValues[1], bicTmpValues[2], bicTmpValues[3]);
889  interpolatedValues.push_back(iValue);
890  /*debug.str("");
891  debug << "interpolated Value: " << iValue;*/
892  }
893  }
894  //INFODebug(debug);
895  return interpolatedValues;
896  }
897 
898 }
Branch GetTopBranch() const
Definition: Branch.cc:63
utl::CoordinateSystemPtr GetLocalCoordinateSystem() const
Get the Auger coordinate system associated to the shower core position.
void SetParameterError(Parameter i, double value, bool lock=true)
constexpr T Sqr(const T &x)
Point object.
Definition: Point.h:32
bool HasStation(const int stationId) const
Check whether station exists.
Definition: SEvent.cc:81
bool HasTriggerData() const
Check whether trigger data object exists.
void SetPulseFound(const bool pulsefound)
StationRecData & GetRecData()
Get station level reconstructed data.
CandidateStationIterator CandidateStationsEnd()
Definition: REvent.h:146
Interface class to access to the Radio part of an event.
Definition: REvent.h:42
Interface class to access to the SD part of an event.
Definition: SEvent.h:39
StationIterator StationsEnd() const
End of the collection of pointers to commissioned stations.
Definition: RDetector.h:68
void MakeSimData()
Make station simulated data object.
bool HasTriggerData() const
Check whether trigger data object exists.
Interface class to access to the RD Reconstruction of a Shower.
StationIterator StationsBegin() const
Beginning of the collection of pointers to commissioned stations.
Definition: RDetector.h:64
double GetParameterError(const Parameter i) const
bool HasParameterError(const Parameter i1) const
const double meter
Definition: GalacticUnits.h:29
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
int debug
Definition: dump1090.h:276
void Init()
Initialise the registry.
bool ok(bool okay)
Definition: testlib.cc:89
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
double pow(const double x, const unsigned int i)
Station & GetStation(const int stationId)
retrieve station by id throw utl::NonExistentComponentException if n.a.
Definition: REvent.h:190
StationTimeSeries & GetStationTimeSeries()
retrieve Station Time Series (write access, only use this if you intend to change the data) ...
bool StringEquivalent(const std::string &a, const std::string &b, Predicate p)
Utility to compare strings for equivalence. It takes a predicate to determine the equivalence of indi...
Definition: StringCompare.h:38
Detector description interface for RDetector-related data.
Definition: RDetector.h:46
void MakeGPSData()
Make GPS data object.
void MakeTriggerData()
Make trigger data object.
Interface class to access Shower Simulated parameters.
Definition: ShowerSimData.h:49
T Get() const
Definition: Branch.h:271
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
class to hold data at the radio Station level.
const utl::Vector & GetDirection() const
Get the direction of the shower axis. This is the true direction of shower movement.
Top of the hierarchy of the detector description interface.
Definition: Detector.h:81
CandidateStationIterator CandidateStationsBegin()
Definition: REvent.h:144
bool HasSimData() const
Check whether station simulated data exists.
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
void SetRejectedReason(const unsigned long long int reason)
#define INFODebug(y)
Definition: VModule.h:163
Station & GetStation(const int stationId)
retrieve station by id throw utl::NonExistentComponentException if n.a.
Definition: SEvent.h:116
double GetParameter(const Parameter i) const
void GetVectorInShowerPlaneVxB(double &x, double &y, double &z, const utl::Point &point) const
in case of positions, the positions has to be relative to the core positions!!!
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
bool HasParameter(const Parameter i) const
void MakeRecData()
Make station reconstructed data object.
Station Trigger Data description
void SetParameter(Parameter i, double value, bool lock=true)
Vector object.
Definition: Vector.h:30
void SetExcludedReason(const ExcludedReason reason)
const rdet::RDetector & GetRDetector() const
Definition: Detector.cc:143
unsigned long long int GetRejectedReason() const
sevt::StationTriggerData & GetTriggerData()
Get Trigger data for the station.
bool HasStation(const int stationId) const
Check whether station exists.
Definition: REvent.cc:132
bool HasRecData() const
Check whether station reconstructed data exists.
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
utl::Vector GetMagneticFieldVector() const
returns the magnetic field vector from the components stored in the parameter storage ...
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
bool HasGPSData() const
Check whether GPS data object exists.
const Station & GetStation(const int stationId) const
Get station by Station Id.
Definition: RDetector.cc:141
void MakeStation(const int stationId)
make a station with specifying Id, throw if invalid stationId
Definition: REvent.cc:94
bool HasSEvent() const

, generated on Tue Sep 26 2023.