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(), [](
const Event & e1,
const 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];
343 double bL = bMean - bDelta;
344 double bR = bMean + bDelta;
347 double r = (x - mean) / sigma;
348 if (bL <= r && r <= bR) {
349 return exp(-1. / 2 * (r * r));
351 double tauL = par[5];
352 double bp = exp(-1. / 2 * (bL * bL));
353 double xb = mean + bL * sigma;
354 return exp((x - xb) / tauL) * bp;
356 double tauR = par[6];
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));
452 double mainFunction(
double xx,
Pars par)
456 fun.
init(par.at(
"mean"),
470 return fun.integralKronrod(2000);
476 std::vector<double> readEvents(
const std::vector<Event>& evts,
double pidCut,
double a,
double b)
479 std::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,
const 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 +=
square(hPull->GetBinContent(j));
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 std::filesystem::create_directories(
"plotsMuMu");
624 can->SaveAs(Form(
"plotsMuMu/mumu_%d.pdf", time));
638 gROOT->SetBatch(isBatch);
642 static void plotMuMuFit(
const std::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 std::pair<Pars, MatrixXd> getInvMassPars(
const std::vector<Event>& evts,
Pars pars,
double mMin,
double mMax,
int bootStrap = 0)
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 bool is4S = evts[0].is4S;
760 pars = is4S ? pars0_4S : pars0_Off;
766 {
"mean", std::make_pair(0, 0)},
767 {
"sigma", std::make_pair(10, 120)},
768 {
"bMean", std::make_pair(0, 0)},
769 {
"bDelta", std::make_pair(0.01, 10.)},
770 {
"tau", std::make_pair(20, 250)},
771 {
"frac", std::make_pair(0.00, 1.0)},
773 {
"m0", std::make_pair(10450, 10950)},
774 {
"slope", std::make_pair(0.3, 0.999)},
775 {
"C", std::make_pair(0, 0)}
779 return fitter.fitData(pars, limits,
true);
787 std::tuple<std::vector<VectorXd>, std::vector<MatrixXd>, MatrixXd> runMuMuInvariantMassAnalysis(
const std::vector<Event>& evts,
788 const std::vector<double>& splitPoints)
790 int n = splitPoints.size() + 1;
792 std::vector<VectorXd> invMassVec(n);
793 std::vector<MatrixXd> invMassVecUnc(n);
794 MatrixXd invMassVecSpred;
796 std::ofstream mumuTextOut(
"mumuEcalib.txt", std::ios::app);
797 static int iPrint = 0;
799 mumuTextOut <<
"n id t1 t2 exp1 run1 exp2 run2 Ecms EcmsUnc state" << std::endl;
802 for (
int iDiv = 0; iDiv < n; ++iDiv) {
805 invMassVec[iDiv].resize(1);
806 invMassVecUnc[iDiv].resize(1, 1);
807 invMassVecSpred.resize(1, 1);
809 std::vector<Event> evtsNow;
810 for (
const auto& ev : evts) {
811 double tMin = (iDiv != 0) ? splitPoints[iDiv - 1] : -1e40;
812 double tMax = (iDiv != n - 1) ? splitPoints[iDiv] : 1e40;
813 if (tMin <= ev.t && ev.t < tMax)
814 evtsNow.push_back(ev);
821 double mMin = 10.2e3, mMax = 10.8e3;
824 if (!evtsNow[0].is4S) {
825 std::vector<double> dataNow;
826 for (
const auto& ev : evtsNow)
827 dataNow.push_back(ev.m);
828 double mMedian = 1e3 * Belle2::BoostVectorCalib::median(dataNow.data(), dataNow.size());
829 double est = mMedian + 30;
841 std::vector<double> vals, errs;
842 for (
int rep = 0; rep < 200; ++rep) {
843 double errEst = 50. /
sqrt(evtsNow.size());
850 tie(resP, resM) = getInvMassPars(evtsNow, inDummy, mMin, mMax, rep);
852 int ind = distance(resP.begin(), resP.find(
"m0"));
853 double mass = resP.at(
"m0");
854 double err =
sqrt(resM(ind, ind));
858 if (!(errEst < err && err < 4 * errEst))
861 vals.push_back(mass);
866 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
873 tie(resP0, resM0) = getInvMassPars(evtsNow, resP, mMin, mMax, 0);
875 int ind0 = distance(resP0.begin(), resP0.find(
"m0"));
876 double mass0 = resP0.at(
"m0");
877 double err0 =
sqrt(resM0(ind0, ind0));
880 if (errEst < err0 && err0 < 4 * errEst) {
883 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP0, resM0, mMin, mMax,
int(round(evtsNow[0].t)));
889 if (vals.size() >= nRep) {
890 plotMuMuFit(readEvents(evtsNow, 0.9, mMin, mMax), resP, resM, mMin, mMax,
int(round(evtsNow[0].t)));
896 if (vals.size() != 1 && vals.size() != nRep)
897 B2FATAL(
"Inconsistency of number of results with number of replicas");
899 double meanMass = accumulate(vals.begin(), vals.end(), 0.) / vals.size();
900 double meanMassUnc = accumulate(errs.begin(), errs.end(), 0.) / errs.size();
904 sum2 +=
square(v - meanMass);
905 double errBootStrap = vals.size() > 1 ?
sqrt(sum2 / (vals.size() - 1)) : 0;
907 mumuTextOut << n <<
" " << iDiv <<
" " << std::setprecision(14) << evtsNow.front().t <<
" " << evtsNow.back().t <<
" " <<
908 evtsNow.front().exp <<
" " << evtsNow.front().run <<
" " << evtsNow.back().exp <<
" " << evtsNow.back().run <<
" " << meanMass
910 " " << meanMassUnc <<
" " << errBootStrap << std::endl;
913 invMassVec[iDiv](0) = meanMass / 1e3;
914 invMassVecUnc[iDiv](0, 0) = meanMassUnc / 1e3;
915 invMassVecSpred(0, 0) = 0;
920 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.