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.
 
 
 
 

1053 lines
46 KiB

//Functions used for the B plus mass fit
//Renata Kopecna
#include "GlobalFunctions.hh"
#include "MassFit.hpp"
#include "BmassShape/BackgroundPdf.hpp"
#include "BmassShape/SignalPdf.hpp"
#include "Paths.hpp"
#include "MVAclass.hpp"
#include "RooFit/RooDoubleCB/RooDoubleCB.h"
#include "Design.hpp"
#include "Utils.hpp"
using namespace std;
using namespace RooFit;
using namespace RooStats;
bool useExtraVarBool(string extraVar){ //Shoudl be easy to add others
vector<string> allVars {"q2", "q2_binned", "q2_binned_fit", "thetak", "thetal", "phi", "pi_zero_ETA", "pi_zero_ETA-K_plus_ETA", "pi_zero_P", "pi_zero_P_DTF", "pi_zero_PT", "pi_zero_PT_DTF","K_plus_P","K_plus_PT"};
for (auto &var: allVars){
if (extraVar == var) return true;
if (extraVar == var+"_equal") return true;
}
return false;
}
string GetsWeightPlots(string year, bool UseOnlyJpsiEvents, bool UseOnlyMuMuEvents, bool KshortDecaysInVelo, bool GetShapeFromMC, string SignalType, string BkgType, bool ConstrainParameters){
string path = GetMassFitFile(year,false,UseOnlyJpsiEvents,UseOnlyMuMuEvents, KshortDecaysInVelo, GetShapeFromMC, SignalType,BkgType, ConstrainParameters,true,false);
replace(path,"BplusMassModel","Sweight");
return path;
}
double massFit(string year, string magnet, int Run,
bool MC, bool Preselected, bool TM, bool PHSP, //input/output file selection
bool UseOnlyJpsiEvents, bool UseOnlyMuMuEvents, //signal/reference
bool GetShapeFromMC, string SigType, string BkgType, bool ConstrainParameters, //shape
bool KshortDecaysInVelo, bool UseLowQ2Range, //LL/DD? q2range?
Double_t TMVAcut, int randomSubset, //TMVA options
bool fixedMassRegion, bool yieldOverFullRange, //yield calculation region
bool sWeight, //sWeight data?
bool loopFit, bool IsEfficiency, //additional options
string sExtraVar, int nExtraBin, //fit in bins of extra variable
bool removeMultiple, //Remove multiple candidates?
bool weighted, bool weightedFromPi0, string whichWeight, //use weight in the fit?
bool nonTM, string customTMbranch, bool gammaTM, //TM options
bool InclusiveSample){ //Fit inclusive sample?
//bool notTM: if true and MC, fits the nonTM part of MC with a CB
// To fit the CB as a background either in MC or Data, add "OneCB" to the BkgType string
//randomSubset \in {-1,0,1}
//loopFit means that MC fit is not performed, but parameters are fixed to previous fit, useful since one doesn't have to fit MC all the time in a loop
//IsEfficiency: Just stored in a different folder
//TODO: possibly add splittig in low/high Q2
//Make ROOT quiet
gStyle -> SetOptStat(0);
LHCbStyle();
gROOT->SetBatch(kTRUE);
//Load all libraries for ROOT
gSystem->Load("./BmassShape/SignalType_cpp.so");
gSystem->Load("./BmassShape/BackgroundType_cpp.so");
gSystem->Load("./BmassShape/ParamValues_cpp.so");
gSystem->Load("./BmassShape/SignalPdf_cpp.so");
gSystem->Load("./BmassShape/BackgroundPdf_cpp.so");
int printLevel = 1;
if (verboseLevel > 1){
printLevel = -1;
RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
}
//sanity checks
magnet = correct_magnet_string(magnet);
checkMC(MC,false,PHSP,false);
if (!checkTM(MC,TM,nonTM,Preselected)) return 0;
checkKshort(KshortDecaysInVelo);
if (!SplitInQ2 && UseLowQ2Range) {
coutWarning("Cannot use low Q2 region if the data is not split in Q2! Setting UseLowQ2Range to false!");
UseLowQ2Range = false;
}
if (!checkQ2Range(UseOnlyJpsiEvents,UseOnlyMuMuEvents)) return 0;
if (TMVAcut > -1.0 && !Preselected){ //if TMVAcut == -1, no TMVA cut is applied
coutWarning("TMVA cut can be only aplied on preselected data! Setting Preselected to true!");
Preselected = true; //Cannot do BDT cut on stripped data
}
if(TM && MC && (GetShapeFromMC || ConstrainParameters)){
coutWarning("Cannot fix MC fit to an MC fit! Setting GetShapeFromMC and ConstrainParameters to false.");
GetShapeFromMC = false; //never run MC twice!
ConstrainParameters = false; // never use constrains on MC samples
}
if (sWeight && MC){
coutWarning("MC cannot be sWeighted! Setting sWeight to false!");
sWeight = false;
}
if (sWeight && UseOnlyMuMuEvents){
coutWarning("Data cannot be sWeighted only in the MuMu region! Setting UseOnlyMuMuEvents to false!");
UseOnlyMuMuEvents = false;
}
if (customTMbranch =="") customTMbranch = TMbranch;
if (customTMbranch =="TMedBKGCAT" && gammaTM == false) gammaTM = true;
bool useExtraVar = useExtraVarBool(sExtraVar); //perform once so it doesn't have to run through all the ifs every time
TMefficiencyClass extraVar = TMefficiencyClass(sExtraVar);
//To make life easier, make a bool for using RefChannel MC
bool UseRefMC = (MC && !PHSP && UseOnlyJpsiEvents);
//Make a years vecotr based on Run and selected proper RunID based on a year
std::vector<string> years;
int RunID = 0;
if (Run == 0){
RunID = getRunID(year);
if (MC && UseRefMC){
//can't use yearVector since we can replace 2017 and 2018 MC by 2016
if (!checkRefYear(year)) years.push_back("2016");
else years.push_back(year);
}
else years.push_back(checkIf2015MC(year,MC,UseRefMC,PHSP));
}
else{
RunID = Run;
if (InclusiveSample) years = yearsBkgMC(UseOnlyJpsiEvents,false, false,true, Run);
else if (MC) years = yearsMC(UseRefMC,PHSP,Run);
else years = yearsData(Run);
}
coutInfo("Using year/s ");
cout << "[INFO]\t"; printVector(years); cout << endl;
coutInfo(" with RunID "+to_string(RunID));
///signal shape
SignalPdf SigShape;
SigShape.setSignalType(SigType,GetShapeFromMC,ConstrainParameters);
///background shape
BackgroundPdf BkgShape;
BkgShape.setBackgroundType(BkgType,TM,GetShapeFromMC,ConstrainParameters);
///----------------------------------------------------
///Get Fit parameters from fit to TMed MC if requested:
///----------------------------------------------------
//Turn off MC fit in case of fitting in a loop, except for when TMVAcut == lowBDTcut
//When performing scans, always fix the parameters to the MC value
//however, the parameters are not calculated each iteration of the scan, because the MC shape does not change
Float_t lowBDTcutCheck = (TMVAmethod == "MLP") ? 0.0 : -1.0; //check if at lower limit
bool runMCforTMVAcut = (TMVAcut == lowBDTcutCheck || TMVAcut == 0.9); //if TMVA at lower limit/0.9 for fine scans, do the MC fit again
coutDebug("Run MC for TMVA cut? " +to_string(runMCforTMVAcut));
coutDebug("TMVA cut: " +to_string(TMVAcut));
bool MC_UseOnlyJpsiEvents, MC_UseOnlyMuMuEvents;
if(GetShapeFromMC && (runMCforTMVAcut || !loopFit)){
//In case of CB in the background model, fit the nonTMed MC by oneCB
if (sExtraVar == "q2_binned"){
MC_UseOnlyJpsiEvents = false;
MC_UseOnlyMuMuEvents = true;
}
else{
MC_UseOnlyJpsiEvents = UseOnlyJpsiEvents;
MC_UseOnlyMuMuEvents = UseOnlyMuMuEvents;
}
if (BkgShape.bkgOneCB){
std::cout << std::endl;
coutInfo("||==============================================||");
coutInfo("|| Fitting the MC to obtain background shape! ||");
coutInfo("||==============================================||");
std::cout << std::endl;
if(massFit(year,magnet,Run,
true,true,false,PHSP,
MC_UseOnlyJpsiEvents, MC_UseOnlyMuMuEvents,
false,"NoSig","OneCB",false,
KshortDecaysInVelo,UseLowQ2Range,
TMVAcut, 0, fixedMassRegion, yieldOverFullRange,
false, false, IsEfficiency, sExtraVar, nExtraBin,
removeMultiple, weighted, weightedFromPi0, whichWeight,
true, customTMbranch, gammaTMdefault, InclusiveSample) == 0){
coutERROR("Fit to MC data did not work out!");
return 0;
}
}
//Now fit the TMed MC
if (false){ //TODO: possibly switch to true
std::cout << std::endl;
coutInfo("||==================================================||");
coutInfo("|| Fitting the MVAed data to obtain signal shape! ||");
coutInfo("||==================================================||");
std::cout << std::endl;
if(massFit(year,magnet,Run,
false, true, false,PHSP,
true, false,
false, SigType,BkgType, false,
KshortDecaysInVelo, UseLowQ2Range,
getTMVAcut(RunID), 0, fixedMassRegion, yieldOverFullRange,
false, false, IsEfficiency, sExtraVar, nExtraBin,
true, false, false, "",
false, "", gammaTMdefault, false) == 0){
coutERROR("Fit to MC data did not work out!");
return 0;
}
}
else{
std::cout << std::endl;
coutInfo("||===========================================||");
coutInfo("|| Fitting the MC to obtain signal shape! ||");
coutInfo("||===========================================||");
std::cout << std::endl;
if(massFit(year,magnet,Run,
true,true, true,PHSP,
MC_UseOnlyJpsiEvents, MC_UseOnlyMuMuEvents,
false,SigType,"NoBckGnd",false,
KshortDecaysInVelo, UseLowQ2Range,
-1.0, 0, fixedMassRegion, yieldOverFullRange,
false, false, IsEfficiency, sExtraVar, nExtraBin,
removeMultiple, weighted, weightedFromPi0, whichWeight,
false, customTMbranch, gammaTM, InclusiveSample) == 0){
coutERROR("Fit to MC data did not work out!");
return 0;
}
}
std::cout << std::endl;
coutInfo("||===========================================||");
coutInfo("|| Apply signal shape and fit data with it! ||");
coutInfo("||===========================================||");
std::cout << std::endl;
}
//For now only MC can be weighted
if (weighted && !MC){
coutWarning("For now only weighted MC can be done! Setting weight to false!");
weighted = false;
}
if (weighted) SumW2Error(kTRUE);
//print info about signal and background shape
coutInfo("Using a " + SigType + " for the Signal shape!");
coutInfo("Using a " + BkgType + " for the Background shape!");
///------------------------------
///Load file
///------------------------------
TChain* tree = new TChain(treeName(MC,Preselected).c_str());
coutInfo("Reading data from TTree... ");
if (TMVAcut != -1 || weightedFromPi0 || removeMultiple) tree = get_BDT_TChain(years, MC, MC && UseOnlyJpsiEvents, PHSP, KshortDecaysInVelo, weightedFromPi0);
else if (weighted) tree = get_weighted_TChain(years, MC, UseOnlyJpsiEvents, PHSP, KshortDecaysInVelo);
else tree = get_basic_TChain(magnet,years,Preselected,MC,UseOnlyJpsiEvents,PHSP,false, false, InclusiveSample);
if(tree->GetEntries() == 0){
coutERROR("No entries found in TTree. Exit program!");
return 0;
}
else coutDebug("DONE!");
///------------------------------
/// Set branches
///------------------------------
string B_mass_branch = UseDTF ? (Preselected ? "B_plus_M_DTF" : "B_plus_DTF_M") : ("B_plus_M");
coutDebug("Deactivating all not needed branches.. ");
tree->SetBranchStatus("*",0);
//activating all needed branches
tree->SetBranchStatus("Q2", 1);
tree->SetBranchStatus(B_mass_branch.c_str(),1);
string weightBranch = weighted ? getWeightName(customTMbranch,gammaTM) : "";
if (weighted) coutDebug("WeightBranch = " + weightBranch + ".");
if (TMVAcut > -1.0) tree->SetBranchStatus(TMVAmethod+"response",1);
if (TM || nonTM) tree->SetBranchStatus(customTMbranch.c_str(),1);
if (TM || nonTM) tree->SetBranchStatus(gammaTMbranch.c_str(),1);
if (TM || nonTM) tree->SetBranchStatus(customTMbranch.c_str(),1);
if (randomSubset!=0) tree->SetBranchStatus("RandomSubSet",1);
if (Kst2Kspiplus && SplitDDandLL) tree->SetBranchStatus("KshortDecayInVeLo",1);
if (weighted) tree->SetBranchStatus(weightBranch.c_str(), 1);
if (weightedFromPi0) tree->SetBranchStatus(Form("w_%s",whichWeight.c_str()),1);
if (useExtraVar){
for (auto var:extraVar.sBranchName)
tree->SetBranchStatus(var.c_str(),1); //add last branch (or the only one)
}
if (removeMultiple) tree->SetBranchStatus(getAloneBranch(MC,TM,customTMbranch,gammaTM).c_str(),1);
coutInfo("DONE!");
///------------------------------
///Fill all needed variables in RooDataSet
///------------------------------
coutInfo("Loading the dataset...");
RooRealVar *B_plus_M;
B_plus_M = new RooRealVar(B_mass_branch.c_str(),
(Kst2Kspiplus ? (UseDTF ? "m(K_{S}^{0}#pi^{+}#mu^{+}#mu^{-})" : "m(#pi^{+}#pi^{-}#pi^{+}#mu^{+}#mu^{-})") : (UseDTF ? "m(K^{+}#pi^{0}#mu^{+}#mu^{-})" : "m(K^{+}#gamma#gamma#mu^{+}#mu^{-})") ),
get_cut_B_plus_M_low(year),
cut_B_plus_M_high,
" MeV/c^{2} ");
//In case we want to change binning, this is really not ideal but oh well
string finalCut = getFinalCut(MC,TM, nonTM, customTMbranch, gammaTM, UseOnlyMuMuEvents, UseOnlyJpsiEvents, SplitInQ2, UseLowQ2Range, useExtraVar, extraVar, nExtraBin, TMVAcut, removeMultiple);
if (!Preselected) finalCut = "B_plus_DTF_M >0"; //Dummy
coutDebug("Using cuts " + finalCut);
RooRealVar Q2Bin ("Q2", " ", -0.1e6, 21.1e6," ");
RooRealVar TMVAresponse (TMVAmethod+"response", " ", -1.0, 1.0, " ");
RooRealVar TMvar (customTMbranch.c_str(), " ", -0.1, 1.1, " ");
RooRealVar TMgammaVar (gammaTMbranch.c_str(), " ", -0.1, 6.1, " ");
RooRealVar KshortDecayInVeLo("KshortDecayInVeLo", " ", KshortDecaysInVelo ? 0.9 : -0.1, KshortDecaysInVelo ? 1.1 : 0.1," ");
RooRealVar RandomSubSet ("RandomSubSet", " ", randomSubset - 0.1, randomSubset + 0.1," ");
const int nExtraVars = extraVar.sBranchName.size();
RooRealVar *RooExtraVars[nExtraVars];
for_indexed (auto var:extraVar.sBranchName){
RooExtraVars[i] = new RooRealVar(var.c_str(), var.c_str(), extraVar.vVarRange.at(i).at(0), extraVar.vVarRange.at(i).at(1)," ");
coutDebug("Var: " + string(var.c_str()));
coutDebug("Range: " + to_string(extraVar.vVarRange.at(i).at(0)) + " to " + to_string(extraVar.vVarRange.at(i).at(1)));
}
RooRealVar IsAlone (getAloneBranch(MC,TM,customTMbranch,gammaTM).c_str(), " ", -1.0, 2.0, " ");
RooRealVar *FinalWeight;
if (weighted && weightedFromPi0){ //TODO: the question is if this works, test it at some point!
FinalWeight = new RooRealVar("weight","weight",-10.0,10.0,"");
double w;
double w_pi0;
tree->SetBranchAddress(weightBranch.c_str(),&w);
tree->SetBranchAddress(Form("w_%s",whichWeight.c_str()),&w_pi0);
for (int e = 0; e<tree->GetEntries();e++){
tree->GetEntry(e);
FinalWeight->setVal(w*w_pi0);
}
}
else if (weighted){
FinalWeight = new RooRealVar(weightBranch.c_str(), weightBranch.c_str(), -10.0, 10.0," ");
}
else if (weightedFromPi0){
FinalWeight = new RooRealVar(Form("w_%s",whichWeight.c_str()), Form("w_%s",whichWeight.c_str()), 0.0, 10.0," ");
}
RooArgSet argSet = RooArgSet(*B_plus_M);
argSet.add(Q2Bin);
if (TM||nonTM) argSet.add(TMvar);
if (TM||nonTM) argSet.add(TMgammaVar);
if (useExtraVar)
for(int i = 0; i < nExtraVars;i++) argSet.add(*RooExtraVars[i]);
if (TMVAcut > -1.0) argSet.add(TMVAresponse);
if (randomSubset) argSet.add(RandomSubSet);
if (SplitDDandLL&&Kst2Kspiplus) argSet.add(KshortDecayInVeLo);
if (removeMultiple) argSet.add(IsAlone);
if (weighted||weightedFromPi0) argSet.add(*FinalWeight);
RooDataSet* data= NULL;
if (weighted||weightedFromPi0) data = new RooDataSet("data","data",argSet,Import(*tree),Cut(finalCut.c_str()), WeightVar(*FinalWeight));
else data = new RooDataSet("data","data",argSet,Import(*tree),Cut(finalCut.c_str()));
coutInfo(" DONE!");
if (verboseLevel < 3) data->Print();
coutDebug("Using weighted events? " + to_string (data->isWeighted()));
coutDebug("The dataset contains " + to_string(data->numEntries()) + " events!");
///------------------------------
///Build the B+ mass signal shape
///------------------------------
gROOT->ProcessLine(".L ./RooFit/RooDoubleCB/RooDoubleCB_cpp.so");
gROOT->ProcessLine(".L ./GlobalFunctions.hh"); //This is very weird, but it works ¯\_(ツ)_/¯
coutInfo("Setting signal fit parameters ... ");
//set mean of B_plus mass peak
RooRealVar* meanBplus = SigShape.getRooRealVar("mean",true);
///------------------------------
///Yields and Background + Signal Fit-Model
///------------------------------
//yields
coutDebug("The dataset has " + to_string(data->numEntries()) + " entries!");
RooRealVar N_Bplus("N_Bplus", "#B^{+}", data->numEntries()/2., 0., 2*data->numEntries());
RooRealVar N_comb("N_comb","N_comb", data->numEntries()/2., 0., 2*data->numEntries());
//Create the signal PDF
//Check if one selected any sigPdf and bkgPdf
if (SigShape.NoSig && BkgShape.NoBackground){
coutERROR("No fit model was selected. Abort.");
return 0;
}
coutDebug("Creating BplusMassModel...");
RooAddPdf *BplusMassModel = NULL;
if (!SigShape.NoSig) BplusMassModel = SigShape.getBplusMassModel(B_plus_M,meanBplus, UseOnlyJpsiEvents);
coutInfo("Signal PDF is created!");
if (!SigShape.NoSig){
coutInfo("Constraints PDF:");
SigShape.ConsPDF->Print();
}
coutDebug("Creating BplusBckGndModel...");
///Build the B+ mass background model
RooAddPdf * BplusBckGndModel = NULL;
if (!BkgShape.NoBackground) BplusBckGndModel = BkgShape.getBplusBkgModel(B_plus_M);
coutInfo("Background PDF is created!");
//add all required pdfs
RooAbsPdf* pdf = NULL;
if (BkgShape.NoBackground){
//Create the signal PDF
pdf = new RooAddPdf("pdf", "pdf", RooArgList(*BplusMassModel), RooArgList(N_Bplus));
}
else{
if (SigShape.NoSig) pdf = new RooAddPdf("pdf", "pdf", RooArgList(*BplusBckGndModel), RooArgList(N_comb));
else pdf = new RooAddPdf("pdf", "pdf", RooArgList(*BplusMassModel, *BplusBckGndModel), RooArgList(N_Bplus, N_comb));
}
if (verboseLevel<2) pdf->Print();
///Gaussian Constraint to MC values
if (!SigShape.AtLeastOneConstrainFound) coutDebug("No parameters in signal costrained.");
if (!BkgShape.AtLeastOneConstrainFound) coutDebug("No parameters in background costrained.");
///------------------------------
///Fit
///------------------------------
RooFitResult *result = new RooFitResult("FitResult","FitResult");
//Add constrained PDFs
if (SigShape.AtLeastOneConstrainFound || BkgShape.AtLeastOneConstrainFound){
RooArgSet *constrPdfs;
if (SigShape.AtLeastOneConstrainFound) constrPdfs = new RooArgSet(*SigShape.ConsPDF);
if (BkgShape.AtLeastOneConstrainFound) constrPdfs = new RooArgSet(*BkgShape.BkgConsPDF);
RooProdPdf *FitPDF_constraint = new RooProdPdf("FitPDF_constraint","FitPDF_constraint",RooArgSet(*pdf,*constrPdfs));
if (!IsEfficiency){
coutDebug("Constrained parameters are:" );
SigShape.ConsParameter->Print();
coutDebug("The following PDF is fitted to the data:" );
FitPDF_constraint->Print();
coutDebug("Start the fit with constrains! " );
}
result = FitPDF_constraint->fitTo(*data,Save(kTRUE),Extended(kTRUE),NumCPU(3),Constrain(*constrPdfs),PrintLevel(printLevel),SumW2Error(weighted ? kTRUE : kFALSE));
delete FitPDF_constraint;
}
else{
coutDebug("The following PDF is fitted to the data:" );
if (verboseLevel<2) pdf->Print();
coutDebug("Start the fit! " );
result = pdf->fitTo(*data,Save(kTRUE),Extended(kTRUE),NumCPU(3),PrintLevel(printLevel),SumW2Error(weighted ? kTRUE : kFALSE));
}
coutDebug("The fit result is --------------- " );
if (verboseLevel<2) result->Print();
//Saving the results in case of constrianing to MC
SigShape.setValuesAndErrors(true);
BkgShape.setValuesAndErrors(false);
///------------------------------
///calculate # (signal)background events in signal region
///------------------------------
coutDebug("The effective sigma is: " + to_string(SigShape.getEffSigmaFromResult()));
if (fixedMassRegion) B_plus_M->setRange("SigRange",meanBplus->getVal() - B_plus_M_signal_window, meanBplus->getVal() + B_plus_M_signal_window );
else B_plus_M->setRange("SigRange",meanBplus->getVal() - SignalRegionNsigma * SignalFitParameter.SigmaEff, meanBplus->getVal() + SignalRegionNsigma * SignalFitParameter.SigmaEff);
coutInfo("Determining the signal and background yield");
//Get signal yield
RooAbsReal* S_fr = NULL;
Double_t S = 0.0, S_error_test = 0.0, S_error = 0.0;
if (!SigShape.NoSig){
S_fr = BplusMassModel->createIntegral(*B_plus_M,NormSet(*B_plus_M),Range("SigRange"));
S = S_fr->getVal() * N_Bplus.getVal();
S_error_test = S_fr->getPropagatedError(*result) * N_Bplus.getVal();
S_error = S_fr->getVal() *N_Bplus.getError();
}
//Get background yield
RooAbsReal* B_fr = nullptr;
Double_t B = 0.0, B_error = 0.0, B_error_test = 0.0;
if(!BkgShape.NoBackground){
B_fr = BplusBckGndModel->createIntegral(*B_plus_M,NormSet(*B_plus_M),Range("SigRange"));
B = B_fr->getVal() * N_comb.getVal();
B_error_test = B_fr->getPropagatedError(*result) * N_comb.getVal();
B_error = B_fr->getVal() * N_comb.getError(); //B * (N_comb.getError()/N_comb.getVal());
}
coutInfo("S/sqrt(S+B)= " + to_string(S/sqrt(S+B)));
if(B != 0.)coutInfo("S/B= " + to_string(S/B));
coutInfo("S= " + to_string(S)+ "+-" + to_string(S_error));//+ "/+-" + to_string(S_error_test));
coutInfo("B= " + to_string(B)+ "+-" + to_string(B_error));//+ "/+-" + to_string(B_error_test));
cout << endl << endl;
///------------------------------
///Plot the models with indidivual components
///------------------------------
//configurables for plotting
Float_t pullHeight = 0.32;
Int_t Bins = 100;
if (UseOnlyMuMuEvents && Preselected && !MC) Bins = useExtraVar ? 30 : 50;
//create two pads into one canvas
TCanvas* c1= new TCanvas("");
TPad *pad1 = new TPad("pad1", "plot",0.0,pullHeight,1.0,1.0,0);
TPad *pad2 = new TPad("pad2", "pull",0.0,0.0,1.0,pullHeight,0);
pad1->Draw();
pad2->Draw();
//modifiy pad for main plot
pad1->SetBorderSize (0);
pad1->SetBottomMargin(1e-6);
pad1->SetTopMargin(pad1->GetTopMargin() / pullHeight * ( 1 - pullHeight) );
pad1->cd();
RooPlot* frame_m = B_plus_M->frame();
//some axis-modifications on the main plot
TGaxis::SetExponentOffset(1e+9,1e+9,"y");//offset = pad size * 1e+7
//make the frame pretty
designMassFitFrame(frame_m, pullHeight);
data->plotOn(frame_m,Name("data"),MarkerSize(0.5),Binning(Bins),DataError(RooAbsData::SumW2));
pdf->plotOn(frame_m,Name("pdf"),LineColor(kBlack),LineWidth(2));
if (!SigShape.NoSig) pdf->plotOn(frame_m,Components("BplusMassModel"),LineColor(kBlue),LineStyle(kDashed),LineWidth(1));
if (!BkgShape.NoBackground){pdf->plotOn(frame_m,Components("BplusBckGndModel"),LineColor(kRed),LineStyle(kDashed),LineWidth(1));
//in case you want to plot ExpGaus
//pdf->plotOn(frame_m,Components("bkg_exp1"),LineColor(kRed),LineStyle(kDashed),LineWidth(1));
//pdf->plotOn(frame_m,Components("ExpG"),LineColor(kRed),LineStyle(kDashed),LineWidth(1));
}
//Plot the pdf and the box with fit results into the frame
data->plotOn(frame_m,Name("data"),MarkerSize(0.5),Binning(Bins));
//pdf->paramOn(frame_m, Format("NEU",AutoPrecision(1)));
pdf->paramOn(frame_m, ShowConstants(kTRUE), Format("NEU",AutoPrecision(2)), Layout(0.65, 0.95, 0.88));
frame_m->Draw();
c1->Update();
// TODO: Add a box with constrained parameters posibly
//signal/background yield
Float_t posX = MC ? 0.40 : 0.41, posY = 0.84;
if(Kst2Kspiplus) posX = 0.34;
TLatex* fitresult = new TLatex();
fitresult->SetTextFont(132);
fitresult->SetTextColor(1);
fitresult->SetTextSize(0.04);
fitresult->SetTextAlign(13);
fitresult->SetNDC(1);
//TODO
if (!SigShape.NoSig) fitresult->DrawLatex(posX, posY - 0.08, Form("Signal: %.0f #pm %.0f", S, S_error)); //Signal defined by N sigma around peak mean value or in the mass window, depends on bool fixedMassRegion and B_plus_M_signal_window
if(!BkgShape.NoBackground) fitresult->DrawLatex(posX, posY - 0.13, Form("Background: %.0f #pm %.0f", B, B_error));
frame_m->addObject(fitresult) ;
frame_m->Draw("SAME");
if (MC) addLHCbtag(posX, 0.82, "simulation", 1./(1. - pullHeight));
else addLHCbtag(posX, 0.82, "data", 1./(1. - pullHeight));
//create pull histogram
pad2->Clear();
pad2->SetTopMargin(1e-6);
pad2->SetBottomMargin(pad2->GetBottomMargin() / pullHeight );
pad2->cd();
//Design pull histogram
RooPlot* pullFrame = B_plus_M->frame();
designPullFrame(pullFrame,frame_m,pullHeight);
//Add two 3-sigma lines:
TLine * lUp = threeSigmaLine(true);
TLine * lLow = threeSigmaLine(false);
pullFrame->addObject(lUp);
pullFrame->addObject(lLow);
//Draw the pull
pullFrame->Draw() ;
//choose path to save files //TODO: check
string filePath = "";
if (IsEfficiency) filePath = GetEfficiencyMassFitFile(year, magnet, Run,
Preselected, TM, PHSP, UseOnlyJpsiEvents, UseOnlyMuMuEvents,
GetShapeFromMC, SigType, BkgType, ConstrainParameters,
KshortDecaysInVelo, UseLowQ2Range,
TMVAcut, fixedMassRegion,
sExtraVar, nExtraBin,
removeMultiple, weighted, weightedFromPi0,
whichWeight, customTMbranch, gammaTM);
else filePath = GetMassFitFile(year,magnet,Run,MC,Preselected,TM,PHSP,UseOnlyJpsiEvents,UseOnlyMuMuEvents,
GetShapeFromMC, SigType, BkgType, ConstrainParameters,
KshortDecaysInVelo, UseLowQ2Range, TMVAcut, randomSubset,
fixedMassRegion, yieldOverFullRange, sExtraVar, nExtraBin,removeMultiple,
weighted, weightedFromPi0, whichWeight, nonTM, customTMbranch, gammaTM, InclusiveSample);
coutDebug("Saving into file "+ filePath);
TFile *fitFile = new TFile(filePath.c_str(),"RECREATE");
//save canvas to pdf and root format
coutInfo("Writting signal and background pdfs into the file " + filePath + ".");
fitFile->cd();
result->Write();
c1->Write();
//Save Signal yield, background yield and it's error
TVectorD yield(1);
yield[0] = S;
yield.Write("yield");
TVectorD yield_err(1);
yield_err[0] = S_error;
yield_err.Write("yield_err");
TVectorD B_vec(1);
B_vec[0] = B;
B_vec.Write("background");
TVectorD B_vec_err(1);
B_vec_err[0] = B_error;
B_vec_err.Write("background_err");
TVectorD sigma_eff(1);
sigma_eff[0] = SignalFitParameter.SigmaEff;
sigma_eff.Write("sigma_eff");
fitFile->Close();
coutDebug("File " + filePath + " closed." );
//Plot the fit
replace(filePath,".root",".eps");
coutInfo("Plotting into " + filePath + ".");
c1->Print(filePath.c_str());
if(sWeight){
if (BkgType == "NoBckGnd"){ //It crashes here if no background is selected
coutERROR("No background selected! Splot needs SingleExponential, DoubleExponential or ExpGauss.");
return 0;
}
meanBplus->setConstant();
SigShape.setAllRooVarsConstant();
BkgShape.setAllRooVarsConstant();
SPlot* sData = new SPlot("sData","An SPlot",*data,pdf,RooArgList(N_Bplus, N_comb));
///Plot the sWeight distributions as a function of mass
TCanvas* SwBplus = new TCanvas("Bplus sWeight","Bplus sWeight distribution");
TH2 * SwBplusHist;
SwBplusHist = (TH2*)data->createHistogram((UseDTF ? "B_plus_M_DTF,N_Bplus_sw" : "B_plus_M,N_Bplus_sw"));
SwBplusHist->GetYaxis()->SetTitle("Signal sWeights");
SwBplusHist->SetTitle("");
//SwBplus->Write("",TObject::kWriteDelete);
SwBplusHist->Draw();
addLHCbtag(0.65, 0.85, "data", 1);
filePath = GetsWeightPlots(year, UseOnlyJpsiEvents,UseOnlyMuMuEvents, KshortDecaysInVelo,GetShapeFromMC,SigType,BkgType,ConstrainParameters);
SwBplus->SaveAs(filePath.c_str());
replace(filePath,".root",".eps");
SwBplus->Print(filePath.c_str());
///Create output file
TFile* output = nullptr;
output = new TFile(GetBDTinputFile(year,false,UseOnlyJpsiEvents,PHSP,KshortDecaysInVelo).c_str() ,"RECREATE");
if(!output->IsOpen()){
coutERROR("Could not create output file. Abort!");
return 0;
}
output->cd();
tree->SetBranchStatus("*",1);
coutInfo("Copy Tree... " );
TTree * new_tree = nullptr;
string sVariable = (UseDTF ? "B_plus_M_DTF" : "B_plus_M");
string q2Cut = "";
if (UseOnlyJpsiEvents) //If for OnlyMuMu not needed so far //TODO
q2Cut = "&& " + getJpsicut();
if (SplitInQ2){
if (UseLowQ2Range)
q2Cut = "&& Q2 < 8.68e6";
else
q2Cut = "&& 10.09e6 < Q2";
}
//no use of saving only mumu data
if(Kst2Kspiplus && SplitDDandLL){
new_tree = tree->CopyTree(Form("%s >= %f && %s <= %f %s && KshortDecayInVeLo==%i", sVariable.c_str(), get_cut_B_plus_M_low(year), sVariable.c_str(), cut_B_plus_M_high, q2Cut.c_str(), KshortDecaysInVelo));
}
else{
new_tree = tree->CopyTree(Form("%s >= %f && %s <= %f %s", sVariable.c_str(), get_cut_B_plus_M_low(year), sVariable.c_str(), cut_B_plus_M_high, q2Cut.c_str()));
}
coutDebug("Finished!" );
double w;
TBranch* Bra_sw = new_tree->Branch("N_Bplus_sw", &w, "N_Bplus_sw/D");
///loop over events
int numEvents = new_tree->GetEntries();
coutDebug("Entries in TTree:\t"+ to_string(numEvents) );
coutDebug("Entries in RooDataSet:\t"+to_string(data->numEntries()));
if(numEvents != data->numEntries()){
coutERROR("Number of weights not equal to number of events");
return 0;
}
coutDebug("Loop over data sample " + year + TheDecay + " to save sWeights from mass fit results!" );
for(int i = 0; i < numEvents; i++){
if ((0ul == (i % 10000ul) || i + 1 == numEvents) && i != 0) coutInfo("Read event " + to_string(i) + "/" + to_string(numEvents));
tree->GetEntry(i);
w = sData->GetSWeight(i,"N_Bplus_sw");
Bra_sw->Fill();
}
coutInfo("Loop finished!!!");
output->cd();
new_tree->Write("",TObject::kWriteDelete);
delete new_tree;
output->Close();
delete SwBplus;
delete SwBplusHist;
delete sData;
}
if (S < 0.1) S = 0.01; //protect zeroes from happening
delete frame_m;
delete tree;
delete result;
coutInfo("Mass fit is done.");
return S;
}
int quickFit(string year, bool MC, bool sWeight, bool UseOnlyJpsiEvents, bool UseOnlyMuMuEvents, bool KshortDecaysInVelo, bool GetShapeFromMC, string SigType, string BkgType, bool ConstrainParameters){
return massFit(year,"both", 0,
MC, true, MC, false,
UseOnlyJpsiEvents, UseOnlyMuMuEvents,
GetShapeFromMC,SigType,BkgType,ConstrainParameters,
KshortDecaysInVelo,false,
-1.0, 0,
false, false,
sWeight,
false, false,
"",-1,
false,
false, false, "",
false, "", false,
false);
}
int quickTest(bool gammaTM = false, string customTMbranch = "TMed"){
setVerboseLevel(1);
return massFit("2015","both", 0,
false, true, true, false,
false, false,
true,"OneCB","SingleExponential",true,
false,false,
-1.0, 0,
false, false,
false,
false, false,
"",-1,false, true, false, "",false, customTMbranch, gammaTM,
false);
}
int testOneCbBackground(bool MC = false, string SigType = "OneCB", string BkgType = "SingleExponentialOneCB", string customTMbranch = "", bool gammaTM = false){
setVerboseLevel(1);
return massFit("2016","both",0,
false, true, true, false,
!MC, false,
true,SigType,BkgType,true,
false, false,
-1.0, 0,
true, false,
false, false, false,
"",-1, false, false, false, "", false, customTMbranch, gammaTM, false);
}
int efficiencyFit(string year = "2011", string magnet = "down", int Run = 0,
bool Preselected = true, bool TM = true, bool PHSP = false, //input/output file selection
bool UseOnlyJpsiEvents = false, bool UseOnlyMuMuEvents = false, //signal/reference
bool GetShapeFromMC = false, string SigType = "OneCB", string BkgType = "SingleExponential", bool ConstrainParameters = false, //shape
bool KshortDecaysInVelo = Kst2Kspiplus, //LL/DD?
Double_t TMVAcut = -1.0, //TMVA options
bool fixedMassRegion = !Kst2Kspiplus, //yield calculation region
bool UseLowQ2Range =false, //q2 ranges
string sExtraVar = "", int nExtraBin = -1,bool removeMultiple = false, bool weighted = false,
bool weightedFromPi0 = false, string whichWeight = "", //fit in bins of extra variable
string customTMbranch = "", bool gammaTM = false
){
return massFit(year,magnet,Run,
true, Preselected, TM, PHSP,
UseOnlyJpsiEvents, UseOnlyMuMuEvents,
GetShapeFromMC,SigType,BkgType,ConstrainParameters,
KshortDecaysInVelo, UseLowQ2Range,
TMVAcut, 0,
fixedMassRegion, false,
false, false, true,
sExtraVar, nExtraBin, removeMultiple,
weighted, weightedFromPi0,whichWeight,
false, customTMbranch, gammaTM, false
);
}
int basicYieldFit(string year, int Run, bool MC, bool PHSP, //input/output file selection
bool UseOnlyJpsiEvents, bool UseOnlyMuMuEvents, //signal/reference
bool GetShapeFromMC, string SigType, string BkgType, bool ConstrainParameters, //shape
bool KshortDecaysInVelo, bool UseLowQ2Range, //LL/DD? q2range?
Double_t TMVAcut, //TMVA options
bool fixedMassRegion, bool loopFit,//yield calculation region
bool removeMultiple //remove multiple candidates
){ //TODO: shape from MC if TMVA cut?
return massFit(year,"both",Run,
MC, true, MC, PHSP,//if MC then truthMatched
UseOnlyJpsiEvents, UseOnlyMuMuEvents,
GetShapeFromMC,SigType,BkgType,ConstrainParameters,
KshortDecaysInVelo, UseLowQ2Range,
TMVAcut, 0,
fixedMassRegion, false,
false, loopFit, false,
"", -1, removeMultiple,
true, false, "", //weighted=true only for MC, but also data then takes the shape from MC that is weighted
false, "", gammaTMdefault, false);
}
int basicYieldFitAllYears(//Fits all years separately
bool MC = true, bool PHSP = false, //input/output file selection
bool UseOnlyJpsiEvents = false, bool UseOnlyMuMuEvents = false, //signal/reference
bool GetShapeFromMC = false, string SigType = "OneCB", string BkgType = "SingleExponential", bool ConstrainParameters = false, //shape
bool KshortDecaysInVelo = Kst2Kspiplus, bool UseLowQ2Range =false, //LL/DD? q2range?
Double_t TMVAcut = -1.0, //TMVA options
bool fixedMassRegion = !Kst2Kspiplus, bool loopFit = false, //yield calculation region
bool removeMultiple = false //remove multiple candidates
){
for(auto &y : yearsVector(MC,UseOnlyJpsiEvents,false, 12)){
if (basicYieldFit(y,0, MC, PHSP, UseOnlyJpsiEvents,UseOnlyMuMuEvents,GetShapeFromMC, SigType, BkgType, ConstrainParameters,
KshortDecaysInVelo,UseLowQ2Range,TMVAcut, fixedMassRegion,loopFit, removeMultiple) ==0) return 0;
}
return 1;
}
int basicFitAllYearsAndRegions(bool MC = true, bool PHSP = false, //input/output file selection
bool GetShapeFromMC = false, string SigType = "OneCB", string BkgType = "SingleExponential", bool ConstrainParameters = false, //shape
bool KshortDecaysInVelo = Kst2Kspiplus, bool UseLowQ2Range =false, //LL/DD? q2range?
Double_t TMVAcut = -1.0, bool removeMultiple = false //TMVA options
){
vector <bool> UseOnlyJpsiEvents = {true,false};
vector <bool> UseOnlyMuMuEvents = {true,false};
vector <bool> fixedMassRegion = {true,false};
for(auto const&jpsi: UseOnlyJpsiEvents){
for(auto const&mumu: UseOnlyMuMuEvents){
for(auto const&fixedWindow: fixedMassRegion){
if (basicYieldFitAllYears(MC,PHSP, jpsi,mumu,GetShapeFromMC, SigType, BkgType, ConstrainParameters,
KshortDecaysInVelo,UseLowQ2Range,TMVAcut, fixedWindow,false,removeMultiple)==0) return 0;
}
}
}
return 1;
}
int getYieldBasicOptionsMC(bool TM, string year, int Run, bool ReferenceChannel, bool PHSP, bool removeMultiple){
string bkg = TM ? "NoBckGnd" : "SingleExponential";
bool useJpsiOnly = ReferenceChannel;
bool useMuMuOnly = !PHSP && !ReferenceChannel;
bool weighted = false;
return massFit(year,"both",Run,
true, true, TM, PHSP,
useJpsiOnly, useMuMuOnly,
false, "OneCB",bkg,false,
false, false,
-1.0, 0,
true, false,
false, false, false,
"", -1, removeMultiple,
weighted, false, "", //weighted=true only for MC, but also data then takes the shape from MC that is weighted
false, "", gammaTMdefault, false);
}
int getYieldBasicOptionsMCAllYears(bool TM, bool ReferenceChannel, bool PHSP, bool removeMultiple){
for (auto year: yearsMC(ReferenceChannel,PHSP,12)){
if (getYieldBasicOptionsMC(TM, year, 0, ReferenceChannel, PHSP, removeMultiple)==0) return 0;
}
if (getYieldBasicOptionsMC(TM, "2011", 1, ReferenceChannel, PHSP, removeMultiple) == 0) return 0;
if (getYieldBasicOptionsMC(TM, "2015", 2, ReferenceChannel, PHSP, removeMultiple) == 0) return 0;
return 1;
}
int getYieldAllYearsBasicOptions(bool TM, bool removeMultiple){
if (getYieldBasicOptionsMCAllYears(TM,false,false, removeMultiple)==0) return 0;
if (getYieldBasicOptionsMCAllYears(TM,true ,false, removeMultiple)==0) return 0;
if (getYieldBasicOptionsMCAllYears(TM,false,true, removeMultiple)==0) return 0;
//if (basicYieldFitAllYears(false, false, true, false, true, "OneCB", "SingleExponential", true,
// false, false, -1, true,false,true)==0) return 0;
//if (basicYieldFitAllYears(false, false, false, true, true, "OneCB", "SingleExponential", true,
// false, false, -1, true,false,true)==0) return 0;
return 1;
}
int basicYieldFitAllRuns( //Fits data per year
bool MC = true, bool PHSP = false, //input/output file selection
bool UseOnlyJpsiEvents = false, bool UseOnlyMuMuEvents = false, //signal/reference
bool GetShapeFromMC = false, string SigType = "OneCB", string BkgType = "SingleExponential", bool ConstrainParameters = false, //shape
bool KshortDecaysInVelo = Kst2Kspiplus, bool UseLowQ2Range =false, //LL/DD? q2range?
Double_t TMVAcut = -1.0, //TMVA options
bool fixedMassRegion = !Kst2Kspiplus, bool loopFit = false,//yield calculation region
bool removeMultiple = false //remove multiple candidates
){
if ( basicYieldFit("2011",1, MC, PHSP, UseOnlyJpsiEvents,UseOnlyMuMuEvents,GetShapeFromMC, SigType, BkgType, ConstrainParameters,
KshortDecaysInVelo,UseLowQ2Range,TMVAcut, fixedMassRegion,loopFit,removeMultiple)==0) return 0;
if ( basicYieldFit("2015",2, MC, PHSP,UseOnlyJpsiEvents,UseOnlyMuMuEvents,GetShapeFromMC, SigType, BkgType, ConstrainParameters,
KshortDecaysInVelo,UseLowQ2Range,TMVAcut, fixedMassRegion,loopFit,removeMultiple)==0) return 0;
return 1;
}
int massFitTestAll(bool GetShapeFromMC = true,
bool ConstrainParameters = false, int Run = 1){
bool KshortDecaysInVelo= false;
bool UseLowQ2Range = false;
bool TM = false;
bool MC = true;
bool UseOnlyJpsiEvents = false;
bool UseOnlyMuMuEvents = false;
bool UseFixedMassRegion = false;
bool yieldOverFullRange = false;
std::vector<string> years = yearsData(Run);
std::vector<string> signalShape = {//"SingleGaussian",
"DoubleGaussian",
//"CBLeft",
//"CBRight",
"CBDouble"
};
std::vector<string> backgroundShape = {//"SingleExponential",
"DoubleExponential",
"ExpGaus"
};
std::vector<string> polarity = { //"down",
//"up",
"both"
};
for (auto& y: years){
for (auto& sig: signalShape){
for (auto& bkg: backgroundShape){
for (auto& magnet: polarity){
if(massFit(y, magnet, 0, MC, true, TM, false,UseOnlyJpsiEvents, UseOnlyMuMuEvents, GetShapeFromMC, sig, bkg, ConstrainParameters,
KshortDecaysInVelo, UseLowQ2Range, -1.0, false, UseFixedMassRegion,yieldOverFullRange,false, false, false, "", -1,false, false, false, "",false,"",false,false) == 0)return 0;
}
}
}
}
return 1;
}
//check distributions in q2
int massFitTestQ2All(int Run, bool PHSP, bool UseOnlyMuMuEvents, bool UseOnlyJpsiEvents){
bool KshortDecaysInVelo= false;
bool UseLowQ2Range = false;
bool UseFixedMassRegion = false;
bool yieldOverFullRange = false;
bool removeMultiple = false;
bool weighted = PHSP;
string signalShape = "OneCB";
string backgroundShape = "ExpGaus";
for (int n = 4; n < 5; n++){
if(massFit("2011", "both", Run,
PHSP, true, PHSP, PHSP,
UseOnlyJpsiEvents, UseOnlyMuMuEvents,
true, signalShape, backgroundShape, true,
KshortDecaysInVelo, UseLowQ2Range,
-1.0, false, UseFixedMassRegion,yieldOverFullRange,
false, false, false, "q2_binned", n, removeMultiple, weighted,
false, "",false,
"",gammaTMdefault,false) == 0)return 0;
}
return 1;
}
//Print efficiencies and fit parameters
int PrintFitResults(RooFitResult* fitRes){
RooArgSet fitargs = fitRes->floatParsFinal();
if (fitargs.getSize() <=0){
coutERROR("RooArgSet size is zero/nonDef!");
return 0;
}
TIterator* iter(fitargs.createIterator());
cout << " ======= results ====== " << endl;
for (TObject *a = iter->Next(); a != 0; a = iter->Next()) {
RooRealVar *rrv = dynamic_cast<RooRealVar *>(a);
string name = rrv->GetName();
cout<< name << ": " << rrv->getVal() <<" +/- "<<rrv->getError() << endl;
}
return 1;
}
int fitJpsi(string year, int Run, bool MC, double TMVAcut, bool RemoveMultiple){
return massFit(year,"both", Run,
MC, true, MC, false,
true, false,
!MC, "OneCB", "SingleExponential", true,
false,false,
TMVAcut, 0,
false, false,
false,
false, false,
"",-1,
RemoveMultiple,
false, false, "",
false, "", gammaTMdefault,
false);
}