FourierBuffer.cxx
1 #include "FourierBuffer.h"
2 #include "TMath.h"
3 #include "FFTWComplex.h"
4 #include "TSpectrum.h"
5 #include "RayleighHist.h"
6 #include "TF1.h"
7 #include "FilteredAnitaEvent.h"
8 #include "TVirtualPad.h"
9 #include "TMath.h"
10 #include "TCanvas.h"
11 #include "RawAnitaHeader.h"
12 #include "RootTools.h"
13 #include "TROOT.h"
14 #include "AnitaDataset.h"
15 #include "FilterStrategy.h"
16 #include "ProgressBar.h"
17 #include "QualityCut.h"
18 #include "AcclaimFilters.h"
19 #include "FFTtools.h"
20 #include "AcclaimFilters.h"
21 #define IS_ROOT_6 (ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0))
22 #define IS_ROOT_6_06_08 (ROOT_VERSION_CODE >= ROOT_VERSION(6,6,8))
23 
24 
25 
26 
33  doneVectorInit(false), fCurrentlyLoadingHistory(false), fForceLoadHistory(false), eventsInBuffer(0), fMinFitFreq(Filters::Bands::anitaHighPassGHz), fMaxFitFreq(Filters::Bands::anitaLowPassGHz), fNumSkipped(0){
34 
35  bufferSize = theBufferSize <= 0 ? 1000 : theBufferSize;
36  df = -1;
37 
38  // will initialize this dynamically to get around this no-copy-constructor bullshit
39  fSpectrum = NULL;
40  const char* rayleighFuncText = "([0]*x/([1]*[1]))*exp(-x*x/(2*[1]*[1]))";
41  for(int ant=0; ant < NUM_SEAVEYS; ant++){
42  summaryPads[ant] = NULL;
43  }
44 
45 
46 #if IS_ROOT_6_06_08
47  fRay = new TF1("fRay", rayleighFuncText, 0, 1e4, TF1::EAddToList::kNo);
48 #else
49  fRay = new TF1("fRay", rayleighFuncText, 0, 1e4);
50 #endif
51 }
52 
53 
54 
55 
60 void Acclaim::FourierBuffer::initGraphAndVector(std::vector<double> vec[][NUM_SEAVEYS],
61  std::vector<TGraphFB>* gr,
62  int n, double df, double defaultVal){
63  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
65 
66  if(gr){
67  gr[pol].reserve(NUM_SEAVEYS);
68  }
69 
70  for(int ant=0; ant < NUM_SEAVEYS; ant++){
71  if(vec){
72  vec[pol][ant].resize(n, defaultVal);
73  }
74 
75  if(gr){
76  gr[pol].push_back(TGraphFB(this, ant, pol, n));
77  for(int freqBin=0; freqBin < n; freqBin++){
78  double f = df*freqBin;
79  gr[pol][ant].GetX()[freqBin] = f;
80  gr[pol][ant].GetY()[freqBin] = defaultVal;
81  }
82  }
83  }
84  }
85 }
86 
87 
88 
89 
96 void Acclaim::FourierBuffer::initVectors(int n, double df){
97 
98  initGraphAndVector(spectrumAmplitudes, grSpectrumAmplitudes, n, df, 0);
99  initGraphAndVector(chiSquares, grChiSquares, n, df, 0);
100  initGraphAndVector(chiSquaresRelativeToSpectrum, grChiSquaresRelativeToSpectrum, n, df, 0);
101  initGraphAndVector(NULL, grReducedChiSquares, n, df, 0);
102  initGraphAndVector(NULL, grReducedChiSquaresRelativeToSpectrum, n, df, 0);
103  initGraphAndVector(probs, grProbs, n, df, 0);
104  initGraphAndVector(fitAmplitudes, grAmplitudes, n, df, 0);
105  initGraphAndVector(sumPowers, NULL, n, df, 0);
106  initGraphAndVector(lastAmps, grLastAmps, n, df, 0);
107  initGraphAndVector(NULL, grNDFs, n, df, 0);
108  initGraphAndVector(chanChiSquares, NULL, n, df, 0);
109 
110  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
112 
113  for(int ant=0; ant < NUM_SEAVEYS; ant++){
114  ndfs[pol][ant].resize(n, 0);
115 
116  hRays[pol][ant].resize(n, NULL);
117  for(int freqBin=0; freqBin < n; freqBin++){
118  double f = df*1e3*freqBin;
119  TString name = TString::Format("hRayleigh_%d_%d_%d", ant, pol, freqBin);
120  const char* polChar = pol == AnitaPol::kHorizontal ? "H" : "V";
121  int phiName = (ant%NUM_PHI)+1;
122  int ring = ant / NUM_PHI;
123  const char* ringChar = ring == 0 ? "T" : ring == 1 ? "M" : "B";
124  TString title = TString::Format("Distribution of amplitudes %d%s%s %4.1lf MHz", phiName, ringChar, polChar, f);
125  title += ";Amplitude (mV/MHz?); Events per bin";
126  hRays[pol][ant].at(freqBin) = new Acclaim::RayleighHist(this, name, title);
127  hRays[pol][ant].at(freqBin)->SetDirectory(0); // hide from when .ls is done in MagicDisplay
128  hRays[pol][ant].at(freqBin)->freqMHz = df*1e3*freqBin;
129  }
130  }
131  }
132 
133  // need to do this at the end so the vector doesn't reallocate the memory (also reserved it too now so doubly fixed)
134  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
136  for(int ant=0; ant < NUM_SEAVEYS; ant++){
137 
138  // get them to know about eachother
139 
140 
141  std::vector<Acclaim::TGraphFB*> grAmpVec;
142  grAmpVec.push_back(&grLastAmps[pol][ant]);
143  grAmpVec.push_back(&grAmplitudes[pol][ant]);
144  grAmpVec.push_back(&grSpectrumAmplitudes[pol][ant]);
145  Acclaim::TGraphFB::setDrawingDependencies(grAmpVec);
146 
147  std::vector<Acclaim::TGraphFB*> grChiSqVec;
148  grChiSqVec.push_back(&grReducedChiSquares[pol][ant]);
149  grChiSqVec.push_back(&grReducedChiSquaresRelativeToSpectrum[pol][ant]);
150 
151  Acclaim::TGraphFB::setDrawingDependencies(grChiSqVec);
152  }
153  }
154 
155  doneVectorInit = true;
156 }
157 
158 
159 
160 
161 
166 
167  if(fSpectrum){
168  delete fSpectrum;
169  fSpectrum = NULL;
170  }
171 
172  for(int pol=0; pol < AnitaPol::kNotAPol; pol++){
173  for(int ant=0; ant < NUM_SEAVEYS; ant++){
174 
175  for(unsigned i=0; i < hRays[pol][ant].size(); i++){
176  if(hRays[pol][ant].at(i)){
177  delete hRays[pol][ant].at(i);
178  hRays[pol][ant].at(i) = NULL;
179  }
180  }
181  }
182  }
183 
184  for(int ant=0; ant < NUM_SEAVEYS; ant++){
185  if(summaryPads[ant]){
186  delete summaryPads[ant];
187  summaryPads[ant] = NULL;
188  }
189  }
190 }
191 
192 
193 
194 
195 
210 
211 
212  // do dynamic initialization, need this first in case we return from this function before the end
213  if(!doneVectorInit){
214  // arbitrarily choose 1TH
216  const TGraphAligned* grPower = wave->power();
217  df = grPower->GetX()[1] - grPower->GetX()[0];
218  initVectors(grPower->GetN(), df);
219  }
220 
221 
222 
223  // don't add nasty events that have crazy amounts of power or other pathologies
224  Bool_t isGoodEvent = QualityCut::applyAll(fEv->getUsefulAnitaEvent());
225  if(!isGoodEvent){
226  fNumSkipped++;
227  // then do nothing
228  return eventNumbers.size();
229  }
230 
231  // handle use in MagicDisplay where refreshing event display on same event...
232  // things still won't be exactly right if you do anything other than repeat the same event
233  // or move forwards sequentially...
234  if(eventNumbers.size() > 0 && fEv->getHeader()->eventNumber == eventNumbers.back()){
235  // However, if we've asked to load the history of an event, we've probably just jumped to that event in MagicDisplay
236  // I'll create an exception to this rule if fForceLoadHistory is true
237  if(!fForceLoadHistory){
238  return eventNumbers.size();
239  }
240  }
241 
242 
243  if(!fCurrentlyLoadingHistory && fForceLoadHistory){
244  automagicallyLoadHistory(fEv);
245  fForceLoadHistory = false;
246  }
247 
248  const RawAnitaHeader* header = fEv->getHeader();
249  eventNumbers.push_back(header->eventNumber);
250  runs.push_back(header->run);
251 
252  bool anyUpdated = false; // should all get updated at the same time, but whatever...
253 
254  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
256  for(int ant=0; ant < NUM_SEAVEYS; ant++){
257 
258  const AnalysisWaveform* wave = fEv->getFilteredGraph(ant, pol);
259  const TGraphAligned* grPower = wave->power();
260 
261  // quick sanity check
262  if(grPower->GetN() != (int)sumPowers[pol][ant].size()){
263  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << ", unexpected waveform size" << std::endl;
264  }
265 
266  // for old compilers, push back copy of empty vector for speed.
267  // then get reference that vector in the list
268  powerRingBuffers[pol][ant].push_back(std::vector<double>(0));
269  std::vector<double>& freqVec = powerRingBuffers[pol][ant].back();
270  freqVec.assign(grPower->GetY(), grPower->GetY()+grPower->GetN());
271 
272  // update sum of power
273  //g_power.SetPoint(i, i * df, the_fft[i].getAbsSq()*2/fft_len/50/1000);
274 
275  // need *50*1000/2 = 25000
276  const double cosminPowerConversionFactor = 25000*grPower->GetN();
277 
278  for(int freqInd=0; freqInd < grPower->GetN(); freqInd++){
279  sumPowers[pol][ant].at(freqInd) += grPower->GetY()[freqInd];
280  double f = df*freqInd;
281  if(f >= fMinFitFreq && f < fMaxFitFreq){
282 
283  double amp = TMath::Sqrt(grPower->GetY()[freqInd]*cosminPowerConversionFactor);
284 
285  bool updated = hRays[pol][ant].at(freqInd)->add(amp);
286  grLastAmps[pol][ant].GetY()[freqInd] = amp;
287  lastAmps[pol][ant][freqInd] = amp;
288 
289  if(updated){
290  anyUpdated = true;
291  hRays[pol][ant].at(freqInd)->getRayleighFitParams(fitAmplitudes[pol][ant][freqInd],
292  chiSquares[pol][ant][freqInd],
293  ndfs[pol][ant][freqInd]);
294 
295  grChiSquares[pol][ant].GetY()[freqInd] = chiSquares[pol][ant][freqInd];
296  if(ndfs[pol][ant][freqInd] > 0){
297 
298  grReducedChiSquares[pol][ant].GetY()[freqInd] = chiSquares[pol][ant][freqInd]/ndfs[pol][ant][freqInd];
299 
300  grNDFs[pol][ant].GetY()[freqInd] = ndfs[pol][ant][freqInd];
301  grAmplitudes[pol][ant].GetY()[freqInd] = fitAmplitudes[pol][ant][freqInd];
302  }
303  }
304  double distAmp = 0;
305  if(spectrumAmplitudes[pol][ant][freqInd] > 0){
306  distAmp = spectrumAmplitudes[pol][ant][freqInd];
307  chiSquaresRelativeToSpectrum[pol][ant].at(freqInd) = hRays[pol][ant].at(freqInd)->getRayleighChiSquare(&spectrumAmplitudes[pol][ant][freqInd]);
308 
309  }
310  else{
311  distAmp = hRays[pol][ant].at(freqInd)->getAmplitude();
312  chiSquaresRelativeToSpectrum[pol][ant].at(freqInd) = chiSquares[pol][ant][freqInd];
313  }
314  grChiSquaresRelativeToSpectrum[pol][ant].GetY()[freqInd] = chiSquaresRelativeToSpectrum[pol][ant].at(freqInd);
315 
316  if(ndfs[pol][ant][freqInd] > 0){
317  grReducedChiSquaresRelativeToSpectrum[pol][ant].GetY()[freqInd] = chiSquaresRelativeToSpectrum[pol][ant].at(freqInd)/ndfs[pol][ant][freqInd];
318  }
319 
320  // if(distAmp > 0){
321  // chanChisquare[pol][ant] += (amp*amp)/(distAmp*distAmp);
322  // chanNdf[pol][ant] += 2;
323  // }
324 
325 
326  double prob = hRays[pol][ant].at(freqInd)->getOneMinusCDF(amp, distAmp);
327 
328  double probVal = probVal = prob > 0 ? TMath::Log10(prob) : 0;
329 
330  // if(!TMath::Finite(probVal)){
331  // std::cout << probVal << "\t" << prob << std::endl;
332  // }
333 
334  probs[pol][ant].at(freqInd) = probVal;
335  grProbs[pol][ant].GetY()[freqInd] = probVal;
336  }
337  }
338 
339  double sumChanChiSquares = 0;
340  int n=0;
341  double sumSquaredChanChiSquares = 0;
342  for(int freqInd=0; freqInd < grPower->GetN(); freqInd++){
343  double amp = lastAmps[pol][ant][freqInd];
344  if(amp > 0){
345  double realAmp = fitAmplitudes[pol][ant][freqInd];
346  chanChiSquares[pol][ant][freqInd] = (amp*amp)/(realAmp*realAmp);
347  sumChanChiSquares += chanChiSquares[pol][ant][freqInd];
348  sumSquaredChanChiSquares += chanChiSquares[pol][ant][freqInd]*chanChiSquares[pol][ant][freqInd];
349  n++;
350 
351  // std::cout << "(" << amp << ", " << realAmp << ")" << std::endl;
352  // std::cout << "(" << chanChiSquares[pol][ant][freqInd] << ")" << std::endl;
353  }
354  }
355  // std::cout << std::endl;
356 
357  if(n > 0){
358  meanChanChiSquare[pol][ant] = sumChanChiSquares/n;
359  varChanChiSquare[pol][ant] = sumSquaredChanChiSquares/n - meanChanChiSquare[pol][ant]*meanChanChiSquare[pol][ant];
360  }
361  else{
362  meanChanChiSquare[pol][ant] = 0;
363  varChanChiSquare[pol][ant] = 0;
364  }
365 
366  // if(!fCurrentlyLoadingHistory){
367  // // std::cout << pol << "\t" << ant << "\t" << sumChanChiSquares << "\t" << sumSquaredChanChiSquares << "\t" << meanChanChiSquare[pol][ant] << "\t" << varChanChiSquare[pol][ant] << "\t" << n << std::endl;
368  // // std::cout << pol << "\t" << ant << "\t" << meanChanChiSquare[pol][ant] << "\t" << varChanChiSquare[pol][ant] << "\t" << n << std::endl;
369  // }
370  // if(!fCurrentlyLoadingHistory){
371  // std::cout << pol << "\t" << ant << "\t" << hChanChiSquares[pol][ant]->GetMean() << "\t" << hChanChiSquares[pol][ant]->GetRMS() << std::endl;
372  // }
373  // if(!fCurrentlyLoadingHistory){
374  // std::cout << pol << "\t" << ant << "\t" << chanChisquare[pol][ant] << "\t" << chanNdf[pol][ant] << std::endl;
375  // }
376  }
377  }
378 
379  // update the spectral amplitudes if we updated the rayleigh distributions
380  if(anyUpdated){
381  int firstSpecInd = 0;
382 
383  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
385  for(int ant=0; ant < NUM_SEAVEYS; ant++){
386 
387  int lastSpecInd = int((isAlfaBandpassed(ant,pol) ? Filters::Bands::alfaLowPassGHz : fMaxFitFreq)/df);
388  int nf = fitAmplitudes[pol][ant].size();
389 
390  // copy the fitted amplitudes into the background array
391  // (before applying the TSpectrum background thing)
392  for(int freqInd = 0; freqInd < nf; freqInd++){
393  spectrumAmplitudes[pol][ant][freqInd] = fitAmplitudes[pol][ant][freqInd];
394  }
395 
396  // do the spectral analysis of the amplitudes
397  getBackgroundSpectrum(&spectrumAmplitudes[pol][ant][firstSpecInd],
398  lastSpecInd - firstSpecInd);
399 
400  // update summary graphs
401  for(int freqInd = 0; freqInd < nf; freqInd++){
402  grSpectrumAmplitudes[pol][ant].GetY()[freqInd] = spectrumAmplitudes[pol][ant][freqInd];
403  }
404  }
405  }
406  }
407 
408 
409  // if(!fCurrentlyLoadingHistory){
410  // for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
411  // AnitaPol::AnitaPol_t pol = (AnitaPol::AnitaPol_t) polInd;
412  // for(int ant=0; ant < NUM_SEAVEYS; ant++){
413  // std::cout << pol << "\t" << ant << "\t" << eventPower[pol][ant] << "\t" << expectedThermalPower[pol][ant] << std::endl;
414  // }
415  // }
416  // }
417  eventsInBuffer++;
418 
419  removeOld();
420  return eventNumbers.size();
421 }
422 
423 
424 
425 
426 
443 TH1D* Acclaim::FourierBuffer::makeChanChisquareHist(AnitaPol::AnitaPol_t pol, Int_t ant, TPad* pad, const char* drawOpt) const{
444 
445  TString hName = TString::Format("hChanChiSquare_%d_%d", pol, ant);
446  TH1D* h = new TH1D(hName, hName, 8, 0, 24);
447  // std::cout << "filling " << pol << "\t" << ant << ":";
448  for(unsigned freqInd=0; freqInd < sumPowers[pol][ant].size(); freqInd++){
449  h->Fill(chanChiSquares[pol][ant][freqInd]);
450  }
451  // std::cout << std::endl;
452 
453  if(!pad){
454  new TCanvas();
455  }
456  else{
457  pad->cd();
458  }
459  h->Draw(drawOpt);
460  return h;
461 }
462 
463 
464 
465 
472 
473  Int_t nPopped = 0;
474  while((int)eventNumbers.size() > bufferSize){
475  eventNumbers.pop_front();
476  runs.pop_front();
477 
478  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
480  for(int ant=0; ant < NUM_SEAVEYS; ant++){
481  std::vector<double>& removeThisPower = powerRingBuffers[pol][ant].front();
482  for(unsigned int freqInd=0; freqInd < removeThisPower.size(); freqInd++){
483  sumPowers[pol][ant].at(freqInd) -= removeThisPower.at(freqInd);
484  }
485  powerRingBuffers[pol][ant].pop_front();
486  }
487  }
488  eventsInBuffer--;
489  nPopped++;
490  }
491  return nPopped;
492 }
493 
494 
501 
502  fCurrentlyLoadingHistory = true;
503  bool loadedHistory = false;
504 
505  const int safetyMargin = 200; // we don't add self triggered blasts or SURF saturated events, but I don't know how many there are before I try
506  const int numEventsToLoopOver = bufferSize + safetyMargin; // so do a little more than the minimum
507 
508  Int_t run = fEv->getHeader()->run;
509  UInt_t eventNumber = fEv->getHeader()->eventNumber;
510 
511  // if this FourierBuffer is inside an operation in the filter, then we can just process all the old events
512  // otherwise we need to manually add them to this FourierBuffer
513  // I imagine that needToAddManually will basically always be false...
514  // bool needToAddManually = true;
515  // const FilterStrategy* fs = fEv->getStrategy();
516  // for(unsigned i=0; i < fs->nOperations(); i++){
517  // const Filters::RayleighMonitor* rm = dynamic_cast<const Filters::RayleighMonitor*>(fs->getOperation(i));
518  // if(rm){
519  // FourierBuffer fb = rm->getFourierBuffer();
520 
521  // std::cout << fb.getAddress() << "\t" << this << std::endl;
522 
523  // if(this == fb.getAddress()){
524  // needToAddManually = false;
525  // break;
526  // }
527  // }
528  // }
529 
530  bool needToAddManually = false;
531 
532  std::cerr << "Info in " << __PRETTY_FUNCTION__ << ": Loading history for FourierBuffer, will loop over the last " << bufferSize << " events plus a few." << std::endl;
533  // std::cerr << "In " << __PRETTY_FUNCTION__ << ", I think I am here " << this << std::endl;
534 
535  while(!loadedHistory){
536 
537  std::vector<AnitaDataset*> ds;
538  std::vector<Int_t> firstEntries;
539  std::vector<Int_t> lastEntries;
540  Long64_t eventsInQueue = 0;
541  int thisRun = run;
542  while(eventsInQueue < numEventsToLoopOver){
543  ds.push_back(new AnitaDataset(thisRun));
544 
545  AnitaDataset* d = ds.back();
546 
547  d->first();
548  UInt_t firstEventThisRun = d->header()->eventNumber;
549 
550  d->last();
551  UInt_t lastEventThisRun = d->header()->eventNumber;
552 
553  UInt_t maxPossEventNumber = run == thisRun ? eventNumber : lastEventThisRun;
554 
555  Int_t potentialEvents = maxPossEventNumber - firstEventThisRun;
556 
557  Int_t eventsThisRun = potentialEvents > numEventsToLoopOver ? numEventsToLoopOver : potentialEvents;
558 
559  firstEntries.push_back(potentialEvents - eventsThisRun);
560  lastEntries.push_back(potentialEvents);
561  eventsInQueue += lastEntries.back() - firstEntries.back();
562 
563  thisRun--;
564  }
565 
566  // now we have the queue of events, iterate backwards (so run number is increasing), so they go in the buffer in the proper order...
567 
568  Long64_t eventsDone = 0;
569  ProgressBar p(eventsInQueue);
570  for(int i = (int)ds.size() - 1; i >= 0; i--){
571 
572  AnitaDataset* d = ds.at(i);
573 
574  for(int entry = firstEntries.at(i); entry < lastEntries.at(i); entry++){
575 
576  int thisEntry = d->getEntry(entry);
577 
578  // std::cout << thisEntry << "\t" << entry << "\t" << d->header()->eventNumber << "\t" << std::endl;
579 
580  if(thisEntry > 0){
581  bool isSafe = Acclaim::QualityCut::applyAll(d->useful(), NULL);
582  if(isSafe){
583  FilteredAnitaEvent fEv2(d->useful(), (FilterStrategy*) fEv->getStrategy(), d->gps(), d->header(), false);
584  if(needToAddManually){
585  add(&fEv2);
586  }
587  }
588  }
589  p.inc(eventsDone, eventsInQueue);
590  eventsDone++;
591  }
592 
593  delete d;
594  }
595 
596  if(eventNumbers.size() != (unsigned) bufferSize){
597  std::cerr << std::endl;
598  std::cerr << "Warning in " << __PRETTY_FUNCTION__ << ", tried to load history, but only got "
599  << eventNumbers.size() << " events when I have a buffer size " << bufferSize << std::endl;
600  }
601 
602  loadedHistory = true;
603  }
604  fCurrentlyLoadingHistory = false;
605 
606 }
607 
608 
609 
610 Acclaim::TGraphFB* Acclaim::FourierBuffer::getAvePowSpec_dB(Int_t ant, AnitaPol::AnitaPol_t pol, int lastNEvents) const{
611 
612  TGraphFB* gr = getAvePowSpec(ant, pol, lastNEvents);
613  gr->dBize();
614  return gr;
615 
616 }
617 
618 
619 Acclaim::TGraphFB* Acclaim::FourierBuffer::getAvePowSpec(Int_t ant, AnitaPol::AnitaPol_t pol, int lastNEvents) const{
620 
621  // set default value (which is the whole range of the fourier buffer)
622 
623  int nEvents = eventNumbers.size();
624 
625  TGraphFB* gr = new TGraphFB(this, ant, pol, sumPowers[pol][ant].size());
626 
627  const char* polName = AnitaPol::kHorizontal ? "HPol" : "VPol";
628  TString name = TString::Format("grAvePowSpec_%d_%s_%u_%u", ant, polName, eventNumbers.front(), eventNumbers.back());
629  TString title = TString::Format("Average Power Spectrum %d %s event %u - %u", ant, polName, eventNumbers.front(), eventNumbers.back());
630  gr->SetNameTitle(name, title);
631 
632 
633  for(unsigned freqInd=0; freqInd < sumPowers[pol][ant].size(); freqInd++){
634  gr->SetPoint(freqInd, freqInd*df, sumPowers[pol][ant].at(freqInd)/nEvents);
635  }
636 
637  return gr;
638 }
639 
640 
641 
642 Acclaim::TGraphFB* Acclaim::FourierBuffer::getSelectedGraphForSummary(SummaryOption_t choice, int ant, AnitaPol::AnitaPol_t pol) const
643 {
644  switch(choice){
645  case None:
646  return NULL;
647  case Chisquare:
648  return &grChiSquares[pol][ant];
649  case ReducedChisquare:
650  // return &grReducedChiSquares[pol][ant];
651  return &grReducedChiSquaresRelativeToSpectrum[pol][ant];
652  case NDF:
653  return &grNDFs[pol][ant];
654  case RayleighAmplitude:
655  // return &grAmplitudes[pol][ant];
656  return &grLastAmps[pol][ant];
657  case Prob:
658  return &grProbs[pol][ant];
659  }
660 }
661 
662 
663 Acclaim::TGraphFB* Acclaim::FourierBuffer::getBackground_dB(Int_t ant, AnitaPol::AnitaPol_t pol, int lastNEvents) const{
664 
665  TGraphFB* gr = getBackground(ant, pol, lastNEvents);
666  gr->dBize();
667  return gr;
668 }
669 
670 Acclaim::TGraphFB* Acclaim::FourierBuffer::getBackground(Int_t ant, AnitaPol::AnitaPol_t pol, int lastNEvents) const{
671 
672  TGraphFB* gr = getAvePowSpec(ant, pol, lastNEvents);
673 
674  getBackgroundSpectrum(gr->GetY(), gr->GetN());
675 
676  return gr;
677 }
678 
679 
680 // wrapper for spectrum since it's interface changes in a fucking stupid way between ROOT versions
681 void Acclaim::FourierBuffer::getBackgroundSpectrum(double* y, int n) const{
682 
683  if(!fSpectrum){
684  fSpectrum = new TSpectrum();
685  }
686 
687 #if IS_ROOT_6
688  double* tempPtr = y;
689 #else
690  std::vector<float> tempFloats(n, 0);
691  for(int i=0; i < n; i++){
692  tempFloats[i] = y[i];
693  }
694  float* tempPtr = &tempFloats[0];
695 #endif
696 
697  const int numIter = 4;
698  fSpectrum->Background(tempPtr,n,
699  numIter,TSpectrum::kBackDecreasingWindow,
700  TSpectrum::kBackOrder4,kFALSE,
701  TSpectrum::kBackSmoothing3,kFALSE);
702 
703 #if !(IS_ROOT_6)
704  for(int i=0; i < n; i++){
705  y[i] = tempFloats[i];
706  }
707 #endif
708 }
709 
710 
711 
712 
713 
714 
715 void Acclaim::FourierBuffer::drawSummary(TPad* pad, SummaryOption_t summaryOpt) const{
716 
717  if(summaryOpt == None){
718  return;
719  }
720 
721  pad->cd();
722 
723  // find the maximum and minimum values before plotting
724  Double_t yMax = -DBL_MAX;
725  Double_t yMin = DBL_MAX;
726  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
728  for(int ant=0; ant < NUM_SEAVEYS; ant++){
729 
730  if(isAlfaBandpassed(ant, pol)){
731  continue;
732  }
733 
734  // TGraphFB& gr = (TGraphFB&) grReducedChiSquares[pol][ant];
735  const TGraphFB* gr = getSelectedGraphForSummary(summaryOpt, ant, pol);
736  // TGraphFB& gr = (TGraphFB&) grProbs[pol][ant];
737 
738  for(int i=0; i < gr->GetN(); i++){
739  double x = gr->GetX()[i];
740  if(x > fMinSpecFreq && x < fMaxFitFreq){
741  if(gr->GetY()[i] > yMax){
742  yMax = gr->GetY()[i];
743  }
744  if(gr->GetY()[i] < yMin){
745  yMin = gr->GetY()[i];
746  }
747  }
748  }
749  }
750  }
751 
752  // now do the plotting (setting the max/min)
753 
754  for(int ant=0; ant < NUM_SEAVEYS; ant++){
755  // dynamically initialize the summary pads
756  if(!summaryPads[ant]){
757  int ring = ant/NUM_PHI;
758  int phi = ant % NUM_PHI;
759 
760  // instead of 3 by 16
761  // do 6 by 8
762  int xBin = phi/2;
763  int yBin = (2*ring + phi%2);
764 
765  summaryPads[ant] = RootTools::makeSubPad(pad, double(xBin)/8, double(5 - yBin)/6,
766  double(xBin+1)/8, double(6 - yBin)/6,
767  TString::Format("FourierBuffer%d", ant));
768  summaryPads[ant]->SetRightMargin(0);
769  summaryPads[ant]->SetLeftMargin(0.1 * (xBin == 0));
770  summaryPads[ant]->SetTopMargin(0.1 * (yBin == 0));
771  summaryPads[ant]->SetBottomMargin(0.1 * (yBin == 5));
772 
773  // avoid deletion?
774  summaryPads[ant]->SetBit(kCanDelete);
775  summaryPads[ant]->InvertBit(kCanDelete);
776  }
777  else{
778  // already have the pad, so append it to the boss pad
779  pad->cd();
780  summaryPads[ant]->AppendPad();
781  }
782 
783 
784  // do the actual plotting
785  summaryPads[ant]->Clear();
786 
787  summaryPads[ant]->cd();
788 
789  if(summaryOpt == FourierBuffer::ReducedChisquare){
790 
791  TH1D* hH = makeChanChisquareHist(AnitaPol::kHorizontal, ant, summaryPads[ant], "e");
792  TH1D* hV = makeChanChisquareHist(AnitaPol::kVertical, ant, summaryPads[ant], "esame");
793  hV->SetBit(kCanDelete);
794  hH->SetBit(kCanDelete);
795  hH->SetLineColor(kBlue);
796  hV->SetLineColor(kBlack);
797  gPad->SetLogy(1);
798 
799  continue;
800  yMax = 10;
801  yMin = 0;
802  // gPad->SetLogy(1);
803  }
804  else{
805  gPad->SetLogy(0);
806  }
807 
808  summaryPads[ant]->cd();
809 
810  if(summaryOpt == FourierBuffer::Prob){
811  yMax = 0; // otherwise some events get a little too crazy..
812  yMin = -10; // otherwise some events get a little too crazy..
813  }
814 
815  for(int polInd=0; polInd < AnitaPol::kNotAPol; polInd++){
817 
818  TGraphFB* gr = getSelectedGraphForSummary(summaryOpt, ant, pol);
819  gr->SetEditable(kFALSE);
820 
821  const char* opt = pol == AnitaPol::kVertical ? "lsame" : "al";
822  EColor lineCol = pol == AnitaPol::kHorizontal ? kBlue : kBlack;
823  gr->SetLineColor(lineCol);
824  gr->SetMaximum(yMax);
825  gr->SetMinimum(yMin);
826 
827  gr->Draw(opt);
828 
829  for(unsigned i=0; i < gr->fDerivatives.size(); i++){
830  TGraphFB* gr2 = gr->fDerivatives[i];
831  gr2->Draw("lsame");
832  gr2->SetLineColor(gr->GetLineColor());
833  gr2->SetLineStyle(i+1);
834  }
835  }
836  }
837 }
838 
839 
840 
841 
842 
843 
844 
845 
846 
847 
848 
849 
850 
851 void Acclaim::TGraphFB::drawCopy() const{
852 
853 
854  if(fDerivedFrom){ // this setup should recursively call draw copy with the parent
855  fDerivedFrom->drawCopy();
856  }
857  else{
858  int logx = gPad->GetLogx();
859  int logy = gPad->GetLogy();
860  int logz = gPad->GetLogz();
861 
862  TCanvas* c1 = new TCanvas();
863  c1->cd();
864  c1->SetLogx(logx);
865  c1->SetLogy(logy);
866  c1->SetLogz(logz);
867 
868  TGraphFB* gr2 = new TGraphFB(this);
869  gr2->SetBit(kCanDelete);
870  gr2->fDoubleClickOption = kDrawRayleigh;
871  gr2->SetTitle(TString::Format(""));
872 
873  gr2->Draw();
874  for(unsigned i=0; i < fDerivatives.size(); i++){
875  TGraphFB* grD = new TGraphFB(fDerivatives.at(i));
876  grD->SetBit(kCanDelete);
877  grD->fDoubleClickOption = kDrawRayleigh;
878  grD->SetTitle(TString::Format(""));
879  grD->Draw("lsame");
880  }
881 
882  gPad->Modified();
883  gPad->Update();
884  }
885 }
886 
887 void Acclaim::TGraphFB::ExecuteEvent(int event, int x, int y){
888 
889  if(event == kButton1Double){
890  if(fDoubleClickOption==kDrawRayleigh){
891  drawRayleighHistNearMouse(x, y);
892  }
893  else if(fDoubleClickOption==kDrawCopy){
894  drawCopy();
895  }
896  }
897  TGraphAligned::ExecuteEvent(event, x, y);
898 }
899 
900 
901 void Acclaim::TGraphFB::drawRayleighHistNearMouse(int x, int y) const{
902 
903  int logx = gPad->GetLogx();
904  int logy = gPad->GetLogy();
905  int selectedPoint = -1;
906  double minD2 = 1e99;
907  for(int i=0; i < GetN(); i++){
908  double xVal = logx ? TMath::Log10(GetX()[i]) : GetX()[i];
909  double yVal = logy ? TMath::Log10(GetY()[i]) : GetY()[i];
910  Int_t pixelX = gPad->XtoAbsPixel(xVal);
911  Int_t pixelY = gPad->YtoAbsPixel(yVal);
912 
913  // std::cout << selectedPoint << "\t" << i << "\t" << x << "\t" << y << "\t" << pixelX << "\t" << pixelY << std::endl;
914 
915 
916  const int closeDist = 4; // number of pixels that means you're close to a point
917  if(TMath::Abs(pixelX - x) < closeDist && TMath::Abs(pixelY - y) < closeDist){
918  double d2 = (pixelX - x)*(pixelX - x) + (pixelY - y)*(pixelY - y);
919 
920  if(d2 < minD2){
921  minD2 = d2;
922  selectedPoint = i;
923  }
924  }
925  }
926 
927 
928  double df = GetX()[1] - GetX()[0];
929 
930  if(selectedPoint > -1 && df > 0){
931  TCanvas* c1 = new TCanvas();
932  c1->cd();
933  // need to pretend it's non-const
934  // don't delete this!
935  RayleighHist* h = (RayleighHist*) fb->getRayleighDistribution(ant, pol, selectedPoint);
936  h->SetLineColor(GetLineColor());
937  h->Draw();
938  c1->Modified();
939  c1->Update();
940  }
941 
942 }
943 
944 
945 // Utility function to set fDerives from and fDerivatives (i.e. the drawing ownership)
946 void Acclaim::TGraphFB::setDrawingDependencies(const std::vector<TGraphFB*> grs){
947  if(grs.size() > 0){
948  for(unsigned i=1; i < grs.size(); i++){
949  grs[0]->fDerivatives.push_back(grs[i]);
950  grs[i]->fDerivedFrom = grs[0];
951  }
952  }
953 }
const TGraphAligned * power() const
void initGraphAndVector(std::vector< double > vec[][NUM_SEAVEYS], std::vector< TGraphFB > *gr, int n, double df, double defaultVal)
Initialise an internal vector and TGraphFB with with an appropriate set of default values...
Hard coded frequencies in GHz which can get used in any given filter.
static Bool_t applyAll(const UsefulAnitaEvent *usefulEvent, AnitaEventSummary *sum=NULL)
Applies all the event quality cuts in succession, this should be the primary interface.
Definition: QualityCut.cxx:45
const FilterStrategy * getStrategy() const
void automagicallyLoadHistory(const FilteredAnitaEvent *fEv)
Function which loops through old events so that the FourierBuffer is filled.
const UsefulAnitaEvent * getUsefulAnitaEvent() const
int getEntry(int entryNumber)
A little class for some GUI magic (for MagicDisplay)
A filter strategy defines the sets of filters that are used and provides some introspection abilities...
RawAnitaHeader – The Raw ANITA Event Header.
void inc(Long64_t &entry, Long64_t numEntries=-1)
New primary function to move through main for loop in analysis program.
USeful in for loops.
size_t add(const FilteredAnitaEvent *fEv)
Adds an event to the FourierBuffer.
Contains all my filter classes, some of which have less than obvious names.
Int_t run
Run number, assigned on ground.
virtual UsefulAnitaEvent * useful(bool force_reload=false)
Prints a progress bar and timer to stderr.
Definition: ProgressBar.h:25
virtual ~FourierBuffer()
Destructor.
Int_t removeOld()
Remove data from the dequeues while their size is greater than the buffer size.
void initVectors(int n, double df)
Initialise all internal vectors.
FourierBuffer(Int_t theBufferSize=1000)
Constructor for FourierBuffer.
Adu5Pat * gps(bool force_reload=false)
const AnalysisWaveform * getFilteredGraph(UInt_t i) const
Vertical Polarisation.
virtual RawAnitaHeader * header(bool force_reload=false)
Horizontal Polarisation.
This class is intended to store all the necessary data about an ANITA event for filtering and analysi...
TH1D * makeChanChisquareHist(AnitaPol::AnitaPol_t pol, Int_t ant, TPad *pad, const char *drawOpt) const
Histogram the event frequency bin amplitudes squared, divided by the rayleigh distribution amplitude ...
enum AnitaPol::EAnitaPol AnitaPol_t
Polarisation enumeration.
This class is intended to be the main storage vessel for ANITA waveforms. It is similar in principle ...
const RawAnitaHeader * getHeader() const