//Renata Kopecna

#include <momfit.hh>
#include <fitter.hh>
#include <folder.hh>
#include <paths.hh>
#include <funcs.hh>
#include <design.hh>
#include <event.hh>

#include <constants.hh>
#include <bu2kstarmumu_pdf.hh>
#include <bu2kstarmumu_plotter.hh>
#include <bu2kstarmumu_parameters.hh>
#include <bu2kstarmumu_generator.hh>

#include <spdlog.h>

#include <TRandom3.h>
#include <TTree.h>

//background coefficients, obtained from fits to the sideband data of the rare channel (David thinks)
//4 cause David had 4 PDFs
const double Bctl1[4] = { 0.11700, -0.0568,  0.0367,  0.0160};
const double Bctl2[4] = {-0.0697, -0.1243, -0.0788, -0.1197};
const double Bctk1[4] = { 0.0720,  0.4544,  0.0761,  0.2105};
const double Bctk2[4] = { 0.1652,  0.2065,  0.1177,  0.1951};

//Obtained from MC //TODO //Taken from main fit, update when fixed
const double f_m_B[4]      = {5282.32, 5282.08, 5278.57, 5279.48};
const double f_lambda1[4]  = {-0.00386, -0.00610, -0.00362, -0.00578};
const double f_lambda2[4]  = {-0.03320, -0.00120, -0.04600, -0.00100};
const double f_alpha_1[4]  = { 1.7910,  1.8000,  1.6510,  1.5400};
const double f_alpha_2[4]  = { 2.3200,  2.4300,  2.0100,  2.2500};
const double f_n_1[4]      = { 1.4400,  1.4900,  1.6800,  1.6100};
const double f_n_2[4]      = { 2.8900,  3.7000,  3.8700,  3.7000};
const double f_sigma_1[4]  = {14.8300, 15.4800, 14.8400, 14.4};
const double f_sigma_2[4]  = {14.0700, 13.1000, 15.6200, 13.3};
const double f_f_CB[4]     = { 0.6360,  0.3600,  0.3040,  0.6200};
const double f_m_scale[4]  = { 1.1814,  1.0648,  1.1547,  1.1168};
//Obtained from MC //TODO //Taken from main fit, update when fixed
///including the first q2bin: //TODO: get from my MC
const std::vector<double> FL_scale = {0.4836193455050577, 1.2251014138607774, 1.274499551405837, 1.1368614009399862};

//Obtained from MC //TODO //Taken from main fit, update when fixed
const std::vector<double> FL_scale_toys = { //TODO Get from my MC!
                0.5,   //scaled from average of bin 1-4
                1.0 + 0.07 /  (61.*4) * (61.+  62.+  96.+ 125.),
                1.0 + 0.12 /  (62.*4) * (61.+  62.+  96.+ 125.),
                1.0 - 0.02 /  (96.*4) * (61.+  62.+  96.+ 125.),
                1.0 - 0.17 / (125.*4) * (61.+  62.+  96.+ 125.),
                1.0,//evaluated by itself
                1.0 + 0.04 / (129. * 2) * (129. + 69.),
                1.0 - 0.04 /  (69. * 2) * (129. + 69.),
};




//TODO: not used at the moment, check for constants and everything before usage


int momfit(fcnc::options opts,
           bool fitReference, bool fitSignalMC, bool fitData, bool blind,
           bool Fit1bin, bool Fit2bins, bool FitAllbins){

    if (fitReference) spdlog::info("[MOM]\t\tMoM from reference channel: J/psi K*+");
    // (jobs_to_do[7]) //reference channel only
    if (fitSignalMC)  spdlog::info("[MOM]\t\tMoM from signal fitSignalMC");
    //if(jobs_to_do[8]) //signal fitSignalMC only
    if (fitData) spdlog::info("[MOM]\t\tMoM signal data");
    // if(jobs_to_do[9]) //signal data << FINAL FIT!!
    //const bool blind            = jobs_to_do[9];

    //have extra option for the usage of binning:
    const bool SimultaneousMoM  = fitReference;
    const bool SimultaneousFit  = true;
    const bool UseAccPerRun     = true;
    const bool UseAccPer2Years  = true;
    const bool LargeBinning     = !fitSignalMC && !fitReference && !fitData;
    const bool WeightedFit      = true;
    const bool OnlyBackground   = false;
    const bool OnlySignal       = false;
    const bool OneFit           = !fitSignalMC && !fitReference && !SimultaneousFit;
    const bool FitR             = fitReference;
    const bool SystematicsWithToys = opts.systematic == 0;
    if (!fitSignalMC && SystematicsWithToys){
        spdlog::critical("Cannot run data AND generate toys for systematics!");
        return 2; //TODO: decide what error is for wrong parameters
    }
    const bool FitFinalToySamples = false;
    const bool FSfrom2DLargeBins = !fitSignalMC && !fitReference && !LargeBinning && !SystematicsWithToys && !FitFinalToySamples;

    const bool UseExternalFS = true;
    const bool FixFStoStart  = false;
    const bool FitOnlyMagDown = opts.job_id == 3 && !SystematicsWithToys;
    const bool FitOnlyMagUp   = opts.job_id == 4 && !SystematicsWithToys;

    const bool LargerMKpiRange = false;

    const bool NP = false;

    //TODO: big time, go through the couts and the constants here
    if(!fitReference && !fitSignalMC) opts.plots_m_bins = 50;

    assert(!OneFit || !SimultaneousMoM);

    if(fitReference){
        opts.TheQ2binsmin = {8.68};
        opts.TheQ2binsmax = {10.09};
    }
    else if(LargeBinning){
        opts.TheQ2binsmin = {1.0, 11.0, 15.0};
        opts.TheQ2binsmax = {8.0, 12.5, 19.0};
    }
    if(fitSignalMC && !fitReference){ //Fit also Jpsi region in fitSignalMC
        opts.TheQ2binsmin.push_back(8.68);
        opts.TheQ2binsmax.push_back(10.09);
    }

    if(LargerMKpiRange){
        opts.mkpi_min -= 50.;
        opts.mkpi_max += 50.;
    }

    opts.write_eps = !(FitOnlyMagDown || FitOnlyMagUp || SystematicsWithToys || FitFinalToySamples);
    opts.write_C   = !(FitOnlyMagDown || FitOnlyMagUp || SystematicsWithToys || FitFinalToySamples);

    //configurate for 2D mass fit to obtain sWeights
    opts.only_mass2DFit = true;
    opts.only_angles = false;
    opts.only_Bmass = false;
    opts.squared_hesse = !fitData;
    opts.minos_errors = false;
    opts.weighted_fit = WeightedFit;
    opts.fit_mkpi = true;
    opts.use_mkpi = false;
    opts.generate_mkpi = true;
    opts.simple_mkpi = false;
    opts.isobar = false;
    opts.shift_lh = false;
    opts.swave = (opts.use_mkpi || opts.fit_mkpi) && !(fitSignalMC || OnlyBackground);
    opts.extended_ml = !fitSignalMC && !OnlyBackground && !OnlySignal; //extended maximum likelyhood
    //Needed for sWeights

    opts.fit_fl = !fitData && SystematicsWithToys;
    opts.fit_afb = opts.fit_fl;

    opts.full_angular = true;

    //how many individual pdfs are used?
    const UInt_t nPDFs = 2;

    std::vector< std::string > samplename;
    samplename.push_back("Run1 DD"); //TODO
    samplename.push_back("Run1 LL");
    samplename.push_back("Run2 DD");
    samplename.push_back("Run2 LL");

    //load events from data tuple:
    std::vector<fcnc::event>events[nPDFs];
    //TODO
    if(FitFinalToySamples){
        events[0] = fcnc::load_events(get_finalToySamplePath(0,opts.job_id,fitReference), "Events", -1); //Run1
        events[1] = fcnc::load_events(get_finalToySamplePath(1,opts.job_id,fitReference), "Events", -1); //Run2
    }
    else{
        events[0] = fcnc::load_events(get_theFCNCpath(fitSignalMC,1), "Events", -1); //Run1
        events[1] = fcnc::load_events(get_theFCNCpath(fitSignalMC,2), "Events", -1); //Run2
    }

    spdlog::info("Events:");
    for(UInt_t n = 0; n < nPDFs; n++){
        std::cout << samplename.at(n) << ":\t" << (blind ? "Larger 1 " : std::to_string(events[n].size())) << std::endl;
        assert(events[n].size() || SystematicsWithToys);
    }

    TRandom3 * rnd = new TRandom3(0);

    //determine number of bins:
    const UInt_t nBins = opts.TheQ2binsmin.size();
    std::vector<int>fit_results[nBins];
    std::vector<double>fitted_FS[nBins];
    std::vector<double>fitted_FSerr[nBins];
    std::vector<double>fitted_FSerrUp[nBins];
    std::vector<double>fitted_FSerrDown[nBins];

    //signal event number estimations:
    double N_sig_Rare[8] = {101., 61., 62., 96., 125., 124., 129., 69.};
    double N_bkg_Rare[8] = {131., 206., 279., 358., 358., 247., 158., 93.};
    //estimation of how many events lie within each sub-set: Run I DD, Run I LL, Run II DD, Run II LL. taken from jpsi!
    double ev_frac[4]    = {0.14, 0.09, 0.46, 0.30};
    if(OneFit)
        ev_frac[0] = 1.0;

    //TODO whyyyy is this all here
    std::vector<double> s1s, s1c, s2s, s2c, s3, s4, s5, s6s, s6c, s7, s8, s9;
    if(nBins == 9){
        s1s = { 0.5010, 0.1660, 0.1270, 0.1760, 0.2570, 0.3910, 0.4670, 0.4930, 0.329};
        s1c = { 0.2450, 0.6996, 0.7993, 0.7384, 0.6414, 0.4201, 0.3513, 0.3344, 0.000};
        s2s = { 0.1448, 0.0749, 0.0514, 0.0662, 0.0900, 0.1449, 0.1620, 0.1662, 0.000};
        s2c = {-0.1953,-0.6639,-0.7774,-0.7254,-0.6334,-0.4171,-0.3497,-0.3332, 0.000};
        s3  = { 0.0110,-0.0030, 0.0010,-0.0100,-0.0330,-0.0520,-0.1460,-0.2240,-0.006};
        s4  = { 0.0050, 0.0100,-0.1140,-0.1970,-0.2530,-0.2620,-0.2910,-0.2980,-0.244};
        s5  = { 0.2330, 0.0730,-0.1630,-0.3100,-0.4130,-0.4430,-0.3410,-0.2570, 0.000};
        s6s = {-0.0650,-0.1950,-0.0860, 0.0950, 0.2930, 0.4920, 0.5410, 0.4650, 0.000};
        s6c = { 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.000};
        s7  = { 0.0030, 0.0350, 0.0120, 0.0080,-0.0110, 0.0150,-0.0140, 0.0130, 0.000};
        s8  = {-0.0050, 0.0060,-0.0040,-0.0050,-0.0120, 0.0160, 0.0010, 0.0060,-0.060};
        s9  = {-0.0220, 0.0010,-0.0020,-0.0090, 0.0130, 0.0010, 0.0100, 0.0000,-0.084};
    }
    else if(nBins == 8){
        //results from signal channel generator level fitSignalMC fit
        s1s = { 0.5120, 0.1800, 0.1370, 0.1930, 0.2750, 0.4170, 0.4840, 0.5030};
        s1c = { 0.2450, 0.6996, 0.7993, 0.7384, 0.6414, 0.4201, 0.3513, 0.3344};
        s2s = { 0.1448, 0.0749, 0.0514, 0.0662, 0.0900, 0.1449, 0.1620, 0.1662};
        s2c = {-0.1953,-0.6639,-0.7774,-0.7254,-0.6334,-0.4171,-0.3497,-0.3332};
        s3  = { 0.0000, 0.0020,-0.0080,-0.0120,-0.0240,-0.0620,-0.1520,-0.2330};
        s4  = { 0.0870, 0.0040,-0.1080,-0.1950,-0.2510,-0.2770,-0.2900,-0.3040};
        s5  = { 0.2440, 0.0950,-0.1590,-0.3050,-0.4140,-0.4210,-0.3400,-0.2490};
        s6s = {-0.1270,-0.2070,-0.0860, 0.0950, 0.3020, 0.5140, 0.5570, 0.4700};
        s6c = { 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
        s7  = {-0.0060,-0.0100,-0.0030, 0.0020, 0.0030,-0.0020,-0.0020, 0.0050};
        s8 = { 0.0010,-0.0030,-0.0040,-0.0030,-0.0010, 0.0030,-0.0010, 0.0030};
        s9  = {-0.0020, 0.0000, 0.0020, 0.0040,-0.0020,-0.0010,-0.0010, 0.0010};
        /* OLD MoM start values
      s1s = { 0.5010, 0.1660, 0.1270, 0.1760, 0.2570, 0.3910, 0.4670, 0.4930};
      s1c = { 0.2450, 0.6996, 0.7993, 0.7384, 0.6414, 0.4201, 0.3513, 0.3344};
      s2s = { 0.1448, 0.0749, 0.0514, 0.0662, 0.0900, 0.1449, 0.1620, 0.1662};
      s2c = {-0.1953,-0.6639,-0.7774,-0.7254,-0.6334,-0.4171,-0.3497,-0.3332};
      s3  = { 0.0110,-0.0030, 0.0010,-0.0100,-0.0330,-0.0520,-0.1460,-0.2240};
      s4  = { 0.0050, 0.0100,-0.1140,-0.1970,-0.2530,-0.2620,-0.2910,-0.2980};
      s5  = { 0.2330, 0.0730,-0.1630,-0.3100,-0.4130,-0.4430,-0.3410,-0.2570};
      s6s = {-0.0650,-0.1950,-0.0860, 0.0950, 0.2930, 0.4920, 0.5410, 0.4650};
      s6c = { 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
      s7  = { 0.0030, 0.0350, 0.0120, 0.0080,-0.0110, 0.0150,-0.0140, 0.0130};
      s8  = {-0.0050, 0.0060,-0.0040,-0.0050,-0.0120, 0.0160, 0.0010, 0.0060};
      s9  = {-0.0220, 0.0010,-0.0020,-0.0090, 0.0130, 0.0010, 0.0100, 0.0000};
      */

        //TODO whyyyy is this all here
        if(NP){
            s1s = {0.5602306113691828,0.23270880313206915,0.1882591401081556,0.2360087282257996,0.3049337611889009,0.4271747118350757,0.49093645131734026,0.5057945417334112};
            s1c = { 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
            s2s = { 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
            s2c = { 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
            s3 = {0.010889127654682522,0.002826464227113492,-0.009846207821458525,-0.0236075131233653,-0.03873716522303356,-0.08541706129465602,-0.17283544777091792,-0.2508649715871772};
            s4 = {0.06515621731101214,-0.03441408879881635,-0.14972587209244403,-0.22058159609322783,-0.2569091889106349,-0.28043043274306023,-0.2933132627545414,-0.3090558271133447};
            s5 = {0.28355403122517436,0.15060676750257493,-0.08697300891551848,-0.2453363631814247,-0.3317290913621316,-0.37328734325703,-0.28988943793825117,-0.20704345542879504};
            s6s = {-0.14203502700533388,-0.2517350722752868,-0.12322680301923153,0.05716905988908093,0.22412264548364097,0.4666205500210169,0.48430363375918584,0.38863572446689215};
            s6c = { 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
            s7 = {-0.018795316409125306,-0.023477089751902755,-0.019670089562814908,-0.015167436307089688,-0.010845329740737182,-0.002747600804479865,-0.0017200885766387283,-0.0006988704922596641};
            s8 = {-0.010521697907580636,-0.008845120251655493,-0.005715190092060276,-0.004200375084315877,-0.0032359717141892687,0.0016256878486157777,0.0005880437600457862,0.00023165273472761083};
            s9 = {-0.0006861229900257304,-0.0006888890894988537,-0.0006222598407671807,-0.0005993069103744563,-0.0006186949055500562,0.0006613554952330075,0.0004840128898600523,0.0003040455330802454};
        }
    }
    else if(nBins == 3){
        s1s = { 0.329, 0.329, 0.329};
        s1c = { 0.0, 0.0, 0.0};
        s2s = { 0.0, 0.0, 0.0};
        s2c = { 0.0, 0.0, 0.0};
        s3 = {-0.006, -0.006, -0.006};
        s4 = {-0.244, -0.244, -0.244};
        s5 = {-0.005, -0.005, -0.005};
        s6s = {-0.002, -0.002, -0.002};
        s6c = { 0.0, 0.0, 0.0};
        s7 = { 0.000, 0.000, 0.000};
        s8 = {-0.060, -0.060, -0.060};
        s9 = {-0.084, -0.084, -0.084};
    }
    else if(nBins == 2){
        s1s = { 0.1959,  0.4917};
        s1c = { 0.7441,  0.3447};
        s2s = { 0.0646,  0.1636};
        s2c = {-0.7217, -0.3432};
        s3  = {-0.0042, -0.1747};
        s4  = { 0.1033,  0.2929};
        s5  = {-0.1458, -0.3157};
        s6s = { 0.0652, -0.5338};
        s6c = { 0.0000,  0.0000};
        s7  = { 0.0340, -0.0000};
        s8  = {-0.0115, -0.0002};
        s9  = { 0.0003,  0.0003};
    }
    else if(nBins == 1){
        s1s = { 0.329};
        s1c = { 0.0};
        s2s = { 0.0};
        s2c = { 0.0};
        s3 = {-0.006};
        s4 = {-0.244};
        s5 = {-0.005};
        s6s = {-0.002};
        s6c = { 0.0};
        s7 = { 0.000};
        s8 = {-0.060};
        s9 = {-0.084};
    }
    else{
        spdlog::error("No init values found for S_i in binning scheme with number of q2 bins: {0:d}", nBins);
        assert(0);
    }

    //current fitter, plotter, parameteres and pdfs:
    fcnc::fitter f(&opts);
    fcnc::folder fldr(&opts);

    fcnc::options theOptions[nPDFs];
    fcnc::bu2kstarmumu_plotter * thePlotter[nPDFs];

    std::vector<fcnc::parameters*> theParams [nBins];
    std::vector<fcnc::parameters*> the2DParams [nBins];
    std::vector<fcnc::pdf*>        theProbs  [nBins];
    std::vector< std::vector<fcnc::event>* >    selection[nBins];

    std::vector<UInt_t> pdf_idx;
    pdf_idx.push_back(0); //Run1 DD
    pdf_idx.push_back(1); //Run1 LL
    pdf_idx.push_back(2); //Run2 DD
    pdf_idx.push_back(3); //Run2 LL

    //set parameter FS common:
    std::vector<std::string> common_params;
    common_params.push_back("FS");
   if(FitR)
        common_params.push_back("R");
    if(!fitReference){
        common_params.push_back("gamkst");
        common_params.push_back("mkst");
    }
    f.set_common_parameters(common_params);

    for(UInt_t n = 0; n < nPDFs; n++){
        theOptions[n] = opts;
        theOptions[n].name = std::to_string(n+1);
        theOptions[n].run  = UseAccPerRun ? (n > 1 ? 2 : 1) : 12;
        theOptions[n].DDLL = (n % 2 == 0) ? "DD" : "LL";
        theOptions[n].update_angle_ranges();

        thePlotter[n] = new fcnc::bu2kstarmumu_plotter(&theOptions[n]);
    }

    double sig_frac[nBins];
    unsigned int event_numbers[nBins][4];
    for(unsigned int b = 0; b < nBins; b++){
        for(unsigned int n = 0; n < 4; n++){
            //get event numbers and signal fraction from global function, given the total number of events
            EventNumbers(b, n, sig_frac[b], event_numbers[b][n], 2597, nBins, 4);
            if(OnlySignal)
                event_numbers[b][n] *= sig_frac[b];
        }
    }

    for(UInt_t b = 0; b < nBins; b++){
        selection[b].clear();
        for(UInt_t n = 0; n < nPDFs; n++){
            //create parameter sets:
            fcnc::bu2kstarmumu_parameters * leParameters = new fcnc::bu2kstarmumu_parameters(&theOptions[n]);

            theOptions[n].q2_min = opts.TheQ2binsmin.at(b);
            theOptions[n].q2_max = opts.TheQ2binsmax.at(b);

            //create PDFs
            fcnc::bu2kstarmumu_pdf * lePDF = new fcnc::bu2kstarmumu_pdf(&theOptions[n], leParameters);

            //initiate parameters for mass fit
            if(opts.extended_ml){
                if(fitSignalMC){
                    spdlog::error("Never use extended_ml option for a pure signal sample, like in fitSignalMC!");
                    assert(0);
                }
                if(OnlyBackground){
                    spdlog::error("Never use extended_ml option for a pure background sample!");
                    assert(0);
                }
                else{
                    if((SystematicsWithToys || FitFinalToySamples) && !fitReference){
                        leParameters->n_sig.init(event_numbers[b][n]*sig_frac[b], event_numbers[b][n]*sig_frac[b]*0.2, event_numbers[b][n]*sig_frac[b]*5., 0.1);
                        leParameters->n_bkg.init(event_numbers[b][n]*(1.-sig_frac[b]), event_numbers[b][n]*(1.-sig_frac[b])*0.2, event_numbers[b][n]*(1.-sig_frac[b])*5., 0.1);
                        leParameters->f_sig.init(sig_frac[b], 0.0, 1.0, 0.0);
                    }
                    else if(fitData && !LargeBinning){
                        leParameters->n_sig.init(N_sig_Rare[b]*ev_frac[n], 0.0/*N_sig_Rare[b]*ev_frac[n]*0.2*/, N_sig_Rare[b]*ev_frac[n]*5., 0.1);
                        leParameters->n_bkg.init(N_bkg_Rare[b]*ev_frac[n], N_bkg_Rare[b]*ev_frac[n]*0.2, N_bkg_Rare[b]*ev_frac[n]*5., 0.1);
                        leParameters->f_sig.init(N_sig_Rare[b]*ev_frac[n]/(N_sig_Rare[b]*ev_frac[n]+N_bkg_Rare[b]*ev_frac[n]), 0.0, 1.0, 0.0);
                    }
                    else if(fitData && LargeBinning){
                        leParameters->n_sig.init(100., 5., 5000., 0.1);
                        leParameters->n_bkg.init(100., 5., 5000., 0.1);
                        leParameters->f_sig.init(0.5, 0.0, 1.0, 0.0);
                    }
                    else{
                        leParameters->n_sig.init(events[n].size() * 0.85, events[n].size() * 0.4, events[n].size() * 1.2, 0.1);
                        leParameters->n_bkg.init(events[n].size() * 0.15, events[n].size() * 0.01, events[n].size() * 0.5, 0.1);
                        leParameters->f_sig.init(0.5, 0.0, 1.0, 0.0);
                    }
                }
            }
            else{
                if(fitSignalMC || OnlySignal)
                    leParameters->f_sig.init(1.0, 0.0, 1.0, 0.0);
                else if(OnlyBackground){
                    leParameters->f_sig.init(0.0, 0.0, 1.0, 0.0);
                }
                else
                    leParameters->f_sig.init(0.35, 0.0, 1.0, 0.01);
            }
            leParameters->m_b.init(f_m_B[n], B_MASS_LOW, B_MASS_HIGH, OnlyBackground ? 0.0 : 0.01);
            if(opts.twotailedcrystalball)
                leParameters->m_res_1.init(1.0, 0.0, 1.0, 0.0);
            else
                leParameters->m_res_1.init(f_f_CB[n], 0.0, 1.0, fitSignalMC ? 0.01 : 0.0);
            if(leParameters->f_sig.get_value() != 1.0){
                if(fitData || true){ //only use single exponential for all cases
                    leParameters->fm_tau.init(1.0, 0.0, 1.0, 0.0);
                    leParameters->m_lambda.init(f_lambda1[n], -1.0e-2, -1.0e-6, 1.0e-6);
                    leParameters->m_lambda_2.init(f_lambda2[n], -1.0e-2, -1.0e-6, 0.0);
                }
                else{
                    leParameters->fm_tau.init((n % 2 == 1) ? 1.0 : 0.8, 0.0, 1.0, (n % 2 == 1) ? 0.0 : 0.01);
                    leParameters->m_lambda.init(f_lambda1[n], -1.0e-1, -1.0e-6, 1.0e-6);
                    leParameters->m_lambda_2.init(f_lambda2[n], -1.0e-1, -1.0e-6, (n % 2 == 1) ? 0.0 : 1.0e-6);
                }
                leParameters->m_tau.init( 1./2.835e-3, 100.0, 1.0e+4, 0.0);
                leParameters->m_tau_2.init(1./1.664e-3, 0.0, 1.0e+4, 0.0);
            }
            else{
                leParameters->fm_tau.init(0.8, 0.0, 1.0, 0.0);
                leParameters->m_lambda.init(-2.835e-3, -1.0e-1, -1.0e-6, 0.0);
                leParameters->m_lambda_2.init(-1.664e-4, -1.0e-1, -1.0e-6, 0.0);
                leParameters->m_tau.init( 1./2.835e-3, 100.0, 1.0e+4, 0.0);
                leParameters->m_tau_2.init(6.01e+2, 0.0, 1.0e+4, 0.0);
            }
            if(opts.twotailedcrystalball)
                leParameters->m_sigma_1.init(f_sigma_1[n], 5.0, 50.0, ((fitReference || fitSignalMC) && !OnlyBackground) ? 0.01 : 0.0);
            else{
                leParameters->m_sigma_1.init(f_sigma_1[n], 5.0, 50.0, ((fitReference || fitSignalMC) && !OnlyBackground) ? 0.01 : 0.0);
                leParameters->m_sigma_2.init(f_sigma_2[n], 5.0, 50.0, ((fitReference || fitSignalMC) && !OnlyBackground) ? 0.01 : 0.0);
            }
            leParameters->alpha_1.init(f_alpha_1[n], 0.5, 5.0, fitSignalMC ? 0.0001 : 0.0);
            leParameters->alpha_2.init(f_alpha_2[n], 0.5, 5.0, fitSignalMC ? 0.0001 : 0.0);
            leParameters->n_1.init(f_n_1[n], 0.1, 50.0, fitSignalMC ? 0.001 : 0.0);
            leParameters->n_2.init(f_n_2[n], 0.1, 50.0, fitSignalMC ? 0.001 : 0.0);
            if(!fitReference && !fitSignalMC && !SystematicsWithToys)
                leParameters->m_scale.init(f_m_scale[n], 0.0, 2.0, 0.0);
            else
                leParameters->m_scale.init(1.0, 0.0, 2.0, 0.0);
            leParameters->eff_q2.init(0.5*(opts.TheQ2binsmin.at(b)+opts.TheQ2binsmax.at(b)), opts.TheQ2binsmin.front(), opts.TheQ2binsmax.back(), 0.0);
            /*
        if(!fitSignalMC && !fitReference){
          if(LargeBinning)
            leParameters->load_only_Bmass_param_values("fitresult_SignalFit_fitSignalMC_SimultaneousFit_2Dfit_bin"+std::to_string(b)+"_pdf"+std::to_string(n)+".txt");
          else{
            if(leParameters->eff_q2() < 8.68)
              leParameters->load_only_Bmass_param_values("fitresult_SignalFit_fitSignalMC_SimultaneousFit_2Dfit_bin2_pdf"+std::to_string(n)+".txt");
            else if(leParameters->eff_q2() > 15.0)
              leParameters->load_only_Bmass_param_values("fitresult_SignalFit_fitSignalMC_SimultaneousFit_2Dfit_bin6_pdf"+std::to_string(n)+".txt");
            else
              leParameters->load_only_Bmass_param_values("fitresult_SignalFit_fitSignalMC_SimultaneousFit_2Dfit_bin5_pdf"+std::to_string(n)+".txt");
          }
        }
*/
            //initialize parameters to blind them!
            //leParameters->Fl.init(3.0/4.0*(s1c.at(b)-s2c.at(b)/3.0), 0.0, 1.0, 0.0);
            leParameters->Fl.init(1.0-4.0/3.0*s1s.at(b), 0.0, 1.0, 0.0);
            leParameters->S1s.init(s1s.at(b), -1.0, 1.0, 0.0);
            leParameters->S3.init(s3.at(b), -1.0, 1.0, 0.0);
            leParameters->S4.init(s4.at(b), -1.0, 1.0, 0.0);
            leParameters->S5.init(s5.at(b), -1.0, 1.0, 0.0);
            leParameters->Afb.init(3.0/4.0*s6s.at(b), -0.75, 0.75, 0.0);
            leParameters->S6s.init(s6s.at(b), -1.0, 1.0, 0.0);
            leParameters->S7.init(s7.at(b), -1.0, 1.0, 0.0);
            leParameters->S8.init(s8.at(b), -1.0, 1.0, 0.0);
            leParameters->S9.init(s9.at(b), -1.0, 1.0, 0.0);

            leParameters->SS1.init(0.0, -1.0, 1.0, 0.0);
            leParameters->SS2.init(0.0, -1.0, 1.0, 0.0);
            leParameters->SS3.init(0.0, -1.0, 1.0, 0.0);
            leParameters->SS4.init(0.0, -1.0, 1.0, 0.0);
            leParameters->SS5.init(0.0, -1.0, 1.0, 0.0);

            if(blind){
                double blind_scale = 1.0;
                leParameters->Fl.set_blinding(true, blind_scale, true);
                leParameters->S1s.set_blinding(true, blind_scale, true);
                leParameters->S3.set_blinding(true, blind_scale, true);
                leParameters->S4.set_blinding(true, blind_scale, true);
                leParameters->S5.set_blinding(true, blind_scale, true);
                leParameters->Afb.set_blinding(true, blind_scale, true);
                leParameters->S6s.set_blinding(true, blind_scale, true);
                leParameters->S7.set_blinding(true, blind_scale, true);
                leParameters->S8.set_blinding(true, blind_scale, true);
                leParameters->S9.set_blinding(true, blind_scale, true);
            }

            leParameters->FS .init(opts.swave ?  0.1*FL_scale[b] : 0.0, -1.0, 1.0, opts.swave ? 0.001 : 0.0);
            if(opts.fit_mkpi || opts.use_mkpi){
                //p-wave
                if(fitData)
                    leParameters->gammakstar.init(0.0503, 0.01, 0.10, 0.001, 0.01, true);//PDG value
                else
                    leParameters->gammakstar.init(0.0503, 0.01, 0.10, OnlyBackground ? 0.0 : 0.001);//PDG value
                leParameters->mkstar.init(PDGMASS_K_STAR_PLUS / 1000., 0.85, 1.0, OnlyBackground ? 0.0 : 0.001);//PDG value
                //s-wave
                leParameters->gammakstarplus.init(0.236, 0.1, 1.0, 0.0); //PDG value
                leParameters->mkstarplus.init(1.41, 1.2, 1.6, 0.0); //PDG value
                leParameters->asphase.init(TMath::Pi(), 0.0, 2.0*TMath::Pi(), 0.0);
                leParameters->a.init(1.95, 0.001, 20.0, 0.0);
                leParameters->r.init(1.78, 0.001, 10.0, 0.0);
                leParameters->R.init(1.6, 0.0, 10.0, FitR ? 0.001 : 0.0);
                //background parameter
                if(leParameters->f_sig() != 1.0){
                    leParameters->cbkgmkpi0.init(1.0, -1.0, 1.0, 0.0);
                    leParameters->cbkgmkpi1.init(0.1, -1.0, 1.0, 0.01);
                    leParameters->cbkgmkpi2.init(0.0, -1.0, 1.0, 0.0);
                    leParameters->cbkgmkpi3.init(0.0, -1.0, 1.0, 0.0);
                    leParameters->cbkgmkpi4.init(0.0, -1.0, 1.0, 0.0);
                    opts.mkpi_threshold = false;
                    leParameters->nthreshold.init(1.5, 0.0, 15.0, 0.0);
                }
            }
            //background parameter //TODO loop //TODO nPDFs
            if(leParameters->f_sig() != 1.0){
                leParameters->cbkgctl0.init(1.0, -1.0, 1.0, 0.0);
                leParameters->cbkgctl1.init(Bctl1[n], -1.0, 1.0, 0.0);
                leParameters->cbkgctl2.init(Bctl2[n], -1.0, 1.0, 0.0);
                leParameters->cbkgctl3.init(0.0, -1.0, 1.0, 0.0);
                leParameters->cbkgctl4.init(0.0, -1.0, 1.0, 0.0);

                leParameters->cbkgctk0.init(1.0, -1.0, 1.0, 0.0);
                leParameters->cbkgctk1.init(Bctk1[n], -1.0, 1.0, 0.0);
                leParameters->cbkgctk2.init(Bctk2[n], -1.0, 1.0, 0.0);
                leParameters->cbkgctk3.init(0.0, -1.0, 1.0, 0.0);
                leParameters->cbkgctk4.init(0.0, -1.0, 1.0, 0.0);

                leParameters->cbkgphi0.init(1.0, -1.0, 1.0, 0.0);
                leParameters->cbkgphi1.init(0.0, -1.0, 1.0, 0.0);
                leParameters->cbkgphi2.init(0.0, -1.0, 1.0, 0.0);
                leParameters->cbkgphi3.init(0.0, -1.0, 1.0, 0.0);
                leParameters->cbkgphi4.init(0.0, -1.0, 1.0, 0.0);
            }

            if(SystematicsWithToys || FitFinalToySamples){
                fcnc::bu2kstarmumu_parameters * le2DParameters = new fcnc::bu2kstarmumu_parameters(&theOptions[n]);
                le2DParameters->eff_q2.init(0.5*(opts.TheQ2binsmin.at(b)+opts.TheQ2binsmax.at(b)), opts.TheQ2binsmin.front(), opts.TheQ2binsmax.back(), 0.0);

                //initiate parameters for B mass fit
                if(OnlySignal)
                    le2DParameters->f_sig.init(1.0, 0.0, 1.0, 0.0);
                else
                    le2DParameters->f_sig.init(N_sig_Rare[b]*ev_frac[n]/(N_sig_Rare[b]*ev_frac[n]+N_bkg_Rare[b]*ev_frac[n]), 0.0, 1.0, 0.001);
                le2DParameters->m_b.init(f_m_B[n], B_MASS_LOW, B_MASS_HIGH, 0.01);
                if(opts.twotailedcrystalball)
                    le2DParameters->m_res_1.init(1.0, 0.0, 1.0, 0.0);
                else
                    le2DParameters->m_res_1.init(f_f_CB[n], 0.0, 1.0, 0.0);
                le2DParameters->fm_tau.init(1.0, 0.0, 1.0, 0.0);
                le2DParameters->m_lambda.init(f_lambda1[n], -1.0e-1, -1.0e-6, 1.0e-6);
                le2DParameters->m_lambda_2.init(f_lambda2[n], -1.0e-1, -1.0e-6, 0.0);
                if(opts.twotailedcrystalball){
                    le2DParameters->m_sigma_1.init(f_sigma_1[n], 5.0, 40.0, 0.0);
                }
                else{
                    le2DParameters->m_sigma_1.init(f_sigma_1[n], 5.0, 40.0, 0.0);
                    le2DParameters->m_sigma_2.init(f_sigma_2[n], 5.0, 40.0, 0.0);
                }
                le2DParameters->alpha_1.init(f_alpha_1[n], 0.5, 5.0, 0.0);
                le2DParameters->alpha_2.init(f_alpha_2[n], 0.5, 3.0, 0.0);
                le2DParameters->n_1.init(f_n_1[n], 0.1, 15.0, 0.0);
                le2DParameters->n_2.init(f_n_2[n], 0.1, 10.0, 0.0);
                le2DParameters->m_scale.init(1.0, 0.0, 2.0, 0.0);

                //mK*
                le2DParameters->gammakstar.init(0.0503, 0.01, 0.8, 0.0); //PDG value
                le2DParameters->mkstar.init(PDGMASS_K_STAR_PLUS / 1000., 0.7, 1.2, 0.01); //PDG value
                //s-wave
                if(opts.swave)
                    le2DParameters->FS.init(0.063, -1.00, 1.00, 0.001);
                else
                    le2DParameters->FS.init(0.0, -1.00, 1.00, 0.0);
                le2DParameters->gammakstarplus.init(0.236, 0.1, 1.0, 0.0); //PDG value
                le2DParameters->mkstarplus.init(1.41, 1.2, 1.6, 0.0); //PDG value
                le2DParameters->asphase.init(TMath::Pi(), 0.0, 2.0*TMath::Pi(), 0.0);
                le2DParameters->a.init(1.95, 0.0, 20.0, 0.0);
                le2DParameters->r.init(1.78, 0.0, 10.0, 0.0);
                le2DParameters->R.init(1.6, 0.0, 10.0, 0.0);
                //background parameter
                le2DParameters->cbkgmkpi0.init(1.0, -1.0, 1.0, 0.0);
                le2DParameters->cbkgmkpi1.init(0.0, -1.0, 1.0, 0.01);

                the2DParams[b].push_back(le2DParameters);
            }

            //define center of q2bin as effective q2:
            lePDF->load_coeffs_eff_phsp_4d();
            lePDF->update_cached_normalization(leParameters);

            //save parameters and pdfs in vectors:

            bool include = false;
            for(UInt_t m = 0; m < pdf_idx.size(); m++){
                if(n == pdf_idx.at(m)){
                    include = true;
                    break;
                }
            }
            if(include){
                theParams [b].push_back(leParameters);
                theProbs  [b].push_back(lePDF);
            }

            spdlog::info("[PDF{0:d}]\tSaved PDF and parameters!", n);

            //create vector with events according to the requested fits/pulls
            std::vector<fcnc::event> * leEvents = new std::vector<fcnc::event>;

            //choose events from the event vector and sort corresponding to q2bin or non-resonant:
            UInt_t NNN = events[n].size();

            //This randomly pre-selected list of events is used, if not all events are wanted:
            std::vector<UInt_t>eee;

            for(UInt_t e = 0; e < NNN; e++){
                fcnc::event meas;
                meas = events[n].at(e);
                //if wanted, only choose events from within q2 bin
                if(meas.q2 < opts.TheQ2binsmin.at(b) || meas.q2 > opts.TheQ2binsmax.at(b))
                    continue;
                if(meas.q2 > 0.98 && meas.q2 < 1.1)//exclude phi resonance
                    continue;
                if(meas.m < opts.m_low || meas.m > opts.m_high)
                    continue;
                if(OnlyBackground)
                    if(meas.m > 5230. && meas.m < 5330.)//exclude B peak
                        continue;
                //crosscheck between mag up and mag down:
                if(FitOnlyMagDown && meas.magnet > 0)
                    continue;
                if(FitOnlyMagUp   && meas.magnet < 0)
                    continue;
                if(meas.costhetal < -1. || meas.costhetal > +1.){
                    spdlog::warn("cos(theta_L) out of range: {0:f}", meas.costhetal);
                    continue;
                }
                if(meas.costhetak < -1. || meas.costhetak > +1.){
                    spdlog::warn("cos(theta_K) out of range: {0:f}", meas.costhetak);
                    continue;
                }
                if(meas.phi < -TMath::Pi() || meas.phi > +TMath::Pi()){
                    spdlog::warn("phi out of range: {0:f}", meas.phi);
                    continue;
                }
                if(meas.mkpi < opts.mkpi_min || meas.mkpi > opts.mkpi_max){
                    spdlog::warn("m(Kpi) out of range: {0:f}", meas.mkpi);
                    continue;
                }
                leEvents->push_back(meas);
            }

            if(SystematicsWithToys){
                leEvents->clear();
                fcnc::bu2kstarmumu_generator gen(&theOptions[n]);
                UInt_t idx = pdf_idx.at(n);
                if(UseAccPer2Years && theOptions[n].run == 2){
                    theOptions[n].run = 21;
                    lePDF->load_coeffs_eff_phsp_4d();
                    lePDF->update_cached_normalization(leParameters);
                    std::vector<fcnc::event> eves1516 = gen.generate(0.5 + event_numbers[b][idx] * (idx%2==0 ? 0.275 : 0.292) , leParameters, lePDF);
                    for(unsigned int k = 0; k < eves1516.size(); k++)
                        eves1516.at(k).year = 2016;
                    theOptions[n].run = 22;
                    lePDF->load_coeffs_eff_phsp_4d();
                    lePDF->update_cached_normalization(leParameters);
                    std::vector<fcnc::event> eves1718 = gen.generate(0.5 + event_numbers[b][idx] * (idx%2==0 ? 0.725 : 0.708), leParameters, lePDF);
                    for(unsigned int k = 0; k < eves1718.size(); k++)
                        eves1718.at(k).year = 2018;
                    theOptions[n].run = 2;
                    leEvents->insert(leEvents->end(), eves1516.begin(), eves1516.end());
                    leEvents->insert(leEvents->end(), eves1718.begin(), eves1718.end());
                }
                else{
                    lePDF->load_coeffs_eff_phsp_4d();
                    lePDF->update_cached_normalization(leParameters);
                    std::vector<fcnc::event> genevents = gen.generate(0.5 + event_numbers[b][idx], leParameters, lePDF);
                    for(unsigned int k = 0; k < genevents.size(); k++)
                        genevents.at(k).year = (theOptions[idx].run == 2 ? 2016 : 2012);
                    leEvents->insert(leEvents->end(), genevents.begin(), genevents.end());
                }
            }

            if(UseAccPer2Years && theOptions[n].run == 2){
                //split the Run2 data-set into two groups: [0]: 2015+16 [1]: 2017+18
                std::vector<fcnc::event> * Events_2015_2016 = new std::vector<fcnc::event>;
                std::vector<fcnc::event> * Events_2017_2018 = new std::vector<fcnc::event>;
                UInt_t nBefore = leEvents->size();

                for(UInt_t e = 0; e < leEvents->size(); e++){
                    fcnc::event meas = leEvents->at(e);
                    if(meas.year == 2015 || meas.year == 2016)
                        Events_2015_2016->push_back(meas);
                    else if(meas.year == 2017 || meas.year == 2018)
                        Events_2017_2018->push_back(meas);
                    else{
                        spdlog::critical("Invalid year found in data-set of Run2: {0:d}", meas.year);
                        assert(0);
                    }
                }
                //update cached eff for 2015+16 and 2017+18 individually
                theOptions[n].run = 21;
                lePDF->load_coeffs_eff_phsp_4d();
                lePDF->update_cached_normalization(leParameters);
                lePDF->update_cached_efficiencies(leParameters, Events_2015_2016);

                theOptions[n].run = 22;
                lePDF->load_coeffs_eff_phsp_4d();
                lePDF->update_cached_normalization(leParameters);
                lePDF->update_cached_efficiencies(leParameters, Events_2017_2018);

                //recombine both data-sets:
                theOptions[n].run = 2;
                leEvents->clear();
                leEvents->insert(leEvents->end(), Events_2015_2016->begin(), Events_2015_2016->end());
                leEvents->insert(leEvents->end(), Events_2017_2018->begin(), Events_2017_2018->end());

                assert(nBefore == leEvents->size());
            }
            else{
                lePDF->load_coeffs_eff_phsp_4d();
                lePDF->update_cached_normalization(leParameters);
                lePDF->update_cached_efficiencies(leParameters, leEvents);
            }

            if(include)
                selection[b].push_back(leEvents);

            spdlog::info("[PDF{0:d}]\tFinished selecting {1:f}  events!", n, leEvents->size());

        } // end of PDF
    } // end of q2 bins

    double FSfromLargeBins[3], dFSfromLargeBins[3];
    if((SystematicsWithToys || FitFinalToySamples) && !OnlySignal && !fitReference){
        //combine events to larger bins and fit before fitting all 8 bins:
        int fit_results[3];
        std::vector< std::vector<fcnc::event>* > combinedEvents[3];
        bool ex_ml_buffer = theOptions[0].extended_ml;
        for(unsigned int n = 0; n < nPDFs; n++){
            combinedEvents[0].push_back(new std::vector<fcnc::event>);
            combinedEvents[0].back()->insert(combinedEvents[0].back()->end(), selection[1].at(n)->begin(), selection[1].at(n)->end());
            combinedEvents[0].back()->insert(combinedEvents[0].back()->end(), selection[2].at(n)->begin(), selection[2].at(n)->end());
            combinedEvents[0].back()->insert(combinedEvents[0].back()->end(), selection[3].at(n)->begin(), selection[3].at(n)->end());
            combinedEvents[0].back()->insert(combinedEvents[0].back()->end(), selection[4].at(n)->begin(), selection[4].at(n)->end());
            combinedEvents[1].push_back(new std::vector<fcnc::event>);
            combinedEvents[1].back()->insert(combinedEvents[1].back()->end(), selection[5].at(n)->begin(), selection[5].at(n)->end());
            combinedEvents[2].push_back(new std::vector<fcnc::event>);
            combinedEvents[2].back()->insert(combinedEvents[2].back()->end(), selection[6].at(n)->begin(), selection[6].at(n)->end());
            combinedEvents[2].back()->insert(combinedEvents[2].back()->end(), selection[7].at(n)->begin(), selection[7].at(n)->end());

            theOptions[n].extended_ml = false;

        }

        //extract FS from this fit and constrain FS to this value:
        for(int b = 0; b < 3; b++){
            fit_results[b] = f.fit(theProbs[b], the2DParams[b], combinedEvents[b]);
            for(unsigned int n = 0; n < nPDFs; n++){
                fcnc::bu2kstarmumu_parameters * dieParameter = (fcnc::bu2kstarmumu_parameters *) the2DParams[b].at(n);
                FSfromLargeBins[b]  = dieParameter->FS.get_value();
                dFSfromLargeBins[b] = dieParameter->FS.get_error();
                spdlog::info("[LARGEBIN{0:d}][PDF{1:d}]\tFS = {2:f}  +/- {3:f}",b, n, FSfromLargeBins[b], dFSfromLargeBins[b]);
            }
        }
        if(false){
            TFile* fout = new TFile(("finalresult_OnlyToys"+std::to_string(opts.job_id)+"_2DfitLargeBins"+(LargerMKpiRange ? "_MediumMKpiRange" : "")+".root").c_str(), "RECREATE");
            fout->cd();
            int param_index = 0;
            fcnc::bu2kstarmumu_parameters * dieParameter = (fcnc::bu2kstarmumu_parameters *) the2DParams[0].at(0);
            for(UInt_t p = 0; p < dieParameter->nparameters(); p++){
                fcnc::parameter* param = dieParameter->get_parameter(p);
                if(param->get_step_size() != 0.0){//skip constant parameters
                    std::string parname(param->get_name());
                    std::string pardesc(param->get_description());

                    spdlog::info("Creating new TTree for parameter: " +parname);

                    TTree* t = new TTree(parname.c_str(), pardesc.c_str());
                    double q2a, q2b, value, error, error_up, error_down, start_value, nominal_value, nominal_error=0.0;
                    int pdf, bin, migrad, status_cov;
                    const unsigned int corr_max = param->correlations.size();
                    double tmp_corr[corr_max];

                    t->Branch("pdf",&pdf,"pdf/I");
                    t->Branch("bin",&bin,"bin/I");
                    t->Branch("value",&value,"value/D");
                    t->Branch("q2min",&q2a,"q2min/D");
                    t->Branch("q2max",&q2b,"q2max/D");
                    t->Branch("error",&error,"error/D");
                    t->Branch("error_up",&error_up,"error_up/D");
                    t->Branch("error_down",&error_down,"error_down/D");
                    t->Branch("start_value",&start_value,"start_value/D");
                    t->Branch("migrad",&migrad,"migrad/I");
                    t->Branch("status_cov",&status_cov,"status_cov/I");
                    t->Branch("nominal_value",&nominal_value,"nominal_value/D");
                    t->Branch("nominal_error",&nominal_error,"nominal_error/D");
                    t->Branch("index",&param_index, "index/I");

                    std::stringstream corr_stream;
                    corr_stream << "correlations[" << corr_max << "]/D";
                    t->Branch("correlations",&tmp_corr,corr_stream.str().c_str());

                    pdf = 1;

                    for(UInt_t b = 0; b < 3; b++){
                        fcnc::parameter* par = the2DParams[b].at(0)->get_parameter(p);

                        UInt_t paridx = 0;
                        while(par->get_name() != parname.c_str()){
                            par = the2DParams[b].at(0)->get_parameter(paridx);
                            paridx++;
                            if(paridx == the2DParams[b].at(0)->nparameters()){
                                spdlog::warn("Parameter '"+parname+"' not found in PDF 0. Continue with next PDF.");
                                break;
                            }
                        }
                        if(paridx == the2DParams[b].at(0)->nparameters())
                            break;

                        bin = b;
                        q2a = opts.TheQ2binsmin[b];
                        q2b = opts.TheQ2binsmax[b];
                        value = par->get_value();
                        error = par->get_error();
                        error_up = par->get_error_up();
                        error_down = par->get_error_down();
                        start_value = par->get_start_value();
                        nominal_value = par->get_start_value();
                        migrad = fit_results[b] % 100;
                        status_cov = fit_results[b] / 100;

                        for (unsigned int l = 0; l < corr_max; l++)
                            tmp_corr[l] = 0.0;
                        for (unsigned int l = 0; l < par->correlations.size(); l++)
                            tmp_corr[l] = par->correlations.at(l);
                        t->Fill();
                    }
                    t->Write();
                    delete t;
                    param_index++;
                }
            }
            fout->Close();
        }
        if(false){
            for(UInt_t b = 0; b < 3; b++){
                for(unsigned int n = 0; n < nPDFs; n++){
                    std::cout << "|| BIN " << b << "\tPDF " << n << std::endl;
                    the2DParams[b].at(n)->print_parameters(false);
                }
            }
        }
        if(false){
            for(UInt_t b = 0; b < 3; b++){
                for(unsigned int n = 0; n < nPDFs; n++){
                    fcnc::bu2kstarmumu_parameters * dieParameter = (fcnc::bu2kstarmumu_parameters *) the2DParams[b].at(n);
                    fcnc::bu2kstarmumu_pdf * leProb = (fcnc::bu2kstarmumu_pdf *) theProbs[b].at(n);
                    thePlotter[n]->plot_data(leProb, dieParameter, combinedEvents[b].at(n), get_MoMPlot_path(), "ToyMoM_LargeBins_bin"+std::to_string(b)+"_pdf"+std::to_string(n), true);
                }
            }
        }
        for(unsigned int n = 0; n < nPDFs; n++){
            theOptions[n].extended_ml = ex_ml_buffer;
        }
    }

    bool do_fit = !OnlySignal;
    int fitresult = 0;
    if(do_fit){
        for(UInt_t b = 0; b < nBins; b++){
            std::vector<fcnc::event> * AllEvents = new std::vector<fcnc::event>;
            for(UInt_t n = 0; n < nPDFs; n++){
                if(SimultaneousFit){
                    if(n == 0){
                        fitresult = f.fit(theProbs[b], theParams[b], selection[b]);
                    }
                }
                else if(OneFit){
                    if(n > 0)
                        continue;
                    AllEvents->clear();
                    for(UInt_t nn = 0; nn < nPDFs; nn++)
                        AllEvents->insert(AllEvents->end(), selection[b].at(nn)->begin(), selection[b].at(nn)->end());
                    fitresult = f.fit(theProbs[b].at(n), theParams[b].at(n), AllEvents);
                }
                else{
                    fitresult = f.fit(theProbs[b].at(n), theParams[b].at(n), selection[b].at(n));
                }
                fit_results[b].push_back(fitresult);
                fcnc::bu2kstarmumu_parameters * leParameters = (fcnc::bu2kstarmumu_parameters *) theParams[b].at(n);
                fcnc::bu2kstarmumu_pdf * leProb = (fcnc::bu2kstarmumu_pdf *) theProbs[b].at(n);

                if(!SimultaneousFit || n == 0){
                    double fitted_fs = leParameters->FS.get_value();
                    double fitted_dfs_up = leParameters->FS.get_error_up();
                    double fitted_dfs_down = leParameters->FS.get_error_down();
                    double fitted_dfs = leParameters->FS.get_error();
                    if(opts.minos_errors)
                        fitted_dfs = std::max(fabs(fitted_dfs_up), fabs(fitted_dfs_down));
                    if(fitSignalMC || !opts.swave){
                        fitted_fs = 0.0;
                        fitted_dfs = 0.0;
                    }
                    else if(FSfrom2DLargeBins){
                        if(leParameters->eff_q2() < 9.0){
                            fitted_fs  = 0.252622 * FL_scale[b];
                            fitted_dfs = 0.103659 * FL_scale[b];
                        }
                        else if(leParameters->eff_q2() < 15.0){
                            fitted_fs  = 0.013818 * FL_scale[b];
                            fitted_dfs = 0.146519 * FL_scale[b];
                        }
                        else{
                            fitted_fs  = 0.0164393 * FL_scale[b];
                            fitted_dfs = 0.0895912 * FL_scale[b];
                        }
                    }
                    else if((SystematicsWithToys || FitFinalToySamples) && !fitReference){//use FS obtained from the fit in the larger q2bins:
                        if(leParameters->eff_q2() < 9.0){
                            fitted_fs  = FSfromLargeBins[0] * FL_scale[b];
                            fitted_dfs = dFSfromLargeBins[0] * FL_scale[b];
                        }
                        else if(leParameters->eff_q2() < 15.0){
                            fitted_fs  = FSfromLargeBins[1] * FL_scale[b];
                            fitted_dfs = dFSfromLargeBins[1] * FL_scale[b];
                        }
                        else{
                            fitted_fs  = FSfromLargeBins[2] * FL_scale[b];
                            fitted_dfs = dFSfromLargeBins[2] * FL_scale[b];
                        }
                    }
                    std::cout << std::setprecision(5) << "FS: " << fitted_fs << "+/-" << fitted_dfs << std::endl;
                    fitted_FS[b].push_back(fitted_fs);
                    fitted_FSerr[b].push_back(fitted_dfs);
                    fitted_FSerrUp[b].push_back(fitted_dfs_up);
                    fitted_FSerrDown[b].push_back(fitted_dfs_down);
                }
                //plot fit projections of 2Dfit
                std::ostringstream eps_label;
                spdlog::info("[PLOT]\tStart configurations for plotting!");
                if(fitReference){
                    eps_label << "JpsiFit";
                }
                else if(fitSignalMC){
                    eps_label << "FCNC_SignalfitSignalMC_fit_bin" << std::to_string(b);
                }
                else{
                    eps_label << "FCNCfit_bin" << std::to_string(b);
                }
                if (LargeBinning) eps_label << "_LargeBins";
                else if(Fit2bins) eps_label << "_2BINS";
                else if(Fit1bin)  eps_label << "_1BIN";
                else if(FitAllbins) eps_label << "_9BINS";

                if(OneFit) eps_label << "_FullDataSet";
                else       eps_label << (n % 2 == 0 ? "_DD_Run" : "_LL_Run") << std::to_string( (int) (1+n/2));

                eps_label << "_MoM_2Dfit";
                theOptions[n].plot_label = "LHCb data";
                theOptions[n].q2_label = q2_label(theOptions[n].TheQ2binsmin.at(b),theOptions[n].TheQ2binsmax.at(b));
                if(opts.write_eps){
                    std::cout << "[PLOT]\t" << eps_label.str() << std::endl;
                    if(OneFit)
                        thePlotter[n]->plot_data(leProb, leParameters, AllEvents, get_MoMPlot_path(), eps_label.str(), false);
                    else
                        thePlotter[n]->plot_data(leProb, leParameters, selection[b].at(n), get_MoMPlot_path(), eps_label.str(), false);
                }
            }//end loop PDFs

            if(SimultaneousFit){
                std::ostringstream eps_label;
                spdlog::info("[PLOT]\tStart configurations for combined plotting!");
                if(fitReference){
                    eps_label << "JpsiFit";
                }
                else if(fitSignalMC){
                    eps_label << "FCNC_SignalfitSignalMC_fit_bin" << std::to_string(b);
                }
                else{
                    eps_label << "FCNCfit_bin" << std::to_string(b);
                }
                if (LargeBinning)   eps_label << "_LargeBins";
                else if(Fit2bins)   eps_label << "_2BINS";
                else if(Fit1bin)    eps_label << "_1BIN";
                else if(FitAllbins) eps_label << "_9BINS";
                eps_label << "_AllPDFs";
                eps_label << "_MoM_2Dfit";
                std::vector<fcnc::bu2kstarmumu_pdf*> * prober = (std::vector<fcnc::bu2kstarmumu_pdf*> *)  & theProbs[b];
                std::vector<fcnc::bu2kstarmumu_parameters*> * paramser = (std::vector<fcnc::bu2kstarmumu_parameters*> *) & theParams[b];
                thePlotter[0]->SetPulls(true);
                thePlotter[0]->plot_added_pdfs(prober, paramser, & selection[b],
                                               get_MoMPlot_path(), eps_label.str(), true);
                thePlotter[0]->SetPulls(false);
                eps_label << "_noPulls";
                thePlotter[0]->plot_added_pdfs(prober, paramser, & selection[b],
                                               get_MoMPlot_path(), eps_label.str(), true);
            }
        }//end loop q2 bins
    }//end do_fit
    else{//fill vectors with nominal values, if fit was not done:
        for(UInt_t b = 0; b < nBins; b++){
            for(UInt_t n = 0; n < nPDFs; n++){
                if(FixFStoStart)
                    fitted_FS[b].push_back( opts.swave ?  0.1*FL_scale[b] : 0.0);
                else
                    fitted_FS[b].push_back(0.);
                fitted_FSerr[b].push_back(0.);
                fitted_FSerrUp[b].push_back(0.);
                fitted_FSerrDown[b].push_back(0.);
            }
            fit_results[b].push_back(300);
        }
    }

    bool do_mom = !LargeBinning;
    if(do_mom){
        for(UInt_t b = 0; b < nBins; b++){
            std::vector<fcnc::event> allEvents;
            allEvents.clear();
            //assign sWeights:
            if(!(fitSignalMC || OnlySignal) && do_fit){//pure signal and fitSignalMC don't need sWeights
                if(OneFit){
                    //for the combined fit, first add all events together and then apply sWeights according to first parameter idx
                    for(UInt_t n = 0; n < nPDFs; n++){
                        spdlog::info("[MOM]\tCombine events into one set for bin={0:d}   pdf={1:d}",b, n);
                        allEvents.insert(allEvents.end(), selection[b].at(n)->begin(), selection[b].at(n)->end());
                    }
                    spdlog::info("[MOM]\tGet sWeights from fit for the full dataset of  bin={0:d}",b);
                    fcnc::bu2kstarmumu_parameters * leParameters = (fcnc::bu2kstarmumu_parameters *) theParams[b].at(0);
                    fcnc::bu2kstarmumu_pdf * leProb = (fcnc::bu2kstarmumu_pdf *) theProbs[b].at(0);
                    spdlog::info("[MOM]\tGet combined sWeights from fit for bin={0:d}",b);
                    leProb->calculate_sweights(leParameters, &allEvents);
                    spdlog::info("[MOM]\tGet combined sWeights from fit for bin={0:d} ... DONE!",b);
                }
                else{
                    //for individual mom, each sub-sets gets sWeights and no sub-sets are added together
                    for(UInt_t n = 0; n < nPDFs; n++){
                        fcnc::bu2kstarmumu_parameters * leParameters = (fcnc::bu2kstarmumu_parameters *) theParams[b].at(n);
                        fcnc::bu2kstarmumu_pdf * leProb = (fcnc::bu2kstarmumu_pdf *) theProbs[b].at(n);
                        spdlog::info("[MOM]\tGet sWeights from fit for bin={0:d}  pdf={1:d}",b, n);
                        leProb->calculate_sweights(leParameters, selection[b].at(n));
                        spdlog::info("[MOM]\tGet sWeights from fit for bin={0:d} pdf={1:d} ...DONE.",b, n);
                        //for the simultaneous mom, first apply sWeights according to parameters[n], then add all events together
                        if(SimultaneousMoM){
                            spdlog::info("[MOM]\tCombine events (after sWeights have been applied) into one set for  bin={0:d}  pdf={1:d}",b, n);
                            allEvents.insert(allEvents.end(), selection[b].at(n)->begin(), selection[b].at(n)->end());
                        }
                    }
                }
            }//end of sWeight assignments
            //extract and save angular moments:
            if(SimultaneousMoM || SimultaneousFit || OneFit){//do MoM for the full dataset of this q2bin
                std::vector<double> mom(18, 0.0), obs(18, 0.0);
                std::vector<double> momcov(18*18, 0.0), obscov(18*18, 0.0);
                spdlog::info("[MoM]\tGet moments from the combined dataset!  bin={0:d}",b);
                if(!allEvents.size()){
                    for(UInt_t n = 0; n < nPDFs; n++){
                        spdlog::info("[MOM]\tCombine events for MoM into one set for  bin={0:d}   pdf={1:d}",b, n);
                        allEvents.insert(allEvents.end(), selection[b].at(n)->begin(), selection[b].at(n)->end());
                    }
                }
                fcnc::bu2kstarmumu_parameters * leParameters = (fcnc::bu2kstarmumu_parameters *) theParams[b].at(0);
                fcnc::bu2kstarmumu_pdf * leProb = (fcnc::bu2kstarmumu_pdf *) theProbs[b].at(0);
                leProb->get_moments(allEvents, mom, momcov);
                spdlog::info("[MoM]\tConvert moments to angular observables for the combined dataset! bin={0:d}",b);
                fcnc::moments_to_observables(rnd, mom, momcov, fitted_FS[b].at(0), fitted_FSerr[b].at(0), obs, obscov, FixFStoStart || UseExternalFS);
                spdlog::info("[MoM]\tSave angular observables to parameters for the combined dataset! bin={0:d}",b);
                leProb->save_moments_to_obs(leParameters, obs, obscov);
                spdlog::info("[MoM]\tDone for the combined dataset of bin={0:d}",b);
            }
            else{//do MoM individually for each sub-set
                for(UInt_t n = 0; n < nPDFs; n++){
                    std::vector<double> mom(18, 0.0), obs(18, 0.0);;
                    std::vector<double> momcov(18*18, 0.0), obscov(18*18, 0.0);
                    spdlog::info("[MoM]\tGet moments from the combined dataset! bin={0:d}   pdf={1:d}",b, n);
                    fcnc::bu2kstarmumu_parameters * leParameters = (fcnc::bu2kstarmumu_parameters *) theParams[b].at(n);
                    fcnc::bu2kstarmumu_pdf * leProb = (fcnc::bu2kstarmumu_pdf *) theProbs[b].at(n);
                    leProb->get_moments(*selection[b].at(n), mom, momcov);
                    spdlog::info("[MoM]\tConvert moments to angular observables for bin={0:d}   pdf={1:d}",b, n);
                    fcnc::moments_to_observables(rnd, mom, momcov, fitted_FS[b].at(n), fitted_FSerr[b].at(n), obs, obscov, FixFStoStart || UseExternalFS);
                    spdlog::info("[MoM]\tSave angular observables to parameters for bin={0:d}   pdf={1:d}",b, n);
                    leProb->save_moments_to_obs(leParameters, obs, obscov);
                    spdlog::info("[MoM]\tDone for bin={0:d}   pdf={1:d}",b, n);
                }
            }
            //plot all four PDFs:
            for(UInt_t n = 0; n < nPDFs; n++){
                if((SimultaneousMoM || OneFit) && n > 0)
                    continue;
                std::ostringstream qqbin;
                std::ostringstream eps_label;
                std::cout << "[PLOT]\tStart configurations for plotting!" << std::endl;
                if(fitReference)     eps_label << "JpsiFit";
                else if(fitSignalMC) eps_label << "FCNC_SignalfitSignalMC_fit_bin" << std::to_string(b);
                else                 eps_label << "FCNCfit_bin" << std::to_string(b);

                if (LargeBinning)   eps_label << "_LargeBins";
                else if(Fit2bins)   eps_label << "_2BINS";
                else if(Fit1bin)    eps_label << "_1BIN";
                else if(FitAllbins) eps_label << "_9BINS";

                if(SimultaneousMoM || OneFit) eps_label << "_FullDataSet";
                else  eps_label << (n % 2 == 0 ? "_DD_Run" : "_LL_Run") << std::to_string( (int) (1+n/2));
                eps_label << "_MoM";
                theOptions[n].plot_label = "LHCb data";
                theOptions[n].q2_label = q2_label(theOptions[n].TheQ2binsmin.at(b),theOptions[n].TheQ2binsmax.at(b));
                if(opts.write_eps){
                    bool wf = theOptions[n].weighted_fit;
                    bool mf = theOptions[n].only_mass2DFit;
                    bool oa = theOptions[n].only_angles;
                    bool el = theOptions[n].extended_ml;
                    theOptions[n].weighted_fit = true; //only for the plotter
                    theOptions[n].only_mass2DFit = false; //only for the plotter
                    theOptions[n].only_angles = true; //only for the plotter
                    theOptions[n].extended_ml = false;//only for the plotter
                    std::cout << "[PLOT]\t" << eps_label.str() << std::endl;
                    if(SimultaneousMoM || OneFit)
                        thePlotter[n]->plot_data((fcnc::bu2kstarmumu_pdf*)theProbs[b].at(n), (fcnc::bu2kstarmumu_parameters*)theParams[b].at(n), &allEvents, get_MoMPlot_path(), eps_label.str(), true);
                    else
                        thePlotter[n]->plot_data((fcnc::bu2kstarmumu_pdf*)theProbs[b].at(n), (fcnc::bu2kstarmumu_parameters*)theParams[b].at(n), selection[b].at(n), get_MoMPlot_path(), eps_label.str(), true);
                    theOptions[n].weighted_fit = wf;
                    theOptions[n].only_mass2DFit = mf;
                    theOptions[n].only_angles = oa;
                    theOptions[n].extended_ml = el;
                }
            } //end loop PDFs
        } //end loop over bins
    } //end do_mom

    bool print_parameters = false;
    //print and save-to-.txt of all parameters:
    std::cout << std::endl;
    std::cout << "==========================================" << std::endl;
    std::cout << "||              PARAMETERS              ||" << std::endl;
    std::cout << "==========================================" << std::endl;
    for(UInt_t b = 0; b < nBins; b++){
        for(UInt_t i = 0; i < (SimultaneousMoM || OneFit ? 1 : pdf_idx.size()); i++){
            if(print_parameters){
                std::cout << "|| BIN " << b << "\tPDF " << pdf_idx.at(i) << std::endl;
                theParams[b].at(i)->print_parameters(false);
            }
            std::ostringstream oss;
            oss << "momresult";
            if(fitReference) oss << "_JpsiFit";
            else             oss << "_SignalFit";

            if(fitSignalMC) oss << "_fitSignalMC";

            if(SimultaneousFit) oss << "_SimultaneousFit";
            else                oss << "_IndividualFit";
            oss << "_2Dfit";

            if(!opts.full_angular) oss << "_folding" << opts.folding;
            if(nBins > 1)          oss << "_bin" << b;

            if (LargeBinning)   oss << "_LargeBins";
            else if(Fit2bins)   oss << "_2BINS";
            else if(Fit1bin)    oss << "_1BIN";
            else if(FitAllbins) oss << "_9BINS";
            if(FitOnlyMagDown)  oss << "_OnlyMagDown";
            if(FitOnlyMagUp)    oss << "_OnlyMagUp";
            if(!(SimultaneousMoM || OneFit)) oss << "_pdf" << i;
            oss << ".txt";
            std::vector<fcnc::bu2kstarmumu_parameters*> * paramser = (std::vector<fcnc::bu2kstarmumu_parameters*> *) & theParams[b];
            if(!(SystematicsWithToys || FitFinalToySamples))
                paramser->at(i)->save_param_values(oss.str());
        }
    }

    //print all fitresults:
    std::cout << std::endl;
    std::cout << "==========================================" << std::endl;
    std::cout << "||              FIT RESULTS             ||" << std::endl;
    std::cout << "==========================================" << std::endl;
    if(SimultaneousFit)
        std::cout << "|| BIN\t\tfit result\tF_S       ||" << std::endl;
    else
        std::cout << "|| BIN\t\tPDF\t\tfit result\tF_S       ||" << std::endl;
    for(UInt_t b = 0; b < nBins; b++){
        if(SimultaneousFit || OneFit){
            if(opts.minos_errors)
                printf("|| %d\t\t%d\t\t%f (+)%f\t (-)%f\t||\n", b, fit_results[b].at(0), fitted_FS[b].at(0), fitted_FSerrUp[b].at(0), fitted_FSerrDown[b].at(0));
            else
                printf("|| %d\t\t%d\t\t%f +/- %f\t||\n", b, fit_results[b].at(0), fitted_FS[b].at(0), fitted_FSerr[b].at(0));
        }
        else{
            for(UInt_t i = 0; i < pdf_idx.size(); i++){
                if(opts.minos_errors)
                    printf("|| %d\t\t%d\t\t%d\t\t%f (+)%f\t (-)%f\t||\n", b, pdf_idx.at(i), fit_results[b].at(i), fitted_FS[b].at(i), fitted_FSerr[b].at(i), fitted_FSerrDown[b].at(i));
                else
                    printf("|| %d\t\t%d\t\t%d\t\t%f +/- %f\t||\n", b, pdf_idx.at(i), fit_results[b].at(i), fitted_FS[b].at(i), fitted_FSerr[b].at(i));
            }
        }
    }
    std::cout << std::endl;

    //save all values to TTree:
    std::ostringstream sout;
    sout << "finalresults_";
    if(fitSignalMC)                  sout << "fitSignalMC_";
    else if(fitReference)   sout << "Jpsi_";

    if(SystematicsWithToys) sout << "OnlyToys" << opts.job_id << "_";
    if(FitFinalToySamples)  sout << "FinalToys" << opts.job_id << "_";
    if(FitOnlyMagDown)      sout << "OnlyMagDown_";
    if(FitOnlyMagUp)        sout << "OnlyMagUp_";
    if(LargeBinning)        sout << "LargeBins_";
    if(NP)  sout << "NP_";
    sout << "MoM.root";

    TFile* fout = new TFile(sout.str().c_str(), "RECREATE");
    fout->cd();

    int param_index = 0;
    //loop over parameters:
    UInt_t pdf_null_idx = (SimultaneousMoM || OneFit || SimultaneousFit ? 0 : nPDFs-1);
    for(UInt_t p = 0; p < theParams[0].at(pdf_null_idx)->nparameters(); p++){
        fcnc::parameter* param = theParams[0].at(pdf_null_idx)->get_parameter(p);
        if(param->get_step_size() != 0.0){//skip constant parameters

            std::string parname(param->get_name());
            std::string pardesc(param->get_description());

            spdlog::info("Creating new TTree for parameter:"+ parname);

            TTree* t = new TTree(parname.c_str(), pardesc.c_str());

            double q2a, q2b, value, error, error_up, error_down, start_value, nominal_value, nominal_error=0.0;
            int pdf, bin, migrad, status_cov;
            const unsigned int corr_max = param->correlations.size();
            double tmp_corr[corr_max];

            t->Branch("pdf",&pdf,"pdf/I");
            t->Branch("bin",&bin,"bin/I");
            t->Branch("value",&value,"value/D");
            t->Branch("q2min",&q2a,"q2min/D");
            t->Branch("q2max",&q2b,"q2max/D");
            t->Branch("error",&error,"error/D");
            t->Branch("error_up",&error_up,"error_up/D");
            t->Branch("error_down",&error_down,"error_down/D");
            t->Branch("start_value",&start_value,"start_value/D");
            t->Branch("migrad",&migrad,"migrad/I");
            t->Branch("status_cov",&status_cov,"status_cov/I");
            t->Branch("nominal_value",&nominal_value,"nominal_value/D");
            t->Branch("nominal_error",&nominal_error,"nominal_error/D");
            t->Branch("index",&param_index, "index/I");

            std::stringstream corr_stream;
            corr_stream << "correlations[" << corr_max << "]/D";
            t->Branch("correlations",&tmp_corr,corr_stream.str().c_str());

            UInt_t startPDF = 0;
            UInt_t stopPDF = pdf_idx.size();
            if(SimultaneousMoM)
                startPDF = stopPDF - 1;
            else if(OneFit)
                stopPDF = 1;

            for(UInt_t i = startPDF; i < stopPDF; i++){

                pdf = i + 1;

                for(UInt_t b = 0; b < nBins; b++){
                    fcnc::parameter* par = theParams[b].at(i)->get_parameter(p);

                    UInt_t paridx = 0;
                    while(par->get_name() != parname.c_str()){
                        par = theParams[b].at(i)->get_parameter(paridx);
                        paridx++;
                        if(paridx == theParams[b].at(i)->nparameters()){
                            spdlog::warn("Parameter '"+parname+"' not found in PDF{0:d}. Continue with next PDF.",i);
                            break;
                        }
                    }
                    if(paridx == theParams[b].at(i)->nparameters())
                        break;

                    bin = b;
                    q2a = opts.TheQ2binsmin[b];
                    q2b = opts.TheQ2binsmax[b];
                    value = par->get_value();
                    error = par->get_error();
                    error_up = par->get_error_up();
                    error_down = par->get_error_down();
                    start_value = par->get_start_value();
                    nominal_value = par->get_start_value();
                    if(SimultaneousFit){
                        migrad = fit_results[b].at(0) % 100;
                        status_cov = fit_results[b].at(0) / 100;
                    }
                    else{
                        migrad = fit_results[b].at(i) % 100;
                        status_cov = fit_results[b].at(i) / 100;
                    }
                    if (opts.minos_errors){
                        if (error_up==0.0 && value < par->get_max())
                            error_up = par->get_max() - value;
                        if (error_down==0.0 && value > par->get_min())
                            error_down = par->get_min() - value;//needs to be negative
                    }

                    for (unsigned int l = 0; l < corr_max; l++)
                        tmp_corr[l] = 0.0;
                    for (unsigned int l = 0; l < par->correlations.size(); l++)
                        tmp_corr[l] = par->correlations.at(l);
                    t->Fill();
                }
            }
            t->Write();
            delete t;
            param_index++;
        }
    }
    fout->Close();
    return 0;
}