Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-04-05 08:08:16

0001 #include "AsymmetryCalc/ShuffleBunches.h"
0002 #include "AsymmetryCalc/Constants.h"
0003 
0004 #include <iostream>
0005 #include <fstream>
0006 #include <sstream>
0007 #include <random>
0008 #include <cstdlib>
0009 #include <numeric> // for iota
0010 
0011 namespace AsymmetryCalc {
0012   
0013   ShuffleBunches::ShuffleBunches(const int iMin,
0014                                  const int iMax,
0015                                  const std::string& inputfilename_fill_run,
0016                                  const std::string& inputfilename_spin_pattern,
0017                                  const std::string& inputfile_template,
0018                                  const std::string& input_csv_pt_pi0_name,
0019                                  const std::string& input_csv_eta_pi0_name,
0020                                  const std::string& input_csv_xf_pi0_name,
0021                                  const std::string& input_csv_pt_eta_name,
0022                                  const std::string& input_csv_eta_eta_name,
0023                                  const std::string& input_csv_xf_eta_name,
0024                                  const std::string& input_csv_pt_ratios_pi0_name,
0025                                  const std::string& input_csv_eta_ratios_pi0_name,
0026                                  const std::string& input_csv_xf_ratios_pi0_name,
0027                                  const std::string& input_csv_pt_ratios_eta_name,
0028                                  const std::string& input_csv_eta_ratios_eta_name,
0029                                  const std::string& input_csv_xf_ratios_eta_name)
0030     : iterMin(iMin),
0031       iterMax(iMax),
0032       infile_template(inputfile_template)
0033   {
0034     nIterations = iterMax - iterMin + 1;
0035     std::ifstream infile_fill_run(inputfilename_fill_run);
0036     if (!infile_fill_run) {
0037       std::cerr << "Could not open file " << inputfilename_fill_run << std::endl;
0038       std::exit(1);
0039     }
0040 
0041     int fill_number, run_number;
0042     while (infile_fill_run >> fill_number >> run_number) {
0043       if (fill_to_runs.empty() || fill_to_runs.back().first != fill_number)
0044       {
0045         fill_to_runs.push_back({fill_number, {}});
0046       }
0047       fill_to_runs.back().second.push_back(run_number);
0048     }
0049     nFills = fill_to_runs.size();
0050 
0051 
0052     // Read average bin value
0053     get_average_bin_pt_pi0(input_csv_pt_pi0_name);
0054     get_average_bin_eta_pi0(input_csv_eta_pi0_name);
0055     get_average_bin_xf_pi0(input_csv_xf_pi0_name);
0056     get_average_bin_pt_eta(input_csv_pt_eta_name);
0057     get_average_bin_eta_eta(input_csv_eta_eta_name);
0058     get_average_bin_xf_eta(input_csv_xf_eta_name);
0059 
0060     // Read background ratio
0061     get_pt_ratios_pi0(input_csv_pt_ratios_pi0_name);
0062     get_eta_ratios_pi0(input_csv_eta_ratios_pi0_name);
0063     get_xf_ratios_pi0(input_csv_xf_ratios_pi0_name);
0064     get_pt_ratios_eta(input_csv_pt_ratios_eta_name);
0065     get_eta_ratios_eta(input_csv_eta_ratios_eta_name);
0066     get_xf_ratios_eta(input_csv_xf_ratios_eta_name);
0067 
0068     // Read Spin Pattern
0069     inputfile_spin = TFile::Open(inputfilename_spin_pattern.c_str());
0070     spin_patterns = (TTree*)inputfile_spin->Get("spin_patterns");
0071     spin_patterns->SetBranchAddress("fill_number", &fill_spin);
0072     spin_patterns->SetBranchAddress("yellow_polarization", &yellow_polarization);
0073     spin_patterns->SetBranchAddress("blue_polarization", &blue_polarization);
0074     spin_patterns->SetBranchAddress("yellow_spin_pattern", &yellow_spin_pattern);
0075     spin_patterns->SetBranchAddress("blue_spin_pattern", &blue_spin_pattern);
0076   }
0077 
0078   void ShuffleBunches::get_average_bin_pt_pi0(const std::string& input_csv_name)
0079   {
0080     std::string line;
0081     std::stringstream linestream;
0082     std::string entry;
0083     std::ifstream input_csv;
0084     input_csv.open(input_csv_name);
0085     if (!input_csv) {
0086       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0087       return;
0088     }
0089     std::getline(input_csv, line);
0090     std::stringstream line_pi0(line);
0091     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0092       std::getline(line_pi0, entry, ',');
0093       float pTMean = std::stof(entry);
0094       pTMeans[0][iPt] = pTMean;
0095     }
0096     std::getline(input_csv, line);
0097     std::stringstream line_eta(line);
0098     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0099       std::getline(line_eta, entry, ','); // skip
0100     }
0101   }
0102 
0103   void ShuffleBunches::get_average_bin_pt_eta(const std::string& input_csv_name)
0104   {
0105     std::string line;
0106     std::stringstream linestream;
0107     std::string entry;
0108     std::ifstream input_csv;
0109     input_csv.open(input_csv_name);
0110     if (!input_csv) {
0111       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0112       return;
0113     }
0114     std::getline(input_csv, line);
0115     std::stringstream line_pi0(line);
0116     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0117       std::getline(line_pi0, entry, ','); // skip
0118     }
0119     std::getline(input_csv, line);
0120     std::stringstream line_eta(line);
0121     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0122       std::getline(line_eta, entry, ',');
0123       float pTMean = std::stof(entry);
0124       pTMeans[1][iPt] = pTMean;
0125     }
0126   }
0127 
0128   void ShuffleBunches::get_average_bin_eta_pi0(const std::string& input_csv_name)
0129   {
0130     std::string line;
0131     std::stringstream linestream;
0132     std::string entry;
0133     std::ifstream input_csv;
0134     input_csv.open(input_csv_name);
0135     if (!input_csv) {
0136       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0137       return;
0138     }
0139     std::getline(input_csv, line);
0140     std::stringstream line_pi0(line);
0141     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0142       std::getline(line_pi0, entry, ',');
0143       float etaMean = std::stof(entry);
0144       etaMeans[0][iEta] = etaMean;
0145     }
0146     std::getline(input_csv, line);
0147     std::stringstream line_eta(line);
0148     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0149       std::getline(line_eta, entry, ','); // skip
0150     }
0151   }
0152 
0153   void ShuffleBunches::get_average_bin_eta_eta(const std::string& input_csv_name)
0154   {
0155     std::string line;
0156     std::stringstream linestream;
0157     std::string entry;
0158     std::ifstream input_csv;
0159     input_csv.open(input_csv_name);
0160     if (!input_csv) {
0161       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0162       return;
0163     }
0164     std::getline(input_csv, line);
0165     std::stringstream line_pi0(line);
0166     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0167       std::getline(line_pi0, entry, ','); // skip
0168     }
0169     std::getline(input_csv, line);
0170     std::stringstream line_eta(line);
0171     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0172       std::getline(line_eta, entry, ',');
0173       float etaMean = std::stof(entry);
0174       etaMeans[1][iEta] = etaMean;
0175     }
0176   }
0177 
0178   void ShuffleBunches::get_average_bin_xf_pi0(const std::string& input_csv_name)
0179   {
0180     std::string line;
0181     std::stringstream linestream;
0182     std::string entry;
0183     std::ifstream input_csv;
0184     input_csv.open(input_csv_name);
0185     if (!input_csv) {
0186       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0187       return;
0188     }
0189     std::getline(input_csv, line);
0190     std::stringstream line_pi0(line);
0191     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0192       std::getline(line_pi0, entry, ',');
0193       float xfMean = std::stof(entry);
0194       xfMeans[0][iXf] = xfMean;
0195     }
0196     std::getline(input_csv, line);
0197     std::stringstream line_eta(line);
0198     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0199       std::getline(line_eta, entry, ','); // skip
0200     }
0201   }
0202 
0203   void ShuffleBunches::get_average_bin_xf_eta(const std::string& input_csv_name)
0204   {
0205     std::string line;
0206     std::stringstream linestream;
0207     std::string entry;
0208     std::ifstream input_csv;
0209     input_csv.open(input_csv_name);
0210     if (!input_csv) {
0211       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0212       return;
0213     }
0214     std::getline(input_csv, line);
0215     std::stringstream line_pi0(line);
0216     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0217       std::getline(line_pi0, entry, ','); // skip
0218     }
0219     std::getline(input_csv, line);
0220     std::stringstream line_eta(line);
0221     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0222       std::getline(line_eta, entry, ',');
0223       float xfMean = std::stof(entry);
0224       xfMeans[1][iXf] = xfMean;
0225     }
0226   }
0227   
0228   void ShuffleBunches::get_pt_ratios_pi0(const std::string& input_csv_name)
0229   {
0230     std::string line;
0231     std::stringstream linestream;
0232     std::string entry;
0233     std::ifstream input_csv;
0234     input_csv.open(input_csv_name);
0235     if (!input_csv) {
0236       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0237       return;
0238     }
0239     std::getline(input_csv, line);
0240     std::stringstream line_pi0(line);
0241     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0242       std::getline(line_pi0, entry, ',');
0243       float pTRatio = std::stof(entry);
0244       bkg_ratio_pt[0][iPt] = pTRatio;
0245     }
0246     std::getline(input_csv, line);
0247     std::stringstream line_eta(line);
0248     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0249       std::getline(line_eta, entry, ','); // skip
0250     }
0251     std::getline(input_csv, line);
0252     std::stringstream line_pi0_err(line);
0253     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0254       std::getline(line_pi0_err, entry, ',');
0255       float pTRatioErr = std::stof(entry);
0256       bkg_ratio_err_pt[0][iPt] = pTRatioErr;
0257     }
0258     std::getline(input_csv, line);
0259     std::stringstream line_eta_err(line);
0260     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0261       std::getline(line_eta_err, entry, ','); // skip
0262     }
0263   }
0264 
0265   void ShuffleBunches::get_pt_ratios_eta(const std::string& input_csv_name)
0266   {
0267     std::string line;
0268     std::stringstream linestream;
0269     std::string entry;
0270     std::ifstream input_csv;
0271     input_csv.open(input_csv_name);
0272     if (!input_csv) {
0273       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0274       return;
0275     }
0276     std::getline(input_csv, line);
0277     std::stringstream line_pi0(line);
0278     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0279       std::getline(line_pi0, entry, ','); // skip
0280     }
0281     std::getline(input_csv, line);
0282     std::stringstream line_eta(line);
0283     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0284       std::getline(line_eta, entry, ',');
0285       float pTRatio = std::stof(entry);
0286       bkg_ratio_pt[1][iPt] = pTRatio;
0287     }
0288     std::getline(input_csv, line);
0289     std::stringstream line_pi0_err(line);
0290     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0291       std::getline(line_pi0_err, entry, ','); // skip
0292     }
0293     std::getline(input_csv, line);
0294     std::stringstream line_eta_err(line);
0295     for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
0296       std::getline(line_eta_err, entry, ',');
0297       float pTRatioErr = std::stof(entry);
0298       bkg_ratio_err_pt[1][iPt] = pTRatioErr;
0299     }
0300   }
0301 
0302   void ShuffleBunches::get_eta_ratios_pi0(const std::string& input_csv_name)
0303   {
0304     std::string line;
0305     std::stringstream linestream;
0306     std::string entry;
0307     std::ifstream input_csv;
0308     input_csv.open(input_csv_name);
0309     if (!input_csv) {
0310       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0311       return;
0312     }
0313     std::getline(input_csv, line);
0314     std::stringstream line_pi0(line);
0315     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0316       std::getline(line_pi0, entry, ',');
0317       float etaRatio = std::stof(entry);
0318       bkg_ratio_eta[0][iEta] = etaRatio;
0319     }
0320     std::getline(input_csv, line);
0321     std::stringstream line_eta(line);
0322     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0323       std::getline(line_eta, entry, ','); // skip
0324     }
0325     std::getline(input_csv, line);
0326     std::stringstream line_pi0_err(line);
0327     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0328       std::getline(line_pi0_err, entry, ',');
0329       float etaRatioErr = std::stof(entry);
0330       bkg_ratio_err_eta[0][iEta] = etaRatioErr;
0331     }
0332     std::getline(input_csv, line);
0333     std::stringstream line_eta_err(line);
0334     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0335       std::getline(line_eta_err, entry, ','); // skip
0336     }
0337   }
0338 
0339   void ShuffleBunches::get_eta_ratios_eta(const std::string& input_csv_name)
0340   {
0341     std::string line;
0342     std::stringstream linestream;
0343     std::string entry;
0344     std::ifstream input_csv;
0345     input_csv.open(input_csv_name);
0346     if (!input_csv) {
0347       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0348       return;
0349     }
0350     std::getline(input_csv, line);
0351     std::stringstream line_pi0(line);
0352     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0353       std::getline(line_pi0, entry, ','); // skip
0354     }
0355     std::getline(input_csv, line);
0356     std::stringstream line_eta(line);
0357     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0358       std::getline(line_eta, entry, ',');
0359       float etaRatio = std::stof(entry);
0360       bkg_ratio_eta[1][iEta] = etaRatio;
0361     }
0362     std::getline(input_csv, line);
0363     std::stringstream line_pi0_err(line);
0364     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0365       std::getline(line_pi0_err, entry, ','); // skip
0366     }
0367     std::getline(input_csv, line);
0368     std::stringstream line_eta_err(line);
0369     for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
0370       std::getline(line_eta_err, entry, ',');
0371       float etaRatioErr = std::stof(entry);
0372       bkg_ratio_err_eta[1][iEta] = etaRatioErr;
0373     }
0374   }
0375 
0376   void ShuffleBunches::get_xf_ratios_pi0(const std::string& input_csv_name)
0377   {
0378     std::string line;
0379     std::stringstream linestream;
0380     std::string entry;
0381     std::ifstream input_csv;
0382     input_csv.open(input_csv_name);
0383     if (!input_csv) {
0384       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0385       return;
0386     }
0387     std::getline(input_csv, line);
0388     std::stringstream line_pi0(line);
0389     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0390       std::getline(line_pi0, entry, ',');
0391       float xfRatio = std::stof(entry);
0392       bkg_ratio_xf[0][iXf] = xfRatio;
0393     }
0394     std::getline(input_csv, line);
0395     std::stringstream line_eta(line);
0396     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0397       std::getline(line_eta, entry, ','); // skip
0398     }
0399     std::getline(input_csv, line);
0400     std::stringstream line_pi0_err(line);
0401     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0402       std::getline(line_pi0_err, entry, ',');
0403       float xfRatioErr = std::stof(entry);
0404       bkg_ratio_err_xf[0][iXf] = xfRatioErr;
0405     }
0406     std::getline(input_csv, line);
0407     std::stringstream line_eta_err(line);
0408     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0409       std::getline(line_eta_err, entry, ','); // skip
0410     }
0411   }
0412 
0413   void ShuffleBunches::get_xf_ratios_eta(const std::string& input_csv_name)
0414   {
0415     std::string line;
0416     std::stringstream linestream;
0417     std::string entry;
0418     std::ifstream input_csv;
0419     input_csv.open(input_csv_name);
0420     if (!input_csv) {
0421       std::cout << "File " << input_csv_name << " could not be opened." << std::endl;
0422       return;
0423     }
0424     std::getline(input_csv, line);
0425     std::stringstream line_pi0(line);
0426     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0427       std::getline(line_pi0, entry, ','); // skip
0428     }
0429     std::getline(input_csv, line);
0430     std::stringstream line_eta(line);
0431     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0432       std::getline(line_eta, entry, ',');
0433       float xfRatio = std::stof(entry);
0434       bkg_ratio_xf[1][iXf] = xfRatio;
0435     }
0436     std::getline(input_csv, line);
0437     std::stringstream line_pi0_err(line);
0438     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0439       std::getline(line_pi0_err, entry, ','); // skip
0440     }
0441     std::getline(input_csv, line);
0442     std::stringstream line_eta_err(line);
0443     for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
0444       std::getline(line_eta_err, entry, ',');
0445       float xfRatioErr = std::stof(entry);
0446       bkg_ratio_err_xf[1][iXf] = xfRatioErr;
0447     }
0448   }
0449 
0450   ShuffleBunches::~ShuffleBunches()
0451   {
0452     clear_fill_yields();
0453     clear_fill_raw_asyms();
0454     clear_average_raw_asyms();
0455     clear_corr_asyms();
0456     clear_fit_asyms();
0457   }
0458 
0459   void ShuffleBunches::clear_fill_yields()
0460   {
0461     vec_yield_pt.clear();
0462     vec_yield_eta.clear();
0463     vec_yield_xf.clear();
0464   }
0465 
0466   void ShuffleBunches::clear_fill_raw_asyms()
0467   {
0468     fill_pt_asyms.clear();
0469     fill_eta_asyms.clear();
0470     fill_xf_asyms.clear();
0471     fill_pt_asym_errs.clear();
0472     fill_eta_asym_errs.clear();
0473     fill_xf_asym_errs.clear();
0474   }
0475 
0476   void ShuffleBunches::clear_average_raw_asyms()
0477   {
0478     mean_pt.clear();
0479     mean_eta.clear();
0480     mean_xf.clear();
0481     unc_pt.clear();
0482     unc_eta.clear();
0483     unc_xf.clear();
0484   }
0485 
0486   void ShuffleBunches::clear_corr_asyms()
0487   {
0488     corrected_mean_pt.clear();
0489     corrected_mean_eta.clear();
0490     corrected_mean_xf.clear();
0491     corrected_unc_pt.clear();
0492     corrected_unc_eta.clear();
0493     corrected_unc_xf.clear();
0494   }
0495 
0496   void ShuffleBunches::clear_fit_asyms()
0497   {
0498     fit_mean_pt.clear();
0499     fit_mean_eta.clear();
0500     fit_mean_xf.clear();
0501     fit_unc_pt.clear();
0502     fit_unc_eta.clear();
0503     fit_unc_xf.clear();
0504   }
0505 
0506   void ShuffleBunches::reserve_fill_yields()
0507   {
0508     vec_yield_pt.reserve(nIterations);
0509     vec_yield_eta.reserve(nIterations);
0510     vec_yield_xf.reserve(nIterations);
0511   }
0512 
0513 
0514   void ShuffleBunches::reserve_fill_raw_asyms()
0515   {
0516     fill_pt_asyms.reserve(nFills * nIterations);
0517     fill_eta_asyms.reserve(nFills * nIterations);
0518     fill_xf_asyms.reserve(nFills * nIterations);
0519     fill_pt_asym_errs.reserve(nFills * nIterations);
0520     fill_eta_asym_errs.reserve(nFills * nIterations);
0521     fill_xf_asym_errs.reserve(nFills * nIterations);
0522   }
0523   
0524   void ShuffleBunches::reserve_average_raw_asyms()
0525   {
0526     mean_pt.reserve(nIterations);
0527     mean_eta.reserve(nIterations);
0528     mean_xf.reserve(nIterations);
0529     unc_pt.reserve(nIterations);
0530     unc_eta.reserve(nIterations);
0531     unc_xf.reserve(nIterations);
0532   }
0533 
0534   void ShuffleBunches::reserve_corr_asyms()
0535   {
0536     corrected_mean_pt.reserve(nIterations);
0537     corrected_mean_eta.reserve(nIterations);
0538     corrected_mean_xf.reserve(nIterations);
0539     corrected_unc_pt.reserve(nIterations);
0540     corrected_unc_eta.reserve(nIterations);
0541     corrected_unc_xf.reserve(nIterations);
0542   }
0543 
0544   void ShuffleBunches::reserve_fit_asyms()
0545   {
0546     fit_mean_pt.reserve(nIterations);
0547     fit_mean_eta.reserve(nIterations);
0548     fit_mean_xf.reserve(nIterations);
0549     fit_unc_pt.reserve(nIterations);
0550     fit_unc_eta.reserve(nIterations);
0551     fit_unc_xf.reserve(nIterations);
0552   }
0553 
0554   void ShuffleBunches::reset()
0555   {
0556     clear_fill_yields();
0557     clear_fill_raw_asyms();
0558     clear_average_raw_asyms();
0559     clear_corr_asyms();
0560     clear_fit_asyms();
0561   }
0562 
0563   void ShuffleBunches::run_1()
0564   {
0565     reserve_fill_yields();
0566     reserve_fill_raw_asyms();
0567     global_irun = 0;
0568     std::cout << "Compute " << nFills << " fills" << std::endl;
0569     for (int iFill = 0; iFill < nFills; iFill++)
0570     {
0571       compute_fill(iFill);
0572     }
0573   }
0574 
0575   void ShuffleBunches::run_2()
0576   {
0577     reserve_average_raw_asyms();
0578     for (int iIter = 0; iIter < nIterations; iIter++) {
0579       std::cout << "average iter " << (iterMin + iIter) << std::endl;
0580       if (store_iter_histos) {
0581         std::stringstream outputfilename;
0582         outputfilename << outfilename_iter_template << "raw_" << (iterMin + iIter) << ".root";
0583         book_outfile_iter_histograms(outputfilename.str().c_str());
0584       }
0585       average_asyms(iIter);
0586       if (store_iter_histos) {
0587         get_iter_raw_asym_histograms();
0588         save_outfile_iter_histograms();
0589       }
0590     }
0591     clear_fill_raw_asyms();
0592     reserve_fit_asyms();
0593     for (int iIter = 0; iIter < nIterations; iIter++) {
0594       std::cout << "fit iter " << (iterMin + iIter) << std::endl;
0595       if (store_iter_histos) {
0596         std::stringstream outputfilename;
0597         outputfilename << outfilename_iter_template << "fit_" << (iterMin + iIter) << ".root";
0598         book_outfile_iter_histograms(outputfilename.str().c_str());
0599       }
0600       fit_raw_asyms(iIter);
0601       if (store_iter_histos) {
0602         get_iter_fit_asym_histograms();
0603         save_outfile_iter_histograms();
0604       }
0605     }
0606     clear_average_raw_asyms();
0607     reserve_corr_asyms();
0608     for (int iIter = 0; iIter < nIterations; iIter++) {
0609       std::cout << "corr iter " << (iterMin + iIter) << std::endl;
0610       if (store_iter_histos) {
0611         std::stringstream outputfilename;
0612         outputfilename << outfilename_iter_template << "corr_" << (iterMin + iIter) << ".root";
0613         book_outfile_iter_histograms(outputfilename.str().c_str());
0614       }
0615       compute_corrected_asyms(iIter);
0616       if (store_iter_histos) {
0617         get_iter_corr_asym_histograms();
0618         save_outfile_iter_histograms();
0619       }
0620     }
0621   }
0622 
0623   void ShuffleBunches::set_store_fill_histos(bool val, const std::string& outputfilename_template)
0624   {
0625     if (val && nIterations > 1)
0626     {
0627       std::cerr << "Error. Can't store histograms for more than one shuffle iteration" << std::endl;
0628       store_fill_histos = false;
0629     }
0630     else if (val)
0631     {
0632       store_fill_histos = true;
0633       outfilename_fill_template = outputfilename_template;
0634     }
0635     else
0636     {
0637       store_fill_histos = false;
0638     }
0639   }
0640 
0641   void ShuffleBunches::set_store_iter_histos(bool val, const std::string& outputfilename_template)
0642   {
0643     if (val && nIterations > 1)
0644     {
0645       std::cerr << "Error. Can't store histograms for more than one shuffle iteration" << std::endl;
0646       store_iter_histos = false;
0647     }
0648     else if (val)
0649     {
0650       store_iter_histos = true;
0651       outfilename_iter_template = outputfilename_template;
0652     }
0653     else
0654     {
0655       store_iter_histos = false;
0656     }
0657   }
0658 
0659   void ShuffleBunches::book_outfile_fill_histograms(const std::string& outputfilename)
0660   {
0661     // Book histograms
0662     outfile_fill_histograms = new TFile(outputfilename.c_str(), "RECREATE");
0663   }
0664 
0665   void ShuffleBunches::book_outfile_iter_histograms(const std::string& outputfilename)
0666   {
0667     // Book histograms
0668     outfile_iter_histograms = new TFile(outputfilename.c_str(), "RECREATE");
0669   }
0670 
0671   void ShuffleBunches::save_outfile_fill_histograms()
0672   {
0673     outfile_fill_histograms->cd();
0674     outfile_fill_histograms->Write();
0675     outfile_fill_histograms->Close();
0676     delete outfile_fill_histograms;
0677     outfile_fill_histograms = nullptr;
0678   }
0679 
0680   void ShuffleBunches::save_outfile_iter_histograms()
0681   {
0682     outfile_iter_histograms->cd();
0683     outfile_iter_histograms->Write();
0684     outfile_iter_histograms->Close();
0685     delete outfile_iter_histograms;
0686     outfile_iter_histograms = nullptr;
0687   }
0688   
0689   void ShuffleBunches::get_yield_histograms()
0690   {
0691     pt_yield_array &arr_pt_yield = vec_yield_pt.back();
0692     eta_yield_array &arr_eta_yield = vec_yield_eta.back();
0693     xf_yield_array &arr_xf_yield = vec_yield_xf.back();
0694     
0695     outfile_fill_histograms->cd();
0696     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++)
0697     {
0698       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++)
0699       {
0700         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++)
0701         {
0702           for (int iS = 0; iS < ASYM_CONSTANTS::nSpins; iS++)
0703           {
0704             for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++)
0705             {
0706               for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++)
0707               {
0708                 // Book histogram
0709                 std::stringstream h_yield_name;
0710                 h_yield_name << "h_yield_" << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP]
0711                              << "_" << ASYM_CONSTANTS::regions[iR] << "_"
0712                              << "pT_" << iPt << "_"
0713                              << ASYM_CONSTANTS::directions[iDir]
0714                              << "_" << ASYM_CONSTANTS::spins[iS];
0715                 std::stringstream h_yield_title;
0716                 h_yield_title << "#phi_{" << (iB == 0 ? "yellow" : "blue")
0717                               << "};counts";
0718                 h_yield_pt[iB][iP][iR][iPt][iDir][iS] =
0719                   new TH1F(h_yield_name.str().c_str(),
0720                            h_yield_title.str().c_str(), 12, -M_PI, M_PI);
0721 
0722                 // Fill histogram
0723                 for (int iphi = 0; iphi < ASYM_CONSTANTS::nPhiBins; iphi++)
0724                 {
0725                   h_yield_pt[iB][iP][iR][iPt][iDir][iS]->SetBinContent(
0726                     iphi + 1,
0727                     arr_pt_yield(iB, iP, iR, iPt, iDir, iS, iphi));
0728                 }
0729               }
0730             }
0731             for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++)
0732             {
0733               // Book histogram
0734               std::stringstream h_yield_name;
0735               h_yield_name << "h_yield_" << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP]
0736                            << "_" << ASYM_CONSTANTS::regions[iR] << "_"
0737                            << "eta_" << (int) iEta << "_" << ASYM_CONSTANTS::spins[iS];
0738               std::stringstream h_yield_title;
0739               h_yield_title << "#phi_{" << (iB == 0 ? "yellow" : "blue")
0740                             << "};counts";
0741               h_yield_eta[iB][iP][iR][iEta][iS] =
0742                   new TH1F(h_yield_name.str().c_str(),
0743                            h_yield_title.str().c_str(), 12, -M_PI, M_PI);
0744 
0745               // Fill histogram
0746               for (int iphi = 0; iphi < ASYM_CONSTANTS::nPhiBins; iphi++)
0747               {
0748                 h_yield_eta[iB][iP][iR][iEta][iS]->SetBinContent(
0749                   iphi + 1,
0750                   arr_eta_yield(iB, iP, iR, iEta, iS, iphi));
0751               }
0752             }
0753             for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++)
0754             {
0755               // Book histogram
0756               std::stringstream h_yield_name;
0757               h_yield_name << "h_yield_" << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP]
0758                            << "_" << ASYM_CONSTANTS::regions[iR] << "_"
0759                            << "xf_" << (int) iXf << "_" << ASYM_CONSTANTS::spins[iS];
0760               std::stringstream h_yield_title;
0761               h_yield_title << "#phi_{" << (iB == 0 ? "yellow" : "blue")
0762                             << "};counts";
0763               h_yield_xf[iB][iP][iR][iXf][iS] =
0764                   new TH1F(h_yield_name.str().c_str(),
0765                            h_yield_title.str().c_str(), 12, -M_PI, M_PI);
0766               
0767               // Fill histogram
0768               for (int iphi = 0; iphi < ASYM_CONSTANTS::nPhiBins; iphi++)
0769               {
0770                 h_yield_xf[iB][iP][iR][iXf][iS]->SetBinContent(
0771                   iphi + 1,
0772                   arr_xf_yield(iB, iP, iR, iXf, iS, iphi));
0773               }
0774             }
0775           }
0776         }
0777       }
0778     }
0779   }
0780 
0781   void ShuffleBunches::get_fill_raw_asym_histograms()
0782   {
0783     pt_asym_array& arr_pt_asym = fill_pt_asyms.back();
0784     eta_asym_array& arr_eta_asym = fill_eta_asyms.back();
0785     xf_asym_array& arr_xf_asym = fill_xf_asyms.back();
0786     pt_asym_array& arr_pt_asym_err = fill_pt_asym_errs.back();
0787     eta_asym_array& arr_eta_asym_err = fill_eta_asym_errs.back();
0788     xf_asym_array& arr_xf_asym_err = fill_xf_asym_errs.back();
0789     
0790     outfile_fill_histograms->cd();
0791     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++)
0792     {
0793       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++)
0794       {
0795         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++)
0796         {
0797           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++)
0798           {
0799             for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++)
0800             {
0801               TGraphErrors *graph_AN = new TGraphErrors();
0802               std::stringstream graph_AN_name;
0803               graph_AN_name << "graph_asym_pt_"
0804                             << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
0805                             << ASYM_CONSTANTS::regions[iR] << "_"
0806                             << "pT_" << iPt << "_"
0807                             << ASYM_CONSTANTS::directions[iDir] << "_"
0808                             << "sqrt";
0809               graph_AN->SetName(graph_AN_name.str().c_str());
0810               std::stringstream graph_title;
0811               graph_title << "; #phi; " << (iR == 0 ? "Raw" : "Bkg") << " Asymmetry";
0812               graph_AN->SetTitle(graph_title.str().c_str());
0813               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++)
0814               {
0815                 float phi = -M_PI + M_PI / 12 + iPhi * M_PI / 6.;
0816                 graph_AN->SetPoint(iPhi, phi, arr_pt_asym(iB, iP, iR, iPt, iDir, iPhi));
0817                 graph_AN->SetPointError(iPhi, 0, arr_pt_asym_err(iB, iP, iR, iPt, iDir, iPhi));
0818               }
0819               graph_AN->Write();
0820             }
0821           }
0822           for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++)
0823           {
0824             TGraphErrors *graph_AN = new TGraphErrors();
0825             std::stringstream graph_AN_name;
0826             graph_AN_name << "graph_asym_eta_"
0827                           << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
0828                           << ASYM_CONSTANTS::regions[iR] << "_"
0829                           << "eta_" << iEta << "_sqrt";
0830             graph_AN->SetName(graph_AN_name.str().c_str());
0831             std::stringstream graph_title;
0832             graph_title << "; #phi; " << (iR == 0 ? "Raw" : "Bkg") << " Asymmetry";
0833             graph_AN->SetTitle(graph_title.str().c_str());
0834             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++)
0835             {
0836               float phi = -M_PI + M_PI / 12 + iPhi * M_PI / 6.;
0837               graph_AN->SetPoint(iPhi, phi, arr_eta_asym(iB, iP, iR, iEta, iPhi));
0838               graph_AN->SetPointError(iPhi, 0, arr_eta_asym_err(iB, iP, iR, iEta, iPhi));
0839             }
0840             graph_AN->Write();
0841           }
0842           for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++)
0843           {
0844             TGraphErrors *graph_AN = new TGraphErrors();
0845             std::stringstream graph_AN_name;
0846             graph_AN_name << "graph_asym_xf_"
0847                           << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
0848                           << ASYM_CONSTANTS::regions[iR] << "_"
0849                           << "xf_" << iXf << "_sqrt";
0850             graph_AN->SetName(graph_AN_name.str().c_str());
0851             std::stringstream graph_title;
0852             graph_title << "; #phi; " << (iR == 0 ? "Raw" : "Bkg") << " Asymmetry";
0853             graph_AN->SetTitle(graph_title.str().c_str());
0854 
0855             // Fill
0856             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++)
0857             {
0858               float phi = -M_PI + M_PI / 12 + iPhi * M_PI / 6.;
0859               graph_AN->SetPoint(iPhi, phi, arr_xf_asym(iB, iP, iR, iXf, iPhi));
0860               graph_AN->SetPointError(iPhi, 0, arr_xf_asym_err(iB, iP, iR, iXf, iPhi));
0861             }
0862             graph_AN->Write();
0863           }
0864         }
0865       }
0866     }
0867   }
0868   
0869   void ShuffleBunches::compute_fill(const int ifill)
0870   {
0871     //std::cout << "Compute fill " << ifill << std::endl;
0872     //std::cout << "yields.size = " << vec_yield_xf.size() << std::endl;
0873     const int fill_number = fill_to_runs[ifill].first;
0874     const std::vector<int>& runs = fill_to_runs[ifill].second;
0875     const int nRuns = runs.size();
0876 
0877     // Get fill-dependent spin pattern
0878     spin_patterns->GetEntry((unsigned long)ifill);
0879     if (fill_number != fill_spin) {
0880       std::cerr << "Mismatch in fill number: " << fill_number << " != " << fill_spin << std::endl;
0881       return;
0882     }
0883     for (int i = 0; i < ASYM_CONSTANTS::nBunches; i++) {
0884       spin_pattern[0][i] = yellow_spin_pattern[i];
0885       spin_pattern[1][i] = blue_spin_pattern[i];
0886     }
0887     polarization[0] = yellow_polarization;
0888     polarization[1] = blue_polarization;
0889 
0890     if (store_fill_histos)
0891     {
0892       std::stringstream outputfilename;
0893       outputfilename << outfilename_fill_template << fill_number << ".root";
0894       book_outfile_fill_histograms(outputfilename.str());
0895     }
0896 
0897     for (int iRun = 0; iRun < nRuns; iRun++)
0898     {
0899       std::string infilename = infile_template + std::to_string(runs[iRun]) + ".bin";
0900       read_binary_array(infilename);
0901       for (int iIter = 0; iIter < nIterations; iIter++)
0902       {
0903         int iter = iterMin + iIter;
0904         // Shuffle bunch indices and flip spin
0905         int seednumber = (do_shuffle ? (iter + 100000 * (global_irun + iRun)) : 0);
0906         shuffle_bunch_indices(seednumber);
0907         
0908         // Sum shuffled bunches
0909         sum_yields(iIter);
0910       }
0911     }
0912 
0913     //std::cout << "yields.size 2 = " << vec_yield_xf.size() << std::endl;
0914 
0915     if (store_fill_histos) {
0916       get_yield_histograms();
0917     }
0918 
0919     for (int iIter = 0; iIter < nIterations; iIter++)
0920     {
0921       // Get (Square Root) Raw Asymmetries
0922       compute_raw_asyms(iIter);
0923     }
0924     clear_fill_yields();
0925 
0926     //std::cout << "yields.size 3 = " << vec_yield_xf.size() << std::endl;
0927 
0928     global_irun += nRuns;
0929 
0930     if (store_fill_histos)
0931     {
0932       get_fill_raw_asym_histograms();
0933       save_outfile_fill_histograms(); // includes deletion
0934     }
0935   }
0936   
0937   void ShuffleBunches::read_binary_array(const std::string& inputfilename)
0938   {
0939     std::ifstream inbinary(inputfilename, std::ios::binary);
0940     //std::cout << "size of pt array = " << sizeof(array_yield_pt_bunches) << std::endl;
0941     inbinary.read(reinterpret_cast<char*>(array_yield_pt_bunches), sizeof(array_yield_pt_bunches));
0942     inbinary.read(reinterpret_cast<char*>(array_yield_eta_bunches), sizeof(array_yield_eta_bunches));
0943     inbinary.read(reinterpret_cast<char*>(array_yield_xf_bunches), sizeof(array_yield_xf_bunches));
0944   }
0945   
0946   void ShuffleBunches::shuffle_bunch_indices(const int seednumber)
0947   {
0948     // Shuffle the spin pattern if the seed number is non zero
0949     // Only consider the first 111/(nBunches = 120) bunches, the last 9 are
0950     // always empty.
0951 
0952     // Reset indices before the shuffle
0953     std::iota(shuffled_indices, shuffled_indices + ASYM_CONSTANTS::nBunches, 0);
0954     if (seednumber != 0)
0955     {
0956       // Pseudo-random generator: Mersenne twister with a period of 2^19937 - 1
0957       //std::cout << "seed = " << seednumber << std::endl;
0958       std::mt19937 rng(seednumber);
0959       std::shuffle(shuffled_indices, shuffled_indices + ASYM_CONSTANTS::nBunches, rng);
0960 
0961       // With a probability 1/2, flip all the bunch spins
0962       std::uniform_int_distribution<std::mt19937::result_type> dist2(0, 1);
0963       int factor = 2 * (int) dist2(rng) - 1;
0964       spin_flip = (factor == -1 ? true : false);
0965     }
0966     
0967     //std::cout << "shuffled_indices = ";
0968     // for (int i = 0; i < ASYM_CONSTANTS::nBunches; i++)
0969     //   std::cout << shuffled_indices[i] << " ";
0970     // std::cout << std::endl;
0971   }
0972 
0973   void ShuffleBunches::sum_yields(const int iIter)
0974   {
0975     pt_yield_array arr_yield_pt;
0976     eta_yield_array arr_yield_eta;
0977     xf_yield_array arr_yield_xf;
0978     
0979     // Use the shuffled spins
0980     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
0981       for (int iBunch = 0; iBunch < ASYM_CONSTANTS::nBunches; iBunch++) {
0982         shuffled_spin_pattern[iB][iBunch] = spin_pattern[iB][shuffled_indices[iBunch]];
0983       }
0984     }
0985     
0986     auto spin_to_index = [](int8_t s) -> int {
0987       if (s == 1)  return 0;
0988       if (s == -1) return 1;
0989       std::cerr << "Error for spin value (expected +1 or -1)" << std::endl;
0990       exit(1);
0991     };
0992 
0993     for (int iBunch = 0; iBunch < ASYM_CONSTANTS::nBunches; ++iBunch) {
0994       for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; ++iB) {
0995         const int8_t true_spin = spin_pattern[iB][iBunch];
0996 
0997         int8_t shuffled_spin = shuffled_spin_pattern[iB][iBunch];
0998         if (spin_flip) shuffled_spin = -shuffled_spin;
0999 
1000         const int iS_true    = spin_to_index(true_spin);
1001         const int iS_shuffle = spin_to_index(shuffled_spin);
1002 
1003         for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; ++iP) {
1004           for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; ++iR) {
1005             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; ++iPhi) {
1006               for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; ++iPt) {
1007                 for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; ++iDir) {
1008                   arr_yield_pt(iB, iP, iR, iPt, iDir, iS_shuffle, iPhi) +=
1009                       array_yield_pt_bunches[iB][iP][iR][iPt][iDir][iS_true][iPhi][iBunch];
1010                 }
1011               }
1012 
1013               for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; ++iEta) {
1014                 arr_yield_eta(iB, iP, iR, iEta, iS_shuffle, iPhi) +=
1015                     array_yield_eta_bunches[iB][iP][iR][iEta][iS_true][iPhi][iBunch];
1016               }
1017 
1018               for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; ++iXf) {
1019                 arr_yield_xf(iB, iP, iR, iXf, iS_shuffle, iPhi) +=
1020                     array_yield_xf_bunches[iB][iP][iR][iXf][iS_true][iPhi][iBunch];
1021               }
1022             }
1023           }
1024         }
1025       }
1026     }
1027     
1028     if (vec_yield_pt.size() <= iIter) {
1029       vec_yield_pt.resize(iIter+1);
1030       vec_yield_eta.resize(iIter+1);
1031       vec_yield_xf.resize(iIter+1);
1032     }
1033     vec_yield_pt[iIter] += arr_yield_pt;
1034     vec_yield_eta[iIter] += arr_yield_eta;
1035     vec_yield_xf[iIter] += arr_yield_xf;
1036   }
1037 
1038   void ShuffleBunches::compute_raw_asyms(const int iIter)
1039   {
1040     pt_yield_array &arr_pt_yield = vec_yield_pt[iIter];
1041     eta_yield_array &arr_eta_yield = vec_yield_eta[iIter];
1042     xf_yield_array &arr_xf_yield = vec_yield_xf[iIter];
1043     
1044     pt_asym_array arr_pt_asym;
1045     pt_nodir_asym_array arr_pt_nodir_asym;
1046     eta_asym_array arr_eta_asym;
1047     xf_asym_array arr_xf_asym;
1048     pt_asym_array arr_pt_asym_err;
1049     pt_nodir_asym_array arr_pt_nodir_asym_err;
1050     eta_asym_array arr_eta_asym_err;
1051     xf_asym_array arr_xf_asym_err;
1052     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
1053       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++) {
1054         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++) {
1055           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1056             {
1057               double array_asym[ASYM_CONSTANTS::nPhiBins];
1058               double array_asym_err[ASYM_CONSTANTS::nPhiBins];
1059               uint32_t array_yield[ASYM_CONSTANTS::nSpins][ASYM_CONSTANTS::nPhiBins];
1060               for (int iS = 0; iS < ASYM_CONSTANTS::nSpins; iS++) {
1061                 for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1062                   array_yield[iS][iPhi] =
1063                     arr_pt_yield(iB, iP, iR, iPt, 0, iS, iPhi) +
1064                     arr_pt_yield(iB, iP, iR, iPt, 1, iS, iPhi);
1065                 }
1066               }
1067               compute_sqrt_asym(array_yield, polarization[iB], array_asym, array_asym_err);
1068               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1069                 arr_pt_nodir_asym(iB, iP, iR, iPt, iPhi) = array_asym[iPhi];
1070                 arr_pt_nodir_asym_err(iB, iP, iR, iPt, iPhi) = array_asym_err[iPhi];
1071               }
1072             }
1073             for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++) {
1074               double array_asym[ASYM_CONSTANTS::nPhiBins];
1075               double array_asym_err[ASYM_CONSTANTS::nPhiBins];
1076               uint32_t array_yield[ASYM_CONSTANTS::nSpins][ASYM_CONSTANTS::nPhiBins];
1077               for (int iS = 0; iS < ASYM_CONSTANTS::nSpins; iS++) {
1078                 for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1079                   array_yield[iS][iPhi] = arr_pt_yield(iB, iP, iR, iPt, iDir, iS, iPhi);
1080                 }
1081               }
1082               compute_sqrt_asym(array_yield, polarization[iB], array_asym, array_asym_err);
1083               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1084                 arr_pt_asym(iB, iP, iR, iPt, iDir, iPhi) = array_asym[iPhi];
1085                 arr_pt_asym_err(iB, iP, iR, iPt, iDir, iPhi) = array_asym_err[iPhi];
1086                 
1087               }
1088             }
1089           }
1090           for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
1091             double array_asym[ASYM_CONSTANTS::nPhiBins];
1092             double array_asym_err[ASYM_CONSTANTS::nPhiBins];
1093             uint32_t array_yield[ASYM_CONSTANTS::nSpins][ASYM_CONSTANTS::nPhiBins];
1094             for (int iS = 0; iS < ASYM_CONSTANTS::nSpins; iS++) {
1095               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1096                 array_yield[iS][iPhi] = arr_eta_yield(iB, iP, iR, iEta, iS, iPhi);
1097               }
1098             }
1099             compute_sqrt_asym(array_yield, polarization[iB], array_asym, array_asym_err);
1100             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1101               arr_eta_asym(iB, iP, iR, iEta, iPhi) = array_asym[iPhi];
1102               arr_eta_asym_err(iB, iP, iR, iEta, iPhi) = array_asym_err[iPhi];
1103             }
1104           }
1105           for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
1106             double array_asym[ASYM_CONSTANTS::nPhiBins];
1107             double array_asym_err[ASYM_CONSTANTS::nPhiBins];
1108             uint32_t array_yield[ASYM_CONSTANTS::nSpins][ASYM_CONSTANTS::nPhiBins];
1109             for (int iS = 0; iS < ASYM_CONSTANTS::nSpins; iS++) {
1110               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1111                 array_yield[iS][iPhi] = arr_xf_yield(iB, iP, iR, iXf, iS, iPhi);
1112               }
1113             }
1114             compute_sqrt_asym(array_yield, polarization[iB], array_asym, array_asym_err);
1115             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1116               arr_xf_asym(iB, iP, iR, iXf, iPhi) = array_asym[iPhi];
1117               arr_xf_asym_err(iB, iP, iR, iXf, iPhi) = array_asym_err[iPhi];
1118             }
1119           }
1120         }
1121       }
1122     }
1123     fill_pt_asyms.push_back(arr_pt_asym);
1124     fill_pt_nodir_asyms.push_back(arr_pt_nodir_asym);
1125     fill_eta_asyms.push_back(arr_eta_asym);
1126     fill_xf_asyms.push_back(arr_xf_asym);
1127     fill_pt_asym_errs.push_back(arr_pt_asym_err);
1128     fill_pt_nodir_asym_errs.push_back(arr_pt_nodir_asym_err);
1129     fill_eta_asym_errs.push_back(arr_eta_asym_err);
1130     fill_xf_asym_errs.push_back(arr_xf_asym_err);
1131   }
1132 
1133   void ShuffleBunches::average_asyms(const int iIter)
1134   {
1135     double sum_weights_pt[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nPtBins][ASYM_CONSTANTS::nDirections][ASYM_CONSTANTS::nPhiBins] = {0};
1136     double sum_weights_pt_nodir[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nPtBins][ASYM_CONSTANTS::nPhiBins] = {0};
1137     double sum_weights_eta[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nEtaBins][ASYM_CONSTANTS::nPhiBins] = {0};
1138     double sum_weights_xf[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nXfBins][ASYM_CONSTANTS::nPhiBins] = {0};
1139 
1140     double sum_weighted_asym_pt[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nPtBins][ASYM_CONSTANTS::nDirections][ASYM_CONSTANTS::nPhiBins] = {0};
1141     double sum_weighted_asym_pt_nodir[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nPtBins][ASYM_CONSTANTS::nPhiBins] = {0};
1142     double sum_weighted_asym_eta[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nEtaBins][ASYM_CONSTANTS::nPhiBins] = {0};
1143     double sum_weighted_asym_xf[ASYM_CONSTANTS::nBeams][ASYM_CONSTANTS::nParticles][ASYM_CONSTANTS::nRegions][ASYM_CONSTANTS::nXfBins][ASYM_CONSTANTS::nPhiBins] = {0};
1144     
1145     for (size_t iFill = 0; iFill < nFills; iFill++) {
1146       for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
1147         for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++) {
1148           for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++) {
1149             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1150               for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1151                 {
1152                   const double& asym = fill_pt_nodir_asyms[nIterations * iFill + iIter](iB, iP, iR, iPt, iPhi);
1153                   const double& asym_err = fill_pt_nodir_asym_errs[nIterations * iFill + iIter](iB, iP, iR, iPt, iPhi);
1154                   if (asym == asym && asym_err == asym_err && asym_err > 0)
1155                   {
1156                     sum_weights_pt_nodir[iB][iP][iR][iPt][iPhi] += std::pow(asym_err, -2);
1157                     sum_weighted_asym_pt_nodir[iB][iP][iR][iPt][iPhi] += asym * std::pow(asym_err, -2);
1158                   }
1159                 }
1160                 for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++) {
1161                   const double& asym = fill_pt_asyms[nIterations * iFill + iIter](iB, iP, iR, iPt, iDir, iPhi);
1162                   const double& asym_err = fill_pt_asym_errs[nIterations * iFill + iIter](iB, iP, iR, iPt, iDir, iPhi);
1163                   if (asym == asym && asym_err == asym_err && asym_err > 0)
1164                   {
1165                     sum_weights_pt[iB][iP][iR][iPt][iDir][iPhi] += std::pow(asym_err, -2);
1166                     sum_weighted_asym_pt[iB][iP][iR][iPt][iDir][iPhi] += asym * std::pow(asym_err, -2);
1167                   }
1168                 }
1169               }
1170               for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
1171                 const double& asym = fill_eta_asyms[nIterations * iFill + iIter](iB, iP, iR, iEta, iPhi);
1172                 const double& asym_err = fill_eta_asym_errs[nIterations * iFill + iIter](iB, iP, iR, iEta, iPhi);
1173                 if (asym == asym && asym_err == asym_err && asym_err > 0)
1174                 {
1175                   sum_weights_eta[iB][iP][iR][iEta][iPhi] += std::pow(asym_err, -2);
1176                   sum_weighted_asym_eta[iB][iP][iR][iEta][iPhi] += asym * std::pow(asym_err, -2);
1177                 }
1178               }
1179               for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
1180                 const double& asym = fill_xf_asyms[nIterations * iFill + iIter](iB, iP, iR, iXf, iPhi);
1181                 const double& asym_err = fill_xf_asym_errs[nIterations * iFill + iIter](iB, iP, iR, iXf, iPhi);
1182                 if (asym == asym && asym_err == asym_err && asym_err > 0)
1183                 {
1184                   
1185                   sum_weights_xf[iB][iP][iR][iXf][iPhi] += std::pow(asym_err, -2);
1186                   sum_weighted_asym_xf[iB][iP][iR][iXf][iPhi] += asym * std::pow(asym_err, -2);
1187                   // if (iB == 1 && iP == 1 && iR == 1 && iXf == 4 && iPhi == 0) {
1188                   //   std::cout << "iFill, asym, asym_err, sum_weights, sum_weighted_asyms =\n"
1189                   //             << iFill << ", "
1190                   //             << asym << ", "
1191                   //             << asym_err << ", "
1192                   //             << sum_weights_xf[iB][iP][iR][iXf][iPhi] << ", "
1193                   //             << sum_weighted_asym_xf[iB][iP][iR][iXf][iPhi] << std::endl;
1194                   // }
1195                 }
1196               }
1197             }
1198           }
1199         }
1200       }
1201     }
1202 
1203     pt_asym_array average_mean_pt;
1204     pt_nodir_asym_array average_mean_pt_nodir;
1205     eta_asym_array average_mean_eta;
1206     xf_asym_array average_mean_xf;
1207 
1208     pt_asym_array average_unc_pt;
1209     pt_nodir_asym_array average_unc_pt_nodir;
1210     eta_asym_array average_unc_eta;
1211     xf_asym_array average_unc_xf;
1212     
1213     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
1214       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++) {
1215         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++) {
1216           for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1217             for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1218               {
1219                 if (sum_weights_pt_nodir[iB][iP][iR][iPt][iPhi] > 0) {
1220                   average_mean_pt_nodir(iB, iP, iR, iPt, iPhi) =
1221                     sum_weighted_asym_pt_nodir[iB][iP][iR][iPt][iPhi] /
1222                     sum_weights_pt_nodir[iB][iP][iR][iPt][iPhi];
1223                   average_unc_pt_nodir(iB, iP, iR, iPt, iPhi) = 1. /
1224                     std::sqrt(sum_weights_pt_nodir[iB][iP][iR][iPt][iPhi]);
1225                 }
1226                 else {
1227                   average_mean_pt_nodir(iB, iP, iR, iPt, iPhi) = 0;
1228                   average_unc_pt_nodir(iB, iP, iR, iPt, iPhi) = 0;
1229                 }
1230               }
1231               for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++) {
1232                 if (sum_weights_pt[iB][iP][iR][iPt][iDir][iPhi] > 0) {
1233                   average_mean_pt(iB, iP, iR, iPt, iDir, iPhi) =
1234                     sum_weighted_asym_pt[iB][iP][iR][iPt][iDir][iPhi] /
1235                     sum_weights_pt[iB][iP][iR][iPt][iDir][iPhi];
1236                   average_unc_pt(iB, iP, iR, iPt, iDir, iPhi) = 1. /
1237                     std::sqrt(sum_weights_pt[iB][iP][iR][iPt][iDir][iPhi]);
1238                 }
1239                 else {
1240                   average_mean_pt(iB, iP, iR, iPt, iDir, iPhi) = 0;
1241                   average_unc_pt(iB, iP, iR, iPt, iDir, iPhi) = 0;
1242                 }
1243               }
1244             }
1245             for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
1246               if (sum_weights_eta[iB][iP][iR][iEta][iPhi] > 0) {
1247                 average_mean_eta(iB, iP, iR, iEta, iPhi) =
1248                   sum_weighted_asym_eta[iB][iP][iR][iEta][iPhi] /
1249                   sum_weights_eta[iB][iP][iR][iEta][iPhi];
1250                 average_unc_eta(iB, iP, iR, iEta, iPhi) = 1. /
1251                   std::sqrt(sum_weights_eta[iB][iP][iR][iEta][iPhi]);
1252               } else {
1253                 average_mean_eta(iB, iP, iR, iEta, iPhi) = 0;
1254                 average_unc_eta(iB, iP, iR, iEta, iPhi) = 0;
1255               }
1256             }
1257             for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
1258               if (sum_weights_xf[iB][iP][iR][iXf][iPhi] > 0) {
1259                 average_mean_xf(iB, iP, iR, iXf, iPhi) =
1260                   sum_weighted_asym_xf[iB][iP][iR][iXf][iPhi] /
1261                   sum_weights_xf[iB][iP][iR][iXf][iPhi];
1262                 average_unc_xf(iB, iP, iR, iXf, iPhi) = 1. /
1263                   std::sqrt(sum_weights_xf[iB][iP][iR][iXf][iPhi]);
1264               } else {
1265                 average_mean_xf(iB, iP, iR, iXf, iPhi) = 0;
1266                 average_unc_xf(iB, iP, iR, iXf, iPhi) = 0;
1267               }
1268             }
1269           }
1270         }
1271       }
1272     }
1273 
1274     // // Fill-dependent raw asymmetries are no longer needed
1275     // fill_pt_asyms.clear();
1276     // fill_eta_asyms.clear();
1277     // fill_xf_asyms.clear();
1278     // fill_pt_asym_errs.clear();
1279     // fill_eta_asym_errs.clear();
1280     // fill_xf_asym_errs.clear();
1281 
1282     // Now fill the iteration-dependent vector
1283     mean_pt.push_back(average_mean_pt);
1284     mean_pt_nodir.push_back(average_mean_pt_nodir);
1285     mean_eta.push_back(average_mean_eta);
1286     mean_xf.push_back(average_mean_xf);
1287     unc_pt.push_back(average_unc_pt);
1288     unc_pt_nodir.push_back(average_unc_pt_nodir);
1289     unc_eta.push_back(average_unc_eta);
1290     unc_xf.push_back(average_unc_xf);
1291   }
1292 
1293   void ShuffleBunches::fit_raw_asyms(const int iIter)
1294   {
1295     const pt_asym_array& average_mean_pt = mean_pt[iIter];
1296     const pt_nodir_asym_array& average_mean_pt_nodir = mean_pt_nodir[iIter];
1297     const eta_asym_array& average_mean_eta = mean_eta[iIter];
1298     const xf_asym_array& average_mean_xf = mean_xf[iIter];
1299     const pt_asym_array& average_unc_pt = unc_pt[iIter];
1300     const pt_nodir_asym_array& average_unc_pt_nodir = unc_pt_nodir[iIter];
1301     const eta_asym_array& average_unc_eta = unc_eta[iIter];
1302     const xf_asym_array& average_unc_xf = unc_xf[iIter];
1303 
1304     pt_fit_array fit_average_mean_pt;
1305     pt_nodir_fit_array fit_average_mean_pt_nodir;
1306     eta_fit_array fit_average_mean_eta;
1307     xf_fit_array fit_average_mean_xf;
1308     pt_fit_array fit_average_unc_pt;
1309     pt_nodir_fit_array fit_average_unc_pt_nodir;
1310     eta_fit_array fit_average_unc_eta;
1311     xf_fit_array fit_average_unc_xf;
1312 
1313     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
1314       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++) {
1315         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++) {
1316           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1317             {
1318               double asym_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1319               double asym_err_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1320               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1321                 asym_azimuth[iPhi] = average_mean_pt_nodir(iB, iP, iR, iPt, iPhi);
1322                 asym_err_azimuth[iPhi] = average_unc_pt_nodir(iB, iP, iR, iPt, iPhi);
1323               }
1324               fit_asym(fit_average_mean_pt_nodir(iB, iP, iR, iPt),
1325                        fit_average_unc_pt_nodir(iB, iP, iR, iPt),
1326                        asym_azimuth,
1327                        asym_err_azimuth);
1328             }
1329             for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++) {
1330               double asym_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1331               double asym_err_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1332               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1333                 asym_azimuth[iPhi] = average_mean_pt(iB, iP, iR, iPt, iDir, iPhi);
1334                 asym_err_azimuth[iPhi] = average_unc_pt(iB, iP, iR, iPt, iDir, iPhi);
1335               }
1336               fit_asym(fit_average_mean_pt(iB, iP, iR, iPt, iDir),
1337                        fit_average_unc_pt(iB, iP, iR, iPt, iDir),
1338                        asym_azimuth,
1339                        asym_err_azimuth);
1340             }
1341           }
1342           for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
1343             double asym_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1344             double asym_err_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1345             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1346               asym_azimuth[iPhi] = average_mean_eta(iB, iP, iR, iEta, iPhi);
1347               asym_err_azimuth[iPhi] = average_unc_eta(iB, iP, iR, iEta, iPhi);
1348             }
1349             fit_asym(fit_average_mean_eta(iB, iP, iR, iEta),
1350                      fit_average_unc_eta(iB, iP, iR, iEta),
1351                      asym_azimuth,
1352                      asym_err_azimuth);
1353           }
1354           for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
1355             double asym_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1356             double asym_err_azimuth[ASYM_CONSTANTS::nPhiBins] = {0};
1357             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1358               asym_azimuth[iPhi] = average_mean_xf(iB, iP, iR, iXf, iPhi);
1359               asym_err_azimuth[iPhi] = average_unc_xf(iB, iP, iR, iXf, iPhi);
1360             }
1361             fit_asym(fit_average_mean_xf(iB, iP, iR, iXf),
1362                      fit_average_unc_xf(iB, iP, iR, iXf),
1363                      asym_azimuth,
1364                      asym_err_azimuth);
1365           }
1366         }
1367       }
1368     }
1369     fit_mean_pt.push_back(fit_average_mean_pt);
1370     fit_mean_pt_nodir.push_back(fit_average_mean_pt_nodir);
1371     fit_mean_eta.push_back(fit_average_mean_eta);
1372     fit_mean_xf.push_back(fit_average_mean_xf);
1373     fit_unc_pt.push_back(fit_average_unc_pt);
1374     fit_unc_pt_nodir.push_back(fit_average_unc_pt_nodir);
1375     fit_unc_eta.push_back(fit_average_unc_eta);
1376     fit_unc_xf.push_back(fit_average_unc_xf);
1377   }
1378 
1379   void ShuffleBunches::fit_asym(double& asym_amplitude,
1380                                 double& asym_amplitude_err,
1381                                 const double (&asym_azimuth_values)[ASYM_CONSTANTS::nPhiBins],
1382                                 const double (&asym_azimuth_uncertainties)[ASYM_CONSTANTS::nPhiBins],
1383                                 bool fit_geom)
1384   {
1385     int N = (fit_geom ? ASYM_CONSTANTS::nPhiBins / 2 : ASYM_CONSTANTS::nPhiBins);
1386 
1387     // Output defaults
1388     asym_amplitude     = 0.0;
1389     asym_amplitude_err = 0.0;
1390 
1391     // 12 equal bins from -pi to +pi  => use bin centers
1392     double phi[N];
1393     double y[N];
1394     double ex[N];
1395     double ey[N];
1396 
1397     double phiMin = (fit_geom ? - M_PI / 2 : -M_PI);
1398     double phiMax = (fit_geom ? M_PI / 2 : M_PI);
1399     const double dphi = (phiMax - phiMin) / N;
1400 
1401     for (int i = 0; i < N; ++i) {
1402       int iphi = (fit_geom ? i + 3 : i);
1403       phi[i] = phiMin + (i + 0.5) * dphi;
1404       y[i]   = asym_azimuth_values[iphi];
1405       ex[i]  = 0.0;                      
1406       
1407       // Protect against zero/negative uncertainties (ROOT chi2 fit needs positive errors)
1408       ey[i] = (asym_azimuth_uncertainties[iphi] > 0.0)
1409         ? asym_azimuth_uncertainties[iphi]
1410         : 1.0;
1411     }
1412 
1413     TGraphErrors gr(N, phi, y, ex, ey);
1414     gr.SetName("gr_asym_phi");
1415     gr.SetTitle("Asymmetry vs #phi;#phi;Asymmetry");
1416 
1417     // Model: f(phi) = -[0] * sin(phi), where [0] is the amplitude A
1418     TF1 f_asym("f_asym", "-[0]*sin(x)", phiMin, phiMax);
1419     f_asym.SetParName(0, "A");
1420 
1421     // Weighted fit, quiet mode, return fit result
1422     // "Q" quiet, "S" return TFitResultPtr
1423     TFitResultPtr fitResult = gr.Fit(&f_asym, "QS");
1424 
1425     asym_amplitude     = f_asym.GetParameter(0);
1426     asym_amplitude_err = f_asym.GetParError(0);
1427   }
1428 
1429     void ShuffleBunches::compute_corrected_asyms(const int iIter)
1430   {
1431     const pt_fit_array& fit_average_mean_pt = fit_mean_pt[iIter];
1432     const pt_nodir_fit_array& fit_average_mean_pt_nodir = fit_mean_pt_nodir[iIter];
1433     const eta_fit_array& fit_average_mean_eta = fit_mean_eta[iIter];
1434     const xf_fit_array& fit_average_mean_xf = fit_mean_xf[iIter];
1435     const pt_fit_array& fit_average_unc_pt = fit_unc_pt[iIter];
1436     const pt_nodir_fit_array& fit_average_unc_pt_nodir = fit_unc_pt_nodir[iIter];
1437     const eta_fit_array& fit_average_unc_eta = fit_unc_eta[iIter];
1438     const xf_fit_array& fit_average_unc_xf = fit_unc_xf[iIter];
1439 
1440     pt_corr_array corrected_average_mean_pt;
1441     pt_nodir_corr_array corrected_average_mean_pt_nodir;
1442     eta_corr_array corrected_average_mean_eta;
1443     xf_corr_array corrected_average_mean_xf;
1444     pt_corr_array corrected_average_unc_pt;
1445     pt_nodir_corr_array corrected_average_unc_pt_nodir;
1446     eta_corr_array corrected_average_unc_eta;
1447     xf_corr_array corrected_average_unc_xf;
1448 
1449     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
1450       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++) {
1451         {
1452           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1453             compute_corrected_asym(corrected_average_mean_pt_nodir(iB, iP, iPt),
1454                                    corrected_average_unc_pt_nodir(iB, iP, iPt),
1455                                    fit_average_mean_pt_nodir(iB, iP, 0, iPt),
1456                                    fit_average_mean_pt_nodir(iB, iP, 1, iPt),
1457                                    fit_average_unc_pt_nodir(iB, iP, 0, iPt),
1458                                    fit_average_unc_pt_nodir(iB, iP, 1, iPt),
1459                                    bkg_ratio_pt[iP][iPt],
1460                                    bkg_ratio_err_pt[iP][iPt]);
1461           }
1462         }
1463         for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++) {
1464           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1465             compute_corrected_asym(corrected_average_mean_pt(iB, iP, iPt, iDir),
1466                                    corrected_average_unc_pt(iB, iP, iPt, iDir),
1467                                    fit_average_mean_pt(iB, iP, 0, iPt, iDir),
1468                                    fit_average_mean_pt(iB, iP, 1, iPt, iDir),
1469                                    fit_average_unc_pt(iB, iP, 0, iPt, iDir),
1470                                    fit_average_unc_pt(iB, iP, 1, iPt, iDir),
1471                                    bkg_ratio_pt[iP][iPt],
1472                                    bkg_ratio_err_pt[iP][iPt]);
1473           }
1474         }
1475         for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++) {
1476           compute_corrected_asym(corrected_average_mean_eta(iB, iP, iEta),
1477                                  corrected_average_unc_eta(iB, iP, iEta),
1478                                  fit_average_mean_eta(iB, iP, 0, iEta),
1479                                  fit_average_mean_eta(iB, iP, 1, iEta),
1480                                  fit_average_unc_eta(iB, iP, 0, iEta),
1481                                  fit_average_unc_eta(iB, iP, 1, iEta),
1482                                  bkg_ratio_eta[iP][iEta],
1483                                  bkg_ratio_err_eta[iP][iEta]);
1484         }
1485         for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++) {
1486           compute_corrected_asym(corrected_average_mean_xf(iB, iP, iXf),
1487                                  corrected_average_unc_xf(iB, iP, iXf),
1488                                  fit_average_mean_xf(iB, iP, 0, iXf),
1489                                  fit_average_mean_xf(iB, iP, 1, iXf),
1490                                  fit_average_unc_xf(iB, iP, 0, iXf),
1491                                  fit_average_unc_xf(iB, iP, 1, iXf),
1492                                  bkg_ratio_xf[iP][iXf],
1493                                  bkg_ratio_err_xf[iP][iXf]);
1494         }
1495       }
1496     }
1497     corrected_mean_pt.push_back(corrected_average_mean_pt);
1498     corrected_mean_pt_nodir.push_back(corrected_average_mean_pt_nodir);
1499     corrected_mean_eta.push_back(corrected_average_mean_eta);
1500     corrected_mean_xf.push_back(corrected_average_mean_xf);
1501     corrected_unc_pt.push_back(corrected_average_unc_pt);
1502     corrected_unc_pt_nodir.push_back(corrected_average_unc_pt_nodir);
1503     corrected_unc_eta.push_back(corrected_average_unc_eta);
1504     corrected_unc_xf.push_back(corrected_average_unc_xf);
1505   }
1506 
1507   void ShuffleBunches::compute_corrected_asym(double &corrected_asym,
1508                                               double &corrected_asym_err,
1509                                               const double &raw_asym,
1510                                               const double &bkg_asym,
1511                                               const double &raw_asym_err,
1512                                               const double &bkg_asym_err,
1513                                               const double &R,
1514                                               const double &R_err)
1515   {
1516     const double Delta_R = 0;//(R > 1 ? 0 : (raw_asym - bkg_asym) / (1. - R) * R_err);
1517     const double Delta_raw = (R > 1 ? 0 : raw_asym_err / (1 - R));
1518     const double Delta_bkg = (R > 1 ? 0 : -R * bkg_asym_err / (1 - R));
1519     corrected_asym = (R > 1 ? 0 : (raw_asym - R * bkg_asym) / (1 - R));
1520     corrected_asym_err = (R > 1 ? 0 : std::sqrt(std::pow(Delta_R, 2) + std::pow(Delta_raw, 2) + std::pow(Delta_bkg, 2)));
1521   }
1522 
1523   void ShuffleBunches::get_iter_raw_asym_histograms()
1524   {
1525     pt_asym_array& arr_pt_asym = mean_pt.back();
1526     eta_asym_array& arr_eta_asym = mean_eta.back();
1527     xf_asym_array& arr_xf_asym = mean_xf.back();
1528     pt_asym_array& arr_pt_asym_err = unc_pt.back();
1529     eta_asym_array& arr_eta_asym_err = unc_eta.back();
1530     xf_asym_array& arr_xf_asym_err = unc_xf.back();
1531     
1532     outfile_iter_histograms->cd();
1533     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++)
1534     {
1535       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++)
1536       {
1537         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++)
1538         {
1539           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++)
1540           {
1541             for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++)
1542             {
1543               TGraphErrors *graph_AN = new TGraphErrors();
1544               std::stringstream graph_AN_name;
1545               graph_AN_name << "graph_asym_pt_"
1546                             << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
1547                             << ASYM_CONSTANTS::regions[iR] << "_"
1548                             << "pT_" << iPt << "_"
1549                             << ASYM_CONSTANTS::directions[iDir] << "_"
1550                             << "sqrt";
1551               graph_AN->SetName(graph_AN_name.str().c_str());
1552               std::stringstream graph_title;
1553               graph_title << "; #phi; " << (iR == 0 ? "Raw" : "Bkg") << " Asymmetry";
1554               graph_AN->SetTitle(graph_title.str().c_str());
1555               for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++)
1556               {
1557                 float phi = -M_PI + M_PI / 12 + iPhi * M_PI / 6.;
1558                 graph_AN->SetPoint(iPhi, phi, arr_pt_asym(iB, iP, iR, iPt, iDir, iPhi));
1559                 graph_AN->SetPointError(iPhi, 0, arr_pt_asym_err(iB, iP, iR, iPt, iDir, iPhi));
1560               }
1561               graph_AN->Write();
1562             }
1563           }
1564           for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++)
1565           {
1566             TGraphErrors *graph_AN = new TGraphErrors();
1567             std::stringstream graph_AN_name;
1568             graph_AN_name << "graph_asym_eta_"
1569                           << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
1570                           << ASYM_CONSTANTS::regions[iR] << "_"
1571                           << "eta_" << iEta << "_sqrt";
1572             graph_AN->SetName(graph_AN_name.str().c_str());
1573             std::stringstream graph_title;
1574             graph_title << "; #phi; " << (iR == 0 ? "Raw" : "Bkg") << " Asymmetry";
1575             graph_AN->SetTitle(graph_title.str().c_str());
1576             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++)
1577             {
1578               float phi = -M_PI + M_PI / 12 + iPhi * M_PI / 6.;
1579               graph_AN->SetPoint(iPhi, phi, arr_eta_asym(iB, iP, iR, iEta, iPhi));
1580               graph_AN->SetPointError(iPhi, 0, arr_eta_asym_err(iB, iP, iR, iEta, iPhi));
1581             }
1582             graph_AN->Write();
1583           }
1584           for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++)
1585           {
1586             TGraphErrors *graph_AN = new TGraphErrors();
1587             std::stringstream graph_AN_name;
1588             graph_AN_name << "graph_asym_xf_"
1589                           << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
1590                           << ASYM_CONSTANTS::regions[iR] << "_"
1591                           << "xf_" << iXf << "_sqrt";
1592             graph_AN->SetName(graph_AN_name.str().c_str());
1593             std::stringstream graph_title;
1594             graph_title << "; #phi; " << (iR == 0 ? "Raw" : "Bkg") << " Asymmetry";
1595             graph_AN->SetTitle(graph_title.str().c_str());
1596 
1597             // Iter
1598             for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++)
1599             {
1600               float phi = -M_PI + M_PI / 12 + iPhi * M_PI / 6.;
1601               graph_AN->SetPoint(iPhi, phi, arr_xf_asym(iB, iP, iR, iXf, iPhi));
1602               graph_AN->SetPointError(iPhi, 0, arr_xf_asym_err(iB, iP, iR, iXf, iPhi));
1603             }
1604             graph_AN->Write();
1605           }
1606         }
1607       }
1608     }
1609   }
1610 
1611   void ShuffleBunches::get_iter_fit_asym_histograms()
1612   {
1613     pt_fit_array& arr_pt_asym = fit_mean_pt.back();
1614     eta_fit_array& arr_eta_asym = fit_mean_eta.back();
1615     xf_fit_array& arr_xf_asym = fit_mean_xf.back();
1616     pt_fit_array& arr_pt_asym_err = fit_unc_pt.back();
1617     eta_fit_array& arr_eta_asym_err = fit_unc_eta.back();
1618     xf_fit_array& arr_xf_asym_err = fit_unc_xf.back();
1619     
1620     outfile_iter_histograms->cd();
1621     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++)
1622     {
1623       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++)
1624       {
1625         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++)
1626         {
1627           for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++)
1628           {
1629             TGraphErrors *graph_AN = new TGraphErrors();
1630             std::stringstream graph_AN_name;
1631             graph_AN_name << "graph_asym_pt_"
1632                           << ASYM_CONSTANTS::beams[iB] << "_"
1633                           << ASYM_CONSTANTS::particle[iP] << "_"
1634                           << ASYM_CONSTANTS::regions[iR] << "_"
1635                           << ASYM_CONSTANTS::directions[iDir] << "_"
1636                           << "sqrt";
1637             graph_AN->SetName(graph_AN_name.str().c_str());
1638             std::stringstream graph_title;
1639             graph_title << "; p_{T} [GeV]; A_{N}^{" << (iR == 0 ? "Raw" : "Bkg") << "}";
1640             graph_AN->SetTitle(graph_title.str().c_str());
1641             for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++)
1642             {
1643               float pT = pTMeans[iP][iPt];
1644               graph_AN->SetPoint(iPt, pT, arr_pt_asym(iB, iP, iR, iPt, iDir));
1645               graph_AN->SetPointError(iPt, 0, arr_pt_asym_err(iB, iP, iR, iPt, iDir));
1646               graph_AN->Write();
1647             }
1648           }
1649           {
1650             TGraphErrors *graph_AN = new TGraphErrors();
1651             std::stringstream graph_AN_name;
1652             graph_AN_name << "graph_asym_eta_"
1653                           << ASYM_CONSTANTS::beams[iB] << "_"
1654                           << ASYM_CONSTANTS::particle[iP] << "_"
1655                           << ASYM_CONSTANTS::regions[iR] << "_"
1656                           << "sqrt";
1657             graph_AN->SetName(graph_AN_name.str().c_str());
1658             std::stringstream graph_title;
1659             graph_title << "; #eta; A_{N}^{" << (iR == 0 ? "Raw" : "Bkg") << "}";
1660             graph_AN->SetTitle(graph_title.str().c_str());
1661             for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++)
1662             {
1663               float eta = etaMeans[iP][iEta];
1664               graph_AN->SetPoint(iEta, eta, arr_eta_asym(iB, iP, iR, iEta));
1665               graph_AN->SetPointError(iEta, 0, arr_eta_asym_err(iB, iP, iR, iEta));
1666 
1667             }
1668             graph_AN->Write();
1669           }
1670           {
1671             TGraphErrors *graph_AN = new TGraphErrors();
1672             std::stringstream graph_AN_name;
1673             graph_AN_name << "graph_asym_xf_"
1674                           << ASYM_CONSTANTS::beams[iB] << "_"
1675                           << ASYM_CONSTANTS::particle[iP] << "_"
1676                           << ASYM_CONSTANTS::regions[iR] << "_"
1677                           << "sqrt";
1678             graph_AN->SetName(graph_AN_name.str().c_str());
1679             std::stringstream graph_title;
1680             graph_title << "; x_{F}; A_{N}^{" << (iR == 0 ? "Raw" : "Bkg") << "}";
1681             graph_AN->SetTitle(graph_title.str().c_str());
1682             for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++)
1683             {
1684               float xf = xfMeans[iP][iXf];
1685               graph_AN->SetPoint(iXf, xf, arr_xf_asym(iB, iP, iR, iXf));
1686               graph_AN->SetPointError(iXf, 0, arr_xf_asym_err(iB, iP, iR, iXf));
1687 
1688             }
1689             graph_AN->Write();
1690           }
1691         }
1692       }
1693     }
1694   }
1695 
1696   void ShuffleBunches::get_iter_corr_asym_histograms()
1697   {
1698     pt_corr_array& arr_pt_asym = corrected_mean_pt.back();
1699     eta_corr_array& arr_eta_asym = corrected_mean_eta.back();
1700     xf_corr_array& arr_xf_asym = corrected_mean_xf.back();
1701     pt_corr_array& arr_pt_asym_err = corrected_unc_pt.back();
1702     eta_corr_array& arr_eta_asym_err = corrected_unc_eta.back();
1703     xf_corr_array& arr_xf_asym_err = corrected_unc_xf.back();
1704     
1705     outfile_iter_histograms->cd();
1706     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++)
1707     {
1708       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++)
1709       {
1710         for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++)
1711         {
1712           TGraphErrors *graph_AN = new TGraphErrors();
1713           std::stringstream graph_AN_name;
1714           graph_AN_name << "graph_asym_pt_"
1715                         << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
1716                         << ASYM_CONSTANTS::directions[iDir] << "_"
1717                         << "sqrt";
1718           graph_AN->SetName(graph_AN_name.str().c_str());
1719           std::stringstream graph_title;
1720           graph_title << "; p_{T} [GeV]; A_{N}";
1721           graph_AN->SetTitle(graph_title.str().c_str());
1722           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++)
1723           {
1724             float pT = pTMeans[iP][iPt];
1725             graph_AN->SetPoint(iPt, pT, arr_pt_asym(iB, iP, iPt, iDir));
1726             graph_AN->SetPointError(iPt, 0, arr_pt_asym_err(iB, iP, iPt, iDir));
1727             graph_AN->Write();
1728           }
1729         }
1730         {
1731           TGraphErrors *graph_AN = new TGraphErrors();
1732           std::stringstream graph_AN_name;
1733           graph_AN_name << "graph_asym_eta_"
1734                         << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_sqrt";
1735           graph_AN->SetName(graph_AN_name.str().c_str());
1736           std::stringstream graph_title;
1737           graph_title << "; #eta; A_{N}";
1738           graph_AN->SetTitle(graph_title.str().c_str());
1739           for (int iEta = 0; iEta < ASYM_CONSTANTS::nEtaBins; iEta++)
1740           {
1741             float eta = etaMeans[iP][iEta];
1742             graph_AN->SetPoint(iEta, eta, arr_eta_asym(iB, iP, iEta));
1743             graph_AN->SetPointError(iEta, 0, arr_eta_asym_err(iB, iP, iEta));
1744 
1745           }
1746           graph_AN->Write();
1747         }
1748         {
1749           TGraphErrors *graph_AN = new TGraphErrors();
1750           std::stringstream graph_AN_name;
1751           graph_AN_name << "graph_asym_xf_"
1752                         << ASYM_CONSTANTS::beams[iB] << "_" << ASYM_CONSTANTS::particle[iP] << "_"
1753                         << "sqrt";
1754           graph_AN->SetName(graph_AN_name.str().c_str());
1755           std::stringstream graph_title;
1756           graph_title << "; x_{F}; A_{N}";
1757           graph_AN->SetTitle(graph_title.str().c_str());
1758           for (int iXf = 0; iXf < ASYM_CONSTANTS::nXfBins; iXf++)
1759           {
1760             float xf = xfMeans[iP][iXf];
1761             graph_AN->SetPoint(iXf, xf, arr_xf_asym(iB, iP, iXf));
1762             graph_AN->SetPointError(iXf, 0, arr_xf_asym_err(iB, iP, iXf));
1763 
1764           }
1765           graph_AN->Write();
1766         }
1767       }
1768     }
1769   }
1770   
1771   void ShuffleBunches::check_array()
1772   {
1773     std::memset(array_yield_pt, 0, sizeof(array_yield_pt));
1774     std::memset(array_yield_eta, 0, sizeof(array_yield_eta));
1775     std::memset(array_yield_xf, 0, sizeof(array_yield_xf));
1776     
1777     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
1778       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++) {
1779         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++) {
1780           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1781             for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++) {
1782               for (int iS = 0; iS < ASYM_CONSTANTS::nSpins; iS++) {
1783                 for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1784                   for(int iBunch = 0; iBunch < ASYM_CONSTANTS::nBunches; iBunch++) {
1785                     // Increment pT yield
1786                     array_yield_pt[iB][iP][iR][iPt][iDir][iS][iPhi] +=
1787                       array_yield_pt_bunches[iB][iP][iR][iPt][iDir][iS][iPhi][iBunch];
1788                   }
1789                 }
1790               }
1791             }
1792           }
1793         }
1794       }
1795     }
1796     
1797     for (int iB = 0; iB < ASYM_CONSTANTS::nBeams; iB++) {
1798       for (int iP = 0; iP < ASYM_CONSTANTS::nParticles; iP++) {
1799         for (int iR = 0; iR < ASYM_CONSTANTS::nRegions; iR++) {
1800           for (int iPt = 0; iPt < ASYM_CONSTANTS::nPtBins; iPt++) {
1801             for (int iDir = 0; iDir < ASYM_CONSTANTS::nDirections; iDir++) {
1802               for (int iS = 0; iS < ASYM_CONSTANTS::nSpins; iS++) {
1803                 for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1804                   std::cout << "array_yield_pt[" << iB << "][" << iP << "][" << iR << "][" << iPt << "][" << iDir << "][" << iS << "][" << iPhi << "] = "
1805                             << array_yield_pt[iB][iP][iR][iPt][iDir][iS][iPhi] << std::endl;
1806                 }
1807               }
1808             }
1809           }
1810         }
1811       }
1812     }
1813   }
1814 
1815   void ShuffleBunches::compute_rellum_asym(const uint32_t (&array_yield)[ASYM_CONSTANTS::nSpins][ASYM_CONSTANTS::nPhiBins],
1816                                            const double pol,
1817                                            double (&array_asym)[ASYM_CONSTANTS::nPhiBins],
1818                                            double (&array_asym_err)[ASYM_CONSTANTS::nPhiBins])
1819   {
1820     auto rellum_asym = [&](double Nup, double Ndown, double RL) -> double {
1821       double numerator = Nup - RL * Ndown;
1822       double denominator = Nup + RL * Ndown;
1823       double  asym = numerator / denominator / pol * 100;
1824       return asym;
1825     };
1826 
1827     auto rellum_asym_err = [&](double Nup, double Ndown, double RL) -> double {
1828       // hypothesis: negligible uncertainty on the relative luminosity compared to the yields
1829       double NupErr = std::sqrt(Nup);
1830       double NdownErr = std::sqrt(Ndown);
1831       double t1 = 2 * RL * Ndown * NupErr;
1832       double t2 = 2 * RL * Nup * NdownErr;
1833       double denominator = pow(Nup + RL * Ndown,2);
1834       double asym_err = sqrt(pow(t1, 2) + pow(t2, 2)) / denominator / pol * 100;
1835       return asym_err;
1836     };
1837 
1838     for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1839       double Nup = (double) array_yield[0][iPhi];
1840       double Ndown = (double) array_yield[1][iPhi];
1841       
1842       array_asym[iPhi] = rellum_asym(Nup, Ndown, relative_luminosity);
1843       array_asym_err[iPhi] = rellum_asym_err(Nup, Ndown, relative_luminosity);
1844     }
1845   }
1846 
1847   void ShuffleBunches::compute_sqrt_asym(const uint32_t (&array_yield)[ASYM_CONSTANTS::nSpins][ASYM_CONSTANTS::nPhiBins],
1848                                          const double pol,
1849                                          double (&array_asym)[ASYM_CONSTANTS::nPhiBins],
1850                                          double (&array_asym_err)[ASYM_CONSTANTS::nPhiBins])
1851   {
1852     auto sqrt_asym = [&](double NLup, double NLdown, double NRup, double NRdown) -> double {
1853       double numerator = sqrt(NLup*NRdown)-sqrt(NRup*NLdown);
1854       double denominator = sqrt(NLup*NRdown)+sqrt(NRup*NLdown);
1855       double asym = numerator / denominator / pol * 100; // Polarization given in %
1856       return asym;
1857     };
1858 
1859     auto sqrt_asym_err = [&](double NLup, double NLdown, double NRup, double NRdown) -> double {
1860       double NLupErr = std::sqrt(NLup);
1861       double NLdownErr = std::sqrt(NLdown);
1862       double NRupErr = std::sqrt(NRup);
1863       double NRdownErr = std::sqrt(NRdown);
1864       double t1 = sqrt(NLdown*NRup*NRdown/NLup)*NLupErr;
1865       double t2 = sqrt(NLup*NRup*NRdown/NLdown)*NLdownErr;
1866       double t3 = sqrt(NLup*NLdown*NRdown/NRup)*NRupErr;
1867       double t4 = sqrt(NLup*NLdown*NRup/NRdown)*NRdownErr;
1868       double denominator = pow(sqrt(NLup*NRdown)+sqrt(NRup*NLdown),2);
1869       double asym_err = sqrt(pow(t1,2)+pow(t2,2)+pow(t3,2)+pow(t4,2)) / denominator / pol * 100;
1870       return asym_err;
1871     };
1872 
1873     for (int iPhi = 0; iPhi < ASYM_CONSTANTS::nPhiBins; iPhi++) {
1874       int iPhiL = iPhi;
1875       int iPhiR = (iPhi + (int)(ASYM_CONSTANTS::nPhiBins/2)) % ASYM_CONSTANTS::nPhiBins;
1876       double NLup = (double) array_yield[0][iPhiL];
1877       double NLdown = (double) array_yield[1][iPhiL];
1878       double NRup = (double) array_yield[0][iPhiR];
1879       double NRdown = (double) array_yield[1][iPhiR];
1880       
1881       array_asym[iPhi] = sqrt_asym(NLup, NLdown, NRup, NRdown);
1882       array_asym_err[iPhi] = sqrt_asym_err(NLup, NLdown, NRup, NRdown);
1883     }
1884   }
1885 };