ROOT logo
#include "TH1D.h"
#include "TH2D.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TLegend.h"
#include "TROOT.h"
#include "TSystem.h"

#include "AliPID.h"

#include <iostream>

#include "THnSparseDefinitions.h"

#include "../../UserTasks/AliAnalysisTaskPID.h"
#include "SystematicErrorUtils.h"

enum axisDataProj { kPidPtProj = 0, kPidJetPtProj = 1, kPidZProj = 2, kPidXiProj = 3, kNDimsProj = 4 };



//___________________________________________________________________
void setupHist(TH1* h, TString histName, TString histTitle, TString xAxisTitle, TString yAxisTitle, Int_t color)
{
  if (histName != "")
    h->SetName(histName.Data());
  h->SetTitle(histTitle.Data());
  
  if (xAxisTitle != "")
    h->GetXaxis()->SetTitle(xAxisTitle.Data());
  if (yAxisTitle != "")
    h->GetYaxis()->SetTitle(yAxisTitle.Data());
  
  h->SetMarkerStyle(24);
  h->SetLineColor(color);
  h->SetMarkerColor(color);
  
  h->SetStats(kFALSE);
}


//____________________________________________________________________________________________________________________
void normaliseYieldHist2D(TH2* hData, TH2* hNumJets, const Int_t lowerCentralityBinLimit, const Int_t upperCentralityBinLimit)
{
  // Normalise to 1/numJets and bin width. NOTE: jetPt binning of hData and hNumJets assumed to be the same!
  
  if (!hData)
    return;
  
  for (Int_t binJetPt = 0; binJetPt <= hData->GetNbinsY() + 1; binJetPt++) {
    // No normalisation to numJets, if no histo is provided
    const Double_t numJets = hNumJets ? hNumJets->Integral(lowerCentralityBinLimit, upperCentralityBinLimit, binJetPt, binJetPt) : 1.;
    Bool_t noJets = numJets < 1e-13;
    
    for (Int_t binObs = 0; binObs <= hData->GetNbinsX() + 1; binObs++) {
      if (noJets) {
        if (hData->GetBinContent(binObs, binJetPt) > 0.) {
          printf("Error: No jets for jetPt ~ %f, but found content %f at y-coord %f!\n", hData->GetYaxis()->GetBinCenter(binJetPt),
                 hData->GetBinContent(binObs, binJetPt),  hData->GetXaxis()->GetBinCenter(binObs));
        }
        continue;
      }
      const Double_t dObservable = hData->GetXaxis()->GetBinWidth(binObs);
      const Double_t normFactor = 1. / (numJets * dObservable);
      
      hData->SetBinContent(binObs, binJetPt, hData->GetBinContent(binObs, binJetPt) * normFactor);
      hData->SetBinError(binObs, binJetPt, hData->GetBinError(binObs, binJetPt) * normFactor);
    }
  }
}

//____________________________________________________________________________________________________________________
void normaliseYieldHist(TH1* h, Double_t numJets)
{
  // Normalise to 1/numJets and bin width
  
  if (numJets <= 0) // Do not normalise
    numJets = 1.;
  
  for (Int_t bin = 0; bin <= h->GetNbinsX() + 1; bin++) {
    const Double_t dObservable = h->GetBinWidth(bin);
    const Double_t normFactor = 1. / (numJets * dObservable);
    h->SetBinContent(bin, h->GetBinContent(bin) * normFactor);
    h->SetBinError(bin, h->GetBinError(bin) * normFactor);
  }
}


//___________________________________________________________________
void GenerateParticleYields(THnSparse* hDataProj, AliAnalysisTaskPID* pidTask, const Double_t centrality,
                            TH2D** hIDFFtrackPt, TH2D** hIDFFz, TH2D** hIDFFxi,
                            const Bool_t setMean, const Bool_t addErrorsQuadratically, const Bool_t smearByError,
                            const Bool_t uniformSystematicError, const Bool_t takeIntoAccountSysError, Int_t nGenerations)
{
  if (!hDataProj || !pidTask || !hIDFFtrackPt || !hIDFFz || !hIDFFxi) {
    printf("Cannot generate particle fractions - missing input!\n");
    return;
  }
  
  if (takeIntoAccountSysError && smearByError) {
    printf("It doesn't make sense to correlate statistical and systematic errors!\n");
    return;
  }
  
  const Int_t nDimProj = hDataProj->GetNdimensions();
  const Long64_t nBinsTHnSparseProj = hDataProj->GetNbins();
  Double_t binContent = 0., binError2 = 0.;
  Int_t binCoord[nDimProj];
  Double_t binCentre[nDimProj];
  Double_t prob[AliPID::kSPECIES];
  
  Bool_t success = kTRUE;
  
  // NOTE: In the following, the bin error is divided according to the fraction. The idea is to divide bin content (and error)
  // into independent sub-samples according to the fractions. But then, adding up the errors of the sub-samples quadratically
  // should recover the original error (think of 100 tracks, error sqrt(100), divided into 10 samples a 10 tracks => error of
  // samples should be sqrt(10) then).
  // This means, that one needs to add error^2 * fraction and NOT error^2 * fraction^2!!
  // However, the errors are ignored anyway at the moment....
  
  if (!smearByError && !takeIntoAccountSysError) {
    nGenerations = 1;
    // Just calculate fractions/spectra w/o any smearing
    const Int_t smearSpeciesByError = -1;
    const Int_t takeIntoAccountSysErrorOfSpecies = -1;
  
    for (Long64_t bin = 0; bin < nBinsTHnSparseProj; bin++) {
      binContent = hDataProj->GetBinContent(bin, binCoord);
      binError2  = hDataProj->GetBinError2(bin);
      
      // If the bin is empty, do not compute the particle fractions -> This bin contributes nothing anyway
      if (binContent < 2. * std::numeric_limits<double>::min())
        continue;
      
      for (Int_t dim = 0; dim < nDimProj; dim++) 
        binCentre[dim] = hDataProj->GetAxis(dim)->GetBinCenter(binCoord[dim]);
      
      // Since there is no smearing, the fraction will stay the same and there is no need to save the result for one iteration in a
      // histogram (cf. case smearByError >= 0).
      success = pidTask->GetParticleFractions(binCentre[kPidPtProj], binCentre[kPidJetPtProj], centrality, prob,
                                              smearSpeciesByError, takeIntoAccountSysErrorOfSpecies, uniformSystematicError);
      
      if (success) {
        for (Int_t species = 0; species < AliPID::kSPECIES; species++) {
          // Track pT
          hIDFFtrackPt[species]->SetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj], 
                                              hIDFFtrackPt[species]->GetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj])
                                              + binContent * prob[species]);
          Double_t tempError = hIDFFtrackPt[species]->GetBinError(binCoord[kPidPtProj], binCoord[kPidJetPtProj]);
          hIDFFtrackPt[species]->SetBinError(binCoord[kPidPtProj], binCoord[kPidJetPtProj], 
                                            TMath::Sqrt(tempError * tempError + binError2 * prob[species]));
          
          // z
          hIDFFz[species]->SetBinContent(binCoord[kPidZProj], binCoord[kPidJetPtProj], 
                                        hIDFFz[species]->GetBinContent(binCoord[kPidZProj], binCoord[kPidJetPtProj])
                                        + binContent * prob[species]);
          tempError = hIDFFz[species]->GetBinError(binCoord[kPidZProj], binCoord[kPidJetPtProj]);
          hIDFFz[species]->SetBinError(binCoord[kPidZProj], binCoord[kPidJetPtProj],
                                      TMath::Sqrt(tempError * tempError + binError2 * prob[species]));
          
          // xi
          hIDFFxi[species]->SetBinContent(binCoord[kPidXiProj], binCoord[kPidJetPtProj], 
                                          hIDFFxi[species]->GetBinContent(binCoord[kPidXiProj], binCoord[kPidJetPtProj])
                                          + binContent * prob[species]);
          tempError = hIDFFxi[species]->GetBinError(binCoord[kPidXiProj], binCoord[kPidJetPtProj]);
          hIDFFxi[species]->SetBinError(binCoord[kPidXiProj], binCoord[kPidJetPtProj],
                                        TMath::Sqrt(tempError * tempError + binError2 * prob[species]));
        }
      }
      else 
        printf("Problem obtaining fractions for: trackPt %f, jetPt %f, cent %f\n", binCentre[kPidPtProj], binCentre[kPidJetPtProj],
              centrality);
    }
  }
  else {
    // Calculate fractions/spectra w/ smearing "nGenerations" times for every species and obtain the statistical or systematic error 
    // from the spread of the results.
    // Note: For a given species, only the spread of the variation of exactly that species is considered, i.e. one is not
    // looking at the change of the fraction if another species is varied (this would bias the result towards smaller errors
    // by construction since the fraction of the considered species changes weighted with its statistical/systematic error)
    
    TH2D* hIDFFtrackPtVaried[AliPID::kSPECIES][nGenerations];
    TH2D* hIDFFzVaried[AliPID::kSPECIES][nGenerations];
    TH2D* hIDFFxiVaried[AliPID::kSPECIES][nGenerations];
    
    // Create this histo and set all entries to -1 (= not calculated yet) in every loop
    TH2D* hPartFractionsSmeared = hDataProj->Projection(kPidJetPtProj, kPidPtProj);
    hPartFractionsSmeared->SetName("hPartFractionsSmeared");
    
    // Generate results with varying fractions
    for (Int_t smearSpeciesByError = 0; smearSpeciesByError < AliPID::kSPECIES; smearSpeciesByError++) {
      for (Int_t i = 0; i < nGenerations; i++) {
        hIDFFtrackPtVaried[smearSpeciesByError][i] = new TH2D(*(TH2D*)hIDFFtrackPt[smearSpeciesByError]);
        hIDFFtrackPtVaried[smearSpeciesByError][i]->SetName(Form("hIDFFtrackPtVaried_%d_%d", smearSpeciesByError, i));
        hIDFFtrackPtVaried[smearSpeciesByError][i]->Reset();
        
        hIDFFzVaried[smearSpeciesByError][i] = new TH2D(*(TH2D*)hIDFFz[smearSpeciesByError]);
        hIDFFzVaried[smearSpeciesByError][i]->SetName(Form("hIDFFzVaried_%d_%d", smearSpeciesByError, i));
        hIDFFzVaried[smearSpeciesByError][i]->Reset();
        
        hIDFFxiVaried[smearSpeciesByError][i] = new TH2D(*(TH2D*)hIDFFxi[smearSpeciesByError]);
        hIDFFxiVaried[smearSpeciesByError][i]->SetName(Form("hIDFFxiVaried_%d_%d", smearSpeciesByError, i));
        hIDFFxiVaried[smearSpeciesByError][i]->Reset();
        
        // In each iteration (moving over all bins), one want only ONE fixed particle fraction per bin in the spectra map.
        // Otherwise, one would assing different fractions to e.g. the same trackPt bin, if only z and xi is different
        // (but jetPt bin is still the same). This would then cause the fluctuations to cancel partially.
        // Thus: Calculate the smeared fraction for each bin in the spectra map only once and store it in a histo. 
        // If it is requested again (i.e. histoEntry >= 0), use the value from the histo.
        
        // Set all entries to -1 (= not calculated yet)
        for (Int_t iX = 0; iX <= hPartFractionsSmeared->GetNbinsX(); iX++) {
          for (Int_t iY = 0; iY <= hPartFractionsSmeared->GetNbinsY(); iY++) {
            hPartFractionsSmeared->SetBinContent(iX, iY, -1);
          }
        }
        
        for (Long64_t bin = 0; bin < nBinsTHnSparseProj; bin++) {
          binContent = hDataProj->GetBinContent(bin, binCoord);
          binError2  = hDataProj->GetBinError2(bin);
          
          // If the bin is empty, do not compute the particle fractions -> This bin contributes nothing anyway
          if (binContent < 2. * std::numeric_limits<double>::min())
            continue;
          
          for (Int_t iS = 0; iS < AliPID::kSPECIES; iS++)
            prob[iS] = 0.;
          
          for (Int_t dim = 0; dim < nDimProj; dim++) 
            binCentre[dim] = hDataProj->GetAxis(dim)->GetBinCenter(binCoord[dim]);
          
          if (hPartFractionsSmeared->GetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj]) >= 0) {
            success = kTRUE;
            prob[smearSpeciesByError] = hPartFractionsSmeared->GetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj]);
          }
          else {
            const Int_t smearSpeciesByStatisticalError = smearByError ? smearSpeciesByError : -1;
            const Int_t takeIntoAccountSysErrorOfSpecies = takeIntoAccountSysError ? smearSpeciesByError : -1;
            
            success = pidTask->GetParticleFractions(binCentre[kPidPtProj], binCentre[kPidJetPtProj], centrality, prob, 
                                                    smearSpeciesByStatisticalError, takeIntoAccountSysErrorOfSpecies, 
                                                    uniformSystematicError);
            
            if (success)
              hPartFractionsSmeared->SetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj], prob[smearSpeciesByError]);
          }
          
          // NOTE: Since only the bin content of the current species is stored in hPartFractionsSmeared,
          // only prob[smearSpeciesByError] can be used in the following!!!!
          
          if (success) {
            // To make things readable...
            TH2D* hIDFFtrackPtVariedCurr = hIDFFtrackPtVaried[smearSpeciesByError][i];
            TH2D* hIDFFzVariedCurr       = hIDFFzVaried[smearSpeciesByError][i];
            TH2D* hIDFFxiVariedCurr      = hIDFFxiVaried[smearSpeciesByError][i];
            
            // Track pT
            hIDFFtrackPtVariedCurr->SetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj], 
                                                  hIDFFtrackPtVariedCurr->GetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj])
                                                  + binContent * prob[smearSpeciesByError]);
            Double_t tempError = hIDFFtrackPtVariedCurr->GetBinError(binCoord[kPidPtProj], binCoord[kPidJetPtProj]);
            hIDFFtrackPtVariedCurr->SetBinError(binCoord[kPidPtProj], binCoord[kPidJetPtProj], 
                                                TMath::Sqrt(tempError * tempError + binError2 * prob[smearSpeciesByError]));
            
            // z
            hIDFFzVariedCurr->SetBinContent(binCoord[kPidZProj], binCoord[kPidJetPtProj], 
                                            hIDFFzVariedCurr->GetBinContent(binCoord[kPidZProj], binCoord[kPidJetPtProj])
                                            + binContent * prob[smearSpeciesByError]);
            tempError = hIDFFzVariedCurr->GetBinError(binCoord[kPidZProj], binCoord[kPidJetPtProj]);
            hIDFFzVariedCurr->SetBinError(binCoord[kPidZProj], binCoord[kPidJetPtProj],
                                          TMath::Sqrt(tempError * tempError + binError2 * prob[smearSpeciesByError]));
            
            // xi
            hIDFFxiVariedCurr->SetBinContent(binCoord[kPidXiProj], binCoord[kPidJetPtProj], 
                                              hIDFFxiVariedCurr->GetBinContent(binCoord[kPidXiProj], binCoord[kPidJetPtProj])
                                              + binContent * prob[smearSpeciesByError]);
            tempError = hIDFFxiVariedCurr->GetBinError(binCoord[kPidXiProj], binCoord[kPidJetPtProj]);
            hIDFFxiVariedCurr->SetBinError(binCoord[kPidXiProj], binCoord[kPidJetPtProj],
                                            TMath::Sqrt(tempError * tempError + binError2 * prob[smearSpeciesByError]));
          }
          else 
            printf("Problem obtaining fractions for: trackPt %f, jetPt %f, cent %f, smearSpeciesByError %d\n", 
                   binCentre[kPidPtProj], binCentre[kPidJetPtProj], centrality, smearSpeciesByError);
        }
      }
    }
    
    delete hPartFractionsSmeared;
    
    const Int_t nHistos = nGenerations;
    
    
    /*OLD error for each species by variation of ALL species (will bias towards smaller errors!)
    // TODO Still does not store all the values in histogram to avoid different fractions for same map bin in same iteration.
    // => If this is build in, one needs a histogram for EACH species!!!

    // Calculate fractions/spectra w/ smearing "nGenerations" times for every species and obtain the statistical error from
    // the spread of the results
    
    TH2D* hIDFFtrackPtVaried[AliPID::kSPECIES][AliPID::kSPECIES * nGenerations];
    TH2D* hIDFFzVaried[AliPID::kSPECIES][AliPID::kSPECIES * nGenerations];
    TH2D* hIDFFxiVaried[AliPID::kSPECIES][AliPID::kSPECIES * nGenerations];
    
    // Generate results with varying fractions
    for (Int_t smearSpeciesByError = 0; smearSpeciesByError < AliPID::kSPECIES; smearSpeciesByError++) {
      for (Int_t i = 0; i < nGenerations; i++) {
        for (Int_t consideredSpecies = 0; consideredSpecies < AliPID::kSPECIES; consideredSpecies++) {
          hIDFFtrackPtVaried[consideredSpecies][smearSpeciesByError * nGenerations + i] = 
            new TH2D(*(TH2D*)hIDFFtrackPt[consideredSpecies]);
          hIDFFtrackPtVaried[consideredSpecies][smearSpeciesByError * nGenerations + i]->Reset();
          hIDFFtrackPtVaried[consideredSpecies][smearSpeciesByError * nGenerations + i]->SetName(Form("hIDFFtrackPtVaried_%d_%d",
                                                                                          consideredSpecies,
                                                                                          smearSpeciesByError * nGenerations + i));
          hIDFFzVaried[consideredSpecies][smearSpeciesByError * nGenerations + i] = 
            new TH2D(*(TH2D*)hIDFFz[consideredSpecies]);
          hIDFFzVaried[consideredSpecies][smearSpeciesByError * nGenerations + i]->Reset();
          hIDFFzVaried[consideredSpecies][smearSpeciesByError * nGenerations + i]->SetName(Form("hIDFFzVaried_%d_%d",
                                                                                          consideredSpecies,
                                                                                          smearSpeciesByError * nGenerations + i));
          hIDFFxiVaried[consideredSpecies][smearSpeciesByError * nGenerations + i] = 
            new TH2D(*(TH2D*)hIDFFxi[consideredSpecies]);
          hIDFFxiVaried[consideredSpecies][smearSpeciesByError * nGenerations + i]->Reset();
          hIDFFxiVaried[consideredSpecies][smearSpeciesByError * nGenerations + i]->SetName(Form("hIDFFxiVaried_%d_%d",
                                                                                          consideredSpecies,
                                                                                          smearSpeciesByError * nGenerations + i));
        }
        
        for (Long64_t bin = 0; bin < nBinsTHnSparseProj; bin++) {
          binContent = hDataProj->GetBinContent(bin, binCoord);
          binError2  = hDataProj->GetBinError2(bin);
          
          // If the bin is empty, do not compute the particle fractions -> This bin contributes nothing anyway
          if (binContent < 2. * std::numeric_limits<double>::min())
            continue;
          
          for (Int_t dim = 0; dim < nDimProj; dim++) 
            binCentre[dim] = hDataProj->GetAxis(dim)->GetBinCenter(binCoord[dim]);
          
          success = pidTask->GetParticleFractions(binCentre[kPidPtProj], binCentre[kPidJetPtProj], centrality, prob, 
                                                  smearSpeciesByError);
          
          if (success) {
            for (Int_t species = 0; species < AliPID::kSPECIES; species++) {
              // To make things readable...
              TH2D* hIDFFtrackPtVariedCurr = hIDFFtrackPtVaried[species][smearSpeciesByError * nGenerations + i];
              TH2D* hIDFFzVariedCurr       = hIDFFzVaried[species][smearSpeciesByError * nGenerations + i];
              TH2D* hIDFFxiVariedCurr      = hIDFFxiVaried[species][smearSpeciesByError * nGenerations + i];
              
              // Track pT
              hIDFFtrackPtVariedCurr->SetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj], 
                                                    hIDFFtrackPtVariedCurr->GetBinContent(binCoord[kPidPtProj], binCoord[kPidJetPtProj])
                                                    + binContent * prob[species]);
              Double_t tempError = hIDFFtrackPtVariedCurr->GetBinError(binCoord[kPidPtProj], binCoord[kPidJetPtProj]);
              hIDFFtrackPtVariedCurr->SetBinError(binCoord[kPidPtProj], binCoord[kPidJetPtProj], 
                                                  TMath::Sqrt(tempError * tempError + binError2 * prob[species]));
              
              // z
              hIDFFzVariedCurr->SetBinContent(binCoord[kPidZProj], binCoord[kPidJetPtProj], 
                                              hIDFFzVariedCurr->GetBinContent(binCoord[kPidZProj], binCoord[kPidJetPtProj])
                                              + binContent * prob[species]);
              tempError = hIDFFzVariedCurr->GetBinError(binCoord[kPidZProj], binCoord[kPidJetPtProj]);
              hIDFFzVariedCurr->SetBinError(binCoord[kPidZProj], binCoord[kPidJetPtProj],
                                            TMath::Sqrt(tempError * tempError + binError2 * prob[species]));
              
              // xi
              hIDFFxiVariedCurr->SetBinContent(binCoord[kPidXiProj], binCoord[kPidJetPtProj], 
                                               hIDFFxiVariedCurr->GetBinContent(binCoord[kPidXiProj], binCoord[kPidJetPtProj])
                                               + binContent * prob[species]);
              tempError = hIDFFxiVariedCurr->GetBinError(binCoord[kPidXiProj], binCoord[kPidJetPtProj]);
              hIDFFxiVariedCurr->SetBinError(binCoord[kPidXiProj], binCoord[kPidJetPtProj],
                                             TMath::Sqrt(tempError * tempError + binError2 * prob[species]));
            }
          }
          else 
            printf("Problem obtaining fractions for: trackPt %f, jetPt %f, cent %f, smearSpeciesByError %d\n", 
                   binCentre[kPidPtProj], binCentre[kPidJetPtProj], centrality, smearSpeciesByError);
        }
      }
    }
    
    const Int_t nHistos = AliPID::kSPECIES * nGenerations;
    */
    
    // Compare results to obtain error
    const Bool_t ignoreSigmaErrors = kTRUE;
    
    for (Int_t species = 0; species < AliPID::kSPECIES; species++) {
      if (!extractSystematicError(nHistos, hIDFFtrackPtVaried[species], hIDFFtrackPt[species], setMean, addErrorsQuadratically,
                                  ignoreSigmaErrors))
        printf("Failed to determine systematic error for trackPt, species %d\n", species);
      
      if (!extractSystematicError(nHistos, hIDFFzVaried[species], hIDFFz[species], setMean, addErrorsQuadratically, ignoreSigmaErrors))
        printf("Failed to determine systematic error for z, species %d\n", species);
      
      if (!extractSystematicError(nHistos, hIDFFxiVaried[species], hIDFFxi[species], setMean, addErrorsQuadratically, 
                                  ignoreSigmaErrors))
        printf("Failed to determine systematic error for xi, species %d\n", species);
      
      for (Int_t i = 0; i < nHistos; i++) {
        delete hIDFFtrackPtVaried[species][i];
        hIDFFtrackPtVaried[species][i] = 0x0;
        
        delete hIDFFzVaried[species][i];
        hIDFFzVaried[species][i] = 0x0;
        
        delete hIDFFxiVaried[species][i];
        hIDFFxiVaried[species][i] = 0x0;
      }
    }
  }
}
  
  
//___________________________________________________________________
Int_t extractFFs(TString particleFractionPackagePathName, TString pathNameData, TString listName /*= ""*/,
                 Bool_t uniformSystematicError, Int_t chargeMode /*kNegCharge = -1, kAllCharged = 0, kPosCharge = 1*/,
                 Double_t lowerCentrality = -2, Double_t upperCentrality = -2, Int_t rebinPt = 1, Int_t rebinZ = 1, Int_t rebinXi = 1)
{
  TObjArray* histList = 0x0;
  
  if (listName == "") {
    listName = pathNameData;
    listName.Replace(0, listName.Last('/') + 1, "");
    listName.ReplaceAll(".root", "");
  }
  
  TFile* f = TFile::Open(pathNameData.Data());
  if (!f)  {
    std::cout << std::endl;
    std::cout << "Failed to open file \"" << pathNameData.Data() << "\"!" << std::endl;
    return -1;
  }
  
  histList = (TObjArray*)(f->Get(listName.Data()));
  if (!histList) {
    std::cout << std::endl;
    std::cout << "Failed to load list \"" << listName.Data() << "\"!" << std::endl;
    return -1;
  }
  
  // Extract the data histogram
  THnSparse* hPIDdata = dynamic_cast<THnSparse*>(histList->FindObject("hPIDdataAll"));
  if (!hPIDdata) {
    std::cout << std::endl;
    std::cout << "Failed to load data histo!" << std::endl;
    return -1;
  }
  
  // Set proper errors, if not yet calculated
  if (!hPIDdata->GetCalculateErrors()) {
    std::cout << "Re-calculating errors of " << hPIDdata->GetName() << "..." << std::endl;
    hPIDdata->Sumw2();
    Long64_t nBinsTHnSparse = hPIDdata->GetNbins();
    Double_t binContent = 0;
    
    for (Long64_t bin = 0; bin < nBinsTHnSparse; bin++) {
      binContent = hPIDdata->GetBinContent(bin);
      hPIDdata->SetBinError(bin, TMath::Sqrt(binContent));
    }
  }
  
  // If desired, restrict centrality axis
  Int_t lowerCentralityBinLimit = -1;
  Int_t upperCentralityBinLimit = -2; // Integral(lowerCentBinLimit, uppCentBinLimit) will not be restricted if these values are kept
  Bool_t restrictCentralityAxis = kFALSE;
  Double_t actualLowerCentrality = -1.;
  Double_t actualUpperCentrality = -1.;
  
  if (lowerCentrality >= -1 && upperCentrality >= -1) {
    // Add subtract a very small number to avoid problems with values right on the border between to bins
    lowerCentralityBinLimit = hPIDdata->GetAxis(kPidCentrality)->FindBin(lowerCentrality + 0.001);
    upperCentralityBinLimit = hPIDdata->GetAxis(kPidCentrality)->FindBin(upperCentrality - 0.001);
    
    // Check if the values look reasonable
    if (lowerCentralityBinLimit <= upperCentralityBinLimit && lowerCentralityBinLimit >= 1
        && upperCentralityBinLimit <= hPIDdata->GetAxis(kPidCentrality)->GetNbins()) {
      actualLowerCentrality = hPIDdata->GetAxis(kPidCentrality)->GetBinLowEdge(lowerCentralityBinLimit);
      actualUpperCentrality = hPIDdata->GetAxis(kPidCentrality)->GetBinUpEdge(upperCentralityBinLimit);

      restrictCentralityAxis = kTRUE;
    }
    else {
      std::cout << std::endl;
      std::cout << "Requested centrality range out of limits or upper and lower limit are switched!" << std::endl;
      return -1;
    }
  }
  
  std::cout << "centrality: ";
  if (restrictCentralityAxis) {
    std::cout << actualLowerCentrality << " - " << actualUpperCentrality << std::endl;
  }
  else {
    std::cout << "All" << std::endl;
  }
    
  if (restrictCentralityAxis) {
    hPIDdata->GetAxis(kPidCentrality)->SetRange(lowerCentralityBinLimit, upperCentralityBinLimit);
  }
  
  // If desired, restrict charge axis
  std::cout << "Charge selection: ";
  if (chargeMode == kAllCharged)
    std::cout << "All charged particles" << std::endl;
  else if (chargeMode == kNegCharge)
    std::cout << "Negative particles only" << std::endl;
  else if (chargeMode == kPosCharge)
    std::cout << "Positive particles only" << std::endl;
  else {
    std::cout << "Unknown -> ERROR" << std::endl;
    return -1;
  }
  
  const Bool_t restrictCharge = (chargeMode != kAllCharged);
  
  const Int_t indexChargeAxisData = GetAxisByTitle(hPIDdata, "Charge (e_{0})");
  if (indexChargeAxisData < 0 && restrictCharge) {
    std::cout << "Error: Charge axis not found for data histogram!" << std::endl;
    return -1;
  }
  Int_t lowerChargeBinLimitData = -1;
  Int_t upperChargeBinLimitData = -2;
  Double_t actualLowerChargeData = -999;
  Double_t actualUpperChargeData = -999;
  
  if (restrictCharge) {
    // Add subtract a very small number to avoid problems with values right on the border between to bins
    if (chargeMode == kNegCharge) {
      lowerChargeBinLimitData = hPIDdata->GetAxis(indexChargeAxisData)->FindBin(-1. + 0.001);
      upperChargeBinLimitData = hPIDdata->GetAxis(indexChargeAxisData)->FindBin(0. - 0.001);
    }
    else if (chargeMode == kPosCharge) {
      lowerChargeBinLimitData = hPIDdata->GetAxis(indexChargeAxisData)->FindBin(0. + 0.001);
      upperChargeBinLimitData = hPIDdata->GetAxis(indexChargeAxisData)->FindBin(1. - 0.001);
    }
    
    // Check if the values look reasonable
    if (lowerChargeBinLimitData <= upperChargeBinLimitData && lowerChargeBinLimitData >= 1
        && upperChargeBinLimitData <= hPIDdata->GetAxis(indexChargeAxisData)->GetNbins()) {
      actualLowerChargeData = hPIDdata->GetAxis(indexChargeAxisData)->GetBinLowEdge(lowerChargeBinLimitData);
      actualUpperChargeData = hPIDdata->GetAxis(indexChargeAxisData)->GetBinUpEdge(upperChargeBinLimitData);
      
      std::cout << "Charge range data: " << actualLowerChargeData << " - " << actualUpperChargeData << std::endl;
    }
    else {
      std::cout << std::endl;
      std::cout << "Requested charge range out of limits or upper and lower limit are switched!" << std::endl;
      return -1;
    }
    
    hPIDdata->GetAxis(indexChargeAxisData)->SetRange(lowerChargeBinLimitData, upperChargeBinLimitData);
  }
  
  // Just take one arbitrary selectSpecies to avoid multiple counting
  hPIDdata->GetAxis(kPidSelectSpecies)->SetRange(1, 1);
  
  // Get projection on dimensions relevant for FFs
  const Int_t nDimProj = kNDimsProj;
  Int_t dimProj[nDimProj];
  dimProj[kPidPtProj] = kPidPt;
  dimProj[kPidJetPtProj] = kPidJetPt;
  dimProj[kPidZProj] = kPidZ;
  dimProj[kPidXiProj] =kPidXi;
  
  THnSparse* hDataProj = hPIDdata->Projection(nDimProj, dimProj, "e");
  
  // If desired, rebin axes
  if (rebinPt != 1 || rebinZ != 1 || rebinXi != 1) {
    Int_t group[hDataProj->GetNdimensions()];
    
    for (Int_t i = 0; i < hDataProj->GetNdimensions(); i++) {
      if (i == kPidPtProj)
        group[i] = rebinPt;
      else if (i == kPidZProj)
        group[i] = rebinZ;
      else if (i == kPidXiProj)
        group[i] = rebinXi;
      else
        group[i] = 1;
    }
    
    THnSparse* hTemp = hDataProj->Rebin(group);
    hDataProj->SetName("temp");
    delete hDataProj;

    hDataProj = hTemp;
  }
  
  /* OLD - Now normalisation to nJets
  Double_t numEvents = -1;
  TH1* hNumEvents = dynamic_cast<TH1*>(histList->FindObject("fhEventsProcessed"));
  if (!hNumEvents) {
    std::cout << std::endl;
    std::cout << "Histo with number of processed events not found! Yields will NOT be normalised to this number!" << std::endl 
              << std::endl;
  }
  else {
    numEvents = hNumEvents->Integral(lowerCentralityBinLimit, upperCentralityBinLimit);
    
    if (numEvents <= 0) {
      numEvents = -1;
      std::cout << std::endl;
      std::cout << "Number of processed events < 1 in selected range! Yields will NOT be normalised to this number!"
                << std::endl << std::endl;
    }
  }*/
  
  
  TH2D* hNjetsGen = 0x0;
  TH2D* hNjetsRec = 0x0;
  
  TH2D* hMCgenPrimYieldPt[AliPID::kSPECIES];
  TH2D* hMCgenPrimYieldZ[AliPID::kSPECIES];
  TH2D* hMCgenPrimYieldXi[AliPID::kSPECIES];
  
  hNjetsGen = (TH2D*)histList->FindObject("fh2FFJetPtGen");
  hNjetsRec = (TH2D*)histList->FindObject("fh2FFJetPtRec");
  
  if (!hNjetsRec) {
    printf("Failed to load number of jets (rec) histo!\n");
    
    // For backward compatibility (TODO REMOVE IN FUTURE): Load info from fixed AnalysisResults file (might be wrong, if other
    // period is considered; also: No multiplicity information)
    TFile* fBackward = TFile::Open("finalCuts/pp/7TeV/LHC10e.pass2/corrected/finalisedSplines/finalMapsAndTail/Jets/noCutOn_ncl_or_liav/AnalysisResults.root");
    
    TString dirDataInFile = "";
    TDirectory* dirData = fBackward ? (TDirectory*)fBackward->Get(fBackward->GetListOfKeys()->At(0)->GetName()) : 0x0;
  
    TList* list = dirData ? (TList*)dirData->Get(dirData->GetListOfKeys()->At(0)->GetName()) : 0x0;

    TH1D* hFFJetPtRec = list ? (TH1D*)list->FindObject("fh1FFJetPtRecCutsInc") : 0x0;
    
    if (hFFJetPtRec) {
      printf("***WARNING: For backward compatibility, using file \"finalCuts/pp/7TeV/LHC10e.pass2/corrected/finalisedSplines/finalMapsAndTail/Jets/noCutOn_ncl_or_liav/AnalysisResults.root\" to get number of jets. BUT: Might be wrong period and has no mult info!***\n");
      printf("ALSO: Using Njets for inclusive jets!!!!\n");
      
      hNjetsRec = new TH2D("fh2FFJetPtRec", "", 1, -1, 1,  hDataProj->GetAxis(kPidJetPtProj)->GetNbins(),
                          hDataProj->GetAxis(kPidJetPtProj)->GetXbins()->GetArray());
      
      for (Int_t iJet = 1; iJet <= hNjetsRec->GetNbinsY(); iJet++) {
        Int_t lowerBin = hFFJetPtRec->FindBin(hNjetsRec->GetYaxis()->GetBinLowEdge(iJet) + 1e-3);
        Int_t upperBin = hFFJetPtRec->FindBin(hNjetsRec->GetYaxis()->GetBinUpEdge(iJet) - 1e-3);
        hNjetsRec->SetBinContent(1, iJet, hFFJetPtRec->Integral(lowerBin, upperBin));
      }
    }
    
    if (!hNjetsRec)
      return -1;
  }
  
  THnSparse* hMCgeneratedYieldsPrimaries = (THnSparse*)histList->FindObject("fhMCgeneratedYieldsPrimaries");
  
  for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
    hMCgenPrimYieldPt[i] = 0x0;
    hMCgenPrimYieldZ[i] = 0x0;
    hMCgenPrimYieldXi[i] = 0x0;
  }
  
  if (hMCgeneratedYieldsPrimaries && hMCgeneratedYieldsPrimaries->GetEntries() > 0) {
    // Set proper errors, if not yet calculated
    if (!hMCgeneratedYieldsPrimaries->GetCalculateErrors()) {
      std::cout << "Re-calculating errors of " << hMCgeneratedYieldsPrimaries->GetName() << "..." << std::endl;
      
      hMCgeneratedYieldsPrimaries->Sumw2();
      
      Long64_t nBinsTHnSparseGenYield = hMCgeneratedYieldsPrimaries->GetNbins();
      Double_t binContentGenYield = 0;
      for (Long64_t bin = 0; bin < nBinsTHnSparseGenYield; bin++) {
        binContentGenYield = hMCgeneratedYieldsPrimaries->GetBinContent(bin);
        hMCgeneratedYieldsPrimaries->SetBinError(bin, TMath::Sqrt(binContentGenYield));
      }
    }
    
    // If desired, rebin axes
    if (rebinPt != 1 || rebinZ != 1 || rebinXi != 1) {
      Int_t group[hMCgeneratedYieldsPrimaries->GetNdimensions()];
      
      for (Int_t k = 0; k < hMCgeneratedYieldsPrimaries->GetNdimensions(); k++) {
        if (k == kPidGenYieldPt)
          group[k] = rebinPt;
        else if (k == kPidGenYieldZ)
          group[k] = rebinZ;
        else if (k == kPidGenYieldXi)
          group[k] = rebinXi;
        else
          group[k] = 1;
      }
      
      THnSparse* hTemp = hMCgeneratedYieldsPrimaries->Rebin(group);
      hMCgeneratedYieldsPrimaries->SetName("temp");
      delete hMCgeneratedYieldsPrimaries;
      
      hMCgeneratedYieldsPrimaries = hTemp;
    }


    if (restrictCentralityAxis)
      hMCgeneratedYieldsPrimaries->GetAxis(kPidGenYieldCentrality)->SetRange(lowerCentralityBinLimit, upperCentralityBinLimit);
    
    if (restrictCharge) {
      const Int_t indexChargeAxisGenYield = GetAxisByTitle(hMCgeneratedYieldsPrimaries, "Charge (e_{0})");
      if (indexChargeAxisGenYield < 0) {
        std::cout << "Error: Charge axis not found for gen yield histogram!" << std::endl;
        return -1;
      }
  
      Int_t lowerChargeBinLimitGenYield = -1;
      Int_t upperChargeBinLimitGenYield = -2;
      Double_t actualLowerChargeGenYield = -999;
      Double_t actualUpperChargeGenYield = -999;
  
      // Add subtract a very small number to avoid problems with values right on the border between to bins
      if (chargeMode == kNegCharge) {
        lowerChargeBinLimitGenYield = hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->FindBin(-1. + 0.001);
        upperChargeBinLimitGenYield = hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->FindBin(0. - 0.001);
      }
      else if (chargeMode == kPosCharge) {
        lowerChargeBinLimitGenYield = hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->FindBin(0. + 0.001);
        upperChargeBinLimitGenYield = hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->FindBin(1. - 0.001);
      }
      
      // Check if the values look reasonable
      if (lowerChargeBinLimitGenYield <= upperChargeBinLimitGenYield && lowerChargeBinLimitGenYield >= 1
          && upperChargeBinLimitGenYield <= hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->GetNbins()) {
        actualLowerChargeGenYield = hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->GetBinLowEdge(lowerChargeBinLimitGenYield);
        actualUpperChargeGenYield = hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->GetBinUpEdge(upperChargeBinLimitGenYield);
        
        if (TMath::Abs(actualLowerChargeGenYield - actualLowerChargeData) > 1e-4 ||
            TMath::Abs(actualUpperChargeGenYield - actualUpperChargeData) > 1e-4) {
          std::cout << std::endl;
          std::cout << "Error: Charge range gen yield: " << actualLowerChargeGenYield << " - " << actualUpperChargeGenYield
                    << std::endl << "differs from that of data: " << actualLowerChargeData << " - " << actualUpperChargeData
                    << std::endl;
          return -1;
        }
      }
      else {
        std::cout << std::endl;
        std::cout << "Requested charge range (gen yield) out of limits or upper and lower limit are switched!" << std::endl;
        return -1;
      }
      
      hMCgeneratedYieldsPrimaries->GetAxis(indexChargeAxisGenYield)->SetRange(lowerChargeBinLimitGenYield, 
                                                                              upperChargeBinLimitGenYield);
    }
  
    for (Int_t MCid = 0; MCid < AliPID::kSPECIES; MCid++) {
      hMCgeneratedYieldsPrimaries->GetAxis(kPidGenYieldMCpid)->SetRange(MCid + 1, MCid + 1);
      
      hMCgenPrimYieldPt[MCid] = hMCgeneratedYieldsPrimaries->Projection(kPidGenYieldJetPt, kPidGenYieldPt, "e");
      hMCgenPrimYieldPt[MCid]->SetName(Form("hMCgenYieldsPrimPt_%s", AliPID::ParticleShortName(MCid)));
      hMCgenPrimYieldPt[MCid]->SetTitle(Form("MC truth generated primary yield, %s", AliPID::ParticleName(MCid)));
      hMCgenPrimYieldPt[MCid]->GetZaxis()->SetTitle("1/N_{Jets} dN/dP_{T} (GeV/c)^{-1}");
      hMCgenPrimYieldPt[MCid]->SetStats(kFALSE);
      
      hMCgenPrimYieldZ[MCid] = hMCgeneratedYieldsPrimaries->Projection(kPidGenYieldJetPt, kPidGenYieldZ, "e");
      hMCgenPrimYieldZ[MCid]->SetName(Form("hMCgenYieldsPrimZ_%s", AliPID::ParticleShortName(MCid)));
      hMCgenPrimYieldZ[MCid]->SetTitle(Form("MC truth generated primary yield, %s", AliPID::ParticleName(MCid)));
      hMCgenPrimYieldZ[MCid]->GetZaxis()->SetTitle("1/N_{Jets} dN/dz");
      hMCgenPrimYieldZ[MCid]->SetStats(kFALSE);
      
      hMCgenPrimYieldXi[MCid] = hMCgeneratedYieldsPrimaries->Projection(kPidGenYieldJetPt, kPidGenYieldXi, "e");
      hMCgenPrimYieldXi[MCid]->SetName(Form("hMCgenYieldsPrimXi_%s", AliPID::ParticleShortName(MCid)));
      hMCgenPrimYieldXi[MCid]->SetTitle(Form("MC truth generated primary yield, %s", AliPID::ParticleName(MCid)));
      hMCgenPrimYieldXi[MCid]->GetZaxis()->SetTitle("1/N_{Jets} dN/d#xi");
      hMCgenPrimYieldXi[MCid]->SetStats(kFALSE);
      
      hMCgeneratedYieldsPrimaries->GetAxis(kPidGenYieldMCpid)->SetRange(0, -1);
    }
  }
  
  
  AliAnalysisTaskPID *pidTask = new AliAnalysisTaskPID("spectrumExtractorTask");
  
  if (!pidTask->SetParticleFractionHistosFromFile(particleFractionPackagePathName, kFALSE)) {
    printf("Failed to load particle fraction package from file \"%s\"!\n", particleFractionPackagePathName.Data());
    return -1;
  }
  
  if (!pidTask->SetParticleFractionHistosFromFile(particleFractionPackagePathName, kTRUE)) {
    printf("Failed to load particle fraction sys error package from file \"%s\"!\n", particleFractionPackagePathName.Data());
    return -1;
  }
  
  printf("Loaded particle fraction package from file \"%s\"!\n", particleFractionPackagePathName.Data());
  
  TH2D* hIDFFtrackPt[AliPID::kSPECIES];
  TH2D* hIDFFz[AliPID::kSPECIES];
  TH2D* hIDFFxi[AliPID::kSPECIES];
  
  for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
    hIDFFtrackPt[i] = hDataProj->Projection(kPidJetPtProj, kPidPtProj);
    hIDFFtrackPt[i]->Reset();
    if (hIDFFtrackPt[i]->GetSumw2N() <= 0)
      hIDFFtrackPt[i]->Sumw2();
    setupHist(hIDFFtrackPt[i], Form("hIDFFtrackPt_%s", AliPID::ParticleShortName(i)), Form("%s", AliPID::ParticleShortName(i)),
              hDataProj->GetAxis(kPidPtProj)->GetTitle(), hDataProj->GetAxis(kPidJetPtProj)->GetTitle(), kBlack);
    
    hIDFFz[i] = hDataProj->Projection(kPidJetPtProj, kPidZProj);
    hIDFFz[i]->Reset();
    if (hIDFFz[i]->GetSumw2N() <= 0)
      hIDFFz[i]->Sumw2();
    setupHist(hIDFFz[i], Form("hIDFFz_%s", AliPID::ParticleShortName(i)), Form("%s", AliPID::ParticleShortName(i)),
              hDataProj->GetAxis(kPidZProj)->GetTitle(), hDataProj->GetAxis(kPidJetPtProj)->GetTitle(), kBlack);
    
    hIDFFxi[i] = hDataProj->Projection(kPidJetPtProj, kPidXiProj);
    hIDFFxi[i]->Reset();
    if (hIDFFxi[i]->GetSumw2N() <= 0)
      hIDFFxi[i]->Sumw2();    
    setupHist(hIDFFxi[i], Form("hIDFFxi_%s", AliPID::ParticleShortName(i)), Form("%s", AliPID::ParticleShortName(i)),
              hDataProj->GetAxis(kPidXiProj)->GetTitle(), hDataProj->GetAxis(kPidJetPtProj)->GetTitle(), kBlack);
  }
  
  const Double_t centrality = (actualLowerCentrality + actualUpperCentrality) / 2.;
  
  // First iteration: Just take the default fractions to obtain the "mean" of the yields
  Bool_t setMean = kTRUE;
  Bool_t addErrorsQuadratically = kFALSE;
  Bool_t smearByError = kFALSE;
  Bool_t takeIntoAccountSysError = kFALSE;
  // setMean and all the follwoing parameters are anyway irrelevant, if smearByError = kFALSE and takeIntoAccountSysError = kFALSE
  GenerateParticleYields(hDataProj, pidTask, centrality, hIDFFtrackPt, hIDFFz, hIDFFxi, setMean, addErrorsQuadratically,
                         smearByError, uniformSystematicError, takeIntoAccountSysError, 1);
  

  // Next iteration: Vary the PID map within statistical errors several times and calculate the resulting statistical error
  // of the spectra from this. But since the mean of the fraction is some kind of "best estimate" of the truth, leave the means
  // as they have been set during the last step.
  
  
  // NOTE: Do NOT add the statistical errors from the last step, since the yields/fractions (rel. error is the same) already
  // contain the stat. uncertainty of the yield of this species in the corresponding bin! I.e. one just takes some kind of weighted
  // mean of the fractions (mean and error) (equivalent of taking the yields with corresponding error).
  setMean = kFALSE;
  addErrorsQuadratically = kFALSE;
  smearByError = kTRUE;
  takeIntoAccountSysError = kFALSE;
  const Int_t nGenerations = 5000; //TODO set to 5000 in the end, after all testing was successful
  GenerateParticleYields(hDataProj, pidTask, centrality, hIDFFtrackPt, hIDFFz, hIDFFxi, setMean, addErrorsQuadratically,
                         smearByError, uniformSystematicError, takeIntoAccountSysError, nGenerations);
  
  
  // Next iteration: Vary the PID map within systematic errors several times and calculate the resulting systematic error
  // of the spectra from this. But since the mean of the fraction is some kind of "best estimate" of the truth, leave the means
  // as they have been set during the last step.
  setMean = kFALSE;
  addErrorsQuadratically = kFALSE;
  smearByError = kFALSE;
  takeIntoAccountSysError = kTRUE;
  // Clone histograms with final statistical errors -> Only set systematic errors, but leave mean as it is
  TH2D* hIDFFtrackPtSysError[AliPID::kSPECIES];
  TH2D* hIDFFzSysError[AliPID::kSPECIES];
  TH2D* hIDFFxiSysError[AliPID::kSPECIES];
  
  for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
    hIDFFtrackPtSysError[i] = new TH2D(*hIDFFtrackPt[i]);
    hIDFFtrackPtSysError[i]->SetName(Form("%s_sysError", hIDFFtrackPt[i]->GetName()));
    hIDFFtrackPtSysError[i]->SetFillStyle(0);
    
    hIDFFzSysError[i] = new TH2D(*hIDFFz[i]);
    hIDFFzSysError[i]->SetName(Form("%s_sysError", hIDFFz[i]->GetName()));
    hIDFFzSysError[i]->SetFillStyle(0);
    
    hIDFFxiSysError[i] = new TH2D(*hIDFFxi[i]);
    hIDFFxiSysError[i]->SetName(Form("%s_sysError", hIDFFxi[i]->GetName()));
    hIDFFxiSysError[i]->SetFillStyle(0);
  }
  
  GenerateParticleYields(hDataProj, pidTask, centrality, hIDFFtrackPtSysError, hIDFFzSysError, hIDFFxiSysError, setMean,
                         addErrorsQuadratically, smearByError, uniformSystematicError, takeIntoAccountSysError, nGenerations);
  
  delete pidTask;
  
  
  // Normalise properly
  for (Int_t species = 0; species < AliPID::kSPECIES; species++) {
    normaliseYieldHist2D(hIDFFtrackPt[species], hNjetsRec, lowerCentralityBinLimit, upperCentralityBinLimit);
    normaliseYieldHist2D(hIDFFz[species], hNjetsRec, lowerCentralityBinLimit, upperCentralityBinLimit);
    normaliseYieldHist2D(hIDFFxi[species], hNjetsRec, lowerCentralityBinLimit, upperCentralityBinLimit);
    
    normaliseYieldHist2D(hIDFFtrackPtSysError[species], hNjetsRec, lowerCentralityBinLimit, upperCentralityBinLimit);
    normaliseYieldHist2D(hIDFFzSysError[species], hNjetsRec, lowerCentralityBinLimit, upperCentralityBinLimit);
    normaliseYieldHist2D(hIDFFxiSysError[species], hNjetsRec, lowerCentralityBinLimit, upperCentralityBinLimit);
    
    normaliseYieldHist2D(hMCgenPrimYieldPt[species], hNjetsGen, lowerCentralityBinLimit, upperCentralityBinLimit);
    normaliseYieldHist2D(hMCgenPrimYieldZ[species], hNjetsGen, lowerCentralityBinLimit, upperCentralityBinLimit);
    normaliseYieldHist2D(hMCgenPrimYieldXi[species], hNjetsGen, lowerCentralityBinLimit, upperCentralityBinLimit);
  }
  
  
  
  
  // Save results to file
  TString chargeString = "";
  if (chargeMode == kPosCharge)
    chargeString = "_posCharge";
  else if (chargeMode == kNegCharge)
    chargeString = "_negCharge";
  
  TString saveFileName = pathNameData;
  saveFileName.Replace(0, pathNameData.Last('/') + 1, "");
  
  TString savePath = pathNameData;
  savePath.ReplaceAll(Form("/%s", saveFileName.Data()), "");
  
  saveFileName.Prepend("output_extractedFFs_");
  saveFileName.ReplaceAll(".root", Form("_centrality_%s%s.root",
                                        restrictCentralityAxis ? Form("%.0f_%.0f.root", actualLowerCentrality, actualUpperCentrality)
                                                               : "all",
                                        chargeString.Data()));
  
  TString saveFilePathName = Form("%s/%s", savePath.Data(), saveFileName.Data());
  TFile* saveFile = TFile::Open(saveFilePathName.Data(), "RECREATE");
  
  if (!saveFile) {
    printf("Failed to save results to file \"%s\"!\n", saveFilePathName.Data());
    return -1;
  }
  
  saveFile->cd();
  
  
  for (Int_t i = 0; i < AliPID::kSPECIES; i++) {
    if (hIDFFtrackPt[i])
      hIDFFtrackPt[i]->Write();
    
    if (hIDFFz[i])
      hIDFFz[i]->Write();
    
    if (hIDFFxi[i])
      hIDFFxi[i]->Write();
    
    
    if (hIDFFtrackPtSysError[i])
      hIDFFtrackPtSysError[i]->Write();
    
    if (hIDFFzSysError[i])
      hIDFFzSysError[i]->Write();
    
    if (hIDFFxiSysError[i])
      hIDFFxiSysError[i]->Write();
    
    
    if (hMCgenPrimYieldPt[i])
      hMCgenPrimYieldPt[i]->Write();
    
    if (hMCgenPrimYieldZ[i])
      hMCgenPrimYieldZ[i]->Write();
    
    if (hMCgenPrimYieldXi[i])
      hMCgenPrimYieldXi[i]->Write();
  }
  
  if (hNjetsGen)
    hNjetsGen->Write();
  
  if (hNjetsRec)
    hNjetsRec->Write();
  

  TNamed* settings = new TNamed(
      Form("Settings: Fraction package \"%s\", Data file \"%s\", lowerCentrality %.0f, upperCentrality %.0f, chargeMode %d, uniformSystematicError %d, rebinPt %d, rebinZ %d, rebinXi %d\n",
           particleFractionPackagePathName.Data(), pathNameData.Data(), lowerCentrality, upperCentrality, chargeMode, 
           uniformSystematicError, rebinPt, rebinZ, rebinXi), "");
  settings->Write();
  
  saveFile->Close();
  
  
  
  /*
  Int_t t1 = hIDFFtrackPt[AliPID::kPion]->GetYaxis()->FindBin(5.1);
  Int_t t2 = hIDFFtrackPt[AliPID::kPion]->GetYaxis()->FindBin(9.9);
  
  printf("t1 %d, t2 %d\n", t1, t2);
  new TCanvas();
  TH1D* hTemp = hIDFFtrackPt[AliPID::kPion]->ProjectionX("_pfy1", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("");
  
  hTemp = hIDFFtrackPtSysError[AliPID::kPion]->ProjectionX("sys_pfy1", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("E2same");
  
  if (hMCgenPrimYieldPt[AliPID::kPion]) {
    hTemp = hMCgenPrimYieldPt[AliPID::kPion]->ProjectionX("MC_pfy1", t1, t2, "e");
    hTemp->SetFillStyle(0);
    hTemp->SetMarkerStyle(23);
    hTemp->Draw("same");
  }
  
  
  new TCanvas();
  hTemp = hIDFFz[AliPID::kPion]->ProjectionX("_pfy2", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("");
  
  hTemp = hIDFFzSysError[AliPID::kPion]->ProjectionX("sys_pfy2", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("E2same");
  
  if (hMCgenPrimYieldZ[AliPID::kPion]) {
    hTemp = hMCgenPrimYieldZ[AliPID::kPion]->ProjectionX("MC_pfy2", t1, t2, "e");
    hTemp->SetFillStyle(0);
    hTemp->SetMarkerStyle(23);
    hTemp->Draw("same");
  }
  
  
  new TCanvas();
  hTemp = hIDFFxi[AliPID::kPion]->ProjectionX("_pfy3", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("");
  
  hTemp = hIDFFxiSysError[AliPID::kPion]->ProjectionX("sys_pfy3", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("E2same");
  
  if (hMCgenPrimYieldXi[AliPID::kPion]) {
    hTemp = hMCgenPrimYieldXi[AliPID::kPion]->ProjectionX("MC_pfy3", t1, t2, "e");
    hTemp->SetFillStyle(0);
    hTemp->SetMarkerStyle(23);
    hTemp->Draw("same");
  }
  
  
  
  
  new TCanvas();
  hTemp = hIDFFtrackPt[AliPID::kProton]->ProjectionX("_pfy4", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("");
  
  hTemp = hIDFFtrackPtSysError[AliPID::kProton]->ProjectionX("sys_pfy4", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("E2same");
  
  if (hMCgenPrimYieldPt[AliPID::kProton]) {
    hTemp = hMCgenPrimYieldPt[AliPID::kProton]->ProjectionX("MC_pfy4", t1, t2, "e");
    hTemp->SetFillStyle(0);
    hTemp->SetMarkerStyle(23);
    hTemp->Draw("same");
  }
  
  
  new TCanvas();
  hTemp = hIDFFz[AliPID::kProton]->ProjectionX("_pfy5", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("");
  
  hTemp = hIDFFzSysError[AliPID::kProton]->ProjectionX("sys_pfy5", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("E2same");
  
  if (hMCgenPrimYieldZ[AliPID::kProton]) {
    hTemp = hMCgenPrimYieldZ[AliPID::kProton]->ProjectionX("MC_pfy5", t1, t2, "e");
    hTemp->SetFillStyle(0);
    hTemp->SetMarkerStyle(23);
    hTemp->Draw("same");
  }
  
  
  new TCanvas();
  hTemp = hIDFFxi[AliPID::kProton]->ProjectionX("_pfy", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("");
  
  hTemp = hIDFFxiSysError[AliPID::kProton]->ProjectionX("sys_pfy", t1, t2, "e");
  hTemp->SetFillStyle(0);
  hTemp->Draw("E2same");
  
  if (hMCgenPrimYieldXi[AliPID::kProton]) {
    hTemp = hMCgenPrimYieldXi[AliPID::kProton]->ProjectionX("MC_pfy", t1, t2, "e");
    hTemp->SetFillStyle(0);
    hTemp->SetMarkerStyle(23);
    hTemp->Draw("same");
  }*/
  
  return 0;
 extractFFs.C:1
 extractFFs.C:2
 extractFFs.C:3
 extractFFs.C:4
 extractFFs.C:5
 extractFFs.C:6
 extractFFs.C:7
 extractFFs.C:8
 extractFFs.C:9
 extractFFs.C:10
 extractFFs.C:11
 extractFFs.C:12
 extractFFs.C:13
 extractFFs.C:14
 extractFFs.C:15
 extractFFs.C:16
 extractFFs.C:17
 extractFFs.C:18
 extractFFs.C:19
 extractFFs.C:20
 extractFFs.C:21
 extractFFs.C:22
 extractFFs.C:23
 extractFFs.C:24
 extractFFs.C:25
 extractFFs.C:26
 extractFFs.C:27
 extractFFs.C:28
 extractFFs.C:29
 extractFFs.C:30
 extractFFs.C:31
 extractFFs.C:32
 extractFFs.C:33
 extractFFs.C:34
 extractFFs.C:35
 extractFFs.C:36
 extractFFs.C:37
 extractFFs.C:38
 extractFFs.C:39
 extractFFs.C:40
 extractFFs.C:41
 extractFFs.C:42
 extractFFs.C:43
 extractFFs.C:44
 extractFFs.C:45
 extractFFs.C:46
 extractFFs.C:47
 extractFFs.C:48
 extractFFs.C:49
 extractFFs.C:50
 extractFFs.C:51
 extractFFs.C:52
 extractFFs.C:53
 extractFFs.C:54
 extractFFs.C:55
 extractFFs.C:56
 extractFFs.C:57
 extractFFs.C:58
 extractFFs.C:59
 extractFFs.C:60
 extractFFs.C:61
 extractFFs.C:62
 extractFFs.C:63
 extractFFs.C:64
 extractFFs.C:65
 extractFFs.C:66
 extractFFs.C:67
 extractFFs.C:68
 extractFFs.C:69
 extractFFs.C:70
 extractFFs.C:71
 extractFFs.C:72
 extractFFs.C:73
 extractFFs.C:74
 extractFFs.C:75
 extractFFs.C:76
 extractFFs.C:77
 extractFFs.C:78
 extractFFs.C:79
 extractFFs.C:80
 extractFFs.C:81
 extractFFs.C:82
 extractFFs.C:83
 extractFFs.C:84
 extractFFs.C:85
 extractFFs.C:86
 extractFFs.C:87
 extractFFs.C:88
 extractFFs.C:89
 extractFFs.C:90
 extractFFs.C:91
 extractFFs.C:92
 extractFFs.C:93
 extractFFs.C:94
 extractFFs.C:95
 extractFFs.C:96
 extractFFs.C:97
 extractFFs.C:98
 extractFFs.C:99
 extractFFs.C:100
 extractFFs.C:101
 extractFFs.C:102
 extractFFs.C:103
 extractFFs.C:104
 extractFFs.C:105
 extractFFs.C:106
 extractFFs.C:107
 extractFFs.C:108
 extractFFs.C:109
 extractFFs.C:110
 extractFFs.C:111
 extractFFs.C:112
 extractFFs.C:113
 extractFFs.C:114
 extractFFs.C:115
 extractFFs.C:116
 extractFFs.C:117
 extractFFs.C:118
 extractFFs.C:119
 extractFFs.C:120
 extractFFs.C:121
 extractFFs.C:122
 extractFFs.C:123
 extractFFs.C:124
 extractFFs.C:125
 extractFFs.C:126
 extractFFs.C:127
 extractFFs.C:128
 extractFFs.C:129
 extractFFs.C:130
 extractFFs.C:131
 extractFFs.C:132
 extractFFs.C:133
 extractFFs.C:134
 extractFFs.C:135
 extractFFs.C:136
 extractFFs.C:137
 extractFFs.C:138
 extractFFs.C:139
 extractFFs.C:140
 extractFFs.C:141
 extractFFs.C:142
 extractFFs.C:143
 extractFFs.C:144
 extractFFs.C:145
 extractFFs.C:146
 extractFFs.C:147
 extractFFs.C:148
 extractFFs.C:149
 extractFFs.C:150
 extractFFs.C:151
 extractFFs.C:152
 extractFFs.C:153
 extractFFs.C:154
 extractFFs.C:155
 extractFFs.C:156
 extractFFs.C:157
 extractFFs.C:158
 extractFFs.C:159
 extractFFs.C:160
 extractFFs.C:161
 extractFFs.C:162
 extractFFs.C:163
 extractFFs.C:164
 extractFFs.C:165
 extractFFs.C:166
 extractFFs.C:167
 extractFFs.C:168
 extractFFs.C:169
 extractFFs.C:170
 extractFFs.C:171
 extractFFs.C:172
 extractFFs.C:173
 extractFFs.C:174
 extractFFs.C:175
 extractFFs.C:176
 extractFFs.C:177
 extractFFs.C:178
 extractFFs.C:179
 extractFFs.C:180
 extractFFs.C:181
 extractFFs.C:182
 extractFFs.C:183
 extractFFs.C:184
 extractFFs.C:185
 extractFFs.C:186
 extractFFs.C:187
 extractFFs.C:188
 extractFFs.C:189
 extractFFs.C:190
 extractFFs.C:191
 extractFFs.C:192
 extractFFs.C:193
 extractFFs.C:194
 extractFFs.C:195
 extractFFs.C:196
 extractFFs.C:197
 extractFFs.C:198
 extractFFs.C:199
 extractFFs.C:200
 extractFFs.C:201
 extractFFs.C:202
 extractFFs.C:203
 extractFFs.C:204
 extractFFs.C:205
 extractFFs.C:206
 extractFFs.C:207
 extractFFs.C:208
 extractFFs.C:209
 extractFFs.C:210
 extractFFs.C:211
 extractFFs.C:212
 extractFFs.C:213
 extractFFs.C:214
 extractFFs.C:215
 extractFFs.C:216
 extractFFs.C:217
 extractFFs.C:218
 extractFFs.C:219
 extractFFs.C:220
 extractFFs.C:221
 extractFFs.C:222
 extractFFs.C:223
 extractFFs.C:224
 extractFFs.C:225
 extractFFs.C:226
 extractFFs.C:227
 extractFFs.C:228
 extractFFs.C:229
 extractFFs.C:230
 extractFFs.C:231
 extractFFs.C:232
 extractFFs.C:233
 extractFFs.C:234
 extractFFs.C:235
 extractFFs.C:236
 extractFFs.C:237
 extractFFs.C:238
 extractFFs.C:239
 extractFFs.C:240
 extractFFs.C:241
 extractFFs.C:242
 extractFFs.C:243
 extractFFs.C:244
 extractFFs.C:245
 extractFFs.C:246
 extractFFs.C:247
 extractFFs.C:248
 extractFFs.C:249
 extractFFs.C:250
 extractFFs.C:251
 extractFFs.C:252
 extractFFs.C:253
 extractFFs.C:254
 extractFFs.C:255
 extractFFs.C:256
 extractFFs.C:257
 extractFFs.C:258
 extractFFs.C:259
 extractFFs.C:260
 extractFFs.C:261
 extractFFs.C:262
 extractFFs.C:263
 extractFFs.C:264
 extractFFs.C:265
 extractFFs.C:266
 extractFFs.C:267
 extractFFs.C:268
 extractFFs.C:269
 extractFFs.C:270
 extractFFs.C:271
 extractFFs.C:272
 extractFFs.C:273
 extractFFs.C:274
 extractFFs.C:275
 extractFFs.C:276
 extractFFs.C:277
 extractFFs.C:278
 extractFFs.C:279
 extractFFs.C:280
 extractFFs.C:281
 extractFFs.C:282
 extractFFs.C:283
 extractFFs.C:284
 extractFFs.C:285
 extractFFs.C:286
 extractFFs.C:287
 extractFFs.C:288
 extractFFs.C:289
 extractFFs.C:290
 extractFFs.C:291
 extractFFs.C:292
 extractFFs.C:293
 extractFFs.C:294
 extractFFs.C:295
 extractFFs.C:296
 extractFFs.C:297
 extractFFs.C:298
 extractFFs.C:299
 extractFFs.C:300
 extractFFs.C:301
 extractFFs.C:302
 extractFFs.C:303
 extractFFs.C:304
 extractFFs.C:305
 extractFFs.C:306
 extractFFs.C:307
 extractFFs.C:308
 extractFFs.C:309
 extractFFs.C:310
 extractFFs.C:311
 extractFFs.C:312
 extractFFs.C:313
 extractFFs.C:314
 extractFFs.C:315
 extractFFs.C:316
 extractFFs.C:317
 extractFFs.C:318
 extractFFs.C:319
 extractFFs.C:320
 extractFFs.C:321
 extractFFs.C:322
 extractFFs.C:323
 extractFFs.C:324
 extractFFs.C:325
 extractFFs.C:326
 extractFFs.C:327
 extractFFs.C:328
 extractFFs.C:329
 extractFFs.C:330
 extractFFs.C:331
 extractFFs.C:332
 extractFFs.C:333
 extractFFs.C:334
 extractFFs.C:335
 extractFFs.C:336
 extractFFs.C:337
 extractFFs.C:338
 extractFFs.C:339
 extractFFs.C:340
 extractFFs.C:341
 extractFFs.C:342
 extractFFs.C:343
 extractFFs.C:344
 extractFFs.C:345
 extractFFs.C:346
 extractFFs.C:347
 extractFFs.C:348
 extractFFs.C:349
 extractFFs.C:350
 extractFFs.C:351
 extractFFs.C:352
 extractFFs.C:353
 extractFFs.C:354
 extractFFs.C:355
 extractFFs.C:356
 extractFFs.C:357
 extractFFs.C:358
 extractFFs.C:359
 extractFFs.C:360
 extractFFs.C:361
 extractFFs.C:362
 extractFFs.C:363
 extractFFs.C:364
 extractFFs.C:365
 extractFFs.C:366
 extractFFs.C:367
 extractFFs.C:368
 extractFFs.C:369
 extractFFs.C:370
 extractFFs.C:371
 extractFFs.C:372
 extractFFs.C:373
 extractFFs.C:374
 extractFFs.C:375
 extractFFs.C:376
 extractFFs.C:377
 extractFFs.C:378
 extractFFs.C:379
 extractFFs.C:380
 extractFFs.C:381
 extractFFs.C:382
 extractFFs.C:383
 extractFFs.C:384
 extractFFs.C:385
 extractFFs.C:386
 extractFFs.C:387
 extractFFs.C:388
 extractFFs.C:389
 extractFFs.C:390
 extractFFs.C:391
 extractFFs.C:392
 extractFFs.C:393
 extractFFs.C:394
 extractFFs.C:395
 extractFFs.C:396
 extractFFs.C:397
 extractFFs.C:398
 extractFFs.C:399
 extractFFs.C:400
 extractFFs.C:401
 extractFFs.C:402
 extractFFs.C:403
 extractFFs.C:404
 extractFFs.C:405
 extractFFs.C:406
 extractFFs.C:407
 extractFFs.C:408
 extractFFs.C:409
 extractFFs.C:410
 extractFFs.C:411
 extractFFs.C:412
 extractFFs.C:413
 extractFFs.C:414
 extractFFs.C:415
 extractFFs.C:416
 extractFFs.C:417
 extractFFs.C:418
 extractFFs.C:419
 extractFFs.C:420
 extractFFs.C:421
 extractFFs.C:422
 extractFFs.C:423
 extractFFs.C:424
 extractFFs.C:425
 extractFFs.C:426
 extractFFs.C:427
 extractFFs.C:428
 extractFFs.C:429
 extractFFs.C:430
 extractFFs.C:431
 extractFFs.C:432
 extractFFs.C:433
 extractFFs.C:434
 extractFFs.C:435
 extractFFs.C:436
 extractFFs.C:437
 extractFFs.C:438
 extractFFs.C:439
 extractFFs.C:440
 extractFFs.C:441
 extractFFs.C:442
 extractFFs.C:443
 extractFFs.C:444
 extractFFs.C:445
 extractFFs.C:446
 extractFFs.C:447
 extractFFs.C:448
 extractFFs.C:449
 extractFFs.C:450
 extractFFs.C:451
 extractFFs.C:452
 extractFFs.C:453
 extractFFs.C:454
 extractFFs.C:455
 extractFFs.C:456
 extractFFs.C:457
 extractFFs.C:458
 extractFFs.C:459
 extractFFs.C:460
 extractFFs.C:461
 extractFFs.C:462
 extractFFs.C:463
 extractFFs.C:464
 extractFFs.C:465
 extractFFs.C:466
 extractFFs.C:467
 extractFFs.C:468
 extractFFs.C:469
 extractFFs.C:470
 extractFFs.C:471
 extractFFs.C:472
 extractFFs.C:473
 extractFFs.C:474
 extractFFs.C:475
 extractFFs.C:476
 extractFFs.C:477
 extractFFs.C:478
 extractFFs.C:479
 extractFFs.C:480
 extractFFs.C:481
 extractFFs.C:482
 extractFFs.C:483
 extractFFs.C:484
 extractFFs.C:485
 extractFFs.C:486
 extractFFs.C:487
 extractFFs.C:488
 extractFFs.C:489
 extractFFs.C:490
 extractFFs.C:491
 extractFFs.C:492
 extractFFs.C:493
 extractFFs.C:494
 extractFFs.C:495
 extractFFs.C:496
 extractFFs.C:497
 extractFFs.C:498
 extractFFs.C:499
 extractFFs.C:500
 extractFFs.C:501
 extractFFs.C:502
 extractFFs.C:503
 extractFFs.C:504
 extractFFs.C:505
 extractFFs.C:506
 extractFFs.C:507
 extractFFs.C:508
 extractFFs.C:509
 extractFFs.C:510
 extractFFs.C:511
 extractFFs.C:512
 extractFFs.C:513
 extractFFs.C:514
 extractFFs.C:515
 extractFFs.C:516
 extractFFs.C:517
 extractFFs.C:518
 extractFFs.C:519
 extractFFs.C:520
 extractFFs.C:521
 extractFFs.C:522
 extractFFs.C:523
 extractFFs.C:524
 extractFFs.C:525
 extractFFs.C:526
 extractFFs.C:527
 extractFFs.C:528
 extractFFs.C:529
 extractFFs.C:530
 extractFFs.C:531
 extractFFs.C:532
 extractFFs.C:533
 extractFFs.C:534
 extractFFs.C:535
 extractFFs.C:536
 extractFFs.C:537
 extractFFs.C:538
 extractFFs.C:539
 extractFFs.C:540
 extractFFs.C:541
 extractFFs.C:542
 extractFFs.C:543
 extractFFs.C:544
 extractFFs.C:545
 extractFFs.C:546
 extractFFs.C:547
 extractFFs.C:548
 extractFFs.C:549
 extractFFs.C:550
 extractFFs.C:551
 extractFFs.C:552
 extractFFs.C:553
 extractFFs.C:554
 extractFFs.C:555
 extractFFs.C:556
 extractFFs.C:557
 extractFFs.C:558
 extractFFs.C:559
 extractFFs.C:560
 extractFFs.C:561
 extractFFs.C:562
 extractFFs.C:563
 extractFFs.C:564
 extractFFs.C:565
 extractFFs.C:566
 extractFFs.C:567
 extractFFs.C:568
 extractFFs.C:569
 extractFFs.C:570
 extractFFs.C:571
 extractFFs.C:572
 extractFFs.C:573
 extractFFs.C:574
 extractFFs.C:575
 extractFFs.C:576
 extractFFs.C:577
 extractFFs.C:578
 extractFFs.C:579
 extractFFs.C:580
 extractFFs.C:581
 extractFFs.C:582
 extractFFs.C:583
 extractFFs.C:584
 extractFFs.C:585
 extractFFs.C:586
 extractFFs.C:587
 extractFFs.C:588
 extractFFs.C:589
 extractFFs.C:590
 extractFFs.C:591
 extractFFs.C:592
 extractFFs.C:593
 extractFFs.C:594
 extractFFs.C:595
 extractFFs.C:596
 extractFFs.C:597
 extractFFs.C:598
 extractFFs.C:599
 extractFFs.C:600
 extractFFs.C:601
 extractFFs.C:602
 extractFFs.C:603
 extractFFs.C:604
 extractFFs.C:605
 extractFFs.C:606
 extractFFs.C:607
 extractFFs.C:608
 extractFFs.C:609
 extractFFs.C:610
 extractFFs.C:611
 extractFFs.C:612
 extractFFs.C:613
 extractFFs.C:614
 extractFFs.C:615
 extractFFs.C:616
 extractFFs.C:617
 extractFFs.C:618
 extractFFs.C:619
 extractFFs.C:620
 extractFFs.C:621
 extractFFs.C:622
 extractFFs.C:623
 extractFFs.C:624
 extractFFs.C:625
 extractFFs.C:626
 extractFFs.C:627
 extractFFs.C:628
 extractFFs.C:629
 extractFFs.C:630
 extractFFs.C:631
 extractFFs.C:632
 extractFFs.C:633
 extractFFs.C:634
 extractFFs.C:635
 extractFFs.C:636
 extractFFs.C:637
 extractFFs.C:638
 extractFFs.C:639
 extractFFs.C:640
 extractFFs.C:641
 extractFFs.C:642
 extractFFs.C:643
 extractFFs.C:644
 extractFFs.C:645
 extractFFs.C:646
 extractFFs.C:647
 extractFFs.C:648
 extractFFs.C:649
 extractFFs.C:650
 extractFFs.C:651
 extractFFs.C:652
 extractFFs.C:653
 extractFFs.C:654
 extractFFs.C:655
 extractFFs.C:656
 extractFFs.C:657
 extractFFs.C:658
 extractFFs.C:659
 extractFFs.C:660
 extractFFs.C:661
 extractFFs.C:662
 extractFFs.C:663
 extractFFs.C:664
 extractFFs.C:665
 extractFFs.C:666
 extractFFs.C:667
 extractFFs.C:668
 extractFFs.C:669
 extractFFs.C:670
 extractFFs.C:671
 extractFFs.C:672
 extractFFs.C:673
 extractFFs.C:674
 extractFFs.C:675
 extractFFs.C:676
 extractFFs.C:677
 extractFFs.C:678
 extractFFs.C:679
 extractFFs.C:680
 extractFFs.C:681
 extractFFs.C:682
 extractFFs.C:683
 extractFFs.C:684
 extractFFs.C:685
 extractFFs.C:686
 extractFFs.C:687
 extractFFs.C:688
 extractFFs.C:689
 extractFFs.C:690
 extractFFs.C:691
 extractFFs.C:692
 extractFFs.C:693
 extractFFs.C:694
 extractFFs.C:695
 extractFFs.C:696
 extractFFs.C:697
 extractFFs.C:698
 extractFFs.C:699
 extractFFs.C:700
 extractFFs.C:701
 extractFFs.C:702
 extractFFs.C:703
 extractFFs.C:704
 extractFFs.C:705
 extractFFs.C:706
 extractFFs.C:707
 extractFFs.C:708
 extractFFs.C:709
 extractFFs.C:710
 extractFFs.C:711
 extractFFs.C:712
 extractFFs.C:713
 extractFFs.C:714
 extractFFs.C:715
 extractFFs.C:716
 extractFFs.C:717
 extractFFs.C:718
 extractFFs.C:719
 extractFFs.C:720
 extractFFs.C:721
 extractFFs.C:722
 extractFFs.C:723
 extractFFs.C:724
 extractFFs.C:725
 extractFFs.C:726
 extractFFs.C:727
 extractFFs.C:728
 extractFFs.C:729
 extractFFs.C:730
 extractFFs.C:731
 extractFFs.C:732
 extractFFs.C:733
 extractFFs.C:734
 extractFFs.C:735
 extractFFs.C:736
 extractFFs.C:737
 extractFFs.C:738
 extractFFs.C:739
 extractFFs.C:740
 extractFFs.C:741
 extractFFs.C:742
 extractFFs.C:743
 extractFFs.C:744
 extractFFs.C:745
 extractFFs.C:746
 extractFFs.C:747
 extractFFs.C:748
 extractFFs.C:749
 extractFFs.C:750
 extractFFs.C:751
 extractFFs.C:752
 extractFFs.C:753
 extractFFs.C:754
 extractFFs.C:755
 extractFFs.C:756
 extractFFs.C:757
 extractFFs.C:758
 extractFFs.C:759
 extractFFs.C:760
 extractFFs.C:761
 extractFFs.C:762
 extractFFs.C:763
 extractFFs.C:764
 extractFFs.C:765
 extractFFs.C:766
 extractFFs.C:767
 extractFFs.C:768
 extractFFs.C:769
 extractFFs.C:770
 extractFFs.C:771
 extractFFs.C:772
 extractFFs.C:773
 extractFFs.C:774
 extractFFs.C:775
 extractFFs.C:776
 extractFFs.C:777
 extractFFs.C:778
 extractFFs.C:779
 extractFFs.C:780
 extractFFs.C:781
 extractFFs.C:782
 extractFFs.C:783
 extractFFs.C:784
 extractFFs.C:785
 extractFFs.C:786
 extractFFs.C:787
 extractFFs.C:788
 extractFFs.C:789
 extractFFs.C:790
 extractFFs.C:791
 extractFFs.C:792
 extractFFs.C:793
 extractFFs.C:794
 extractFFs.C:795
 extractFFs.C:796
 extractFFs.C:797
 extractFFs.C:798
 extractFFs.C:799
 extractFFs.C:800
 extractFFs.C:801
 extractFFs.C:802
 extractFFs.C:803
 extractFFs.C:804
 extractFFs.C:805
 extractFFs.C:806
 extractFFs.C:807
 extractFFs.C:808
 extractFFs.C:809
 extractFFs.C:810
 extractFFs.C:811
 extractFFs.C:812
 extractFFs.C:813
 extractFFs.C:814
 extractFFs.C:815
 extractFFs.C:816
 extractFFs.C:817
 extractFFs.C:818
 extractFFs.C:819
 extractFFs.C:820
 extractFFs.C:821
 extractFFs.C:822
 extractFFs.C:823
 extractFFs.C:824
 extractFFs.C:825
 extractFFs.C:826
 extractFFs.C:827
 extractFFs.C:828
 extractFFs.C:829
 extractFFs.C:830
 extractFFs.C:831
 extractFFs.C:832
 extractFFs.C:833
 extractFFs.C:834
 extractFFs.C:835
 extractFFs.C:836
 extractFFs.C:837
 extractFFs.C:838
 extractFFs.C:839
 extractFFs.C:840
 extractFFs.C:841
 extractFFs.C:842
 extractFFs.C:843
 extractFFs.C:844
 extractFFs.C:845
 extractFFs.C:846
 extractFFs.C:847
 extractFFs.C:848
 extractFFs.C:849
 extractFFs.C:850
 extractFFs.C:851
 extractFFs.C:852
 extractFFs.C:853
 extractFFs.C:854
 extractFFs.C:855
 extractFFs.C:856
 extractFFs.C:857
 extractFFs.C:858
 extractFFs.C:859
 extractFFs.C:860
 extractFFs.C:861
 extractFFs.C:862
 extractFFs.C:863
 extractFFs.C:864
 extractFFs.C:865
 extractFFs.C:866
 extractFFs.C:867
 extractFFs.C:868
 extractFFs.C:869
 extractFFs.C:870
 extractFFs.C:871
 extractFFs.C:872
 extractFFs.C:873
 extractFFs.C:874
 extractFFs.C:875
 extractFFs.C:876
 extractFFs.C:877
 extractFFs.C:878
 extractFFs.C:879
 extractFFs.C:880
 extractFFs.C:881
 extractFFs.C:882
 extractFFs.C:883
 extractFFs.C:884
 extractFFs.C:885
 extractFFs.C:886
 extractFFs.C:887
 extractFFs.C:888
 extractFFs.C:889
 extractFFs.C:890
 extractFFs.C:891
 extractFFs.C:892
 extractFFs.C:893
 extractFFs.C:894
 extractFFs.C:895
 extractFFs.C:896
 extractFFs.C:897
 extractFFs.C:898
 extractFFs.C:899
 extractFFs.C:900
 extractFFs.C:901
 extractFFs.C:902
 extractFFs.C:903
 extractFFs.C:904
 extractFFs.C:905
 extractFFs.C:906
 extractFFs.C:907
 extractFFs.C:908
 extractFFs.C:909
 extractFFs.C:910
 extractFFs.C:911
 extractFFs.C:912
 extractFFs.C:913
 extractFFs.C:914
 extractFFs.C:915
 extractFFs.C:916
 extractFFs.C:917
 extractFFs.C:918
 extractFFs.C:919
 extractFFs.C:920
 extractFFs.C:921
 extractFFs.C:922
 extractFFs.C:923
 extractFFs.C:924
 extractFFs.C:925
 extractFFs.C:926
 extractFFs.C:927
 extractFFs.C:928
 extractFFs.C:929
 extractFFs.C:930
 extractFFs.C:931
 extractFFs.C:932
 extractFFs.C:933
 extractFFs.C:934
 extractFFs.C:935
 extractFFs.C:936
 extractFFs.C:937
 extractFFs.C:938
 extractFFs.C:939
 extractFFs.C:940
 extractFFs.C:941
 extractFFs.C:942
 extractFFs.C:943
 extractFFs.C:944
 extractFFs.C:945
 extractFFs.C:946
 extractFFs.C:947
 extractFFs.C:948
 extractFFs.C:949
 extractFFs.C:950
 extractFFs.C:951
 extractFFs.C:952
 extractFFs.C:953
 extractFFs.C:954
 extractFFs.C:955
 extractFFs.C:956
 extractFFs.C:957
 extractFFs.C:958
 extractFFs.C:959
 extractFFs.C:960
 extractFFs.C:961
 extractFFs.C:962
 extractFFs.C:963
 extractFFs.C:964
 extractFFs.C:965
 extractFFs.C:966
 extractFFs.C:967
 extractFFs.C:968
 extractFFs.C:969
 extractFFs.C:970
 extractFFs.C:971
 extractFFs.C:972
 extractFFs.C:973
 extractFFs.C:974
 extractFFs.C:975
 extractFFs.C:976
 extractFFs.C:977
 extractFFs.C:978
 extractFFs.C:979
 extractFFs.C:980
 extractFFs.C:981
 extractFFs.C:982
 extractFFs.C:983
 extractFFs.C:984
 extractFFs.C:985
 extractFFs.C:986
 extractFFs.C:987
 extractFFs.C:988
 extractFFs.C:989
 extractFFs.C:990
 extractFFs.C:991
 extractFFs.C:992
 extractFFs.C:993
 extractFFs.C:994
 extractFFs.C:995
 extractFFs.C:996
 extractFFs.C:997
 extractFFs.C:998
 extractFFs.C:999
 extractFFs.C:1000
 extractFFs.C:1001
 extractFFs.C:1002
 extractFFs.C:1003
 extractFFs.C:1004
 extractFFs.C:1005
 extractFFs.C:1006
 extractFFs.C:1007
 extractFFs.C:1008
 extractFFs.C:1009
 extractFFs.C:1010
 extractFFs.C:1011
 extractFFs.C:1012
 extractFFs.C:1013
 extractFFs.C:1014
 extractFFs.C:1015
 extractFFs.C:1016
 extractFFs.C:1017
 extractFFs.C:1018
 extractFFs.C:1019
 extractFFs.C:1020
 extractFFs.C:1021
 extractFFs.C:1022
 extractFFs.C:1023
 extractFFs.C:1024
 extractFFs.C:1025
 extractFFs.C:1026
 extractFFs.C:1027
 extractFFs.C:1028
 extractFFs.C:1029
 extractFFs.C:1030
 extractFFs.C:1031
 extractFFs.C:1032
 extractFFs.C:1033
 extractFFs.C:1034
 extractFFs.C:1035
 extractFFs.C:1036
 extractFFs.C:1037
 extractFFs.C:1038
 extractFFs.C:1039
 extractFFs.C:1040
 extractFFs.C:1041
 extractFFs.C:1042
 extractFFs.C:1043
 extractFFs.C:1044
 extractFFs.C:1045
 extractFFs.C:1046
 extractFFs.C:1047
 extractFFs.C:1048
 extractFFs.C:1049
 extractFFs.C:1050
 extractFFs.C:1051
 extractFFs.C:1052
 extractFFs.C:1053
 extractFFs.C:1054
 extractFFs.C:1055
 extractFFs.C:1056
 extractFFs.C:1057
 extractFFs.C:1058
 extractFFs.C:1059
 extractFFs.C:1060
 extractFFs.C:1061
 extractFFs.C:1062
 extractFFs.C:1063
 extractFFs.C:1064
 extractFFs.C:1065
 extractFFs.C:1066
 extractFFs.C:1067
 extractFFs.C:1068
 extractFFs.C:1069
 extractFFs.C:1070
 extractFFs.C:1071
 extractFFs.C:1072
 extractFFs.C:1073
 extractFFs.C:1074
 extractFFs.C:1075
 extractFFs.C:1076
 extractFFs.C:1077
 extractFFs.C:1078
 extractFFs.C:1079
 extractFFs.C:1080