//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);
}
