CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
MuonResidualsFitter.cc
Go to the documentation of this file.
1 // $Id: MuonResidualsFitter.cc,v 1.12 2011/10/12 23:44:11 khotilov Exp $
2 
3 #ifdef STANDALONE_FITTER
4 #include "MuonResidualsFitter.h"
5 #else
7 #endif
8 
9 #include <fstream>
10 #include <set>
11 #include "TMath.h"
12 #include "TH1.h"
13 #include "TF1.h"
14 #include "TRobustEstimator.h"
15 
16 // all global variables begin with "MuonResidualsFitter_" to avoid
17 // namespace clashes (that is, they do what would ordinarily be done
18 // with a class structure, but Minuit requires them to be global)
19 
20 const double MuonResidualsFitter_gsbinsize = 0.01;
21 const double MuonResidualsFitter_tsbinsize = 0.1;
24 
27 
29 
30 // fit function
31 double MuonResidualsFitter_logPureGaussian(double residual, double center, double sigma)
32 {
33  sigma = fabs(sigma);
34  static const double cgaus = 0.5 * log( 2.*M_PI );
35  return (-pow(residual - center, 2) *0.5 / sigma / sigma) - cgaus - log(sigma);
36 }
37 
38 // TF1 interface version
39 Double_t MuonResidualsFitter_pureGaussian_TF1(Double_t *xvec, Double_t *par)
40 {
41  return par[0] * exp(MuonResidualsFitter_logPureGaussian(xvec[0], par[1], par[2]));
42 }
43 
44 
45 // 2D Gauss fit function
46 double MuonResidualsFitter_logPureGaussian2D(double x, double y, double x0, double y0, double sx, double sy, double r)
47 {
48  sx = fabs(sx); sy = fabs(sy);
49  static const double c2gaus = log( 2.*M_PI );
50  double one_r2 = 1. - r*r;
51  double dx = x - x0;
52  double dy = y - y0;
53  return -0.5/one_r2 * ( pow(dx/sx, 2) + pow(dy/sy, 2) - 2.*r*dx/sx*dy/sy ) - c2gaus - log(sx*sy*sqrt(one_r2));
54 }
55 
56 
57 double MuonResidualsFitter_compute_log_convolution(double toversigma, double gammaoversigma, double max, double step, double power)
58 {
59  if (gammaoversigma == 0.) return (-toversigma*toversigma/2.) - log(sqrt(2*M_PI));
60 
61  double sum = 0.;
62  double uplus = 0.;
63  double integrandplus_last = 0.;
64  double integrandminus_last = 0.;
65  for (double inc = 0.; uplus < max; inc += step)
66  {
67  double uplus_last = uplus;
68  uplus = pow(inc, power);
69 
70  double integrandplus = exp(-pow(uplus - toversigma, 2)/2.) / (uplus*uplus/gammaoversigma + gammaoversigma) / M_PI / sqrt(2.*M_PI);
71  double integrandminus = exp(-pow(-uplus - toversigma, 2)/2.) / (uplus*uplus/gammaoversigma + gammaoversigma) / M_PI / sqrt(2.*M_PI);
72 
73  sum += integrandplus * (uplus - uplus_last);
74  sum += 0.5 * fabs(integrandplus_last - integrandplus) * (uplus - uplus_last);
75 
76  sum += integrandminus * (uplus - uplus_last);
77  sum += 0.5 * fabs(integrandminus_last - integrandminus) * (uplus - uplus_last);
78 
79  integrandplus_last = integrandplus;
80  integrandminus_last = integrandminus;
81  }
82  return log(sum);
83 }
84 
85 // fit function
86 double MuonResidualsFitter_logPowerLawTails(double residual, double center, double sigma, double gamma)
87 {
88  sigma = fabs(sigma);
89  double gammaoversigma = fabs(gamma / sigma);
90  double toversigma = fabs((residual - center) / sigma);
91 
92  int gsbin0 = int(floor(gammaoversigma / MuonResidualsFitter_gsbinsize));
93  int gsbin1 = int(ceil(gammaoversigma / MuonResidualsFitter_gsbinsize));
94  int tsbin0 = int(floor(toversigma / MuonResidualsFitter_tsbinsize));
95  int tsbin1 = int(ceil(toversigma / MuonResidualsFitter_tsbinsize));
96 
97  bool gsisbad = (gsbin0 >= MuonResidualsFitter_numgsbins || gsbin1 >= MuonResidualsFitter_numgsbins);
98  bool tsisbad = (tsbin0 >= MuonResidualsFitter_numtsbins || tsbin1 >= MuonResidualsFitter_numtsbins);
99 
100  if (gsisbad || tsisbad)
101  {
102  return log(gammaoversigma/M_PI) - log(toversigma*toversigma + gammaoversigma*gammaoversigma) - log(sigma);
103  }
104  else
105  {
106  double val00 = MuonResidualsFitter_lookup_table[gsbin0][tsbin0];
107  double val01 = MuonResidualsFitter_lookup_table[gsbin0][tsbin1];
108  double val10 = MuonResidualsFitter_lookup_table[gsbin1][tsbin0];
109  double val11 = MuonResidualsFitter_lookup_table[gsbin1][tsbin1];
110 
111  double val0 = val00 + ((toversigma / MuonResidualsFitter_tsbinsize) - tsbin0) * (val01 - val00);
112  double val1 = val10 + ((toversigma / MuonResidualsFitter_tsbinsize) - tsbin0) * (val11 - val10);
113 
114  double val = val0 + ((gammaoversigma / MuonResidualsFitter_gsbinsize) - gsbin0) * (val1 - val0);
115 
116  return val - log(sigma);
117  }
118 }
119 
120 
121 // TF1 interface version
122 Double_t MuonResidualsFitter_powerLawTails_TF1(Double_t *xvec, Double_t *par)
123 {
124  return par[0] * exp(MuonResidualsFitter_logPowerLawTails(xvec[0], par[1], par[2], par[3]));
125 }
126 
127 
128 double MuonResidualsFitter_logROOTVoigt(double residual, double center, double sigma, double gamma)
129 {
130  return log(TMath::Voigt(residual - center, fabs(sigma), fabs(gamma)*2.));
131 }
132 
133 
134 Double_t MuonResidualsFitter_ROOTVoigt_TF1(Double_t *xvec, Double_t *par)
135 {
136  return par[0] * TMath::Voigt(xvec[0] - par[1], fabs(par[2]), fabs(par[3])*2.);
137 }
138 
139 
140 double MuonResidualsFitter_logGaussPowerTails(double residual, double center, double sigma) {
141  double x = residual-center;
142  double s = fabs(sigma);
143  double m = 2.*s;
144  static const double e2 = exp(-2.), sqerf = sqrt(2.*M_PI)*erf(sqrt(2.));
145  double a = pow(m,4)*e2;
146  double n = sqerf*s + 2.*a*pow(m,-3)/3.;
147 
148  if (fabs(x)<m) return -x*x/(2.*s*s) - log(n);
149  else return log(a) -4.*log(fabs(x)) - log(n);
150 }
151 
152 
153 Double_t MuonResidualsFitter_GaussPowerTails_TF1(Double_t *xvec, Double_t *par)
154 {
155  return par[0] * exp(MuonResidualsFitter_logGaussPowerTails(xvec[0], par[1], par[2]));
156 }
157 
158 
159 double MuonResidualsFitter_integrate_pureGaussian(double low, double high, double center, double sigma)
160 {
161  static const double isqr2 = 1./sqrt(2.);
162  return (erf((high + center) * isqr2 / sigma) - erf((low + center) * isqr2 / sigma)) * exp(0.5/sigma/sigma) * 0.5;
163 }
164 
165 
167 {
170 
171  std::ifstream convolution_table("convolution_table.txt");
172  if (convolution_table.is_open())
173  {
174  int numgsbins = 0;
175  int numtsbins = 0;
176  double tsbinsize = 0.;
177  double gsbinsize = 0.;
178 
179  convolution_table >> numgsbins >> numtsbins >> tsbinsize >> gsbinsize;
180  if (numgsbins != MuonResidualsFitter_numgsbins || numtsbins != MuonResidualsFitter_numtsbins ||
182  {
183  throw cms::Exception("MuonResidualsFitter") << "convolution_table.txt has the wrong bin width/bin size. Throw it away and let the fitter re-create the file.\n";
184  }
185 
186  for (int gsbin = 0; gsbin < MuonResidualsFitter_numgsbins; gsbin++)
187  {
188  for (int tsbin = 0; tsbin < MuonResidualsFitter_numtsbins; tsbin++)
189  {
190  int read_gsbin = 0;
191  int read_tsbin = 0;
192  double val = 0.;
193 
194  convolution_table >> read_gsbin >> read_tsbin >> val;
195  if (read_gsbin != gsbin || read_tsbin != tsbin)
196  {
197  throw cms::Exception("MuonResidualsFitter") << "convolution_table.txt is out of order. Throw it away and let the fitter re-create the file.\n";
198  }
199  MuonResidualsFitter_lookup_table[gsbin][tsbin] = val;
200  }
201  }
202  convolution_table.close();
203  }
204  else
205  {
206  std::ofstream convolution_table2("convolution_table.txt");
207 
208  if (!convolution_table2.is_open()) throw cms::Exception("MuonResidualsFitter") << "Couldn't write to file convolution_table.txt\n";
209 
211 
212  std::cout << "Initializing convolution look-up table (takes a few minutes)..." << std::endl;
213 
214  for (int gsbin = 0; gsbin < MuonResidualsFitter_numgsbins; gsbin++)
215  {
216  double gammaoversigma = double(gsbin) * MuonResidualsFitter_gsbinsize;
217  std::cout << " gsbin " << gsbin << "/" << MuonResidualsFitter_numgsbins << std::endl;
218  for (int tsbin = 0; tsbin < MuonResidualsFitter_numtsbins; tsbin++)
219  {
220  double toversigma = double(tsbin) * MuonResidualsFitter_tsbinsize;
221 
222  // 1e-6 errors (out of a value of ~0.01) with max=100, step=0.001, power=4 (max=1000 does a little better with the tails)
223  MuonResidualsFitter_lookup_table[gsbin][tsbin] = MuonResidualsFitter_compute_log_convolution(toversigma, gammaoversigma);
224 
225  // <10% errors with max=20, step=0.005, power=4 (faster computation for testing)
226  // MuonResidualsFitter_lookup_table[gsbin][tsbin] = MuonResidualsFitter_compute_log_convolution(toversigma, gammaoversigma, 100., 0.005, 4.);
227 
228  convolution_table2 << gsbin << " " << tsbin << " " << MuonResidualsFitter_lookup_table[gsbin][tsbin] << std::endl;
229  }
230  }
231  convolution_table2.close();
232  std::cout << "Initialization done!" << std::endl;
233  }
234 }
235 
236 
237 bool MuonResidualsFitter::dofit(void (*fcn)(int&,double*,double&,double*,int), std::vector<int> &parNum, std::vector<std::string> &parName,
238  std::vector<double> &start, std::vector<double> &step, std::vector<double> &low, std::vector<double> &high)
239 {
241 
242  MuonResidualsFitter_TMinuit = new TMinuit(npar());
244  MuonResidualsFitter_TMinuit->SetObjectFit(fitinfo);
247 
248  std::vector<int>::const_iterator iNum = parNum.begin();
249  std::vector<std::string>::const_iterator iName = parName.begin();
250  std::vector<double>::const_iterator istart = start.begin();
251  std::vector<double>::const_iterator istep = step.begin();
252  std::vector<double>::const_iterator ilow = low.begin();
253  std::vector<double>::const_iterator ihigh = high.begin();
254 
255  //MuonResidualsFitter_TMinuit->SetPrintLevel(-1);
256 
257  for (; iNum != parNum.end(); ++iNum, ++iName, ++istart, ++istep, ++ilow, ++ihigh)
258  {
259  MuonResidualsFitter_TMinuit->DefineParameter(*iNum, iName->c_str(), *istart, *istep, *ilow, *ihigh);
260  if (fixed(*iNum)) MuonResidualsFitter_TMinuit->FixParameter(*iNum);
261  }
262 
263  double arglist[10];
264  int ierflg;
265  int smierflg; //second MIGRAD ierflg
266 
267  // chi^2 errors should be 1.0, log-likelihood should be 0.5
268  for (int i = 0; i < 10; i++) arglist[i] = 0.;
269  arglist[0] = 0.5;
270  ierflg = 0;
271  smierflg = 0;
272  MuonResidualsFitter_TMinuit->mnexcm("SET ERR", arglist, 1, ierflg);
273  if (ierflg != 0) { delete MuonResidualsFitter_TMinuit; delete fitinfo; return false; }
274 
275  // set strategy = 2 (more refined fits)
276  for (int i = 0; i < 10; i++) arglist[i] = 0.;
277  arglist[0] = m_strategy;
278  ierflg = 0;
279  MuonResidualsFitter_TMinuit->mnexcm("SET STR", arglist, 1, ierflg);
280  if (ierflg != 0) { delete MuonResidualsFitter_TMinuit; delete fitinfo; return false; }
281 
282  bool try_again = false;
283 
284  // minimize
285  for (int i = 0; i < 10; i++) arglist[i] = 0.;
286  arglist[0] = 50000;
287  ierflg = 0;
288  MuonResidualsFitter_TMinuit->mnexcm("MIGRAD", arglist, 1, ierflg);
289  if (ierflg != 0) try_again = true;
290 
291  // just once more, if needed (using the final Minuit parameters from the failed fit; often works)
292  if (try_again)
293  {
294  for (int i = 0; i < 10; i++) arglist[i] = 0.;
295  arglist[0] = 50000;
296  MuonResidualsFitter_TMinuit->mnexcm("MIGRAD", arglist, 1, smierflg);
297  }
298 
299  Double_t fmin, fedm, errdef;
300  Int_t npari, nparx, istat;
301  MuonResidualsFitter_TMinuit->mnstat(fmin, fedm, errdef, npari, nparx, istat);
302 
303  if (istat != 3)
304  {
305  for (int i = 0; i < 10; i++) arglist[i] = 0.;
306  ierflg = 0;
307  MuonResidualsFitter_TMinuit->mnexcm("HESSE", arglist, 0, ierflg);
308  }
309 
310  // read-out the results
311  m_loglikelihood = -fmin;
312 
313  m_value.clear();
314  m_error.clear();
315  for (int i = 0; i < npar(); i++)
316  {
317  double v, e;
318  MuonResidualsFitter_TMinuit->GetParameter(i, v, e);
319  m_value.push_back(v);
320  m_error.push_back(e);
321  }
322  m_cov.ResizeTo(npar(),npar());
323  MuonResidualsFitter_TMinuit->mnemat( m_cov.GetMatrixArray(), npar());
324 
326  delete fitinfo;
327  if (smierflg != 0) return false;
328  return true;
329 }
330 
331 
332 void MuonResidualsFitter::write(FILE *file, int which)
333 {
334  long rows = numResiduals();
335  int cols = ndata();
336  int whichcopy = which;
337 
338  fwrite(&rows, sizeof(long), 1, file);
339  fwrite(&cols, sizeof(int), 1, file);
340  fwrite(&whichcopy, sizeof(int), 1, file);
341 
342  double *likeAChecksum = new double[cols];
343  double *likeAChecksum2 = new double[cols];
344  for (int i = 0; i < cols; i++)
345  {
346  likeAChecksum[i] = 0.;
347  likeAChecksum2[i] = 0.;
348  }
349 
350  for (std::vector<double*>::const_iterator residual = residuals_begin(); residual != residuals_end(); ++residual)
351  {
352  fwrite((*residual), sizeof(double), cols, file);
353  for (int i = 0; i < cols; i++)
354  {
355  if (fabs((*residual)[i]) > likeAChecksum[i]) likeAChecksum[i] = fabs((*residual)[i]);
356  if (fabs((*residual)[i]) < likeAChecksum2[i]) likeAChecksum2[i] = fabs((*residual)[i]);
357  }
358  } // end loop over residuals
359 
360  // the idea is that mal-formed doubles are likely to be huge values (or tiny values)
361  // because the exponent gets screwed up; we want to check for that
362  fwrite(likeAChecksum, sizeof(double), cols, file);
363  fwrite(likeAChecksum2, sizeof(double), cols, file);
364 
365  delete [] likeAChecksum;
366  delete [] likeAChecksum2;
367 }
368 
369 void MuonResidualsFitter::read(FILE *file, int which)
370 {
371  long rows = -100;
372  int cols = -100;
373  int readwhich = -100;
374 
375  fread(&rows, sizeof(long), 1, file);
376  fread(&cols, sizeof(int), 1, file);
377  fread(&readwhich, sizeof(int), 1, file);
378 
379  if (cols != ndata() || rows < 0 || readwhich != which)
380  {
381  throw cms::Exception("MuonResidualsFitter") << "temporary file is corrupted (which = " << which << " readwhich = " << readwhich << " rows = " << rows << " cols = " << cols << ")\n";
382  }
383 
384  double *likeAChecksum = new double[cols];
385  double *likeAChecksum2 = new double[cols];
386  for (int i = 0; i < cols; i++)
387  {
388  likeAChecksum[i] = 0.;
389  likeAChecksum2[i] = 0.;
390  }
391 
392  m_residuals.reserve(rows);
393  for (long row = 0; row < rows; row++)
394  {
395  double *residual = new double[cols];
396  fread(residual, sizeof(double), cols, file);
397  fill(residual);
398  for (int i = 0; i < cols; i++)
399  {
400  if (fabs(residual[i]) > likeAChecksum[i]) likeAChecksum[i] = fabs(residual[i]);
401  if (fabs(residual[i]) < likeAChecksum2[i]) likeAChecksum2[i] = fabs(residual[i]);
402  }
403  } // end loop over records in file
404 
405  double *readChecksum = new double[cols];
406  double *readChecksum2 = new double[cols];
407  fread(readChecksum, sizeof(double), cols, file);
408  fread(readChecksum2, sizeof(double), cols, file);
409 
410  for (int i = 0; i < cols; i++)
411  {
412  if (fabs(likeAChecksum[i] - readChecksum[i]) > 1e-10 || fabs(1./likeAChecksum2[i] - 1./readChecksum2[i]) > 1e10)
413  {
414  throw cms::Exception("MuonResidualsFitter") << "temporary file is corrupted (which = " << which << " rows = " << rows << " likeAChecksum " << likeAChecksum[i] << " != readChecksum " << readChecksum[i] << " " << " likeAChecksum2 " << likeAChecksum2[i] << " != readChecksum2 " << readChecksum2[i] << ")\n";
415  }
416  }
417 
418  m_residuals_ok.resize(numResiduals(), true);
419 
420  delete [] likeAChecksum;
421  delete [] likeAChecksum2;
422 }
423 
424 
425 void MuonResidualsFitter::plotsimple(std::string name, TFileDirectory *dir, int which, double multiplier)
426 {
427  double window = 100.;
428  if (which == 0) window = 2.*30.;
429  else if (which == 1) window = 2.*30.;
430  else if (which == 2) window = 2.*20.;
431  else if (which == 3) window = 2.*50.;
432 
433  TH1F *hist = dir->make<TH1F>(name.c_str(), "", 200, -window, window);
434  for (std::vector<double*>::const_iterator r = residuals_begin(); r != residuals_end(); ++r) hist->Fill(multiplier * (*r)[which]);
435 }
436 
437 
438 void MuonResidualsFitter::plotweighted(std::string name, TFileDirectory *dir, int which, int whichredchi2, double multiplier)
439 {
440  double window = 100.;
441  if (which == 0) window = 2.*30.;
442  else if (which == 1) window = 2.*30.;
443  else if (which == 2) window = 2.*20.;
444  else if (which == 3) window = 2.*50.;
445 
446  TH1F *hist = dir->make<TH1F>(name.c_str(), "", 200, -window, window);
447  for (std::vector<double*>::const_iterator r = residuals_begin(); r != residuals_end(); ++r)
448  {
449  double weight = 1./(*r)[whichredchi2];
450  if (TMath::Prob(1./weight*12, 12) < 0.99) hist->Fill(multiplier * (*r)[which], weight);
451  }
452 }
453 
454 
455 void MuonResidualsFitter::computeHistogramRangeAndBinning(int which, int &nbins, double &a, double &b)
456 {
457  // first, make a numeric array while discarding some crazy outliers
458  double *data = new double[numResiduals()];
459  int n = 0;
460  for (std::vector<double*>::const_iterator r = m_residuals.begin(); r != m_residuals.end(); r++)
461  if (fabs((*r)[which])<50.)
462  {
463  data[n] = (*r)[which];
464  n++;
465  }
466 
467  // compute "3 normal sigma" and regular interquantile ranges
468  const int n_quantiles = 7;
469  double probabilities[n_quantiles] = {0.00135, 0.02275, 0.25, 0.5, 0.75, 0.97725, 0.99865}; // "3 normal sigma"
470  //double probabilities[n_quantiles] = {0.02275, 0.25, 0.75, 0.97725}; // "2 normal sigma"
471  double quantiles[n_quantiles];
472  std::sort(data, data + n);
473  TMath::Quantiles(n, n_quantiles, data, quantiles, probabilities, true, NULL, 7);
474  delete [] data;
475  double iqr = quantiles[4] - quantiles[2];
476 
477  // estimate optimal bin size according to Freedman-Diaconis rule
478  double hbin = 2 * iqr / pow( n, 1./3);
479 
480  a = quantiles[1];
481  b = quantiles[5];
482  nbins = (int) ( (b - a) / hbin + 3. ); // add extra safety margin of 3
483 
484  std::cout<<" quantiles: "; for (int i=0;i<n_quantiles;i++) std::cout<<quantiles[i]<<" "; std::cout<<std::endl;
485  //cout<<"n="<<select_count<<" quantiles ["<<quantiles[1]<<", "<<quantiles[2]<<"] IQR="<<iqr
486  // <<" full range=["<<minx<<","<<maxx<<"]"<<" 2 normal sigma quantile range = ["<<quantiles[0]<<", "<<quantiles[3]<<"]"<<endl;
487  std::cout<<" optimal h="<<hbin<<" nbins="<<nbins<<std::endl;
488 }
489 
490 
491 void MuonResidualsFitter::histogramChi2GaussianFit(int which, double &fit_mean, double &fit_sigma)
492 {
493  int nbins;
494  double a, b;
495  computeHistogramRangeAndBinning(which, nbins, a, b);
496  if (a==b || a > b) { fit_mean = a; fit_sigma = 0; return; }
497 
498  TH1D *hist = new TH1D("htmp", "", nbins, a, b);
499  for (std::vector<double*>::const_iterator r = m_residuals.begin(); r != m_residuals.end(); ++r) hist->Fill( (*r)[which] );
500 
501  // do simple chi2 gaussian fit
502  TF1 *f1= new TF1("f1","gaus", a, b);
503  f1->SetParameter(0, hist->GetEntries());
504  f1->SetParameter(1, 0);
505  f1->SetParameter(2, hist->GetRMS());
506  hist->Fit("f1","RQ");
507 
508  fit_mean = f1->GetParameter(1);
509  fit_sigma = f1->GetParameter(2);
510  std::cout<<" h("<<nbins<<","<<a<<","<<b<<") mu="<<fit_mean<<" sig="<<fit_sigma<<std::endl;
511 
512  delete f1;
513  delete hist;
514 }
515 
516 
517 // simple non-turned ellipsoid selection
518 void MuonResidualsFitter::selectPeakResiduals_simple(double nsigma, int nvar, int *vars)
519 {
520  // does not make sense for small statistics
521  if (numResiduals()<25) return;
522 
523  int nbefore = numResiduals();
524 
525  //just to be sure (can't see why it might ever be more then 10)
526  assert(nvar<=10);
527 
528  // estimate nvar-D ellipsoid center & axes
529  for (int v = 0; v<nvar; v++)
530  {
531  int which = vars[v];
532  histogramChi2GaussianFit(which, m_center[which], m_radii[which]);
533  m_radii[which] = nsigma * m_radii[which];
534  }
535 
536  // filter out residuals that don't fit into the ellipsoid
537  std::vector<double*>::iterator r = m_residuals.begin();
538  while (r != m_residuals.end())
539  {
540  double ellipsoid_sum = 0;
541  for (int v = 0; v<nvar; v++)
542  {
543  int which = vars[v];
544  if (m_radii[which] == 0.) continue;
545  ellipsoid_sum += pow( ( (*r)[which] - m_center[which]) / m_radii[which] , 2);
546  }
547  if (ellipsoid_sum <= 1.) ++r;
548  else
549  {
550  delete [] (*r);
551  r = m_residuals.erase(r);
552  }
553  }
554  std::cout<<" N residuals "<<nbefore<<" -> "<<numResiduals()<<std::endl;
555 }
556 
557 
558 // pre-selection using robust covariance estimator
559 void MuonResidualsFitter::selectPeakResiduals(double nsigma, int nvar, int *vars)
560 {
561  //std::cout<<"doing selectpeakresiduals: nsig="<<nsigma<<" nvar="<<nvar<<" vars=";
562  for (int i=0; i<nvar; ++i) std::cout<<vars[i]<<" ";
563  std::cout<<std::endl;
564 
565  // does not make sense for small statistics
566  if (numResiduals()<50) return;
567 
568  size_t nbefore = numResiduals();
569  std::cout<<" N residuals "<<nbefore<<" ~ "<<(size_t) std::count(m_residuals_ok.begin(), m_residuals_ok.end(), true)<<std::endl;
570  //just to be sure (can't see why it might ever be more then 10)
571  assert(nvar<=10 && nvar>0);
572 
573  std::vector<double*>::iterator r = m_residuals.begin();
574 
575  // it's awkward, but the 1D case has to be handled separately
576  if (nvar==1)
577  {
578  // get robust estimates for the peak and sigma
579  double *data = new double[nbefore];
580  for (size_t i = 0; i < nbefore; i++) data[i] = m_residuals[i][ vars[0] ];
581  double peak, sigma;
582  TRobustEstimator re;
583  re.EvaluateUni(nbefore, data, peak, sigma);
584 
585  // filter out residuals that are more then nsigma away from the peak
586  while (r != m_residuals.end())
587  {
588  double distance = fabs( ((*r)[ vars[0] ] - peak)/sigma );
589  if (distance <= nsigma) ++r;
590  else
591  {
592  m_residuals_ok[r - m_residuals.begin()] = false;
593  ++r;
594  //delete [] (*r);
595  //r = m_residuals.erase(r);
596  }
597  }
598  std::cout<<" N residuals "<<nbefore<<" -> "<<numResiduals()<<std::endl;
599  return;
600  } // end 1D case
601 
602  // initialize and run the robust estimator for D>1
603  TRobustEstimator re(nbefore, nvar);
604  r = m_residuals.begin();
605  while (r != m_residuals.end())
606  {
607  double *row = new double[nvar];
608  for (int v = 0; v<nvar; v++) row[v] = (*r)[ vars[v] ];
609  re.AddRow(row);
610  delete[] row;
611  ++r;
612  }
613  re.Evaluate();
614 
615  // get nvar-dimensional ellipsoid center & covariance
616  TVectorD M(nvar);
617  re.GetMean(M);
618  TMatrixDSym Cov(nvar);
619  re.GetCovariance(Cov);
620  Cov.Invert();
621 
622  // calculate the normalized radius for this nvar-dimensional ellipsoid from a 1D-Gaussian nsigma equivalent distance
623  double conf_1d = TMath::Erf(nsigma/sqrt(2));
624  double surf_radius = sqrt(TMath::ChisquareQuantile(conf_1d, nvar));
625 
626  // filter out residuals that are outside of the covariance ellipsoid with the above normalized radius
627  r = m_residuals.begin();
628  while (r != m_residuals.end())
629  {
630  TVectorD res(nvar);
631  for (int v = 0; v<nvar; v++) res[v] = (*r)[ vars[v] ];
632  double distance = sqrt( Cov.Similarity(res - M) );
633  if (distance <= surf_radius) ++r;
634  else
635  {
636  m_residuals_ok[r - m_residuals.begin()] = false;
637  ++r;
638  //delete [] (*r);
639  //r = m_residuals.erase(r);
640  }
641  }
642  std::cout<<" N residuals "<<nbefore<<" -> "<<(size_t) std::count(m_residuals_ok.begin(), m_residuals_ok.end(), true)<<std::endl;
643 }
644 
645 
646 void MuonResidualsFitter::correctBField(int idx_momentum, int idx_q)
647 {
648  const int Nbin = 17;
649  // find max 1/pt and bin width
650  double min_pt = 9999.;
651  for (std::vector<double*>::const_iterator r = residuals_begin(); r != residuals_end(); ++r)
652  {
653  double pt = fabs((*r)[idx_momentum]);
654  if (pt < min_pt) min_pt = pt;
655  }
656  min_pt -= 0.01; // to prevent bin # overflow
657  const double bin_width = 1./min_pt/Nbin;
658 
659  // fill indices of positive and negative charge residuals in each bin
660  std::vector<size_t> pos[Nbin], neg[Nbin], to_erase;
661  for (size_t i = 0; i < m_residuals.size(); i++)
662  {
663  if (!m_residuals_ok[i]) continue;
664  int bin = (int)floor(1./fabs(m_residuals[i][idx_momentum])/bin_width);
665  if (m_residuals[i][idx_q] > 0) pos[bin].push_back(i);
666  else neg[bin].push_back(i);
667  }
668 
669  // equalize pos and neg in each bin
670  for (int j = 0; j < Nbin; j++)
671  {
672  size_t psize = pos[j].size();
673  size_t nsize = neg[j].size();
674  if (psize == nsize) continue;
675 
676  std::set<int> idx_set; // use a set to collect certain number of unique random indices to erase
677  if (psize > nsize)
678  {
679  while (idx_set.size() < psize - nsize) idx_set.insert( gRandom->Integer(psize) );
680  for (std::set<int>::iterator it = idx_set.begin() ; it != idx_set.end(); it++ ) to_erase.push_back(pos[j][*it]);
681  }
682  else
683  {
684  while (idx_set.size() < nsize - psize) idx_set.insert( gRandom->Integer(nsize) );
685  for (std::set<int>::iterator it = idx_set.begin() ; it != idx_set.end(); it++ ) to_erase.push_back(neg[j][*it]);
686  }
687  }
688  // sort in descending order, so we safely go from higher to lower indices:
689  std::sort(to_erase.begin(), to_erase.end(), std::greater<int>() );
690  for (std::vector<size_t>::const_iterator e = to_erase.begin(); e != to_erase.end(); ++e)
691  {
692  m_residuals_ok[*e] = false;
693  //delete[] *(m_residuals.begin() + *e);
694  //m_residuals.erase(m_residuals.begin() + *e);
695  }
696 
697  std::vector<size_t> apos[Nbin], aneg[Nbin];
698  for (size_t i = 0; i < m_residuals.size(); i++)
699  {
700  if (!m_residuals_ok[i]) continue;
701  int bin = (int)floor(1./fabs(m_residuals[i][idx_momentum])/bin_width);
702  if (m_residuals[i][idx_q] > 0) apos[bin].push_back(i);
703  else aneg[bin].push_back(i);
704  }
705  for (int j = 0; j < Nbin; j++) std::cout << "bin " << j << ": [pos,neg] sizes before & after: ["
706  << pos[j].size() <<","<< neg[j].size()<<"] -> [" << apos[j].size() <<","<< aneg[j].size() << "]" << std::endl;
707  std::cout<<" N residuals "<<m_residuals.size()<<" -> "<<(size_t) std::count(m_residuals_ok.begin(), m_residuals_ok.end(), true)<<std::endl;
708 }
709 
710 
712 {
713  // it should probably be faster then doing erase
714  size_t n_ok = (size_t) std::count(m_residuals_ok.begin(), m_residuals_ok.end(), true);
715  std::vector<double*> tmp(n_ok, 0);
716  std::cout << "residuals sizes: all=" << m_residuals.size()<<" good="<<n_ok<<std::endl;
717  int iok=0;
718  for (size_t i = 0; i < m_residuals.size(); i++)
719  {
720  if (!m_residuals_ok[i]) continue;
721  tmp[iok++] = m_residuals[i];
722  }
723  m_residuals.swap(tmp);
724 
725  std::vector<bool> tmp_ok(n_ok, true);
726  m_residuals_ok.swap(tmp_ok);
727 
728  std::cout << "residuals size after eraseNotSelectedResiduals =" << m_residuals.size()<<" ok size="<<m_residuals_ok.size()<<std::endl;
729 }
tuple arglist
Definition: fitWZ.py:38
void histogramChi2GaussianFit(int which, double &fit_mean, double &fit_sigma)
double MuonResidualsFitter_logGaussPowerTails(double residual, double center, double sigma)
int i
Definition: DBlmapReader.cc:9
def window
Definition: svgfig.py:642
double MuonResidualsFitter_integrate_pureGaussian(double low, double high, double center, double sigma)
Double_t MuonResidualsFitter_powerLawTails_TF1(Double_t *xvec, Double_t *par)
virtual void inform(TMinuit *tMinuit)=0
void computeHistogramRangeAndBinning(int which, int &nbins, double &a, double &b)
void selectPeakResiduals(double nsigma, int nvar, int *vars)
const int MuonResidualsFitter_numgsbins
list step
Definition: launcher.py:15
double MuonResidualsFitter_logPureGaussian2D(double x, double y, double x0, double y0, double sx, double sy, double r)
void write(FILE *file, int which=0)
virtual int npar()=0
std::vector< double > m_error
void read(FILE *file, int which=0)
void fill(double *residual)
#define NULL
Definition: scimark2.h:8
bool dofit(void(*fcn)(int &, double *, double &, double *, int), std::vector< int > &parNum, std::vector< std::string > &parName, std::vector< double > &start, std::vector< double > &step, std::vector< double > &low, std::vector< double > &high)
double MuonResidualsFitter_logROOTVoigt(double residual, double center, double sigma, double gamma)
double MuonResidualsFitter_compute_log_convolution(double toversigma, double gammaoversigma, double max=1000., double step=0.001, double power=4.)
std::vector< double > m_value
std::vector< double * > m_residuals
const T & max(const T &a, const T &b)
bool fixed(int parNum)
T sqrt(T t)
Definition: SSEVec.h:46
const int MuonResidualsFitter_numtsbins
double MuonResidualsFitter_logPowerLawTails(double residual, double center, double sigma, double gamma)
const double MuonResidualsFitter_gsbinsize
int j
Definition: DBlmapReader.cc:9
std::vector< bool > m_residuals_ok
Double_t MuonResidualsFitter_GaussPowerTails_TF1(Double_t *xvec, Double_t *par)
virtual void correctBField()=0
const double MuonResidualsFitter_tsbinsize
static TMinuit * MuonResidualsFitter_TMinuit
Double_t MuonResidualsFitter_pureGaussian_TF1(Double_t *xvec, Double_t *par)
void plotsimple(std::string name, TFileDirectory *dir, int which, double multiplier)
virtual int ndata()=0
#define M_PI
Definition: BFit3D.cc:3
void fcn(int &, double *, double &, double *, int)
double b
Definition: hdecay.h:120
std::vector< double * >::const_iterator residuals_end() const
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
void plotweighted(std::string name, TFileDirectory *dir, int which, int whichredchi2, double multiplier)
double a
Definition: hdecay.h:121
bool MuonResidualsFitter_table_initialized
double MuonResidualsFitter_lookup_table[MuonResidualsFitter_numgsbins][MuonResidualsFitter_numtsbins]
T * make() const
make new ROOT object
tuple cout
Definition: gather_cfg.py:121
void selectPeakResiduals_simple(double nsigma, int nvar, int *vars)
dbl *** dir
Definition: mlp_gen.cc:35
x
Definition: VDTMath.h:216
Double_t MuonResidualsFitter_ROOTVoigt_TF1(Double_t *xvec, Double_t *par)
std::vector< double * >::const_iterator residuals_begin() const
double MuonResidualsFitter_logPureGaussian(double residual, double center, double sigma)
tuple size
Write out results.
mathSSE::Vec4< T > v
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40