Belle II Software  release-06-01-15
InvariantMassMuMuStandAlone.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 
10 #include <iostream>
11 #include <iomanip>
12 #include <filesystem>
13 #include <vector>
14 #include <tuple>
15 #include <numeric>
16 #include <fstream>
17 
18 #include <TROOT.h>
19 #include <TTree.h>
20 #include <TVector3.h>
21 #include <TGraph.h>
22 #include <TRandom3.h>
23 #include <TH1D.h>
24 #include <TGraph.h>
25 #include <TLegend.h>
26 #include <TLine.h>
27 #include <TCanvas.h>
28 #include <TStyle.h>
29 #include <TPad.h>
30 #include <Math/Functor.h>
31 #include <Math/SpecFuncMathCore.h>
32 #include <Math/DistFunc.h>
33 
34 #include <Eigen/Dense>
35 
36 #include <framework/particledb/EvtGenDatabasePDG.h>
37 
38 //if compiled within BASF2
39 #ifdef _PACKAGE_
40 #include <tracking/calibration/InvariantMassMuMuStandAlone.h>
41 #include <tracking/calibration/InvariantMassMuMuIntegrator.h>
42 #include <tracking/calibration/BoostVectorStandAlone.h>
43 #include <tracking/calibration/Splitter.h>
44 #include <tracking/calibration/tools.h>
45 #include <tracking/calibration/ChebFitter.h>
46 #else
47 #include <InvariantMassMuMuStandAlone.h>
48 #include <InvariantMassMuMuIntegrator.h>
49 #include <Splitter.h>
50 #include <tools.h>
51 #include <ChebFitter.h>
52 #endif
53 
54 using Eigen::MatrixXd;
55 using Eigen::VectorXd;
56 
57 using namespace std;
58 
59 
60 namespace Belle2::InvariantMassMuMuCalib {
61 
62 
63 
64 
66  vector<Event> getEvents(TTree* tr, bool is4S)
67  {
68 
69  vector<Event> events;
70  events.reserve(tr->GetEntries());
71 
72  Event evt;
73 
74  tr->SetBranchAddress("run", &evt.run);
75  tr->SetBranchAddress("exp", &evt.exp);
76  tr->SetBranchAddress("event", &evt.evtNo);
77 
78  TVector3* p0 = nullptr;
79  TVector3* p1 = nullptr;
80 
81  tr->SetBranchAddress("mu0_p", &p0);
82  tr->SetBranchAddress("mu1_p", &p1);
83 
84  tr->SetBranchAddress("mu0_pid", &evt.mu0.pid);
85  tr->SetBranchAddress("mu1_pid", &evt.mu1.pid);
86 
87 
88  tr->SetBranchAddress("time", &evt.t); //time in hours
89 
90  const double mMu = EvtGenDatabasePDG::Instance()->GetParticle("mu-")->Mass(); //muon mass, i.e. around 105.66e-3 [GeV]
91 
92  for (int i = 0; i < tr->GetEntries(); ++i) {
93  tr->GetEntry(i);
94 
95  evt.mu0.p = *p0;
96  evt.mu1.p = *p1;
97 
98  evt.m = sqrt(pow(hypot(evt.mu0.p.Mag(), mMu) + hypot(evt.mu1.p.Mag(), mMu), 2) - (evt.mu0.p + evt.mu1.p).Mag2());
99 
100  evt.nBootStrap = 1;
101  evt.isSig = true;
102  evt.is4S = is4S;
103  events.push_back(evt);
104  }
105 
106  //sort by time
107  sort(events.begin(), events.end(), [](Event e1, Event e2) {return e1.t < e2.t;});
108 
109 
110  return events;
111  }
112 
113 
114 
115 
116 
117  // Numerical integration using Gauss-Konrod algorithm
118  double integrate(function<double(double)> f, double a, double b)
119  {
120  static const vector<double> nodes = {
121  -0.991455371120813,
122  -0.949107912342759,
123  -0.864864423359769,
124  -0.741531185599394,
125  -0.586087235467691,
126  -0.405845151377397,
127  -0.207784955007898,
128  0.000000000000000
129  };
130 
131  static const vector<double> wgts = {
132  0.022935322010529,
133  0.063092092629979,
134  0.104790010322250,
135  0.140653259715525,
136  0.169004726639267,
137  0.190350578064785,
138  0.204432940075298,
139  0.209482141084728
140  };
141 
142  if (b < a) B2FATAL("Wrongly defined integration interval");
143 
144  double m = (b + a) / 2; //middle of the interval
145  double d = (b - a) / 2; //half-width of the interval
146 
147  double sum = 0;
148  for (unsigned i = 0; i < nodes.size() - 1; ++i) {
149  double x1 = m - d * nodes[i];
150  double x2 = m + d * nodes[i];
151  sum += (f(x1) + f(x2)) * wgts[i];
152  }
153 
154  //add the central point (which is not in pair)
155  sum += f(m) * wgts.back();
156 
157 
158  // scale by size of interval, for example a=-1, b=1 -> no scaling
159  return sum * d;
160  }
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
172  double gausInt(double a, double b, double c, double d)
173  {
174  double res = sqrt(M_PI) / (2 * sqrt(c)) * (TMath::Erf((b * c - d) / sqrt(c)) - TMath::Erf((a * c - d) / sqrt(c)));
175  return res;
176  }
177 
178 
181  double convGausGaus(double sK, double s, double a, double b, double m, double x)
182  {
183  a -= m;
184  b -= m;
185  x -= m;
186 
187 
188  double c = 1. / 2 * (1. / s / s + 1. / sK / sK);
189  double d = 1. / 2 * x / sK / sK;
190 
191  double Const = 1. / (2 * M_PI) * 1. / (s * sK) * exp(-1. / 2 * x * x / (s * s + sK * sK));
192 
193  double res = Const * gausInt(a, b, c, d);
194  assert(isfinite(res));
195  return res;
196  }
197 
198 
199 
200 
204  double convExpGaus(double sK, double tau, double a, double x)
205  {
206  x -= a;
207 
208  double A = 1. / sqrt(2) * (-x / sK + sK / tau);
209  double B = -x / tau + 1. / 2 * pow(sK / tau, 2);
210  double res = 0;
211  if (B > 700 || A > 20) { // safety term to deal with 0 * inf limit
212  res = 1. / (2 * tau) * 1. / sqrt(M_PI) * exp(-A * A + B) * (1 / A - 1 / 2. / pow(A, 3) + 3. / 4 / pow(A, 5));
213  } else {
214  res = 1. / (2 * tau) * TMath::Erfc(A) * exp(B);
215  }
216  assert(isfinite(res));
217  return res;
218  }
219 
220 
221  // convolution of Gaussian with exp tails with the Gaussian smearing kernel
222  double gausExpConv(double mean, double sigma, double bMean, double bDelta, double tauL, double tauR, double sigmaK, double x)
223  {
224  double bL = bMean - bDelta;
225  double bR = bMean + bDelta;
226 
227  double xL = bL * sigma + mean;
228  double xR = bR * sigma + mean;
229 
230  double iGaus = sqrt(2 * M_PI) * sigma * convGausGaus(sigmaK, sigma, xL, xR, mean, x);
231  double iRight = exp(-1. / 2 * pow(bR, 2)) * tauR * convExpGaus(sigmaK, tauR, xR, x);
232  double iLeft = exp(-1. / 2 * pow(bL, 2)) * tauL * convExpGaus(sigmaK, tauL, -xL, -x);
233 
234  return (iGaus + iLeft + iRight);
235  }
236 
238  double gausExpConvRoot(const double* par)
239  {
240  double x = par[0]; // point where the function is evaluated
241  double mean = par[1]; // mean of Gauss in "Crystal Ball" with exp tails instead of pow
242  double sigma = par[2]; // sigma of Gauss in "Crystal Ball" with exp tails instead of pow
243  double bMean = par[3]; // mean of the transition points between Gaus and exp
244  double bDelta = par[4]; // diff/2 of the transition points between Gaus and exp
245  double tauL = par[5]; // decay par of the left exp
246  double tauR = par[6]; // decay par of the right exp
247  double sigmaK = par[7]; // sigma of the Gaussian smearing Kernel
248  double sigmaA = par[8]; // sigma of the added Gaussian
249  double fA = par[9]; // fraction of the added Gaussian
250 
251  //added Gaussian
252  double G = 1. / (sqrt(2 * M_PI) * sigmaA) * exp(-1. / 2 * pow((x - mean) / sigmaA, 2));
253  return (1 - fA) * gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x) + fA * G;
254  }
255 
256 
259  double gausExpPowConvRoot(const double* par)
260  {
261  double x = par[0]; // point where the function is evaluated
262  double mean = par[1]; // mean of Gauss in "Crystal Ball" with exp tails instead of pow
263  double sigma = par[2]; // sigma of Gauss in "Crystal Ball" with exp tails instead of pow
264  double bMean = par[3]; // mean of the transition points between Gaus and exp
265  double bDelta = par[4]; // diff/2 of the transition points between Gaus and exp
266  double tauL = par[5]; // decay par of the left exp
267  double tauR = par[6]; // decay par of the right exp
268  double sigmaK = par[7]; // sigma of the Gaussian smearing Kernel
269  double sigmaA = par[8]; // sigma of the added Gaussian
270  double fA = par[9]; // fraction of the added Gaussian
271 
272 
273 
274  double eCMS = par[10]; // center of mass energy of the collisions
275  double slope = par[11]; // power-slope of gen-level spectra from ISR
276  double K = par[12]; // normalisation of the part without photon ISR
277 
278  double step = 0.10; // step size in the integration
279  int N = 800 * 1. / step;
280 
281  double sum = 0;
282 
283  //calculation of the convolution using trapezium rule
284  for (int i = 0; i < N; ++i) {
285 
286  double t = eCMS - i * step;
287 
288  double y = x - t;
289  double G = 1. / (sqrt(2 * M_PI) * sigmaA) * exp(-1. / 2 * pow((y - mean) / sigmaA, 2));
290  double Core = (1 - fA) * gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, y) + fA * G;
291 
292  double C = (i == 0 || i == N - 1) ? 0.5 : 1;
293 
294  double Kernel;
295  if (i == 0)
296  Kernel = K * pow(step, -slope);
297  else
298  Kernel = pow(eCMS - t, -slope);
299 
300 
301  sum += Kernel * Core * step * C;
302  }
303 
304  return sum;
305  }
306 
307 
308 
309 
310 
311 
314  void plotTest()
315  {
316  double mean = 0;
317  double bMean = 0;
318  double bDelta = 5;
319  double tauL = 30;
320  double tauR = 30;
321  double sigma = 10;
322  double sigmaK = 40;
323 
324  TGraph* gr = new TGraph;
325  for (double x = -300; x < 300; x += 1) {
326 
327  double v = gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x);
328 
329  gr->SetPoint(gr->GetN(), x, v);
330  }
331 
332  gr->Draw();
333  }
334 
335 
337  double gausExp(const double* par)
338  {
339  double x = par[0]; // point where the function is evaluated
340  double mean = par[1]; // mean of Gaus
341  double sigma = par[2]; // sigma of Gaus
342  double bMean = par[3]; // mean of the transition points between Gaus and exp
343  double bDelta = par[4]; // diff/2 of the transition points between Gaus and exp
344  double tauL = par[5]; // decay par of the left exp
345  double tauR = par[6]; // decay par of the right exp
346 
347  double bL = bMean - bDelta;
348  double bR = bMean + bDelta;
349 
350 
351  double r = (x - mean) / sigma;
352  if (bL <= r && r <= bR) {
353  return exp(-1. / 2 * pow(r, 2));
354  } else if (r < bL) {
355  double bp = exp(-1. / 2 * pow(bL, 2));
356  double xb = mean + bL * sigma;
357  return exp((x - xb) / tauL) * bp;
358  } else {
359  double bp = exp(-1. / 2 * pow(bR, 2));
360  double xb = mean + bR * sigma;
361  return exp(-(x - xb) / tauR) * bp;
362  }
363  }
364 
365 
366 
367 
368 
369 
372  void plotInt()
373  {
374  double mean = 4;
375  double sigma = 30;
376  double sigmaK = 30;
377  double bMean = 0;
378  double bDelta = 2.6;
379  double tau = 60;
380 
381  double x = 10300;
382 
383  TGraph* gr = new TGraph;
384  TGraph* grE = new TGraph;
385  TGraph* grRat = new TGraph;
386  TGraph* grR = new TGraph;
387 
388  double m0 = 10500;
389  double slope = 0.95;
390  double eps = 0.01;
391 
392  double frac = 0.2;
393  double sigmaE = 30;
394 
395  for (double t = eps; t < 5000; t += 1.00) {
396  double Core = gausExpConv(mean, sigma, bMean, bDelta, tau, tau, sigmaK, x + t - m0);
397  double K = (+t) >= eps ? pow(+ t, -slope) : 0;
398 
399  double fun = Core * K;
400  gr->SetPoint(gr->GetN(), t, fun);
401 
402  double s = exp(-t / tau);
403 
404  double funE = exp(-abs(x - m0 + t) / tau) * 1 / t;
405  grE->SetPoint(grE->GetN(), t, funE);
406  if (funE > 0) {
407  grRat->SetPoint(grE->GetN(), t, fun / funE);
408  grR->SetPoint(grR->GetN(), s, fun / funE);
409  }
410  }
411 
412 
413  InvariantMassMuMuIntegrator integrator;
414 
415  TGraph* grM = new TGraph; // the PDF used in the fit
416 
417  double C = 16;
418 
419  for (double xNow = 10000; xNow <= 11000; xNow += 0.1) {
420 
421  integrator.init(mean,
422  sigma,
423  sigmaK,
424  bMean,
425  bDelta,
426  tau,
427  sigmaE,
428  frac,
429  m0,
430  eps,
431  C,
432  slope,
433  xNow);
434 
435 
436  grM->SetPoint(grM->GetN(), xNow, integrator.integralKronrod(2000));
437  }
438 
439  grM->Draw();
440 
441 
442  delete gr;
443  delete grE;
444  delete grRat;
445  delete grR;
446  delete grM;
447 
448  }
449 
450 
452  double mainFunction(double xx, Pars par)
453  {
454  InvariantMassMuMuIntegrator fun;
455 
456  fun.init(par.at("mean"), // mean
457  par.at("sigma"), // sigma
458  par.at("sigma"), // sigmaK
459  par.at("bMean"), // bMean
460  par.at("bDelta"),// bDelta
461  par.at("tau"), // tau=tauL=tauR
462  par.at("sigma"), // sigmaE
463  par.at("frac"), // frac
464  par.at("m0"), // m0
465  0.1, // eps
466  par.at("C"), // C
467  par.at("slope"), // slope
468  xx); // x
469 
470  return fun.integralKronrod(2000);
471  }
472 
473 
476  vector<double> readEvents(const vector<Event>& evts, double pidCut, double a, double b)
477  {
478 
479  vector<double> vMass;
480  for (const auto& ev : evts) {
481 
482  //Keep only muons
483  if (ev.mu0.pid < pidCut || ev.mu1.pid < pidCut) {
484  continue;
485  }
486 
487  double m = 1e3 * ev.m; // from GeV to MeV
488  if (a < m && m < b)
489  vMass.push_back(m);
490  }
491 
492  return vMass;
493  }
494 
495 
497  static void plotMuMuFitBase(TH1D* hData, TGraph* gr, TH1D* hPull, Pars pars, Eigen::MatrixXd mat, int time)
498  {
499  bool isBatch = gROOT->IsBatch();
500  gROOT->SetBatch(kTRUE);
501 
502  gStyle->SetOptStat(0);
503 
504  TCanvas* can = new TCanvas(Form("canMuMu_%d", time), "");
505 
506  TPad* pad1 = new TPad(Form("pad1_%d", time), "", 0, 0.3, 1, 1.0);
507  TPad* pad2 = new TPad(Form("pad2_%d", time), "", 0, 0, 1, 0.3);
508 
509  pad1->SetBottomMargin(0.05);
510  pad2->SetTopMargin(0.05);
511  pad2->SetBottomMargin(0.35);
512 
513  pad1->Draw();
514  pad2->Draw();
515 
517  // Main plot
519 
520  pad1->cd();
521 
522  hData->SetMarkerStyle(kFullCircle);
523  hData->Draw();
524  gr->SetLineColor(kRed);
525  gr->SetLineWidth(2);
526  gr->Draw("same");
527  hData->GetXaxis()->SetLabelSize(0.0001);
528  hData->GetYaxis()->SetLabelSize(0.05);
529  hData->GetYaxis()->SetTitle("Number of events");
530  hData->GetYaxis()->SetTitleSize(0.05);
531  hData->GetYaxis()->SetTitleOffset(0.9);
532 
533  double mY4S = 10579.4;
534  double y = gr->Eval(mY4S);
535  TLine* line = new TLine(mY4S, 0, mY4S, y);
536  line->SetLineColor(kGreen);
537  line->SetLineWidth(2);
538  line->Draw();
539 
540 
541 
542  TLegend* leg = new TLegend(.15, .4, .35, .87);
543  int i = 0, nPars = 0;
544  for (auto p : pars) {
545  double err = sqrt(mat(i, i));
546  if (err != 0) {
547  int nDig = log10(p.second / err) + 2;
548 
549  TString s = "%s = %." + TString(Form("%d", nDig)) + "g";
550  TString dig = "%." + TString(Form("%d", nDig)) + "g";
551  TString digE = "%.2g";
552  leg->AddEntry((TObject*)0, Form("%s = " + dig + " #pm " + digE, p.first.c_str(), p.second, err), "h");
553  ++nPars;
554  }
555  ++i;
556  }
557  leg->SetTextSize(0.05);
558  leg->SetBorderSize(0);
559  leg->SetFillStyle(0);
560  leg->Draw();
561 
562 
563  double chi2 = 0;
564  for (int j = 1; j <= hPull->GetNbinsX(); ++j)
565  chi2 += pow(hPull->GetBinContent(j), 2);
566  int ndf = hPull->GetNbinsX() - nPars - 1;
567 
568 
569  TLegend* leg2 = new TLegend(.73, .75, .93, .87);
570  leg2->AddEntry((TObject*)0, Form("chi2/ndf = %.2f", chi2 / ndf), "h");
571  leg2->AddEntry((TObject*)0, Form("p = %.2g", TMath::Prob(chi2, ndf)), "h");
572 
573  leg2->SetTextSize(0.05);
574  leg2->SetBorderSize(0);
575  leg2->SetFillStyle(0);
576  leg2->Draw();
577 
578 
579  double mFit = pars.at("m0");
580  double yF = gr->Eval(mFit);
581  TLine* lineR = new TLine(mFit, 0, mFit, yF);
582  lineR->SetLineColor(kRed);
583  lineR->SetLineWidth(2);
584  lineR->Draw();
585 
586 
587 
589  // Ratio plot
591 
592  pad2->cd();
593  hPull->SetMarkerStyle(kFullCircle);
594  hPull->Draw("p");
595 
596  hPull->GetXaxis()->SetTitle("M (#mu#mu) [MeV]");
597  hPull->GetYaxis()->SetTitle("pull");
598  hPull->GetXaxis()->SetTitleSize(0.13);
599  hPull->GetXaxis()->SetTitleOffset(1.25);
600  hPull->GetXaxis()->SetLabelSize(0.13);
601  hPull->GetXaxis()->SetLabelOffset(0.05);
602  hPull->GetXaxis()->SetTickSize(0.07);
603 
604 
605  hPull->GetYaxis()->SetTitleSize(0.13);
606  hPull->GetYaxis()->SetLabelSize(0.13);
607  hPull->GetYaxis()->SetTitleOffset(0.2);
608  hPull->GetYaxis()->CenterTitle();
609 
610 
611  hPull->GetYaxis()->SetNdivisions(404);
612 
613  hPull->GetYaxis()->SetRangeUser(-5, 5);
614 
615  TGraph* grLine = new TGraph(2);
616  grLine->SetPoint(0, hPull->GetBinLowEdge(1), 0);
617  grLine->SetPoint(1, hPull->GetBinLowEdge(hPull->GetNbinsX()) + hPull->GetBinWidth(hPull->GetNbinsX()), 0);
618  grLine->SetLineWidth(2);
619  grLine->SetLineColor(kRed);
620  grLine->Draw("same");
621 
622  filesystem::create_directories("plotsMuMu");
623 
624  can->SaveAs(Form("plotsMuMu/mumu_%d.pdf", time));
625 
626 
627  delete leg;
628  delete leg2;
629  delete line;
630  delete lineR;
631  delete grLine;
632 
633  delete pad1;
634  delete pad2;
635  delete can;
636 
637 
638  gROOT->SetBatch(isBatch);
639  }
640 
642  static void plotMuMuFit(const vector<double>& data, const Pars& pars, Eigen::MatrixXd mat, double mMin, double mMax, int time)
643  {
644  const int nBins = 100;
645 
646  // Fill the data histogram
647  TH1D::SetDefaultSumw2();
648  TH1D* hData = new TH1D("hData", "", nBins, mMin, mMax);
649  TH1D* hFit = new TH1D("hFit", "", nBins, mMin, mMax);
650  TH1D* hPull = new TH1D("hPull", "", nBins, mMin, mMax);
651  hData->SetDirectory(nullptr);
652  hFit->SetDirectory(nullptr);
653  hPull->SetDirectory(nullptr);
654 
655  // fill histogram with data
656  for (auto d : data)
657  hData->Fill(d);
658 
659 
660  // construct the fitted function
661  TGraph* gr = new TGraph();
662  const double step = (mMax - mMin) / (nBins);
663 
664  for (int i = 0; i <= 2 * nBins; ++i) {
665  double m = mMin + 0.5 * step * i;
666  double V = mainFunction(m, pars);
667  gr->SetPoint(gr->GetN(), m, V);
668  }
669 
670 
671  // Calculate integrals of the fitted function within each bin
672  for (int i = 0; i < nBins; ++i) {
673  double lV = gr->GetPointY(2 * i + 0);
674  double cV = gr->GetPointY(2 * i + 1);
675  double rV = gr->GetPointY(2 * i + 2);
676 
677  double I = step / 6 * (lV + 4 * cV + rV);
678  hFit->SetBinContent(i + 1, I);
679  }
680 
681  //Normalization factor
682  double F = hData->Integral() / hFit->Integral();
683 
684  hFit->Scale(F);
685 
686  // Normalize the curve
687  for (int i = 0; i < gr->GetN(); ++i)
688  gr->SetPointY(i, gr->GetPointY(i) * F * step);
689 
690 
691  // calculate pulls
692  for (int i = 1; i <= nBins; ++i) {
693  double pull = (hData->GetBinContent(i) - hFit->GetBinContent(i)) / sqrt(hFit->GetBinContent(i));
694  hPull->SetBinContent(i, pull);
695  }
696 
697 
698  plotMuMuFitBase(hData, gr, hPull, pars, mat, time);
699 
700  delete hData;
701  delete hFit;
702  delete hPull;
703  delete gr;
704  }
705 
706 
707 
708 
711  pair<Pars, MatrixXd> getInvMassPars(const vector<Event>& evts, Pars pars, double mMin, double mMax, int bootStrap = 0)
712  {
713  bool is4S = evts[0].is4S;
714 
715  vector<double> dataNow = readEvents(evts, 0.9/*PIDcut*/, mMin, mMax);
716 
717 
718  // do bootStrap
719  vector<double> data;
720  TRandom3* rand = nullptr;
721  if (bootStrap) rand = new TRandom3(bootStrap);
722  for (auto d : dataNow) {
723  int nP = bootStrap ? rand->Poisson(1) : 1;
724  for (int i = 0; i < nP; ++i)
725  data.push_back(d);
726  }
727 
728  if (bootStrap)
729  delete rand;
730 
731  ChebFitter fitter;
732  fitter.setDataAndFunction(mainFunction, data);
733  fitter.init(256 + 1, mMin, mMax);
734 
735 
736  Pars pars0_4S = {
737  {"C" , 15 },
738  {"bDelta" , 1.60307 },
739  {"bMean" , 0 },
740  {"frac" , 0.998051 },
741  {"m0" , 10570.2 },
742  {"mean" , 4.13917 },
743  {"sigma" , 37.0859 },
744  {"slope" , 0.876812 },
745  {"tau" , 99.4225}
746  };
747 
748  Pars pars0_Off = {
749  {"C" , 15 },
750  {"bDelta" , 2.11 },
751  {"bMean" , 0 },
752  {"frac" , 0.9854 },
753  {"m0" , mMax - 230 },
754  {"mean" , 4.13917 },
755  {"sigma" , 36.4 },
756  {"slope" , 0.892 },
757  {"tau" , 64.9}
758  };
759 
760  if (pars.empty()) {
761  pars = is4S ? pars0_4S : pars0_Off;
762  }
763 
764 
765 
766  Limits limits = {
767  {"mean", make_pair(0, 0)},
768  {"sigma", make_pair(10, 120)},
769  {"bMean", make_pair(0, 0)},
770  {"bDelta", make_pair(0.01, 10.)},
771  {"tau", make_pair(20, 250)},
772  {"frac", make_pair(0.00, 1.0)},
773 
774  {"m0", make_pair(10450, 10950)},
775  {"slope", make_pair(0.3, 0.999)},
776  {"C", make_pair(0, 0)}
777  };
778 
779 
780  return fitter.fitData(pars, limits, true/*useCheb*/);
781 
782  }
783 
784 
785 
786 
787  // Returns tuple with the invariant mass parameters (cmsEnergy in GeV)
788  tuple<vector<VectorXd>, vector<MatrixXd>, MatrixXd> runMuMuInvariantMassAnalysis(vector<Event> evts,
789  const vector<double>& splitPoints)
790  {
791  int n = splitPoints.size() + 1;
792 
793  vector<VectorXd> invMassVec(n);
794  vector<MatrixXd> invMassVecUnc(n);
795  MatrixXd invMassVecSpred;
796 
797  std::ofstream mumuTextOut("mumuEcalib.txt", ios::app);
798  static int iPrint = 0;
799  if (iPrint == 0)
800  mumuTextOut << "n id t1 t2 exp1 run1 exp2 run2 Ecms EcmsUnc state" << endl;
801  ++iPrint;
802 
803  for (int iDiv = 0; iDiv < n; ++iDiv) {
804 
805 
806  invMassVec[iDiv].resize(1); //1D vector for center of the 1D Gauss
807  invMassVecUnc[iDiv].resize(1, 1); //1x1 matrix covariance mat of the center
808  invMassVecSpred.resize(1, 1); //1x1 matrix for spread of the 1D Gauss
809 
810  vector<Event> evtsNow;
811  for (auto ev : evts) {
812  double tMin = (iDiv != 0) ? splitPoints[iDiv - 1] : -1e40;
813  double tMax = (iDiv != n - 1) ? splitPoints[iDiv] : 1e40;
814  if (tMin <= ev.t && ev.t < tMax)
815  evtsNow.push_back(ev);
816 
817  }
818 
819 
820 
821  // default fitting range for the mumu invariant mass
822  double mMin = 10.2e3, mMax = 10.8e3;
823 
824  // in case of offResonance runs adjust limits from median
825  if (!evtsNow[0].is4S) {
826  vector<double> dataNow;
827  for (const auto& ev : evtsNow)
828  dataNow.push_back(ev.m);
829  double mMedian = 1e3 * Belle2::BoostVectorCalib::median(dataNow.data(), dataNow.size());
830  double est = mMedian + 30;
831  mMax = est + 220;
832  mMin = est - 380;
833  }
834 
835 
836 
837 
838  // number of required successful bootstrap replicas
839  const int nRep = 25;
840 
841 
842  vector<double> vals, errs;
843  for (int rep = 0; rep < 200; ++rep) {
844  double errEst = 50. / sqrt(evtsNow.size());
845 
846  Pars resP, inDummy;
847  MatrixXd resM;
848 
849 
850  // fit using bootstrap replica replicas, rep=0 is no replica
851  tie(resP, resM) = getInvMassPars(evtsNow, inDummy, mMin, mMax, rep);
852 
853  int ind = distance(resP.begin(), resP.find("m0"));
854  double mass = resP.at("m0");
855  double err = sqrt(resM(ind, ind));
856 
857 
858  // if there are problems with fit, try again with diffrent bootstrap replica
859  if (!(errEst < err && err < 4 * errEst))
860  continue;
861 
862  vals.push_back(mass);
863  errs.push_back(err);
864 
865  // if now bootstrapping needed, plot & break
866  if (rep == 0) {
867  plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP, resM, mMin, mMax, int(round(evtsNow[0].t)));
868  break;
869  }
870 
871  // try fit with different input parameters, but without bootstrapping
872  Pars resP0;
873  MatrixXd resM0;
874  tie(resP0, resM0) = getInvMassPars(evtsNow, resP, mMin, mMax, 0);
875 
876  int ind0 = distance(resP0.begin(), resP0.find("m0"));
877  double mass0 = resP0.at("m0");
878  double err0 = sqrt(resM0(ind0, ind0));
879 
880  // if successful, plot & break
881  if (errEst < err0 && err0 < 4 * errEst) {
882  vals = {mass0};
883  errs = {err0};
884  plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP0, resM0, mMin, mMax, int(round(evtsNow[0].t)));
885  break;
886  }
887 
888 
889  // if the fit was sucesfull several times only on replicas, plot & break
890  if (vals.size() >= nRep) {
891  plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP, resM, mMin, mMax, int(round(evtsNow[0].t)));
892  break;
893  }
894 
895  }
896 
897  if (vals.size() != 1 && vals.size() != nRep)
898  B2FATAL("Inconsistency of number of results with number of replicas");
899 
900  double meanMass = accumulate(vals.begin(), vals.end(), 0.) / vals.size();
901  double meanMassUnc = accumulate(errs.begin(), errs.end(), 0.) / errs.size();
902 
903  double sum2 = 0;
904  for (auto v : vals)
905  sum2 += pow(v - meanMass, 2);
906  double errBootStrap = vals.size() > 1 ? sqrt(sum2 / (vals.size() - 1)) : 0;
907 
908  mumuTextOut << n << " " << iDiv << " " << setprecision(14) << evtsNow.front().t << " " << evtsNow.back().t << " " <<
909  evtsNow.front().exp << " " << evtsNow.front().run << " " << evtsNow.back().exp << " " << evtsNow.back().run << " " << meanMass
910  <<
911  " " << meanMassUnc << " " << errBootStrap << endl;
912 
913  // Convert to GeV
914  invMassVec[iDiv](0) = meanMass / 1e3;
915  invMassVecUnc[iDiv](0, 0) = meanMassUnc / 1e3;
916  invMassVecSpred(0, 0) = 0;
917  }
918 
919  mumuTextOut.close();
920 
921  return make_tuple(invMassVec, invMassVecUnc, invMassVecSpred);
922  }
923 
924 }
std::map< std::string, double > Pars
values of parameters in ML fit
Definition: ChebFitter.h:25
std::map< std::string, std::pair< double, double > > Limits
limits of parameters in ML fit
Definition: ChebFitter.h:28