File indexing completed on 2026-07-16 08:11:28
0001 #include <cmath>
0002 #include <iostream>
0003 #include <sstream>
0004 #include <string>
0005 #ifndef __CINT__
0006 #include <RooGlobalFunc.h>
0007 #endif
0008 #include <RooBifurGauss.h>
0009 #include <RooDataHist.h>
0010 #include <RooDataSet.h>
0011 #include <RooGaussian.h>
0012 #include <RooRealVar.h>
0013
0014 #include <RooAbsDataHelper.h>
0015 #include <RooAddPdf.h>
0016 #include <RooExponential.h>
0017 #include <RooHist.h>
0018 #include <RooPlot.h>
0019 #include <RooStats/SPlot.h>
0020
0021 #include <TBranch.h>
0022 #include <TCanvas.h>
0023 #include <TChain.h>
0024 #include <TCut.h>
0025 #include <TFile.h>
0026 #include <TH1F.h>
0027 #include <TMath.h>
0028 #include <TPad.h>
0029 #include <TTree.h>
0030
0031 using namespace RooFit;
0032 using namespace std;
0033
0034 void RDataframeToRoofit_SOnly(const bool doSnapshot,
0035 std::string snapshotName,
0036 std::string inputfilename,
0037 TCut selections,
0038 fitparam_config &fit_conf,
0039 const std::string plotdir = "./figure"
0040 )
0041 {
0042 RooMsgService::instance().setGlobalKillBelow(RooFit::ERROR);
0043
0044 system(Form("mkdir -p %s", plotdir.c_str()));
0045
0046 std::string dirName = snapshotName;
0047 std::string::size_type pos = dirName.find_last_of("/");
0048 if (pos != std::string::npos)
0049 {
0050 dirName = dirName.substr(0, pos);
0051 system(Form("mkdir -p %s", dirName.c_str()));
0052 }
0053
0054 auto start = std::chrono::high_resolution_clock::now();
0055
0056 ROOT::EnableImplicitMT();
0057 ROOT::RDataFrame df("DecayTree", inputfilename.c_str());
0058
0059 auto filtered_df = df.Filter(selections.GetTitle());
0060 if (doSnapshot)
0061 {
0062 filtered_df.Snapshot("DecayTree", Form("%s", snapshotName.c_str()));
0063 }
0064
0065
0066 int nEntries = filtered_df.Count().GetValue();
0067 std::cout << "Number of entries in the dataframe: " << nEntries << std::endl;
0068
0069 FitParams::branch = fit_conf.branch;
0070 std::string xAxisTitle = fit_conf.decaystring + " candidate mass [GeV]";
0071
0072 FitParams::minMass = fit_conf.minMass;
0073 FitParams::maxMass = fit_conf.maxMass;
0074 FitParams::mass.SetName(FitParams::branch.c_str());
0075 FitParams::mass.SetTitle("mass");
0076 FitParams::mass.setRange(FitParams::minMass, FitParams::maxMass);
0077
0078 auto dataset_result = filtered_df.Book<float>(RooDataSetHelper("dataset", "dataset", RooArgSet(FitParams::mass)), {FitParams::branch.c_str()});
0079 RooDataSet *dataset = dataset_result.GetPtr();
0080
0081 if (fit_conf.sigmodel == "Gaussian")
0082 {
0083 FitParams::mean.setVal(fit_conf.mean);
0084 FitParams::mean.setRange(fit_conf.mean_low, fit_conf.mean_high);
0085 FitParams::sigma.setVal(fit_conf.sigma);
0086 FitParams::sigma.setRange(fit_conf.sigma_low, fit_conf.sigma_high);
0087 }
0088 else if (fit_conf.sigmodel == "Voigtian")
0089 {
0090 FitParams::mean.setVal(fit_conf.mean);
0091 FitParams::mean.setRange(fit_conf.mean_low, fit_conf.mean_high);
0092 FitParams::sigma.setVal(fit_conf.sigma);
0093 FitParams::sigma.setRange(fit_conf.sigma_low, fit_conf.sigma_high);
0094 FitParams::width.setVal(fit_conf.width);
0095 FitParams::width.setRange(fit_conf.width_low, fit_conf.width_high);
0096 }
0097 else if (fit_conf.sigmodel == "CrystalBall")
0098 {
0099 FitParams::mean.setVal(fit_conf.mean);
0100 FitParams::mean.setRange(fit_conf.mean_low, fit_conf.mean_high);
0101 FitParams::sigma.setVal(fit_conf.sigma);
0102 FitParams::sigma.setRange(fit_conf.sigma_low, fit_conf.sigma_high);
0103 FitParams::alpha1.setVal(fit_conf.alpha1);
0104 FitParams::alpha1.setRange(fit_conf.alpha1_low, fit_conf.alpha1_high);
0105 FitParams::n1.setVal(fit_conf.n1);
0106 FitParams::n1.setRange(fit_conf.n1_low, fit_conf.n1_high);
0107 }
0108 else if (fit_conf.sigmodel == "DoubleCrystalBall")
0109 {
0110 FitParams::mean.setVal(fit_conf.mean);
0111 FitParams::mean.setRange(fit_conf.mean_low, fit_conf.mean_high);
0112 FitParams::sigma.setVal(fit_conf.sigma);
0113 FitParams::sigma.setRange(fit_conf.sigma_low, fit_conf.sigma_high);
0114 FitParams::alpha1.setVal(fit_conf.alpha1);
0115 FitParams::alpha1.setRange(fit_conf.alpha1_low, fit_conf.alpha1_high);
0116 FitParams::n1.setVal(fit_conf.n1);
0117 FitParams::n1.setRange(fit_conf.n1_low, fit_conf.n1_high);
0118 FitParams::alpha2.setVal(fit_conf.alpha2);
0119 FitParams::alpha2.setRange(fit_conf.alpha2_low, fit_conf.alpha2_high);
0120 FitParams::n2.setVal(fit_conf.n2);
0121 FitParams::n2.setRange(fit_conf.n2_low, fit_conf.n2_high);
0122 FitParams::frac.setVal(fit_conf.frac);
0123 FitParams::frac.setRange(0, 1);
0124 }
0125 else
0126 {
0127 std::cerr << "Unknown signal model type: " << fit_conf.sigmodel << ", returning nullptr. Please define the model." << std::endl;
0128 }
0129
0130 RooAbsPdf *signal = signalModel(fit_conf.sigmodel, FitParams::mass);
0131 FitParams::nSig.setVal(float(nEntries));
0132 FitParams::nSig.setRange(float(nEntries)*0.95, float(nEntries)*1.05);
0133 RooAddPdf *model = new RooAddPdf("model", "model", RooArgList(*signal), RooArgList(FitParams::nSig));
0134
0135 RooFitResult *m_fitres(0);
0136 m_fitres = model->fitTo(*dataset, Save(kTRUE), Extended(kTRUE), PrintLevel(-1));
0137 m_fitres->Print();
0138
0139 TFile *fitresfile = new TFile(Form("%s/fitresults_signal.root", plotdir.c_str()), "RECREATE");
0140 fitresfile->cd();
0141 m_fitres->Write("fitres");
0142 fitresfile->Close();
0143
0144 std::cout << "Making plots..." << std::endl;
0145
0146
0147 std::string plotTitle = "";
0148 RooPlot *frame = FitParams::mass.frame(Title(plotTitle.c_str()));
0149 RooBinning bins(FitParams::minMass, FitParams::maxMass);
0150 bins.addUniform(fit_conf.nBins, FitParams::minMass, FitParams::maxMass);
0151 dataset->plotOn(frame, DrawOption("PE1"), Binning(bins), XErrorSize(0), DataError(RooAbsData::SumW2), RooFit::Name("data"));
0152 signal->plotOn(frame, LineColor(TColor::GetColor("#FF7F0E")), RooFit::Name("signalpdf"));
0153
0154 RooHist *pull = frame->pullHist();
0155 RooPlot *frame2 = FitParams::mass.frame(Title(""));
0156 frame2->addPlotable(pull, "PE1");
0157
0158 std::cout << "Creating canvas..." << std::endl;
0159
0160 TCanvas *c = new TCanvas("massFitCanvas", "massFitCanvas", 800, 800);
0161 TPad mainPad("mainPad", "mainPad", 0., 0.3, 1., 1.);
0162 mainPad.SetTopMargin(TopMargin);
0163 mainPad.SetBottomMargin(0);
0164 mainPad.Draw();
0165 TPad pullPad("pullPad", "pullPad", 0., 0.0, 1., 0.3);
0166 pullPad.SetBottomMargin(0.5);
0167 pullPad.SetTopMargin(0);
0168 pullPad.Draw();
0169 mainPad.cd();
0170 frame->SetMarkerStyle(kCircle);
0171 frame->SetMarkerSize(0.02);
0172 frame->SetLineWidth(1);
0173 frame->GetXaxis()->SetTitleSize(0);
0174 frame->GetXaxis()->SetLabelSize(0);
0175 frame->GetYaxis()->SetTitleSize(AxisTitleSize * textscale_pad1);
0176 frame->GetYaxis()->SetLabelSize(AxisLabelSize * textscale_pad1);
0177 frame->GetYaxis()->SetTitleOffset(1.2);
0178 frame->GetYaxis()->SetTitleFont(42);
0179 frame->GetYaxis()->SetLabelFont(42);
0180 TH1 *hdataset = dataset->createHistogram("hdataset", FitParams::mass, Binning(fit_conf.nBins, FitParams::minMass, FitParams::maxMass));
0181
0182 frame->GetYaxis()->SetRangeUser(0.1, hdataset->GetMaximum() * 1.8);
0183 float binWidth = 1000. * (FitParams::maxMass - FitParams::minMass) / fit_conf.nBins;
0184 string yAxisTitle = "Candidates / (" + to_string_with_precision(binWidth, 1) + " MeV)";
0185 frame->GetYaxis()->SetTitle(yAxisTitle.c_str());
0186 frame->Draw();
0187 frame->Print();
0188 c->RedrawAxis();
0189
0190 TLatex *datestamp = new TLatex();
0191 datestamp->SetTextSize(0.06);
0192 datestamp->SetTextAlign(kHAlignRight + kVAlignBottom);
0193 datestamp->SetNDC();
0194 datestamp->DrawLatex(1 - mainPad.GetRightMargin(),
0195 1 - mainPad.GetTopMargin() + 0.01,
0196 getTime().c_str()
0197 );
0198
0199 TLegend *sphnxleg = new TLegend(mainPad.GetLeftMargin() + 0.03,
0200 1 - mainPad.GetTopMargin() - 0.2,
0201 mainPad.GetLeftMargin() + 0.2,
0202 1 - mainPad.GetTopMargin() - 0.05
0203 );
0204 sphnxleg->SetTextAlign(kHAlignLeft + kVAlignCenter);
0205 sphnxleg->SetTextSize(0.06);
0206 sphnxleg->SetFillStyle(0);
0207 sphnxleg->AddEntry("", Form("#it{#bf{sPHENIX}} %s", prelimtext.c_str()), "");
0208 sphnxleg->AddEntry("", "p+p #sqrt{s_{NN}}=200 GeV", "");
0209 sphnxleg->Draw();
0210
0211 TLegend *leg = new TLegend(1 - mainPad.GetRightMargin() - 0.27,
0212 1 - mainPad.GetTopMargin() - 0.2,
0213 1 - mainPad.GetRightMargin() - 0.1,
0214 1 - mainPad.GetTopMargin() - 0.06
0215 );
0216 leg->AddEntry(frame->findObject("data"), "Data", "PE2");
0217 leg->AddEntry(frame->findObject("signalpdf"), "Fit", "L");
0218 leg->SetFillColor(0);
0219 leg->SetFillStyle(0);
0220 leg->SetBorderSize(0);
0221 leg->SetTextSize(0.055);
0222 leg->Draw();
0223
0224
0225 float spacing = 0.05;
0226 TLatex *fitparams = new TLatex();
0227 fitparams->SetTextSize(0.045);
0228 fitparams->SetTextAlign(kHAlignLeft + kVAlignCenter);
0229 fitparams->SetNDC();
0230 fitparams->DrawLatex(mainPad.GetLeftMargin() + 0.07,
0231 1 - mainPad.GetTopMargin() - 0.15 - spacing - 0.06,
0232 Form("#mu = %.0f #pm %.0g MeV", FitParams::mean.getVal() * 1000, FitParams::mean.getError() * 1000)
0233 );
0234 fitparams->DrawLatex(mainPad.GetLeftMargin() + 0.07,
0235 1 - mainPad.GetTopMargin() - 0.15 - spacing - 0.06 - 0.055,
0236 Form("#sigma = %.2f #pm %.1g MeV", FitParams::sigma.getVal() * 1000, FitParams::sigma.getError() * 1000)
0237 );
0238
0239 gPad->Modified();
0240 pullPad.cd();
0241 frame2->SetMarkerStyle(kCircle);
0242 frame2->SetMarkerSize(0.02);
0243 frame2->SetTitle("");
0244 frame2->GetXaxis()->SetTitle(xAxisTitle.c_str());
0245 frame2->GetXaxis()->SetTitleOffset(1.3);
0246 frame2->GetXaxis()->SetTitleFont(42);
0247 frame2->GetXaxis()->SetTitleSize(AxisTitleSize * textscale_pad2);
0248 frame2->GetXaxis()->SetLabelFont(42);
0249 frame2->GetXaxis()->SetLabelSize(AxisLabelSize * textscale_pad2);
0250 frame2->GetYaxis()->SetTitle("Pull");
0251 frame2->GetYaxis()->SetTitleOffset(0.5);
0252 frame2->GetYaxis()->SetTitleFont(42);
0253 frame2->GetYaxis()->SetTitleSize(AxisTitleSize * textscale_pad2);
0254 frame2->GetYaxis()->SetLabelFont(42);
0255 frame2->GetYaxis()->SetLabelSize(AxisLabelSize * textscale_pad2);
0256 frame2->GetYaxis()->SetRangeUser(-6, 6);
0257 frame2->GetYaxis()->SetNdivisions(5);
0258 TLine *plusThreeLine = new TLine(FitParams::minMass, 3, FitParams::maxMass, 3);
0259 plusThreeLine->SetLineColor(1);
0260 plusThreeLine->SetLineStyle(2);
0261 plusThreeLine->SetLineWidth(2);
0262 TLine *zeroLine = new TLine(FitParams::minMass, 0, FitParams::maxMass, 0);
0263 zeroLine->SetLineColor(1);
0264 zeroLine->SetLineStyle(2);
0265 zeroLine->SetLineWidth(2);
0266 TLine *minusThreeLine = new TLine(FitParams::minMass, -3, FitParams::maxMass, -3);
0267 minusThreeLine->SetLineColor(1);
0268 minusThreeLine->SetLineStyle(2);
0269 minusThreeLine->SetLineWidth(2);
0270 frame2->Draw();
0271 plusThreeLine->Draw("same");
0272 zeroLine->Draw("same");
0273 minusThreeLine->Draw("same");
0274
0275 std::cout << "Saving plots to " << plotdir << std::endl;
0276
0277 vector<string> extensions = {".C", ".pdf", ".png"};
0278 for (auto &extension : extensions)
0279 {
0280 c->SaveAs(Form("%s/RDataframeToRoofit_%s_signal%s", plotdir.c_str(), FitParams::branch.c_str(), extension.c_str()));
0281 }
0282
0283 auto end = std::chrono::high_resolution_clock::now();
0284 std::chrono::duration<double> elapsed = end - start;
0285 std::cout << "Elapsed time: " << elapsed.count() / 60. << " minutes" << std::endl;
0286 }