//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 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 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; eGetEntries();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 UseOnlyJpsiEvents = {true,false}; vector UseOnlyMuMuEvents = {true,false}; vector 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 years = yearsData(Run); std::vector signalShape = {//"SingleGaussian", "DoubleGaussian", //"CBLeft", //"CBRight", "CBDouble" }; std::vector backgroundShape = {//"SingleExponential", "DoubleExponential", "ExpGaus" }; std::vector 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(a); string name = rrv->GetName(); cout<< name << ": " << rrv->getVal() <<" +/- "<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); }