Angular analysis of B+->K*+(K+pi0)mumu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

414 lines
18 KiB

//Renata Kopecna
#include <massfit.hh>
#include <event.hh>
#include <fitter.hh>
#include <bu2kstarmumu_plotter.hh>
#include <paths.hh>
#include <design.hh>
#include <helpers.hh>
#include <fstream>
#include <spdlog.h>
#include <TROOT.h>
#include <TStyle.h>
//Fitter part that fits only the mass of DATA
bool checkForCommonValues(std::vector<std::string> vec_one,std::vector<std::string> vec_two){
for (auto key: vec_one){
if (std::find(vec_two.begin(), vec_two.end(), key)!= vec_two.end()){
spdlog::warn("Parameter " + key + " is shared between two vectors!");
return true;
}
}
return false;
}
int massfit(fcnc::options opts, bool fitReference, bool splitRuns, basic_params pars){
//splitRuns = true means one gets a simFit of Run 1 and Run 2
//splitRuns = false means Run 1 and Run 2 are fit together
const bool fitKstarMass = true;
bool Blind = false;//!fitReference; //If signal channel, blind to be sure
const unsigned int nBins = opts.get_nQ2bins(); //unsigned because vector.size is unsigned
bool constrainMassFromMC = false; //Use mass fit of MC to constrain mass parameters?
bool constrainMassFromRefMC = true;//Use mass fit of *RefMC* to constrain mass parameters?
bool constrainMassFromData = !fitReference; //Use the mass fit of data Reference to constrain the parameters?
bool fixBMass = !fitReference; //Fix the B mass to PDG?
//Set the parameters that should be constrained
std::vector<std::string> toBeConstrainedMC = {};
std::vector<std::string> toBeFixedMC = {};
std::vector<std::string> toBeConstrainedRefMC = {};
std::vector<std::string> toBeFixedRefMC = {"alpha_1","alpha_2","n_1","n_2"};
std::vector<std::string> toBeConstrainedRefData = {};
std::vector<std::string> toBeFixedRefData = {"m_b","m_sigma_1"};
//Sanity check one doesn't constrain one thing to two different values
if (constrainMassFromMC && constrainMassFromRefMC){
if (checkForCommonValues(toBeConstrainedMC, toBeConstrainedRefMC)){
spdlog::warn("Fix your options, aborting now!");
return 2;
}
if (checkForCommonValues(toBeFixedMC, toBeFixedRefMC)){
spdlog::warn("Fix your options, aborting now!");
return 2;
}
}
if (constrainMassFromMC && constrainMassFromData){
if (checkForCommonValues(toBeConstrainedMC, toBeConstrainedRefData)){
spdlog::warn("Fix your options, aborting now!");
return 2;
}
if (checkForCommonValues(toBeFixedMC, toBeFixedRefData)){
spdlog::warn("Fix your options, aborting now!");
return 2;
}
}
if (constrainMassFromRefMC && constrainMassFromData){
if (checkForCommonValues(toBeConstrainedRefMC, toBeConstrainedRefData) ){
spdlog::warn("Fix your options, aborting now!");
return 2;
}
if (checkForCommonValues(toBeFixedRefMC, toBeFixedRefData)){
spdlog::warn("Fix your options, aborting now!");
return 2;
}
}
if (constrainMassFromMC && checkForCommonValues(toBeConstrainedMC, toBeFixedMC)){
spdlog::warn("The parameter will be fixed!");
}
if (constrainMassFromRefMC && checkForCommonValues(toBeConstrainedRefMC, toBeFixedRefMC)){
spdlog::warn("The parameter will be fixed!");
}
if (constrainMassFromData && checkForCommonValues(toBeConstrainedRefData, toBeFixedRefData)){
spdlog::warn("The parameter will be fixed!");
}
gROOT->SetBatch(kTRUE);
gROOT->SetStyle("Plain");
set_gStyle();
//Open texFile
std::ofstream myFile;
open_Latex_noteFile(latex_massFit(), myFile);
spdlog::info("[FIT]\t\tFitting only mass...");
// --- Set the options --- //
opts.only_Bmass = !fitKstarMass;
opts.only_mass2DFit = fitKstarMass;
opts.swave = fitKstarMass;
opts.shift_lh = false; //keep it, it was there before
opts.weighted_fit = fitKstarMass; // weights for the MASS DATA fit
opts.plot_chi2 = true;
opts.fit_mkpi = fitKstarMass;
opts.use_mkpi = false;
opts.plot_folder = get_MassFitPlot_path(); //Set the plot path
opts.minos_errors = true; //TODO!
opts.squared_hesse = false;
opts.asymptotic = false;
if (!fitReference) opts.plots_m_bins = 30; //Plot less bins for signal channel as the stats are sad there
if (!fitReference) opts.plots_mkpi_bins = 20; //Plot less bins for signal channel as the stats are sad there
// --- Load events from data tuple --- //
std::vector<std::vector<fcnc::event>>events;
std::vector<UInt_t> pdf_idx;
if (opts.run == 1 || opts.run == 12){
std::vector<fcnc::event> tmp = fcnc::load_events(get_theFCNCpath(0,1), "Events", -1);
if (!fitReference) events.push_back(fcnc::filterResonances(tmp));
else events.push_back(tmp);
pdf_idx.push_back(1);
}
if (opts.run == 2 || opts.run == 12){
std::vector<fcnc::event> tmp = fcnc::load_events(get_theFCNCpath(0,2), "Events", -1);
if (!fitReference) events.push_back(fcnc::filterResonances(tmp));
else events.push_back(tmp);
pdf_idx.push_back(2);
}
//No need to keep the datasets separated, as there is no need for the weights
if (!splitRuns && opts.run == 12){
pdf_idx.clear();
pdf_idx.push_back(12);
//Add the vector from Run 2 into Run 1 vector
events[0].insert(events[0].end(), events[1].begin(), events[1].end());
//Delete the Run 2 vector
events.pop_back();
}
//check that the number of pdfs is the same as number of event vectors
if (pdf_idx.size() != events.size()){
spdlog::error("Something went very wrong when loading the events and setting the pdfs.");
spdlog::error("The number of PDFs!= number of event vectors: {0:d} vs {1:d}",pdf_idx.size(), events.size());
return 5;
}
//we are good to go, now; how many individual pdfs are used?
const UInt_t nPDFs = pdf_idx.size();
//Check the number of events
UInt_t N_tot = 0;
for (UInt_t n = 0; n < nPDFs; n++){
spdlog::debug("Event vector {0:d}:\t"+(Blind ? "Larger 1 ":std::to_string(events.at(n).size())), n);
if (events.at(n).size()==0){
spdlog::error("Empty event vector!");
return 404;
}
N_tot += events.at(n).size();
}
spdlog::info("Total number of used events:\t{0:d}", N_tot);
//Get the path to the file where to get the values/constraints from
//Always use simFit from MCand mass only, it is easier
std::string ParamInitFileMC = final_result_name_MC(pars, nBins, fitReference, false, true, false, false);
std::string ParamInitFileRefMC = final_result_name_MC(pars, 1, true, false, true, false, true);
std::string ParamInitFileRefData = final_result_name_mass(true, 1, splitRuns, pars, pars.Run);
//current fitter, plotter, parameter and pdf:
fcnc::fitter f(&opts);
fcnc::options theOptions[nPDFs];
fcnc::bu2kstarmumu_plotter * thePlotter[nPDFs];
std::vector<fcnc::parameters*> theParams [nBins];
std::vector<fcnc::pdf*> theProbs [nBins];
std::vector< std::vector<fcnc::event>*> selection[nBins];
//Set FS as a common parameter if fitting the sWeight
if(fitKstarMass) f.set_common_parameters({"FS"});
//Loop over PDFs and initialize parameters
for(unsigned n = 0; n < nPDFs; n++){
opts.run = pdf_idx.at(n); //Set proper run to options
opts.name = get_MassFit_label(fitReference, -1, nBins, splitRuns, pars, pdf_idx.at(n));
spdlog::debug("Initializing run {0:d}", opts.run);
opts.update_efficiencies = true; //This ensures the acceptance weights to be taken into account.
//loop over number of bins
for(UInt_t b = 0; b < nBins; b++){
//Create parameter set
fcnc::bu2kstarmumu_parameters * leParameters = new fcnc::bu2kstarmumu_parameters(&opts);
//create PDF
fcnc::bu2kstarmumu_pdf * lePDF = new fcnc::bu2kstarmumu_pdf(&opts, leParameters);
//Init the sig/bkg fraction
leParameters->f_sig.init(fitReference ? 0.8 : 0.3, 0.1, 1.0, 0.1);
//Init PDG mass, keep the range this large!
leParameters->m_b.init(PDGMASS_B, B_MASS_LOW, B_MASS_HIGH, fixBMass ? 0.0 : 0.1);
//Init mass parameters to defaults
leParameters->init_mass_parameters(n,nBins,b,0.01);
//Overwrite the defaults with constraints/fixes from MC/Ref, if needed
if (constrainMassFromMC){
leParameters->constrain_param_from_rootfile(ParamInitFileMC, toBeConstrainedMC, splitRuns ? pdf_idx.at(n) : 2, b);
leParameters->fix_param_from_rootfile(ParamInitFileMC, toBeFixedMC, splitRuns ? pdf_idx.at(n) : 2, b);
}
if (constrainMassFromRefMC){ //Fix to refrence channel, so always read 0th bin
leParameters->constrain_param_from_rootfile(ParamInitFileRefMC, toBeConstrainedRefMC, splitRuns ? pdf_idx.at(n) : 2, 0);
leParameters->fix_param_from_rootfile(ParamInitFileRefMC, toBeFixedRefMC, splitRuns ? pdf_idx.at(n) : 2, 0);
}
if (constrainMassFromData){ //Fix to refrence channel, so always read 0th bin
leParameters->constrain_param_from_rootfile(ParamInitFileRefData, toBeConstrainedRefData, splitRuns ? pdf_idx.at(n) : 2, 0);
leParameters->fix_param_from_rootfile(ParamInitFileRefData, toBeFixedRefData, splitRuns ? pdf_idx.at(n) : 2, 0);
}
//Make sure the B mass range is correct
leParameters->m_b.set_min(B_MASS_LOW);
leParameters->m_b.set_max(B_MASS_HIGH);
//Init the ratio of sigmas in signal MC/reference MC
if (!fitReference) leParameters->m_sigma_1.init_fixed(leParameters->m_sigma_1.get_value()*get_sigmaRatio_fromMC(pars,nBins,b,pdf_idx.at(n)));
//I don't trust the m_scale
//Init background
leParameters->init_mass_background_parameters(nBins, b, opts.fit_lambda);
//define center of q2bin as effective q2:
leParameters->eff_q2.init_fixed(bin_center_q2(opts,b));
//Init the Kstar mass fit
if(opts.fit_mkpi || opts.use_mkpi){
//p-wave;
leParameters->init_mkpi_pWave_parameters(fitReference,0.001);
leParameters->init_kpi_background_parameters(fitReference,0.05);
//s-wave
leParameters->FS.init(0.055, 0.00, 0.5, 0.001); //David got 0.055
leParameters->init_mkpi_sWave_parameters(fitReference, 0.0); //Fix it, otherwise it doesn't converge
}
//Control print of the parameters
//leParameters->print_parameters(false);
//Save the parameters and PDF per bin
leParameters->take_current_as_start();
theParams[b].push_back(leParameters);
theProbs [b].push_back(lePDF);
spdlog::info("[PDF{0:d}]\tSaved PDF and parameters!", pdf_idx.at(n));
//create vector with events according to the requested fits/pulls
std::vector<fcnc::event> *leEvents= new std::vector<fcnc::event>;
//Loop over events
spdlog::debug("Loop over events");
for (auto meas: events.at(n)){
if(meas.m < opts.m_low || meas.m > opts.m_high) continue;
if(pars.polarity==1 && meas.magnet > 0) continue;
if(pars.polarity==-1 && meas.magnet < 0) continue;
if(meas.q2 < opts.TheQ2binsmin.at(b) || meas.q2 > opts.TheQ2binsmax.at(b)) continue;
leEvents->push_back(meas);
}
//Update efficiencies (aka take into account angular parametrization weights) ONCE
lePDF->load_coeffs_eff_phsp_4d();
lePDF->update_cached_normalization(leParameters);
lePDF->update_cached_efficiencies(leParameters, leEvents);
spdlog::info("[PDF{0:d}]\tFinished selecting the events: {1:d}",n, leEvents->size());
//save event vector in vector
selection[b].push_back(leEvents);
if(selection[b].back()->size() > 0){
spdlog::info("[PDF{0:d}]\t[BIN{1:d}]\tDone!", n, b);
}
else{
spdlog::critical("No events found for PDF={0:d} and q2 bin={1:d}. Exit!",n,b);
assert(0);
}
} //End loop over bins
opts.update_efficiencies = false; //Prevent the weights to be applied several more times in fitter::fit
theOptions[n] = opts;
//Allocate the plotter... sigh #ItIsn'tThe90sAnymore
thePlotter[n] = new fcnc::bu2kstarmumu_plotter(&theOptions[n]);
}//end loop over PDFs
//--------------------------------
// FIT
//--------------------------------
spdlog::info("[MASSFIT]\tMass fit started.");
//Measure the time for the fit:
runTime timer = runTime();
//Save the fit results
std::vector<int>fit_results[nBins];
std::vector<double>f_sigs[nBins];
std::vector<double>f_sigserr[nBins];
std::vector<double> bkg_int_full_range[nBins]; //Not really used
std::vector<UInt_t>evts_cntr[nBins];
//fit per bins:
for(unsigned int b = 0; b < nBins; b++){
//Start the clock
timer.start();
time_t startTime = time(0);
spdlog::info("[START]\tStart the fit for bin #{0:d}", b);
std::string tag = get_MassFit_label(fitReference, b,nBins, splitRuns, pars, 0);
clear_Latex_noteFile(latex_fitterFile(tag));
spdlog::info("[FIT]\tRunning the fitter...");
fit_results[b].push_back(f.fit(theProbs[b], theParams[b], selection[b], tag));
spdlog::info("Q2BIN={0:d}\tLLH={1:f}", b, f.likelihood());
//Stop the clock
timer.stop(startTime);
//save signal fraction and event number for each bin and each pdf:
for(UInt_t n = 0; n < nPDFs; n++){
f_sigs[b] .push_back(((fcnc::bu2kstarmumu_parameters *) theParams[b].at(n))->f_sig.get_value());
f_sigserr[b].push_back(((fcnc::bu2kstarmumu_parameters *) theParams[b].at(n))->f_sig.get_error());
evts_cntr[b].push_back(selection[b].at(n)->size());
//integrate the background pdf over the range [opts.m_min; opts.m_max] to estimate the background contribution in each q2bin:
bkg_int_full_range[b].push_back(((fcnc::bu2kstarmumu_pdf*)theProbs[b].at(n))->integral_m_bkg_prob((fcnc::bu2kstarmumu_parameters*)theParams[b].at(n),B_MASS_LOW, B_MASS_HIGH));
}
//Plot everything
bool sigRegion = true; //Plot only in the signal region
for(UInt_t n = 0; n < nPDFs; n++){
tag = get_MassFit_label(fitReference, b,nBins, splitRuns, pars, pdf_idx.at(n));
theOptions[n].plot_label = "LHCb data";
theOptions[n].q2_label =q2_label(opts.TheQ2binsmin.at(b), opts.TheQ2binsmax.at(b));
if (nPDFs>1){ //If only one PDF, just plot the "added pdfs"
spdlog::info("[PLOT]\t"+theOptions[n].plot_label);
thePlotter[n]->plot_data((fcnc::bu2kstarmumu_pdf*)theProbs[b].at(n),
(fcnc::bu2kstarmumu_parameters*)theParams[b].at(n),
selection[b].at(n), get_MassFitPlot_path(),tag, sigRegion);
}
}
//Plot joint result
std::vector<fcnc::bu2kstarmumu_pdf*> * prober = (std::vector<fcnc::bu2kstarmumu_pdf*> *) & theProbs[b];
std::vector<fcnc::bu2kstarmumu_parameters*> * paramser = (std::vector<fcnc::bu2kstarmumu_parameters*> *) & theParams[b];
tag = get_MassFit_label(fitReference, b,nBins, splitRuns, pars, pars.Run);
thePlotter[0]->plot_added_pdfs(prober, paramser, &selection[b],
get_MassFitPlot_path(), tag, sigRegion);
}//end bin loop
//Plot the significances and yields in the fancy plot
//TODO: unhardcode the runs
if (!fitReference && nBins>1){
std::string tag = get_MassFit_label(fitReference, -1,nBins, splitRuns, pars, 12);
spdlog::info("Saving yield plots into " + tag);
thePlotter[0]->plotYieldInQ2(true, theParams, theProbs, nPDFs, evts_cntr, get_MassFitPlot_path(), tag);
thePlotter[1]->plotYieldInQ2(false, theParams, theProbs, nPDFs, evts_cntr, get_MassFitPlot_path(), tag);
}
//--------------------------------
// Print & Save
//--------------------------------
//Print running time
timer.print(nBins);
//Print all fit results
print_all_parameters(nBins, pdf_idx, theParams, spdlog::level::debug);
//Save the fit results
for(unsigned int b = 0; b < nBins; b++){
for(UInt_t i = 0; i < pdf_idx.size(); i++){
std::vector<fcnc::bu2kstarmumu_parameters*> * paramser = (std::vector<fcnc::bu2kstarmumu_parameters*> *) & theParams[b];
std::string results_file = get_MassFitResult_path()+ "fitresult_"
+get_MassFit_label(fitReference, b, nBins, splitRuns, pars, pars.Run)+ ".txt";
paramser->at(i)->save_param_values(results_file);
}
}
//Print signal yield in the terminal and to a tex file
if (!Blind){
print_sig_yields(nBins, pdf_idx, evts_cntr, f_sigs, f_sigserr);
print_bkg_yields(nBins, pdf_idx, evts_cntr, f_sigs, f_sigserr);
}
print_sig_yields_tex(get_MassFit_label(fitReference, -1,nBins,
splitRuns, pars, pars.Run),
nBins, pdf_idx, &opts, evts_cntr, f_sigs, f_sigserr);
//Save results to root file
std::string results_file = final_result_name_mass(fitReference, nBins, splitRuns, pars, pars.Run);
save_results(results_file, nBins, pdf_idx, fit_results, theParams, true, &opts);
//Close Latex file
myFile.close();
spdlog::info("[MASSFIT]\tMass fit finished.");
return 0;
}