29#include <Math/Functor.h>
30#include <Math/SpecFuncMathCore.h>
31#include <Math/DistFunc.h>
35#include <framework/particledb/EvtGenDatabasePDG.h>
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>
46#include <InvariantMassMuMuStandAlone.h>
47#include <InvariantMassMuMuIntegrator.h>
50#include <ChebFitter.h>
57namespace Belle2::InvariantMassMuMuCalib {
63 std::vector<Event> getEvents(TTree* tr,
bool is4S)
66 std::vector<Event> events;
67 events.reserve(tr->GetEntries());
71 tr->SetBranchAddress(
"run", &evt.run);
72 tr->SetBranchAddress(
"exp", &evt.exp);
73 tr->SetBranchAddress(
"event", &evt.evtNo);
78 tr->SetBranchAddress(
"mu0_p", &p0);
79 tr->SetBranchAddress(
"mu1_p", &p1);
81 tr->SetBranchAddress(
"mu0_pid", &evt.mu0.pid);
82 tr->SetBranchAddress(
"mu1_pid", &evt.mu1.pid);
85 tr->SetBranchAddress(
"time", &evt.t);
89 for (
int i = 0; i < tr->GetEntries(); ++i) {
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());
100 events.push_back(evt);
104 sort(events.begin(), events.end(), [](Event e1, Event e2) {return e1.t < e2.t;});
115 double integrate(std::function<
double(
double)> f,
double a,
double b)
117 static const std::vector<double> nodes = {
128 static const std::vector<double> wgts = {
139 if (b < a) B2FATAL(
"Wrongly defined integration interval");
141 double m = (b + a) / 2;
142 double d = (b - a) / 2;
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];
152 sum += f(m) * wgts.back();
169 double gausInt(
double a,
double b,
double c,
double d)
171 double res =
sqrt(M_PI) / (2 *
sqrt(c)) * (TMath::Erf((b * c - d) /
sqrt(c)) - TMath::Erf((a * c - d) /
sqrt(c)));
178 double convGausGaus(
double sK,
double s,
double a,
double b,
double m,
double x)
185 double c = 1. / 2 * (1. / s / s + 1. / sK / sK);
186 double d = 1. / 2 * x / sK / sK;
188 double Const = 1. / (2 * M_PI) * 1. / (s * sK) * exp(-1. / 2 * x * x / (s * s + sK * sK));
190 double res = Const * gausInt(a, b, c, d);
191 assert(isfinite(res));
201 double convExpGaus(
double sK,
double tau,
double a,
double x)
205 double A = 1. /
sqrt(2) * (-x / sK + sK / tau);
206 double B = -x / tau + 1. / 2 * pow(sK / tau, 2);
208 if (B > 700 || A > 20) {
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));
211 res = 1. / (2 * tau) * TMath::Erfc(A) * exp(B);
213 assert(isfinite(res));
219 double gausExpConv(
double mean,
double sigma,
double bMean,
double bDelta,
double tauL,
double tauR,
double sigmaK,
double x)
221 double bL = bMean - bDelta;
222 double bR = bMean + bDelta;
224 double xL = bL * sigma + mean;
225 double xR = bR * sigma + mean;
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);
231 return (iGaus + iLeft + iRight);
235 double gausExpConvRoot(
const double* par)
238 double mean = par[1];
239 double sigma = par[2];
240 double bMean = par[3];
241 double bDelta = par[4];
242 double tauL = par[5];
243 double tauR = par[6];
244 double sigmaK = par[7];
245 double sigmaA = par[8];
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;
256 double gausExpPowConvRoot(
const double* par)
259 double mean = par[1];
260 double sigma = par[2];
261 double bMean = par[3];
262 double bDelta = par[4];
263 double tauL = par[5];
264 double tauR = par[6];
265 double sigmaK = par[7];
266 double sigmaA = par[8];
271 double eCMS = par[10];
272 double slope = par[11];
276 int N = 800 * 1. / step;
281 for (
int i = 0; i < N; ++i) {
283 double t = eCMS - i * step;
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;
289 double C = (i == 0 || i == N - 1) ? 0.5 : 1;
293 Kernel =
K * pow(step, -slope);
295 Kernel = pow(eCMS - t, -slope);
298 sum += Kernel * Core * step * C;
321 TGraph* gr =
new TGraph;
322 for (
double x = -300; x < 300; x += 1) {
324 double v = gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x);
326 gr->SetPoint(gr->GetN(), x, v);
334 double gausExp(
const double* par)
337 double mean = par[1];
338 double sigma = par[2];
339 double bMean = par[3];
340 double bDelta = par[4];
341 double tauL = par[5];
342 double tauR = par[6];
344 double bL = bMean - bDelta;
345 double bR = bMean + bDelta;
348 double r = (x - mean) / sigma;
349 if (bL <= r && r <= bR) {
350 return exp(-1. / 2 * pow(r, 2));
352 double bp = exp(-1. / 2 * pow(bL, 2));
353 double xb = mean + bL * sigma;
354 return exp((x - xb) / tauL) * bp;
356 double bp = exp(-1. / 2 * pow(bR, 2));
357 double xb = mean + bR * sigma;
358 return exp(-(x - xb) / tauR) * bp;
380 TGraph* gr =
new TGraph;
381 TGraph* grE =
new TGraph;
382 TGraph* grRat =
new TGraph;
383 TGraph* grR =
new TGraph;
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;
396 double fun = Core *
K;
397 gr->SetPoint(gr->GetN(), t, fun);
399 double s = exp(-t / tau);
401 double funE = exp(-abs(x - m0 + t) / tau) * 1 / t;
402 grE->SetPoint(grE->GetN(), t, funE);
404 grRat->SetPoint(grE->GetN(), t, fun / funE);
405 grR->SetPoint(grR->GetN(), s, fun / funE);
410 InvariantMassMuMuIntegrator integrator;
412 TGraph* grM =
new TGraph;
416 for (
double xNow = 10000; xNow <= 11000; xNow += 0.1) {
418 integrator.init(mean,
433 grM->SetPoint(grM->GetN(), xNow, integrator.integralKronrod(2000));
449 double mainFunction(
double xx,
Pars par)
451 InvariantMassMuMuIntegrator fun;
453 fun.init(par.at(
"mean"),
467 return fun.integralKronrod(2000);
473 std::vector<double> readEvents(
const std::vector<Event>& evts,
double pidCut,
double a,
double b)
476 std::vector<double> vMass;
477 for (
const auto& ev : evts) {
480 if (ev.mu0.pid < pidCut || ev.mu1.pid < pidCut) {
484 double m = 1e3 * ev.m;
494 static void plotMuMuFitBase(TH1D* hData, TGraph* gr, TH1D* hPull,
Pars pars, Eigen::MatrixXd mat,
int time)
496 bool isBatch = gROOT->IsBatch();
497 gROOT->SetBatch(kTRUE);
499 gStyle->SetOptStat(0);
501 TCanvas* can =
new TCanvas(Form(
"canMuMu_%d", time),
"");
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);
506 pad1->SetBottomMargin(0.05);
507 pad2->SetTopMargin(0.05);
508 pad2->SetBottomMargin(0.35);
519 hData->SetMarkerStyle(kFullCircle);
521 gr->SetLineColor(kRed);
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);
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);
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));
544 int nDig = log10(p.second / err) + 2;
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");
554 leg->SetTextSize(0.05);
555 leg->SetBorderSize(0);
556 leg->SetFillStyle(0);
561 for (
int j = 1; j <= hPull->GetNbinsX(); ++j)
562 chi2 += pow(hPull->GetBinContent(j), 2);
563 int ndf = hPull->GetNbinsX() - nPars - 1;
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");
570 leg2->SetTextSize(0.05);
571 leg2->SetBorderSize(0);
572 leg2->SetFillStyle(0);
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);
590 hPull->SetMarkerStyle(kFullCircle);
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);
602 hPull->GetYaxis()->SetTitleSize(0.13);
603 hPull->GetYaxis()->SetLabelSize(0.13);
604 hPull->GetYaxis()->SetTitleOffset(0.2);
605 hPull->GetYaxis()->CenterTitle();
608 hPull->GetYaxis()->SetNdivisions(404);
610 hPull->GetYaxis()->SetRangeUser(-5, 5);
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");
619 std::filesystem::create_directories(
"plotsMuMu");
621 can->SaveAs(Form(
"plotsMuMu/mumu_%d.pdf", time));
635 gROOT->SetBatch(isBatch);
639 static void plotMuMuFit(
const std::vector<double>& data,
const Pars& pars, Eigen::MatrixXd mat,
double mMin,
double mMax,
int time)
641 const int nBins = 100;
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);
658 TGraph* gr =
new TGraph();
659 const double step = (mMax - mMin) / (nBins);
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);
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);
674 double I = step / 6 * (lV + 4 * cV + rV);
675 hFit->SetBinContent(i + 1, I);
679 double F = hData->Integral() / hFit->Integral();
684 for (
int i = 0; i < gr->GetN(); ++i)
685 gr->SetPointY(i, gr->GetPointY(i) * F * step);
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);
695 plotMuMuFitBase(hData, gr, hPull, pars, mat, time);
708 std::pair<Pars, MatrixXd> getInvMassPars(
const std::vector<Event>& evts,
Pars pars,
double mMin,
double mMax,
int bootStrap = 0)
710 bool is4S = evts[0].is4S;
712 std::vector<double> dataNow = readEvents(evts, 0.9, mMin, mMax);
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)
729 fitter.setDataAndFunction(mainFunction, data);
730 fitter.init(256 + 1, mMin, mMax);
735 {
"bDelta", 1.60307 },
741 {
"slope", 0.876812 },
758 pars = is4S ? pars0_4S : pars0_Off;
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)},
771 {
"m0", std::make_pair(10450, 10950)},
772 {
"slope", std::make_pair(0.3, 0.999)},
773 {
"C", std::make_pair(0, 0)}
777 return fitter.fitData(pars, limits,
true);
785 std::tuple<std::vector<VectorXd>, std::vector<MatrixXd>, MatrixXd> runMuMuInvariantMassAnalysis(std::vector<Event> evts,
786 const std::vector<double>& splitPoints)
788 int n = splitPoints.size() + 1;
790 std::vector<VectorXd> invMassVec(n);
791 std::vector<MatrixXd> invMassVecUnc(n);
792 MatrixXd invMassVecSpred;
794 std::ofstream mumuTextOut(
"mumuEcalib.txt", std::ios::app);
795 static int iPrint = 0;
797 mumuTextOut <<
"n id t1 t2 exp1 run1 exp2 run2 Ecms EcmsUnc state" << std::endl;
800 for (
int iDiv = 0; iDiv < n; ++iDiv) {
803 invMassVec[iDiv].resize(1);
804 invMassVecUnc[iDiv].resize(1, 1);
805 invMassVecSpred.resize(1, 1);
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);
819 double mMin = 10.2e3, mMax = 10.8e3;
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;
839 std::vector<double> vals, errs;
840 for (
int rep = 0; rep < 200; ++rep) {
841 double errEst = 50. /
sqrt(evtsNow.size());
848 tie(resP, resM) = getInvMassPars(evtsNow, inDummy, mMin, mMax, rep);
850 int ind = distance(resP.begin(), resP.find(
"m0"));
851 double mass = resP.at(
"m0");
852 double err =
sqrt(resM(ind, ind));
856 if (!(errEst < err && err < 4 * errEst))
859 vals.push_back(mass);
864 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
871 tie(resP0, resM0) = getInvMassPars(evtsNow, resP, mMin, mMax, 0);
873 int ind0 = distance(resP0.begin(), resP0.find(
"m0"));
874 double mass0 = resP0.at(
"m0");
875 double err0 =
sqrt(resM0(ind0, ind0));
878 if (errEst < err0 && err0 < 4 * errEst) {
881 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP0, resM0, mMin, mMax,
int(round(evtsNow[0].t)));
887 if (vals.size() >= nRep) {
888 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
894 if (vals.size() != 1 && vals.size() != nRep)
895 B2FATAL(
"Inconsistency of number of results with number of replicas");
897 double meanMass = accumulate(vals.begin(), vals.end(), 0.) / vals.size();
898 double meanMassUnc = accumulate(errs.begin(), errs.end(), 0.) / errs.size();
902 sum2 += pow(v - meanMass, 2);
903 double errBootStrap = vals.size() > 1 ?
sqrt(sum2 / (vals.size() - 1)) : 0;
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
908 " " << meanMassUnc <<
" " << errBootStrap << std::endl;
911 invMassVec[iDiv](0) = meanMass / 1e3;
912 invMassVecUnc[iDiv](0, 0) = meanMassUnc / 1e3;
913 invMassVecSpred(0, 0) = 0;
918 return std::make_tuple(invMassVec, invMassVecUnc, invMassVecSpred);
static EvtGenDatabasePDG * Instance()
Instance method that loads the EvtGen table.
B2Vector3< double > B2Vector3D
typedef for common usage with double
double sqrt(double a)
sqrt for double
std::map< std::string, double > Pars
values of parameters in ML fit
std::map< std::string, std::pair< double, double > > Limits
limits of parameters in ML fit