29#include <Math/Functor.h>
30#include <Math/SpecFuncMathCore.h>
31#include <Math/DistFunc.h>
35#include <framework/particledb/EvtGenDatabasePDG.h>
36#include <framework/utilities/MathHelpers.h>
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>
47#include <InvariantMassMuMuStandAlone.h>
48#include <InvariantMassMuMuIntegrator.h>
51#include <ChebFitter.h>
58namespace Belle2::InvariantMassMuMuCalib {
64 std::vector<Event> getEvents(TTree* tr,
bool is4S)
67 std::vector<Event> events;
68 events.reserve(tr->GetEntries());
72 tr->SetBranchAddress(
"run", &evt.run);
73 tr->SetBranchAddress(
"exp", &evt.exp);
74 tr->SetBranchAddress(
"event", &evt.evtNo);
79 tr->SetBranchAddress(
"mu0_p", &p0);
80 tr->SetBranchAddress(
"mu1_p", &p1);
82 tr->SetBranchAddress(
"mu0_pid", &evt.mu0.pid);
83 tr->SetBranchAddress(
"mu1_pid", &evt.mu1.pid);
86 tr->SetBranchAddress(
"time", &evt.t);
90 for (
int i = 0; i < tr->GetEntries(); ++i) {
96 evt.m =
sqrt(
square(hypot(evt.mu0.p.Mag(), mMu) + hypot(evt.mu1.p.Mag(), mMu)) - (evt.mu0.p + evt.mu1.p).Mag2());
101 events.push_back(evt);
105 sort(events.begin(), events.end(), [](
Event e1,
Event e2) {return e1.t < e2.t;});
116 double integrate(std::function<
double(
double)> f,
double a,
double b)
118 static const std::vector<double> nodes = {
129 static const std::vector<double> wgts = {
140 if (b < a) B2FATAL(
"Wrongly defined integration interval");
142 double m = (b + a) / 2;
143 double d = (b - a) / 2;
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];
153 sum += f(m) * wgts.back();
170 double gausInt(
double a,
double b,
double c,
double d)
172 double res =
sqrt(M_PI) / (2 *
sqrt(c)) * (TMath::Erf((b * c - d) /
sqrt(c)) - TMath::Erf((a * c - d) /
sqrt(c)));
179 double convGausGaus(
double sK,
double s,
double a,
double b,
double m,
double x)
186 double c = 1. / 2 * (1. / s / s + 1. / sK / sK);
187 double d = 1. / 2 * x / sK / sK;
189 double Const = 1. / (2 * M_PI) * 1. / (s * sK) * exp(-1. / 2 * x * x / (s * s + sK * sK));
191 double res = Const * gausInt(a, b, c, d);
192 assert(std::isfinite(res));
202 double convExpGaus(
double sK,
double tau,
double a,
double x)
206 double A = 1. /
sqrt(2) * (-x / sK + sK / tau);
207 double B = -x / tau + 1. / 2 *
square(sK / tau);
209 if (B > 700 || A > 20) {
210 res = 1. / (2 * tau) * 1. /
sqrt(M_PI) * exp(-A * A + B) * (1 / A - 1 / 2. /
cube(A) + 3. / 4 /
pow5(A));
212 res = 1. / (2 * tau) * TMath::Erfc(A) * exp(B);
214 assert(std::isfinite(res));
220 double gausExpConv(
double mean,
double sigma,
double bMean,
double bDelta,
double tauL,
double tauR,
double sigmaK,
double x)
222 double bL = bMean - bDelta;
223 double bR = bMean + bDelta;
225 double xL = bL * sigma + mean;
226 double xR = bR * sigma + mean;
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);
232 return (iGaus + iLeft + iRight);
236 double gausExpConvRoot(
const double* par)
239 double mean = par[1];
240 double sigma = par[2];
241 double bMean = par[3];
242 double bDelta = par[4];
243 double tauL = par[5];
244 double tauR = par[6];
245 double sigmaK = par[7];
246 double sigmaA = par[8];
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;
257 double gausExpPowConvRoot(
const double* par)
260 double mean = par[1];
261 double sigma = par[2];
262 double bMean = par[3];
263 double bDelta = par[4];
264 double tauL = par[5];
265 double tauR = par[6];
266 double sigmaK = par[7];
267 double sigmaA = par[8];
272 double eCMS = par[10];
273 double slope = par[11];
277 int N = 800 * 1. / step;
282 for (
int i = 0; i < N; ++i) {
284 double t = eCMS - i * step;
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;
290 double C = (i == 0 || i == N - 1) ? 0.5 : 1;
294 Kernel =
K * pow(step, -slope);
296 Kernel = pow(eCMS - t, -slope);
299 sum += Kernel * Core * step * C;
322 TGraph* gr =
new TGraph;
323 for (
double x = -300; x < 300; x += 1) {
325 double v = gausExpConv(mean, sigma, bMean, bDelta, tauL, tauR, sigmaK, x);
327 gr->SetPoint(gr->GetN(), x, v);
335 double gausExp(
const double* par)
338 double mean = par[1];
339 double sigma = par[2];
340 double bMean = par[3];
341 double bDelta = par[4];
342 double tauL = par[5];
343 double tauR = par[6];
345 double bL = bMean - bDelta;
346 double bR = bMean + bDelta;
349 double r = (x - mean) / sigma;
350 if (bL <= r && r <= bR) {
351 return exp(-1. / 2 * (r * r));
353 double bp = exp(-1. / 2 * (bL * bL));
354 double xb = mean + bL * sigma;
355 return exp((x - xb) / tauL) * bp;
357 double bp = exp(-1. / 2 * (bR * bR));
358 double xb = mean + bR * sigma;
359 return exp(-(x - xb) / tauR) * bp;
381 TGraph* gr =
new TGraph;
382 TGraph* grE =
new TGraph;
383 TGraph* grRat =
new TGraph;
384 TGraph* grR =
new TGraph;
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;
397 double fun = Core *
K;
398 gr->SetPoint(gr->GetN(), t, fun);
400 double s = exp(-t / tau);
402 double funE = exp(-abs(x - m0 + t) / tau) * 1 / t;
403 grE->SetPoint(grE->GetN(), t, funE);
405 grRat->SetPoint(grE->GetN(), t, fun / funE);
406 grR->SetPoint(grR->GetN(), s, fun / funE);
413 TGraph* grM =
new TGraph;
417 for (
double xNow = 10000; xNow <= 11000; xNow += 0.1) {
419 integrator.init(mean,
434 grM->SetPoint(grM->GetN(), xNow, integrator.integralKronrod(2000));
450 double mainFunction(
double xx,
Pars par)
454 fun.
init(par.at(
"mean"),
468 return fun.integralKronrod(2000);
474 std::vector<double> readEvents(
const std::vector<Event>& evts,
double pidCut,
double a,
double b)
477 std::vector<double> vMass;
478 for (
const auto& ev : evts) {
481 if (ev.mu0.pid < pidCut || ev.mu1.pid < pidCut) {
485 double m = 1e3 * ev.m;
495 static void plotMuMuFitBase(TH1D* hData, TGraph* gr, TH1D* hPull,
Pars pars, Eigen::MatrixXd mat,
int time)
497 bool isBatch = gROOT->IsBatch();
498 gROOT->SetBatch(kTRUE);
500 gStyle->SetOptStat(0);
502 TCanvas* can =
new TCanvas(Form(
"canMuMu_%d", time),
"");
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);
507 pad1->SetBottomMargin(0.05);
508 pad2->SetTopMargin(0.05);
509 pad2->SetBottomMargin(0.35);
520 hData->SetMarkerStyle(kFullCircle);
522 gr->SetLineColor(kRed);
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);
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);
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));
545 int nDig = log10(p.second / err) + 2;
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");
555 leg->SetTextSize(0.05);
556 leg->SetBorderSize(0);
557 leg->SetFillStyle(0);
562 for (
int j = 1; j <= hPull->GetNbinsX(); ++j)
563 chi2 +=
square(hPull->GetBinContent(j));
564 int ndf = hPull->GetNbinsX() - nPars - 1;
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");
571 leg2->SetTextSize(0.05);
572 leg2->SetBorderSize(0);
573 leg2->SetFillStyle(0);
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);
591 hPull->SetMarkerStyle(kFullCircle);
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);
603 hPull->GetYaxis()->SetTitleSize(0.13);
604 hPull->GetYaxis()->SetLabelSize(0.13);
605 hPull->GetYaxis()->SetTitleOffset(0.2);
606 hPull->GetYaxis()->CenterTitle();
609 hPull->GetYaxis()->SetNdivisions(404);
611 hPull->GetYaxis()->SetRangeUser(-5, 5);
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");
620 std::filesystem::create_directories(
"plotsMuMu");
622 can->SaveAs(Form(
"plotsMuMu/mumu_%d.pdf", time));
636 gROOT->SetBatch(isBatch);
640 static void plotMuMuFit(
const std::vector<double>& data,
const Pars& pars, Eigen::MatrixXd mat,
double mMin,
double mMax,
int time)
642 const int nBins = 100;
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);
659 TGraph* gr =
new TGraph();
660 const double step = (mMax - mMin) / (nBins);
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);
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);
675 double I = step / 6 * (lV + 4 * cV + rV);
676 hFit->SetBinContent(i + 1, I);
680 double F = hData->Integral() / hFit->Integral();
685 for (
int i = 0; i < gr->GetN(); ++i)
686 gr->SetPointY(i, gr->GetPointY(i) * F * step);
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);
696 plotMuMuFitBase(hData, gr, hPull, pars, mat, time);
709 std::pair<Pars, MatrixXd> getInvMassPars(
const std::vector<Event>& evts,
Pars pars,
double mMin,
double mMax,
int bootStrap = 0)
711 bool is4S = evts[0].is4S;
713 std::vector<double> dataNow = readEvents(evts, 0.9, mMin, mMax);
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)
730 fitter.setDataAndFunction(mainFunction, data);
731 fitter.init(256 + 1, mMin, mMax);
736 {
"bDelta", 1.60307 },
742 {
"slope", 0.876812 },
759 pars = is4S ? pars0_4S : pars0_Off;
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)},
772 {
"m0", std::make_pair(10450, 10950)},
773 {
"slope", std::make_pair(0.3, 0.999)},
774 {
"C", std::make_pair(0, 0)}
778 return fitter.fitData(pars, limits,
true);
786 std::tuple<std::vector<VectorXd>, std::vector<MatrixXd>, MatrixXd> runMuMuInvariantMassAnalysis(std::vector<Event> evts,
787 const std::vector<double>& splitPoints)
789 int n = splitPoints.size() + 1;
791 std::vector<VectorXd> invMassVec(n);
792 std::vector<MatrixXd> invMassVecUnc(n);
793 MatrixXd invMassVecSpred;
795 std::ofstream mumuTextOut(
"mumuEcalib.txt", std::ios::app);
796 static int iPrint = 0;
798 mumuTextOut <<
"n id t1 t2 exp1 run1 exp2 run2 Ecms EcmsUnc state" << std::endl;
801 for (
int iDiv = 0; iDiv < n; ++iDiv) {
804 invMassVec[iDiv].resize(1);
805 invMassVecUnc[iDiv].resize(1, 1);
806 invMassVecSpred.resize(1, 1);
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);
820 double mMin = 10.2e3, mMax = 10.8e3;
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;
840 std::vector<double> vals, errs;
841 for (
int rep = 0; rep < 200; ++rep) {
842 double errEst = 50. /
sqrt(evtsNow.size());
849 tie(resP, resM) = getInvMassPars(evtsNow, inDummy, mMin, mMax, rep);
851 int ind = distance(resP.begin(), resP.find(
"m0"));
852 double mass = resP.at(
"m0");
853 double err =
sqrt(resM(ind, ind));
857 if (!(errEst < err && err < 4 * errEst))
860 vals.push_back(mass);
865 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
872 tie(resP0, resM0) = getInvMassPars(evtsNow, resP, mMin, mMax, 0);
874 int ind0 = distance(resP0.begin(), resP0.find(
"m0"));
875 double mass0 = resP0.at(
"m0");
876 double err0 =
sqrt(resM0(ind0, ind0));
879 if (errEst < err0 && err0 < 4 * errEst) {
882 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP0, resM0, mMin, mMax,
int(round(evtsNow[0].t)));
888 if (vals.size() >= nRep) {
889 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
895 if (vals.size() != 1 && vals.size() != nRep)
896 B2FATAL(
"Inconsistency of number of results with number of replicas");
898 double meanMass = accumulate(vals.begin(), vals.end(), 0.) / vals.size();
899 double meanMassUnc = accumulate(errs.begin(), errs.end(), 0.) / errs.size();
903 sum2 +=
square(v - meanMass);
904 double errBootStrap = vals.size() > 1 ?
sqrt(sum2 / (vals.size() - 1)) : 0;
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
909 " " << meanMassUnc <<
" " << errBootStrap << std::endl;
912 invMassVec[iDiv](0) = meanMass / 1e3;
913 invMassVecUnc[iDiv](0, 0) = meanMassUnc / 1e3;
914 invMassVecSpred(0, 0) = 0;
919 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.
constexpr T cube(const T &x)
Calculate the cube of the input.
constexpr T square(const T &x)
Calculate the square of the input.
constexpr T pow5(const T &x)
Calculate the fifth power of the input.
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.