EASFitter.cc
1 #include "EASFitter.h"
2 #include "FFTtools.h"
3 #include "DeltaT.h"
4 #include "AntennaPositions.h"
5 #include "TH2.h"
6 #include "AnalysisWaveform.h"
7 #include "TGraph2D.h"
8 #include "TCanvas.h"
9 #include "TFile.h"
10 #include "Minuit2/Minuit2Minimizer.h"
11 #include "FilteredAnitaEvent.h"
12 #include "FreqDomainFunction.h"
13 #include "TimeDependentAverage.h"
14 #include "RawAnitaHeader.h"
15 #include "ResponseManager.h"
16 
17 
18 
19 static TH2D * hpower =0;
20 static TH2D * hphase =0;
21 static std::vector<TGraph*> vpower;
22 static std::vector<TGraph*> vphase;
23 
24 
25 static double getOffAxisPowerMultiplier(int pol, int plane, double f, double deg)
26 {
27 
28  static TFile foff(Form("%s/share/data/A3offaxis.root", getenv("ANITA_UTIL_INSTALL_DIR")));
29  static bool init = false;
30  static TGraph2D * data[2][2];
31 
32  if (!init)
33  {
34  data[0][1]= (TGraph2D*) foff.Get("Hpol_Hplane");
35  data[0][0]= (TGraph2D*) foff.Get("Hpol_Eplane");
36  data[1][1]= (TGraph2D*) foff.Get("Vpol_Hplane");
37  data[1][0] = (TGraph2D*) foff.Get("Vpol_Eplane");
38  init = true;
39  }
40 
41  return pow(10,data[pol][plane]->Interpolate(f, deg)/10);
42 }
43 
44 static void setupHists()
45 {
46 
47  TFile f(Form("%s/share/data/templates/crTmpltsA3.root",getenv("ANITA_UTIL_INSTALL_DIR")));
48 
49  for (int i = 0; i < 27; i++)
50  {
51  TGraph * g = FFTtools::cropWave((TGraph*) f.Get(Form("efield%d",i)),0,600);
52  g->SetTitle(Form("Template %d",i));
53 
54  AnalysisWaveform * wf = new AnalysisWaveform(g->GetN(),g->GetY(), g->GetX()[1]-g->GetX()[0], g->GetX()[0]);
55  wf->setTitle(g->GetTitle());
56 
57  int roll;
58  wf->hilbertEnvelope()->peakVal(&roll);
59  FFTtools::rotate(wf->updateEven(), -roll);
60 
61  TGraphAligned * gpower = (TGraphAligned*) wf->power();
62  TGraphAligned * gphase = new TGraphAligned(*wf->phase());
63 
64  //find the peak of the power spectrum
65  int peak;
66  double val = gpower->peakVal(&peak);
67  FFTtools::unwrap(gphase->GetN(), gphase->GetY(), 2*TMath::Pi());
68  for (int j = 0; j < gpower->GetN(); j++)
69  {
70  if (j < peak) continue;
71 
72  if (gpower->GetY()[j] / val < 1e-3)
73  {
74  gphase->Set(j);
75  break;
76  }
77  }
78 
79  gpower->SetTitle(g->GetTitle());
80  gphase->SetTitle(g->GetTitle());
81  vpower.push_back(gpower);
82  vphase.push_back(gphase);
83  }
84 
85  double df = vpower[0]->GetX()[1] - vpower[0]->GetX()[0];
86 
87  hpower = new TH2D("hpower","POWER;freq;T", vpower[0]->GetN(), -df/2, vpower[0]->GetX()[vpower[0]->GetN()-1]+df/2,
88  27,-13.5,13.5);
89  hphase = new TH2D("hphase","PHASE;freq;T", vpower[0]->GetN(), -df/2, vpower[0]->GetX()[vpower[0]->GetN()-1]+df/2,
90  27,-13.5,13.5);
91 
92  hpower->SetDirectory(0);
93  hphase->SetDirectory(0);
94 
95  for (int x = 1; x <= hpower->GetNbinsX(); x++)
96  {
97  for (int y = 1; y <= hpower->GetNbinsY(); y++)
98  {
99  hpower->SetBinContent(x,y, vpower[y-1]->GetY()[x-1]);
100  hphase->SetBinContent(x,y, vphase[y-1]->GetN() < x ? vphase[y-1]->GetY()[vphase[y-1]->GetN()-1] : vphase[y-1]->GetY()[x-1]);
101  }
102  }
103 
104 }
105 
106 static std::complex<double> crfitfn (double f, const double * pars)
107 {
108 
109  if (!hpower) setupHists();
110 
111  double T = *pars;
112  if (T < -13 || T > 13) return 0;
113  if (f < 0 || f> hpower->GetXaxis()->GetBinCenter(hpower->GetNbinsX())) return 0;
114  double dphi = pars[1];
115  double dtheta = pars[2];
116  int ipol = int(pars[3]);
117  //printf("%g %g %g %d\n", T,dphi,dtheta,ipol);
118 
119  double atten_phi = dphi == 0 ? 1 : getOffAxisPowerMultiplier(ipol, ipol == 0,f, dphi);
120  double atten_theta = dtheta == 0 ? 1 : getOffAxisPowerMultiplier(ipol, ipol == 1,f, dtheta);
121 
122 // printf(" %g %g\n",f,T);
123  double pow = hpower->Interpolate(f,T) * atten_phi*atten_theta;
124  double phase = hphase->Interpolate(f,T);
125  double amp = sqrt(pow);
126 
127  return std::complex<double>( cos(phase) * amp, sin(phase)*amp);
128 }
129 
130 
131 
132 
133 class EASFitFn : public ROOT::Math::IBaseFunctionMultiDim
134 {
135 
136 
137  public:
138  virtual ~EASFitFn()
139  {
140 
141  for (unsigned i = 0; i < fns.size(); i++)
142  {
143  delete fns[i];
144  delete wfs[i];
145  }
146  }
147 
148 
149  EASFitFn(int nants, const int * ants, const FilteredAnitaEvent * ev, int pol, double t, double phi, double theta, const AnitaResponse::ResponseManager * rm, bool freqonly = false, bool dedisperse = false)
150  : dedisperse(dedisperse), freqonly(freqonly), nants(nants), pol(pol), ants(ants), rms(nants), event(ev),wfs(nants), fns(nants), t(t), phi(phi), theta(theta), rm(rm)
151  {
152 
154  for (int i = 0; i < nants; i++)
155  {
156  rms[i] = freqonly ? 0 : UCorrelator::TimeDependentAverageLoader::getRMS(t,0,ants[i]);
157  wfs[i] = new AnalysisWaveform(*ev->getRawGraph(ants[i],AnitaPol::kHorizontal));
158  if (!freqonly && dedisperse) rm->response(0,ants[i])->deconvolveInPlace(wfs[i], &allpass);
159  fns[i] = new FreqDomainFunction(crfitfn, 4, rm->response(0,ants[i]),wfs[i]->deltaT()/4,-wfs[i]->even()->GetX()[wfs[i]->Neven()-1], wfs[i]->even()->GetX()[wfs[i]->Neven()-1]);
160  if (!freqonly && dedisperse) fns[i]->dedisperseResponse(true);
161  }
162  }
163  virtual ROOT::Math::IBaseFunctionMultiDim * Clone() const { return new EASFitFn(rms.size(), ants, event, pol, t, phi,theta,rm,freqonly,dedisperse); }
164  virtual unsigned int NDim() const { return 2 *nants+3; }
165 
166 
167  virtual double DoEval(const double *x) const
168  {
169  double A = x[0];
170  double t0 = x[1];
171  double T = x[2];
172  double chisq = 0;
173 // printf("T: %g:\n", T);
174 
175  for (int i = 0; i < nants; i++)
176  {
177  double delta_t = UCorrelator::getDeltaT(ants[0], ants[i], phi, theta, AnitaPol::kHorizontal,true);
178  double dphi = FFTtools::wrap(UCorrelator::AntennaPositions::instance()->phiAnt[0][ants[i]] -phi,360,0);
179  double dtheta = 10 - theta;
180 
181  double p[6] = { A*x[2*i+3], freqonly ? 0 : t0-delta_t + x[2*i+4], T, dphi, dtheta,(double)pol};
182 // printf("%g %g %g %g %g\n", p[0],p[1], p[2],p[3],p[4]);
183  fns[i]->setParameters(p);
184 
185  if (freqonly)
186  {
187  double df = wfs[i]->deltaF();
188  for (int j = 0; j < wfs[i]->Nfreq(); j++)
189  {
190  chisq += pow(wfs[i]->power()->GetY()[j] - fns[i]->evalPower(j*df),2);
191  }
192  }
193  else
194  {
195  for (int j = 0; j < wfs[i]->Neven(); j++)
196  {
197  if (dedisperse)
198  chisq += pow(wfs[i]->even()->GetY()[j] - fns[i]->eval(wfs[i]->even()->GetX()[j]),2)/((wfs[i]->Neven() - 3) *rms[i]*rms[i]);
199  else
200  chisq += pow(wfs[i]->uneven()->GetY()[j] - fns[i]->eval(wfs[i]->uneven()->GetX()[j]),2)/((wfs[i]->Nuneven() - 3) *rms[i]*rms[i]);
201  }
202  }
203  }
204  return chisq;
205  }
206 
207 
208  void plot(TCanvas *c, std::vector<TObject*> *save = 0)
209  {
210  c->Divide(nants/3,3);
211 
212  for (int i = 0; i < nants; i++)
213  {
214  c->cd(i+1);
215  AnalysisWaveform *wf = wfs[i];
216  wf->updateEven()->SetTitle(Form("Ant %d", ants[i]));
217  wf->updateEven()->setPlottingLimits(1.1,true,20);
218  if (save)
219  {
220  TGraphAligned * g = new TGraphAligned(*wf->even());
221  save->push_back(g);
222  g->Draw("al");
223  }
224  else
225  {
226  wf->drawEven("al");
227  }
228  TF1 * f = fns[i]->makeTF1(Form("fn_%d",i));
229  if (save) save->push_back(f);
230  f->Draw("same");
231  }
232  }
233 
234 
235 
236  bool dedisperse;
237  bool freqonly;
238  int nants;
239  int pol;
240  const int* ants;
241  std::vector<double> rms;
242  const FilteredAnitaEvent * event;
243  std::vector<AnalysisWaveform *> wfs;
244  mutable std::vector<FreqDomainFunction *> fns;
245  double t;
246  double phi,theta;
247  const AnitaResponse::ResponseManager * rm;
248 
249 };
250 
251 
252 
253 int UCorrelator::EASFitter::fitEvent(int nants, const int * ants,
254  const FilteredAnitaEvent * event,
255  double phi, double theta, bool dedisperse)
256 {
257 
258  EASFitFn freq_fit(nants, ants, event, AnitaPol::kHorizontal, event->getHeader()->triggerTime, phi,theta,rm,true,dedisperse);
259  EASFitFn time_fit(nants, ants, event, AnitaPol::kHorizontal, event->getHeader()->triggerTime, phi,theta,rm,false,dedisperse);
260 
261  double freq_scale = freq_fit.fns[0]->waveform()->power()->peakVal();
262 
263  int toffset_loc;
264  double scale = time_fit.fns[0]->waveform()->even()->peakVal(&toffset_loc,0,-1,true);
265 
266  for (int side_of_cone = -1; side_of_cone <=1; side_of_cone+=2)
267  {
268 
269  //start with a frequency domain fit, which doesn't care about polarity
270  ROOT::Minuit2::Minuit2Minimizer min_freq;
271  AnalysisWaveform * wf = (AnalysisWaveform*) freq_fit.wfs[0]->freq();
272  int loc;
273  double fA = wf->even()->peakVal(&loc, 0,-1,true) / freq_scale ;
274  int ivar = 0;
275  min_freq.SetLimitedVariable(ivar++, "A", fA, fA*0.1, 0, 2*fA);
276  min_freq.SetFixedVariable(ivar++, "t0", 0); //doesn't matter for frequency
277  min_freq.SetLimitedVariable(ivar++,"T", side_of_cone*7,0.1,side_of_cone > 0 ? 0 : -13, side_of_cone > 0 ? 13 : 0);
278 
279  for (int i =0; i < nants; i++)
280  {
281  // min.SetLimitedVariable(ivar++, Form("relA_%d",i), 1,0.1, 0.8, 1.2);
282  min_freq.SetFixedVariable(ivar++, Form("relA_%d",i), 1);
283  min_freq.SetFixedVariable(ivar++, Form("tadj_%d",i), 0); //doesn't matter for frequency fit
284  }
285 
286  min_freq.SetFunction(freq_fit);
287  min_freq.Minimize();
288 
289  printf("Side of Cone: %d, status: %d. T: %g, A: %g\n",
290  side_of_cone, min_freq.Status(), min_freq.X()[2], min_freq.X()[0]);
291 
292 
293  for (int polarity = -1; polarity <=1; polarity+=2)
294  {
295 
296 
297  ROOT::Minuit2::Minuit2Minimizer min_time;
298 
299  min_time.SetFunction(time_fit);
300 
301 
302  const AnalysisWaveform * wf = (AnalysisWaveform*) time_fit.wfs[0];
303  int loc;
304  double A = wf->even()->peakVal(&loc, 0,-1,true) / scale ;
305  double t0 = wf->even()->GetX()[loc];
306 
307  int ivar = 0;
308  min_time.SetLimitedVariable(ivar++, "A", A, A*0.1, 0, 2*A);
309  min_time.SetVariable(ivar++, "t0", t0, 0.5);
310  min_time.SetLimitedVariable(ivar++,"T", 7,0.1,-13,13);
311 
312  for (int i =0; i < nants; i++)
313  {
314  printf("ant: %d\n", ants[i]);
315  // min.SetLimitedVariable(ivar++, Form("relA_%d",i), 1,0.1, 0.8, 1.2);
316  min_time.SetFixedVariable(ivar++, Form("relA_%d",i), 1);
317  min_time.SetLimitedVariable(ivar++, Form("tadj_%d",i), 0, 0.1 , -1, 1);
318  }
319 
320  min_time.Minimize();
321  min_time.PrintResults();
322 
323  }
324  }
325  return 0;
326 }
327 
328 
329 UCorrelator::EASFitter::~EASFitter()
330 {
331  for (unsigned i = 0; i < plots.size(); i++) delete plots[i];
332  for (unsigned i = 0; i < save.size(); i++) delete plots[i];
333 }
334 
335 
336 
337 
void rotate(TGraph *g, int rot)
Definition: FFTtools.cxx:2627
const TGraphAligned * power() const
const TGraphAligned * phase() const
TGraph * cropWave(const TGraph *grWave, Double_t minTime, Double_t maxTime)
This returns a TGraph which has been cropped in.
Definition: FFTtools.cxx:2012
TGraphAligned * updateEven()
const FFTWComplex * freq() const
double getDeltaT(int ant1, int ant2, double phi, double theta, AnitaPol::AnitaPol_t pol, bool includeGroupDelay=false)
Definition: DeltaT.h:68
void drawEven(const char *opt="", int color=-1) const
const AnalysisWaveform * getRawGraph(UInt_t i) const
void wrap(size_t N, double *vals, double period=360)
Definition: FFTtools.cxx:2851
const TGraphAligned * hilbertEnvelope() const
void unwrap(size_t N, double *vals, double period=360)
Definition: FFTtools.cxx:2857
const TGraphAligned * even() const
Horizontal Polarisation.
This class is intended to store all the necessary data about an ANITA event for filtering and analysi...
This class is intended to be the main storage vessel for ANITA waveforms. It is similar in principle ...
static double getRMS(double t, int ipol, int ant, int nsecs=10)
const RawAnitaHeader * getHeader() const
UInt_t triggerTime
Trigger time from TURF converted to unixTime.