InterferometricMap.cxx
1 #include "InterferometricMap.h"
2 #include "AnalysisReco.h" // for the geometric definitions
3 #include "InterferometryCache.h"
4 
5 #include "TAxis.h"
6 #include "TMath.h"
7 #include "TMatrixD.h"
8 
9 #include <iostream>
10 #include "TString.h"
11 #include "UsefulAdu5Pat.h"
12 #include "RampdemReader.h"
13 #include "TruthAnitaEvent.h"
14 #include "TGraphAntarctica.h"
15 #include "TArrowAntarctica.h"
16 #include "TLegend.h"
17 #include "AcclaimClustering.h"
18 
20 
21 std::vector<Double_t> coarseBinEdgesPhi; // has size NUM_BINS_PHI+1
22 std::vector<Double_t> fineBinEdgesPhi; // has size NUM_BINS_PHI_ZOOM_TOTAL+1
23 
24 std::vector<Double_t> coarseBinEdgesTheta; // has size NUM_BINS_THETA+1
25 std::vector<Double_t> fineBinEdgesTheta; // has size NUM_BINS_THETA_ZOOM_TOTAL+1
26 Double_t bin0PhiDeg = -9999;
27 
28 TDecompSVD theSVD;
29 bool doneInitSVD = false;
30 
31 
32 std::vector<Double_t> phiCenterCenterDegs;
33 
34 
46 void Acclaim::InterferometricMap::getDeltaBinRangeSVD(Int_t& dPhiBinLow, Int_t& dPhiBinHigh, Int_t& dThetaBinLow, Int_t& dThetaBinHigh){
47  dPhiBinLow = -NUM_BINS_QUAD_FIT_PHI/2;
48  dPhiBinHigh = dPhiBinLow + NUM_BINS_QUAD_FIT_PHI;
49  dThetaBinLow = -NUM_BINS_QUAD_FIT_THETA/2;
50  dThetaBinHigh = dThetaBinLow + NUM_BINS_QUAD_FIT_THETA;
51 }
52 
53 
54 
55 
56 
68 const TDecompSVD& Acclaim::InterferometricMap::getSVD(){
69 
70  if(!doneInitSVD){
71 
72  // 2D quadratic defined by ax^{2} + by^{2} + cxy + dx + ey + f, so 6 coefficients
73  const int nCoeffs = 6;
74 
75  // get grid offsets
76  int firstBinPhi, lastBinPhi, firstBinTheta, lastBinTheta;
77  getDeltaBinRangeSVD(firstBinPhi, lastBinPhi, firstBinTheta, lastBinTheta);
78 
79  // one row per data point, one column per coefficient
80  TMatrixD A(NUM_BINS_QUAD_FIT_PHI*NUM_BINS_QUAD_FIT_THETA, nCoeffs);
81 
82  int row=0;
83  for(int i=firstBinPhi; i < lastBinPhi; i++){
84  const double dPhi = ZOOM_BIN_SIZE_PHI * i;
85  for(int j=firstBinTheta; j < lastBinTheta; j++){
86  const double dTheta = ZOOM_BIN_SIZE_THETA * j;
87  A(row, 0) = dPhi*dPhi;
88  A(row, 1) = dTheta*dTheta;
89  A(row, 2) = dPhi*dTheta;
90  A(row, 3) = dPhi;
91  A(row, 4) = dTheta;
92  A(row, 5) = 1;
93  row++;
94  }
95  }
96  theSVD.SetMatrix(A);
97  doneInitSVD = true;
98  }
99  return theSVD;
100 }
101 
102 
103 
104 
105 
112 
113  // trigger the creation of the contained graphs upon drawing
114  getSunGraph();
115  getTruthGraph();
116  if(fIsZoomMap){
117  getEdgeBoxGraph();
118  }
119  TH2D::Draw(opt);
120 }
121 
122 
131 void Acclaim::InterferometricMap::ExecuteEvent(int event, int x, int y){
132 
133  if(event == kButton1Double){
134  (void) x;
135  (void) y;
136  new TCanvas();
137  DrawGroup("colz");
138  }
139  TH2D::ExecuteEvent(event, x, y);
140 }
141 
142 
143 
144 
154  if(phiCenterCenterDegs.size()==0){
156  Double_t aftForeOffset = geom->aftForeOffsetAngleVertical*TMath::RadToDeg();
157 
158  Double_t phi0 = -aftForeOffset;
159  if(phi0 < -DEGREES_IN_CIRCLE/2){
160  phi0+=DEGREES_IN_CIRCLE;
161  }
162  else if(phi0 >= DEGREES_IN_CIRCLE/2){
163  phi0-=DEGREES_IN_CIRCLE;
164  }
165 
166  for(int phi=0; phi < NUM_PHI; phi++){
167  phiCenterCenterDegs.push_back(phi0 + PHI_RANGE*phi);
168  }
169  }
170 
171  return phiCenterCenterDegs.at(phi);
172 }
173 
174 
175 
182 
183  if(bin0PhiDeg == -9999){
184  double phi0 = getPhiSectorCenterPhiDeg(0);
185  bin0PhiDeg = phi0 - PHI_RANGE/2;
186  }
187  return bin0PhiDeg;
188 }
189 
190 
191 
192 
199 
200  if(coarseBinEdgesTheta.size()==0) // then not initialized so do it here...
201  {
202 
203  // funk up the theta bin spacing...
204  UInt_t nBinsTheta = NUM_BINS_THETA;
205  Double_t minTheta = MIN_THETA;
206  Double_t maxTheta = MAX_THETA;
207 
208  // calculate the bin spaces in sin(theta)
209  Double_t sinThetaMin = sin(minTheta*TMath::DegToRad());
210  Double_t sinThetaMax = sin(maxTheta*TMath::DegToRad());
211  Double_t sinThetaRange = sinThetaMax - sinThetaMin;
212  Double_t dSinTheta = sinThetaRange/nBinsTheta;
213 
214  // std::vector<Double_t> binEdges(nBinsTheta+1);
215  coarseBinEdgesTheta.reserve(nBinsTheta+1);
216  for(unsigned bt = 0; bt <= nBinsTheta; bt++){
217  Double_t thisSinTheta = sinThetaMin + bt*dSinTheta;
218  Double_t thisTheta = TMath::RadToDeg()*TMath::ASin(thisSinTheta);
219  // coarseBinEdgesTheta.at(bt) = thisTheta;
220  coarseBinEdgesTheta.push_back(thisTheta);
221  }
222  }
223  return coarseBinEdgesTheta;
224 }
225 
226 
233 
234  if(fineBinEdgesTheta.size()==0) // then not initialized so do it here...
235  {
236 
237  UInt_t nBinsTheta = NUM_BINS_THETA_ZOOM_TOTAL;
238  Double_t minTheta = MIN_THETA - THETA_RANGE_ZOOM/2;
239  Double_t maxTheta = MAX_THETA + THETA_RANGE_ZOOM/2;
240 
241  Double_t dTheta = (maxTheta - minTheta) / nBinsTheta;
242  fineBinEdgesTheta.reserve(nBinsTheta+1);
243  for(unsigned bt = 0; bt <= nBinsTheta; bt++){
244  double thisTheta = minTheta + bt*dTheta;
245  fineBinEdgesTheta.push_back(thisTheta);
246  }
247  }
248  return fineBinEdgesTheta;
249 }
250 
251 
252 
253 
254 
261 
262  if(coarseBinEdgesPhi.size()==0) // then not initialized so do it here...
263  {
264  UInt_t nBinsPhi = NUM_BINS_PHI*NUM_PHI;
265  Double_t minPhi = getBin0PhiDeg();
266  Double_t dPhi = double(DEGREES_IN_CIRCLE)/nBinsPhi;
267  // std::vector<Double_t> binEdges(nBinsTheta+1);
268  coarseBinEdgesTheta.reserve(nBinsPhi+1);
269  for(unsigned bp = 0; bp <= nBinsPhi; bp++){
270  Double_t thisPhi = minPhi + dPhi*bp;
271  coarseBinEdgesPhi.push_back(thisPhi);
272  }
273  }
274  return coarseBinEdgesPhi;
275 }
276 
277 
278 
284 const std::vector<Double_t>& Acclaim::InterferometricMap::getFineBinEdgesPhi(){
285 
286  if(fineBinEdgesPhi.size()==0) // then not initialized so do it here...
287  {
288 
289  // funk up the theta bin spacing...
290  UInt_t nBinsPhi = NUM_BINS_PHI_ZOOM_TOTAL;
291  Double_t minPhi = getBin0PhiDeg() - PHI_RANGE_ZOOM/2;
292  // need some extra degrees here to account for the fact that you might get a coarse peak
293  // on the edge of a map, therefore the fine peak might extend off the left/right edge
294  Double_t dPhi = double(DEGREES_IN_CIRCLE + PHI_RANGE_ZOOM)/nBinsPhi;
295  // std::vector<Double_t> binEdges(nBinsTheta+1);
296  fineBinEdgesTheta.reserve(nBinsPhi+1);
297  for(unsigned bp = 0; bp <= nBinsPhi; bp++){
298  Double_t thisPhi = minPhi + dPhi*bp;
299  fineBinEdgesPhi.push_back(thisPhi);
300  }
301  }
302  return fineBinEdgesPhi;
303 }
304 
305 
306 
307 
313 
314  static unsigned defaultCounter = 0;
315  fName = TString::Format("hDefault%u", defaultCounter);
316  defaultCounter++;
317 }
318 
319 
320 
325 
326 
327  if(fIsZoomMap){
328  fName = "hFine";
329  fName += pol == AnitaPol::kVertical ? "ImageV" : "ImageH";
330  fName += TString::Format("%u_%u", peakIndex, eventNumber);
331 
332  fTitle = TString::Format("Event %u ", eventNumber);
333  fTitle += (pol == AnitaPol::kVertical ? "VPOL" : "HPOL");
334  fTitle += TString::Format(" Zoom Map - Peak %u", peakIndex);
335  }
336  else{
337  fName = "hCoarse";
338  fName += pol == AnitaPol::kVertical ? "V" : "H";
339  fName += TString::Format("%u", eventNumber);
340 
341  fTitle = TString::Format("Event %u ", eventNumber);
342  fTitle += (pol == AnitaPol::kVertical ? "VPOL" : "HPOL");
343  }
344 }
345 
346 
347 
348 
349 
350 
351 
352 
353 
354 
355 
356 
357 
368 Acclaim::InterferometricMap::InterferometricMap(Int_t peakInd, Int_t phiSector, Double_t zoomCentrePhi, Double_t phiRange, Double_t zoomCentreTheta, Double_t thetaRange)
369  : fUsefulPat(NULL), truthLat(-9999), truthLon(-9999), truthAlt(-9999)
370 {
371  fIsZoomMap = true;
372  fPeakPhiSector = phiSector;
373  peakIndex = peakInd;
374  Double_t minPhiDesired = zoomCentrePhi - phiRange/2;
375  Double_t maxPhiDesired = zoomCentrePhi + phiRange/2;
376  const std::vector<double> fineBinsPhi = Acclaim::InterferometricMap::getFineBinEdgesPhi();
377  // int minPhiBin, maxPhiBin;
378  minPhiBin = -1;
379  int maxPhiBin = -1;
380  getIndicesOfEdgeBins(fineBinsPhi, minPhiDesired, maxPhiDesired, minPhiBin, maxPhiBin);
381 
382  // std::cerr << "ctr 0" << "\t" << minPhiBin << "\t" << maxPhiBin << "\t" << fineBinsPhi.size() << std::endl;
383 
384  Double_t minThetaDesired = zoomCentreTheta - thetaRange/2;
385  Double_t maxThetaDesired = zoomCentreTheta + thetaRange/2;
386  const std::vector<double> fineBinsTheta = Acclaim::InterferometricMap::getFineBinEdgesTheta();
387  // int minThetaBin, maxThetaBin;
388  minThetaBin = -1;
389  int maxThetaBin = -1;
390  getIndicesOfEdgeBins(fineBinsTheta, minThetaDesired, maxThetaDesired, minThetaBin, maxThetaBin);
391 
392  // std::cerr << "ctr 1" << "\t" << minThetaBin << "\t" << maxThetaBin << "\t" << fineBinsTheta.size() << std::endl;
393 
394  SetBins(maxPhiBin - minPhiBin, &fineBinsPhi[minPhiBin], maxThetaBin - minThetaBin, &fineBinsTheta[minThetaBin]); // changes also errors array (if any)
395  initializeInternals();
396 
397  // std::cerr << "ctr 2" << std::endl;
398 }
399 
400 
401 
406  : fUsefulPat(NULL), truthLat(-9999), truthLon(-9999), truthAlt(-9999)
407 {
408  fIsZoomMap = false;
409  fPeakPhiSector = -1;
410  minPhiBin = -1;
411  minThetaBin = -1;
412  peakIndex = -1;
413  fSigmaTheta = -1;
414  fSigmaPhi = -1;
415  const std::vector<double> coarseBinsPhi = Acclaim::InterferometricMap::getCoarseBinEdgesPhi();
416  const std::vector<double> coarseBinsTheta = Acclaim::InterferometricMap::getCoarseBinEdgesTheta();
417  SetBins(coarseBinsPhi.size()-1, &coarseBinsPhi[0], coarseBinsTheta.size()-1, &coarseBinsTheta[0]);
418 
419  initializeInternals();
420 }
421 
422 
423 
428  deletePat();
429 }
430 
431 
432 void Acclaim::InterferometricMap::Reset(Option_t* opt){
433  TH2D::Reset(opt);
434  deleteChildren();
435 }
436 
437 
442  if(fUsefulPat) {
443  // std::cerr << fUsefulPat->heading << "\t" << std::endl;
444  delete fUsefulPat;
445  }
446  fUsefulPat = NULL;
447 }
448 
449 
450 
457  // std::cerr << __PRETTY_FUNCTION__ << "\t" << this << "\t" << pat << std::endl;
458  deletePat();
459 
460  fUsefulPat = new UsefulAdu5Pat(pat);
461 }
462 
463 
464 
471 
472  if(truth){
473  truthLon = truth->sourceLon;
474  truthLat = truth->sourceLat;
475  truthAlt = truth->sourceAlt;
476  }
477 }
478 
479 
480 
481 
482 
483 
484 
493 
494  pol = thePol;
495  eventNumber = cc->eventNumber[pol];
496  setNameAndTitle();
497 
498  if(!fIsZoomMap){
499 
500  std::vector<Int_t>* combosToUse = NULL;
501  Int_t binsPerPhiSector = GetNbinsPhi()/NUM_PHI;
502  for(Int_t phiSector = 0; phiSector < NUM_PHI; phiSector++){
503  combosToUse = &cc->combosToUseGlobal[phiSector];
504 
505  Int_t startPhiBin = phiSector*binsPerPhiSector;
506  Int_t endPhiBin = startPhiBin + binsPerPhiSector;
507 
508  for(UInt_t comboInd=0; comboInd<combosToUse->size(); comboInd++){
509  Int_t combo = combosToUse->at(comboInd);
510  if(cc->kOnlyThisCombo >= 0 && combo!=cc->kOnlyThisCombo){
511  continue;
512  }
513  for(Int_t phiBin = startPhiBin; phiBin < endPhiBin; phiBin++){
514  for(Int_t thetaBin = 0; thetaBin < GetNbinsTheta(); thetaBin++){
515 
516  Int_t bin = (thetaBin+1)*(GetNbinsPhi()+2) + phiBin+1;
517  Double_t cInterp = cc->getCrossCorrelation(pol, combo, dtCache->coarseDt(pol, combo, phiBin, thetaBin));
518  AddBinContent(bin,cInterp);
519  fEntries++; // otherwise drawing don't work at all
520  }
521  }
522  }
523  }
524 
525  for(Int_t phiSector = 0; phiSector < NUM_PHI; phiSector++){
526  combosToUse = &cc->combosToUseGlobal[phiSector];
527 
528  Double_t normFactor = cc->kOnlyThisCombo < 0 && combosToUse->size() > 0 ? combosToUse->size() : 1;
529  // absorb the removed inverse FFT normalization
530  normFactor*=(cc->numSamples*cc->numSamples);
531 
532  Int_t startPhiBin = phiSector*binsPerPhiSector;
533  Int_t endPhiBin = (phiSector+1)*binsPerPhiSector;
534  for(Int_t phiBin = startPhiBin; phiBin < endPhiBin; phiBin++){
535  for(Int_t thetaBin = 0; thetaBin < GetNbinsTheta(); thetaBin++){
536 
537  Double_t val = GetBinContent(phiBin+1, thetaBin+1);
538  SetBinContent(phiBin+1, thetaBin+1, val/normFactor);
539 
540  if(val > fPeakBinValue){
541  fPeakBinValue = val;
542  // peakPhiDeg = GetPhiAxis()->GetBinLowEdge(phiBin+1);
543  // peakThetaDeg = GetThetaAxis()->GetBinLowEdge(thetaBin+1);
544  fPeakBinPhi = phiBin;
545  fPeakBinTheta = thetaBin;
546  fPeakPhiSector = phiSector;
547  }
548  }
549  }
550  }
551  setPeakInfoJustFromPeakBin(fPeakBinPhi, fPeakBinTheta);
552  }
553 
554  else{
555  // std::cerr << "zmps " << fPeakPhiSector << std::endl;
556  cc->doUpsampledCrossCorrelations(pol, fPeakPhiSector);
557 
558  std::vector<Int_t>* combosToUse = &cc->combosToUseGlobal[fPeakPhiSector];
559 
560  const Int_t offset = cc->numSamplesUpsampled/2;
561  for(UInt_t comboInd=0; comboInd<combosToUse->size(); comboInd++){
562  Int_t combo = combosToUse->at(comboInd);
563  if(cc->kOnlyThisCombo >= 0 && combo!=cc->kOnlyThisCombo){
564  continue;
565  }
566  int ant1 = cc->comboToAnt1s[combo];
567  int ant2 = cc->comboToAnt2s[combo];
568  // for(Int_t thetaBin = 0; thetaBin < NUM_BINS_THETA_ZOOM; thetaBin++){
569  for(Int_t thetaBin = 0; thetaBin < GetNbinsTheta(); thetaBin++){
570  Int_t zoomThetaInd = minThetaBin + thetaBin;
571  // Double_t zoomThetaWave = zoomedThetaWaves[zoomThetaInd];
572  // Double_t partBA = partBAsZoom[pol][combo][zoomThetaInd];
573  Double_t partBA = dtCache->fPartBAsZoom[dtCache->partBAsIndex(pol, combo, zoomThetaInd)]; //)[pol][combo][zoomThetaInd];
574  // Double_t dtFactor = dtFactors[zoomThetaInd];
575  Double_t dtFactor = dtCache->fDtFactors[zoomThetaInd];
576 
577  // for(Int_t phiBin = 0; phiBin < NUM_BINS_PHI_ZOOM; phiBin++){
578  for(Int_t phiBin = 0; phiBin < GetNbinsPhi(); phiBin++){
579  Int_t zoomPhiInd = minPhiBin + phiBin;
580  // Double_t zoomPhiWave = zoomedPhiWaveLookup[zoomPhiInd];
581 
582  int p21 = dtCache->part21sIndex(pol, combo, zoomPhiInd);
583  Double_t offsetLowDouble = dtFactor*(partBA - dtCache->fPart21sZoom[p21]);//[pol][combo][zoomPhiInd]);
584 
585  offsetLowDouble += dtCache->fUseOffAxisDelay > 0 ? dtCache->fOffAxisDelaysDivided[p21] : 0;
586 
587  offsetLowDouble += cc->startTimes[pol][ant1]/cc->correlationDeltaT;
588  offsetLowDouble -= cc->startTimes[pol][ant2]/cc->correlationDeltaT;
589 
590 
591  // hack for floor()
592  Int_t offsetLow = (int) offsetLowDouble - (offsetLowDouble < (int) offsetLowDouble);
593 
594  Double_t deltaT = (offsetLowDouble - offsetLow);
595  offsetLow += offset;
596  Double_t c1 = cc->crossCorrelationsUpsampled[pol][combo][offsetLow];
597  Double_t c2 = cc->crossCorrelationsUpsampled[pol][combo][offsetLow+1];
598  Double_t cInterp = deltaT*(c2 - c1) + c1;
599 
600  Int_t bin = (thetaBin+1)*(GetNbinsPhi()+2) + phiBin+1;
601  AddBinContent(bin, cInterp);
602  fEntries++;
603  }
604  }
605  }
606 
607  Double_t normFactor = cc->kOnlyThisCombo < 0 && combosToUse->size() > 0 ? combosToUse->size() : 1;
608  // absorb the removed inverse FFT normalization
609  normFactor*=(cc->numSamples*cc->numSamples);
610 
611  // set peak finding variables
612  fPeakBinValue = -DBL_MAX;
613 
614  for(Int_t thetaBin = 0; thetaBin < GetNbinsTheta(); thetaBin++){
615  for(Int_t phiBin = 0; phiBin < GetNbinsPhi(); phiBin++){
616  Double_t val = GetBinContent(phiBin+1, thetaBin+1);
617  val /= normFactor;
618  SetBinContent(phiBin+1, thetaBin+1, val);
619  if(val > fPeakBinValue){
620  fPeakBinValue = val;
621  // peakPhiDeg = GetPhiAxis()->GetBinLowEdge(phiBin+1);
622  // peakThetaDeg = GetThetaAxis()->GetBinLowEdge(thetaBin+1);
623  fPeakBinPhi = phiBin;
624  fPeakBinTheta = thetaBin;
625  }
626  }
627  }
628  fitPeakWithQuadratic(fPeakBinPhi, fPeakBinTheta);
629 
630  }
631 
632 }
633 
634 
635 
642 void Acclaim::InterferometricMap::setPeakInfoJustFromPeakBin(Int_t peakPhiBin, Int_t peakThetaBin){
643  fPeakPhi = GetPhiAxis()->GetBinLowEdge(peakPhiBin+1);
644  fPeakTheta = GetThetaAxis()->GetBinLowEdge(peakThetaBin+1);
645  fPeakValue = GetBinContent(peakPhiBin+1, peakThetaBin+1);
646 }
647 
648 
657 void Acclaim::InterferometricMap::fitPeakWithQuadratic(Int_t peakPhiBin, Int_t peakThetaBin){
658 
659  if(!fIsZoomMap){
660  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", not implemented for coarse map." << std::endl;
661  return;
662  }
663 
664  // Get range and check we're not too close to the edge...
665  int minDeltaPhiBin, maxDeltaPhiBin, minDeltaThetaBin, maxDeltaThetaBin;
666  getDeltaBinRangeSVD(minDeltaPhiBin, maxDeltaPhiBin, minDeltaThetaBin, maxDeltaThetaBin);
667 
668  int firstPhiBin = minDeltaPhiBin + peakPhiBin;
669  int lastPhiBin = maxDeltaPhiBin + peakPhiBin;
670  int firstThetaBin = minDeltaThetaBin + peakThetaBin;
671  int lastThetaBin = maxDeltaThetaBin + peakThetaBin;
672 
673  if(firstPhiBin < 0 || lastPhiBin >= GetNbinsPhi() || firstThetaBin < 0 || lastThetaBin >= GetNbinsTheta()){
674  // don't warn as this happens a lot and gets very verbose...
675  // std::cerr << "Warning in " << __PRETTY_FUNCTION__ << ", too close to to the edge to do quadratic peak fit" << std::endl;
676  setPeakInfoJustFromPeakBin(peakPhiBin, peakThetaBin);
677  return;
678  }
679 
680  // put bin values around peak into a vector for the matrix equation we're about to solve
681  TVectorD peakData(NUM_BINS_QUAD_FIT_PHI*NUM_BINS_QUAD_FIT_THETA);
682  int row=0;
683  for(int phiBin=firstPhiBin; phiBin < lastPhiBin; phiBin++){
684  for(int thetaBin=firstThetaBin; thetaBin < lastThetaBin; thetaBin++){
685  peakData[row] = GetBinContent(phiBin+1, thetaBin+1);
686  row++;
687  }
688  }
689 
690  // solve for the quadratic coefficients a,b,c,d,e,f
691  TDecompSVD& svd = const_cast<TDecompSVD&>(getSVD()); // cast away const-ness
692  Bool_t ok = false;
693  TVectorD quadraticCoefficients = svd.Solve(peakData, ok);
694  if(!ok){
695  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << ": something went wrong with the peak interpolation. Will just use peak bin." << std::endl;
696  setPeakInfoJustFromPeakBin(peakPhiBin, peakThetaBin);
697  return;
698  }
699 
700  // pick 2D quadratic coefficients out from the results vector
701  double a = quadraticCoefficients(0);
702  double b = quadraticCoefficients(1);
703  double c = quadraticCoefficients(2);
704  double d = quadraticCoefficients(3);
705  double e = quadraticCoefficients(4);
706  double f = quadraticCoefficients(5);
707 
708 
709  // do some algebra to determine the centre position and peak value
710  const double denom = (4*a*b - c*c);
711  const double x_c = (-2*b*d + c*e)/denom;
712  const double y_c = (-2*a*e + c*d)/denom;
713  const double p_c = a*x_c*x_c + b*y_c*y_c + c*x_c*y_c + d*x_c + e*y_c + f;
714 
715  // Put fit results into member variables containing the results
716  fPeakPhi = x_c + GetPhiAxis()->GetBinLowEdge(peakPhiBin+1);
717  fPeakTheta = y_c + GetThetaAxis()->GetBinLowEdge(peakThetaBin+1);
718  fPeakValue = p_c;
719 
720  // now also get uncertainties, correlation, chisquare
721  TVectorD residual = svd.GetMatrix()*quadraticCoefficients - peakData;
722  fPeakReducedChisquare = residual.Norm2Sqr()/(residual.GetNrows());
723 
724  // @todo, add uncertainties in phi/theta and covariance
725  // would have been better to do a gaussian fit
726  // by taking the logarithm beforehand...
727  fPeakSigmaPhi = 0;
728  fPeakSigmaTheta = 0;
729  fPeakCovariance = 0;
730 }
731 
732 
733 
734 
735 
736 
737 
738 void Acclaim::InterferometricMap::findPeakValues(Int_t numPeaks, std::vector<Double_t>& peakValues, std::vector<Double_t>& phiDegs, std::vector<Double_t>& thetaDegs) const{
739 
740 
741  // In this function I want to find numPeak peaks and set an exclusion zone around each peak
742  // so that the next peak isn't just a close neighbour of a true peak.
743 
744  // Set not crazy, but still debug visible values for peak values/location
745  // -DBL_MAX was causing me some while loop issues in RootTools::getDeltaAngleDeg(...)
746  // which has an unrestricted while loop inside.
747 
748  peakValues.clear();
749  phiDegs.clear();
750  thetaDegs.clear();
751 
752  peakValues.resize(numPeaks, -999);
753  phiDegs.resize(numPeaks, -999);
754  thetaDegs.resize(numPeaks, -999);
755 
756 
757  // As we start, all regions are allowed.
758  // Int_t allowedBins[NUM_BINS_PHI*NUM_PHI][NUM_BINS_THETA];
759  // Int_t allowedBins[NUM_BINS_PHI*NUM_PHI][NUM_BINS_THETA];
760  int nTheta = GetNbinsTheta();
761  int nPhi = GetNbinsPhi();
762  std::vector<short> allowedBins(nPhi*nTheta, 1);
763 
764 
765  for(Int_t peakInd=0; peakInd < numPeaks; peakInd++){
766  Int_t gotHere = 0;
767  for(Int_t phiBin=0; phiBin<nPhi; phiBin++){
768  for(Int_t thetaBin = 0; thetaBin < nTheta; thetaBin++){
769 
770  // if(allowedBins[phiBin][thetaBin] > 0){
771  if(allowedBins[phiBin*nTheta + thetaBin] > 0){
772  // then we are in an allowed region
773 
774  // Double_t mapValue = coarseMap[pol][phiBin][thetaBin];
775  Double_t mapValue = GetBinContent(phiBin+1, thetaBin+1);
776  if(mapValue > peakValues[peakInd]){
777  // higher than the current highest map value
778 
779  gotHere = 1;
780  // Time for something a little tricky to read...
781  // I want to stop bins that are on the edge of allowed regions registering as peaks
782  // if the bins just inside the disallowed regions are higher valued.
783  // To ensure a local maxima so I am going to ensure that all neighbouring
784  // bins are less than the current value.
785  // Checking the 3x3 grid around the current bin (wrapping in phi).
786 
787  // Wrap phi edges
788  Int_t lastPhiBin = phiBin != 0 ? phiBin - 1 : (NUM_BINS_PHI*NUM_PHI) - 1;
789  Int_t nextPhiBin = phiBin != (NUM_BINS_PHI*NUM_PHI) - 1 ? phiBin + 1 : 0;
790 
791 
792  // Is current bin higher than phi neighbours in same theta row?
793  // if(coarseMap[pol][lastPhiBin][thetaBin] < mapValue &&
794  // coarseMap[pol][nextPhiBin][thetaBin] < mapValue){
795  if(GetBinContent(lastPhiBin+1, thetaBin+1) < mapValue &&
796  GetBinContent(nextPhiBin+1, thetaBin+1) < mapValue){
797 
798  gotHere = 2;
799  // So far so good, now check theta neigbours
800  // This doesn't wrap, so I will allow edge cases to pass as maxima
801  Int_t nextThetaBin = thetaBin != (NUM_BINS_THETA) - 1 ? thetaBin+1 : thetaBin;
802  Int_t lastThetaBin = thetaBin != 0 ? thetaBin-1 : thetaBin;
803 
804  // Check theta bins below
805  gotHere = 3;
806  if(thetaBin == 0 || (GetBinContent(lastPhiBin+1, lastThetaBin+1) < mapValue &&
807  GetBinContent(phiBin+1, lastThetaBin+1) < mapValue &&
808  GetBinContent(nextPhiBin+1, lastThetaBin+1) < mapValue)){
809 
810  // Check theta bins above
811  gotHere = 4;
812  if(thetaBin == NUM_BINS_THETA-1 || (GetBinContent(lastPhiBin+1, nextThetaBin+1) < mapValue &&
813  GetBinContent(phiBin+1, nextThetaBin+1) < mapValue &&
814  GetBinContent(nextPhiBin+1, nextThetaBin+1) < mapValue)){
815 
816  // Okay okay okay... you're a local maxima, you can be my next peak.
817  peakValues[peakInd] = GetBinContent(phiBin+1, thetaBin+1);
818  // phiDegs[peakInd] = phiWaveLookup[phiBin]*TMath::RadToDeg();
819  // thetaDegs[peakInd] = thetaWaves[thetaBin]*TMath::RadToDeg();
820  phiDegs[peakInd] = GetPhiAxis()->GetBinLowEdge(phiBin+1);
821  thetaDegs[peakInd] = GetThetaAxis()->GetBinLowEdge(thetaBin+1);
822  // thetaDegs[peakInd] = Acclaim::InterferometricMap::getCoarseBinEdgesTheta()[thetaBin];
823  }
824  }
825  }
826  }
827  }
828  } // thetaBin
829  } // phiBin
830 
831  // Still inside the peakInd loop
832 
833  // Here I set the exclusion zone around the peak bin.
834  if(peakValues[peakInd] >= -999){ // Checks that a peak was found, probably unnecessary
835 
836  for(Int_t phiBin=0; phiBin<nPhi; phiBin++){
837  // Double_t phiDeg = phiWaveLookup[phiBin]*TMath::RadToDeg();
838  Double_t phiDeg = GetPhiAxis()->GetBinLowEdge(phiBin+1);
839  Double_t absDeltaPhi = TMath::Abs(RootTools::getDeltaAngleDeg(phiDegs[peakInd], phiDeg));
840  if(absDeltaPhi < PEAK_PHI_DEG_RANGE){
841 
842  for(Int_t thetaBin = 0; thetaBin < nTheta; thetaBin++){
843 
844  // Double_t thetaDeg = thetaWaves[thetaBin]*TMath::RadToDeg();
845  Double_t thetaDeg = GetThetaAxis()->GetBinLowEdge(thetaBin+1);
846  Double_t absDeltaTheta = TMath::Abs(RootTools::getDeltaAngleDeg(thetaDegs[peakInd], thetaDeg));
847  if(absDeltaTheta < PEAK_THETA_DEG_RANGE){
848 
849  // Now this region in phi/theta is disallowed on the next loop through...
850  // allowedBins[phiBin][thetaBin] = 0;
851  allowedBins[phiBin*nTheta + thetaBin] = 0;
852  }
853  }
854  }
855  }
856  }
857  if(peakValues[peakInd] < 0){
858  std::cerr << "Peak " << peakInd << " = " << peakValues[peakInd] << "\t" << gotHere << std::endl;
859  for(int pi=0; pi <= peakInd; pi++){
860  std::cerr << peakValues[pi] << "\t" << phiDegs[pi] << "\t" << thetaDegs[pi] << std::endl;
861  }
862  }
863  }
864 }
865 
866 
867 
868 
869 
870 
871 
872 void Acclaim::InterferometricMap::initializeInternals(){
873  fThetaAxisInSinTheta = true;
874  pol = AnitaPol::kNotAPol;
875  eventNumber = 0;
876  fPeakPhi = -9999;
877  fPeakTheta = -9999;
878  fPeakValue = -1;
879  fSigmaTheta = -1;
880  fSigmaPhi = -1;
881  setDefaultName();
882 }
883 
884 
885 
886 void Acclaim::InterferometricMap::getIndicesOfEdgeBins(const std::vector<double>& binEdges, Double_t lowVal, Double_t highVal, Int_t& lowIndex, Int_t& highIndex){
887 
888 
889  // double minDiff = 1e9;
890 
891  // get last below
892  lowIndex = 0;
893  for(unsigned i=0; i < binEdges.size(); i++){
894  // if(fabs(binEdges.at(i) - lowVal) < minDiff){
895  // minDiff = fabs(binEdges.at(i) - lowVal);
896  // lowIndex = i;
897  // }
898 
899  if(binEdges.at(i) < lowVal){
900  lowIndex = i;
901  }
902  else{
903  break;
904  }
905  }
906 
907  // if(binEdges.at(0) == fineBinEdgesPhi.at(0)){
908  // highIndex = lowIndex + NUM_BINS_PHI_ZOOM;
909  // }
910  // else{
911  // highIndex = lowIndex + NUM_BINS_THETA_ZOOM;
912  // }
913 
914  highIndex = binEdges.size() - 1;
915  // get last phi above
916  for(int i=binEdges.size()-1; i >= 0; i--){
917  if(binEdges.at(i) > highVal){
918  highIndex = i;
919  }
920  else{
921  break;
922  }
923  }
924 }
925 
927  Acclaim::Clustering::getAngularResolution(snr, fSigmaTheta, fSigmaPhi);
928  // std::cout << fSigmaTheta << "\t" << fSigmaPhi << std::endl;
929 }
930 
932 
933  if(fUsefulPat){
934  double phiWave = fPeakPhi*TMath::DegToRad();
935  double thetaWave = -fPeakTheta*TMath::DegToRad();
936  double sourceLon, sourceLat, sourceAlt, thetaAdj;
937 
938  int success = fUsefulPat->traceBackToContinent3(phiWave, thetaWave, &sourceLon, &sourceLat, &sourceAlt, &thetaAdj);
939 
940  TGraphAntarctica* grSource = new TGraphAntarctica(1, &sourceLon, &sourceLat);
941  grSource->SetName("Source");
942 
943  TPad* thisPad = pad ? pad : new TCanvas();
944  thisPad->cd();
945  grSource->SetMarkerStyle(8);
946 
947  const TGraphInteractive* grPeak = getPeakPointGraph();
948  grSource->SetMarkerColor(grPeak->GetMarkerColor());
949 
951  b->Draw();
952 
953  grSource->Draw("psame");
954  grSource->SetBit(kCanDelete);
955 
956  TGraphAntarctica* grAnita = new TGraphAntarctica(1, &fUsefulPat->longitude, &fUsefulPat->latitude);
957  grAnita->SetName("ANITA");
958 
959  grAnita->SetMarkerColor(kGreen);
960  grAnita->SetMarkerStyle(8);
961  grAnita->Draw("psame");
962  grAnita->SetBit(kCanDelete);
963 
964 
965  TArrowAntarctica* arr = new TArrowAntarctica(grAnita, grSource);
966  arr->SetBit(kCanDelete);
967  arr->SetFillColor(grSource->GetMarkerColor());
968  arr->SetLineColor(grSource->GetMarkerColor());
969  arr->Draw();
970 
971 
972  thisPad->Update();
973 
974  double meanEasting = 0.5*(grSource->GetEasting()[0] + grAnita->GetEasting()[0]);
975  double meanNorthing = 0.5*(grSource->GetNorthing()[0] + grAnita->GetNorthing()[0]);
976 
977  const double zoomRangeEastingNorthing = 500*1000;
978  grSource->GetXaxis()->SetRangeUser(meanEasting - zoomRangeEastingNorthing, meanEasting + zoomRangeEastingNorthing);
979  grSource->GetYaxis()->SetRangeUser(meanNorthing - zoomRangeEastingNorthing, meanNorthing + zoomRangeEastingNorthing);
980 
981  b->SetGrayScale(true);
982  b->SetShowBases(true);
983 
984  TLegend* l = new TLegend(0.79, 0.69, 0.99, 0.99);
985  l->AddEntry(grAnita, "ANITA", "p");
986  l->AddEntry(grSource, "Source", "p");
987  l->AddEntry(arr, "Projection", "l");
988  l->Draw();
989 
990  if(fSigmaTheta > 0 && fSigmaPhi > 0){
991 
992  const int numSigma = 3;
993  const int numPointsPerContour = 100;
994  const double x0 = phiWave;
995  const double y0 = thetaWave;
996 
997  for(int sigma = 1; sigma <= numSigma; sigma++){
998 
999  TGraphAntarctica* grSigma = new TGraphAntarctica();
1000  grSigma->SetName(TString::Format("%d_sigma_contour", sigma));
1001  grSigma->SetBit(kCanDelete);
1002 
1003  const double sigmaThetaRad = sigma*fSigmaTheta*TMath::DegToRad();
1004  const double sigmaPhiRad = sigma*fSigmaPhi*TMath::DegToRad();
1005 
1006  for(int point=0; point < numPointsPerContour; point++){
1007 
1008  // trace out an ellipse...
1009  // 1.5 rather than 0.5 as +ve theta is down in the UsefulAdu5Pat
1010  // so this will stop lines getting drawn across the top of the ellipse
1011  // if it goes over the horizon
1012  double alpha = 1.5*TMath::Pi() + TMath::TwoPi()*point/(numPointsPerContour - 1); // -1 to make a complete loop
1013  double x = sigmaThetaRad*cos(alpha);
1014  double y = sigmaPhiRad*sin(alpha);
1015 
1016  double lon, lat, alt, dTheta = 0;
1017  int success = fUsefulPat->traceBackToContinent3(x+x0, y+y0, &lon, &lat, &alt, &dTheta);
1018 
1019  if(fabs(dTheta) <= 1e-8){
1020  grSigma->SetPoint(grSigma->GetN(), lon, lat);
1021  }
1022  }
1023 
1024  if(grSigma->GetN() > 0){
1025  grSigma->SetLineStyle(1+sigma);
1026  grSigma->Draw("lsame");
1027  }
1028  else{
1029  delete grSigma;
1030  }
1031  }
1032  }
1033 
1034  return thisPad;
1035  }
1036  return pad;
1037 }
1038 
1039 
1040 
1041 
1042 const Acclaim::TGraphInteractive* Acclaim::InterferometricMap::getPeakPointGraph(){
1043 
1044  TString name = "grPeak";
1045  TGraphInteractive* grPeak = const_cast<TGraphInteractive*>(findChild(name));
1046  if(grPeak==NULL){
1047  grPeak = new TGraphInteractive(1, &fPeakPhi, &fPeakTheta, "p");
1048  grPeak->SetName(name);
1049  addGuiChild(grPeak);
1050  }
1051  grPeak->SetMarkerColor(GetLineColor());
1052  grPeak->SetMarkerStyle(8);
1053  grPeak->SetMarkerSize(1);
1054  return grPeak;
1055 
1056 }
1057 
1058 
1059 const Acclaim::TGraphInteractive* Acclaim::InterferometricMap::getSunGraph(){
1060 
1061  TString name = "grSun";
1062  TGraphInteractive* grSun = const_cast<TGraphInteractive*>(findChild(name));
1063  if(fUsefulPat && grSun==NULL){
1064  Double_t phiDeg, thetaDeg;
1065  fUsefulPat->getSunPosition(phiDeg, thetaDeg);
1066 
1067  const double phi0 = getBin0PhiDeg();
1068  phiDeg = phiDeg < phi0 ? phiDeg + DEGREES_IN_CIRCLE : phiDeg;
1069  phiDeg = phiDeg >= phi0 + DEGREES_IN_CIRCLE ? phiDeg - DEGREES_IN_CIRCLE : phiDeg;
1070  thetaDeg*=-1;
1071 
1072  grSun = new TGraphInteractive(1, &phiDeg, &thetaDeg, "p");
1073  grSun->SetName(name);
1074  addGuiChild(grSun);
1075  }
1076  grSun->SetMarkerStyle(kOpenCircle);
1077  grSun->SetMarkerSize(1);
1078  return grSun;
1079 }
1080 
1081 
1082 const Acclaim::TGraphInteractive* Acclaim::InterferometricMap::getTruthGraph(){
1083 
1084  const char* name = "grTruth";
1085  TGraphInteractive* grTruth = const_cast<TGraphInteractive*>(findChild(name));
1086 
1087  if(fUsefulPat && grTruth == NULL && truthLon > -999 && truthLat > -999 && truthAlt > -999){
1088  Double_t thetaDeg, phiDeg;
1089  fUsefulPat->getThetaAndPhiWave(truthLon, truthLat, truthAlt, thetaDeg, phiDeg);
1090 
1091  thetaDeg*=-TMath::RadToDeg();
1092  phiDeg*=TMath::RadToDeg();
1093 
1094  const double phi0 = getBin0PhiDeg();
1095  phiDeg = phiDeg < phi0 ? phiDeg + DEGREES_IN_CIRCLE : phiDeg;
1096  phiDeg = phiDeg >= phi0 + DEGREES_IN_CIRCLE ? phiDeg - DEGREES_IN_CIRCLE : phiDeg;
1097 
1098  grTruth = new TGraphInteractive(1, &phiDeg, &thetaDeg, "p");
1099  addGuiChild(grTruth);
1100  // std::cerr << phiDeg << "\t" << thetaDeg << "\t" << std::endl;
1101  }
1102  if(grTruth){
1103  grTruth->SetMarkerStyle(kFullStar);
1104  grTruth->SetMarkerSize(1.5);
1105  grTruth->SetMarkerColor(kRed);
1106  }
1107  return grTruth;
1108 
1109 }
1110 
1111 
1112 const Acclaim::TGraphInteractive* Acclaim::InterferometricMap::getEdgeBoxGraph(){
1113 
1114  const char* name = "grEdgeBox";
1115  TGraphInteractive* grEdgeBox = const_cast<TGraphInteractive*>(findChild(name));
1116 
1117  if(grEdgeBox==NULL){
1118  grEdgeBox = new TGraphInteractive(0, NULL, NULL, "l");
1119  const TAxis* phiAxis = GetPhiAxis();
1120  const TAxis* thetaAxis = GetThetaAxis();
1121  // left->right across bottom edge
1122  for(int phiBin=1; phiBin <= GetNbinsPhi()+1; phiBin++){
1123  grEdgeBox->SetPoint(grEdgeBox->GetN(), phiAxis->GetBinLowEdge(phiBin), thetaAxis->GetBinLowEdge(1));
1124  }
1125  // bottom->top on right edge
1126  for(int thetaBin=1; thetaBin <= GetNbinsTheta()+1; thetaBin++){
1127  grEdgeBox->SetPoint(grEdgeBox->GetN(), phiAxis->GetBinLowEdge(GetNbinsPhi()+1), thetaAxis->GetBinLowEdge(thetaBin));
1128  }
1129  // right->left on top edge
1130  for(int phiBin=GetNbinsPhi()+1; phiBin > 0; phiBin--){
1131  grEdgeBox->SetPoint(grEdgeBox->GetN(), phiAxis->GetBinLowEdge(phiBin), thetaAxis->GetBinLowEdge(GetNbinsTheta()+1));
1132  }
1133  // top->bottom on left edge
1134  for(int thetaBin=GetNbinsTheta()+1; thetaBin > 0; thetaBin--){
1135  grEdgeBox->SetPoint(grEdgeBox->GetN(), phiAxis->GetBinLowEdge(1), thetaAxis->GetBinLowEdge(thetaBin));
1136  }
1137  addGuiChild(grEdgeBox);
1138  }
1139  grEdgeBox->SetLineWidth(3);
1140  grEdgeBox->SetLineColor(GetLineColor());
1141 
1142  return grEdgeBox;
1143 
1144 }
1145 
1146 
1147 
1148 Int_t Acclaim::InterferometricMap::getPhiSectorFromPhiRough(double phiRough){
1149  Double_t phi0 = getBin0PhiDeg();
1150  return static_cast<Int_t>((phiRough - phi0)/PHI_RANGE);
1151 }
double coarseDt(int pol, int combo, int phiBin, int thetaBin)
Look up the delay for the antenna pair / polarization at a given angle.
Double_t sourceLat
RF position when leaving the ice: Latitude (using icemc model)
static const std::vector< Double_t > & getFineBinEdgesTheta()
void addTruthInfo(const TruthAnitaEvent *truth)
std::vector< Int_t > comboToAnt1s
Vector mapping combo index to ant1.
Adu5Pat – The ADU5 Position and Attitude Data.
Definition: Adu5Pat.h:26
virtual void Draw(Option_t *opt="")
static const std::vector< Double_t > & getFineBinEdgesPhi()
void setPeakInfoJustFromPeakBin(Int_t peakPhiBin, Int_t peakThetaBin)
static const std::vector< Double_t > & getCoarseBinEdgesTheta()
Double_t correlationDeltaT
nominalSamplingDeltaT/UPSAMPLE_FACTOR, deltaT of for interpolation.
int fUseOffAxisDelay
Should we use the off-axis delay? Set to 1 or 0 as it&#39;s used in a multiplication for speed...
Double_t sourceLon
RF position when leaving the ice: Longitude (using icemc model)
Double_t sourceAlt
RF position when leaving the ice: Altitude (using icemc model)
virtual void Draw(Option_t *opt)
std::vector< double > fDtFactors
Multiplier factor for the finely binned InterferometricMap.
void Fill(AnitaPol::AnitaPol_t pol, CrossCorrelator *cc, InterferometryCache *dtCache)
std::vector< Int_t > comboToAnt2s
Vector mapping combo index to ant2.
void fitPeakWithQuadratic(Int_t peakPhiBin, Int_t peakThetaBin)
Fit a 2D quadratic function to the bins around the peak of the map. Only implemented for zoomed maps...
std::vector< double > fOffAxisDelaysDivided
Same as fOffAxisDelays, but delays scaled to remove an operation from an inner loop in Interfermetric...
USeful in for loops.
std::vector< double > fPartBAsZoom
Partial caching for the finely binned InterferometricMap.
A minimalistic extension to TGraphAligned for some GUI bells and whistles.
UInt_t eventNumber[AnitaPol::kNotAPol]
For tracking event number.
Double_t fSigmaPhi
Estimate of the pointing resolution from the waveform SNR.
std::vector< Int_t > combosToUseGlobal[NUM_PHI]
Depends on L3 trigger for global image.
int partBAsIndex(int pol, int combo, int fineThetaBin)
Get the index for part of the deltaT calculation for the finely binned InterferometricMap.
Double_t fSigmaTheta
Width of peak theta.
TruthAnitaEvent – The Truth ANITA Event.
static Double_t getPhiSectorCenterPhiDeg(int phi)
Int_t numSamples
Number of samples in waveform after padding.
As UsefulAnitaEvent is to RawAnitaEvent, UsefulAdu5Pat is to Adu5Pat. Well not quite as useful but yo...
Definition: UsefulAdu5Pat.h:39
virtual void ExecuteEvent(int event, int x, int y)
Vertical Polarisation.
A class to take in FiteredAnitaEvents and cross-correlate nearby channels.
Int_t numSamplesUpsampled
Number of samples in waveform after padding and up sampling.
Double_t crossCorrelationsUpsampled[AnitaPol::kNotAPol][336][NUM_SAMP *2 *6 *2]
Upsampled cross correlations.
Class to cache the deltaTs or parts of their calculation for fast map making.
std::vector< double > fPart21sZoom
Partial caching for the finely binned InterferometricMap.
void setResolutionEstimateFromWaveformSNR(double snr)
static const std::vector< Double_t > & getCoarseBinEdgesPhi()
void addGpsInfo(const Adu5Pat *pat)
virtual void SetPoint(Int_t i, Double_t lon, Double_t lat)
Draw an arrow between two lon/lat points.
enum AnitaPol::EAnitaPol AnitaPol_t
Polarisation enumeration.
static AnitaGeomTool * Instance(int anita_version=0)
Instance generator. If version_number == 0, uses AnitaVersion::get();.
Int_t kOnlyThisCombo
For debugging, only fill histograms with one particular antenna pair.
AnitaGeomTool – The ANITA Geometry Tool.
Definition: AnitaGeomTool.h:48
int part21sIndex(int pol, int combo, int finePhiBin)