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(std::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(std::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);
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)
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.
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
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
Event containing two tracks.