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