AnalysisReco.cxx
1 #include "AnalysisReco.h"
2 #include "InterferometricMap.h"
3 #include "InterferometryCache.h"
4 #include "AcclaimFilters.h"
5 #include "ResponseManager.h"
6 #include "NoiseMonitor.h"
7 #include <numeric>
8 #include "RootTools.h"
9 #include "TGraphInteractive.h"
10 #include "ImpulsivityMeasure.h"
11 #include "TPaveText.h"
12 
13 ClassImp(Acclaim::AnalysisReco);
14 
15 
16 
22 }
23 
24 
29 
30  if(fSpawnedCrossCorrelator && (fCrossCorr != nullptr)){
31  delete fCrossCorr;
32  fCrossCorr = nullptr;
33  }
34  nicelyDeleteInternalFilteredEvents();
35 }
36 
37 
39  if(fEvMin != nullptr){
40  delete fEvMin;
41  fEvMin = nullptr;
42  }
43  if(fEvMinDeco != nullptr){
44  delete fEvMinDeco;
45  fEvMinDeco = nullptr;
46  }
47  if(fEvDeco != nullptr){
48  delete fEvDeco;
49  fEvDeco = nullptr;
50  }
51 }
52 
53 
54 
55 
58  const FilteredAnitaEvent* fEv,
59  AnalysisWaveform** waveStore,
61  NoiseMonitor* noiseMonitor,
62  std::vector<double>& I,
63  std::vector<double>& Q,
64  std::vector<double>& U,
65  std::vector<double>& V) {
66 
67 
69  // Double_t snr; ///Signal to Noise of waveform
70  // Double_t peakHilbert; /// peak of hilbert envelope
71  // Double_t peakVal; /// peak value
72  // Double_t xPolPeakVal; // Peak of xpol trace
73  // Double_t xPolPeakHilbert; // Peak of xpol hilbert Envelope
74 
75  // Double_t I,Q,U,V; // Stokes Parameters
76 
77  // Double_t totalPower; ///Total power in waveform
78  // Double_t totalPowerXpol; ///Total power in xPol waveform
79 
80  Int_t peakPhiSector = h->getPeakPhiSector();
81  const std::vector<Int_t>& theAnts = phiSectorToCoherentAnts(peakPhiSector);
82 
83  Double_t peak, phiDeg, thetaDeg;
84  h->getPeakInfo(peak, phiDeg, thetaDeg);
85  Double_t largestPeakToPeak = 0;
86  AnalysisWaveform* coherentWave = coherentlySum(fEv, pol, theAnts, phiDeg, thetaDeg, &largestPeakToPeak);
87 
88  // Internal storage
89  if(waveStore[0] != nullptr){
90  delete waveStore[0];
91  }
92  waveStore[0] = coherentWave;
93 
94  info.snr = 0;
95  {
96  double noise = 0;
97  for(int ant : theAnts){
98  double thisRMS = 0;
99  if(noiseMonitor != nullptr){
100  thisRMS = noiseMonitor->getRMS(pol, ant, fEv->getHeader()->realTime);
101  }
102  else{
103  static int warnCount = 0;
104  const TGraphAligned* gr = fEv->getFilteredGraph(ant, pol)->even();
105  thisRMS = gr->GetRMS(2);
106  const int numWarnings = 10;
107  if(warnCount < numWarnings){
108  std::cerr << "Warning ("<< warnCount + 1 << "/" << numWarnings << ") in "
109  << __PRETTY_FUNCTION__ << ", getting RMS from entire waveform rather than NoiseMonitor."
110  << " this many overestimate the noise... thisRMS = " << thisRMS << std::endl;
111  warnCount++;
112  }
113  }
114  noise += thisRMS;
115 
116  }
117  noise /= theAnts.size();
118 
119  info.snr = largestPeakToPeak/(2*noise);
120 
121  // std::cout << "SNR = " << info.snr << std::endl;
122  }
123 
124 
125  const TGraphAligned* grHilbert = coherentWave->hilbertEnvelope();
126  info.peakHilbert = TMath::MaxElement(grHilbert->GetN(), grHilbert->GetY());
127 
128  const TGraphAligned* gr = coherentWave->even();
129  info.peakVal = TMath::MaxElement(gr->GetN(), gr->GetY());
130 
131  AnitaPol::AnitaPol_t xPol = RootTools::swapPol(pol);
132  Double_t largestPeakToPeakXPol = 0;
133  AnalysisWaveform* xPolCoherentWave = coherentlySum(fEv, xPol, theAnts, phiDeg, thetaDeg, &largestPeakToPeakXPol, &gr->GetX()[0]); // cross polarisation
134 
135  // Internal storage
136  if(waveStore[1] != nullptr){
137  delete waveStore[1];
138  }
139  waveStore[1] = xPolCoherentWave;
140 
141  const TGraphAligned* grHilbertX = xPolCoherentWave->hilbertEnvelope();
142  info.xPolPeakHilbert = TMath::MaxElement(grHilbertX->GetN(), grHilbertX->GetY());
143 
144  const TGraphAligned* grX = xPolCoherentWave->even();
145  info.xPolPeakVal = TMath::MaxElement(grX->GetN(), grX->GetY());
146 
147  const AnalysisWaveform* hWave = pol == AnitaPol::kHorizontal ? coherentWave : xPolCoherentWave;
148  const AnalysisWaveform* vWave = pol == AnitaPol::kHorizontal ? xPolCoherentWave : coherentWave;
149 
150  const TGraphAligned* grV = vWave->even();
151  const TGraphAligned* grH = hWave->even();
152 
153  const TGraphAligned* grV_hilbert = vWave->hilbertTransform()->even();
154  const TGraphAligned* grH_hilbert = hWave->hilbertTransform()->even();
155 
156  // Stokes params (I,Q,U,V) - from the wikipedia https://en.wikipedia.org/wiki/Stokes_parameters#Examples
157  // (1, 1, 0, 0) HPol linearly polarised
158  // (1, -1, 0, 0) VPol linearly polarised
159  // (1, 0, 1, 0) +45 deg linearly polarised
160  // (1, 0, -1, 0) -45 deg linearly polarised
161  // (1, 0, 0, 1) Right hand circularaly polarised
162  // (1, 0, 0, -1) Left hand circularaly polarised
163  // (1, 0, 0, 0) Unpolarised
164 
165  FFTtools::stokesParameters(grH->GetN(),
166  grH->GetY(), grH_hilbert->GetY(),
167  grV->GetY(), grV_hilbert->GetY(),
168  &info.I, &info.Q, &info.U, &info.V,
169  &info.max_dI, &info.max_dQ,&info.max_dU,&info.max_dV,
170  true);
171 
172 
173  if(fInstantaneousStokes > 0){
174 
175  I.resize(grH->GetN());
176  Q.resize(grH->GetN());
177  U.resize(grH->GetN());
178  V.resize(grH->GetN());
179 
180  FFTtools::stokesParameters(grH->GetN(),
181  grH->GetY(), grH_hilbert->GetY(),
182  grV->GetY(), grV_hilbert->GetY(),
183  &info.I, &info.Q, &info.U, &info.V,
184  I.data(), Q.data(), U.data(), V.data(),
185  false);
186  }
187 
188 
189 
190 
191  info.totalPower = RootTools::getTimeIntegratedPower(coherentWave->even());
192  info.totalPowerXpol = RootTools::getTimeIntegratedPower(xPolCoherentWave->even());
193 
194  // //Shape parameters, computed using hilbert envelope
195  // // This should probably taken out into its own class
196  // Double_t riseTime_10_90; /// Rise time of hilbert env from 10% to 90% of peak
197  // Double_t riseTime_10_50; /// Rise time of hilbert env from 10% to 50% of peak
198  // Double_t fallTime_90_10; /// Fall time of hilbert env from 90% to 10% of peak
199  // Double_t fallTime_50_10; /// Fall time of hilbert env from 50% to 10% of peak
200  // Double_t width_50_50; /// Width from first envelope crossing of 50 percent of peak to last
201  // Double_t width_10_10; /// Width from first envelope crossing of 10 percent of peak to last
202  // Double_t power_10_10; /// Power enclosed within 10_10 width
203  // Double_t power_50_50; /// Power enclosed within 50_50 width
204  // Double_t peakTime; // Time that peak hilbert env occurs
205  // Double_t peakMoments[5]; // moments about Peak (1st - 5th moments)
206 
207  int maxIndex = std::find(grHilbert->GetY(), grHilbert->GetY() + grHilbert->GetN(), info.peakHilbert) - grHilbert->GetY();
208  if(maxIndex >= grHilbert->GetN()){
209  std::cerr << "Error in " << __PRETTY_FUNCTION__
210  << ", unable to find time of Hilbert envelope peak using std::find()."
211  << "peakHilbert = " << info.peakHilbert << ", numPoints = " << grHilbert->GetN()
212  << ", maxIndex = " << maxIndex << std::endl;
213  }
214  info.peakTime = grHilbert->GetX()[maxIndex];
215 
216  grHilbert->getMoments(sizeof(info.peakMoments)/sizeof(double), info.peakTime, info.peakMoments);
217 
218  // set impulsivity measure defined in AnitaAnalysisSummary
219  info.impulsivityMeasure = impulsivity::impulsivityMeasure(coherentWave, nullptr, maxIndex, true);
220 
221  for(int w=0; w < AnitaEventSummary::numFracPowerWindows; w++){
222  const double powerFraction = (w+1)*0.1;
223  std::pair<double, double> window = RootTools::findSmallestWindowContainingFracOfPower(grHilbert, powerFraction);
224  // info.narrowestWidths[w] = window.second - window.first;
225  info.fracPowerWindowBegins[w] = window.first;
226  info.fracPowerWindowEnds[w] = window.second;
227  }
228 
230  // //spectrum info
231  // Double_t bandwidth[peaksPerSpectrum]; /// bandwidth of each peak (implementation defined, may not be comparable between analyses)
232  // Double_t peakFrequency[peaksPerSpectrum]; //peak frequency of power spectrum
233  // Double_t peakPower[peaksPerSpectrum]; //power within +/- bandwidth of each peak
234  // Double_t spectrumSlope; /// Slope of line fit to spectrum (in log-space, so this is spectral-index)
235  // Double_t spectrumIntercept; /// Intercept of line fit to spectrum (in log-space)
236 
237  // we have interpolated the coherently summed waveform, probably significantly to extract useful information
238  // from the time domain. Therefore there's a bunch of trailing high frequency crap that I want to ignore
239  // The maximum useful frequency is the nominal sampling
240 
241  if(fFillSpectrumInfo != 0){
242  const double maxFreqIfIHadNotIntepolated = FancyFFTs::getNumFreqs(NUM_SAMP)*(1./(NOMINAL_SAMPLING_DELTAT*NUM_SAMP));
243  const double df = coherentWave->deltaF(); // the actual deltaF
244  int numGoodFreqBins = floor(maxFreqIfIHadNotIntepolated/df);
245 
246  // std::cout << maxFreq << std::endl;
247  const TGraphAligned* grPow = coherentWave->power();
248 
249  if(numGoodFreqBins > grPow->GetN()){
250  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " for run " << fCurrentRun << ", eventNumber " << fCurrentEventNumber
251  << ", expected at least " << numGoodFreqBins << " frequency bins, only got " << grPow->GetN()
252  << ". Did you downsample the coherently summed waveform?" << std::endl;
253  numGoodFreqBins = grPow->GetN();
254  }
255 
256  TGraph grMaxima;
257  for(int i=1; i < numGoodFreqBins-1; i++){
258  if(grPow->GetY()[i] > grPow->GetY()[i-i] && grPow->GetY()[i] > grPow->GetY()[i+i] ){
259  grMaxima.SetPoint(grMaxima.GetN(), grPow->GetX()[i], grPow->GetY()[i]);
260  }
261 
262  // This check should be redundent now, but won't hurt to leave it in...
263  if(grPow->GetX()[i] >= maxFreqIfIHadNotIntepolated){
264  break;
265  }
266  }
267 
268  // Sort my collection of local maxima,
269  // The second argument, false, means sort the local maxima in decreasing order (i.e. biggest first)
270  grMaxima.Sort(TGraph::CompareY, false);
271 
272  // Put the N largest local maxima into the AnitaEventSummary::WaveformInfo
273  for(int i=0; i < AnitaEventSummary::peaksPerSpectrum; i++){
274  if(i < grMaxima.GetN()){
275  info.bandwidth[i] = 0; // for now, let's just try the peak value and frequency
276  info.peakPower[i] = grMaxima.GetY()[i];
277  info.peakFrequency[i] = grMaxima.GetX()[i];
278  }
279  else{
280  info.bandwidth[i] = 0;
281  info.peakPower[i] = 0;
282  info.peakFrequency[i] = 0;
283  }
284  }
285 
286  const TGraphAligned* grPow_db = coherentWave->powerdB();
287 
288  const int firstSlopeBin = TMath::Nint(fSlopeFitStartFreqGHz/df);
289  const int lastSlopeBin = TMath::Nint(fSlopeFitEndFreqGHz/df);
290  const int numSlopeBins = lastSlopeBin - firstSlopeBin;
291 
292  const double mean_f = TMath::Mean(numSlopeBins, &grPow_db->GetX()[firstSlopeBin]);
293  const double mean_pow_db = TMath::Mean(numSlopeBins, &grPow_db->GetY()[firstSlopeBin]);
294 
295  double gradNumerator = 0;
296  double gradDenominator = 0;
297  for(int i=firstSlopeBin; i < lastSlopeBin; i++){
298  double dx = grPow_db->GetX()[i] - mean_f;
299  double dy = grPow_db->GetY()[i] - mean_pow_db;
300 
301  gradNumerator += dy*dx;
302  gradDenominator += dx*dx;
303  }
304 
305  if(gradDenominator <= 0){
306  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " for run "
307  << fCurrentRun << ", eventNumber " << fCurrentEventNumber
308  << ", got gradDenominator = " << gradDenominator << " will get NaN or Inf..." << std::endl;
309  }
310  info.spectrumSlope = gradNumerator/gradDenominator;
311  info.spectrumIntercept = mean_pow_db - info.spectrumSlope*mean_f;
312 
313  }
314 }
315 
316 
317 
318 
319 
320 
321 
322 
323 
324 
325 
327  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
328  auto pol = (AnitaPol::AnitaPol_t) polInd;
329  for(int ant=0; ant<NUM_SEAVEYS; ant++){
330  const AnalysisWaveform* wf = fEv->getFilteredGraph(ant, pol);
331  const TGraphAligned* gr = wf->even();
332  const TGraphAligned* he = wf->hilbertEnvelope();
333 
334  sum->channels[polInd][ant].rms = gr->GetRMS();
335  sum->channels[polInd][ant].avgPower = RootTools::getTimeIntegratedPower(gr);
336  Double_t maxY, maxX, minY, minX;
337  RootTools::getLocalMaxToMin(gr, maxY, maxX, minY, minX);
338  sum->channels[polInd][ant].snr = (maxY - minY)/sum->channels[polInd][ant].rms;
339  sum->channels[polInd][ant].peakHilbert = TMath::MaxElement(he->GetN(), he->GetY());
340  }
341  }
342 }
343 
344 
345 
347 
348  fCurrentEventNumber = fEv->getHeader()->eventNumber;
349  fCurrentRun = fEv->getHeader()->run;
350 
351  // spawn a CrossCorrelator if we need one
352  if(fCrossCorr == nullptr){
353  fCrossCorr = new CrossCorrelator();
354  fSpawnedCrossCorrelator = true;
355  fDtCache.init(fCrossCorr, this);
356  }
357 
358  // FilteredAnitaEvent fEvMin(fEv->getUsefulAnitaEvent(), fMinFilter, fEv->getGPS(), fEv->getHeader(), false); // just the minimum filter
359  // FilteredAnitaEvent fEvMinDeco(fEv->getUsefulAnitaEvent(), fMinDecoFilter, fEv->getGPS(), fEv->getHeader(), false); // minimum + deconvolution
360  // FilteredAnitaEvent fEvDeco(fEv, fMinDecoFilter); // extra deconvolution
361  nicelyDeleteInternalFilteredEvents();
362  fEvMin = new FilteredAnitaEvent(fEv->getUsefulAnitaEvent(), fMinFilter, fEv->getGPS(), fEv->getHeader(), false); // just the minimum filter
363  fEvMinDeco = new FilteredAnitaEvent(fEv->getUsefulAnitaEvent(), fMinDecoFilter, fEv->getGPS(), fEv->getHeader(), false); // minimum + deconvolution
364  fEvDeco = new FilteredAnitaEvent(fEv, fMinDecoFilter); // extra deconvolution
365 
366  if(fFillChannelInfo != 0){
367  fillChannelInfo(fEv, sum);
368  }
369 
370  sum->eventNumber = fEv->getHeader()->eventNumber;
371 
372  chooseAntennasForCoherentlySumming(fCoherentDeltaPhi);
373 
374  for(Int_t polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
375 
376  auto pol = (AnitaPol::AnitaPol_t) polInd;
377 
378  fCrossCorr->correlateEvent(fEv, pol);
379 
380  // do the coarsely binned reconstruction
381  reconstruct(pol);
382 
383  std::vector<Double_t> coarseMapPeakValues;
384  std::vector<Double_t> coarseMapPeakPhiDegs;
385  std::vector<Double_t> coarseMapPeakThetaDegs;
386  coarseMaps[pol]->findPeakValues(fNumPeaks, coarseMapPeakValues, coarseMapPeakPhiDegs, coarseMapPeakThetaDegs);
387  coarseMaps[pol]->addGpsInfo(fEv->getGPS());
388  coarseMaps[pol]->addTruthInfo(truth);
389 
390  sum->nPeaks[pol] = fNumPeaks;
391 
392  for(Int_t peakInd=0; peakInd < fNumPeaks; peakInd++){
393  reconstructZoom(pol, peakInd, coarseMapPeakPhiDegs.at(peakInd), coarseMapPeakThetaDegs.at(peakInd));
394 
395  InterferometricMap* h = fineMaps[pol][peakInd];
396  if(h != nullptr){
397 
398  // for plotting
399  h->addGpsInfo(fEv->getGPS());
400  h->addTruthInfo(truth);
401 
402 
403  h->getPeakInfo(sum->peak[pol][peakInd].value,
404  sum->peak[pol][peakInd].phi,
405  sum->peak[pol][peakInd].theta,
406  sum->peak[pol][peakInd].chisq);
407 
408  // fill in difference between rough and fine
409  sum->peak[pol][peakInd].dphi_rough = sum->peak[pol][peakInd].phi - coarseMapPeakPhiDegs.at(peakInd);
410  sum->peak[pol][peakInd].dtheta_rough = sum->peak[pol][peakInd].theta - coarseMapPeakThetaDegs.at(peakInd);
411 
412  // based on Cosmin's comments in AnitaAnalysisSummary.h
413  sum->peak[pol][peakInd].phi_separation = RootTools::getDeltaAngleDeg(sum->peak[pol][peakInd].phi, sum->peak[pol][0].phi);
414 
415  // hwAngle, is the angle between the peak and the nearest L3 phi-sector trigger of that polarisation
416  setTriggerInfoFromPeakPhi(fEv->getHeader(), pol, h->getPeakPhiSector(), sum->peak[pol][peakInd]);
417 
418  // coherent
419  // coherent_filtered
420  // deconvolved
421  // deconvolved_filtered
422 
423 
424  fillWaveformInfo(pol, peakInd, sum->coherent_filtered[pol][peakInd], fEv, fCoherentFiltered[pol][peakInd], h, noiseMonitor,
425  f_dICoherentFiltered[pol][peakInd], f_dQCoherentFiltered[pol][peakInd],
426  f_dUCoherentFiltered[pol][peakInd], f_dVCoherentFiltered[pol][peakInd]);
427  fillWaveformInfo(pol, peakInd, sum->deconvolved_filtered[pol][peakInd], fEvDeco, fDeconvolvedFiltered[pol][peakInd], h, noiseMonitor,
428  f_dIDeconvolvedFiltered[pol][peakInd], f_dQDeconvolvedFiltered[pol][peakInd],
429  f_dUDeconvolvedFiltered[pol][peakInd], f_dVDeconvolvedFiltered[pol][peakInd]);
430 
431  h->setResolutionEstimateFromWaveformSNR(sum->deconvolved_filtered[pol][peakInd].snr);
432 
433  if(fFillUnfiltered != 0){
434  std::vector<double> dI ,dQ ,dU ,dV;
435  fillWaveformInfo(pol, peakInd, sum->coherent[pol][peakInd], fEvMin, fCoherent[pol][peakInd], h, noiseMonitor, dI, dQ, dU, dV);
436  fillWaveformInfo(pol, peakInd, sum->deconvolved[pol][peakInd], fEvMinDeco, fDeconvolved[pol][peakInd], h, noiseMonitor, dI, dQ, dU, dV);
437  }
438 
439  // if(sum->eventNumber==60840043){
440  // double x = sum->trainingDeconvolvedFiltered().fracPowerWindowGradient();
441  // for(int i=0; i < 5; i++){
442  // std::cout << sum->trainingDeconvolvedFiltered().fracPowerWindowBegins[i] << "\t" << sum->trainingDeconvolvedFiltered().fracPowerWindowEnds[i] << std::endl;
443  // }
444  // std::cout << x << std::endl;
445  // }
446 
447  if(fEv->getGPS() != nullptr){
448  UsefulAdu5Pat usefulPat(fEv->getGPS());
449  int success = 0;
450  if(sum->peak[pol][peakInd].theta < 0){ // work around for bug in traceBackToContinent
451  Double_t phiWave = TMath::DegToRad()*sum->peak[pol][peakInd].phi;
452  Double_t thetaWave = -1*TMath::DegToRad()*sum->peak[pol][peakInd].theta;
453 
454  success = usefulPat.traceBackToContinent3(phiWave, thetaWave,
455  &sum->peak[pol][peakInd].longitude,
456  &sum->peak[pol][peakInd].latitude,
457  &sum->peak[pol][peakInd].altitude,
458  &sum->peak[pol][peakInd].theta_adjustment_needed);
459  }
460  if(success==0){
461  sum->peak[pol][peakInd].longitude = -9999;
462  sum->peak[pol][peakInd].latitude = -9999;
463  sum->peak[pol][peakInd].altitude = -9999;
464  sum->peak[pol][peakInd].theta_adjustment_needed = -9999;
465  sum->peak[pol][peakInd].distanceToSource = -9999;
466  }
467  else{
468  sum->peak[pol][peakInd].distanceToSource = SPEED_OF_LIGHT_NS*usefulPat.getTriggerTimeNsFromSource(sum->peak[pol][peakInd].latitude,
469  sum->peak[pol][peakInd].longitude,
470  sum->peak[pol][peakInd].altitude);
471  }
472  }
473  }
474  }
475  }
476 
477  // keep internal copy of summary
478  fSummary = (*sum);
479 }
480 
481 
482 
483 
485 
486  const double bandsLowGHz[AnitaEventSummary::numBlastPowerBands] = {0.15-1e-10, 0};
487  const double bandsHighGHz[AnitaEventSummary::numBlastPowerBands] = {0.25+1e-10, 999};
488 
489  // reset the values
490  for(int band=0; band < AnitaEventSummary::numBlastPowerBands; band++){
491  flags.middleOrBottomPower[band] = 0;
492  flags.middleOrBottomAnt[band] = -1;
493  flags.middleOrBottomPol[band] = 2;
494  flags.topPower[band] = 0;
495  }
496 
497  for(Int_t polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
498  auto pol = (AnitaPol::AnitaPol_t) polInd;
499  for(UInt_t phi=0; phi < NUM_PHI; phi++){
500  for(UInt_t ring=AnitaRing::kMiddleRing; ring < AnitaRing::kNotARing; ring++){
501  Int_t ant = ring*NUM_PHI + phi;
502 
503  const AnalysisWaveform* wf = fEv->getRawGraph(ant, pol);
504  const TGraphAligned* grPow = wf->power();
505  const double df_GHz = grPow->GetX()[1] - grPow->GetX()[0];
506 
507  Double_t powThisAnt[AnitaEventSummary::numBlastPowerBands] = {0};
508 
509  for(int i=0; i < grPow->GetN(); i++){
510  const double f_GHz = grPow->GetX()[i];
511  for(int band=0; band < AnitaEventSummary::numBlastPowerBands; band++){
512  if(f_GHz >= bandsLowGHz[band] && f_GHz < bandsHighGHz[band]){
513  powThisAnt[band] +=grPow->GetY()[i]*df_GHz;
514  }
515  }
516  }
517 
518  for(int band=0; band < AnitaEventSummary::numBlastPowerBands; band++){
519  if(powThisAnt[band] > flags.middleOrBottomPower[band]){
520  flags.middleOrBottomPower[band] = powThisAnt[band];
521  flags.middleOrBottomAnt[band] = ant;
522  flags.middleOrBottomPol[band] = polInd;
523  }
524  }
525  }
526  }
527  }
528 
529 
530  for(int band=0; band < AnitaEventSummary::numBlastPowerBands; band++){
531  int ant = flags.middleOrBottomAnt[band] % NUM_PHI;
532  auto pol = (AnitaPol::AnitaPol_t) flags.middleOrBottomPol[band];
533  const AnalysisWaveform* wf = fEv->getRawGraph(ant, pol);
534  const TGraphAligned* grPow = wf->power();
535  const double df_GHz = grPow->GetX()[1] - grPow->GetX()[0];
536 
537  for(int i=0; i < grPow->GetN(); i++){
538  const double f_GHz = grPow->GetX()[i];
539  for(int band=0; band < AnitaEventSummary::numBlastPowerBands; band++){
540  if(f_GHz >= bandsLowGHz[band] && f_GHz < bandsHighGHz[band]){
541  flags.topPower[band] +=grPow->GetY()[i]*df_GHz;
542  }
543  }
544  }
545  }
546 }
547 
548 
549 
550 
553  Int_t peakPhiSector,
555 
556 
557  AnitaPol::AnitaPol_t xPol = RootTools::swapPol(pol);
558  // const RawAnitaHeader* header = fEv->getHeader();
559  peak.hwAngle = -9999;
560  peak.hwAngleXPol = -9999;
561 
562  for(int phi=0; phi < NUM_PHI; phi++){
563  int phiWasTriggered = header->isInL3Pattern(phi, pol);
564  if(phiWasTriggered > 0){
565  double phiSectorPhi = InterferometricMap::getPhiSectorCenterPhiDeg(phi);
566  double dPhi = RootTools::getDeltaAngleDeg(peak.phi, phiSectorPhi);
567  if(TMath::Abs(dPhi) < TMath::Abs(peak.hwAngle)){
568  peak.hwAngle = dPhi;
569  }
570  }
571  int phiWasTriggeredXPol = header->isInL3Pattern(phi, xPol);
572  if(phiWasTriggeredXPol > 0){
573  double phiSectorPhi = InterferometricMap::getPhiSectorCenterPhiDeg(phi);
574  double dPhi = RootTools::getDeltaAngleDeg(peak.phi, phiSectorPhi);
575  if(TMath::Abs(dPhi) < TMath::Abs(peak.hwAngleXPol)){
576  peak.hwAngleXPol = dPhi;
577  }
578  }
579  }
580 
581  peak.triggered = (header->isInL3Pattern(peakPhiSector, pol) != 0);
582  peak.triggered_xpol = (header->isInL3Pattern(peakPhiSector, xPol) != 0);
583 
584  peak.masked = (header->isInPhiMaskOffline(peakPhiSector, pol) != 0) || (header->isInL1MaskOffline(peakPhiSector, pol) != 0);
585  peak.masked_xpol = (header->isInPhiMaskOffline(peakPhiSector, xPol) != 0) || (header->isInL1MaskOffline(peakPhiSector, xPol) != 0);
586 }
587 
588 
590 
591  fCrossCorr = nullptr;
592  fSpawnedCrossCorrelator = false;
593  fWhichResponseDir = 0;
595  for(Int_t pol=0; pol < AnitaPol::kNotAPol; pol++){
596  for(int ant=0; ant<NUM_SEAVEYS; ant++){
597  fRArray[pol].push_back(geom->getAntR(ant, AnitaPol::AnitaPol_t(pol)));
598  fZArray[pol].push_back(geom->getAntZ(ant, AnitaPol::AnitaPol_t(pol)));
599  fPhiArrayDeg[pol].push_back(geom->getAntPhiPositionRelToAftFore(ant, AnitaPol::AnitaPol_t(pol))*TMath::RadToDeg());
600  }
601  }
602 
603  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
604  coarseMaps[polInd] = nullptr;
605  for(int peakInd=0; peakInd < AnitaEventSummary::maxDirectionsPerPol; peakInd++){
606  fineMaps[polInd][peakInd] = nullptr;
607  for(int xPol=0; xPol < AnitaPol::kNotAPol; xPol++){
608  fCoherentFiltered[polInd][peakInd][xPol] = nullptr;
609  fCoherent[polInd][peakInd][xPol] = nullptr;
610  fDeconvolved[polInd][peakInd][xPol] = nullptr;
611  fDeconvolvedFiltered[polInd][peakInd][xPol] = nullptr;
612  }
613  }
614  }
615 
616  fDebug = 0;
617  fUseOffAxisDelay = 1;
618  fCoherentDeltaPhi = 2;
619  fLastCoherentDeltaPhi = -1;
620  fNumPeaks = 3;
621  fCoherentDtNs = 0.01;
622  fSlopeFitStartFreqGHz = 0.18;
623  fSlopeFitEndFreqGHz = 1.3;
624  fFillChannelInfo = 0;
625  fFillSpectrumInfo = 0;
626  fFillUnfiltered = 0;
627  fMeanPowerFlagLowFreqGHz = 0;
628  fMeanPowerFlagHighFreqGHz = 0;
629  fCurrentEventNumber = 0;
630  fCurrentRun = 0;
631 
632  fDrawNPeaks = 3;
633  fDrawDomain = kTimeDomain;
634  fDrawCoherent=1;
635  fDrawDedispersed=1;
636  fDrawXPol=1;
637  fDrawXPolDedispersed=1;
638 
639  const TString minFiltName = "Minimum";
640  fMinFilter = Filters::findDefaultStrategy(minFiltName);
641  if(fMinFilter == nullptr){
642  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", unable to find default filter " << minFiltName << std::endl;
643  }
644 
645  const TString minDecoFiltName = "Deconvolve";
646  fMinDecoFilter = Filters::findDefaultStrategy(minDecoFiltName);
647  if(fMinDecoFilter == nullptr){
648  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", unable to find default filter " << minDecoFiltName << std::endl;
649  }
650 
651  fEvMin = nullptr;
652  fEvMinDeco = nullptr;
653  fEvDeco = nullptr;
654 
655  chooseAntennasForCoherentlySumming(fCoherentDeltaPhi);
656 
657 }
658 
659 
660 
661 
662 Double_t Acclaim::AnalysisReco::singleAntennaOffAxisDelay(Double_t deltaPhiDeg) const {
663 
664 
665  // These are the numbers from Linda's fits...
666  // FCN=2014.5 FROM HESSE STATUS=NOT POSDEF 40 CALLS 407 TOTAL
667  // EDM=5.13972e-17 STRATEGY= 1 ERR MATRIX NOT POS-DEF
668  // EXT PARAMETER APPROXIMATE STEP FIRST
669  // NO. NAME VALUE ERROR SIZE DERIVATIVE
670  // 1 p0 0.00000e+00 fixed
671  // 2 p1 0.00000e+00 fixed
672  // 3 p2 -1.68751e-05 1.90656e-07 4.07901e-10 1.39356e-03
673  // 4 p3 0.00000e+00 fixed
674  // 5 p4 2.77815e-08 9.38089e-11 7.26358e-14 2.34774e+01
675  // 6 p5 0.00000e+00 fixed
676  // 7 p6 -8.29351e-12 1.78286e-14 7.64605e-18 -1.72486e+05
677  // 8 p7 0.00000e+00 fixed
678  // 9 p8 1.15064e-15 1.78092e-18 6.93019e-22 -1.31237e+09
679  // 10 p9 0.00000e+00 fixed
680  // 11 p10 -7.71170e-20 1.63489e-22 6.05470e-26 4.32831e+13
681  // 12 p11 0.00000e+00 fixed
682  // 13 p12 1.99661e-24 9.79818e-27 1.84698e-29 -6.15528e+16
683 
684  // ... in a const array
685  const Int_t numPowers = 13;
686  static const Double_t params[numPowers] = {0.00000e+00, 0.00000e+00, -1.68751e-05, 0.00000e+00,
687  2.77815e-08, 0.00000e+00, -8.29351e-12, 0.00000e+00,
688  1.15064e-15, 0.00000e+00, -7.71170e-20, 0.00000e+00,
689  1.99661e-24};
690 
691  // Sum up the powers in off boresight angle.
692  Double_t offBoresightDelay = 0;
693  for(int power=0; power < numPowers; power++){
694  offBoresightDelay += params[power]*TMath::Power(deltaPhiDeg, power);
695  }
696 
697  return offBoresightDelay;
698 }
699 
700 
701 
703  Double_t phiDeg) const {
704 
705  Double_t deltaPhiDeg1 = RootTools::getDeltaAngleDeg(fPhiArrayDeg[pol].at(ant1), phiDeg);
706  Double_t deltaPhiDeg2 = RootTools::getDeltaAngleDeg(fPhiArrayDeg[pol].at(ant2), phiDeg);
707  Double_t delay1 = singleAntennaOffAxisDelay(deltaPhiDeg1);
708  Double_t delay2 = singleAntennaOffAxisDelay(deltaPhiDeg2);
709  return (delay1-delay2);
710 }
711 
712 
713 
714 
715 Double_t Acclaim::AnalysisReco::getDeltaTExpected(AnitaPol::AnitaPol_t pol, Int_t ant1, Int_t ant2, Double_t phiWave, Double_t thetaWave) const {
716 
717  // Double_t tanThetaW = tan(thetaWave);
718  Double_t tanThetaW = tan(-1*thetaWave);
719  Double_t part1 = fZArray[pol].at(ant1)*tanThetaW - fRArray[pol].at(ant1)*cos(phiWave-TMath::DegToRad()*fPhiArrayDeg[pol].at(ant1));
720  Double_t part2 = fZArray[pol].at(ant2)*tanThetaW - fRArray[pol].at(ant2)*cos(phiWave-TMath::DegToRad()*fPhiArrayDeg[pol].at(ant2));
721  Double_t tdiff = 1e9*((cos(thetaWave) * (part2 - part1))/SPEED_OF_LIGHT); // Returns time in ns
722 
723  return tdiff;
724 }
725 
726 
727 Double_t Acclaim::AnalysisReco::getDeltaTExpected(AnitaPol::AnitaPol_t pol, Int_t ant, Double_t phiWave, Double_t thetaWave) const {
728 
729  // Double_t tanThetaW = tan(thetaWave);
730  Double_t tanThetaW = tan(-1*thetaWave);
731  Double_t part = fZArray[pol].at(ant)*tanThetaW - fRArray[pol].at(ant)*cos(phiWave-TMath::DegToRad()*fPhiArrayDeg[pol].at(ant));
732  Double_t tdiff = 1e9*((cos(thetaWave) * (part))/SPEED_OF_LIGHT); // Returns time in ns
733 
734  return tdiff;
735 }
736 
737 
738 
739 
742  geom->usePhotogrammetryNumbers(1);
743  for(Int_t pol=0; pol < AnitaPol::kNotAPol; pol++){
744  for(int ant=0; ant<NUM_SEAVEYS; ant++){
745  fRArray[pol].at(ant) = geom->getAntR(ant, AnitaPol::AnitaPol_t(pol));
746  fZArray[pol].at(ant) = geom->getAntZ(ant, AnitaPol::AnitaPol_t(pol));
747  fPhiArrayDeg[pol].at(ant) = geom->getAntPhiPositionRelToAftFore(ant, AnitaPol::AnitaPol_t(pol))*TMath::RadToDeg();
748  }
749  }
750 
752  for(auto & delaysPerSurf : cal->relativePhaseCenterToAmpaDelays){
753  for(double& delayThisChannel : delaysPerSurf){
754  delayThisChannel = 0;
755  }
756  }
757 
758  if(fCrossCorr == nullptr){
759  fCrossCorr = new CrossCorrelator();
760  fSpawnedCrossCorrelator = true;
761  }
762 
763  fDtCache.init(fCrossCorr, this, true);
764  geom->usePhotogrammetryNumbers(0);
765 
766 }
767 
768 
769 
770 
771 
772 
774  InterferometricMap* h = coarseMaps[pol];
775  coarseMaps[pol] = nullptr;
776  return h;
777 }
778 
779 
780 
781 
782 
783 
785 
786  InterferometricMap* h = fineMaps[pol][peakInd];
787  if(h==nullptr){
788  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " for run "
789  << fCurrentRun << ", eventNumber " << fCurrentEventNumber
790  << ", unable to find fineMap with pol " << pol
791  << " for peakInd = " << peakInd << " about to return NULL." << std::endl;
792  }
793  fineMaps[pol][peakInd] = nullptr;
794 
795  return h;
796 }
797 
798 
799 
800 
801 
802 
803 
805 
806  if(coarseMaps[pol]==nullptr)
807  {
808  // std::cerr << "new coarse map " << pol << std::endl;
809  // I don't own the map or there isn't one, so I'll make a new one
810  coarseMaps[pol] = new InterferometricMap();
811  }
812  else{// I own the map so I can overwrite it to avoid allocating memory
813  // std::cerr << "old coarse map " << pol << std::endl;
814  coarseMaps[pol]->Reset();
815  }
816 
817  if(pat != nullptr){
818  coarseMaps[pol]->addGpsInfo(pat);
819  }
820 
821  coarseMaps[pol]->Fill(pol, fCrossCorr, &fDtCache);
822 }
823 
824 
825 
826 
827 void Acclaim::AnalysisReco::reconstructZoom(AnitaPol::AnitaPol_t pol, Int_t peakIndex, Double_t zoomCenterPhiDeg, Double_t zoomCenterThetaDeg, const Adu5Pat* pat) {
828 
829  // Some kind of sanity check here due to the unterminating while loop inside RootTools::getDeltaAngleDeg
830  if(zoomCenterPhiDeg < -500 || zoomCenterThetaDeg < -500 ||
831  zoomCenterPhiDeg >= 500 || zoomCenterThetaDeg >= 500){
832 
833  std::cerr << "Warning in "<< __PRETTY_FUNCTION__ << " in " << __FILE__
834  << ". zoomCenterPhiDeg = " << zoomCenterPhiDeg
835  << " and zoomCenterThetaDeg = " << zoomCenterThetaDeg
836  << " ...these values look suspicious so I'm skipping this reconstruction."
837  << " eventNumber = " << fCrossCorr->eventNumber[pol] << std::endl;
838  return;
839  }
840 
841  Double_t deltaPhiDegPhi0 = RootTools::getDeltaAngleDeg(zoomCenterPhiDeg, InterferometricMap::getBin0PhiDeg());
842  deltaPhiDegPhi0 = deltaPhiDegPhi0 < 0 ? deltaPhiDegPhi0 + DEGREES_IN_CIRCLE : deltaPhiDegPhi0;
843 
844  Int_t phiSector = floor(deltaPhiDegPhi0/PHI_RANGE);
845 
846  auto* h = new InterferometricMap(peakIndex, phiSector, zoomCenterPhiDeg, PHI_RANGE_ZOOM, zoomCenterThetaDeg, THETA_RANGE_ZOOM);
847  if(pat != nullptr){
848  h->addGpsInfo(pat);
849  }
850  h->Fill(pol, fCrossCorr, &fDtCache);
851 
852  // std::cout << h->GetName() << std::endl;
853  // std::cout << "in " << __PRETTY_FUNCTION__ << ": " << fineMaps[pol][peakIndex] << std::endl;
854  if(fineMaps[pol][peakIndex] != nullptr){
855  delete fineMaps[pol][peakIndex];
856  }
857  fineMaps[pol][peakIndex] = h;
858 }
859 
860 
862 
863  // Since I am simulataneously testing many of Linda's geometries on lots of different files
864  // I need the help of a machine to check I'm testing the geometry I think I'm testing.
865 
867  geom->usePhotogrammetryNumbers(0); // i.e. definitely use the numbers I am inserting.
869 
870 
871  std::ifstream lindasNums(pathToLindasFile.Data());
872  if(static_cast<int>(lindasNums.is_open())==0){
873  return 1; // This is an error
874  }
875 
876  Int_t ant;
877  Double_t dr, dPhiRad, dz, dt;
878 
879  while(lindasNums >> ant >> dr >> dz >> dPhiRad >> dt){
880 
881  Int_t surf, chan, ant2;
883  surf, chan, ant2);
884 
885  Double_t newR = geom->rPhaseCentreFromVerticalHornPhotogrammetry[ant][pol] + dr;
886  Double_t newPhi = geom->azPhaseCentreFromVerticalHornPhotogrammetry[ant][pol] + dPhiRad;
887  Double_t newZ = geom->zPhaseCentreFromVerticalHornPhotogrammetry[ant][pol] + dz;
888  Double_t newT = dt;
889 
890  if(newPhi >= TMath::TwoPi()){
891  newPhi -= TMath::TwoPi();
892  }
893  else if(newPhi < 0){
894  newPhi += TMath::TwoPi();
895  }
896 
897  geom->rPhaseCentreFromVerticalHorn[ant][pol] = newR;
898  geom->azPhaseCentreFromVerticalHorn[ant][pol] = newPhi;
899  geom->zPhaseCentreFromVerticalHorn[ant][pol] = newZ;
900  cal->relativePhaseCenterToAmpaDelays[surf][chan] = newT;
901 
902  // std::cout << ant << "\t" << dr << "\t" << dz << "\t" << dPhiRad << "\t" << dt << std::endl;
903 
904  }
905  if(ant != NUM_SEAVEYS - 1){
906  // then you didn't make it to the end of the file!
907  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " in " << __FILE__ << std::endl;
908  std::cerr << "It looks like you didn't read to the end of Linda's geometry file!" << std::endl;
909  return 1;
910  }
911 
912  return 0;
913 }
914 
916 
917  // std::cerr << __PRETTY_FUNCTION__ << std::endl;
918 
919  if(coherentDeltaPhi!=fLastCoherentDeltaPhi){
920 
921  for(int peakPhiSector = 0; peakPhiSector < NUM_PHI; peakPhiSector++){
922  fPhiSectorToAnts[peakPhiSector] = std::vector<Int_t>();
923 
924  // fPhiSectorToAnts[peakPhiSector].clear();
925  for(int deltaPhiSect=-fCoherentDeltaPhi; deltaPhiSect <= fCoherentDeltaPhi; deltaPhiSect++){
926 
927  Int_t phiSector = peakPhiSector + deltaPhiSect;
928  phiSector = phiSector < 0 ? phiSector + NUM_PHI : phiSector;
929  phiSector = phiSector >= NUM_PHI ? phiSector - NUM_PHI : phiSector;
930 
931  for(int ring = 0; ring < AnitaRing::kNotARing; ring++){
932  int ant = AnitaGeomTool::getAntFromPhiRing(phiSector, AnitaRing::AnitaRing_t(ring));
933  fPhiSectorToAnts[peakPhiSector].push_back(ant);
934  }
935  }
936  }
937  fLastCoherentDeltaPhi = fCoherentDeltaPhi;
938  }
939 }
940 
942  Double_t peakPhiDeg, Double_t peakThetaDeg, std::vector<double>& dts) {
943 
944  dts.clear(); // first empty the vector
945  dts.reserve(theAnts.size());
946 
947  Double_t phiWave = peakPhiDeg*TMath::DegToRad();
948  Double_t thetaWave = peakThetaDeg*TMath::DegToRad();
949  for(int ant : theAnts){
950  // Double_t dt = getDeltaTExpected(pol, theAnts.at(0), ant, phiWave, thetaWave);
951  Double_t dt = getDeltaTExpected(pol, ant, phiWave, thetaWave);
952  dts.push_back(dt);
953  }
954 }
955 
957  const std::vector<Int_t>& theAnts,
958  Double_t peakPhiDeg, Double_t peakThetaDeg,
959  Double_t* biggestPeakToPeak, Double_t* forceT0) {
960 
961  Int_t biggest = -1;
962  Double_t largestPeakToPeak = 0;
963  std::vector<const AnalysisWaveform*> waves;
964  waves.reserve(theAnts.size());
965 
966  for(int ant : theAnts){
967  const AnalysisWaveform* wf = fEv->getFilteredGraph(ant, pol);
968  waves.push_back(wf);
969  const TGraphAligned* gr = wf->even();
970 
971  Double_t vMax, vMin, tMax, tMin;
972  RootTools::getLocalMaxToMin((TGraph *)gr, vMax, tMax, vMin, tMin);
973 
974  if(vMax - vMin > largestPeakToPeak){
975  largestPeakToPeak = vMax - vMin;
976  biggest = ant;
977  }
978  else if(largestPeakToPeak <= 0){
979  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " for run "
980  << fCurrentRun << ", eventNumber " << fCurrentEventNumber << ", the waveform max/min aren't sensible?" << std::endl;
981  std::cerr << vMax << "\t" << vMin << "\t" << tMax << "\t" << tMin << std::endl;
982  }
983  }
984 
985  if(biggestPeakToPeak != nullptr){
986  (*biggestPeakToPeak) = largestPeakToPeak;
987  }
988 
989  if(biggest < 0 || biggest >= NUM_SEAVEYS){
990  std::cerr << "Error in " << __PRETTY_FUNCTION__
991  << ", I couldn't find a waveform where vMax - vMin > 0. "
992  << "Something's wrong!" << std::endl;
993  }
994 
995  std::vector<double> dts;
996  directionAndAntennasToDeltaTs(theAnts, pol, peakPhiDeg, peakThetaDeg, dts);
997 
998  return coherentlySum(waves, dts, forceT0);
999 }
1000 
1001 size_t Acclaim::AnalysisReco::checkWavesAndDtsMatch(std::vector<const AnalysisWaveform*>& waves, std::vector<Double_t>& dts) {
1002  size_t s = waves.size();
1003  if(s < 1){
1004  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " for run " << fCurrentRun
1005  << ", eventNumber " << fCurrentEventNumber << ", nothing to sum." << std::endl;
1006  }
1007  else if(s != dts.size()){
1008  const char* action = dts.size() < waves.size() ? "padding" : "trimming";
1009  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " for run " << fCurrentRun
1010  << ", eventNumber " << fCurrentEventNumber << ", unequal vectors (waves.size() = "
1011  << waves.size() << ", dts.size() = " << dts.size() << ")\n"
1012  << action << " dts..." << std::endl;
1013  while(s != dts.size()){
1014  if(dts.size() < s){
1015  dts.push_back(0);
1016  }
1017  else{
1018  dts.pop_back();
1019  }
1020  }
1021  }
1022  return s;
1023 }
1024 
1025 AnalysisWaveform* Acclaim::AnalysisReco::coherentlySum(std::vector<const AnalysisWaveform*>& waves, std::vector<Double_t>& dts, const Double_t* forceT0) {
1026 
1027  if(checkWavesAndDtsMatch(waves, dts)==0){
1028  std::cerr << "Nothing to sum.. about to return NULL" << std::endl;
1029  return nullptr;
1030  }
1031 
1032  const double extraTimeNs = 20; //2*(*std::max_element(dts.begin(), dts.end()));
1033  const TGraph* gr0 = waves[0]->even();
1034  const double totalTime = gr0->GetX()[gr0->GetN()-1] - gr0->GetX()[0] + extraTimeNs;
1035  const int interpN = floor(totalTime/fCoherentDtNs);
1036 
1037  std::vector<double> zeros(interpN, 0);
1038  double t0 = forceT0 != nullptr ? *forceT0 : gr0->GetX()[0] - 0.5*extraTimeNs;
1039  auto* coherentWave = new AnalysisWaveform(interpN, &zeros[0], fCoherentDtNs, t0);
1040  TGraphAligned* grCoherent = coherentWave->updateEven();
1041 
1042  for(UInt_t i=0; i < waves.size(); i++){
1043  const TGraphAligned* grU = waves[i]->even();
1044  // std::cout << i << " here" << std::endl;
1045 
1046  const double t0 = grU->GetX()[0];
1047  const double tN = grU->GetX()[grU->GetN()-1];
1048 
1049  if(fDebug != 0){
1050  std::cerr << "Debug in " << __PRETTY_FUNCTION__ << ", waves[" << i << "] has even with " << grU->GetN() << " points. ";
1051  const TGraphAligned* grA = waves[i]->uneven();
1052 
1053  std::cerr << "(uneven has " << grA->GetN() << " points)." << std::endl;
1054  for(int samp=1; samp < grU->GetN(); samp++){
1055  if(grU->GetX()[samp] - grU->GetX()[samp-1] <= 0){
1056  std::cerr << "Debug in " << __PRETTY_FUNCTION__ << ", x not monotonically increasing!" << std::endl;
1057  std::cerr << "x[" << samp-1 << "] = " << grU->GetX()[samp-1] << std::endl;
1058  std::cerr << "x[" << samp << "] = " << grU->GetX()[samp] << std::endl;
1059  break;
1060  }
1061  }
1062  }
1063 
1064  int numNan = 0;
1065  for(int samp=0; samp < grCoherent->GetN(); samp++){
1066  double t = grCoherent->GetX()[samp];
1067 
1068  double tPlusDt = t + dts[i];
1069  if(tPlusDt > t0 && tPlusDt < tN){
1070  double y = waves[i]->evalEven(tPlusDt, AnalysisWaveform::EVAL_AKIMA);
1071  if(TMath::IsNaN(y)){ // Hopefully this is a bit redundent
1072  numNan++;
1073  }
1074  else{
1075  grCoherent->GetY()[samp] += y;
1076  }
1077  }
1078  }
1079 
1080  if(numNan > 0){
1081  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << " for run "
1082  << fCurrentRun << ", eventNumber " << fCurrentEventNumber << " interpolation returned "
1083  << numNan << " NaNs for wave " << i << std::endl;
1084  }
1085  }
1086 
1087  for(int samp=0; samp < grCoherent->GetN(); samp++){
1088  grCoherent->GetY()[samp]/=waves.size();
1089  }
1090 
1091  return coherentWave;
1092 }
1093 
1094 void Acclaim::AnalysisReco::wavesInCoherent(std::vector<const AnalysisWaveform*>& waves, std::vector<Double_t>& dts, std::vector<TGraphAligned*>& grs){
1095 
1096  for(unsigned w=0; w < waves.size(); w++){
1097  const TGraphAligned* grOld = waves[w]->even();
1098  auto* gr = new TGraphAligned(grOld->GetN(), grOld->GetX(), grOld->GetY());
1099 
1100  for(int i=0; i < gr->GetN(); i++){
1101  gr->GetX()[i] -= dts[w];
1102  }
1103 
1104  grs.push_back(gr);
1105  }
1106 }
1107 
1108 
1109 inline TString nameLargestPeak(Int_t peakInd){
1110  TString title;
1111  switch (peakInd){
1112  case 0: title = "Largest Peak "; break;
1113  case 1: title = "2nd Largest Peak "; break;
1114  case 2: title = "3rd Largest Peak "; break;
1115  default: title = TString::Format("%dth Largest Peak", peakInd+1); break;
1116  }
1117  return title;
1118 }
1119 
1120 
1122 
1123  constexpr int numColsForNow = 3;
1124  EColor peakColors[AnitaPol::kNotAPol][numColsForNow] = {{kBlack, EColor(kMagenta+2), EColor(kViolet+2)},
1125  {kBlue, EColor(kSpring+4), EColor(kPink + 10)}};
1126 
1127  constexpr int nStokesVecs = 4;
1128  EColor stokesCols[nStokesVecs] = {kBlack, kRed, kBlue, kGreen};
1129 
1130  // will go from top to bottom, like this...
1131  // 0-1: vpol/hpol Reconstruction
1132  // 1-2: Coarse Map
1133  // 2-3: Fine map layers title
1134  // 3-4: Fine maps (divided into fDrawNPeaks internally)
1135  // 4-5: Detailed data tables
1136  std::vector<double> wholePadVLayers = {1, 0.95, 0.75, 0.72, 0.3, 0};
1137  Int_t wholePadLayer = 0;
1138 
1139  if(fDrawNPeaks==1){ // tweak layout as there's too much space for just 1 fine map
1140  wholePadVLayers = {1, 0.95, 0.65, 0.62, 0.35, 0};
1141  }
1142 
1143  if(wholePad==nullptr){
1144  UInt_t eventNumber = fCrossCorr->eventNumber[pol];
1145  TString canName = TString::Format("can%u", eventNumber);
1146  TString polSuffix = pol == AnitaPol::kHorizontal ? "HPol" : "VPol";
1147  canName += polSuffix;
1148  TString canTitle = TString::Format("Event %u - ", eventNumber) + polSuffix;
1149  wholePad = new TCanvas(canName);
1150  }
1151  wholePad->Clear();
1152 
1153  TPad* wholeTitlePad = RootTools::makeSubPad(wholePad,
1154  0, wholePadVLayers.at(wholePadLayer+1),
1155  1, wholePadVLayers.at(wholePadLayer),
1156  TString::Format("%d_title", (int)pol));
1157  wholePadLayer++;
1158 
1159  (void) wholeTitlePad;
1160  auto *wholeTitle = new TPaveText(0, 0, 1, 1);
1161  TString wholeTitleText; // = TString::Format(");
1162  wholeTitleText += pol == AnitaPol::kHorizontal ? "HPol" : "VPol";
1163  wholeTitleText += " Reconstruction";
1164  wholeTitle->AddText(wholeTitleText);
1165  wholeTitle->SetBit(kCanDelete, true);
1166  wholeTitle->SetLineWidth(0);
1167  wholeTitle->Draw();
1168 
1169  TPad* coarseMapPad = RootTools::makeSubPad(wholePad,
1170  0, wholePadVLayers.at(wholePadLayer+1),
1171  1, wholePadVLayers.at(wholePadLayer),
1172  TString::Format("%d_coarse", (int)pol));
1173  wholePadLayer++;
1174 
1175  InterferometricMap* hCoarse = coarseMaps[pol];
1176 
1177  const double fracFinePeak = 0.2; // fraction of pad width for the fine peak, the rest is split between coherent/dedispsered
1178  const EColor xPolColor = kRed;
1179  const double xPolTitleBoxWidth = 0.1;
1180 
1181  TPad* tempPad = RootTools::makeSubPad(wholePad,
1182  0, wholePadVLayers.at(wholePadLayer+1),
1183  1, wholePadVLayers.at(wholePadLayer),
1184  "tempTitlePad");
1185  wholePadLayer++;
1186  tempPad->cd();
1187 
1188  std::vector<TPaveText*> paves;
1189  paves.push_back(new TPaveText(0, 0, fracFinePeak, 1));
1190  paves.back()->AddText("Fine Map");
1191  paves.back()->SetTextAlign(kVAlignCenter + kHAlignCenter);
1192 
1193  paves.push_back(new TPaveText(fracFinePeak, 0, fracFinePeak+0.5*(1-fracFinePeak)-0.1, 1));
1194  paves.back()->AddText("Coherent");
1195  paves.back()->SetTextAlign(kVAlignCenter + kHAlignCenter);
1196  if(fDrawXPol != 0 && fDrawDomain!=kStokesParams){
1197  double x2 = paves.back()->GetX2();
1198  double x1 = x2 - xPolTitleBoxWidth;
1199  paves.back()->SetX2(x1);
1200  paves.back()->SetTextAlign(kVAlignCenter + kHAlignRight);
1201 
1202  paves.push_back(new TPaveText(x1, 0, x2, 1));
1203  paves.back()->AddText("(Cross-Pol)");
1204  paves.back()->SetTextAlign(kVAlignCenter + kHAlignLeft);
1205  ((TText*)paves.back()->GetListOfLines()->Last())->SetTextColor(xPolColor);
1206  }
1207 
1208  paves.push_back(new TPaveText(fracFinePeak+0.5*(1-fracFinePeak), 0, 1, 1));
1209  paves.back()->AddText("Dedispersed");
1210  paves.back()->SetTextAlign(kVAlignCenter + kHAlignCenter);
1211 
1212  if(fDrawXPolDedispersed != 0 && fDrawDomain!=kStokesParams){
1213  double x2 = paves.back()->GetX2();
1214  double x1 = x2 - xPolTitleBoxWidth;
1215  paves.back()->SetX2(x1);
1216  paves.back()->SetTextAlign(kVAlignCenter + kHAlignRight);
1217 
1218  paves.push_back(new TPaveText(x1, 0, x2, 1));
1219  paves.back()->AddText("(Cross-Pol)");
1220  ((TText*)paves.back()->GetListOfLines()->Last())->SetTextColor(xPolColor);
1221  paves.back()->SetTextAlign(kVAlignCenter + kHAlignLeft);
1222  }
1223 
1224  for(auto & pave : paves){
1225  pave->SetBit(kCanDelete);
1226  pave->SetShadowColor(0);
1227  pave->SetLineWidth(0);
1228  pave->SetLineColor(0);
1229  pave->Draw();
1230  }
1231 
1232  TPad* finePeaksAndCoherent = RootTools::makeSubPad(wholePad,
1233  0, wholePadVLayers.at(wholePadLayer+1),
1234  1, wholePadVLayers.at(wholePadLayer),
1235  "peaks");
1236  wholePadLayer++;
1237 
1238  std::list<InterferometricMap*> drawnFineMaps;
1239 
1240  const int nFine = TMath::Min(fNumPeaks, fDrawNPeaks);
1241  for(int peakInd = 0; peakInd < nFine; peakInd++){
1242  double yUp = 1 - double(peakInd)/nFine;
1243  double yLow = yUp - double(1)/nFine;
1244  TPad* finePeak = RootTools::makeSubPad(finePeaksAndCoherent, 0, yLow, fracFinePeak, yUp, "fine");
1245  (void) finePeak;
1246 
1247  InterferometricMap* h = fineMaps[pol][peakInd];
1248  if(h != nullptr){
1249  h->SetTitleSize(1);
1250  h->GetXaxis()->SetTitleSize(0.01);
1251  h->GetYaxis()->SetTitleSize(0.01);
1252  h->SetLineColor(peakColors[pol][peakInd]);
1253  h->SetLineWidth(3);
1254 
1255  h->DrawGroup("col");
1256  drawnFineMaps.push_back(h);
1257 
1258  coarseMapPad->cd();
1259 
1260  const TGraphInteractive* grEdge = h->getEdgeBoxGraph();
1261  hCoarse->addGuiChild(*grEdge, "l");
1262  }
1263 
1264  double x0 = fCoherentFiltered[pol][peakInd][0]->even()->GetX()[0] - 10;
1265  double xN = fCoherentFiltered[pol][peakInd][0]->even()->GetX()[fCoherentFiltered[pol][peakInd][0]->even()->GetN()-1] + 10;
1266 
1267  for(int j=0; j <= 1; j++){ // j loops over a coherent/dedispersed
1268  std::vector<AnalysisWaveform*> wavesToDraw;
1269  std::vector<const AnitaEventSummary::WaveformInfo*> waveInfo;
1270  std::vector<EColor> waveColors;
1271  std::vector<Style_t> lineStyles;
1272  std::vector<TString> legText;
1273  if(j==0) {
1274  if(fDrawCoherent > 0){
1275  wavesToDraw.push_back(fCoherentFiltered[pol][peakInd][0]);
1276  waveInfo.push_back(&fSummary.coherent_filtered[pol][peakInd]);
1277  waveColors.push_back(peakColors[pol][peakInd]);
1278  lineStyles.push_back(1);
1279  legText.emplace_back("Co-pol");
1280  }
1281  if(fDrawXPol > 0){
1282  wavesToDraw.push_back(fCoherentFiltered[pol][peakInd][1]);
1283  waveInfo.push_back(nullptr);
1284  // waveColors.push_back(peakColors[pol][peakInd]);
1285  waveColors.push_back(xPolColor);
1286  lineStyles.push_back(7);
1287  legText.emplace_back("Cross-pol");
1288  }
1289  }
1290  else{
1291  if(fDrawDedispersed > 0){
1292  wavesToDraw.push_back(fDeconvolvedFiltered[pol][peakInd][0]);
1293  waveInfo.push_back(&fSummary.deconvolved_filtered[pol][peakInd]);
1294  waveColors.push_back(peakColors[pol][peakInd]);
1295  lineStyles.push_back(1);
1296  legText.emplace_back("Co-pol");
1297  }
1298  if(fDrawXPolDedispersed > 0){
1299  wavesToDraw.push_back(fDeconvolvedFiltered[pol][peakInd][1]);
1300  waveInfo.push_back(nullptr);
1301  waveColors.push_back(xPolColor); //peakColors[pol][peakInd]);
1302  lineStyles.push_back(7);
1303  legText.emplace_back("Cross-pol");
1304  }
1305  }
1306 
1307  // if(fDebug) std::cerr << "Draw flags:\t" << fDrawCoherent << "\t" << fDrawXPol << "\t" << fDrawDedispersed << "\t" << fDrawXPolDedispersed << std::endl;
1308  // if(fDebug) std::cerr << "This gives us " << wavesToDraw.size() << " waveforms" << std::endl;
1309  TGraphInteractive* gr = nullptr;
1310 
1311  for(int i=0; i < wavesToDraw.size(); i++){
1312 
1313  if(fDrawDomain==kTimeDomain){
1314  const TGraphAligned* gr2 = wavesToDraw[i]->even();
1315 
1316  auto* gr3 = new TGraphInteractive(gr2, "l");
1317  gr3->SetFillColor(0);
1318  gr3->SetLineColor(waveColors[i]);
1319  gr3->SetMarkerColor(waveColors[i]);
1320  gr3->SetLineStyle(lineStyles[i]);
1321 
1322  gr3->GetXaxis()->SetTitleSize(1);
1323  gr3->GetYaxis()->SetTitleSize(1);
1324 
1325  gr3->SetBit(kCanDelete); // Let ROOT track and handle deletion
1326 
1327  if(gr != nullptr){
1328  gr->addGuiChild(gr3);
1329  }
1330  else {
1331  gr = gr3;
1332 
1333  TString title = nameLargestPeak(peakInd);
1334  title += (j == 0 ? "Coherent Waveform" : "Dedispersed Waveform");
1335  title += (pol == AnitaPol::kHorizontal ? " HPol" : " VPol");
1336  title += ";Time (ns);Amplitude (mV)";
1337 
1338  gr->SetTitle(title);
1339  gr->GetXaxis()->SetRangeUser(x0, xN);
1340  }
1341  }
1342  else if(fDrawDomain==kFreqDomain){ // freq domain
1343  const TGraphAligned* grPower2 = wavesToDraw[i]->powerdB();
1344 
1345  auto* grPower = new TGraphInteractive(grPower2, "l");
1346 
1347  grPower->SetLineColor(waveColors[i]);
1348  grPower->SetMarkerColor(waveColors[i]);
1349  grPower->SetLineStyle(lineStyles[i]);
1350 
1351  grPower->SetBit(kCanDelete); // Let ROOT track and handle deletion
1352 
1353  if(gr == nullptr){
1354  gr = grPower;
1355  const double maxFreqGHz = 1.3;
1356  gr->GetXaxis()->SetRangeUser(0, maxFreqGHz);
1357  TString title = nameLargestPeak(peakInd);
1358  title += (j == 0 ? "Coherent Waveform Spectrum" : "Dedispersed Waveform Spectrum");
1359  title += (pol == AnitaPol::kHorizontal ? " HPol" : " VPol");
1360  title += ";Frequency (GHz);Power Spectral Density (dBm/MHz)";
1361  grPower->SetTitle(title);
1362  }
1363  else{
1364  gr->addGuiChild(grPower);
1365  }
1366 
1367  if((waveInfo[i] != nullptr) && (fFillSpectrumInfo != 0) && (gr != nullptr)){
1368  double y0 = waveInfo[i]->spectrumSlope*fSlopeFitStartFreqGHz + waveInfo[i]->spectrumIntercept;
1369  auto* grSlope = new TGraphInteractive(1, &fSlopeFitStartFreqGHz, &y0, "l");
1370  grSlope->SetPoint(1, fSlopeFitEndFreqGHz, waveInfo[i]->spectrumSlope*fSlopeFitEndFreqGHz + waveInfo[i]->spectrumIntercept);
1371  grSlope->SetLineColor(grPower->GetLineColor());
1372  gr->addGuiChild(grSlope); // pass it a pointer and it takes ownership
1373 
1374  double df = wavesToDraw[i]->deltaF();
1375  auto* grCoherentPeakMarker = new TGraphInteractive(0, nullptr, nullptr, "p");
1376  grCoherentPeakMarker->SetMarkerStyle(4);
1377  grCoherentPeakMarker->SetMarkerSize(0.75);
1378  grCoherentPeakMarker->SetMarkerColor(grPower->GetLineColor());
1379 
1380  for(double k : waveInfo[i]->peakFrequency){
1381  if(k > 0){
1382  int powerBin = TMath::Nint(k/df);
1383  grCoherentPeakMarker->SetPoint(grCoherentPeakMarker->GetN(), grPower->GetX()[powerBin], grPower->GetY()[powerBin]);
1384  }
1385  }
1386  gr->addGuiChild(grCoherentPeakMarker);
1387  }
1388  }
1389  else{ // stokes
1390  auto gr2 = j == 0 ? fCoherentFiltered[pol][peakInd][0]->even() : fDeconvolvedFiltered[pol][peakInd][0]->even();
1391  const double t0 = gr2->GetX()[0];
1392  const double dt = gr2->GetX()[1] - t0;
1393 
1394  std::vector<double> times;
1395  {
1396  times.reserve(gr2->GetN());
1397  double t = t0;
1398  while(times.size() < times.capacity()){
1399  times.push_back(t);
1400  t += dt;
1401  }
1402  }
1403 
1404  int k=0;
1405  const std::vector<double>& I = (j == 0
1406  ? f_dICoherentFiltered[pol][peakInd]
1407  : f_dIDeconvolvedFiltered[pol][peakInd]);
1408  const std::vector<double>& Q = (j == 0
1409  ? f_dQCoherentFiltered[pol][peakInd]
1410  : f_dQDeconvolvedFiltered[pol][peakInd]);
1411  const std::vector<double>& U = (j == 0
1412  ? f_dUCoherentFiltered[pol][peakInd]
1413  : f_dUDeconvolvedFiltered[pol][peakInd]);
1414  const std::vector<double>& V = (j == 0
1415  ? f_dVCoherentFiltered[pol][peakInd]
1416  : f_dVDeconvolvedFiltered[pol][peakInd]);
1417 
1418  for(const auto& v : {I, Q, U, V}){
1419 
1420  const int n = v.size();
1421  TGraphInteractive* gr3 = new TGraphInteractive(n, times.data(), v.data());
1422  if(gr==nullptr){
1423  gr = gr3;
1424  TString title = nameLargestPeak(peakInd);
1425  title += (j == 0 ? "Coherent Stokes Parameters" : "Dedispersed Stokes Parameters");
1426  title += (pol == AnitaPol::kHorizontal ? " HPol" : " VPol");
1427  title += ";Time (ns);Amplitude (mV)";
1428  gr->SetTitle(title);
1429  gr->GetXaxis()->SetRangeUser(x0, xN);
1430  }
1431  else{
1432  gr->addGuiChild(gr3);
1433  }
1434  gr3->SetFillColor(0);
1435  gr3->SetLineColor(stokesCols[k]);
1436  gr3->SetBit(kCanDelete);
1437  k++;
1438  }
1439  }
1440  if(fDrawDomain==kStokesParams){
1441  break;
1442  }
1443  }
1444  if(j==0){
1445  TPad* coherentPad = RootTools::makeSubPad(finePeaksAndCoherent, fracFinePeak, yLow, fracFinePeak + 0.5*(1 - fracFinePeak), yUp, "coherent");
1446  coherentPad->cd();
1447  }
1448  else{
1449  TPad* dedispersedPad = RootTools::makeSubPad(finePeaksAndCoherent, fracFinePeak + 0.5*(1 - fracFinePeak), yLow, 1, yUp, "dedispersed");
1450  dedispersedPad->cd();
1451  }
1452  if(gr != nullptr){
1453  gr->DrawGroup("al");
1454  // if(peakInd==0){
1455  // gPad->Update(); // necessary to get root to paint it into existence
1456  // TPaveText* titlePave = (TPaveText*)gPad->FindObject("title");
1457  // if(titlePave){
1458  // std::cout << titlePave->GetSize() << std::endl;
1459  // }
1460  // }
1461  }
1462  }
1463  }
1464 
1465  coarseMapPad->cd();
1466  hCoarse->DrawGroup("colz");
1467 
1468  if(!drawnFineMaps.empty()){
1469  auto it = drawnFineMaps.begin();
1470  Double_t polMax = -1e9;
1471  Double_t polMin = 1e9;
1472  for(; it!=drawnFineMaps.end(); ++it){
1473  polMax = (*it)->GetMaximum() > polMax ? (*it)->GetMaximum() : polMax;
1474  polMin = (*it)->GetMinimum() < polMin ? (*it)->GetMinimum() : polMin;
1475  }
1476  for(it=drawnFineMaps.begin(); it!=drawnFineMaps.end(); ++it){
1477  (*it)->SetMaximum(polMax);
1478  (*it)->SetMinimum(polMin);
1479  }
1480  if(hCoarse != nullptr){
1481  hCoarse->SetMaximum(polMax);
1482  // hCoarse->SetMinimum(polMin);
1483  }
1484  while(!drawnFineMaps.empty()){
1485  drawnFineMaps.pop_back();
1486  }
1487  // std::cout << polMax << "\t" << polMin << std::endl;
1488  }
1489 
1490  const double epsilon = 0.001; // so there's enough room for line border on the edges of the pave text
1491  TPad* textPad = RootTools::makeSubPad(wholePad,
1492  0, wholePadVLayers.at(wholePadLayer+1),
1493  1, wholePadVLayers.at(wholePadLayer),
1494  "text");
1495  wholePadLayer++;
1496  (void) textPad;
1497  for(int peakInd=0; peakInd < nFine; peakInd++){
1498  double xlow = double(peakInd)/nFine;
1499  double xup = xlow + double(1.)/nFine - epsilon;
1500 
1501  auto *title = new TPaveText(xlow, 0.9, xup, 1);
1502  // title->SetBorderSize(0);
1503  title->SetBit(kCanDelete, true);
1504  title->SetTextColor(peakColors[pol][peakInd]);
1505  title->SetLineColor(peakColors[pol][peakInd]);
1506 
1507  // TString titleText = pol == AnitaPol::kHorizontal ? "HPol" : "VPol";
1508  TString titleText = nameLargestPeak(peakInd);
1509  if(fDrawDomain==kStokesParams){
1510  titleText += "Stokes";
1511  }
1512  title->AddText(titleText);
1513  title->Draw();
1514 
1515 
1516  if(fDrawDomain!=kStokesParams){
1517  auto *pt = new TPaveText(xlow, epsilon, xup, 0.9);
1518  // pt->SetBorderSize(0);
1519  pt->SetBit(kCanDelete, true);
1520  pt->SetTextColor(peakColors[pol][peakInd]);
1521  pt->SetLineColor(peakColors[pol][peakInd]);
1522  pt->AddText(TString::Format("Image peak = %4.4lf", fSummary.peak[pol][peakInd].value));
1523  pt->AddText(TString::Format("#phi_{fine} = %4.2lf#circ", fSummary.peak[pol][peakInd].phi));
1524  pt->AddText(TString::Format("#theta_{fine} = %4.2lf#circ",fSummary.peak[pol][peakInd].theta));
1525  pt->AddText(TString::Format("Hilbert peak = %4.2lf mV, ", fSummary.coherent[pol][peakInd].peakHilbert));
1526 
1527  pt->AddText(TString::Format("Latitude = %4.2lf #circ", fSummary.peak[pol][peakInd].latitude));
1528  pt->AddText(TString::Format("Longitude = %4.2lf #circ", fSummary.peak[pol][peakInd].longitude));
1529  pt->AddText(TString::Format("Altitude = %4.2lf #circ", fSummary.peak[pol][peakInd].altitude));
1530  pt->Draw();
1531  }
1532  else{
1533  const double width = 0.03;
1534  auto e = new TPaveText(xlow, 0.8, xlow+width, 0.9);
1535  auto f = new TPaveText(xlow, 0.7, xlow+width, 0.8);
1536 
1537  auto ept = new TPaveText(xlow, epsilon, xlow+width, 0.7);
1538  ept->AddText("I")->SetTextColor(stokesCols[0]);
1539  ept->AddText("Q")->SetTextColor(stokesCols[1]);
1540  ept->AddText("U")->SetTextColor(stokesCols[2]);
1541  ept->AddText("V")->SetTextColor(stokesCols[3]);
1542 
1543  xlow += width;
1544  const double xmid = (xlow + xup)/2;
1545 
1546  auto lpt_t = new TPaveText(xlow, 0.8, xmid, 0.9);
1547  lpt_t->AddText("Coherent");
1548  auto lpt_f = new TPaveText(xlow, 0.7, xmid, 0.8);
1549  lpt_f->AddText("max (mean)");
1550 
1551  auto rpt_t = new TPaveText(xmid, 0.8, xup, 0.9);
1552  rpt_t->AddText("Dedispersed");
1553  auto rpt_f = new TPaveText(xmid, 0.7, xup, 0.8);
1554  rpt_f->AddText("max (mean)");
1555 
1556  auto* lpt = new TPaveText(xlow, epsilon, xmid, 0.7);
1557  auto& ci = fSummary.coherent_filtered[pol][peakInd];
1558  lpt->AddText(TString::Format("%4.2lf (%4.2lf)", ci.max_dI, ci.I))->SetTextColor(stokesCols[0]);
1559  lpt->AddText(TString::Format("%4.2lf (%4.2lf)", ci.max_dQ, ci.Q))->SetTextColor(stokesCols[1]);
1560  lpt->AddText(TString::Format("%4.2lf (%4.2lf)", ci.max_dU, ci.U))->SetTextColor(stokesCols[2]);
1561  lpt->AddText(TString::Format("%4.2lf (%4.2lf)", ci.max_dV, ci.V))->SetTextColor(stokesCols[3]);
1562 
1563  auto* rpt = new TPaveText(xmid, epsilon, xup, 0.7);
1564  auto& di = fSummary.deconvolved_filtered[pol][peakInd];
1565  rpt->AddText(TString::Format("%4.2lf (%4.2lf)", di.max_dI, di.I))->SetTextColor(stokesCols[0]);
1566  rpt->AddText(TString::Format("%4.2lf (%4.2lf)", di.max_dQ, di.Q))->SetTextColor(stokesCols[1]);
1567  rpt->AddText(TString::Format("%4.2lf (%4.2lf)", di.max_dU, di.U))->SetTextColor(stokesCols[2]);
1568  rpt->AddText(TString::Format("%4.2lf (%4.2lf)", di.max_dV, di.V))->SetTextColor(stokesCols[3]);
1569 
1570 
1571  for(auto pt : {e, ept, f, lpt_t, rpt_t, lpt_f, rpt_f, lpt, rpt}){
1572  pt->SetBit(kCanDelete, true);
1573  pt->SetTextColor(peakColors[pol][peakInd]);
1574  pt->SetLineColor(peakColors[pol][peakInd]);
1575  pt->SetShadowColor(0);
1576  pt->Draw();
1577  }
1578  }
1579  }
1580 
1581  wholePad->SetBorderSize(2);
1582 
1583 }
1584 
1585 
1586 
1588  AnalysisWaveform* wf = fCoherentFiltered[pol][peakInd][xPol];
1589  fCoherentFiltered[pol][peakInd][xPol] = nullptr;
1590  return wf;
1591 }
1592 
1593 
1595  AnalysisWaveform* wf = fCoherent[pol][peakInd][xPol];
1596  fCoherent[pol][peakInd][xPol] = nullptr;
1597  return wf;
1598 }
1599 
1600 
1601 
1603  AnalysisWaveform* wf = fDeconvolved[pol][peakInd][xPol];
1604  fDeconvolved[pol][peakInd][xPol] = nullptr;
1605  return wf;
1606 }
1607 
1608 
1609 
1611  AnalysisWaveform* wf = fDeconvolvedFiltered[pol][peakInd][xPol];
1612  fDeconvolvedFiltered[pol][peakInd][xPol] = nullptr;
1613  return wf;
1614 }
1615 
1616 
1617 
1618 
1620  FilteredAnitaEvent* f = fEvMin;
1621  fEvMin = nullptr;
1622  return f;
1623 }
1624 
1625 
1626 
1628  FilteredAnitaEvent* f = fEvMinDeco;
1629  fEvMinDeco = nullptr;
1630  return f;
1631 }
1632 
1633 
1634 
1636  FilteredAnitaEvent* f = fEvDeco;
1637  fEvDeco = nullptr;
1638  return f;
1639 }
AnalysisWaveform * getCoherentFiltered(AnitaPol::AnitaPol_t pol, Int_t peakInd=0, bool xPol=false)
Coherently summed filtered (un-deconvolved) waveform accessor for external processes. Only works once per event processed as ownership is transferred to the function caller.
const TGraphAligned * power() const
const AnalysisWaveform * hilbertTransform() const
void process(const FilteredAnitaEvent *fEv, AnitaEventSummary *sum, NoiseMonitor *noiseMonitor=NULL, TruthAnitaEvent *truth=NULL)
Bool_t masked_xpol
was this in a masked phi sector?
static Int_t directlyInsertGeometry(TString pathToLindasFile, AnitaPol::AnitaPol_t pol)
Double_t totalPower
The number of points used in the above estimates.
const TGraphAligned * powerdB() const
Double_t hwAngleXPol
angle with respect to triggering phi sector
Double_t getAntPhiPositionRelToAftFore(Int_t ant, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical)
get antenna phi position relative to ADU5 AFT-FORE line
const UsefulAnitaEvent * getUsefulAnitaEvent() const
void directionAndAntennasToDeltaTs(const std::vector< Int_t > &theAnts, AnitaPol::AnitaPol_t pol, Double_t peakPhiDeg, Double_t peakThetaDeg, std::vector< double > &dts)
From a list of antennas, get a set of dts relative to the first antenna.
AnalysisWaveform * getCoherent(AnitaPol::AnitaPol_t pol, Int_t peakInd=0, bool xPol=false)
Coherently summed (un-filtered, un-deconvolved) waveform accessor for external processes. Only works once per event processed as ownership is transferred to the function caller.
Adu5Pat – The ADU5 Position and Attitude Data.
Definition: Adu5Pat.h:26
Does the event reconstruction, and produces a summary of it.
Definition: AnalysisReco.h:30
Double_t getAntZ(Int_t ant, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical)
get antenna z position
static AnitaEventCalibrator * Instance(int version=0)
Instance generator.
int isInL3Pattern(int phi, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical) const
Returns 1 if given phi-ring had l3 trigger. pol does nothing for A4.
void fillPowerFlags(const FilteredAnitaEvent *fEv, AnitaEventSummary::EventFlags &flags)
Double_t hwAngle
value of average of the peak location over the past 60 min-bias events
Double_t relativeOffAxisDelay(AnitaPol::AnitaPol_t pol, Int_t ant1, Int_t ant2, Double_t phiDeg) const
Get the off axis delay between two antennas for a given phi angle.
static void setTriggerInfoFromPeakPhi(const RawAnitaHeader *header, AnitaPol::AnitaPol_t pol, Int_t peakPhiSector, AnitaEventSummary::PointingHypothesis &peak)
Calculate and fill the info the AnitaEventSummary relating the compatibility of the hardware trigger ...
Double_t impulsivityMeasure
moments about Peak (1st - 5th moments)
InterferometricMap * getZoomMap(AnitaPol::AnitaPol_t pol, UInt_t peakInd=0)
Get a pointer to a finely binned interferometric map stored in memory, once called, you own this InterferometricMap and must delete it.
void reconstructZoom(AnitaPol::AnitaPol_t pol, Int_t peakIndex, Double_t zoomCenterPhiDeg, Double_t zoomCenterThetaDeg, const Adu5Pat *pat=NULL)
produce and store a finely binned interferometric map, (overwrites fineMaps)
static const Int_t numFracPowerWindows
The maximum number of frequency peaks per waveform spectrum.
static const Int_t peaksPerSpectrum
The maximum number of hypotheses storable per polarization */.
Double_t getAntR(Int_t ant, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical)
get antenna r position
Double_t getDeltaTExpected(AnitaPol::AnitaPol_t pol, Int_t ant1, Int_t ant2, Double_t phiWave, Double_t thetaWave) const
Get the expected delay between antenna pairs for a given direction.
static void getSurfChanAntFromRingPhiPol(AnitaRing::AnitaRing_t ring, Int_t phi, AnitaPol::AnitaPol_t pol, Int_t &surf, Int_t &chan, Int_t &ant)
Convert ring-phi-pol to surf-chan-ant.
AnalysisWaveform * getDeconvolved(AnitaPol::AnitaPol_t pol, Int_t peakInd=0, bool xPol=false)
Coherently summed (un-filtered) deconvolved waveform accessor for external processes. Only works once per event processed as ownership is transferred to the function caller.
Double_t max_dI
Integral Stokes Parameters (over the entire waveform)
RawAnitaHeader – The Raw ANITA Event Header.
Bool_t triggered
theta - theta rough
AnitaEventCalibrator – The ANITA Event Calibrator.
const UsefulAdu5Pat * getGPS() const
Double_t totalPowerXpol
Total power in waveform.
static void fillChannelInfo(const FilteredAnitaEvent *fEv, AnitaEventSummary *sum)
Calculate and fill the numbers for Peng&#39;s ChannelInfo object.
USeful in for loops.
AnalysisReco()
Constructor.
Bool_t masked
was this in a triggered xpol phi sector?
void reconstruct(AnitaPol::AnitaPol_t pol, const Adu5Pat *pat=NULL)
produce and store the coarsely binned interferometric map, (overwrites coarseMaps) ...
Int_t run
Run number, assigned on ground.
A minimalistic extension to TGraphAligned for some GUI bells and whistles.
Double_t singleAntennaOffAxisDelay(Double_t deltaPhiDeg) const
virtual void DrawGroup(Option_t *opt="")
Must be overloaded by children (TGraphInteractive*) to return pointer to parent
enum AnitaRing::EAnitaRing AnitaRing_t
Ring enumeration.
size_t checkWavesAndDtsMatch(std::vector< const AnalysisWaveform *> &waves, std::vector< Double_t > &dts)
Bounds checking for coherent averaging. Checks input vectors are the same length and zero pads/trims ...
FilteredAnitaEvent * getEvMinDeco()
void initializeInternals()
Sets default values and zeros pointers for dynamically initialised heap members.
void fillWaveformInfo(AnitaPol::AnitaPol_t pol, Int_t peakInd, AnitaEventSummary::WaveformInfo &info, const FilteredAnitaEvent *fEv, AnalysisWaveform **waveStore, InterferometricMap *h, NoiseMonitor *noiseMonitor, std::vector< double > &I, std::vector< double > &Q, std::vector< double > &U, std::vector< double > &V)
virtual void DrawGroup(Option_t *opt="")
Must be overloaded by children (TGraphInteractive*) to return pointer to parent
const AnalysisWaveform * getRawGraph(UInt_t i) const
Double_t bandwidth[peaksPerSpectrum]
Total power in xPol waveform.
TruthAnitaEvent – The Truth ANITA Event.
static Double_t getPhiSectorCenterPhiDeg(int phi)
As UsefulAnitaEvent is to RawAnitaEvent, UsefulAdu5Pat is to Adu5Pat. Well not quite as useful but yo...
Definition: UsefulAdu5Pat.h:39
double deltaF() const
virtual ~AnalysisReco()
Destructor.
Stores information about a coherently summed waveform (filtered/unfiltered/deconvolved) The coherent ...
static Int_t getAntFromPhiRing(Int_t phi, AnitaRing::AnitaRing_t ring)
get antenna number from phi and ring
void drawSummary(TPad *wholePad, AnitaPol::AnitaPol_t pol)
Draw everything interesting onto a TPad.
AnalysisWaveform * coherentlySum(const FilteredAnitaEvent *fEv, AnitaPol::AnitaPol_t pol, const std::vector< Int_t > &theAnts, Double_t peakPhiDeg, Double_t peakThetaDeg, Double_t *biggestPeakToPeak=NULL, double *forceT0=NULL)
Make a coherently summed waveform for a given polarization, set of antennas in a particular direction...
FilteredAnitaEvent * getEvDeco()
Double_t relativePhaseCenterToAmpaDelays[12][9]
From phase center to AMPAs (hopefully)
void nicelyDeleteInternalFilteredEvents()
does NULL pointer checking deletion on the internally generated FilteredAnitaEvents, fEvMin, fEvMinDeco, fEvDeco
const AnalysisWaveform * getFilteredGraph(UInt_t i) const
A class to take in FiteredAnitaEvents and cross-correlate nearby channels.
Useful in for loops.
const TGraphAligned * hilbertEnvelope() const
void chooseAntennasForCoherentlySumming(int coherentDeltaPhi)
Generate a set of antennas to use to generate the coherent waveform.
void wavesInCoherent(std::vector< const AnalysisWaveform *> &waves, std::vector< Double_t > &dts, std::vector< TGraphAligned *> &grs)
Generate a new set of TGraphAligned such that the peaks are aligned,.
AnalysisWaveform * getDeconvolvedFiltered(AnitaPol::AnitaPol_t pol, Int_t peakInd=0, bool xPol=false)
Coherently summed filtered deconvolved waveform accessor for external processes. Only works once per ...
Common analysis format between UCorrelator and Acclaim.
const TGraphAligned * even() const
Horizontal Polarisation.
Double_t peakTime
Power enclosed within 50_50 width.
InterferometricMap * getMap(AnitaPol::AnitaPol_t pol)
Get a pointer to the coarsely binned interferometric map stored in memory, once called, you own this InterferometricMap and must delete it.
void insertPhotogrammetryGeometry()
Inserts the photogrammetry geometry from AnitaGeomTool into this classes copy of the antenna position...
UInt_t realTime
unixTime of readout
This class is intended to store all the necessary data about an ANITA event for filtering and analysi...
FilteredAnitaEvent * getEvMin()
enum AnitaPol::EAnitaPol AnitaPol_t
Polarisation enumeration.
static AnitaGeomTool * Instance(int anita_version=0)
Instance generator. If version_number == 0, uses AnitaVersion::get();.
AnitaGeomTool – The ANITA Geometry Tool.
Definition: AnitaGeomTool.h:48
Bool_t triggered_xpol
was this in a triggered phi sector?
This class is intended to be the main storage vessel for ANITA waveforms. It is similar in principle ...
const RawAnitaHeader * getHeader() const