PeakFinder.cc
1 #include "PeakFinder.h"
2 #include "TH2.h"
3 #include "TF2.h"
4 #include "FFTtools.h"
5 #include "Minuit2/Minuit2Minimizer.h"
6 #include "Math/Interpolator.h"
7 #include "TGraph.h"
8 
9 #ifdef UCORRELATOR_USE_EIGEN_FOR_PEAK_FINDER
10 #include <Eigen/Dense>
11 #else
12 #include "TMatrix.h"
13 #include "TDecompSVD.h"
14 #endif
15 
16 #include "TError.h"
17 
18 static bool isLocalMaxima(const TH2D * hist, int bin)
19 {
20 
21 
22  const double* I = hist->GetArray();
23  const int width = hist->GetNbinsX()+2;
24 
25  // in the unlikely case that there are two bins with exactly the same value
26  // we'll pick the one to the top left because why not
27  // I haven't checked if that really fixes it but oh well
28  if (I[bin-1] >= I[bin]) return false;
29  if (I[bin+1] > I[bin]) return false;
30  if (I[bin-width-1] >= I[bin]) return false;
31  if (I[bin-width] >= I[bin]) return false;
32  if (I[bin-width+1] >= I[bin]) return false;
33  if (I[bin+width+1] > I[bin]) return false;
34  if (I[bin+width] > I[bin]) return false;
35  if (I[bin+width+1] > I[bin]) return false;
36 
37 
38  return true;
39 }
40 
41 static int findMaximum(const TH2D* hist, std::vector<char> * notallowed)
42 {
43  const double * arr = hist->GetArray();
44  int width = hist->GetNbinsX() + 2;
45  int height = hist->GetNbinsY() + 2;
46  int N = width * height;
47 
48  double max = -DBL_MAX;
49  int max_i = -1;
50  for (int i = 0; i < N; i++)
51  {
52  if (notallowed->at(i))
53  {
54  // printf("Skipping bin %d\n",i);
55  continue;
56  }
57  //skip overflow
58 
59  if (i % width == 0) continue;
60  if (i % width == width-1) continue;
61  if (i / width == 0) continue;
62  if (i / width == height-1) break;
63 
64  if (arr[i] > max && isLocalMaxima(hist,i))
65  {
66  max = arr[i];
67  max_i = i;
68  }
69  }
70  return max_i;
71 }
72 
73 static void maskNearbyBins(const TH2D * hist, double distance, int bin, std::vector<char> * used)
74 {
75 
76  const int width = hist->GetNbinsX()+2;
77  const int height = hist->GetNbinsY()+2;
78  int int_dist = int(distance+0.5);
79 
80  double dw = hist->GetXaxis()->GetBinWidth(1);
81  double dh = hist->GetYaxis()->GetBinWidth(1);
82  double dw2 = dw*dw;
83  double dh2 = dh*dh;
84 
85 
86  int i0 = bin % width;
87  int j0 = bin / width;
88 
89  double dist2 = distance*distance;
90 
91  for (int jj = -int_dist; jj <= int_dist; jj++)
92  {
93  int j = j0 +jj;
94  if (j < 1) continue;
95  if (j >= height) continue;
96  int j2 = jj*jj;
97  for (int ii = -int_dist; ii <= int_dist; ii++)
98  {
99  int i = i0 +ii;
100  if (i < 1) i += width;
101  if (i >= width) i-=width;
102  if (ii*ii*dw2 + j2*dh2 > dist2) continue;
103 
104  int bin2use = i+ j * width;
105 // printf("Disallowing %d\n", bin2use);
106  (*used)[bin2use] = 1;
107  }
108  }
109 }
110 
111 
112 int UCorrelator::peakfinder::findIsolatedMaxima(const TH2D * hist, double distance, int Nmaxima, RoughMaximum * maxima,
113  double minPhi, double maxPhi, double minTheta, double maxTheta, bool exclude, bool use_bin_center)
114 {
115  int width = hist->GetNbinsX()+2;
116  int height = hist->GetNbinsY()+2;
117  std::vector<char> used( width*height, false);
118 
119  int nfound = 0;
120 
121  std::vector<int> row_not_allowed(0);
122  std::vector<int> col_not_allowed(0);
123 
124  minPhi = FFTtools::wrap(minPhi,360);
125  maxPhi = FFTtools::wrap(maxPhi,360);
126 
127  //if min and maxes are set, blocks out corresponding rows/columns
128  if(minTheta != maxTheta)
129  {
130  for(int ybin = 2; ybin < hist->GetNbinsY(); ybin++)
131  {
132  double yCenter = hist->GetYaxis()->GetBinCenter(ybin);
133  if(yCenter <= minTheta || yCenter >= maxTheta) row_not_allowed.push_back(ybin);
134  }
135  }
136 
137  if(minPhi != maxPhi)
138  {
139 // printf("[%g,%g]\n",minPhi,maxPhi);
140  for(int xbin = 1; xbin < hist->GetNbinsX()+1; xbin++)
141  {
142  double xCenter = hist->GetXaxis()->GetBinCenter(xbin);
143  if( (xCenter <= minPhi && xCenter >= maxPhi ))
144  {
145 // printf("Disallowing %g\n",xCenter);
146  col_not_allowed.push_back(xbin);
147  }
148  }
149  }
150 
151  for (unsigned i = 0; i < row_not_allowed.size(); i++)
152  {
153  memset(&used[(width)*row_not_allowed[i]], 1, width);
154  }
155  for (unsigned i = 0; i < col_not_allowed.size(); i++)
156  {
157  for(unsigned j = 0; j < (unsigned) height; j++) used[col_not_allowed[i] + (j*width)] = 1;
158  }
159 
160  //if set to exclude, this flips all 1s and 0s (max sure phi and theta are actually set if using this or it will just block out everything)
161  if(exclude)
162  {
163  for(unsigned i = 0; i < (unsigned)width*height; i++) used[i] = used[i] xor 1;
164  }
165 
166  //block out bins closest to top and bottom since we don't want maxima on the top or bottom edge
167 
168  int rows_not_allowed[] = {1,hist->GetNbinsY()};
169  for(unsigned i = 0; i < sizeof(rows_not_allowed) / sizeof(*rows_not_allowed); i++)
170  {
171  memset(&used[(width)*rows_not_allowed[i]], 1, width);
172  }
173 
174  while (nfound < Nmaxima)
175  {
176  int bin = findMaximum(hist, &used);
177  if (bin < 0) break;
178 
179  maxima[nfound].bin = bin;
180  maxima[nfound].val = hist->GetArray()[bin];
181  int xbin = bin % (hist->GetNbinsX() + 2);
182  maxima[nfound].xbin = xbin;
183  maxima[nfound].x = use_bin_center ? hist->GetXaxis()->GetBinCenter(xbin) : hist->GetXaxis()->GetBinLowEdge(xbin);
184  int ybin = bin / (hist->GetNbinsX() + 2);
185  maxima[nfound].y = use_bin_center ? hist->GetYaxis()->GetBinCenter(ybin) : hist->GetYaxis()->GetBinLowEdge(ybin);
186  maskNearbyBins(hist, distance, bin, &used);
187  nfound++;
188  }
189 
190  for (int i = nfound; i < Nmaxima; i++)
191  {
192  maxima[i].bin = -1;
193  maxima[i].val = -9999;
194  maxima[i].x = -9999;
195  maxima[i].y = -9999;
196  }
197 
198  return nfound;
199 }
200 
201 
202 
204 {
205  p->phi = x;
206  p->theta = -y;
207  p->sigma_theta = sigma_y;
208  p->sigma_phi = sigma_x;
209  p->rho = covar / (sigma_x * sigma_y);
210  p->value = val;
211  p->chisq = chisq;
212 }
213 
214 const int X2COEFF = 0;
215 const int Y2COEFF = 1;
216 const int XYCOEFF = 2;
217 const int XCOEFF = 3;
218 const int YCOEFF = 4;
219 const int CCOEFF = 5;
220 
221 
222 
223 #ifdef UCORRELATOR_USE_EIGEN_FOR_PEAK_FINDER
224 
225 template <unsigned N>
226 static const Eigen::Matrix<double,N*N,6> & getM()
227 {
228  int halfway = N/2;
229  static Eigen::Matrix<double, N*N,6> M;
230  for (unsigned i = 0; i < N; i++)
231  {
232  for (unsigned j = 0; j < N; j++)
233  {
234  int x = i- halfway;
235  int y = j - halfway;
236  M(i + j * N, X2COEFF) = x * x;
237  M(i + j * N, Y2COEFF) = y * y;
238  M(i + j * N, XYCOEFF) = x * y;
239  M(i + j * N, XCOEFF) = x;
240  M(i + j * N, YCOEFF) = y;
241  M(i + j * N, CCOEFF) = 1;
242  }
243  }
244  return M;
245 }
246 
247 template <unsigned N>
248 static const Eigen::JacobiSVD<Eigen::Matrix<double, N*N,6> > & getSVD()
249 {
250  static Eigen::JacobiSVD<Eigen::Matrix<double, N*N,6> > svd(getM<N>(),Eigen::ComputeFullU | Eigen::ComputeFullV);
251  return svd;
252 }
253 #else
254 
255 template <unsigned N>
256 static const TMatrixD & getM()
257 {
258  int halfway = N/2;
259  static TMatrixD M(N*N,6);
260  for (unsigned i = 0; i < N; i++)
261  {
262  for (unsigned j = 0; j < N; j++)
263  {
264  int x = i- halfway;
265  int y = j - halfway;
266  M(i + j * N, X2COEFF) = x * x;
267  M(i + j * N, Y2COEFF) = y * y;
268  M(i + j * N, XYCOEFF) = x * y;
269  M(i + j * N, XCOEFF) = x;
270  M(i + j * N, YCOEFF) = y;
271  M(i + j * N, CCOEFF) = 1;
272  }
273  }
274 
275  return M;
276 }
277 
278 template <unsigned N>
279 static const TDecompSVD & getSVD()
280 {
281  static TDecompSVD svd(getM<N>());
282  svd.Decompose();
283  return svd;
284 
285 
286 }
287 
288 #endif
289 
290 
291 template <unsigned N>
292 static void doQuadraticPeakFinding(const TH2D * hist, UCorrelator::peakfinder::FineMaximum * peak)
293 {
294  int xmax, ymax, ignored;
295  hist->GetMaximumBin(xmax,ymax,ignored);
296 
297  double dx = hist->GetXaxis()->GetBinWidth(1);
298  double dy = hist->GetYaxis()->GetBinWidth(1);
299  int nbinsx = hist->GetNbinsX();
300  int nbinsy = hist->GetNbinsY();
301  int width = nbinsx + 2;
302 
303  //build the linear system
304 #ifdef UCORRELATOR_USE_EIGEN_FOR_PEAK_FINDER
305  static const Eigen::JacobiSVD<Eigen::Matrix<double, N*N, 6> > & svd = getSVD<N>(); //I hope this works!
306  Eigen::Matrix<double,N*N,1> Z;
307 #else
308  static const TDecompSVD & svd = getSVD<N>();
309  TVectorD Z(N*N);
310 
311 #endif
312 
313  double xcenter = hist->GetXaxis()->GetBinCenter(xmax);
314  double ycenter = hist->GetYaxis()->GetBinCenter(ymax);
315 
316 
317  int halfway = N/2;
318  for (unsigned i = 0; i < N; i++)
319  {
320  for (unsigned j = 0; j < N; j++)
321  {
322  int ii = xmax + i - halfway;
323  int jj = ymax + j - halfway;
324  double z = ii < 1 || ii > nbinsx || jj < 1 || jj > nbinsy ? 0 : hist->GetArray()[ii + jj * width];
325  Z(i + j * N) = z;
326  }
327  }
328 
329  //solve the linear system
330 #ifdef UCORRELATOR_USE_EIGEN_FOR_PEAK_FINDER
331  Eigen::Matrix<double,6,1> B = svd.solve(Z);
332 #else
333  bool ok = true;
334  TVectorD B = ((TDecompSVD & )svd).Solve(Z,ok); // I think this is effectively const since the matrix is fixed, but maybe it'll backfire with multiple threads. In that case, use EIGEN I guess?
335  if (!ok)
336  {
337  fprintf(stderr, "Warning in doQuadraticPeakFinding: SVD decomposition failed!\n");
338  }
339 #endif
340 
341  //now do some algebra to figure out what x0,y0,sigma_x,sigma_y, covar are
342  //someone needs to check this
343  double a = B(X2COEFF);
344  double b = B(Y2COEFF);
345  double c = B(XYCOEFF);
346  double d = B(XCOEFF);
347  double e = B(YCOEFF);
348  double f = B(CCOEFF);
349 
350 // printf("[%f,%f,%f,%f,%f,%f]\n",a,b,c,d,e,f);
351 
352  //from taking gradient of ax^2 + by^2 + cxy + dx + ey + f and setting equal to 0
353  double x0 = (2 * b * d / c - e) / (c - 4*a*b / c);
354  double y0 = ( -d - 2* a * x0)/ c;
355 
356  peak->x = xcenter + x0*dx;
357  peak->y = ycenter + y0*dy;
358 
359  // now use -hessian matrix to compute variance, covariance. Not sure this is right.
360  // Could instead try to match coefficients to taylor expansion, but that's a lot of work!
361  peak->val = a*x0*x0 + b * y0*y0 + c * x0*y0 + d * x0 + e * y0 + f;
362  peak->sigma_x = sqrt(-2*b*peak->val / fabs(4*a*b - c*c))*dx; //i don't think that fabs is correct
363  peak->sigma_y = sqrt(-2*a*peak->val / fabs(4*a*b - c*c))*dy;
364  peak->covar = c*peak->val / fabs(4*a*b - c*c)*dx*dy;
365 #ifdef UCORRELATOR_USE_EIGEN_FOR_PEAK_FINDER
366  peak->chisq = (getM<N>() * B - Z).squaredNorm()/ (N*N);
367 #else
368  peak->chisq = (getM<N>() * B - Z).Norm2Sqr()/ (N*N);
369 #endif
370 
371 }
372 
373 
375 {
376  doQuadraticPeakFinding<3>(hist,peak);
377 }
378 
379 void UCorrelator::peakfinder::doPeakFindingQuadratic16(const TH2D * hist, FineMaximum * peak)
380 {
381  doQuadraticPeakFinding<4>(hist,peak);
382 }
383 
384 void UCorrelator::peakfinder::doPeakFindingQuadratic25(const TH2D * hist, FineMaximum * peak)
385 {
386  doQuadraticPeakFinding<5>(hist,peak);
387 }
388 
389 void UCorrelator::peakfinder::doPeakFindingQuadratic36(const TH2D * hist, FineMaximum * peak)
390 {
391  doQuadraticPeakFinding<6>(hist,peak);
392 }
393 
394 void UCorrelator::peakfinder::doPeakFindingQuadratic49(const TH2D * hist, FineMaximum * peak)
395 {
396  doQuadraticPeakFinding<7>(hist,peak);
397 }
398 
399 
400 
402 {
403  // This is mostly Abby's code, with some stuff in front and after to make it work here
404  // As far as I can tell, if there are any correlations between theta and phi in the peak, this will not give you
405  // the right answer, but maybe I'm wrong.
406 
407  int peakPhiBin, peakThetaBin, ignored;
408  int max_bin = hist->GetMaximumBin(peakPhiBin,peakThetaBin,ignored);
409  double peakVal = hist->GetArray()[max_bin];
410 
411  int NUM_BINS_FINE_THETA = hist->GetNbinsY();
412  int NUM_BINS_FINE_PHI = hist->GetNbinsX();
413  double FINE_BIN_SIZE=hist->GetXaxis()->GetBinWidth(1);
414 
415  int npointsTheta=NUM_BINS_FINE_THETA - 19; // ok...
416  int npointsPhi=NUM_BINS_FINE_THETA - 19;// why not...
417 
418  double thetaArray[npointsTheta];
419  double phiArray[npointsPhi];
420  double thetaValArray[npointsTheta], phiValArray[npointsPhi];
421 
422  for (int i=0;i<npointsTheta;i++){//construct an array of 10 values in phi and theta around the peak
423  if (int(peakThetaBin-npointsTheta/2.)>=0 && int(peakThetaBin+npointsTheta/2.)<NUM_BINS_FINE_THETA){
424  thetaValArray[i]=hist->GetBinContent(int(peakThetaBin-npointsTheta/2+i),peakPhiBin);
425  thetaArray[i]=hist->GetYaxis()->GetBinCenter(int(peakThetaBin-npointsTheta/2+i));
426  }
427 
428  else if(int(peakThetaBin-npointsTheta/2.)<0){
429  thetaValArray[i]=hist->GetBinContent(i,peakPhiBin);
430  thetaArray[i]=hist->GetYaxis()->GetBinCenter(i);
431  }
432  else{
433  thetaValArray[i]=hist->GetBinContent(NUM_BINS_FINE_THETA-(npointsTheta-i),peakPhiBin);
434  thetaArray[i]=hist->GetYaxis()->GetBinCenter(NUM_BINS_FINE_THETA-(npointsTheta-i));
435  }
436  }
437  for (int i=0;i<npointsPhi;i++){
438  if (int(peakPhiBin-npointsPhi/2.)>=0 && int(peakPhiBin+npointsPhi/2.)<NUM_BINS_FINE_PHI){
439  phiValArray[i]=hist->GetBinContent(peakThetaBin,int(peakPhiBin-npointsPhi/2+i));
440  phiArray[i]=hist->GetXaxis()->GetBinCenter(int(peakPhiBin-npointsPhi/2+i));
441  }
442 
443  else if (int(peakPhiBin-npointsPhi/2.)<0){
444  phiValArray[i]=hist->GetBinContent(peakThetaBin,i);
445  phiArray[i]=hist->GetXaxis()->GetBinCenter(i);
446  }
447  else{
448  phiValArray[i]=hist->GetBinContent(peakThetaBin,NUM_BINS_FINE_PHI-(npointsPhi-i));
449  phiArray[i]=hist->GetXaxis()->GetBinCenter(NUM_BINS_FINE_PHI-(npointsPhi-i));
450  }
451  //cout<<"i: "<<i<<", phi: "<<phiArray[i]<<", phiVal: "<<phiValArray[i]<<endl;
452  //cout<<"i: "<<i<<", theta: "<<thetaArray[i]<<", thetaVal: "<<thetaValArray[i]<<endl;
453  }
454 
455  //do interpolation with akima to get peak and find FWHM or something like that.
456  std::vector<double> thetaVector(npointsTheta);
457  std::vector<double> thetaValVector(npointsTheta);
458  std::vector<double> phiVector(npointsPhi);
459  std::vector<double> phiValVector(npointsPhi);
460  for (int i=0;i<npointsTheta;i++){
461  thetaVector[i]=thetaArray[i];
462  thetaValVector[i]=thetaValArray[i];
463  }
464  for (int i=0;i<npointsPhi;i++){
465  phiVector[i]=phiArray[i];
466  phiValVector[i]=phiValArray[i];
467  }
468 
469  ROOT::Math::Interpolator interpolatorTheta(thetaVector.size(), ROOT::Math::Interpolation::kAKIMA );
470  interpolatorTheta.SetData(thetaVector,thetaValVector);
471  ROOT::Math::Interpolator interpolatorPhi(phiVector.size(), ROOT::Math::Interpolation::kAKIMA );
472  interpolatorPhi.SetData(phiVector,phiValVector);
473 
474  int upsampleFactor=100;
475  int interpCtr=0;
476  double interpThetaArray[npointsTheta*upsampleFactor], interpThetaValArray[npointsTheta*upsampleFactor];
477  double interpPhiArray[npointsPhi*upsampleFactor], interpPhiValArray[npointsPhi*upsampleFactor];
478 
479  for (double interp_theta=thetaArray[0];interp_theta<thetaArray[npointsTheta-1];
480  interp_theta+=FINE_BIN_SIZE/double(upsampleFactor)){
481  interpThetaArray[interpCtr]=interp_theta;
482  interpThetaValArray[interpCtr]=interpolatorTheta.Eval(interp_theta);
483  interpCtr++;
484  }
485 
486  interpCtr=0;
487  for (double interp_phi=phiArray[0];interp_phi<phiArray[npointsPhi-1];interp_phi+=FINE_BIN_SIZE/double(upsampleFactor)){
488  interpPhiArray[interpCtr]=interp_phi;
489  interpPhiValArray[interpCtr]=interpolatorPhi.Eval(interp_phi);
490  interpCtr++;
491  }
492 
493 
494  //make a graph of
495  TGraph *gInterpTheta=new TGraph((npointsTheta-1)*upsampleFactor,interpThetaArray,interpThetaValArray);
496  TGraph *gInterpPhi=new TGraph((npointsPhi-1)*upsampleFactor,interpPhiArray,interpPhiValArray);
497 
498  /*
499  if (drawFlag==1){
500  TCanvas *cInterpolation=new TCanvas("cInterpolation","cInterpolation",800,800);
501  cInterpolation->Divide(1,2);
502  cInterpolation->cd(1);
503  gInterpTheta->Draw("aP");
504  gInterpTheta->SetMarkerStyle(22);
505  gInterpTheta->SetMarkerSize(0.5);
506  cInterpolation->cd(2);
507  gInterpPhi->SetMarkerStyle(22);
508  gInterpPhi->SetMarkerSize(0.5);
509  gInterpPhi->Draw("aP");
510 // cInterpolation->Print("interpolatedPeak.eps");
511 
512  }
513 */
514 
515  //get the peak of the interpolated graph.
516  Int_t peakBinTheta=FFTtools::getPeakBin(gInterpTheta);
517  Double_t peakValTheta;
518  Double_t peakTheta;
519  gInterpTheta->GetPoint(peakBinTheta,peakTheta,peakValTheta);
520  Int_t peakBinPhi=FFTtools::getPeakBin(gInterpPhi);
521  Double_t peakValPhi;
522  Double_t peakPhi;
523  gInterpPhi->GetPoint(peakBinPhi,peakPhi,peakValPhi);
524 
525  delete gInterpTheta;
526  delete gInterpPhi;
527 
528 // if (printFlag==1) cout<<"Peak of interpolation in theta: "<<peakTheta<<", and phi: "<<peakPhi<<endl;
529  if (peakValTheta<peakValPhi) peakVal=peakValTheta;
530  else peakVal=peakValPhi;
531 
532  //get the FWHM of the peak
533  double halfPeakThetaLeft=0;
534  double halfPeakThetaRight=0;
535 
536  for (int i=0;i<(npointsTheta-1)*upsampleFactor;i++){
537  if (peakBinTheta-i>0){
538  if (interpThetaValArray[peakBinTheta-i]<peakValTheta/2.
539  && interpThetaValArray[peakBinTheta-(i-1)]>peakValTheta/2.){
540  halfPeakThetaLeft=(interpThetaArray[peakBinTheta-i]+interpThetaArray[peakBinTheta-(i-1)])/2.;
541  }
542  }
543  if (halfPeakThetaLeft!=0) break;
544  }
545  //if (halfPeakThetaLeft==0) halfPeakThetaLeft=interpThetaArray[0];
546 
547  for (int i=0;i<(npointsTheta-1)*upsampleFactor;i++){
548  if (peakBinTheta+i<(npointsTheta-1)*upsampleFactor){
549  if (interpThetaValArray[peakBinTheta+i]<peakValTheta/2.
550  && interpThetaValArray[peakBinTheta+(i-1)]>peakValTheta/2.){
551  halfPeakThetaRight=(interpThetaArray[peakBinTheta+i]+interpThetaArray[peakBinTheta+(i-1)])/2.;
552  }
553  }
554  if (halfPeakThetaRight!=0) break;
555  }
556  // if (halfPeakThetaRight==0) halfPeakThetaRight=interpThetaArray[(npointsTheta-1)*upsampleFactor];
557 
558  double halfPeakPhiLeft=0;
559  double halfPeakPhiRight=0;
560  for (int i=0;i<(npointsPhi-1)*upsampleFactor;i++){
561  if (peakBinPhi-i>0){
562  if (interpPhiValArray[peakBinPhi-i]<peakValPhi/2. && interpPhiValArray[peakBinPhi-(i-1)]>peakValPhi/2.){
563  halfPeakPhiLeft=(interpPhiArray[peakBinPhi-i]+interpPhiArray[peakBinPhi-(i-1)])/2.;
564  }
565  }
566  if (halfPeakPhiLeft!=0) break;
567  }
568  //if (halfPeakPhiLeft==0) halfPeakPhiLeft=interpPhiArray[0];
569 
570  for (int i=0;i<(npointsPhi-1)*upsampleFactor;i++){
571  if (peakBinPhi+i<(npointsPhi-1)*upsampleFactor){
572  if (interpPhiValArray[peakBinPhi+i]<peakValPhi/2. && interpPhiValArray[peakBinPhi+(i-1)]>peakValPhi/2.){
573  halfPeakPhiRight=(interpPhiArray[peakBinPhi+i]+interpPhiArray[peakBinPhi+(i-1)])/2.;
574  }
575  }
576  if (halfPeakPhiRight!=0) break;
577  }
578  // if (halfPeakPhiRight==0) halfPeakPhiRight=interpPhiArray[(npointsPhi-1)*upsampleFactor];
579 
580  Double_t FWHMTheta, FWHMPhi;
581  if (halfPeakThetaRight==0 || halfPeakThetaLeft==0) FWHMTheta=-1;
582  else FWHMTheta=halfPeakThetaRight-halfPeakThetaLeft;
583  if (halfPeakPhiRight==0 || halfPeakPhiLeft==0) FWHMPhi=-1;
584  else FWHMPhi=halfPeakPhiRight-halfPeakPhiLeft;
585 // if (printFlag==1) cout<<"FWHM Theta: "<<FWHMTheta<<", FWHM Phi: "<<FWHMPhi<<endl;
586 
587 
588  const double fwhm_conversion = 2 * sqrt(2 * log(2));
589 
590  peak->x = peakPhi;
591  peak->y = peakTheta;
592  peak->sigma_x = FWHMPhi / fwhm_conversion;
593  peak->sigma_y = FWHMTheta / fwhm_conversion;
594  peak->covar = 0;
595  peak->val = peakVal;
596  peak->chisq = 0; // not sure what the best way to do this is
597 
598 }
599 
600 
601 
602 const int GAUS_A = 0;
603 const int GAUS_X0 = 1;
604 const int GAUS_Y0 = 2;
605 const int GAUS_SIGMA_X = 3;
606 const int GAUS_SIGMA_Y = 4;
607 const int GAUS_COVAR = 5;
608 const int GAUS_PEDESTAL = 6;
609 const int GAUS_NPAR = 7;
610 
611 static double gaus2d(double *xx, double *ps)
612 {
613 
614  double A = ps[GAUS_A];
615  double sx = ps[GAUS_SIGMA_X];
616  double sy = ps[GAUS_SIGMA_Y];
617  double x0 = ps[GAUS_X0];
618  double y0 = ps[GAUS_Y0];
619  double p = ps[GAUS_COVAR];
620  double z0 = ps[GAUS_PEDESTAL];
621 
622  double x= xx[0];
623  double y= xx[1];
624 
625  return z0 + A / (2 * M_PI * sx * sy * sqrt(1-p*p))
626  * exp( - (x-x0)*(x-x0) / (2 * sx * sx * (1-p*p))
627  - (y-y0)*(y-y0) / (2 * sy * sy * (1-p*p))
628  + p * (x-x0) * (y-y0) / ( (1-p*p) * sx * sy)
629  );
630 }
631 
633 {
634 
635 
636  TF2 gaus2dfn("fitter", gaus2d, GAUS_NPAR,
637  zoomed->GetXaxis()->GetXmin(), zoomed->GetXaxis()->GetXmax(),
638  zoomed->GetYaxis()->GetXmin(), zoomed->GetYaxis()->GetXmax() );
639 
640  int xmax, ymax, ignored;
641  int max_bin = zoomed->GetMaximumBin(xmax,ymax,ignored);
642  gaus2dfn.SetParameter(GAUS_A, zoomed->GetArray()[max_bin]);
643  gaus2dfn.SetParameter(GAUS_SIGMA_X, zoomed->GetRMS(1));
644  gaus2dfn.SetParameter(GAUS_SIGMA_Y, zoomed->GetRMS(2));
645  gaus2dfn.SetParameter(GAUS_X0, zoomed->GetXaxis()->GetBinCenter(xmax));
646  gaus2dfn.SetParameter(GAUS_Y0, zoomed->GetYaxis()->GetBinCenter(ymax));
647  gaus2dfn.SetParameter(GAUS_COVAR, 0);
648  gaus2dfn.SetParameter(GAUS_PEDESTAL, 0);
649 
650  TH2D copy = *zoomed;
651  copy.Fit(&gaus2dfn, "NQ");
652 
653  peak->sigma_x = gaus2dfn.GetParameter(GAUS_SIGMA_X);
654  peak->sigma_y = gaus2dfn.GetParameter(GAUS_SIGMA_Y);
655  peak->covar = gaus2dfn.GetParameter(GAUS_COVAR) * peak->sigma_x * peak->sigma_y;
656  peak->x = gaus2dfn.GetParameter(GAUS_X0);
657  peak->y = gaus2dfn.GetParameter(GAUS_Y0);
658  peak->val = gaus2dfn.GetParameter(GAUS_A) / (2 * M_PI * peak->sigma_x * peak->sigma_y * sqrt(1-peak->covar *peak->covar));
659  peak->chisq = gaus2dfn.GetChisquare()/ gaus2dfn.GetNDF();
660 }
661 
662 
663 const double M1_elems[] = { 1,0,0,0,
664  0,0,1,0,
665  -3,3,-2,-1,
666  2,-2,1,1};
667 
668 const static TMatrixD M1(4,4, M1_elems);
669 const double M2_elems[] = { 1,0,-3,2,
670  0,0,3,-2,
671  0,1,-2,1,
672  0,0,-1,1};
673 
674 const static TMatrixD M2(4,4, M2_elems);
675 
676 
677 
678 
679 class NegativeBicubicFunction : public ROOT::Math::IGradientFunctionMultiDim
680 {
681 
682  public:
683  NegativeBicubicFunction( const double m[4][4], double xwidth, double ywidth) ;
684  NegativeBicubicFunction( const NegativeBicubicFunction & other) { memcpy(a,other.a, sizeof(a)); }
685 
686  virtual double DoEval(const double * x) const;
687  virtual double DoDerivative(const double * x, unsigned int coord) const;
688  unsigned NDim() const { return 2; }
689 
690  virtual ROOT::Math::IBaseFunctionMultiDim * Clone() const { return new NegativeBicubicFunction(*this); }
691 
692  private:
693  double a[4][4];
694 };
695 
696 
697 NegativeBicubicFunction::NegativeBicubicFunction (const double m[4][4], double xw, double yw)
698 {
699  TMatrixD Mf(4,4);
700  //construct the bicubic polynomial over this bin
701 
702  // This uses notation similar to wikipedia
703 
704 
705  double f_00 = m[1][1];
706  double f_11 = m[2][2];
707  double f_01 = m[1][2];
708  double f_10 = m[2][1];
709 
710 
711  double fx_00 = (m[2][1] - m[0][1]) / (2*xw);
712  double fx_10 = (m[3][1] - m[1][1]) / (2*xw);
713  double fx_01 = (m[2][2] - m[0][2]) / (2*xw);
714  double fx_11 = (m[3][2] - m[1][2]) / (2*xw);
715 
716  double fy_00 = (m[1][2] - m[1][0]) / (2*yw);
717  double fy_10 = (m[2][2] - m[2][0]) / (2*yw);
718  double fy_01 = (m[1][3] - m[1][1]) / (2*yw);
719  double fy_11 = (m[2][3] - m[2][1]) / (2*yw);
720 
721  double fxy_00 = ( (m[2][2] - m[0][2]) -(m[2][0] - m[0][0])) / (4*xw*yw) ;
722  double fxy_01 = ( (m[2][3] - m[0][3]) -(m[2][1] - m[0][1])) / (4*xw*yw) ;
723  double fxy_10 = ( (m[3][2] - m[1][2]) -(m[3][0] - m[1][0])) / (4*xw*yw) ;
724  double fxy_11 = ( (m[3][3] - m[1][3]) -(m[3][1] - m[1][1])) / (4*xw*yw) ;
725 
726  Mf(0,0) = f_00; Mf(0,1) = f_01; Mf(0,2) = fy_00; Mf(0,3) = fy_01;
727  Mf(1,0) = f_10; Mf(1,1) = f_11; Mf(1,2) = fy_10; Mf(1,3) = fy_11;
728  Mf(2,0) = fx_00; Mf(2,1) = fx_01; Mf(2,2) = fxy_00; Mf(2,3) = fxy_01;
729  Mf(3,0) = fx_10; Mf(3,1) = fx_11; Mf(3,2) = fxy_10; Mf(3,3) = fxy_11;
730 
731  //now there is probably some smart way to reuse some of the information between bins, but I dont' feel like figuring it out right now
732 
733  TMatrix Ma = M1 * Mf * M2;
734  for (int i = 0; i < 4; i++)
735  {
736  for (int j = 0; j < 4; j++)
737  {
738  a[i][j] = Ma(i,j);
739  }
740  }
741 
742 }
743 
744 double NegativeBicubicFunction::DoEval(const double * p) const
745 {
746  double x[4];
747  double y[4];
748  x[0] = 1;
749  y[0] = 1;
750  for (int i = 1; i < 3; i++)
751  {
752  x[i] = p[0] * x[i-1];
753  y[i] = p[1] * y[i-1];
754  }
755 
756 
757  double val = 0;
758 
759  for (int i = 0; i < 3; i++)
760  {
761  for (int j = 0; j < 3; j++)
762  {
763  val += a[i][j] * x[i] * y[j];
764  }
765  }
766 
767  return -val;
768 }
769 
770 double NegativeBicubicFunction::DoDerivative(const double * p, unsigned int coord) const
771 {
772  double x[4];
773  double y[4];
774  x[0] = 1;
775  y[0] = 1;
776  for (int i = 1; i < 3; i++)
777  {
778  x[i] = p[0] * x[i-1];
779  y[i] = p[1] * y[i-1];
780  }
781 
782 
783  double val = 0;
784 
785 
786  if (coord == 0)
787  {
788  for (int i = 1; i < 3; i++)
789  {
790  for (int j = 0; j < 3; j++)
791  {
792  val += a[i][j] * x[i-1] * y[j] * i;
793  }
794  }
795  }
796  else
797  {
798  for (int i = 0; i < 3; i++)
799  {
800  for (int j = 1; j < 3; j++)
801  {
802  val += a[i][j] * x[i] * y[j-1]*j;
803  }
804  }
805  }
806 
807  return -val;
808 }
809 
810 
811 static __thread ROOT::Minuit2::Minuit2Minimizer *min = 0;
812 
813 void UCorrelator::peakfinder::doInterpolationPeakFindingBicubic(const TH2D * zoomed, FineMaximum * peak, double min_to_consider )
814 {
815 
816  TMatrixD Mf(4,4);
817  double xwidth = zoomed->GetXaxis()->GetBinWidth(1);
818  double ywidth = zoomed->GetYaxis()->GetBinWidth(1);
819  double m[4][4];
820 
821  if (!min) min = new ROOT::Minuit2::Minuit2Minimizer;
822 
823  double stupid_max = zoomed->GetMaximum();
824 
825  peak->val = 0;
826 
827  for (int i = 2; i < zoomed->GetNbinsX(); i++)
828  {
829  for (int j = 2; j < zoomed->GetNbinsY(); j++)
830  {
831  //stupid heuristic quick fail
832  bool ok = false;
833  for (int ii = -1; ii < 3; ii++)
834  {
835  for (int jj = -1; jj < 3; jj++)
836  {
837  double val = zoomed->GetBinContent(i+ii, j+ii);
838  if (val > stupid_max * min_to_consider) ok = true;
839 
840  m[ii+1][jj+1] = zoomed->GetBinContent(i+ii,j+jj);
841  }
842  }
843 
844  if (!ok) continue;
845 
846  NegativeBicubicFunction f(m,xwidth,ywidth);
847 
848  min->Clear();
849  min->SetFunction(f);
850  min->SetLimitedVariable(0,"x", 0.5, 0.1, 0,1);
851  min->SetLimitedVariable(1,"y", 0.5, 0.1, 0,1);
852 
853 
854  //shut it up
855  int old_level = gErrorIgnoreLevel;
856  min->Minimize();
857  gErrorIgnoreLevel = old_level;
858 
859 
860  if (-min->MinValue() > peak->val)
861  {
862  peak->val = -min->MinValue();
863  peak->x = min->X()[0];
864  peak->y = min->X()[1];
865  peak->sigma_x = sqrt(min->CovMatrix(0,0));
866  peak->sigma_y = sqrt(min->CovMatrix(1,1));
867  peak->covar = min->CovMatrix(0,1);
868  peak->chisq = 0;
869  }
870  }
871  }
872 }
873 
874 
876 {
877 
878  int max_bin = hist->GetMaximumBin();
879  int bx,by,bz;
880  hist->GetBinXYZ(max_bin,bx,by,bz);
881 
882  peak->val = hist->GetBinContent(bx,by);
883  peak->x = hist->GetXaxis()->GetBinCenter(bx);
884  peak->y = hist->GetYaxis()->GetBinCenter(by);
885 
886  //compute covariance matrix around point
887 
888  double var_x = 0;
889  double var_y = 0;
890  double covar = 0;
891  double total = 0;
892 
893  for (int i = 1; i <= hist->GetNbinsX(); i++)
894  {
895  for (int j = 1; j <= hist->GetNbinsY(); j++)
896  {
897  double val = hist->GetBinContent(i,j);
898  double x = hist->GetXaxis()->GetBinCenter(i);
899  double y = hist->GetYaxis()->GetBinCenter(j);
900 
901  total += val;
902  var_x += val * (x-peak->x) * (x-peak->x);
903  var_y += val * (y-peak->y) * (y-peak->y);
904  covar += val * (y-peak->y) * (x-peak->x);
905  }
906  }
907 
908 
909  peak->sigma_x = sqrt( var_x / (total-1));
910  peak->sigma_y = sqrt( var_y / (total-1));
911  peak->covar = covar / (total - 1);
912  peak->chisq = 0;
913 }
914 
int findIsolatedMaxima(const TH2D *hist, double distance, int Nmaxima, RoughMaximum *maxima, double minPhi=0., double maxPhi=0., double minTheta=0., double maxTheta=0., bool exclude=false, bool use_bin_center=true)
Definition: PeakFinder.cc:112
void doPeakFindingGaussian(const TH2D *hist, FineMaximum *peak)
Definition: PeakFinder.cc:632
Double_t sigma_theta
on continent, or -9999 if doesn&#39;t intersect
void copyToPointingHypothesis(AnitaEventSummary::PointingHypothesis *p)
Definition: PeakFinder.cc:203
void doPeakFindingHistogram(const TH2D *hist, FineMaximum *peak)
Definition: PeakFinder.cc:875
void doPeakFindingQuadratic9(const TH2D *hist, FineMaximum *peak)
Definition: PeakFinder.cc:374
Double_t chisq
correlation coefficient between theta and phi
void doInterpolationPeakFindingBicubic(const TH2D *hist, FineMaximum *peak, double min_to_consider=0.75)
Definition: PeakFinder.cc:813
Int_t getPeakBin(const TGraph *gr)
Find the peak (maximum positive) bin in a TGraph.
Definition: FFTtools.cxx:1456
Double_t theta
peak phi, degrees
void wrap(size_t N, double *vals, double period=360)
Definition: FFTtools.cxx:2851
void doInterpolationPeakFindingAbby(const TH2D *hist, FineMaximum *peak)
Definition: PeakFinder.cc:401
Double_t value
peak theta, degrees