Belle II Software development
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#include <framework/utilities/MathHelpers.h>
37
38//if compiled within BASF2
39#ifdef _PACKAGE_
40#include <reconstruction/calibration/BeamSpotBoostInvMass/InvariantMassMuMuStandAlone.h>
41#include <reconstruction/calibration/BeamSpotBoostInvMass/InvariantMassMuMuIntegrator.h>
42#include <reconstruction/calibration/BeamSpotBoostInvMass/BoostVectorStandAlone.h>
43#include <reconstruction/calibration/BeamSpotBoostInvMass/Splitter.h>
44#include <reconstruction/calibration/BeamSpotBoostInvMass/tools.h>
45#include <reconstruction/calibration/BeamSpotBoostInvMass/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
54using Eigen::MatrixXd;
55using Eigen::VectorXd;
56
57
58namespace Belle2::InvariantMassMuMuCalib {
59
60
61
62
64 std::vector<Event> getEvents(TTree* tr, bool is4S)
65 {
66
67 std::vector<Event> events;
68 events.reserve(tr->GetEntries());
69
70 Event evt;
71
72 tr->SetBranchAddress("run", &evt.run);
73 tr->SetBranchAddress("exp", &evt.exp);
74 tr->SetBranchAddress("event", &evt.evtNo);
75
76 B2Vector3D* p0 = nullptr;
77 B2Vector3D* p1 = nullptr;
78
79 tr->SetBranchAddress("mu0_p", &p0);
80 tr->SetBranchAddress("mu1_p", &p1);
81
82 tr->SetBranchAddress("mu0_pid", &evt.mu0.pid);
83 tr->SetBranchAddress("mu1_pid", &evt.mu1.pid);
84
85
86 tr->SetBranchAddress("time", &evt.t); //time in hours
87
88 const double mMu = EvtGenDatabasePDG::Instance()->GetParticle("mu-")->Mass(); //muon mass, i.e. around 105.66e-3 [GeV]
89
90 for (int i = 0; i < tr->GetEntries(); ++i) {
91 tr->GetEntry(i);
92
93 evt.mu0.p = *p0;
94 evt.mu1.p = *p1;
95
96 evt.m = sqrt(square(hypot(evt.mu0.p.Mag(), mMu) + hypot(evt.mu1.p.Mag(), mMu)) - (evt.mu0.p + evt.mu1.p).Mag2());
97
98 evt.nBootStrap = 1;
99 evt.isSig = true;
100 evt.is4S = is4S;
101 events.push_back(evt);
102 }
103
104 //sort by time
105 sort(events.begin(), events.end(), [](const Event & e1, const Event & e2) {return e1.t < e2.t;});
106
107
108 return events;
109 }
110
111
112
113
114
115 // Numerical integration using Gauss-Konrod algorithm
116 double integrate(std::function<double(double)> f, double a, double b)
117 {
118 static const std::vector<double> nodes = {
119 -0.991455371120813,
120 -0.949107912342759,
121 -0.864864423359769,
122 -0.741531185599394,
123 -0.586087235467691,
124 -0.405845151377397,
125 -0.207784955007898,
126 0.000000000000000
127 };
128
129 static const std::vector<double> wgts = {
130 0.022935322010529,
131 0.063092092629979,
132 0.104790010322250,
133 0.140653259715525,
134 0.169004726639267,
135 0.190350578064785,
136 0.204432940075298,
137 0.209482141084728
138 };
139
140 if (b < a) B2FATAL("Wrongly defined integration interval");
141
142 double m = (b + a) / 2; //middle of the interval
143 double d = (b - a) / 2; //half-width of the interval
144
145 double sum = 0;
146 for (unsigned i = 0; i < nodes.size() - 1; ++i) {
147 double x1 = m - d * nodes[i];
148 double x2 = m + d * nodes[i];
149 sum += (f(x1) + f(x2)) * wgts[i];
150 }
151
152 //add the central point (which is not in pair)
153 sum += f(m) * wgts.back();
154
155
156 // scale by size of interval, for example a=-1, b=1 -> no scaling
157 return sum * d;
158 }
159
160
161
162
163
164
165
166
167
168
170 double gausInt(double a, double b, double c, double d)
171 {
172 double res = sqrt(M_PI) / (2 * sqrt(c)) * (TMath::Erf((b * c - d) / sqrt(c)) - TMath::Erf((a * c - d) / sqrt(c)));
173 return res;
174 }
175
176
179 double convGausGaus(double sK, double s, double a, double b, double m, double x)
180 {
181 a -= m;
182 b -= m;
183 x -= m;
184
185
186 double c = 1. / 2 * (1. / s / s + 1. / sK / sK);
187 double d = 1. / 2 * x / sK / sK;
188
189 double Const = 1. / (2 * M_PI) * 1. / (s * sK) * exp(-1. / 2 * x * x / (s * s + sK * sK));
190
191 double res = Const * gausInt(a, b, c, d);
192 assert(std::isfinite(res));
193 return res;
194 }
195
196
197
198
202 double convExpGaus(double sK, double tau, double a, double x)
203 {
204 x -= a;
205
206 double A = 1. / sqrt(2) * (-x / sK + sK / tau);
207 double B = -x / tau + 1. / 2 * square(sK / tau);
208 double res = 0;
209 if (B > 700 || A > 20) { // safety term to deal with 0 * inf limit
210 res = 1. / (2 * tau) * 1. / sqrt(M_PI) * exp(-A * A + B) * (1 / A - 1 / 2. / cube(A) + 3. / 4 / pow5(A));
211 } else {
212 res = 1. / (2 * tau) * TMath::Erfc(A) * exp(B);
213 }
214 assert(std::isfinite(res));
215 return res;
216 }
217
218
219 // convolution of Gaussian with exp tails with the Gaussian smearing kernel
220 double gausExpConv(double mean, double sigma, double bMean, double bDelta, double tauL, double tauR, double sigmaK, double x)
221 {
222 double bL = bMean - bDelta;
223 double bR = bMean + bDelta;
224
225 double xL = bL * sigma + mean;
226 double xR = bR * sigma + mean;
227
228 double iGaus = sqrt(2 * M_PI) * sigma * convGausGaus(sigmaK, sigma, xL, xR, mean, x);
229 double iRight = exp(-1. / 2 * (bR * bR)) * tauR * convExpGaus(sigmaK, tauR, xR, x);
230 double iLeft = exp(-1. / 2 * (bL * bL)) * tauL * convExpGaus(sigmaK, tauL, -xL, -x);
231
232 return (iGaus + iLeft + iRight);
233 }
234
236 double gausExpConvRoot(const double* par)
237 {
238 double x = par[0]; // point where the function is evaluated
239 double mean = par[1]; // mean of Gauss in "Crystal Ball" with exp tails instead of pow
240 double sigma = par[2]; // sigma of Gauss in "Crystal Ball" with exp tails instead of pow
241 double bMean = par[3]; // mean of the transition points between Gaus and exp
242 double bDelta = par[4]; // diff/2 of the transition points between Gaus and exp
243 double tauL = par[5]; // decay par of the left exp
244 double tauR = par[6]; // decay par of the right exp
245 double sigmaK = par[7]; // sigma of the Gaussian smearing Kernel
246 double sigmaA = par[8]; // sigma of the added Gaussian
247 double fA = par[9]; // fraction of the added Gaussian
248
249 //added Gaussian
250 double G = 1. / (sqrt(2 * M_PI) * sigmaA) * exp(-1. / 2 * square((x - mean) / sigmaA));
251 return (1 - fA) * gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x) + fA * G;
252 }
253
254
257 double gausExpPowConvRoot(const double* par)
258 {
259 double x = par[0]; // point where the function is evaluated
260 double mean = par[1]; // mean of Gauss in "Crystal Ball" with exp tails instead of pow
261 double sigma = par[2]; // sigma of Gauss in "Crystal Ball" with exp tails instead of pow
262 double bMean = par[3]; // mean of the transition points between Gaus and exp
263 double bDelta = par[4]; // diff/2 of the transition points between Gaus and exp
264 double tauL = par[5]; // decay par of the left exp
265 double tauR = par[6]; // decay par of the right exp
266 double sigmaK = par[7]; // sigma of the Gaussian smearing Kernel
267 double sigmaA = par[8]; // sigma of the added Gaussian
268 double fA = par[9]; // fraction of the added Gaussian
269
270
271
272 double eCMS = par[10]; // center of mass energy of the collisions
273 double slope = par[11]; // power-slope of gen-level spectra from ISR
274 double K = par[12]; // normalisation of the part without photon ISR
275
276 double step = 0.10; // step size in the integration
277 int N = 800 * 1. / step;
278
279 double sum = 0;
280
281 //calculation of the convolution using trapezium rule
282 for (int i = 0; i < N; ++i) {
283
284 double t = eCMS - i * step;
285
286 double y = x - t;
287 double G = 1. / (sqrt(2 * M_PI) * sigmaA) * exp(-1. / 2 * square((y - mean) / sigmaA));
288 double Core = (1 - fA) * gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, y) + fA * G;
289
290 double C = (i == 0 || i == N - 1) ? 0.5 : 1;
291
292 double Kernel;
293 if (i == 0)
294 Kernel = K * pow(step, -slope);
295 else
296 Kernel = pow(eCMS - t, -slope);
297
298
299 sum += Kernel * Core * step * C;
300 }
301
302 return sum;
303 }
304
305
306
307
308
309
312 void plotTest()
313 {
314 double mean = 0;
315 double bMean = 0;
316 double bDelta = 5;
317 double tauL = 30;
318 double tauR = 30;
319 double sigma = 10;
320 double sigmaK = 40;
321
322 TGraph* gr = new TGraph;
323 for (double x = -300; x < 300; x += 1) {
324
325 double v = gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x);
326
327 gr->SetPoint(gr->GetN(), x, v);
328 }
329
330 gr->Draw();
331 }
332
333
335 double gausExp(const double* par)
336 {
337 double x = par[0]; // point where the function is evaluated
338 double mean = par[1]; // mean of Gaus
339 double sigma = par[2]; // sigma of Gaus
340 double bMean = par[3]; // mean of the transition points between Gaus and exp
341 double bDelta = par[4]; // diff/2 of the transition points between Gaus and exp
342
343 double bL = bMean - bDelta;
344 double bR = bMean + bDelta;
345
346
347 double r = (x - mean) / sigma;
348 if (bL <= r && r <= bR) {
349 return exp(-1. / 2 * (r * r));
350 } else if (r < bL) {
351 double tauL = par[5]; // decay par of the left exp
352 double bp = exp(-1. / 2 * (bL * bL));
353 double xb = mean + bL * sigma;
354 return exp((x - xb) / tauL) * bp;
355 } else {
356 double tauR = par[6]; // decay par of the right exp
357 double bp = exp(-1. / 2 * (bR * bR));
358 double xb = mean + bR * sigma;
359 return exp(-(x - xb) / tauR) * bp;
360 }
361 }
362
363
364
365
366
367
370 void plotInt()
371 {
372 double mean = 4;
373 double sigma = 30;
374 double sigmaK = 30;
375 double bMean = 0;
376 double bDelta = 2.6;
377 double tau = 60;
378
379 double x = 10300;
380
381 TGraph* gr = new TGraph;
382 TGraph* grE = new TGraph;
383 TGraph* grRat = new TGraph;
384 TGraph* grR = new TGraph;
385
386 double m0 = 10500;
387 double slope = 0.95;
388 double eps = 0.01;
389
390 double frac = 0.2;
391 double sigmaE = 30;
392
393 for (double t = eps; t < 5000; t += 1.00) {
394 double Core = gausExpConv(mean, sigma, bMean, bDelta, tau, tau, sigmaK, x + t - m0);
395 double K = (+t) >= eps ? pow(+ t, -slope) : 0;
396
397 double fun = Core * K;
398 gr->SetPoint(gr->GetN(), t, fun);
399
400 double s = exp(-t / tau);
401
402 double funE = exp(-abs(x - m0 + t) / tau) * 1 / t;
403 grE->SetPoint(grE->GetN(), t, funE);
404 if (funE > 0) {
405 grRat->SetPoint(grE->GetN(), t, fun / funE);
406 grR->SetPoint(grR->GetN(), s, fun / funE);
407 }
408 }
409
410
412
413 TGraph* grM = new TGraph; // the PDF used in the fit
414
415 double C = 16;
416
417 for (double xNow = 10000; xNow <= 11000; xNow += 0.1) {
418
419 integrator.init(mean,
420 sigma,
421 sigmaK,
422 bMean,
423 bDelta,
424 tau,
425 sigmaE,
426 frac,
427 m0,
428 eps,
429 C,
430 slope,
431 xNow);
432
433
434 grM->SetPoint(grM->GetN(), xNow, integrator.integralKronrod(2000));
435 }
436
437 grM->Draw();
438
439
440 delete gr;
441 delete grE;
442 delete grRat;
443 delete grR;
444 delete grM;
445
446 }
447
448
450 // The signature is imposed by its use as a callback, 'par' cannot be passed by const reference.
451 // cppcheck-suppress passedByValueCallback
452 double mainFunction(double xx, Pars par)
453 {
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 std::vector<double> readEvents(const std::vector<Event>& evts, double pidCut, double a, double b)
477 {
478
479 std::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, const 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 += square(hPull->GetBinContent(j));
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 std::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 std::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 std::pair<Pars, MatrixXd> getInvMassPars(const std::vector<Event>& evts, Pars pars, double mMin, double mMax, int bootStrap = 0)
712 {
713 std::vector<double> dataNow = readEvents(evts, 0.9/*PIDcut*/, mMin, mMax);
714
715
716 // do bootStrap
717 std::vector<double> data;
718 TRandom3* rand = nullptr;
719 if (bootStrap) rand = new TRandom3(bootStrap);
720 for (auto d : dataNow) {
721 int nP = bootStrap ? rand->Poisson(1) : 1;
722 for (int i = 0; i < nP; ++i)
723 data.push_back(d);
724 }
725
726 if (bootStrap)
727 delete rand;
728
729 ChebFitter fitter;
730 fitter.setDataAndFunction(mainFunction, data);
731 fitter.init(256 + 1, mMin, mMax);
732
733
734 Pars pars0_4S = {
735 {"C", 15 },
736 {"bDelta", 1.60307 },
737 {"bMean", 0 },
738 {"frac", 0.998051 },
739 {"m0", 10570.2 },
740 {"mean", 4.13917 },
741 {"sigma", 37.0859 },
742 {"slope", 0.876812 },
743 {"tau", 99.4225}
744 };
745
746 Pars pars0_Off = {
747 {"C", 15 },
748 {"bDelta", 2.11 },
749 {"bMean", 0 },
750 {"frac", 0.9854 },
751 {"m0", mMax - 230 },
752 {"mean", 4.13917 },
753 {"sigma", 36.4 },
754 {"slope", 0.892 },
755 {"tau", 64.9}
756 };
757
758 if (pars.empty()) {
759 bool is4S = evts[0].is4S;
760 pars = is4S ? pars0_4S : pars0_Off;
761 }
762
763
764
765 Limits limits = {
766 {"mean", std::make_pair(0, 0)},
767 {"sigma", std::make_pair(10, 120)},
768 {"bMean", std::make_pair(0, 0)},
769 {"bDelta", std::make_pair(0.01, 10.)},
770 {"tau", std::make_pair(20, 250)},
771 {"frac", std::make_pair(0.00, 1.0)},
772
773 {"m0", std::make_pair(10450, 10950)},
774 {"slope", std::make_pair(0.3, 0.999)},
775 {"C", std::make_pair(0, 0)}
776 };
777
778
779 return fitter.fitData(pars, limits, true/*useCheb*/);
780
781 }
782
783
784
785
786 // Returns tuple with the invariant mass parameters (cmsEnergy in GeV)
787 std::tuple<std::vector<VectorXd>, std::vector<MatrixXd>, MatrixXd> runMuMuInvariantMassAnalysis(const std::vector<Event>& evts,
788 const std::vector<double>& splitPoints)
789 {
790 int n = splitPoints.size() + 1;
791
792 std::vector<VectorXd> invMassVec(n);
793 std::vector<MatrixXd> invMassVecUnc(n);
794 MatrixXd invMassVecSpred;
795
796 std::ofstream mumuTextOut("mumuEcalib.txt", std::ios::app);
797 static int iPrint = 0;
798 if (iPrint == 0)
799 mumuTextOut << "n id t1 t2 exp1 run1 exp2 run2 Ecms EcmsUnc state" << std::endl;
800 ++iPrint;
801
802 for (int iDiv = 0; iDiv < n; ++iDiv) {
803
804
805 invMassVec[iDiv].resize(1); //1D vector for center of the 1D Gauss
806 invMassVecUnc[iDiv].resize(1, 1); //1x1 matrix covariance mat of the center
807 invMassVecSpred.resize(1, 1); //1x1 matrix for spread of the 1D Gauss
808
809 std::vector<Event> evtsNow;
810 for (const auto& ev : evts) {
811 double tMin = (iDiv != 0) ? splitPoints[iDiv - 1] : -1e40;
812 double tMax = (iDiv != n - 1) ? splitPoints[iDiv] : 1e40;
813 if (tMin <= ev.t && ev.t < tMax)
814 evtsNow.push_back(ev);
815
816 }
817
818
819
820 // default fitting range for the mumu invariant mass
821 double mMin = 10.2e3, mMax = 10.8e3;
822
823 // in case of offResonance runs adjust limits from median
824 if (!evtsNow[0].is4S) {
825 std::vector<double> dataNow;
826 for (const auto& ev : evtsNow)
827 dataNow.push_back(ev.m);
828 double mMedian = 1e3 * Belle2::BoostVectorCalib::median(dataNow.data(), dataNow.size());
829 double est = mMedian + 30;
830 mMax = est + 220;
831 mMin = est - 380;
832 }
833
834
835
836
837 // number of required successful bootstrap replicas
838 const int nRep = 25;
839
840
841 std::vector<double> vals, errs;
842 for (int rep = 0; rep < 200; ++rep) {
843 double errEst = 50. / sqrt(evtsNow.size());
844
845 Pars resP, inDummy;
846 MatrixXd resM;
847
848
849 // fit using bootstrap replica replicas, rep=0 is no replica
850 tie(resP, resM) = getInvMassPars(evtsNow, inDummy, mMin, mMax, rep);
851
852 int ind = distance(resP.begin(), resP.find("m0"));
853 double mass = resP.at("m0");
854 double err = sqrt(resM(ind, ind));
855
856
857 // if there are problems with fit, try again with different bootstrap replica
858 if (!(errEst < err && err < 4 * errEst))
859 continue;
860
861 vals.push_back(mass);
862 errs.push_back(err);
863
864 // if now bootstrapping needed, plot & break
865 if (rep == 0) {
866 plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP, resM, mMin, mMax, int(round(evtsNow[0].t)));
867 break;
868 }
869
870 // try fit with different input parameters, but without bootstrapping
871 Pars resP0;
872 MatrixXd resM0;
873 tie(resP0, resM0) = getInvMassPars(evtsNow, resP, mMin, mMax, 0);
874
875 int ind0 = distance(resP0.begin(), resP0.find("m0"));
876 double mass0 = resP0.at("m0");
877 double err0 = sqrt(resM0(ind0, ind0));
878
879 // if successful, plot & break
880 if (errEst < err0 && err0 < 4 * errEst) {
881 vals = {mass0};
882 errs = {err0};
883 plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP0, resM0, mMin, mMax, int(round(evtsNow[0].t)));
884 break;
885 }
886
887
888 // if the fit was successful several times only on replicas, plot & break
889 if (vals.size() >= nRep) {
890 plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP, resM, mMin, mMax, int(round(evtsNow[0].t)));
891 break;
892 }
893
894 }
895
896 if (vals.size() != 1 && vals.size() != nRep)
897 B2FATAL("Inconsistency of number of results with number of replicas");
898
899 double meanMass = accumulate(vals.begin(), vals.end(), 0.) / vals.size();
900 double meanMassUnc = accumulate(errs.begin(), errs.end(), 0.) / errs.size();
901
902 double sum2 = 0;
903 for (auto v : vals)
904 sum2 += square(v - meanMass);
905 double errBootStrap = vals.size() > 1 ? sqrt(sum2 / (vals.size() - 1)) : 0;
906
907 mumuTextOut << n << " " << iDiv << " " << std::setprecision(14) << evtsNow.front().t << " " << evtsNow.back().t << " " <<
908 evtsNow.front().exp << " " << evtsNow.front().run << " " << evtsNow.back().exp << " " << evtsNow.back().run << " " << meanMass
909 <<
910 " " << meanMassUnc << " " << errBootStrap << std::endl;
911
912 // Convert to GeV
913 invMassVec[iDiv](0) = meanMass / 1e3;
914 invMassVecUnc[iDiv](0, 0) = meanMassUnc / 1e3;
915 invMassVecSpred(0, 0) = 0;
916 }
917
918 mumuTextOut.close();
919
920 return std::make_tuple(invMassVec, invMassVecUnc, invMassVecSpred);
921 }
922
923}
#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.
constexpr T cube(const T &x)
Calculate the cube of the input.
Definition MathHelpers.h:29
constexpr T square(const T &x)
Calculate the square of the input.
Definition MathHelpers.h:21
constexpr T pow5(const T &x)
Calculate the fifth power of the input.
Definition MathHelpers.h:46
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition B2Vector3.h:522
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