RdPolarizationReconstructor.cc
Go to the documentation of this file.
1 
10 
11 #include <fwk/CentralConfig.h>
12 #include <fwk/CoordinateSystemRegistry.h>
13 
14 #include <utl/ErrorLogger.h>
15 #include <utl/Reader.h>
16 #include <utl/config.h>
17 #include <utl/Trace.h>
18 #include <utl/TraceAlgorithm.h>
19 #include <utl/TimeStamp.h>
20 #include <utl/TimeInterval.h>
21 #include <utl/AugerUnits.h>
22 #include <utl/AugerException.h>
23 #include <utl/FFTDataContainerAlgorithm.h>
24 #include <utl/Math.h>
25 #include <utl/Vector.h>
26 #include <utl/AxialVector.h>
27 #include <utl/AugerCoordinateSystem.h>
28 #include <utl/CoordinateSystemPtr.h>
29 #include <utl/UTMPoint.h>
30 
31 #include <evt/Event.h>
32 #include <revt/REvent.h>
33 #include <revt/Header.h>
34 #include <evt/ShowerRecData.h>
35 #include <evt/ShowerSimData.h>
36 #include <evt/ShowerRRecData.h>
37 #include <evt/ShowerFRecData.h>
38 #include <evt/ShowerSRecData.h>
39 #include <revt/Channel.h>
40 
41 #include <rdet/RDetector.h>
42 #include <rdet/Station.h>
43 
44 #include <fwk/LocalCoordinateSystem.h>
45 
46 #define OUT(x) if ((x) <= fInfoLevel) cerr << " "
47 
48 using namespace revt;
49 using namespace fwk;
50 using namespace utl;
51 using std::string;
52 using std::pair;
53 using std::cerr;
54 using std::endl;
55 
56 
58 
59  //Complex const I(0.0, 1.0); // To be used as shorthand
60 
61  // This is to create a coordinate system at the Rodrigo tank.
62  // Unfortunately there is no survey of the earth magnetic field in every possible location
63  // so we have to assume that it is constant over the complete area of the observatory.
66  {
67  ReferenceEllipsoid wgs84 =
68  ReferenceEllipsoid::Get(ReferenceEllipsoid::eWGS84);
69  const CoordinateSystemPtr ecef = wgs84.GetECEF();
70 
71  const UTMPoint rodrigoOrigin(6113924.83*m, 448375.63*m, 1560.0*m, 19, 'H', wgs84);
72  return AugerBaseCoordinateSystem::Create(rodrigoOrigin, ecef);
73  }
74 
75 
76  typedef TraceV3C::SizeType SizeType; // Shorthand
77 
78 
80  RawStokesParameters::GetSliceX(SizeType pos, SizeType size)
81  {
82  return BoostVecRangeC(fSliceX, boost::numeric::ublas::range(pos, pos + size));
83  }
84 
85 
87  RawStokesParameters::GetSliceY(SizeType pos, SizeType size)
88  {
89  return BoostVecRangeC(fSliceY, boost::numeric::ublas::range(pos, pos + size));
90  }
91 
92 
93  Complex
94  RawStokesParameters::GetIndex(char channel, int index)
95  const
96  {
97  switch (channel) {
98  case 'X': return fSliceX[index];
99  case 'Y': return fSliceY[index];
100  case 'A': return fSliceA[index];
101  case 'B': return fSliceB[index];
102  case 'L': return fSliceL[index];
103  case 'R': return fSliceR[index];
104  }
105  ERROR("The channel parameters should be one of the letters in \"XYABLR\"");
106  return Complex(0,0);
107  }
108 
109 
110  // initializes the polarization data with four channels: two for the signal
111  // and two more to correct for the background noise
112  StokesParameters::StokesParameters(const BoostVecRangeC& signal_x, const BoostVecRangeC& signal_y,
113  const BoostVecRangeC& noise_x, const BoostVecRangeC& noise_y,
114  bool subtract_noise) :
115  fSignal(signal_x, signal_y),
116  fNoise(noise_x, noise_y),
117  fStokesI(subtract_noise ? fSignal.GetRawStokesI() - fNoise.GetRawStokesI() : fSignal.GetRawStokesI()),
118  fStokesQ(subtract_noise ? fSignal.GetRawStokesQ() - fNoise.GetRawStokesQ() : fSignal.GetRawStokesQ()),
119  fStokesU(subtract_noise ? fSignal.GetRawStokesU() - fNoise.GetRawStokesU() : fSignal.GetRawStokesU()),
120  fStokesV(subtract_noise ? fSignal.GetRawStokesV() - fNoise.GetRawStokesV() : fSignal.GetRawStokesV()),
121  fStokesRatioQdivI(fStokesQ/fStokesI),
122  fStokesRatioUdivI(fStokesU/fStokesI),
123  fStokesRatioVdivI(fStokesV/fStokesI)
124  { }
125 
126 
127  StokesParameters::StokesParameters(const BoostVecC& signal_x, const BoostVecC& signal_y,
128  RawStokesParameters& noise, double multiply_noise) :
129  fSignal(signal_x, signal_y),
130  fStokesI(fSignal.GetRawStokesI() - multiply_noise*noise.GetRawStokesI()),
131  fStokesQ(fSignal.GetRawStokesQ() - multiply_noise*noise.GetRawStokesQ()),
132  fStokesU(fSignal.GetRawStokesU() - multiply_noise*noise.GetRawStokesU()),
133  fStokesV(fSignal.GetRawStokesV() - multiply_noise*noise.GetRawStokesV()),
134  fStokesRatioQdivI(fStokesQ/fStokesI),
135  fStokesRatioUdivI(fStokesU/fStokesI),
136  fStokesRatioVdivI(fStokesV/fStokesI)
137  { }
138 
139 
140  // Part of inner loop in GetNoiseAdditionCovariance
141  void
142  StokesParameters::NoiseAdditionCovarianceHelper(BoostVecD& quantities, const StationRRecDataQuantities quantity_enum,
143  const StokesParameters& sliding_stokes, SizeType index)
144  {
145  switch (quantity_enum) {
146  case eStokesI:
147  quantities[index] = sliding_stokes.GetStokesI();
148  break;
149  case eStokesQ:
150  quantities[index] = sliding_stokes.GetStokesQ();
151  break;
152  case eStokesU:
153  quantities[index] = sliding_stokes.GetStokesU();
154  break;
155  case eStokesV:
156  quantities[index] = sliding_stokes.GetStokesV();
157  break;
158  case eStokesRatioQdivI:
159  quantities[index] = sliding_stokes.GetStokesRatioQdivI();
160  break;
161  case eStokesRatioUdivI:
162  quantities[index] = sliding_stokes.GetStokesRatioUdivI();
163  break;
164  case eStokesRatioVdivI:
165  quantities[index] = sliding_stokes.GetStokesRatioVdivI();
166  break;
167  case ePolarizationAngle:
168  quantities[index] = sliding_stokes.GetPolarizationAngle();
169  break;
170  default:
171  ERROR("Incorrect enum.");
172  break;
173  }
174  }
175 
176 
177  // It is assumed that the uncertainties are Gaussian. This is only approximately
178  // the case for most of the values and especially for the polarization angle this can be a
179  // problem when the values wrap through -0.5*pi and 0.5*pi. This wrapping leads to a problem
180  // when calculating the mean when the individual values are distributed around -0.5*pi and 0.5*pi.
181  // The assumption of Gaussianity becomes acceptable when the uncertainty is sufficiently small
182  // but without this subroutine, errors would be made for values close to -0.5*pi and 0.5*pi.
183  void
185  const
186  {
187  angle -= origval;
188  while (angle > kPiOnTwo)
189  angle -= kPi;
190  while (angle <= -kPiOnTwo)
191  angle += kPi;
192  angle += origval;
193  }
194 
195 
196  double
197  StokesParameters::GetNoiseAdditionCovariance(const StationRRecDataQuantities quantity_enum1,
198  const StationRRecDataQuantities quantity_enum2)
199  {
200  using namespace boost::numeric::ublas;
201  if (fNoise.GetSize() == 0) {
202  ERROR("(Co)variances can't be calculated if no noise has been provided.");
203  }
204  SizeType signal_size = fSignal.GetSize();
205  SizeType num_sliding_windows = fNoise.GetSize() - signal_size;
206  BoostVecD quantities1(num_sliding_windows);
207  BoostVecD quantities2(num_sliding_windows);
208  for (SizeType i = 0; i < num_sliding_windows; ++i) {
209  const BoostVecRangeC sliding_noise_window_x = fNoise.GetSliceX(i, signal_size);
210  const BoostVecRangeC sliding_noise_window_y = fNoise.GetSliceY(i, signal_size);
211  const BoostVecRangeC signal_x = fSignal.GetSliceX(0, signal_size);
212  const BoostVecRangeC signal_y = fSignal.GetSliceY(0, signal_size);
213  BoostVecC double_noise_signal_x = signal_x + sliding_noise_window_x;
214  BoostVecC double_noise_signal_y = signal_y + sliding_noise_window_y;
215  StokesParameters sliding_stokes(double_noise_signal_x, double_noise_signal_y, fNoise, sqrt(2));
216  NoiseAdditionCovarianceHelper(quantities1, quantity_enum1, sliding_stokes, i);
217  NoiseAdditionCovarianceHelper(quantities2, quantity_enum2, sliding_stokes, i);
218  }
219 
220  // Calculate the mean
221  double mean1 = 0;
222  double mean2 = 0;
223  for (SizeType i = 0; i < num_sliding_windows; ++i) {
224  double q1i = quantities1[i];
225  double q2i = quantities2[i];
226  if (quantity_enum1 == ePolarizationAngle) {
228  }
229  if (quantity_enum2 == ePolarizationAngle) {
231  }
232  mean1 += q1i;
233  mean2 += q2i;
234  }
235  mean1 /= num_sliding_windows;
236  mean2 /= num_sliding_windows;
237 
238  // Calculate the differences with the mean
239  for (SizeType i = 0; i < num_sliding_windows; ++i) {
240  quantities1[i] -= mean1;
241  quantities2[i] -= mean2;
242  if (quantity_enum1 == ePolarizationAngle) {
244  }
245  if (quantity_enum2 == ePolarizationAngle) {
247  }
248  }
249 
250  // Estimate the variance and return
251  return inner_prod(quantities1, quantities2) / (num_sliding_windows - 1);
252  }
253 
254 
255  // This method is about different types of covariances than the NoiseAdditionCovariance*() methods.
256  // Here we deal with the covariances between the samples for the analytic method
257  Complex
259  {
260  SizeType Ms = fSignal.GetSize();
261  // The map is used to cache already calculated values
262  // The count() method is implicitly cast to a boolean value to determine wether the channel is in the map or not
263  // Because sampleCovariances is of the type map count() can only return 0 or 1
264  // The use of this count method may seem strange but specified as such in the C++ documentation
265  if (!sampleCovariances.count(pair<char, char>(channel1, channel2))) {
266  SizeType Mn = fNoise.GetSize();
267  BoostVecC covariances(Ms);
268  for (SizeType i = 0; i < Ms; ++i) {
269  covariances[i] = Complex(0, 0);
270  for (SizeType j = 0; j < Mn - Ms; ++j) {
271  covariances[i] += fNoise.GetIndex(channel2, j) * conj(fNoise.GetIndex(channel1, j+i));
272  }
273  covariances[i] /= Mn - Ms; // not Mn - Ms - 1 because the baseline has already been substracted for the whole trace that's why we don't subtract the mean either
274  }
275  // To store the values in the map we only need to give the command below
276  // The python equivalent would be something like: sampleCovariances[channel1, channel2] = covariances
277  // But of course the next line is much more human readable in C++
278  sampleCovariances.insert(
279  pair<pair<char, char>, BoostVecC>(
280  pair<char, char>(channel1, channel2),
281  covariances
282  )
283  );
284  }
285  if (index >= Ms) {
286  ERROR("Requested index out of range.");
287  }
288  return sampleCovariances[pair<char, char>(channel1, channel2)][index];
289  }
290 
291 
292  double
294  {
295  // Values are cached in the same way as in StokesParameters::AnalyticMethodSampleCovarianceHelper()
296  if (!oneChannelPulseVariances.count(channel)) {
297  SizeType Ms = fSignal.GetSize();
298  Complex result(0.0, 0.0);
299  for (SizeType i = 0; i < Ms; ++i) {
300  for (SizeType j = 0; j < Ms; ++j) {
301  Complex Vi = fSignal.GetIndex(channel, i);
302  Complex Vjc = conj(fSignal.GetIndex(channel, j));
303  Complex Covccij = i > j ?
304  AnalyticMethodSampleCovarianceHelper(channel, channel, i-j) :
305  conj(AnalyticMethodSampleCovarianceHelper(channel, channel, j-i));
306  result += Complex(2, 0)*Vi*Vjc*Covccij;
307  }
308  }
309  oneChannelPulseVariances.insert(pair<char, double>(channel, fabs(result.real())/(Ms*Ms)));
310  }
311  return oneChannelPulseVariances[channel];
312  }
313 
314 
315  // Currently this variance helper only calculates the variances in Q, U, V, QdivI, UdivI, VdivI
316  // and the polarization angle. The covariances between these quantities are not implemented with the
317  // analytical method.
318  double
319  StokesParameters::GetAnalyticMethodVariance(const StationRRecDataQuantities quantity_enum)
320  {
321  #define VAR(x) AnalyticMethodOneChannelVarianceHelper(x)
322  #define I fStokesI
323  #define Q fStokesQ
324  #define U fStokesU
325  #define V fStokesV
326  switch (quantity_enum) {
327  default:
328  ERROR("This enum is not allowed.");
329  return std::numeric_limits<double>::infinity();
330  case eStokesI: // fall through expected: these four parameters have the same uncertainty (see GAP 2011-088)
331  case eStokesQ:
332  case eStokesU:
333  case eStokesV:
334  return VAR('X') + VAR('Y');
335  case eStokesRatioQdivI:
336  return (VAR('X')*pow((I - Q), 2) + VAR('Y')*pow((I + Q), 2))/pow(I, 4);
337  case eStokesRatioUdivI:
338  return (VAR('A')*pow((I - U), 2) + VAR('B')*pow((I + U), 2))/pow(I, 4);
339  case eStokesRatioVdivI:
340  return (VAR('L')*pow((I - V), 2) + VAR('R')*pow((I + V), 2))/pow(I, 4);
341  case ePolarizationAngle:
342  return (VAR('X') + VAR('Y'))/(4*(Q*Q)*(1 + U*U/(Q*Q)));
343  }
344  #undef VAR
345  #undef I
346  #undef Q
347  #undef U
348  #undef V
349  }
350 
351 
353  fInfoLevel(0),
354  fProjectOntoGroundPlane(1),
355  fQuadraticNoiseSubtraction(true),
356  fGeometrySource("ShowerRRecData"),
357  fErrorCalculationType("NoiseAddition"),
358  fSignalWindowStartOverride(0.0),
359  fSignalWindowStopOverride(0.0),
360  fNoiseWindowStartOverride(0.0),
361  fNoiseWindowStopOverride(0.0)
362  {
363  // The geomagnetic field for the simulations
364  // At this moment this is hardcoded here.
365  // The origin of these values can be found on
366  // the wiki page at
367  // https://www.auger.unam.mx/AugerWiki/AERA%2C_Polarization_analysis
368 
369  // First create a UTM point at the specified location of Rodrigo
370  CoordinateSystemPtr rodrigoCs(GetRodrigoCS());
371 
372  }
373 
374 
375  Vector
376  RdPolarizationReconstructor::GetArrivalDirection(const evt::Event& event)
377  const
378  {
379  if (!event.HasRecShower() && fGeometrySource.find("Rec") != string::npos)
380  ERROR("Event doesn't have a ShowerRecData object!");
381  Vector axis;
382  if (fGeometrySource == "ShowerRRecData") {
383  if (!event.GetRecShower().HasRRecShower())
384  ERROR("Event doesn't have a ShowerRRecData object!");
385  axis = event.GetRecShower().GetRRecShower().GetAxis();
386  } else if (fGeometrySource == "ShowerSRecData") {
387  if (!event.GetRecShower().HasSRecShower())
388  ERROR("Event doesn't have a ShowerSRecData object!");
389  axis = event.GetRecShower().GetSRecShower().GetAxis();
390  } else {
391  if (!event.HasSimShower())
392  ERROR("Event doesn't have a ShowerSimData object!");
393  axis = event.GetSimShower().GetDirection();
394  }
395  return -axis / axis.GetMag();
396  }
397 
398 
400  RdPolarizationReconstructor::GetCS(const evt::Event& event)
401  const
402  {
403  if (!event.HasRecShower() && fGeometrySource.find("Rec") != string::npos)
404  ERROR("Event doesn't have a ShowerRecData object!");
405  if (fGeometrySource == "ShowerRRecData") {
406  if (!event.GetRecShower().HasRRecShower())
407  ERROR("Event doesn't have a ShowerRRecData object!");
408  return LocalCoordinateSystem::Create(event.GetRecShower().GetRRecShower().GetCoordinateOrigin());
409  } else if (fGeometrySource == "ShowerSRecData") {
410  if (!event.GetRecShower().HasSRecShower())
411  ERROR("Event doesn't have a ShowerSRecData object!");
412  return LocalCoordinateSystem::Create(event.GetRecShower().GetSRecShower().GetBarycenter());
413  } else {
414  if (!event.HasSimShower())
415  ERROR("Event doesn't have a ShowerSimData object!");
416  return event.GetSimShower().GetLocalCoordinateSystem();
417  }
418  }
419 
420 
421  void
422  RdPolarizationReconstructor::GetCoreXY(const evt::Event& event,
423  const CoordinateSystemPtr& CS, double& CoreX, double& CoreY)
424  const
425  {
426  if (!event.HasRecShower() && fGeometrySource.find("Rec") != string::npos)
427  ERROR("Event doesn't have a ShowerRecData object!");
428  Point position;
429  if (fGeometrySource == "ShowerRRecData") {
430  if (!event.GetRecShower().HasRRecShower())
431  ERROR("Event doesn't have a ShowerRRecData object!");
432  position = event.GetRecShower().GetRRecShower().GetCorePosition();
433  } else if (fGeometrySource == "ShowerSRecData") {
434  if (!event.GetRecShower().HasSRecShower())
435  ERROR("Event doesn't have a ShowerSRecData object!");
436  position = event.GetRecShower().GetSRecShower().GetBarycenter();
437  } else {
438  if (!event.HasSimShower())
439  ERROR("Event doesn't have a ShowerSimData object!");
440  position = event.GetSimShower().GetPosition();
441  }
442  CoreX = position.GetX(CS);
443  CoreY = position.GetY(CS);
444  }
445 
446 
447  Point
448  RdPolarizationReconstructor::GetCore(const evt::Event& event)
449  const
450  {
451  if (!event.HasRecShower() && fGeometrySource.find("Rec") != string::npos)
452  ERROR("Event doesn't have a ShowerRecData object!");
453  if (fGeometrySource == "ShowerRRecData") {
454  if (!event.GetRecShower().HasRRecShower())
455  ERROR("Event doesn't have a ShowerRRecData object!");
456  return event.GetRecShower().GetRRecShower().GetCorePosition();
457  } else if (fGeometrySource == "ShowerSRecData") {
458  if (!event.GetRecShower().HasSRecShower())
459  ERROR("Event doesn't have a ShowerSRecData object!");
460  return event.GetRecShower().GetSRecShower().GetBarycenter();
461  } else {
462  if (!event.HasSimShower())
463  ERROR("Event doesn't have a ShowerSimData object!");
464  return event.GetSimShower().GetPosition();
465  }
466  }
467 
468 
469  Vector
470  RdPolarizationReconstructor::GetPerpVector(const Point& point, const Line& line)
471  const
472  {
473  const Vector a = point - line.GetAnchor();
474  const Vector& dir = line.GetDirection();
475  const Vector b = (dir*a)*dir;
476  const Vector perp = a - b;
477  return perp;
478  }
479 
480 
483  {
484  INFO("RdPolarizationReconstructor::Init()");
485 
486  // Read in the configurations of the xml file
487  Branch topBranch =
488  CentralConfig::GetInstance()->GetTopBranch("RdPolarizationReconstructor");
489  topBranch.GetChild("QuadraticNoiseSubtraction").GetData(fQuadraticNoiseSubtraction);
490  topBranch.GetChild("ProjectOntoGroundPlane").GetData(fProjectOntoGroundPlane);
491  topBranch.GetChild("AssumeGroundPlaneIsHorizontalAndFlat").GetData(fAssumeGroundPlaneIsHorizontalAndFlat);
492  topBranch.GetChild("InfoLevel").GetData(fInfoLevel);
493  topBranch.GetChild("GeometrySource").GetData(fGeometrySource);
494  topBranch.GetChild("ErrorCalculationType").GetData(fErrorCalculationType);
495  topBranch.GetChild("SignalWindowStartOverride").GetData(fSignalWindowStartOverride);
496  topBranch.GetChild("SignalWindowStopOverride").GetData(fSignalWindowStopOverride);
497  topBranch.GetChild("NoiseWindowStartOverride").GetData(fNoiseWindowStartOverride);
498  topBranch.GetChild("NoiseWindowStopOverride").GetData(fNoiseWindowStopOverride);
499 
500  return eSuccess;
501  }
502 
503 
505  RdPolarizationReconstructor::Run(evt::Event& event)
506  {
507  INFO("RdPolarizationReconstructor::Run()");
508 
509  // Check wether there are events at all
510  if (!event.HasREvent()) {
511  WARNING("No radio event found!");
512  return eContinueLoop;
513  }
514 
515  // The rdet::RDetector object is needed to retrieve the coordinate system that corresponds
516  // to the StationTimeSeries instance. These lines have to be removed when the appropriate
517  // functionality has been incorporated in the StationTimeSeries.
518  REvent& rEvent = event.GetREvent();
519  const rdet::RDetector& rDetector = det::Detector::GetInstance().GetRDetector();
520 
522  sIt != rEvent.SignalStationsEnd(); ++sIt) {
523 
524  // Creating the analytic signal
525  StationFFTDataContainer eFieldDataImag = sIt->GetFFTDataContainer();
526  FFTDataContainerAlgorithm::HilbertTransform(eFieldDataImag);
527  const StationTimeSeries &TimeSeriesReal = sIt->GetFFTDataContainer().GetConstTimeSeries();
528  const StationTimeSeries &TimeSeriesImag = eFieldDataImag.GetConstTimeSeries();
529  TraceV3C analyticSignal;
530  for (unsigned int i = 0; i < TimeSeriesReal.GetSize(); ++i) {
531  Vector3C c;
532  c[0] = Complex(TimeSeriesReal[i][0], TimeSeriesImag[i][0]);
533  c[1] = Complex(TimeSeriesReal[i][1], TimeSeriesImag[i][1]);
534  c[2] = Complex(TimeSeriesReal[i][2], TimeSeriesImag[i][2]);
535  analyticSignal.PushBack(c);
536  }
537 
538  SizeType size = analyticSignal.GetSize();
539  // the 3D time series need to be translated to a 2D signal that is perpendicular
540  // to the Poynting-vector (= arrival-direction) of the pulse
541  BoostVecC traceX(size);
542  BoostVecC traceY(size);
543  double observerAngle;
544  double alpha;
545  double chxfraction;
546  // traceX and traceY will be filled with the rotated complex electric field
547  GetRotatedPolarizationTraces(event, *sIt, rDetector, analyticSignal, traceX, traceY,
548  observerAngle, alpha);
549  // stokes parameters are calculated from traceX and traceY using the RecData signal window and noise window
550  CalculateAndFillStokesParameters(*sIt, traceX, traceY, observerAngle, alpha);
551  // Charge excess relative contribution "a"
552  CalculateAndFillChargeExcessFraction(*sIt, alpha, chxfraction);
553 
554  }
555  return eSuccess;
556  }
557 
558 
559  // This method generates two traces that are rotated to the appropriate coordinate system
560  // for further polarization analysis. An explicit coordinate transformation is necessary
561  // because we need to go to a two dimensional system that is perpendicular to the Poynting vector
562  // (The Poynting vector is approximated by the arrival direction)
563  // NOTE: If in the future something more elaborate than a plane fit is done then this code
564  // needs to be modified with a better approximation of the Poynting vector
565  void
566  RdPolarizationReconstructor::GetRotatedPolarizationTraces(const evt::Event& event, const Station& station,
567  const rdet::RDetector& rDetector, const TraceV3C& analyticSignal,
568  BoostVecC& traceX, BoostVecC& traceY, double& observerAngle,
569  double& alpha)
570  const
571  {
572  CoordinateSystemPtr CS = GetCS(event);
573  // The components of the electric field are now in a vector that has a coordinate frame
574  // associated to it
575 
576  // Get the arrival direction and normalize to make sure it has length one
577  // (which should be the case at this moment but with new definitions this
578  // may not be the case any more)
579  Vector arrivalDirection = GetArrivalDirection(event);
580 
581  OUT(3) << "Event: " << event.GetREvent().GetHeader().GetId() << " Station: " << station.GetId() << endl;
582  OUT(3) << "arrivalDirection = " << arrivalDirection.GetX(CS) << " " << arrivalDirection.GetY(CS) << " " << arrivalDirection.GetZ(CS) << endl;
583 
584  arrivalDirection /= arrivalDirection.GetMag();
585  //magnetic field vector
586  utl::Vector bfield = event.GetRecShower().GetRRecShower().GetMagneticFieldVector();
587  // Calculate the basis vectors for the vxB frame
588  // So the X direction is defined as -1*-vxB
589  AxialVector baseVectorX = Cross(arrivalDirection, bfield/bfield.GetMag());
590 
591  OUT(3) << "bfield = " << bfield.GetX(CS) << " " << bfield.GetY(CS) << " " << bfield.GetZ(CS) << endl;
592  OUT(3) << "-vxB (normalized v and B) = " << -baseVectorX.GetX(CS) << " " << -baseVectorX.GetY(CS) << " " << -baseVectorX.GetZ(CS) << endl;
593 
594  baseVectorX /= baseVectorX.GetMag(); // baseVectorX now holds vxB (normalized)
595  AxialVector baseVectorY = Cross(arrivalDirection, baseVectorX);
596  baseVectorY /= baseVectorY.GetMag(); // baseVectorY is chosen perpendicular to she shower axis
597  // baseVectorX, baseVectorY and a Z vector along the arrival direction now constitute the
598  // vxB coordinate frame
599 
600  // If ProjectOntoGroundPlane == 1 then Calculate the pojection of vxB
601  // onto the ground plane and produce a different coordinate system
602  // where baseVectorX and baseVectorY lie on the ground plane
604  AxialVector projectedVectorX(baseVectorX.GetX(CS), baseVectorX.GetY(CS), 0, CS);
605  AxialVector projectedVectorY(-baseVectorX.GetY(CS), baseVectorX.GetX(CS), 0, CS);
606  projectedVectorX /= projectedVectorX.GetMag();
607  projectedVectorY /= projectedVectorY.GetMag();
608  baseVectorX = projectedVectorX;
609  baseVectorY = projectedVectorY;
610  OUT(3) << "projected -vxB (normalized v and B) = " << -baseVectorX.GetX(CS) << " " << -baseVectorX.GetY(CS) << " " << -baseVectorX.GetZ(CS) << endl;
611  }
612 
613  // Get the core position
614  Point core = GetCore(event);
615 
616  // Get the station position
617  Point stationPos = rDetector.GetStation(station).GetPosition();
618 
619  // Set the station Z position to the same value as the core Z position
620  // if AssumeGroundPlaneIsHorizontalAndFlat is 1 in the settings
622  stationPos = Point(stationPos.GetX(CS), stationPos.GetY(CS), core.GetZ(CS), CS);
623  }
624 
625  // Calculate the vector with length 1 that is perpendicular to the shower axis
626  // and points to the station
627  Vector vectorPointingToStation;
629  // Most general behavior
630  vectorPointingToStation = GetPerpVector(stationPos, Line(core, arrivalDirection));
631  } else {
632  // Calculations for the projected case
633  // In this case vectorPointingToStation is not really a perpendictular vector.
634  // It is the vector that points from the shower core to the station
635  Vector coreProj(core.GetX(CS), core.GetY(CS), 0, CS);
636  Vector stationProj(stationPos.GetX(CS), stationPos.GetY(CS), 0, CS);
637  vectorPointingToStation = stationProj - coreProj;
638  }
639  vectorPointingToStation /= vectorPointingToStation.GetMag();
640 
641  // Determine the opening angle between the shower axis and the geomagnetic field
642  alpha = Angle(arrivalDirection, bfield/bfield.GetMag());
643  // // Use the full coordinate frame to allow the angle to run from 0 to 2pi
644  // if (Cross(arrivalDirection, bfield).GetZ(CS) < 0) {
645  // alpha = 2*kPi - alpha;
646  // }
647 
648  // Determine the observer angle in the vxB frame
649  observerAngle = Angle(baseVectorX, vectorPointingToStation);
650 
651  OUT(3) << "" << endl;
652  OUT(3) << "baseVectorX = " << baseVectorX.GetX(CS) << " " << baseVectorX.GetY(CS) << " " << baseVectorX.GetZ(CS) << endl;
653  OUT(3) << "baseVectorY = " << baseVectorY.GetX(CS) << " " << baseVectorY.GetY(CS) << " " << baseVectorY.GetZ(CS) << endl;
654  OUT(3) << "vectorPointingToStation = " << vectorPointingToStation.GetX(CS) << " " << vectorPointingToStation.GetY(CS) << " " << vectorPointingToStation.GetZ(CS) << endl;
655  OUT(3) << "observerAngle = " << observerAngle << endl;
656 
657  // Use the full coordinate frame to allow the angle to run from 0 to 2pi
658  if (baseVectorY * vectorPointingToStation < 0) {
659  observerAngle = 2*kPi - observerAngle;
660  }
661 
662  OUT(3) << "observerAngle in [0, 2*Pi) = " << observerAngle << endl;
663 
664  for (SizeType i = 0; i != analyticSignal.GetSize(); ++i) {
665  Vector3C electricField3C = analyticSignal[i];
666 
667  Vector electricFieldVectorRe(electricField3C[0].real(), electricField3C[1].real(), electricField3C[2].real(), CS);
668  Vector electricFieldVectorIm(electricField3C[0].imag(), electricField3C[1].imag(), electricField3C[2].imag(), CS);
669 
670  double electricFieldXRe = electricFieldVectorRe*baseVectorX;
671  double electricFieldYRe = electricFieldVectorRe*baseVectorY;
672  double electricFieldXIm = electricFieldVectorIm*baseVectorX;
673  double electricFieldYIm = electricFieldVectorIm*baseVectorY;
674  // electricFieldX and electricFieldY are now the components perpendicular to the
675  // Poynting vector which is approximated by the arrival direction. electricFieldX
676  // is parallel to vxB. electricFieldY is perpendicular to vxB and the arrival direction.
677  traceX[i] = Complex(electricFieldXRe, electricFieldXIm);
678  traceY[i] = Complex(electricFieldYRe, electricFieldYIm);
679  }
680  }
681 
682 
683  void
684  RdPolarizationReconstructor::CheckSignalAndNoiseRanges(SizeType signal_start_bin, SizeType signal_stop_bin,
685  SizeType noise_start_bin, SizeType noise_stop_bin, SizeType size)
686  const
687  {
688  OUT(2) << "Ranges for extracting polarization information:" << endl;
689  OUT(2) << " - signal range = [" << signal_start_bin << ", " << signal_stop_bin << ") samples" << endl;
690  OUT(2) << " - noise range = [" << noise_start_bin << ", " << noise_stop_bin << ") samples" << endl;
691 
692  if (signal_start_bin > size)
693  ERROR("signal_start_bin out of bounds.");
694  if (signal_stop_bin > size)
695  ERROR("signal_stop_bin out of bounds.");
696  if (noise_start_bin > size)
697  ERROR("noise_start_bin out of bounds.");
698  if (noise_stop_bin > size)
699  ERROR("noise_stop_bin out of bounds.");
700  if (signal_start_bin >= signal_stop_bin)
701  ERROR("invalid values: can't allow: signal_start_bin >= signal_stop_bin");
702  if (noise_start_bin >= noise_stop_bin)
703  ERROR("invalid values: can't allow: noise_start_bin >= noise_top_bin");
704  if (signal_stop_bin - signal_start_bin > noise_stop_bin - noise_start_bin)
705  ERROR("the signal region should not be larger than the noise region");
706  if (((noise_start_bin >= signal_start_bin) && (noise_start_bin < signal_stop_bin)) ||
707  ((noise_stop_bin >= signal_start_bin) && (noise_stop_bin < signal_stop_bin)) ||
708  ((noise_start_bin <= signal_start_bin) && (noise_stop_bin > signal_stop_bin)))
709  ERROR("the signal and noise regions may not overlap");
710  if ((signal_stop_bin - signal_start_bin)*5 > noise_stop_bin - noise_start_bin)
711  WARNING("for accurate error determination the signal region should be much smaller than the noise region");
712  }
713 
714 
715  void
716  RdPolarizationReconstructor::CalculateAndFillStokesParameters(Station& station, BoostVecC& traceX,
717  BoostVecC& traceY, double observerAngle, double alpha)
718  {
719  using namespace boost::numeric::ublas;
720  double binning = station.GetStationTimeSeries().GetBinning();
721  SizeType total_size = station.GetStationTimeSeries().GetSize();
722  // Use start and stop times from StationRecData
723 
724  double signal_start_time = fSignalWindowStartOverride == 0.0 ?
725  station.GetRecData().GetParameter(eSignalWindowStart) : fSignalWindowStartOverride;
726  double signal_stop_time = fSignalWindowStopOverride == 0.0 ?
727  station.GetRecData().GetParameter(eSignalWindowStop) : fSignalWindowStopOverride;
728  double noise_start_time = fNoiseWindowStartOverride == 0.0 ?
729  station.GetRecData().GetParameter(eNoiseWindowStart) : fNoiseWindowStartOverride;
730  double noise_stop_time = fNoiseWindowStopOverride == 0.0 ?
731  station.GetRecData().GetParameter(eNoiseWindowStop) : fNoiseWindowStopOverride;
732  // translate the times to bins
733 
734  OUT(3) << "signal_start_time = " << signal_start_time/ns << " ns" << endl;
735  OUT(3) << "signal_stop_time = " << signal_stop_time/ns << " ns" << endl;
736  OUT(3) << "noise_start_time = " << noise_start_time/ns << " ns" << endl;
737  OUT(3) << "noise_stop_time = " << noise_stop_time/ns << " ns" << endl;
738  OUT(3) << "binning = " << binning/ns << " ns" << endl;
739 
740  SizeType signal_start_bin = round(signal_start_time / binning);
741  SizeType signal_stop_bin = round(signal_stop_time / binning);
742  SizeType noise_start_bin = round(noise_start_time / binning);
743  SizeType noise_stop_bin = round(noise_stop_time / binning);
744  // test wether the start and stop times contain decent values
745  CheckSignalAndNoiseRanges(signal_start_bin, signal_stop_bin, noise_start_bin, noise_stop_bin, total_size);
746  // cut out the signal and the noise region from the trace
747  BoostVecRangeC signal_x(traceX, range(signal_start_bin, signal_stop_bin));
748  BoostVecRangeC signal_y(traceY, range(signal_start_bin, signal_stop_bin));
749  BoostVecRangeC noise_x(traceX, range(noise_start_bin, noise_stop_bin));
750  BoostVecRangeC noise_y(traceY, range(noise_start_bin, noise_stop_bin));
751 
752  // here the stokes parameters are calculated
753  StokesParameters stokes(signal_x, signal_y, noise_x, noise_y, fQuadraticNoiseSubtraction);
754  // the stokes parameters are filled into the reconstruction data structure here
755  StationRecData &recData(station.GetRecData());
756  recData.SetParameter(eStokesI, stokes.GetStokesI());
757  recData.SetParameter(eStokesQ, stokes.GetStokesQ());
758  recData.SetParameter(eStokesU, stokes.GetStokesU());
759  recData.SetParameter(eStokesV, stokes.GetStokesV());
760  recData.SetParameter(eStokesRatioQdivI, stokes.GetStokesRatioQdivI());
761  recData.SetParameter(eStokesRatioUdivI, stokes.GetStokesRatioUdivI());
762  recData.SetParameter(eStokesRatioVdivI, stokes.GetStokesRatioVdivI());
763  recData.SetParameter(ePolarizationAngle, stokes.GetPolarizationAngle());
764 
765  recData.SetParameter(eObserverAngle, observerAngle);
766  recData.SetParameter(eAlpha, alpha);
767 
768  // the errors, i.e. variances and covariances for the stokes parameters are filled here
769  // if requested by the configuration
770  StationRRecDataQuantities quantities1[8] = {
771  eStokesI,
772  eStokesQ,
773  eStokesU,
774  eStokesV,
775  eStokesRatioQdivI,
776  eStokesRatioUdivI,
777  eStokesRatioVdivI,
778  ePolarizationAngle
779  };
780  if (fErrorCalculationType == "NoiseAddition") {
781  for (int i = 0; i < 8; ++i) {
782  for (int j = i; j < 8; ++j) {
783  StationRRecDataQuantities ei = quantities1[i];
784  StationRRecDataQuantities ej = quantities1[j];
785  recData.SetParameterCovariance(ei, ej, stokes.GetNoiseAdditionCovariance(ei, ej));
786  }
787  }
788  }
789  // The analytical calculation only sets the variances, no covariances are calculated
790  if (fErrorCalculationType == "Analytical") {
791  for (int i = 0; i < 8; ++i) {
792  StationRRecDataQuantities ei = quantities1[i];
793  recData.SetParameterCovariance(ei, ei, stokes.GetAnalyticMethodVariance(ei));
794  }
795  }
796  }
797 
798 
799  void
800  RdPolarizationReconstructor::CalculateAndFillChargeExcessFraction(Station& station, double& alpha, double& chxfraction)
801  {
802  // Get the polarization Angle and Observer Angle
803  double polAngle = station.GetRecData().GetParameter(ePolarizationAngle);
804  double obsAngle = station.GetRecData().GetParameter(eObserverAngle);
805 
806  // Calculate "a" using polarization angle as function of the observer angle
807  chxfraction = (sin(alpha) * tan(polAngle)) / (sin(obsAngle) - cos(obsAngle)*tan(polAngle));
808 
809  // Estimate lower-limit uncertainty, approximation but agrees with MC though
810  double polAngErr = station.GetRecData().GetParameterError(ePolarizationAngle);
811  double chxFracError = abs((sin(alpha)*tan(polAngle + polAngErr))/(sin(obsAngle) - cos(obsAngle)*tan(polAngle + polAngErr)) - (sin(alpha)*tan(polAngle - polAngErr))/(sin(obsAngle) - cos(obsAngle)*tan(polAngle - polAngErr)))/2;
812 
813  // Set Parameters
814  StationRecData &recData(station.GetRecData());
815  recData.SetParameter(eCxxFraction, chxfraction);
816  recData.SetParameterError(eCxxFraction, chxFracError);
817  }
818 
819 
821  RdPolarizationReconstructor::Finish()
822  {
823  INFO("RdPolarizationReconstructor::Finish()");
824 
825  return eSuccess;
826  }
827 
828 }
Branch GetTopBranch() const
Definition: Branch.cc:63
AxialVector Cross(const Vector &l, const Vector &r)
Definition: OperationsAV.h:25
Class to access station level reconstructed data.
void GetRotatedPolarizationTraces(const evt::Event &event, const revt::Station &station, const rdet::RDetector &rDetector, const utl::TraceV3C &stationTimeSeries, BoostVecC &traceX, BoostVecC &traceY, double &observerAngle, double &alpha) const
Point object.
Definition: Point.h:32
double Angle(const double theta1, const double phi1, const double theta2, const double phi2)
boost::numeric::ublas::vector< double > BoostVecD
void CalculateAndFillStokesParameters(revt::Station &station, BoostVecC &traceX, BoostVecC &traceY, double observerAngle, double alpha)
void NoiseAdditionCovariancePolarizationAngleHelper(double &angle, double origval) const
Report success to RunController.
Definition: VModule.h:62
const Complex I(0.0, 1.0)
double GetNoiseAdditionCovariance(const revt::StationRRecDataQuantities, revt::StationRRecDataQuantities)
StationRecData & GetRecData()
Get station level reconstructed data.
bool HasRecShower() const
Interface class to access to the Radio part of an event.
Definition: REvent.h:42
Class to hold and convert a point in geodetic coordinates.
Definition: UTMPoint.h:40
Skip remaining modules in the current loop and continue with next iteration of the loop...
Definition: VModule.h:68
ShowerRecData & GetRecShower()
bool HasSimShower() const
double GetAnalyticMethodVariance(const revt::StationRRecDataQuantities)
double GetParameterError(const Parameter i) const
double GetBinning() const
size of one slot
Definition: Trace.h:138
double GetMag() const
Definition: AxialVector.h:56
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void Init()
Initialise the registry.
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)
bool HasREvent() const
double GetMag() const
Definition: Vector.h:58
ShowerRRecData & GetRRecShower()
StationTimeSeries & GetStationTimeSeries()
retrieve Station Time Series (write access, only use this if you intend to change the data) ...
ShowerSRecData & GetSRecShower()
#define U
Detector description interface for RDetector-related data.
Definition: RDetector.h:46
#define V
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
Class representing a document branch.
Definition: Branch.h:107
std::complex< double > Complex
Definition: fftw++.h:83
utl::Point GetCoordinateOrigin() const
class to hold data at the radio Station level.
Reference ellipsoids for UTM transformations.
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
std::vector< T >::size_type SizeType
Definition: Trace.h:58
utl::Vector GetPerpVector(const utl::Point &point, const utl::Line &line) const
const double ns
boost::numeric::ublas::vector< Complex > BoostVecC
Static (small and dense) vector class.
Definition: SVector.h:33
constexpr double kPi
Definition: MathConstants.h:24
double abs(const SVector< n, T > &v)
const Data result[]
void CalculateAndFillChargeExcessFraction(revt::Station &station, double &alpha, double &chxfraction)
bool HasRRecShower() const
const utl::Point & GetBarycenter() const
constexpr double kPiOnTwo
Definition: MathConstants.h:25
void NoiseAdditionCovarianceHelper(BoostVecD &quanities, const revt::StationRRecDataQuantities quantity_enum, const StokesParameters &sliding_stokes, SizeT index)
SizeType GetSize() const
Definition: Trace.h:156
const CoordinateSystemPtr GetECEF() const
Get the ECEF.
utl::Vector GetArrivalDirection(const evt::Event &event) const
#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
Complex AnalyticMethodSampleCovarianceHelper(char channel1, char channel2, SizeT index)
int GetId() const
Get the station Id.
void CheckSignalAndNoiseRanges(SizeT signal_start_bin, SizeT signal_stop_bin, SizeT noise_start_bin, SizeT noise_stop_bin, SizeT size) const
double GetParameter(const Parameter i) const
utl::CoordinateSystemPtr GetCS(const evt::Event &event) const
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
Template class for a data container that offers and takes both time series and corresponding frequenc...
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
StokesParameters(const BoostVecRangeC &signal_x, const BoostVecRangeC &signal_y, const BoostVecRangeC &noise_x, const BoostVecRangeC &noise_y, bool subtract_noise)
Template class for a FADC data or calibrated data container. Use the typedefs (TraceD, TraceI, etc.) defined in Trace-fwd.h.
Definition: Trace-fwd.h:19
boost::numeric::ublas::vector_range< BoostVecC > BoostVecRangeC
void SetParameter(Parameter i, double value, bool lock=true)
Vector object.
Definition: Vector.h:30
const Vector & GetDirection() const
Definition: Line.h:22
AxialVector object.
Definition: AxialVector.h:30
utl::CoordinateSystemPtr Get(const std::string &id)
Get a well-known Coordinate System.
#define OUT(x)
SignalStationIterator SignalStationsEnd()
Definition: REvent.h:114
const Point & GetAnchor() const
Definition: Line.h:21
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
#define VAR(x)
utl::Point GetPosition() const
Tank position in Site Cartesian Coordinates.
void PushBack(const T &value)
Insert a single value at the end.
Definition: Trace.h:119
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
const Station & GetStation(const int stationId) const
Get station by Station Id.
Definition: RDetector.cc:141
bool HasSRecShower() const
Definition: Line.h:17
boost::filter_iterator< SignalStationFilter, AllStationIterator > SignalStationIterator
Iterator over all signal stations.
Definition: REvent.h:109
#define Q
SignalStationIterator SignalStationsBegin()
Definition: REvent.h:112

, generated on Tue Sep 26 2023.