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(), [](Event e1, 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 double tauL = par[5]; // decay par of the left exp
343 double tauR = par[6]; // decay par of the right exp
344
345 double bL = bMean - bDelta;
346 double bR = bMean + bDelta;
347
348
349 double r = (x - mean) / sigma;
350 if (bL <= r && r <= bR) {
351 return exp(-1. / 2 * (r * r));
352 } else if (r < bL) {
353 double bp = exp(-1. / 2 * (bL * bL));
354 double xb = mean + bL * sigma;
355 return exp((x - xb) / tauL) * bp;
356 } else {
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 double mainFunction(double xx, Pars par)
451 {
453
454 fun.init(par.at("mean"), // mean
455 par.at("sigma"), // sigma
456 par.at("sigma"), // sigmaK
457 par.at("bMean"), // bMean
458 par.at("bDelta"),// bDelta
459 par.at("tau"), // tau=tauL=tauR
460 par.at("sigma"), // sigmaE
461 par.at("frac"), // frac
462 par.at("m0"), // m0
463 0.1, // eps
464 par.at("C"), // C
465 par.at("slope"), // slope
466 xx); // x
467
468 return fun.integralKronrod(2000);
469 }
470
471
474 std::vector<double> readEvents(const std::vector<Event>& evts, double pidCut, double a, double b)
475 {
476
477 std::vector<double> vMass;
478 for (const auto& ev : evts) {
479
480 //Keep only muons
481 if (ev.mu0.pid < pidCut || ev.mu1.pid < pidCut) {
482 continue;
483 }
484
485 double m = 1e3 * ev.m; // from GeV to MeV
486 if (a < m && m < b)
487 vMass.push_back(m);
488 }
489
490 return vMass;
491 }
492
493
495 static void plotMuMuFitBase(TH1D* hData, TGraph* gr, TH1D* hPull, Pars pars, Eigen::MatrixXd mat, int time)
496 {
497 bool isBatch = gROOT->IsBatch();
498 gROOT->SetBatch(kTRUE);
499
500 gStyle->SetOptStat(0);
501
502 TCanvas* can = new TCanvas(Form("canMuMu_%d", time), "");
503
504 TPad* pad1 = new TPad(Form("pad1_%d", time), "", 0, 0.3, 1, 1.0);
505 TPad* pad2 = new TPad(Form("pad2_%d", time), "", 0, 0, 1, 0.3);
506
507 pad1->SetBottomMargin(0.05);
508 pad2->SetTopMargin(0.05);
509 pad2->SetBottomMargin(0.35);
510
511 pad1->Draw();
512 pad2->Draw();
513
515 // Main plot
517
518 pad1->cd();
519
520 hData->SetMarkerStyle(kFullCircle);
521 hData->Draw();
522 gr->SetLineColor(kRed);
523 gr->SetLineWidth(2);
524 gr->Draw("same");
525 hData->GetXaxis()->SetLabelSize(0.0001);
526 hData->GetYaxis()->SetLabelSize(0.05);
527 hData->GetYaxis()->SetTitle("Number of events");
528 hData->GetYaxis()->SetTitleSize(0.05);
529 hData->GetYaxis()->SetTitleOffset(0.9);
530
531 double mY4S = 10579.4;
532 double y = gr->Eval(mY4S);
533 TLine* line = new TLine(mY4S, 0, mY4S, y);
534 line->SetLineColor(kGreen);
535 line->SetLineWidth(2);
536 line->Draw();
537
538
539
540 TLegend* leg = new TLegend(.15, .4, .35, .87);
541 int i = 0, nPars = 0;
542 for (auto p : pars) {
543 double err = sqrt(mat(i, i));
544 if (err != 0) {
545 int nDig = log10(p.second / err) + 2;
546
547 TString s = "%s = %." + TString(Form("%d", nDig)) + "g";
548 TString dig = "%." + TString(Form("%d", nDig)) + "g";
549 TString digE = "%.2g";
550 leg->AddEntry((TObject*)0, Form("%s = " + dig + " #pm " + digE, p.first.c_str(), p.second, err), "h");
551 ++nPars;
552 }
553 ++i;
554 }
555 leg->SetTextSize(0.05);
556 leg->SetBorderSize(0);
557 leg->SetFillStyle(0);
558 leg->Draw();
559
560
561 double chi2 = 0;
562 for (int j = 1; j <= hPull->GetNbinsX(); ++j)
563 chi2 += square(hPull->GetBinContent(j));
564 int ndf = hPull->GetNbinsX() - nPars - 1;
565
566
567 TLegend* leg2 = new TLegend(.73, .75, .93, .87);
568 leg2->AddEntry((TObject*)0, Form("chi2/ndf = %.2f", chi2 / ndf), "h");
569 leg2->AddEntry((TObject*)0, Form("p = %.2g", TMath::Prob(chi2, ndf)), "h");
570
571 leg2->SetTextSize(0.05);
572 leg2->SetBorderSize(0);
573 leg2->SetFillStyle(0);
574 leg2->Draw();
575
576
577 double mFit = pars.at("m0");
578 double yF = gr->Eval(mFit);
579 TLine* lineR = new TLine(mFit, 0, mFit, yF);
580 lineR->SetLineColor(kRed);
581 lineR->SetLineWidth(2);
582 lineR->Draw();
583
584
585
587 // Ratio plot
589
590 pad2->cd();
591 hPull->SetMarkerStyle(kFullCircle);
592 hPull->Draw("p");
593
594 hPull->GetXaxis()->SetTitle("M (#mu#mu) [MeV]");
595 hPull->GetYaxis()->SetTitle("pull");
596 hPull->GetXaxis()->SetTitleSize(0.13);
597 hPull->GetXaxis()->SetTitleOffset(1.25);
598 hPull->GetXaxis()->SetLabelSize(0.13);
599 hPull->GetXaxis()->SetLabelOffset(0.05);
600 hPull->GetXaxis()->SetTickSize(0.07);
601
602
603 hPull->GetYaxis()->SetTitleSize(0.13);
604 hPull->GetYaxis()->SetLabelSize(0.13);
605 hPull->GetYaxis()->SetTitleOffset(0.2);
606 hPull->GetYaxis()->CenterTitle();
607
608
609 hPull->GetYaxis()->SetNdivisions(404);
610
611 hPull->GetYaxis()->SetRangeUser(-5, 5);
612
613 TGraph* grLine = new TGraph(2);
614 grLine->SetPoint(0, hPull->GetBinLowEdge(1), 0);
615 grLine->SetPoint(1, hPull->GetBinLowEdge(hPull->GetNbinsX()) + hPull->GetBinWidth(hPull->GetNbinsX()), 0);
616 grLine->SetLineWidth(2);
617 grLine->SetLineColor(kRed);
618 grLine->Draw("same");
619
620 std::filesystem::create_directories("plotsMuMu");
621
622 can->SaveAs(Form("plotsMuMu/mumu_%d.pdf", time));
623
624
625 delete leg;
626 delete leg2;
627 delete line;
628 delete lineR;
629 delete grLine;
630
631 delete pad1;
632 delete pad2;
633 delete can;
634
635
636 gROOT->SetBatch(isBatch);
637 }
638
640 static void plotMuMuFit(const std::vector<double>& data, const Pars& pars, Eigen::MatrixXd mat, double mMin, double mMax, int time)
641 {
642 const int nBins = 100;
643
644 // Fill the data histogram
645 TH1D::SetDefaultSumw2();
646 TH1D* hData = new TH1D("hData", "", nBins, mMin, mMax);
647 TH1D* hFit = new TH1D("hFit", "", nBins, mMin, mMax);
648 TH1D* hPull = new TH1D("hPull", "", nBins, mMin, mMax);
649 hData->SetDirectory(nullptr);
650 hFit->SetDirectory(nullptr);
651 hPull->SetDirectory(nullptr);
652
653 // fill histogram with data
654 for (auto d : data)
655 hData->Fill(d);
656
657
658 // construct the fitted function
659 TGraph* gr = new TGraph();
660 const double step = (mMax - mMin) / (nBins);
661
662 for (int i = 0; i <= 2 * nBins; ++i) {
663 double m = mMin + 0.5 * step * i;
664 double V = mainFunction(m, pars);
665 gr->SetPoint(gr->GetN(), m, V);
666 }
667
668
669 // Calculate integrals of the fitted function within each bin
670 for (int i = 0; i < nBins; ++i) {
671 double lV = gr->GetPointY(2 * i + 0);
672 double cV = gr->GetPointY(2 * i + 1);
673 double rV = gr->GetPointY(2 * i + 2);
674
675 double I = step / 6 * (lV + 4 * cV + rV);
676 hFit->SetBinContent(i + 1, I);
677 }
678
679 //Normalization factor
680 double F = hData->Integral() / hFit->Integral();
681
682 hFit->Scale(F);
683
684 // Normalize the curve
685 for (int i = 0; i < gr->GetN(); ++i)
686 gr->SetPointY(i, gr->GetPointY(i) * F * step);
687
688
689 // calculate pulls
690 for (int i = 1; i <= nBins; ++i) {
691 double pull = (hData->GetBinContent(i) - hFit->GetBinContent(i)) / sqrt(hFit->GetBinContent(i));
692 hPull->SetBinContent(i, pull);
693 }
694
695
696 plotMuMuFitBase(hData, gr, hPull, pars, mat, time);
697
698 delete hData;
699 delete hFit;
700 delete hPull;
701 delete gr;
702 }
703
704
705
706
709 std::pair<Pars, MatrixXd> getInvMassPars(const std::vector<Event>& evts, Pars pars, double mMin, double mMax, int bootStrap = 0)
710 {
711 bool is4S = evts[0].is4S;
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 pars = is4S ? pars0_4S : pars0_Off;
760 }
761
762
763
764 Limits limits = {
765 {"mean", std::make_pair(0, 0)},
766 {"sigma", std::make_pair(10, 120)},
767 {"bMean", std::make_pair(0, 0)},
768 {"bDelta", std::make_pair(0.01, 10.)},
769 {"tau", std::make_pair(20, 250)},
770 {"frac", std::make_pair(0.00, 1.0)},
771
772 {"m0", std::make_pair(10450, 10950)},
773 {"slope", std::make_pair(0.3, 0.999)},
774 {"C", std::make_pair(0, 0)}
775 };
776
777
778 return fitter.fitData(pars, limits, true/*useCheb*/);
779
780 }
781
782
783
784
785 // Returns tuple with the invariant mass parameters (cmsEnergy in GeV)
786 std::tuple<std::vector<VectorXd>, std::vector<MatrixXd>, MatrixXd> runMuMuInvariantMassAnalysis(std::vector<Event> evts,
787 const std::vector<double>& splitPoints)
788 {
789 int n = splitPoints.size() + 1;
790
791 std::vector<VectorXd> invMassVec(n);
792 std::vector<MatrixXd> invMassVecUnc(n);
793 MatrixXd invMassVecSpred;
794
795 std::ofstream mumuTextOut("mumuEcalib.txt", std::ios::app);
796 static int iPrint = 0;
797 if (iPrint == 0)
798 mumuTextOut << "n id t1 t2 exp1 run1 exp2 run2 Ecms EcmsUnc state" << std::endl;
799 ++iPrint;
800
801 for (int iDiv = 0; iDiv < n; ++iDiv) {
802
803
804 invMassVec[iDiv].resize(1); //1D vector for center of the 1D Gauss
805 invMassVecUnc[iDiv].resize(1, 1); //1x1 matrix covariance mat of the center
806 invMassVecSpred.resize(1, 1); //1x1 matrix for spread of the 1D Gauss
807
808 std::vector<Event> evtsNow;
809 for (auto ev : evts) {
810 double tMin = (iDiv != 0) ? splitPoints[iDiv - 1] : -1e40;
811 double tMax = (iDiv != n - 1) ? splitPoints[iDiv] : 1e40;
812 if (tMin <= ev.t && ev.t < tMax)
813 evtsNow.push_back(ev);
814
815 }
816
817
818
819 // default fitting range for the mumu invariant mass
820 double mMin = 10.2e3, mMax = 10.8e3;
821
822 // in case of offResonance runs adjust limits from median
823 if (!evtsNow[0].is4S) {
824 std::vector<double> dataNow;
825 for (const auto& ev : evtsNow)
826 dataNow.push_back(ev.m);
827 double mMedian = 1e3 * Belle2::BoostVectorCalib::median(dataNow.data(), dataNow.size());
828 double est = mMedian + 30;
829 mMax = est + 220;
830 mMin = est - 380;
831 }
832
833
834
835
836 // number of required successful bootstrap replicas
837 const int nRep = 25;
838
839
840 std::vector<double> vals, errs;
841 for (int rep = 0; rep < 200; ++rep) {
842 double errEst = 50. / sqrt(evtsNow.size());
843
844 Pars resP, inDummy;
845 MatrixXd resM;
846
847
848 // fit using bootstrap replica replicas, rep=0 is no replica
849 tie(resP, resM) = getInvMassPars(evtsNow, inDummy, mMin, mMax, rep);
850
851 int ind = distance(resP.begin(), resP.find("m0"));
852 double mass = resP.at("m0");
853 double err = sqrt(resM(ind, ind));
854
855
856 // if there are problems with fit, try again with different bootstrap replica
857 if (!(errEst < err && err < 4 * errEst))
858 continue;
859
860 vals.push_back(mass);
861 errs.push_back(err);
862
863 // if now bootstrapping needed, plot & break
864 if (rep == 0) {
865 plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP, resM, mMin, mMax, int(round(evtsNow[0].t)));
866 break;
867 }
868
869 // try fit with different input parameters, but without bootstrapping
870 Pars resP0;
871 MatrixXd resM0;
872 tie(resP0, resM0) = getInvMassPars(evtsNow, resP, mMin, mMax, 0);
873
874 int ind0 = distance(resP0.begin(), resP0.find("m0"));
875 double mass0 = resP0.at("m0");
876 double err0 = sqrt(resM0(ind0, ind0));
877
878 // if successful, plot & break
879 if (errEst < err0 && err0 < 4 * errEst) {
880 vals = {mass0};
881 errs = {err0};
882 plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP0, resM0, mMin, mMax, int(round(evtsNow[0].t)));
883 break;
884 }
885
886
887 // if the fit was successful several times only on replicas, plot & break
888 if (vals.size() >= nRep) {
889 plotMuMuFit(readEvents(evtsNow, 0.9/*PIDcut*/, mMin, mMax), resP, resM, mMin, mMax, int(round(evtsNow[0].t)));
890 break;
891 }
892
893 }
894
895 if (vals.size() != 1 && vals.size() != nRep)
896 B2FATAL("Inconsistency of number of results with number of replicas");
897
898 double meanMass = accumulate(vals.begin(), vals.end(), 0.) / vals.size();
899 double meanMassUnc = accumulate(errs.begin(), errs.end(), 0.) / errs.size();
900
901 double sum2 = 0;
902 for (auto v : vals)
903 sum2 += square(v - meanMass);
904 double errBootStrap = vals.size() > 1 ? sqrt(sum2 / (vals.size() - 1)) : 0;
905
906 mumuTextOut << n << " " << iDiv << " " << std::setprecision(14) << evtsNow.front().t << " " << evtsNow.back().t << " " <<
907 evtsNow.front().exp << " " << evtsNow.front().run << " " << evtsNow.back().exp << " " << evtsNow.back().run << " " << meanMass
908 <<
909 " " << meanMassUnc << " " << errBootStrap << std::endl;
910
911 // Convert to GeV
912 invMassVec[iDiv](0) = meanMass / 1e3;
913 invMassVecUnc[iDiv](0, 0) = meanMassUnc / 1e3;
914 invMassVecSpred(0, 0) = 0;
915 }
916
917 mumuTextOut.close();
918
919 return std::make_tuple(invMassVec, invMassVecUnc, invMassVecSpred);
920 }
921
922}
#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: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