30 #include <Math/Functor.h>
31 #include <Math/SpecFuncMathCore.h>
32 #include <Math/DistFunc.h>
34 #include <Eigen/Dense>
36 #include <framework/particledb/EvtGenDatabasePDG.h>
40 #include <tracking/calibration/InvariantMassMuMuStandAlone.h>
41 #include <tracking/calibration/InvariantMassMuMuIntegrator.h>
42 #include <tracking/calibration/BoostVectorStandAlone.h>
43 #include <tracking/calibration/Splitter.h>
44 #include <tracking/calibration/tools.h>
45 #include <tracking/calibration/ChebFitter.h>
47 #include <InvariantMassMuMuStandAlone.h>
48 #include <InvariantMassMuMuIntegrator.h>
51 #include <ChebFitter.h>
54 using Eigen::MatrixXd;
55 using Eigen::VectorXd;
60 namespace Belle2::InvariantMassMuMuCalib {
66 vector<Event> getEvents(TTree* tr,
bool is4S)
70 events.reserve(tr->GetEntries());
74 tr->SetBranchAddress(
"run", &evt.run);
75 tr->SetBranchAddress(
"exp", &evt.exp);
76 tr->SetBranchAddress(
"event", &evt.evtNo);
78 TVector3* p0 =
nullptr;
79 TVector3* p1 =
nullptr;
81 tr->SetBranchAddress(
"mu0_p", &p0);
82 tr->SetBranchAddress(
"mu1_p", &p1);
84 tr->SetBranchAddress(
"mu0_pid", &evt.mu0.pid);
85 tr->SetBranchAddress(
"mu1_pid", &evt.mu1.pid);
88 tr->SetBranchAddress(
"time", &evt.t);
90 const double mMu = EvtGenDatabasePDG::Instance()->GetParticle(
"mu-")->Mass();
92 for (
int i = 0; i < tr->GetEntries(); ++i) {
98 evt.m = sqrt(pow(hypot(evt.mu0.p.Mag(), mMu) + hypot(evt.mu1.p.Mag(), mMu), 2) - (evt.mu0.p + evt.mu1.p).Mag2());
103 events.push_back(evt);
107 sort(events.begin(), events.end(), [](Event e1, Event e2) {return e1.t < e2.t;});
118 double integrate(
function<
double(
double)> f,
double a,
double b)
120 static const vector<double> nodes = {
131 static const vector<double> wgts = {
142 if (b < a) B2FATAL(
"Wrongly defined integration interval");
144 double m = (b + a) / 2;
145 double d = (b - a) / 2;
148 for (
unsigned i = 0; i < nodes.size() - 1; ++i) {
149 double x1 = m - d * nodes[i];
150 double x2 = m + d * nodes[i];
151 sum += (f(x1) + f(x2)) * wgts[i];
155 sum += f(m) * wgts.back();
172 double gausInt(
double a,
double b,
double c,
double d)
174 double res = sqrt(M_PI) / (2 * sqrt(c)) * (TMath::Erf((b * c - d) / sqrt(c)) - TMath::Erf((a * c - d) / sqrt(c)));
181 double convGausGaus(
double sK,
double s,
double a,
double b,
double m,
double x)
188 double c = 1. / 2 * (1. / s / s + 1. / sK / sK);
189 double d = 1. / 2 * x / sK / sK;
191 double Const = 1. / (2 * M_PI) * 1. / (s * sK) * exp(-1. / 2 * x * x / (s * s + sK * sK));
193 double res = Const * gausInt(a, b, c, d);
194 assert(isfinite(res));
204 double convExpGaus(
double sK,
double tau,
double a,
double x)
208 double A = 1. / sqrt(2) * (-x / sK + sK / tau);
209 double B = -x / tau + 1. / 2 * pow(sK / tau, 2);
211 if (B > 700 || A > 20) {
212 res = 1. / (2 * tau) * 1. / sqrt(M_PI) * exp(-A * A + B) * (1 / A - 1 / 2. / pow(A, 3) + 3. / 4 / pow(A, 5));
214 res = 1. / (2 * tau) * TMath::Erfc(A) * exp(B);
216 assert(isfinite(res));
222 double gausExpConv(
double mean,
double sigma,
double bMean,
double bDelta,
double tauL,
double tauR,
double sigmaK,
double x)
224 double bL = bMean - bDelta;
225 double bR = bMean + bDelta;
227 double xL = bL * sigma + mean;
228 double xR = bR * sigma + mean;
230 double iGaus = sqrt(2 * M_PI) * sigma * convGausGaus(sigmaK, sigma, xL, xR, mean, x);
231 double iRight = exp(-1. / 2 * pow(bR, 2)) * tauR * convExpGaus(sigmaK, tauR, xR, x);
232 double iLeft = exp(-1. / 2 * pow(bL, 2)) * tauL * convExpGaus(sigmaK, tauL, -xL, -x);
234 return (iGaus + iLeft + iRight);
238 double gausExpConvRoot(
const double* par)
241 double mean = par[1];
242 double sigma = par[2];
243 double bMean = par[3];
244 double bDelta = par[4];
245 double tauL = par[5];
246 double tauR = par[6];
247 double sigmaK = par[7];
248 double sigmaA = par[8];
252 double G = 1. / (sqrt(2 * M_PI) * sigmaA) * exp(-1. / 2 * pow((x - mean) / sigmaA, 2));
253 return (1 - fA) * gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x) + fA * G;
259 double gausExpPowConvRoot(
const double* par)
262 double mean = par[1];
263 double sigma = par[2];
264 double bMean = par[3];
265 double bDelta = par[4];
266 double tauL = par[5];
267 double tauR = par[6];
268 double sigmaK = par[7];
269 double sigmaA = par[8];
274 double eCMS = par[10];
275 double slope = par[11];
279 int N = 800 * 1. / step;
284 for (
int i = 0; i < N; ++i) {
286 double t = eCMS - i * step;
289 double G = 1. / (sqrt(2 * M_PI) * sigmaA) * exp(-1. / 2 * pow((y - mean) / sigmaA, 2));
290 double Core = (1 - fA) * gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, y) + fA * G;
292 double C = (i == 0 || i == N - 1) ? 0.5 : 1;
296 Kernel = K * pow(step, -slope);
298 Kernel = pow(eCMS - t, -slope);
301 sum += Kernel * Core * step * C;
324 TGraph* gr =
new TGraph;
325 for (
double x = -300; x < 300; x += 1) {
327 double v = gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x);
329 gr->SetPoint(gr->GetN(), x, v);
337 double gausExp(
const double* par)
340 double mean = par[1];
341 double sigma = par[2];
342 double bMean = par[3];
343 double bDelta = par[4];
344 double tauL = par[5];
345 double tauR = par[6];
347 double bL = bMean - bDelta;
348 double bR = bMean + bDelta;
351 double r = (x - mean) / sigma;
352 if (bL <= r && r <= bR) {
353 return exp(-1. / 2 * pow(r, 2));
355 double bp = exp(-1. / 2 * pow(bL, 2));
356 double xb = mean + bL * sigma;
357 return exp((x - xb) / tauL) * bp;
359 double bp = exp(-1. / 2 * pow(bR, 2));
360 double xb = mean + bR * sigma;
361 return exp(-(x - xb) / tauR) * bp;
383 TGraph* gr =
new TGraph;
384 TGraph* grE =
new TGraph;
385 TGraph* grRat =
new TGraph;
386 TGraph* grR =
new TGraph;
395 for (
double t = eps; t < 5000; t += 1.00) {
396 double Core = gausExpConv(mean, sigma, bMean, bDelta, tau, tau, sigmaK, x + t - m0);
397 double K = (+t) >= eps ? pow(+ t, -slope) : 0;
399 double fun = Core * K;
400 gr->SetPoint(gr->GetN(), t, fun);
402 double s = exp(-t / tau);
404 double funE = exp(-abs(x - m0 + t) / tau) * 1 / t;
405 grE->SetPoint(grE->GetN(), t, funE);
407 grRat->SetPoint(grE->GetN(), t, fun / funE);
408 grR->SetPoint(grR->GetN(), s, fun / funE);
413 InvariantMassMuMuIntegrator integrator;
415 TGraph* grM =
new TGraph;
419 for (
double xNow = 10000; xNow <= 11000; xNow += 0.1) {
421 integrator.init(mean,
436 grM->SetPoint(grM->GetN(), xNow, integrator.integralKronrod(2000));
452 double mainFunction(
double xx,
Pars par)
454 InvariantMassMuMuIntegrator fun;
456 fun.init(par.at(
"mean"),
470 return fun.integralKronrod(2000);
476 vector<double> readEvents(
const vector<Event>& evts,
double pidCut,
double a,
double b)
479 vector<double> vMass;
480 for (
const auto& ev : evts) {
483 if (ev.mu0.pid < pidCut || ev.mu1.pid < pidCut) {
487 double m = 1e3 * ev.m;
497 static void plotMuMuFitBase(TH1D* hData, TGraph* gr, TH1D* hPull,
Pars pars, Eigen::MatrixXd mat,
int time)
499 bool isBatch = gROOT->IsBatch();
500 gROOT->SetBatch(kTRUE);
502 gStyle->SetOptStat(0);
504 TCanvas* can =
new TCanvas(Form(
"canMuMu_%d", time),
"");
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);
509 pad1->SetBottomMargin(0.05);
510 pad2->SetTopMargin(0.05);
511 pad2->SetBottomMargin(0.35);
522 hData->SetMarkerStyle(kFullCircle);
524 gr->SetLineColor(kRed);
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);
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);
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));
547 int nDig = log10(p.second / err) + 2;
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");
557 leg->SetTextSize(0.05);
558 leg->SetBorderSize(0);
559 leg->SetFillStyle(0);
564 for (
int j = 1; j <= hPull->GetNbinsX(); ++j)
565 chi2 += pow(hPull->GetBinContent(j), 2);
566 int ndf = hPull->GetNbinsX() - nPars - 1;
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");
573 leg2->SetTextSize(0.05);
574 leg2->SetBorderSize(0);
575 leg2->SetFillStyle(0);
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);
593 hPull->SetMarkerStyle(kFullCircle);
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);
605 hPull->GetYaxis()->SetTitleSize(0.13);
606 hPull->GetYaxis()->SetLabelSize(0.13);
607 hPull->GetYaxis()->SetTitleOffset(0.2);
608 hPull->GetYaxis()->CenterTitle();
611 hPull->GetYaxis()->SetNdivisions(404);
613 hPull->GetYaxis()->SetRangeUser(-5, 5);
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");
622 filesystem::create_directories(
"plotsMuMu");
624 can->SaveAs(Form(
"plotsMuMu/mumu_%d.pdf", time));
638 gROOT->SetBatch(isBatch);
642 static void plotMuMuFit(
const vector<double>& data,
const Pars& pars, Eigen::MatrixXd mat,
double mMin,
double mMax,
int time)
644 const int nBins = 100;
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);
661 TGraph* gr =
new TGraph();
662 const double step = (mMax - mMin) / (nBins);
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);
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);
677 double I = step / 6 * (lV + 4 * cV + rV);
678 hFit->SetBinContent(i + 1, I);
682 double F = hData->Integral() / hFit->Integral();
687 for (
int i = 0; i < gr->GetN(); ++i)
688 gr->SetPointY(i, gr->GetPointY(i) * F * step);
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);
698 plotMuMuFitBase(hData, gr, hPull, pars, mat, time);
711 pair<Pars, MatrixXd> getInvMassPars(
const vector<Event>& evts,
Pars pars,
double mMin,
double mMax,
int bootStrap = 0)
713 bool is4S = evts[0].is4S;
715 vector<double> dataNow = readEvents(evts, 0.9, mMin, mMax);
720 TRandom3* rand =
nullptr;
721 if (bootStrap) rand =
new TRandom3(bootStrap);
722 for (
auto d : dataNow) {
723 int nP = bootStrap ? rand->Poisson(1) : 1;
724 for (
int i = 0; i < nP; ++i)
732 fitter.setDataAndFunction(mainFunction, data);
733 fitter.init(256 + 1, mMin, mMax);
738 {
"bDelta" , 1.60307 },
740 {
"frac" , 0.998051 },
743 {
"sigma" , 37.0859 },
744 {
"slope" , 0.876812 },
753 {
"m0" , mMax - 230 },
761 pars = is4S ? pars0_4S : pars0_Off;
767 {
"mean", make_pair(0, 0)},
768 {
"sigma", make_pair(10, 120)},
769 {
"bMean", make_pair(0, 0)},
770 {
"bDelta", make_pair(0.01, 10.)},
771 {
"tau", make_pair(20, 250)},
772 {
"frac", make_pair(0.00, 1.0)},
774 {
"m0", make_pair(10450, 10950)},
775 {
"slope", make_pair(0.3, 0.999)},
776 {
"C", make_pair(0, 0)}
780 return fitter.fitData(pars, limits,
true);
788 tuple<vector<VectorXd>, vector<MatrixXd>, MatrixXd> runMuMuInvariantMassAnalysis(vector<Event> evts,
789 const vector<double>& splitPoints)
791 int n = splitPoints.size() + 1;
793 vector<VectorXd> invMassVec(n);
794 vector<MatrixXd> invMassVecUnc(n);
795 MatrixXd invMassVecSpred;
797 std::ofstream mumuTextOut(
"mumuEcalib.txt", ios::app);
798 static int iPrint = 0;
800 mumuTextOut <<
"n id t1 t2 exp1 run1 exp2 run2 Ecms EcmsUnc state" << endl;
803 for (
int iDiv = 0; iDiv < n; ++iDiv) {
806 invMassVec[iDiv].resize(1);
807 invMassVecUnc[iDiv].resize(1, 1);
808 invMassVecSpred.resize(1, 1);
810 vector<Event> evtsNow;
811 for (
auto ev : evts) {
812 double tMin = (iDiv != 0) ? splitPoints[iDiv - 1] : -1e40;
813 double tMax = (iDiv != n - 1) ? splitPoints[iDiv] : 1e40;
814 if (tMin <= ev.t && ev.t < tMax)
815 evtsNow.push_back(ev);
822 double mMin = 10.2e3, mMax = 10.8e3;
825 if (!evtsNow[0].is4S) {
826 vector<double> dataNow;
827 for (
const auto& ev : evtsNow)
828 dataNow.push_back(ev.m);
829 double mMedian = 1e3 * Belle2::BoostVectorCalib::median(dataNow.data(), dataNow.size());
830 double est = mMedian + 30;
842 vector<double> vals, errs;
843 for (
int rep = 0; rep < 200; ++rep) {
844 double errEst = 50. / sqrt(evtsNow.size());
851 tie(resP, resM) = getInvMassPars(evtsNow, inDummy, mMin, mMax, rep);
853 int ind = distance(resP.begin(), resP.find(
"m0"));
854 double mass = resP.at(
"m0");
855 double err = sqrt(resM(ind, ind));
859 if (!(errEst < err && err < 4 * errEst))
862 vals.push_back(mass);
867 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
874 tie(resP0, resM0) = getInvMassPars(evtsNow, resP, mMin, mMax, 0);
876 int ind0 = distance(resP0.begin(), resP0.find(
"m0"));
877 double mass0 = resP0.at(
"m0");
878 double err0 = sqrt(resM0(ind0, ind0));
881 if (errEst < err0 && err0 < 4 * errEst) {
884 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP0, resM0, mMin, mMax,
int(round(evtsNow[0].t)));
890 if (vals.size() >= nRep) {
891 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
897 if (vals.size() != 1 && vals.size() != nRep)
898 B2FATAL(
"Inconsistency of number of results with number of replicas");
900 double meanMass = accumulate(vals.begin(), vals.end(), 0.) / vals.size();
901 double meanMassUnc = accumulate(errs.begin(), errs.end(), 0.) / errs.size();
905 sum2 += pow(v - meanMass, 2);
906 double errBootStrap = vals.size() > 1 ? sqrt(sum2 / (vals.size() - 1)) : 0;
908 mumuTextOut << n <<
" " << iDiv <<
" " << setprecision(14) << evtsNow.front().t <<
" " << evtsNow.back().t <<
" " <<
909 evtsNow.front().exp <<
" " << evtsNow.front().run <<
" " << evtsNow.back().exp <<
" " << evtsNow.back().run <<
" " << meanMass
911 " " << meanMassUnc <<
" " << errBootStrap << endl;
914 invMassVec[iDiv](0) = meanMass / 1e3;
915 invMassVecUnc[iDiv](0, 0) = meanMassUnc / 1e3;
916 invMassVecSpred(0, 0) = 0;
921 return make_tuple(invMassVec, invMassVecUnc, invMassVecSpred);
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