//Functions that calculate/fit the yield for given MVA response cut
//and make pretty plots from it
//Renata Kopecna

#include "GlobalFunctions.hh"
#include "Paths.hpp"
#include "MassFit.hpp"
#include "Utils.hpp"
#include "./BmassShape/SignalType.hpp"
#include "EfficiencyClass.cpp"


using namespace std;
using namespace RooFit;
using namespace RooStats;

class YieldInfo{
 public:
    string year;
    double sigYield;
    double sigYieldErr;
    double refYield;
    double refYieldErr;
    double bkgYield;
    double bkgYieldErr;
    double sigEff;
    double refEff;
    double allSigEvts;
    YieldInfo(){ //default constructor
        year        = "";
        sigYield    = 0;
        sigYieldErr = 0;
        refYield    = 0;
        refYieldErr = 0;
        bkgYield    = 0;
        bkgYieldErr = 0;
        sigEff      = 0;
        refEff      = 0;
        allSigEvts  = 0;
    }
    void addYield(YieldInfo addInfo){
        sigYield    += addInfo.sigYield;
        sigYieldErr += addInfo.sigYieldErr;
        refYield    += addInfo.refYield;
        refYieldErr += addInfo.refYieldErr;
        bkgYield    += addInfo.bkgYield;
        bkgYieldErr += addInfo.bkgYieldErr;
        sigEff      += addInfo.sigEff; //this doesn't make much sense
        refEff      += addInfo.refEff; //this doesn't make much sense
        allSigEvts  += addInfo.allSigEvts;
    }

    ~YieldInfo();   //destuctor
};

YieldInfo::~YieldInfo(){//destuctor

}

bool FixShape = true;

bool RemoveMultiple = true; //For now use as a global boolean

//Function that takes upper mass sideband histogram and fits it with an exponential
//Using a Tree, starting the upper mass sideband from range+PDGMASS.Bplus and possibly cutting away stuff defined by cut
double GetBackgroundFromSidebandFit(TChain *Tree, double range, string cut, string path){

    TString massBranch = UseDTF ? "B_plus_M" : "B_plus_DTF_M";
    bool savePlots = true;

    //Fill histogram from Tree
    int nBins = 50;
    TH1D *h_B_mass = new TH1D("h_B_mass","h_B_mass",nBins,PDGMASS.B_PLUS + range, cut_B_plus_M_high);
    double binWidth = (cut_B_plus_M_high - PDGMASS.B_PLUS - range)/nBins;
    Tree->Draw(massBranch+" >> h_B_mass",cut.c_str());

    //Define fit function
    TF1 *f_bkg = new TF1("f_bkg","expo",cut_B_plus_M_low,cut_B_plus_M_high);
    design_function(f_bkg,kRed,1);

    //Fit
    h_B_mass->Fit(f_bkg,"Q","", PDGMASS.B_PLUS + range,cut_B_plus_M_high); //exponential is f(x) = exp(p0+p1*x)
    double integral = f_bkg->Integral(PDGMASS.B_PLUS-range,PDGMASS.B_PLUS+range)/binWidth;

    //Save the plots
    if (savePlots){
        string name = path.substr(path.find("/Kplus")+6,path.length());
        //Create canvas
        TCanvas  *c = c_canvas(name);
        c->cd();
        design_TH1D(h_B_mass,"B^{+} mass [MeV]","Counts a.u.", kBlack);
        h_B_mass->GetYaxis()->SetTitleOffset(1.05);
        h_B_mass->Draw();
        //Create TPaveText
        TPaveText *fitParams= new TPaveText(0.6,0.7,0.87,0.9,"NDC");
        fitParams->SetFillColor(kWhite);
        fitParams->AddText(Form("Offset : %.2f ",  f_bkg->GetParameter(0)));
        fitParams->AddText(Form("Exp: %.2f%%", f_bkg->GetParameter(1)*100));
        fitParams->AddText(Form("Integral: %.2f ", integral));
        fitParams->Draw("SAME");

        //Create file
        TFile *fitFile  = new TFile(path.c_str(),"RECREATE");
        coutDebug("Opening " + string(fitFile->GetPath()));
        fitFile->cd();
        h_B_mass->Write();
        f_bkg->Write();
        c->Write();
        replace(path,".root",".eps");
        c->SaveAs(path.c_str(), ".eps");
        fitFile->Close();
    }
    //return the integral
    h_B_mass->Clear();
    return integral;

}

double GetMVAefficiency(string year, int Run, bool KshortDecaysInVelo,
                        bool UseLowQ2Range, bool IncludeMultipleEff, bool sig, double TMVAcut){
    //Load the efficiencies
    coutDebug("Openning MVA efficiency files.");
    string path = GetEfficiencyFile("BDT", year, "both", Run, !sig, sig,  false, KshortDecaysInVelo, IncludeMultipleEff, true, UseLowQ2Range, false,"");

    if (Run == 0 && std::stoi(year) > 2016 && !sig) replace(path,year,"2016"); //RefChann available for 2015-2016
    if (Run == 0 && year=="2015" && sig) replace(path,year,"2016");            //No reasonable MC for 2015

    coutDebug("Openning file: " + path);
    TFile * effFile = new TFile(path.c_str(), "OPEN");

    //Get the TGraphs
    coutDebug("File opened, getting the graphs now.");
    string graphName = "effScan_" + (Run ==0 ? year : "Run" + to_string(Run));
    if (Run == 0 && std::stoi(year) > 2016) replace(graphName,year,"2016");
    if (Run == 0 && year=="2015" && sig)    replace(graphName,year,"2016");
    coutDebug("\t" + graphName);

    TGraphErrors *effGraph= (TGraphErrors*)effFile->Get(TMVAmethod+graphName.c_str());
    double efficiency = effGraph->Eval(TMVAcut);

    coutDebug(string(sig ? "Signal   " : "Reference") +" MVA efficiency: " + to_string(efficiency));

    //Close the efficiency files
    effFile->Close();
    return efficiency;

}

double GetSelectionEfficiency(string year, int Run, bool KshortDecaysInVelo,
                              bool UseLowQ2Range, bool RemoveMultiple, bool sig){
    //Load the efficiencies
    coutDebug("Openning efficiency files.");
    EffAndError eff = getSelectionEfficiencySimple(true,year,Run,sig,!sig, false, KshortDecaysInVelo, RemoveMultiple, true, "", -1, "", gammaTMdefault);

    coutDebug(string(sig ? "Signal   " : "Reference") +" selection efficiency: " + to_string(eff.value));

    //Close the efficiency files
    return eff.value;
}


string GetBackgroundFunction(bool KshortDecaysInVelo){    //Set signal and background function separately for each decay channel
    string BackGroundFunction = "SingleExponential";
    if(Kst2Kspiplus){
        if(KshortDecaysInVelo) BackGroundFunction = "SingleExponential";
        else                   BackGroundFunction = "DoubleExponential";
    }
    return BackGroundFunction;
}

//Takes yield from the reference channel,
YieldInfo GetSigAndBkgEstimation(string year, int Run, bool KshortDecaysInVelo,
                                 bool UseLowQ2Range, Double_t TMVAcut, bool scan){

    bool fixedMassRegion = !Kst2Kspiplus; //Calculates the signal from +- 100 MeV or +- SignalRegionNsigma*effective sigma

    //initialize the struct
    YieldInfo yield = YieldInfo();
    yield.year = year;

    bool RemoveMultiple = true;

    //Set signal and background function separately for each decay channel
    string SignalFunction = "OneCB";
    string BackGroundFunction = GetBackgroundFunction(KshortDecaysInVelo);

    //Get the reference signal yield
    if (!scan){
        coutInfo("Running the fit!");
        yield.refYield = basicYieldFit(year,Run,
                                       false, false, true, false,
                                       FixShape, SignalFunction, BackGroundFunction, FixShape,
                                       KshortDecaysInVelo, UseLowQ2Range,
                                       TMVAcut, fixedMassRegion, true, RemoveMultiple);
    }

    //Load the file from fitting
    TFile *fitFile  = new TFile(GetMassFitFile(year, Run,
                                               false, false, true, false,
                                               FixShape, SignalFunction, BackGroundFunction, FixShape,
                                               KshortDecaysInVelo, UseLowQ2Range,
                                               TMVAcut, fixedMassRegion, RemoveMultiple).c_str(),"OPEN");

    coutDebug("Opening " + string(fitFile->GetPath()));

    if (scan) yield.refYield = getSigYield(fitFile);
    double effSigma = fixedMassRegion ? B_plus_M_signal_window : getEffSigma(fitFile);

    if (yield.refYield == 0) coutWarning("Reference channel yield is zero!");

    yield.sigEff = GetMVAefficiency(year,Run,KshortDecaysInVelo,UseLowQ2Range,RemoveMultiple,true,TMVAcut) * GetSelectionEfficiency(year, Run, KshortDecaysInVelo, UseLowQ2Range, !RemoveMultiple, true);
    yield.refEff = GetMVAefficiency(year,Run,KshortDecaysInVelo,UseLowQ2Range,RemoveMultiple,false,TMVAcut) * GetSelectionEfficiency(year, Run, KshortDecaysInVelo, UseLowQ2Range, !RemoveMultiple, false);

    coutDebug("Sig Yield efficiency = " + to_string(yield.sigEff));
    coutDebug("Ref Yield efficiency = " + to_string(yield.refEff));

    //Calculate the signal yield from reference yield, efficiencies and the Jpsi->mumu BR
    yield.sigYield = BR_sig / BR_ref * yield.refYield * yield.sigEff/yield.refEff;

    //Get the background yield from side band
    TChain * tree   = new TChain("DecayTree");

    std::vector<string> years;
    if (Run == 0) years.push_back(year);
    else years = yearsData(Run);

    for (auto& yr : years){
        string BDToutputPath = GetBDToutputFile(yr,getRunID(yr),false,false,false,KshortDecaysInVelo,UseLowQ2Range,false);
        tree->Add(BDToutputPath.c_str());
        coutDebug("Opening " + BDToutputPath);
    }

    string sVariable = (UseDTF ? "B_plus_M_DTF" : "B_plus_M");
    string cutMass = Form("%s > %f && %s < %f",
                           sVariable.c_str(), getBplusMeanFromResult(fitFile) -  effSigma, sVariable.c_str(),
                           getBplusMeanFromResult(fitFile) + effSigma);
    coutDebug("B mass cut: " + cutMass);

    //cut away Jpsi
    string cut = getFinalCut(false, false, false, "", gammaTMdefault, true, false, false, false, false, TMefficiencyClass(), -1, TMVAcut, RemoveMultiple);
    coutDebug("Using cut " + cut);

    //Get background estimation from sideband
    string bkgFitPath = GetBDTScanBackgroundFitFile(year,Run,KshortDecaysInVelo,UseLowQ2Range,TMVAcut);
    yield.bkgYield = GetBackgroundFromSidebandFit(tree, fixedMassRegion ? effSigma : B_plus_M_signal_window, cut, bkgFitPath);
    cut = cut + " && (" + cutMass + ")";
    coutDebug("Using cut " + cut);

    //data: create histograms from tree
    tree->Draw(Form("%s>>B_plus_M_plot", sVariable.c_str()), cut.c_str());
    TH1 * histo = ((TH1 *) gPad->GetPrimitive("B_plus_M_plot"));
    Int_t EventsAfterPreSelection = histo->GetEntries();

    yield.allSigEvts = EventsAfterPreSelection;

    //Print signal, background and all evts
    string trackType = (Kst2Kspiplus && SplitDDandLL ? (KshortDecaysInVelo ? "LL Tracks: " : "DD Tracks: ") : ":");
    coutDebug(TheDecay + "[SIGNAL]: "  + trackType + to_string(yield.sigYield));
    coutDebug(TheDecay + "[BCKGND]: "  + trackType + to_string(yield.bkgYield));
    coutDebug(TheDecay + "[ALLEVTS]: " + trackType + to_string(yield.allSigEvts));

    coutInfo("Expected yield is: " + to_string(yield.sigYield) + "\t+-" + to_string(yield.sigYieldErr));

    return yield;
}

YieldInfo GetSigAndBkgEstimationFromData(string year = "2011", int Run = 0, int randomSubset = 0,
                                         bool KshortDecaysInVelo = false, bool UseLowQ2Range = false,
                                         Double_t TMVAcut = -1.0, bool scan = false){
    gStyle->SetOptStat(0);
    LHCbStyle();

    bool fixedMassRegion = !Kst2Kspiplus; //Fix it in pi0 channel //TODO
    string magnet = "both"; //prepare in case of polarity studies

    //initialize the struct
    YieldInfo yield = YieldInfo();
    yield.year = year;

    //Set signal and background function separately for each decay channel
    string SignalFunction = "OneCB";
    string BackGroundFunction = GetBackgroundFunction(KshortDecaysInVelo);

    if (!scan) { //Do the fit first
        yield.refYield = massFit(year,magnet,Run,
                                 false, true, false, false,
                                 true, false,
                                 FixShape, SignalFunction, BackGroundFunction, FixShape,
                                 KshortDecaysInVelo, UseLowQ2Range,
                                 TMVAcut, randomSubset,
                                 fixedMassRegion, false,
                                 false, true, false,
                                 "", -1,
                                 RemoveMultiple, true,
                                 false, "", false,
                                 "", gammaTMdefault, false);
        yield.sigYield = massFit(year,magnet,Run,
                                 false, true, false, false,
                                 false, true,
                                 FixShape, SignalFunction, BackGroundFunction, FixShape,
                                 KshortDecaysInVelo, UseLowQ2Range,
                                 TMVAcut, randomSubset,
                                 fixedMassRegion, false,
                                 false, true, false,
                                 "", -1,
                                 RemoveMultiple, true,
                                 false, "", false,
                                 "", gammaTMdefault, false);
    }    
    //Load fit results now:

    // Get reference yield
    TFile *fitFileRef  = new TFile(GetMassFitFile(year, magnet, Run,
                                                  false, true, false, false,
                                                  true, false,
                                                  FixShape, SignalFunction, BackGroundFunction, FixShape,
                                                  KshortDecaysInVelo, UseLowQ2Range,
                                                  TMVAcut, randomSubset,
                                                  fixedMassRegion, false,
                                                  "", -1,
                                                  RemoveMultiple, false, //Data cannot be weighted technically, so the name is without "weighted"
                                                  false, "", false,
                                                  "", gammaTMdefault, false).c_str(),"OPEN");

    coutDebug("Opening " + string(fitFileRef->GetPath()));
    yield.refYield    = getSigYield(fitFileRef);
    yield.refYieldErr = getSigYieldErr(fitFileRef);
    fitFileRef->Close();

    // Get signal yield
    TFile *fitFile  = new TFile(GetMassFitFile(year, magnet, Run,
                                               false, true, false, false,
                                               false, true,
                                               FixShape, SignalFunction, BackGroundFunction, FixShape,
                                               KshortDecaysInVelo, UseLowQ2Range,
                                               TMVAcut, randomSubset,
                                               fixedMassRegion, false,
                                               "", -1,
                                               RemoveMultiple, false, //Data cannot be weighted technically, so the name is without "weighted"
                                               false, "", false,
                                               "", gammaTMdefault, false).c_str(),"OPEN");

    coutDebug("Opening " + string(fitFile->GetPath()));
    yield.sigYield    = getSigYield(fitFile);
    yield.sigYieldErr = getSigYieldErr(fitFile);
    yield.bkgYield    = getBkgYield(fitFile);
    yield.bkgYieldErr = getBkgYieldErr(fitFile);
    double mean_sig = getBplusMeanFromResult(fitFile);
    double effSigma = fixedMassRegion ? B_plus_M_signal_window : getEffSigma(fitFile);
    fitFile->Close();

    //Get the number of all events in the signal region
    TChain * tree   = new TChain("DecayTree");
    std::vector<string> years;
    if (Run == 0) years.push_back(year);
    else years = yearsData(Run);

    for (auto& yr : years){
        string BDToutputPath = GetBDToutputFile(yr,getRunID(yr),false,false,false,KshortDecaysInVelo,UseLowQ2Range,false);
        tree->Add(BDToutputPath.c_str());
        coutDebug("Opening " + BDToutputPath);
    }

    coutDebug("eff sigma: " + to_string(effSigma));
    string sVariable = (UseDTF ? "B_plus_M_DTF" : "B_plus_M");
    string cutMass = Form("%s > %f && %s < %f",
                           sVariable.c_str(), mean_sig -  effSigma, sVariable.c_str(),
                          mean_sig + effSigma);
    coutDebug("B mass cut: " + cutMass);

    //cut away resonances
    string cut = getFinalCut(false, false, false, "", gammaTMdefault, true, false, false, false, false, TMefficiencyClass(), -1, TMVAcut, RemoveMultiple);
    coutDebug("Using cut " + cut);

    //data: create histograms from tree
    tree->Draw(Form("%s>>B_plus_M_plot", sVariable.c_str()), cut.c_str());
    TH1 * histo = ((TH1 *) gPad->GetPrimitive("B_plus_M_plot"));
    Int_t EventsAfterPreSelection = histo->GetEntries();

    yield.allSigEvts = EventsAfterPreSelection;

    //Print signal, background and all evts
    string trackType = (Kst2Kspiplus && SplitDDandLL ? (KshortDecaysInVelo ? "LL Tracks: " : "DD Tracks: ") : ":");
    coutDebug(TheDecay + "[SIGNAL]: "  + trackType + to_string(yield.sigYield));
    coutDebug(TheDecay + "[BCKGND]: "  + trackType + to_string(yield.bkgYield));
    coutDebug(TheDecay + "[ALLEVTS]: " + trackType + to_string(yield.allSigEvts));

    coutInfo("Expected yield is: " + to_string(yield.sigYield) + "\t+-" + to_string(yield.sigYieldErr));
    coutDebug("Signal yield error: " + to_string(yield.sigYieldErr));
    coutDebug("Background yield error: " + to_string(yield.bkgYieldErr));
    coutDebug("Reference channel  yield error: " + to_string(yield.refYieldErr));

    if (yield.refYield == 0) coutERROR("Reference channel yield is zero!");
    if (yield.sigYield == 0) coutERROR("Signal channel yield is zero! Abort.");

    return yield;

}

int SaveTGraphs(string path, bool fineScan, string year, int Run, string basicPath,
                TGraphErrors *yieldGraph, TGraphErrors *bkgGraph, TGraphErrors *bkgGraphFromAllEvts, TGraphErrors *refYieldGraph, TGraphErrors *allEvtsInSig, TGraphErrors *significance, TGraphErrors *significanceFromAllEvts){

    coutInfo("Making pretty plots and saving them!");
    coutDebug("Writting into " + path);
    coutDebug("Using basicPath " + basicPath);

    TFile * TGraphOutput = new TFile(path.c_str(), "RECREATE");
    TGraphOutput->cd();

    designYieldGraph(yieldGraph,              Run, year, "sigYield",                 basicPath, TGraphOutput, false);
    designYieldGraph(bkgGraph,                Run, year, "bkgYield",                 basicPath, TGraphOutput, false);
    designYieldGraph(bkgGraphFromAllEvts,     Run, year, "bkgYield_fromAllEvts",     basicPath, TGraphOutput, fineScan);
    designYieldGraph(refYieldGraph,           Run, year, "refYield",                 basicPath, TGraphOutput, fineScan);
    designYieldGraph(significance,            Run, year, "significance",             basicPath, TGraphOutput, false);
    designYieldGraph(significanceFromAllEvts, Run, year, "significance_fromAllEvts", basicPath, TGraphOutput, fineScan);
    designYieldGraph(allEvtsInSig,            Run, year, "EventsInSigRegion",        basicPath, TGraphOutput, false);

    TGraphOutput->Close();
    return 1;


}

int ScanSignalAndBckgndEstimation(string year, int Run, Double_t BDTstep, bool KshortDecaysInVelo, bool UseLowQ2Range, bool scan, bool fineScan){
    //If Run==0, do the scan for year, if Run == 1/2, do the scan per run

    if (verboseLevel > 1)RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);

    bool section = true; //In case of fine scan, section the scan in more fine way
    int n_divisions = 3;

    //Get low TMVA response lower boundary
    Double_t lowBDTcut = (TMVAmethod == "MLP") ? 0.0 : -1.0;
    if (fineScan){
        coutInfo("Making fine BDT cut study.");
        lowBDTcut = 0.9;
        BDTstep =   0.001;
    }

    //prepare in case of polarity studies
    string magnet = "both";

    TGraphErrors *yieldGraph = new TGraphErrors();
    TGraphErrors *bkgGraph = new TGraphErrors();
    TGraphErrors *bkgGraphFromAllEvts = new TGraphErrors();
    TGraphErrors *refYieldGraph = new TGraphErrors();
    TGraphErrors *significance = new TGraphErrors();
    TGraphErrors *significanceFromAllEvts = new TGraphErrors();
    YieldInfo yield = YieldInfo(); //put zeroes everywhere

    //loop over BDT cuts
    coutInfo("Loop over BDT cuts with a step of " + to_string(BDTstep));
    coutDebug("Starting the loop at " + to_string(lowBDTcut));
    double tmpBDTcut = 0.0;

    for(double fBDTcut = lowBDTcut; fBDTcut < (section ? 0.999 : 1.0); fBDTcut += section ? ((1.0-fBDTcut)/double(n_divisions)) : BDTstep){
        for (int k = 0; k < n_divisions; k++){
            tmpBDTcut = fBDTcut + k*(1.0-fBDTcut)/double(n_divisions);
            yield = GetSigAndBkgEstimation(year, Run, KshortDecaysInVelo, UseLowQ2Range, tmpBDTcut, scan);
            yieldGraph              ->SetPoint(yieldGraph->GetN(),          tmpBDTcut, yield.sigYield);
            bkgGraphFromAllEvts     ->SetPoint(bkgGraphFromAllEvts->GetN(), tmpBDTcut, yield.allSigEvts-yield.sigYield);
            bkgGraph                ->SetPoint(bkgGraph->GetN(),            tmpBDTcut, yield.bkgYield);
            refYieldGraph           ->SetPoint(yieldGraph->GetN(),          tmpBDTcut, yield.refYield);
            significance            ->SetPoint(significance->GetN(),        tmpBDTcut, yield.sigYield / (TMath::Sqrt(yield.sigYield + yield.bkgYield)));
            significanceFromAllEvts ->SetPoint(significance->GetN(),        tmpBDTcut, yield.sigYield / (TMath::Sqrt(yield.allSigEvts)));
            coutDebug("---" + string(TMVAmethod) + " cut " + to_string(tmpBDTcut) + " yield: " + to_string(yield.sigYield) + ", background: " + to_string( yield.allSigEvts-yield.sigYield ));
        }
    }

    //Write to file and close
    string path = GetBDTScanFile(year, magnet, Run, KshortDecaysInVelo, UseLowQ2Range, fineScan);
    SaveTGraphs(path,fineScan,year,Run,path,yieldGraph,bkgGraph,bkgGraphFromAllEvts,refYieldGraph,NULL,significance,significanceFromAllEvts);

    coutInfo("Signal scan done for year " + year + "!");
    return 1;

}

int ScanSignalAndBckgndEstimationPerYear(string year = "2011", Double_t BDTstep = 0.01, bool KshortDecaysInVelo = true, bool UseLowQ2Range = false, bool scan = false, bool fineScan = false){
    return ScanSignalAndBckgndEstimation(year = "2011", 0, BDTstep, KshortDecaysInVelo, UseLowQ2Range, scan, fineScan);
}
int ScanSignalAndBckgndEstimationAllYears(Double_t BDTstep = 0.01, bool KshortDecaysInVelo = true, bool UseLowQ2Range = false, bool scan = false, bool fineScan = true){
    for (auto yr: yearsData(12)) ScanSignalAndBckgndEstimationPerYear(yr, BDTstep, KshortDecaysInVelo, UseLowQ2Range, scan, fineScan);
    return 1;
}

int ScanSignalAndBckgndEstimationSimple(string year = "2011",int Run = 1, Double_t BDTstep = 0.01, int randomSubset = 0,
                                        bool KshortDecaysInVelo = true, bool UseLowQ2Range = false, bool scan = false, bool fineScan = true){
    //Get low TMVA response lower boundary

    double lowBDTcut = (TMVAmethod == "MLP") ? 0.0 : -1.0;
    if (fineScan){
        coutInfo("Making fine BDT cut study.");
        lowBDTcut = 0.9;
        BDTstep = 0.002;
    }
    bool halve = true;


    //prepare in case of polarity studies
    string magnet = "both";

    TGraphErrors *yieldGraph = new TGraphErrors();
    TGraphErrors *bkgGraph = new TGraphErrors();
    TGraphErrors *bkgGraphFromAllEvts = new TGraphErrors();
    TGraphErrors *refYieldGraph = new TGraphErrors();
    TGraphErrors *allEvtsInSig = new TGraphErrors();
    TGraphErrors *significance = new TGraphErrors();
    TGraphErrors *significanceFromAllEvts = new TGraphErrors();
    YieldInfo yield = YieldInfo(); //put zeroes everywhere

    //loop over BDT cuts
    coutInfo("Loop over BDT cuts with a step of " + to_string(BDTstep));
    coutDebug("Starting the loop at " + to_string(lowBDTcut));
    int n_divisions = halve ? 3 : 1;
    double tmpcut = 0.0;
    for(double fBDTcut = lowBDTcut; fBDTcut < (halve ? 0.9999 : 1); fBDTcut += halve ? ((1.0-fBDTcut)/double(n_divisions)) : BDTstep){
        for (int k = 0; k < n_divisions-1; k++){
            tmpcut = fBDTcut + k*(1.0-fBDTcut)/double(n_divisions);
            coutDebug("Cutting at: " + to_string(tmpcut));
            yield =GetSigAndBkgEstimationFromData(year,Run, randomSubset, KshortDecaysInVelo, UseLowQ2Range, tmpcut, scan);
            //Save the efficiency
            yieldGraph              ->SetPoint(yieldGraph->GetN(),          tmpcut, yield.sigYield);
            yieldGraph              ->SetPointError(yieldGraph->GetN()-1,   0,       yield.sigYieldErr);
            bkgGraph                ->SetPoint(bkgGraph->GetN(),            tmpcut, yield.bkgYield);
            bkgGraph                ->SetPointError(bkgGraph->GetN()-1,     0,       yield.bkgYieldErr);
            bkgGraphFromAllEvts     ->SetPoint(bkgGraph->GetN(),            tmpcut, yield.allSigEvts-yield.sigYield);
            refYieldGraph           ->SetPoint(yieldGraph->GetN(),          tmpcut, yield.refYield);
            refYieldGraph           ->SetPointError(yieldGraph->GetN()-1,   0,       yield.refYieldErr);
            allEvtsInSig            ->SetPoint(allEvtsInSig->GetN(),        tmpcut, yield.allSigEvts);
            significance            ->SetPoint(significance->GetN(),        tmpcut, yield.sigYield / (TMath::Sqrt(yield.sigYield+yield.bkgYield)));
            significanceFromAllEvts ->SetPoint(significance->GetN(),        tmpcut, yield.sigYield / (TMath::Sqrt(yield.allSigEvts)));
            coutDebug("---" + string(TMVAmethod) + " cut " + to_string(tmpcut) + " yield: " + to_string(yield.sigYield) + ", background: " + to_string( yield.allSigEvts-yield.sigYield ));
        }
    }

    //Write to file and close //TODO at some point
    string path = GetBDTScanFile(year, magnet, Run, KshortDecaysInVelo, UseLowQ2Range, fineScan);
    replace(path, ".root", "fromData.root");
    if (randomSubset == -1) replace(path,".root","_subset1.root");
    if (randomSubset ==  1) replace(path,".root","_subset2.root");
    SaveTGraphs(path,fineScan,year,0,path,yieldGraph,bkgGraph,bkgGraphFromAllEvts,refYieldGraph,NULL,significance,significanceFromAllEvts);

    coutInfo("Signal scan done for Run " + to_string(Run) + "!");
    return 1;
}

int ScanSignalAndBckgndEstimationSimplePerYear(string year = "2011", Double_t BDTstep = 0.01, int randomSubset = 0, bool KshortDecaysInVelo = true, bool UseLowQ2Range = false, bool scan = false, bool fineScan = true){
    return ScanSignalAndBckgndEstimationSimple(year = "2011", 0, BDTstep, randomSubset, KshortDecaysInVelo, UseLowQ2Range, scan, fineScan);
}

int ScanSignalAndBckgndEstimationSimpleAllYears(Double_t BDTstep = 0.01, int randomSubset = 0, bool KshortDecaysInVelo = true, bool UseLowQ2Range = false, bool scan = false, bool fineScan = true){
    for (auto yr: yearsData(12)) ScanSignalAndBckgndEstimationSimplePerYear(yr, BDTstep, randomSubset, KshortDecaysInVelo, UseLowQ2Range, scan, fineScan);
    return 1;
}

double getMaxBDTresponse(string year = "2011", int Run = 0,  bool fineScan = false, bool directScan = false, int randomSubset = 0, bool KshortDecaysInVelo = true, bool UseLowQ2Range  = false){

    //prepare in case of polarity studies
    string magnet = "both";

    if (Run == 0) coutInfo("Getting BDTresponse with highest significance for YEAR " + year + ". .  .");
    else          coutInfo("Getting BDTresponse with highest significance for RUN "+to_string(Run)+". .  .");

    string path = GetBDTScanFile(year, magnet, Run, KshortDecaysInVelo, UseLowQ2Range, fineScan);
    if (directScan) replace(path, ".root", "fromData.root");
    if (randomSubset == -1) replace(path,".root","_subset1.root");
    if (randomSubset ==  1) replace(path,".root","_subset2.root");

    TGraphErrors *significance = new TGraphErrors();
    TFile *scanFile = new TFile(path.c_str(),"OPEN");
    string graphName = "significance_fromAllEvts";
    significance = (TGraphErrors*) scanFile->Get(graphName.c_str());
    if(significance == NULL){
        coutERROR("TGraphError was not found in the file!");
        coutERROR("File:\t" + path);
        coutERROR("TGraph:\t" + graphName);
        return 0;
    }

    //Get the best BDTcut
    double LargestFoM = -100.;
    double bestCut = 0.0;
    for(int p = 0; p < significance->GetN(); p++){
        if(significance->GetY()[p] > LargestFoM){
            LargestFoM  = significance->GetY()[p];
            bestCut     = significance->GetX()[p];
        }
    }
    return bestCut;
}

int optimizeBDTCut(string year = "2011", int Run = 0, bool KshortDecaysInVelo = true, Double_t BDTstep = 0.01, bool UseRandomSubset = false,
                       bool UseLowQ2Range  = false, bool scan = false, bool fineScan = false, bool directScan = false){

    //Get low TMVA response lower boundary
    double lowBDTcut = (TMVAmethod == "MLP") ? 0.0 : -1.0;
    if (fineScan){
        coutInfo("Making fine BDT cut study.");
        lowBDTcut = 0.9;
        BDTstep = 0.002;
    }

    double BestCut = 0;

    if (directScan){
        if (UseRandomSubset){
            ScanSignalAndBckgndEstimationSimple(year, Run, BDTstep, -1, KshortDecaysInVelo, UseLowQ2Range, scan, fineScan);
            ScanSignalAndBckgndEstimationSimple(year, Run, BDTstep, +1, KshortDecaysInVelo, UseLowQ2Range, scan, fineScan);
            double BestCut1 = getMaxBDTresponse(year, Run, fineScan, true, -1, KshortDecaysInVelo, UseLowQ2Range);
            double BestCut2 = getMaxBDTresponse(year, Run, fineScan, true, +1, KshortDecaysInVelo, UseLowQ2Range);
            BestCut = roundf(BestCut1 * 100) / 100 +roundf(BestCut2 * 100); // round to 2 decimal points, return e.g. 0.96 + 94 (easy to untangle)
        }
        else{
            ScanSignalAndBckgndEstimationSimple(year, Run, BDTstep, 0, KshortDecaysInVelo, UseLowQ2Range, scan, fineScan);
            BestCut = getMaxBDTresponse(year, Run, fineScan, true, 0, KshortDecaysInVelo,  UseLowQ2Range);
        }

        //TODO
    }
    else{ //TODO: add subset fits
        if (Run == 0){
            ScanSignalAndBckgndEstimationPerYear(year,BDTstep,KshortDecaysInVelo,UseLowQ2Range,scan,fineScan);
        }
        else{
            ScanSignalAndBckgndEstimation(year,Run,BDTstep,KshortDecaysInVelo,UseLowQ2Range,scan,fineScan);
        }
        //TODO make a pretty plot

        BestCut = getMaxBDTresponse(year, Run, fineScan, false, 0, KshortDecaysInVelo, UseLowQ2Range);

    }

    return BestCut;

}
