Big update to forward flow tasks. Can run on VZERO and use TPC tracks for reference...
authorAlexander Hansen <alexander.hansen@cern.ch>
Wed, 18 Dec 2013 14:42:19 +0000 (15:42 +0100)
committerAlexander Hansen <alexander.hansen@cern.ch>
Wed, 18 Dec 2013 14:42:19 +0000 (15:42 +0100)
PWGLF/FORWARD/analysis2/AddTaskForwardFlowQC.C
PWGLF/FORWARD/analysis2/AliForwardFlowTaskQC.cxx
PWGLF/FORWARD/analysis2/AliForwardFlowTaskQC.h
PWGLF/FORWARD/analysis2/AliForwardMCFlowTaskQC.cxx
PWGLF/FORWARD/analysis2/AliForwardMCFlowTaskQC.h
PWGLF/FORWARD/analysis2/MakeFlow.C
PWGLF/FORWARD/analysis2/trains/MakeFlowTrain.C
PWGLF/PWGLFforward2LinkDef.h

index c316956..a8255b3 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * @file   AddTaskForwardFlow.C
+ * @file   AddTaskForwardFlowQC.C
  * @author Alexander Hansen alexander.hansen@cern.ch 
  * 
  * @brief  
 /** 
  * Add Flow task to train 
  * 
- * @param type          Which moments to do 
+ * @param maxMom        Max moment to do 
  * @param useEtaGap     Whehter to use @f$\eta@f$ gaps
- * @param etaGap        Size of @f$\eta@f$ gap
- * @param useCent       Whether to use centrality 
  * @param mc            Monte-carlo input
- * @param satVtx        Use satellite interactions 
  * @param outlierCutFMD Cut to remove events with outliers 
  * @param outlierCutSPD Cut to remove events with outliers 
+ * @param etaGap        Size of @f$\eta@f$ gap
+ * @param useCent       Whether to use centrality or impact parameter for MC 
+ * @param useMCVtx      Whether to use vertex info from MC header
+ * @param satVtx        Use satellite interactions 
  * @param addFlow       Afterburn what (MC only)
  * @param addFType      Afterburner parameterization
  * @param addFOrder     Afterburder order 
  *
  * @ingroup pwglf_forward_flow
  */
-void AddTaskForwardFlow(TString  type          = "234", 
-                        Bool_t   useEtaGap     = kFALSE,
-                        Bool_t   mc            = kFALSE,
-                       Double_t outlierCutFMD = 4.0, 
-                       Double_t outlierCutSPD = 0,
-                       Double_t etaGap        = 2.0,
-                       Bool_t   useCent       = kFALSE,
-                       Bool_t   satVtx        = kFALSE,
-                        TString  addFlow       = "",
-                        Int_t    addFType      = 0,
-                        Int_t    addFOrder     = 0)
+void AddTaskForwardFlowQC(Int_t    maxMom        = 5,
+                          TString  fwdDet        = "FMD",
+                          Bool_t   useEtaGap     = kFALSE,
+                          Bool_t   use3cor       = kFALSE,
+                          Bool_t   mc            = kFALSE,
+                         Double_t outlierCutFMD = 4.0, 
+                         Double_t outlierCutSPD = 4.0,
+                         Double_t etaGap        = 2.0,
+                         Bool_t   useTPCForRef  = kFALSE,
+                         Bool_t   useCent       = kFALSE,
+                         Bool_t   useMCVtx      = kFALSE,
+                         Bool_t   satVtx        = kFALSE,
+                         TString  addFlow       = "",
+                         Int_t    addFType      = 0,
+                         Int_t    addFOrder     = 0)
 {
   // --- Get analysis manager ----------------------------------------
   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
@@ -58,12 +63,27 @@ void AddTaskForwardFlow(TString  type          = "234",
     Fatal("","The relevant tasks weren't added to the train");
 
   // --- For the selected flow tasks the input and output is set -----
-  const char* name = (useEtaGap ? "ForwardQCumulantsEtaGap", "ForwardQCumulants");
+  fwdDet.ToUpper();
+  
+  // --- Set flow flags --------------------------------------------
+  if (useEtaGap && use3cor) 
+    Fatal("", "You're doing it wrong! Cannot do both eta-gap and 3-sub");
+  UShort_t flags = AliForwardFlowTaskQC::kStdQC|AliForwardFlowTaskQC::kSymEta;
+  if (useEtaGap)              flags = AliForwardFlowTaskQC::kEtaGap;
+  if (use3cor)                flags = AliForwardFlowTaskQC::k3Cor;
+  if (satVtx)                 flags |= AliForwardFlowTaskQC::kSatVtx;
+  if (fwdDet.Contains("FMD")) flags |= AliForwardFlowTaskQC::kNUAcorr;
+  if      (fwdDet.Contains("FMD"))   flags |= AliForwardFlowTaskQC::kFMD;
+  else if (fwdDet.Contains("VZERO")) flags |= AliForwardFlowTaskQC::kVZERO;
+  if (useTPCForRef) flags |= AliForwardFlowTaskQC::kTPC;
+
+  const char* name = Form("ForwardFlowQC%s%s", fwdDet.Data(), AliForwardFlowTaskQC::GetQCType(flags, false));
   AliForwardFlowTaskQC* task = 0;
   // --- Set up adding flow to MC input ----------------------------
   if (mc) {
     AliForwardMCFlowTaskQC* mcTask = new AliForwardMCFlowTaskQC(name);
     mcTask->SetUseImpactParameter(!useCent);
+    mcTask->SetUseMCHeaderVertex(useMCVtx);
     if (addFlow.Data()[0] != '\0') {
       mcTask->AddFlow(addFlow);
       mcTask->AddFlowType(addFType);
@@ -75,32 +95,17 @@ void AddTaskForwardFlow(TString  type          = "234",
   else 
     task = new AliForwardFlowTaskQC(name);
   
-  mgr->AddTask(task); 
-
-  // --- Set flow flags --------------------------------------------
-  UShort_t flags = AliForwardFlowTaskQC::kSymEta;
-  if (useEtaGap)           flags |= AliForwardFlowTaskQC::kEtaGap;
-  if (satVtx)              flags |= AliForwardFlowTaskQC::kSatVtx;
-  if (useEtaGap || satVtx) flags ^= AliForwardFlowTaskQC::kSymEta;
+  mgr->AddTask(task);
+//  mgr->SetSkipTerminate(true);
+//  task->SelectCollisionCandidates(AliVEvent::kCentral);
   task->SetFlowFlags(flags);
   
   // --- Set eta gap value -----------------------------------------
   task->SetEtaGapValue(etaGap);
 
   // --- Check which harmonics to calculate --------------------------
-  const char* harm = type.Data();
-  Int_t i = 0;
-  std::cout << "Type string: " << type.Data();
-  std::cout << "\t harm string: " << harm << std::endl;
-  while (i < type.Length()) {
-    char c = harm[i];
-    std::cout << "Adding moment: " << c << std::endl;
-    Short_t n = atoi(&c);
-    std::cout << "Adding moment: " << n << std::endl;
-    task->AddFlowMoment(n);
-    i++;
-  }
-
+  task->SetMaxFlowMoment(maxMom);
+  
   // --- Set non-default axis for vertices ---------------------------
   TAxis* a = 0;
   if (satVtx) {
@@ -108,14 +113,23 @@ void AddTaskForwardFlow(TString  type          = "234",
   }
   else 
     a = new TAxis(20, -10, 10);
+//    a = new TAxis(10, -5, 5);
   task->SetVertexAxis(a);
 
+  // --- Set non-default axis for centrality -------------------------
+  Double_t cent[] = {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100 };
+  //Double_t cent[] = {0, 2.5, 15, 25, 50, 100 };
+  //Double_t cent[] = {0, 100};
+  Int_t nBins = sizeof(cent)/sizeof(Double_t) -1;
+  TAxis* centAxis = new TAxis(nBins, cent);
+  task->SetCentralityAxis(centAxis);
+
   // --- Set sigma cuts for outliers ---------------------------------
   task->SetDetectorCuts(outlierCutFMD, outlierCutSPD);
 
   // --- Create containers for output --------------------------------
-  const char* sumName = (useEtaGap ? "FlowQCSumsEtaGap" : "FlowQCSums");
-  const char* resName = (useEtaGap ? "FlowQCResultsEtaGap" : "FlowQCResults");
+  const char* sumName = Form("FlowQCSums%s%s", fwdDet.Data(), AliForwardFlowTaskQC::GetQCType(flags, false));
+  const char* resName = Form("FlowQCResults%s%s", fwdDet.Data(), AliForwardFlowTaskQC::GetQCType(flags, false));
   AliAnalysisDataContainer* sums = 
     mgr->CreateContainer(sumName, TList::Class(), 
                         AliAnalysisManager::kOutputContainer, 
index ab1f583..6806e04 100644 (file)
@@ -6,29 +6,20 @@
 //  - AliAODEvent
 //
 // Outputs:
-//  - AnalysisResults.root
+//  - AnalysisResults.root or forward_flow.root
 //
-/**
- * @file   AliForwardFlowTaskQC.cxx
- * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
- * @date   Thu Feb  7 01:09:00 2013
- * 
- * @brief  
- * 
- * 
- * @ingroup pwglf_forward_flow
- */
 #include <TROOT.h>
 #include <TSystem.h>
 #include <TInterpreter.h>
 #include <TChain.h>
 #include <TFile.h>
 #include <TList.h>
-#include <iostream>
 #include <TMath.h>
 #include <TH3D.h>
 #include <TProfile2D.h>
 #include <TParameter.h>
+#include <TMatrixD.h>
+#include <TVectorD.h>
 #include <TGraph.h>
 #include "AliLog.h"
 #include "AliForwardFlowTaskQC.h"
 #include "AliAODCentralMult.h"
 #include "AliAODEvent.h"
 #include "AliForwardUtil.h"
+#include "AliAODVZERO.h"
+#include "AliAODVertex.h"
+#include "AliCentrality.h"
+#include "AliESDEvent.h"
+#include "AliVTrack.h"
+#include "AliESDtrackCuts.h"
+#include "AliAODTrack.h"
 
 ClassImp(AliForwardFlowTaskQC)
 #if 0
@@ -47,50 +45,62 @@ ClassImp(AliForwardFlowTaskQC)
 
 AliForwardFlowTaskQC::AliForwardFlowTaskQC()
   : AliAnalysisTaskSE(),
-    fVtxAxis(),         // Axis to contorl vertex binning
-    fFMDCut(-1),        // FMD sigma cut
-    fSPDCut(-1),        // SPD sigma cut
-    fFlowFlags(kSymEta),// Flow flags
-    fEtaGap(2.),        // Eta gap value
-    fBinsFMD(),         // List with FMD flow histos
-    fBinsSPD(),         // List with SPD flow histos
-    fSumList(0),       // Event sum list
-    fOutputList(0),    // Result output list
-    fAOD(0),           // AOD input event
-    fV(),               // Flow moments
-    fVtx(1111),                // Z vertex coordinate
-    fCent(-1),         // Centrality
-    fHistCent(),        // Histo for centrality
-    fHistVertexSel()    // Histo for selected vertices
+    fVtxAxis(),          // Axis to control vertex binning
+    fCentAxis(),         // Axis to control centrality/multiplicity binning
+    fFMDCut(-1),         // FMD sigma cut
+    fSPDCut(-1),         // SPD sigma cut
+    fFlowFlags(0),       // Flow flags
+    fEtaGap(-1),         // Eta gap value
+    fBinsForward(),      // List with forward flow hists
+    fBinsCentral(),      // List with central flow hists
+    fSumList(0),        // Event sum list
+    fOutputList(0),     // Result output list
+    fAOD(0),            // AOD input event
+    fESDTrackCuts(0),    // ESD track cuts
+    fMaxMoment(0),       // Max flow moment
+    fVtx(1111),                 // Z vertex coordinate
+    fCent(-1),          // Centrality
+    fHistdNdedpV0(),     // Hist for v0
+    fHistdNdedp3Cor(),   // Hist for combining detectors
+    fHistFMDSPDCorr(),   // FMD SPD correlation
+    fHistCent(),         // Hist for centrality
+    fHistVertexSel(),    // Hist for selected vertices
+    fHistEventSel()      // Hist for event selection
 {
   // 
-  // Default constructor
+  //  Default constructor
   //
 }
 //_____________________________________________________________________
 AliForwardFlowTaskQC::AliForwardFlowTaskQC(const char* name) 
   : AliAnalysisTaskSE(name),
-    fVtxAxis(),         // Axis to contorl vertex binning
+    fVtxAxis(),         // Axis to control vertex binning
+    fCentAxis(),        // Axis to control centrality/multiplicity binning
     fFMDCut(-1),        // FMD sigma cut
     fSPDCut(-1),        // SPD sigma cut
-    fFlowFlags(kSymEta),// Flow flags
+    fFlowFlags(kSymEta|kStdQC), // Flow flags
     fEtaGap(2.),        // Eta gap value
-    fBinsFMD(),         // List with FMD flow histos
-    fBinsSPD(),         // List with SPD flow histos
+    fBinsForward(),     // List with forward flow hists
+    fBinsCentral(),     // List with central flow hists
     fSumList(0),        // Event sum list           
     fOutputList(0),     // Result output list       
     fAOD(0),           // AOD input event          
-    fV(),               // Flow moments
+    fESDTrackCuts(0),   // ESD track cuts
+    fMaxMoment(4),      // Max flow moment
     fVtx(1111),         // Z vertex coordinate      
     fCent(-1),          // Centrality               
-    fHistCent(),        // Histo for centrality
-    fHistVertexSel()    // Histo for selected vertices
+    fHistdNdedpV0(),    // Histo for v0
+    fHistdNdedp3Cor(),  // Histo for combining detectors
+    fHistFMDSPDCorr(),  // FMD SPD correlation
+    fHistCent(),        // Hist for centrality
+    fHistVertexSel(),   // Hist for selected vertices
+    fHistEventSel()     // Hist for event selection
 {
   // 
-  // Constructor
+  //  Constructor
   //
-  // Parameters:
-  //  name: Name of task
+  //  Parameters:
+  //   name: Name of task
   //
   DefineOutput(1, TList::Class());
   DefineOutput(2, TList::Class());
@@ -98,27 +108,33 @@ AliForwardFlowTaskQC::AliForwardFlowTaskQC(const char* name)
 //_____________________________________________________________________
 AliForwardFlowTaskQC::AliForwardFlowTaskQC(const AliForwardFlowTaskQC& o)
   : AliAnalysisTaskSE(o),
-    fVtxAxis(o.fVtxAxis),              // Axis to contorl vertex binning
+    fVtxAxis(o.fVtxAxis),              // Axis to control vertex binning
+    fCentAxis(o.fCentAxis),            // Array to control centrality/multiplicity binning
     fFMDCut(o.fFMDCut),                // FMD sigma cut
     fSPDCut(o.fSPDCut),                // SPD sigma cut
     fFlowFlags(o.fFlowFlags),          // Flow flags
     fEtaGap(o.fEtaGap),                // Eta gap value
-    fBinsFMD(),                        // List with FMD flow histos
-    fBinsSPD(),                        // List with SPD flow histos
+    fBinsForward(),                    // List with forward flow hists
+    fBinsCentral(),                    // List with central flow hists
     fSumList(o.fSumList),              // Event sum list           
     fOutputList(o.fOutputList),        // Result output list       
     fAOD(o.fAOD),                     // AOD input event          
-    fV(o.fV),                          // Flow moments
+    fESDTrackCuts(o.fESDTrackCuts),    // ESD track cuts
+    fMaxMoment(o.fMaxMoment),          // Flow moments
     fVtx(o.fVtx),                      // Z vertex coordinate      
     fCent(o.fCent),                   // Centrality
-    fHistCent(o.fHistCent),            // Histo for centrality
-    fHistVertexSel(o.fHistVertexSel)   // Histo for selected vertices
+    fHistdNdedpV0(o.fHistdNdedpV0),    // Histo for v0
+    fHistdNdedp3Cor(o.fHistdNdedp3Cor),// Histo for combining detectors
+    fHistFMDSPDCorr(o.fHistFMDSPDCorr),// FMD SPD correlation
+    fHistCent(o.fHistCent),            // Hist for centrality
+    fHistVertexSel(o.fHistVertexSel),  // Hist for selected vertices
+    fHistEventSel(o.fHistEventSel)     // Hist for event selection
 {
   // 
-  // Copy constructor 
+  //  Copy constructor 
   // 
-  // Parameters:
-  //    o Object to copy from 
+  //  Parameters:
+  //   o: Object to copy from 
   //
 }
 //_____________________________________________________________________
@@ -126,53 +142,77 @@ AliForwardFlowTaskQC&
 AliForwardFlowTaskQC::operator=(const AliForwardFlowTaskQC& o)
 {
   // 
-  // Assignment operator 
+  //  Assignment operator 
   //
   if (&o == this) return *this;
-  fVtxAxis       = o.fVtxAxis;
-  fFMDCut        = o.fFMDCut;
-  fSPDCut        = o.fSPDCut;
-  fFlowFlags     = o.fFlowFlags;
-  fEtaGap        = o.fEtaGap;
-  fSumList       = o.fSumList;
-  fOutputList    = o.fOutputList;
-  fAOD           = o.fAOD;
-  fV             = o.fV;
-  fVtx           = o.fVtx;
-  fCent          = o.fCent;
-  fHistCent      = o.fHistCent;
-  fHistVertexSel = o.fHistVertexSel;
+  fVtxAxis        = o.fVtxAxis;
+  fCentAxis       = o.fCentAxis;
+  fFMDCut         = o.fFMDCut;
+  fSPDCut         = o.fSPDCut;
+  fFlowFlags      = o.fFlowFlags;
+  fEtaGap         = o.fEtaGap;
+  fSumList        = o.fSumList;
+  fOutputList     = o.fOutputList;
+  fAOD            = o.fAOD;
+  fESDTrackCuts   = o.fESDTrackCuts;
+  fMaxMoment      = o.fMaxMoment;
+  fVtx            = o.fVtx;
+  fCent           = o.fCent;
+  fHistdNdedpV0   = o.fHistdNdedpV0;
+  fHistdNdedp3Cor = o.fHistdNdedp3Cor;
+  fHistFMDSPDCorr = o.fHistFMDSPDCorr;
+  fHistCent       = o.fHistCent;
+  fHistVertexSel  = o.fHistVertexSel;
+  fHistEventSel   = o.fHistEventSel;
 
   return *this;
 }
 //_____________________________________________________________________
+void AliForwardFlowTaskQC::SetFlowFlags(UShort_t flags)
+{
+  //
+  //  Set flow flags, making sure the detector setup is right
+  //
+  //  Parameters:
+  //   flags: Flow flags
+  //
+  if ((flags & kFMD) && (flags & kVZERO)) 
+    AliFatal("Cannot do analysis on more than one forward detector!");
+  else if (!(flags & kFMD) && !(flags & kVZERO)) 
+    AliFatal("You need to add a forward detector!");
+  else fFlowFlags = flags;
+}
+//_____________________________________________________________________
 void AliForwardFlowTaskQC::UserCreateOutputObjects()
 {
   //
-  // Create output objects
+  //  Create output objects
   //
   InitVertexBins();
   InitHists();
+  if (fFlowFlags & kTPC) {
+    fESDTrackCuts = AliESDtrackCuts::GetStandardTPCOnlyTrackCuts();
+  }
   PrintFlowSetup();
 
   PostData(1, fSumList);
-  PostData(2, fOutputList);
-
 }
 //_____________________________________________________________________
 void AliForwardFlowTaskQC::InitVertexBins()
 {
   // 
-  // Init vertexbin objects for FMD and SPD, and add them to the lists
-  //
-  Int_t moment = 0;
-  for(UShort_t n = 0; n < fV.GetSize(); n++) {
-    moment = fV.At(n);
-    for (Int_t v = 1; v <= fVtxAxis->GetNbins(); v++) {
-      Int_t vL = Int_t(fVtxAxis->GetBinLowEdge(v));
-      Int_t vH = Int_t(fVtxAxis->GetBinUpEdge(v));
-      fBinsFMD.Add(new VertexBin(vL, vH, moment, "FMD", fFlowFlags, fFMDCut, fEtaGap));
-      fBinsSPD.Add(new VertexBin(vL, vH, moment, "SPD", fFlowFlags, fSPDCut, fEtaGap));
+  //  Init vertexbin objects for forward and central detectors, and add them to the lists
+  //
+  for (Int_t v = 1; v <= fVtxAxis->GetNbins(); v++) {
+    Int_t vL = Int_t(fVtxAxis->GetBinLowEdge(v));
+    Int_t vH = Int_t(fVtxAxis->GetBinUpEdge(v));
+    if ((fFlowFlags & kFMD)) {
+      fBinsForward.Add(new VertexBin(vL, vH, fMaxMoment, "FMD", fFlowFlags, fFMDCut, fEtaGap));
+      if (!(fFlowFlags & k3Cor)) fBinsCentral.Add(new VertexBin(vL, vH, fMaxMoment, "SPD-FMD", fFlowFlags|kNUAcorr, fSPDCut, fEtaGap));
+    }
+    else if ((fFlowFlags & kVZERO)) {
+      fBinsForward.Add(new VertexBin(vL, vH, fMaxMoment, "VZERO", fFlowFlags, 0, fEtaGap));
+      if (!(fFlowFlags & k3Cor)) fBinsCentral.Add(new VertexBin(vL, vH, fMaxMoment, "SPD-VZERO", fFlowFlags|kNUAcorr, fSPDCut, fEtaGap));
     }
   }
 }
@@ -180,9 +220,8 @@ void AliForwardFlowTaskQC::InitVertexBins()
 void AliForwardFlowTaskQC::InitHists()
 {
   //
-  // Init histograms and add vertex bin histograms to the sum list
+  //  Init histograms and add vertex bin histograms to the sum list
   //
-  
   if (!fSumList)
     fSumList = new TList();
   fSumList->SetName("Sums");
@@ -190,36 +229,73 @@ void AliForwardFlowTaskQC::InitHists()
 
   if (!fVtxAxis) fVtxAxis = new TAxis(20, -10, 10);
   fVtxAxis->SetName("VtxAxis");
+  if (!fCentAxis) fCentAxis = new TAxis(20, 0, 100);
+  fVtxAxis->SetName("CentAxis");
+  
   fHistCent         = new TH1D("hCent", "Centralities", 100, 0, 100);
   fHistVertexSel    = new TH1D("hVertexSel", "Selected vertices", fVtxAxis->GetNbins(), fVtxAxis->GetXmin(), fVtxAxis->GetXmax());
+  fHistEventSel     = new TH1I("hEventSel", "Event Selection", kOK, 0.5, kOK+0.5);
+  fHistEventSel->GetXaxis()->SetBinLabel(kNoEvent, "No AOD event");
+  fHistEventSel->GetXaxis()->SetBinLabel(kNoForward, "No forward det");
+  fHistEventSel->GetXaxis()->SetBinLabel(kNoCentral, "No central det");
+  fHistEventSel->GetXaxis()->SetBinLabel(kNoTrigger, "Not triggered");
+  fHistEventSel->GetXaxis()->SetBinLabel(kNoCent, "No centrality");
+  fHistEventSel->GetXaxis()->SetBinLabel(kInvCent, "Centrality outside range");
+  fHistEventSel->GetXaxis()->SetBinLabel(kNoVtx, "No vertex");
+  fHistEventSel->GetXaxis()->SetBinLabel(kInvVtx, "Vtx outside range");
+  fHistEventSel->GetXaxis()->SetBinLabel(kOK, "OK!");
+
+  fHistFMDSPDCorr = new TH2D("hFMDSPDCorr", "hFMDSPCCorr", 200, 0., 20000., 200, 0, 7500);
 
   TList* dList = new TList();
   dList->SetName("Diagnostics");
-//  dList->Add(fVtxAxis);
   dList->Add(fHistCent);
   dList->Add(fHistVertexSel);
+  dList->Add(fHistEventSel);
+  dList->Add(fHistFMDSPDCorr);
   fSumList->Add(dList);
 
-  TIter nextFMD(&fBinsFMD);
+  fHistdNdedp3Cor = TH2D(Form("hdNdedpCombined_%s", GetQCType(fFlowFlags)), Form("hdNdedpCombined_%s", GetQCType(fFlowFlags)), 
+                           200, -4., 6., 20, 0., TMath::TwoPi());
+  if ((fFlowFlags & kVZERO)) {
+    Double_t bins[12] = { -6, -3.7, -3.2, -2.7, -2.2, -1.7, 
+                         2.8, 3.4,  3.9,  4.5,  5.1, 6 };
+    fHistdNdedpV0 = TH2D(Form("hdNdedpv0%s", GetQCType(fFlowFlags)), Form("hdNdedpv0%s", GetQCType(fFlowFlags)),
+                   11, -6, 6, 8, 0, TMath::TwoPi());
+    fHistdNdedpV0.GetXaxis()->Set(11, bins);
+    if ((fFlowFlags & k3Cor)) {
+      Double_t bins2[20] = { -6, -3.7, -3.2, -2.7, -2.2, // VZERO
+                             -2.0, -1.5, -1.0, -0.5 , 0., 0.5, 1.0, 1.5, 2.0, // SPD
+                           2.8, 3.4,  3.9,  4.5,  5.1, 6 }; // VZERO
+      fHistdNdedp3Cor.GetXaxis()->Set(19, bins2);
+      fHistdNdedp3Cor.GetYaxis()->Set(8, 0., TMath::TwoPi());
+    }
+  }
+
+  TIter nextForward(&fBinsForward);
   VertexBin* bin = 0;
-  while ((bin = static_cast<VertexBin*>(nextFMD()))) {
-    bin->AddOutput(fSumList);
+  while ((bin = static_cast<VertexBin*>(nextForward()))) {
+    bin->AddOutput(fSumList, fCentAxis);
   }
-  TIter nextSPD(&fBinsSPD);
-  while ((bin = static_cast<VertexBin*>(nextSPD()))) {
-    bin->AddOutput(fSumList);
+  TIter nextCentral(&fBinsCentral);
+  while ((bin = static_cast<VertexBin*>(nextCentral()))) {
+    bin->AddOutput(fSumList, fCentAxis);
   }
 }
 //_____________________________________________________________________
 void AliForwardFlowTaskQC::UserExec(Option_t */*option*/)
 {
   //
-  // Calls the analyze function - called every event
+  //  Calls the analyze function - called every event
   //
-  // Parameters:
-  //  option: Not used
+  //  Parameters:
+  //   option: Not used
   //
   
+  // Reset data members
+  fCent = -1;
+  fVtx = 1111;
+
   Analyze();
   
   PostData(1, fSumList);
@@ -230,108 +306,285 @@ void AliForwardFlowTaskQC::UserExec(Option_t */*option*/)
 Bool_t AliForwardFlowTaskQC::Analyze()
 {
   // 
-  // Load FMD and SPD objects from aod tree and call the cumulants 
-  // calculation for the correct vertexbin
+  //  Load forward and central detector objects from aod tree and call the 
+  //  cumulants calculation for the correct vertex bin
+  //
+  //  Return: true on success
   //
-
-  // Reset data members
-  fCent = -1;
-  fVtx = 1111;
 
   // Get input event
-//  fAOD = dynamic_cast<AliAODEvent*>(InputEvent());
   fAOD = dynamic_cast<AliAODEvent*>(AliForwardUtil::GetAODEvent(this));
-  if (!fAOD) return kFALSE;
+  if (!fAOD) {
+    fHistEventSel->Fill(kNoEvent);
+    return kFALSE;
+  }
 
-  const AliAODForwardMult* aodfmult = static_cast<AliAODForwardMult*>(fAOD->FindListObject("Forward"));
-  const AliAODCentralMult* aodcmult = static_cast<AliAODCentralMult*>(fAOD->FindListObject("CentralClusters"));
-  if (!aodfmult) return kFALSE;
-  
-  // Check event for triggers, get centrality, vtx etc.
-  if (!CheckEvent(aodfmult)) return kFALSE;
-  Int_t vtx = fVtxAxis->FindBin(fVtx)-1;
+  // Get detector objects
+  AliAODForwardMult* aodfmult = static_cast<AliAODForwardMult*>(fAOD->FindListObject("Forward"));
+  AliAODCentralMult* aodcmult = static_cast<AliAODCentralMult*>(fAOD->FindListObject("CentralClusters"));
+  AliAODVZERO* aodvzero = fAOD->GetVZEROData();
+  if ((fFlowFlags & kVZERO)) {
+    if (aodvzero) {
+      fHistdNdedpV0.Reset();
+      FillVZEROHist(aodvzero);
+    }
+  }
 
-  // If everything is OK: get histos and run analysis
-  const TH2D& fmddNdetadphi = aodfmult->GetHistogram();
-  if ((fFlowFlags & kEtaGap)) {
-    FillVtxBinListEtaGap(fBinsFMD, fmddNdetadphi, fmddNdetadphi, vtx);
-  } else {
-    FillVtxBinList(fBinsFMD, fmddNdetadphi, vtx);
+  // We make sure that the necessary forward object is there
+  if ((fFlowFlags & kFMD) && !aodfmult) {
+    fHistEventSel->Fill(kNoForward);
+    return kFALSE; 
+  }
+  else if ((fFlowFlags & kVZERO) && !aodvzero) {
+    fHistEventSel->Fill(kNoForward);
+    return kFALSE; 
   }
+  if (!aodcmult) fHistEventSel->Fill(kNoCentral);
 
+   // Check event for triggers, get centrality, vtx etc.
+  if (!CheckEvent(aodfmult)) return kFALSE;
+  Int_t vtx = fVtxAxis->FindBin(fVtx)-1;
+  
+  // Then we assign a reference to the forward histogram of interest
+  TH2D& forwarddNdedp = ((fFlowFlags & kFMD) ? aodfmult->GetHistogram() : fHistdNdedpV0);
+  TH2D& spddNdedp = aodcmult->GetHistogram();
+  if ((fFlowFlags & kStdQC)) {
+    FillVtxBinList(fBinsForward, forwarddNdedp, vtx);
+  } else if ((fFlowFlags & kEtaGap)) {
+    FillVtxBinListEtaGap(fBinsForward, forwarddNdedp, forwarddNdedp, vtx);
+  }
+  // At the moment only clusters are supported for the central region (some day add tracks?)
+  // So no extra checks necessary
   if (aodcmult) {
-    const TH2D& spddNdetadphi = aodcmult->GetHistogram();
-    if ((fFlowFlags & kEtaGap)) {
-      FillVtxBinListEtaGap(fBinsSPD, fmddNdetadphi, spddNdetadphi, vtx);
-    } else {
-      FillVtxBinList(fBinsSPD, spddNdetadphi, vtx);
+    if ((fFlowFlags & kStdQC)) {
+      FillVtxBinList(fBinsCentral, spddNdedp, vtx);
+    } else if ((fFlowFlags & kEtaGap)) {
+      FillVtxBinListEtaGap(fBinsCentral, forwarddNdedp, spddNdedp, vtx);
+    } else if ((fFlowFlags & k3Cor)) {
+      FillVtxBinList3Cor(fBinsForward, spddNdedp, forwarddNdedp, vtx);
+    }
+    // Diagnostics
+    if (aodfmult) {
+      Double_t totForward = forwarddNdedp.Integral(1, forwarddNdedp.GetNbinsX(), 1, forwarddNdedp.GetNbinsY());
+      Double_t totSPD = spddNdedp.Integral(1, spddNdedp.GetNbinsX(), 1, spddNdedp.GetNbinsY());
+      fHistFMDSPDCorr->Fill(totForward, totSPD);
     }
   }
 
   return kTRUE;
 }
 //_____________________________________________________________________
-Bool_t AliForwardFlowTaskQC::FillVtxBinList(const TList& list, const TH2D& h, Int_t vtx) const
+void AliForwardFlowTaskQC::FillVtxBinList(const TList& list, TH2D& h, Int_t vtx, UShort_t flags) const
 {
   //
-  // Loops over list of VtxBins, fills hists of bins for current vertex
-  // and runs analysis on those bins
+  //  Loops over list of VtxBins, fills hists of bins for current vertex
+  //  and runs analysis on those bins
   //
-  // Parameters:
-  //  list: list of VtxBins
-  //  h:    dN/detadphi histogram
-  //  vBin: current vertex bin
+  //  Parameters:
+  //   list:  list of VtxBins
+  //   h:     dN/detadphi histogram
+  //   vtx:   current vertex bin
+  //   flags: extra flags to handle calculations.
+  // 
+  //   Note: The while loop is used in this function and the next 2 for historical reasons,
+  //         as originally each moment had it's own VertexBin object.
+  VertexBin* bin = 0;
+  Int_t i = 0;
+  Int_t nVtxBins = fVtxAxis->GetNbins();
+  
+  while ((bin = static_cast<VertexBin*>(list.At(vtx+(nVtxBins*i))))) {
+    // If no tracks do things normally
+    if (!(fFlowFlags & kTPC) && !bin->FillHists(h, fCent, kFillBoth|flags|kReset)) return;
+    // if tracks things are more complicated
+    else if ((fFlowFlags & kTPC)) {
+      TObjArray* trList = GetTracks();
+      if (!trList) return;
+      Bool_t useEvent = bin->FillTracks(trList, kFillRef|kReset|flags);
+      // If esd input trList is a new object owned by this task and should be cleaned up
+      if (AliForwardUtil::CheckForAOD() == 2) delete trList;
+      if (!useEvent) return;
+      if (!bin->FillHists(h, fCent, kFillDiff|kReset|flags)) return;
+    }
+    bin->CumulantsAccumulate(fCent);
+    i++;
+  }
+
+  return;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::FillVtxBinListEtaGap(const TList& list, TH2D& href, 
+                                                  TH2D& hdiff, Int_t vtx, UShort_t flags) const
+{
+  //
+  //  Loops over list of VtxBins, fills hists of bins for current vertex
+  //  and runs analysis on those bins
   //
-  // return true on success
+  //  Parameters:
+  //   list:  list of VtxBins
+  //   href:  dN/detadphi histogram for ref. flow
+  //   hdiff: dN/detadphi histogram for diff. flow
+  //   vBin:  current vertex bin
+  //   flags: extra flags to handle calculations.
   //
   VertexBin* bin = 0;
   Int_t i = 0;
   Int_t nVtxBins = fVtxAxis->GetNbins();
 
   while ((bin = static_cast<VertexBin*>(list.At(vtx+(nVtxBins*i))))) {
-    Bool_t skipFourP = !bin->FillHists(h, fCent, kFillBoth);
-    bin->CumulantsAccumulate(fCent, skipFourP);
+    if (!bin->FillHists(href, fCent, kFillRef|flags|kReset)) return;
+    bin->FillHists(hdiff, fCent, kFillDiff|kReset);
+    bin->CumulantsAccumulate(fCent);
     i++;
   }
 
-  return kTRUE;
+  return;
 }
 //_____________________________________________________________________
-Bool_t AliForwardFlowTaskQC::FillVtxBinListEtaGap(const TList& list, const TH2D& href, 
-                                                  const TH2D& hdiff, Int_t vtx) const
+void AliForwardFlowTaskQC::FillVtxBinList3Cor(const TList& list, TH2D& hcent, 
+                                              TH2D& hfwd, Int_t vtx, UShort_t flags)
 {
   //
-  // Loops over list of VtxBins, fills hists of bins for current vertex
-  // and runs analysis on those bins
+  //  Loops over list of VtxBins, fills hists of bins for current vertex
+  //  and runs analysis on those bins
   //
-  // Parameters:
-  //  list: list of VtxBins
-  //  h:    dN/detadphi histogram
-  //  vBin: current vertex bin
-  //
-  // return true on success
+  //  Parameters:
+  //   list:  list of VtxBins
+  //   hcent: dN/detadphi histogram for central coverage
+  //   hfwd:  dN/detadphi histogram for forward coverage
+  //   vBin:  current vertex bin
+  //   flags: extra flags to handle calculations.
   //
   VertexBin* bin = 0;
   Int_t i = 0;
   Int_t nVtxBins = fVtxAxis->GetNbins();
 
+  TH2D& h = CombineHists(hcent, hfwd);
+
   while ((bin = static_cast<VertexBin*>(list.At(vtx+(nVtxBins*i))))) {
-    bin->FillHists(href, fCent, kFillRef);
-    bin->FillHists(hdiff, fCent, kFillDiff);
-    bin->CumulantsAccumulate(fCent);
+    if (!bin->FillHists(h, fCent, kFillBoth|flags|kReset)) return;
+    bin->CumulantsAccumulate3Cor(fCent);
     i++;
   }
 
-  return kTRUE;
+  return;
+}
+//_____________________________________________________________________
+TH2D& AliForwardFlowTaskQC::CombineHists(TH2D& hcent, TH2D& hfwd)
+{
+  // 
+  //  Combines a forward and central d^2N/detadphi histogram.
+  //  At some point it might need a flag to choose which histogram gets
+  //  priority when there is an overlap, at the moment the average is chosen
+  //
+  //  Parameters:
+  //    hcent: Central barrel detector
+  //    hfwd: Forward detector
+  //
+  //  Return: reference to combined hist
+  //
+
+  // If hists are the same (MC input) don't do anything
+  if (&hcent == &hfwd) return hcent;
+
+  fHistdNdedp3Cor.Reset();
+  // FMD, SPD input
+  if ((fFlowFlags & kFMD)) {
+    for (Int_t e = 1; e <= fHistdNdedp3Cor.GetNbinsX(); e++)  {
+      Double_t eta = fHistdNdedp3Cor.GetXaxis()->GetBinCenter(e);
+      Bool_t fwdCov = (hfwd.GetBinContent(e, 0) != 0);
+      Bool_t centCov = (hcent.GetBinContent(e, 0) != 0);
+      if (!fwdCov && !centCov) continue;
+      else fHistdNdedp3Cor.SetBinContent(e, 0, 1);
+      for (Int_t p = 1; p <= fHistdNdedp3Cor.GetNbinsY(); p++) {
+       Double_t phi = fHistdNdedp3Cor.GetYaxis()->GetBinCenter(p);
+       Int_t n = 0;
+       Double_t cont = 0.;
+       if (fwdCov) {
+         cont += hfwd.GetBinContent(e, p);
+         n++;
+       }
+       if (centCov) {
+         cont += hcent.GetBinContent(e, p);
+         n++;
+       }
+       if (cont == 0 || n == 0) continue;
+       cont /= n;
+       fHistdNdedp3Cor.Fill(eta, phi, cont);
+      }
+    }
+  // VZERO, SPD input, here we do not average but cut to avoid
+  // (too much) overlap.
+  } else if ((fFlowFlags & kVZERO)) {
+    // VZERO loop
+    for (Int_t eV = 1; eV <= hfwd.GetNbinsX(); eV++) {
+      Double_t eta = hfwd.GetXaxis()->GetBinLowEdge(eV)+0.1;
+      if (hfwd.GetBinContent(eV, 0) == 0) continue;
+      else { 
+        Int_t he = fHistdNdedp3Cor.GetXaxis()->FindBin(eta);
+       fHistdNdedp3Cor.SetBinContent(he, 0, 1);
+      }
+      for (Int_t p = 1; p <= hfwd.GetNbinsY(); p++) { 
+        Double_t phi = hfwd.GetYaxis()->GetBinCenter(p);
+        Double_t cont = hfwd.GetBinContent(eV, p);
+        fHistdNdedp3Cor.Fill(eta, phi, cont);
+      }
+    }
+    // SPD loop
+    Int_t eSs = hcent.GetXaxis()->FindBin(-1.99);
+    Int_t eSe = hcent.GetXaxis()->FindBin(1.99);
+    for (Int_t eS = eSs; eS <= eSe; eS++) {
+      Double_t eta = hcent.GetXaxis()->GetBinCenter(eS);
+      if (hcent.GetBinContent(eS, 0) == 0) continue;
+      else {
+        Int_t he = fHistdNdedp3Cor.GetXaxis()->FindBin(eta);
+       fHistdNdedp3Cor.SetBinContent(he, 0, 1);
+      }
+      for (Int_t p = 1; p <= hcent.GetNbinsY(); p++) {
+        Double_t phi = hcent.GetYaxis()->GetBinCenter(p);
+        Double_t cont = hcent.GetBinContent(eS, p);
+        fHistdNdedp3Cor.Fill(eta, phi, cont);
+      }
+    }
+  }
+  return fHistdNdedp3Cor;
+}
+//_____________________________________________________________________
+TObjArray* AliForwardFlowTaskQC::GetTracks() const
+{
+  // 
+  //  Get TPC tracks to use for reference flow.
+  //
+  //  Return: TObjArray with tracks
+  //
+  TObjArray* trList = 0;
+  // Get input type
+  UShort_t input = AliForwardUtil::CheckForAOD();
+  switch (input) {
+    // If AOD input, simply get the track array from the event
+    case 1: trList = static_cast<TObjArray*>(fAOD->GetTracks());
+           break;
+    case 2: {
+    // If ESD input get event, apply track cuts
+             AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());
+             if (!esd) return 0;
+             // Warning! trList is now a new array, we need to delete it after use
+             // this is not a very good implementation!
+             trList = fESDTrackCuts->GetAcceptedTracks(esd, kTRUE);
+             break;
+           }
+    default: AliFatal("Neither ESD or AOD input. This should never happen");
+           break;
+  }
+  return trList;
 }
 //_____________________________________________________________________
 void AliForwardFlowTaskQC::Terminate(Option_t */*option*/)
 {
   //
-  // Calls the finalize function, done at the end of the analysis
+  //  Calls the finalize function, done at the end of the analysis
   //
-  // Parameters:
-  //  option: Not used
+  //  Parameters:
+  //   option: Not used
   //
 
   // Make sure pointers are set to the correct lists
@@ -349,47 +602,55 @@ void AliForwardFlowTaskQC::Terminate(Option_t */*option*/)
     TParameter<Double_t>* etaGap = new TParameter<Double_t>("EtaGap", fEtaGap);
     fOutputList->Add(etaGap);
   }
-
-  // We make summary histograms of accepted events.
-  TList* list = 0;
-  TH3D* hist = 0;
-  TH1D* cent = 0;
-  TObject* o = 0;
-  for (Int_t i = 1; i < fSumList->GetEntries(); i++) {
-    list = dynamic_cast<TList*>(fSumList->At(i));
-    if (!list) continue;
-    hist = dynamic_cast<TH3D*>(list->At(0));
-    if (!hist) continue;
-    const char* histname = hist->GetName();
-    TString name = "";
-    for (Int_t j = 0; ; j++) {
-      if (histname[j] == 'v') break;
-      name += histname[j];
-    }
-    if ((fFlowFlags & kEtaGap)) name += "_etaGap";
-    cent = (TH1D*)fOutputList->FindObject(name.Data());
-    if (!cent) {
-      cent = new TH1D(name.Data(), name.Data(), hist->GetNbinsY(), hist->GetYaxis()->GetXmin(), hist->GetYaxis()->GetXmax());
-      cent->GetXaxis()->Set(hist->GetNbinsY(), hist->GetYaxis()->GetXbins()->GetArray());
-      fOutputList->Add(cent);
-    }
-    for (Int_t k = 1; k <= hist->GetNbinsY(); k++) {
-      Double_t centrality = hist->GetYaxis()->GetBinCenter(k);
-      Double_t events = hist->GetBinContent(0, k, 0);
-      cent->Fill(centrality, events);
-    }
-    o = fOutputList->FindObject(Form("hQCQuality%s", name.Data()));
-    if (!o) MakeQualityHist(name);
-  }
+  // We only add axes in terminate, as TAxis object do not merge well,
+  // and so we get a mess when running on the grid if we put them in the sum list...
+  fVtxAxis->SetName("VtxAxis");
+  fOutputList->Add(fVtxAxis);
+  fCentAxis->SetName("CentAxis");
+  fOutputList->Add(fCentAxis);
 
   // Run finalize on VertexBins
   Finalize();
 
-  // Collect centralities
+  // Loop over output to get dN/deta hists - used for diagnostics
+  TIter next(fOutputList);
+  TObject* o = 0;
+  TString name;
+  TH2D* dNdeta = 0;
+  TH1D* cent = 0;
+  while ((o = next())) {
+    name = o->GetName();
+    if (name.Contains("dNdeta")) {
+      dNdeta = dynamic_cast<TH2D*>(o);
+      name.ReplaceAll("dNdeta", "cent");
+      name.ReplaceAll("Ref", "");
+      name.ReplaceAll("Diff", "");
+      cent = dynamic_cast<TH1D*>(fOutputList->FindObject(name.Data()));
+      if (!dNdeta || !cent) continue;
+      for (Int_t cBin = 1; cBin <= dNdeta->GetNbinsY(); cBin++) {
+        Double_t nEvents = cent->GetBinContent(cBin);
+        if (nEvents == 0) continue;
+       for (Int_t eBin = 1; eBin <= dNdeta->GetNbinsX(); eBin++) {
+         dNdeta->SetBinContent(eBin, cBin, dNdeta->GetBinContent(eBin, cBin)/nEvents);
+         dNdeta->SetBinError(eBin, cBin, dNdeta->GetBinError(eBin, cBin)/nEvents);
+       }
+      }
+    }
+  }   
+
+  // Loop over output and make 1D projections for fast look at results
   MakeCentralityHists(fOutputList);
   TList* vtxList = (TList*)fOutputList->FindObject("vtxList");
   if (vtxList) MakeCentralityHists(vtxList);
   TList* nuaList = (TList*)fOutputList->FindObject("NUATerms");
+  TIter nextNua(nuaList);
+  o = 0;
+  TH2D* h = 0;
+  while ((o = nextNua())) {
+    if (!(h = dynamic_cast<TH2D*>(o))) continue;
+    Double_t evts = h->GetBinContent(0, 0);
+    if (evts != 0) h->Scale(1./evts);
+  }
   if (nuaList) MakeCentralityHists(nuaList);
 
   PostData(2, fOutputList);
@@ -397,30 +658,19 @@ void AliForwardFlowTaskQC::Terminate(Option_t */*option*/)
   return;
 }
 //_____________________________________________________________________
-void AliForwardFlowTaskQC::AddFlowMoment(Short_t n)
-{
-    //
-    // Add a flow moment to be calculated
-    //
-    if (n > 10) AliFatal(Form("Too big moment added: %d (bug)", n));
-    Int_t size = fV.GetSize();
-    fV.Set(size+1);
-    fV.AddAt(n, size);
-}
-//_____________________________________________________________________
 void AliForwardFlowTaskQC::Finalize()
 {
   //
-  // Finalize command, called by Terminate()
+  //  Finalize command, called by Terminate()
   //
 
   // Reinitiate vertex bins if Terminate is called separately!
-  if (fBinsFMD.GetEntries() == 0) InitVertexBins();
+  if (fBinsForward.GetEntries() == 0) InitVertexBins();
 
   // Iterate over all vertex bins objects and finalize cumulants
   // calculations
-  EndVtxBinList(fBinsFMD);
-  EndVtxBinList(fBinsSPD);
+  EndVtxBinList(fBinsForward);
+  EndVtxBinList(fBinsCentral);
 
   return;
 } 
@@ -428,10 +678,10 @@ void AliForwardFlowTaskQC::Finalize()
 void AliForwardFlowTaskQC::EndVtxBinList(const TList& list) const
 {
   //
-  // Loop over VertexBin list and call terminate on each 
+  //  Loop over VertexBin list and call terminate on each 
   //
-  // Parameters:
-  //  list VertexBin list
+  //  Parameters:
+  //   list: VertexBin list
   //
   TIter next(&list);
   VertexBin* bin = 0;
@@ -441,22 +691,22 @@ void AliForwardFlowTaskQC::EndVtxBinList(const TList& list) const
   return;
 }
 // _____________________________________________________________________
-void AliForwardFlowTaskQC::MakeCentralityHists(TList* list)
+void AliForwardFlowTaskQC::MakeCentralityHists(TList* list) const
 {
   //
-  // Loop over a list containing a TProfile2D with flow results and project
+  // Loop over a list containing a TH2D with flow results
   // and project to TH1's in specific centrality bins
   //
   // Parameters:
-  //  list Flow results list
+  //  list: Flow results list
   //
-  TProfile2D* hist2D = 0;
+  TH2D* hist2D = 0;
   TList* centList = 0;
   TH1D* hist1D = 0;
   TObject* helper = 0;
-  TIter nextProfile(list);
-  while ((helper = dynamic_cast<TObject*>(nextProfile()))) {
-    if (!(hist2D = dynamic_cast<TProfile2D*>(helper))) continue;
+  TIter nextHist(list);
+  while ((helper = dynamic_cast<TObject*>(nextHist()))) {
+    if (!(hist2D = dynamic_cast<TH2D*>(helper))) continue;
     for (Int_t cBin = 1; cBin <= hist2D->GetNbinsY(); cBin++) {
       Int_t cMin = Int_t(hist2D->GetYaxis()->GetBinLowEdge(cBin));
       Int_t cMax = Int_t(hist2D->GetYaxis()->GetBinUpEdge(cBin));
@@ -478,27 +728,35 @@ void AliForwardFlowTaskQC::MakeCentralityHists(TList* list)
 Bool_t AliForwardFlowTaskQC::CheckEvent(const AliAODForwardMult* aodfm) 
 {
   // 
-  // Function to check that and AOD event meets the cuts
+  //  Function to check that an AOD event meets the cuts
   //
-  // Parameters: 
-  //  AliAODForwardMult: forward mult object with trigger and vertex info
+  //  Parameters: 
+  //   AliAODForwardMult: forward mult object with trigger and vertex info
   //
-  // Returns false if there is no trigger or if the centrality or vertex
-  // is out of range. Otherwise true.
+  //  Return: false if there is no trigger or if the centrality or vertex
+  //  is out of range. Otherwise true.
   //
 
   // First check for trigger
-  if (!CheckTrigger(aodfm)) return kFALSE;
+  if (!CheckTrigger(aodfm)) {
+    fHistEventSel->Fill(kNoTrigger);
+    return kFALSE;
+  }
 
   // Then check for centrality
-  if (!GetCentrality(aodfm)) return kFALSE;
+  if (!GetCentrality(aodfm)) {
+    return kFALSE;
+  }
 
   // And finally check for vertex
-  if (!GetVertex(aodfm)) return kFALSE;
+  if (!GetVertex(aodfm)) {
+    return kFALSE;
+  }
 
   // Ev. accepted - filling diag. hists
   fHistCent->Fill(fCent);
   fHistVertexSel->Fill(fVtx);
+  fHistEventSel->Fill(kOK);
   
   return kTRUE;
 }
@@ -506,88 +764,159 @@ Bool_t AliForwardFlowTaskQC::CheckEvent(const AliAODForwardMult* aodfm)
 Bool_t AliForwardFlowTaskQC::CheckTrigger(const AliAODForwardMult* aodfm) const 
 {
   //
-  // Function to look for a trigger string in the event.
+  //  Function to look for a trigger string in the event.
+  //  First check for info in forward mult object, if not there, use the AOD header
   //
-  // Parameters: 
-  //  AliAODForwardMult: forward mult object with trigger and vertex info
+  //  Parameters: 
+  //   AliAODForwardMult: forward mult object with trigger and vertex info
   //
-  // Returns true if offline trigger is present
+  //  Return: true if offline trigger is present
   //
-  return aodfm->IsTriggerBits(AliAODForwardMult::kOffline);
+  if (aodfm) return aodfm->IsTriggerBits(AliAODForwardMult::kOffline);
+  // this may need to be changed for 2011 data to handle kCentral and so on...
+  else return (((AliInputEventHandler*)(AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler()))
+                 ->IsEventSelected() & AliVEvent::kMB);
 }
 // _____________________________________________________________________
 Bool_t AliForwardFlowTaskQC::GetCentrality(const AliAODForwardMult* aodfm) 
 {
   //
-  // Function to look get centrality of the event.
+  //  Function to look get centrality of the event.
+  //  First check for info in forward mult object, if not there, use the AOD header
   //
-  // Parameters: 
-  //  AliAODForwardMult: forward mult object with trigger and vertex info
+  //  Parameters: 
+  //   AliAODForwardMult: forward mult object with trigger and vertex info
   //
-  // Returns true if centrality determination is present
+  //  Return: true if centrality determination is present
   //
-  if (aodfm->HasCentrality()) {
-    fCent = (Double_t)aodfm->GetCentrality();
-    if (0. >= fCent || fCent >= 100.) return kFALSE;
-  }
-  else fCent = 97.5;
-
-  return kTRUE;
+  if (aodfm) {
+    if (aodfm->HasCentrality()) {
+      fCent = (Double_t)aodfm->GetCentrality();
+      if (fCentAxis->GetXmin() > fCent || fCent >= fCentAxis->GetXmax()) {
+       fHistEventSel->Fill(kInvCent);
+       return kFALSE;
+      }
+    }
+    else {
+      fCent = 97.5;
+      fHistEventSel->Fill(kNoCent);
+    }
+    return kTRUE;
+  } else {
+    AliCentrality* aodCent = fAOD->GetCentrality();
+    if (aodCent) {
+      fCent = (Double_t)aodCent->GetCentralityPercentile("V0M");
+      if (fCentAxis->GetXmin() > fCent || fCent >= fCentAxis->GetXmax()) {
+       fHistEventSel->Fill(kInvCent);
+       return kFALSE;
+      }
+    }
+    else {
+      fCent = 97.5;
+      fHistEventSel->Fill(kNoCent);
+    }
+    return kTRUE;
+  } 
 }
-// _____________________________________________________________________
+//_____________________________________________________________________
 Bool_t AliForwardFlowTaskQC::GetVertex(const AliAODForwardMult* aodfm) 
 {
   //
-  // Function to look for vertex determination in the event.
+  //  Function to look for vertex determination in the event.
+  //  First check for info in forward mult object, if not there, use the AOD header
   //
-  // Parameters: 
-  //  AliAODForwardMult: forward mult object with trigger and vertex info
+  //  Parameters: 
+  //   AliAODForwardMult: forward mult object with trigger and vertex info
   //
-  // Returns true if vertex is determined
+  //  Return: true if vertex is determined
   //
-  fVtx = aodfm->GetIpZ();
-  if (fVtx < fVtxAxis->GetXmin() || fVtx > fVtxAxis->GetXmax()) return kFALSE;
-
-  return kTRUE;
+  if (aodfm) {
+    if (aodfm->HasIpZ()) {
+      fVtx = aodfm->GetIpZ();
+      if (fVtx < fVtxAxis->GetXmin() || fVtx >= fVtxAxis->GetXmax()) {
+       fHistEventSel->Fill(kInvVtx);
+       return kFALSE;
+      }
+    } else {
+      fVtx = 9999;
+      fHistEventSel->Fill(kNoVtx);
+      return kFALSE;
+    }
+    return kTRUE;
+  } else {
+    AliAODVertex* aodVtx = fAOD->GetPrimaryVertex();
+    if (aodVtx) {
+      fVtx = aodVtx->GetZ();
+      if (fVtx < fVtxAxis->GetXmin() || fVtx >= fVtxAxis->GetXmax()) {
+       fHistEventSel->Fill(kInvVtx);
+       return kFALSE;
+      }
+    } else {
+      fVtx = 9999;
+      fHistEventSel->Fill(kNoVtx);
+      return kFALSE;
+    }
+    return kTRUE;
+  }
 }
-//_____________________________________________________________________
-void AliForwardFlowTaskQC::MakeQualityHist(const Char_t* name) const {
-  
-  TH1I* quality = new TH1I(Form("hQCQuality%s", name), 
-                     Form("hQCQuality%s", name),
-                     fV.GetSize()*8, 1, fV.GetSize()*8+1);
-  for (Int_t i = 0, j = 1; i < fV.GetSize(); i++) {
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{2} > 0", fV.At(i)));
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{2} <= 0", fV.At(i)));
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{2} > 0", fV.At(i)));
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{2} <= 0", fV.At(i)));
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{4} < 0", fV.At(i)));
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{4} >= 0", fV.At(i)));
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{4} < 0", fV.At(i)));
-    quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{4} >= 0", fV.At(i)));
-  }
-
-  fOutputList->Add(quality);
+// _____________________________________________________________________
+void AliForwardFlowTaskQC::FillVZEROHist(AliAODVZERO* aodVZero)
+{
+  //
+  //  Loops over VZERO data object and fill up d^2N/detadphi histogram for flow analysis
+  //
+  //  Parameters:
+  //   aodVZero: VZERO AOD data object
+  //
+  Int_t ring = 0;
+  Int_t bin = 0;
+  Double_t eta = 0;
+  // Sort of right for 2010 data, do not use for 2011!
+  Double_t eq[64] = { 1.43536, 1.45727, 1.44993, 1.30051, 1.17425, 1.2335, 1.22247, 1.14362, 
+                     1.14647, 1.25208, 1.17681, 1.21642, 1.16604, 1.05532, 1.03212, 1.1032, 
+                     1.22941, 1.36986, 1.14652, 1.20056, 0.927086, 1.10809, 1.03343, 1.29472, 
+                     1.21204, 1.29217, 1.2003, 2.10382, 1.28513, 1.40558, 1.25784, 1.21848, 
+                     0.475162, 0.50421, 0.503617, 0.512471, 0.515276, 0.39831, 0.415199, 0.444664, 
+                     0.521922, 0.785915, 0.703658, 0.832479, 0.77461, 0.73129, 0.778697, 0.710265, 
+                     0.89686, 0.967688, 0.974225, 0.873445, 0.811096, 0.828493, 0.889609, 0.586056, 
+                     1.15877, 0.954656, 0.914557, 0.979028, 1.04907, 0.748518, 0.928043, 0.98175 };
+  for (Int_t i = 0; i < 64; i++) {
+    if (i % 8 == 0) {
+      ring++;
+      bin = (ring < 5 ? ring+1 : 15-ring);
+      eta = fHistdNdedpV0.GetXaxis()->GetBinCenter(bin);
+      fHistdNdedpV0.SetBinContent(bin, 0, 1);
+    }
+    Float_t amp = aodVZero->GetMultiplicity(i);
+    amp /= eq[i];
+    Double_t phi = TMath::Pi()/8.+TMath::TwoPi()*i/8.;
+    while (phi > TMath::TwoPi()) phi -= TMath::TwoPi();
+    fHistdNdedpV0.Fill(eta, phi, amp);
+  }
 }
 //_____________________________________________________________________
 AliForwardFlowTaskQC::VertexBin::VertexBin()
   : TNamed(),
-    fMoment(0),      // Flow moment for this vertexbin
-    fVzMin(0),       // Vertex z-coordinate min
-    fVzMax(0),       // Vertex z-coordinate max
+    fMaxMoment(0),   // Max flow moment for this vertexbin
+    fVzMin(0),       // Vertex z-coordinate min [cm]
+    fVzMax(0),       // Vertex z-coordinate max [cm]
     fType(),         // Data type name e.g., FMD/SPD/FMDTR/SPDTR/MC
-    fFlags(0),       // Use forward-backward symmetry, if detector allows it
+    fFlags(0),       // Flow flags
     fSigmaCut(-1),   // Sigma cut to remove outlier events
-    fEtaGap(2.),     // Eta gap value
+    fEtaGap(-1),     // Eta gap value
+    fEtaLims(),      // Limits for binning in 3Cor method
     fCumuRef(),      // Histogram for reference flow
     fCumuDiff(),     // Histogram for differential flow
-    fCumuHist(),     // Sum histogram for cumulants
-    fdNdedpAcc(),    // Diagnostics histogram to make acc. maps
+    fCumuHists(0,0), // CumuHists object for keeping track of results
+    fCumuNUARef(),   // Histogram for ref NUA terms
+    fCumuNUADiff(),  // Histogram for diff NUA terms
+    fdNdedpRefAcc(), // Diagnostics histogram for acc. maps
+    fdNdedpDiffAcc(),// Diagnostics histogram for acc. maps
     fOutliers(),     // Histogram for sigma distribution
     fDebug()         // Debug level
 {
   //
-  // Default constructor
+  //  Default constructor
   //
 }
 //_____________________________________________________________________
@@ -596,502 +925,736 @@ AliForwardFlowTaskQC::VertexBin::VertexBin(Int_t vLow, Int_t vHigh,
                                            UShort_t flags, Double_t cut,
                                            Double_t etaGap)
   : TNamed("", ""),
-    fMoment(moment),  // Flow moment for this vertexbin
-    fVzMin(vLow),     // Vertex z-coordinate min
-    fVzMax(vHigh),    // Vertex z-coordinate max
-    fType(name),      // Data type name e.g., FMD/SPD/FMDTR/SPDTR/MC
-    fFlags(flags),    // Use forward-backward symmetry, if detector allows it
-    fSigmaCut(cut),   // Sigma cut to remove outlier events
-    fEtaGap(etaGap),  // Eta gap value
-    fCumuRef(),       // Histogram for reference flow
-    fCumuDiff(),      // Histogram for differential flow
-    fCumuHist(),      // Sum histogram for cumulants
-    fdNdedpAcc(),     // Diagnostics histogram to make acc. maps
-    fOutliers(),      // Histogram for sigma distribution
-    fDebug(0)         // Debug level
+    fMaxMoment(moment),  // Max flow moment for this vertexbin
+    fVzMin(vLow),        // Vertex z-coordinate min [cm]
+    fVzMax(vHigh),       // Vertex z-coordinate max [cm]
+    fType(name),         // Data type name e.g., FMD/SPD/FMDTR/SPDTR/MC
+    fFlags(flags),       // Flow flags 
+    fSigmaCut(cut),      // Sigma cut to remove outlier events
+    fEtaGap(etaGap),     // Eta gap value
+    fEtaLims(),          // Limits for binning in 3Cor method
+    fCumuRef(),          // Histogram for reference flow
+    fCumuDiff(),         // Histogram for differential flow
+    fCumuHists(moment,0),// CumuHists object for keeping track of results
+    fCumuNUARef(),       // Histogram for ref NUA terms
+    fCumuNUADiff(),      // Histogram for diff NUA terms
+    fdNdedpRefAcc(),     // Diagnostics histogram for acc. maps
+    fdNdedpDiffAcc(),    // Diagnostics histogram for acc. maps
+    fOutliers(),         // Histogram for sigma distribution
+    fDebug(0)            // Debug level
 {
   //
-  // Constructor
+  //  Constructor
   //
-  // Parameters
-  //  vLow: min z-coordinate
-  //  vHigh: max z-coordinate
-  //  moment: flow moment
-  //  name: data type name (FMD/SPD/FMDTR/SPDTR/MC)
-  //  sym: data is symmetric in eta
+  //  Parameters
+  //   vLow: min z-coordinate
+  //   vHigh: max z-coordinate
+  //   moment: max flow moment
+  //   name: data type name (FMD/SPD/FMDTR/SPDTR/MC)
+  //   flags: flow flags
+  //   cut: sigma cut
+  //   etaGap: eta-gap value
   //
   fType.ToUpper();
 
-  SetName(Form("%svertexBin%d_%d_%d%s", fType.Data(), moment, vLow, vHigh, ((fFlags & kEtaGap) ? "_etaGap" : "")));
-  SetTitle(Form("%svertexBin%d_%d_%d%s", fType.Data(), moment, vLow, vHigh, ((fFlags & kEtaGap) ? "_etaGap" : "")));
-
+  SetName(Form("%svertexBin%d_%d_%d%s", fType.Data(), moment, vLow, vHigh, GetQCType(fFlags)));
+  SetTitle(Form("%svertexBin%d_%d_%d%s", fType.Data(), moment, vLow, vHigh, GetQCType(fFlags)));
+  
   fDebug = AliAnalysisManager::GetAnalysisManager()->GetDebugLevel();
   if (fDebug > 0) Printf("AliForwardFlowTaskQC::VertexBin()\tDebugMode: %d", fDebug);
+
+  // Set limits for 3 correlator method
+  if ((fFlags & kFMD)) {
+    fEtaLims[0] = -6.;
+    fEtaLims[1] = -1.5;
+    fEtaLims[2] = -0.5;
+    fEtaLims[3] = 2.;
+    fEtaLims[4] = 3.;
+    fEtaLims[5] = 6.;
+  } else if ((fFlags & kVZERO)) {
+    fEtaLims[0] = -6;
+    fEtaLims[1] = -2.7;
+    fEtaLims[2] = -2.0;
+    fEtaLims[3] = 2.0;
+    fEtaLims[4] = 3.9;
+    fEtaLims[5] = 6;
+  }
 }
 //_____________________________________________________________________
 AliForwardFlowTaskQC::VertexBin&
 AliForwardFlowTaskQC::VertexBin::operator=(const AliForwardFlowTaskQC::VertexBin& o)
 {
   //
-  // Assignment operator
+  //  Assignment operator
   //
-  // Parameters
-  //  o: AliForwardFlowTaskQC::VertexBin
+  //  Parameters
+  //   o: AliForwardFlowTaskQC::VertexBin
   //
   if (&o == this) return *this;
-  fType         = o.fType;
-  fCumuRef      = o.fCumuRef;
-  fCumuDiff     = o.fCumuDiff;
-  fCumuHist     = o.fCumuHist;
-  fdNdedpAcc    = o.fdNdedpAcc;
-  fOutliers     = o.fOutliers;
-  fDebug        = o.fDebug;
+  fMaxMoment     = o.fMaxMoment;
+  fVzMin         = o.fVzMin;
+  fVzMax         = o.fVzMax;
+  fType          = o.fType;
+  fFlags         = o.fFlags;
+  fSigmaCut      = o.fSigmaCut;
+  fEtaGap        = o.fEtaGap;
+  fCumuRef       = o.fCumuRef;
+  fCumuDiff      = o.fCumuDiff;
+  fCumuHists     = o.fCumuHists;
+  fCumuNUARef    = o.fCumuNUARef;
+  fCumuNUADiff   = o.fCumuNUADiff;
+  fdNdedpRefAcc  = o.fdNdedpRefAcc;
+  fdNdedpDiffAcc = o.fdNdedpDiffAcc;
+  fOutliers      = o.fOutliers;
+  fDebug         = o.fDebug;
+  for (UInt_t i = 0; i < sizeof(fEtaLims)/sizeof(Int_t); i++) fEtaLims[i] = o.fEtaLims[i];
 
   return *this;
 }
 //_____________________________________________________________________
-void AliForwardFlowTaskQC::VertexBin::AddOutput(TList* outputlist)
+void AliForwardFlowTaskQC::VertexBin::AddOutput(TList* outputlist, TAxis* centAxis)
 {
   //
-  // Add histograms to outputlist
+  //  Add histograms to outputlist
   //
-  // Parameters
-  //  outputlist: list of histograms
+  //  Parameters
+  //   outputlist: list of histograms
+  //   centAxis: centrality axis
   //
 
   // First we try to find an outputlist for this vertexbin
-  TList* list = (TList*)outputlist->FindObject(Form("%svertex_%d_%d%s", fType.Data(), fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")));
-
+  TList* list = (TList*)outputlist->FindObject(Form("%svertex_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)));
   // If it doesn't exist we make one
   if (!list) {
     list = new TList();
-    list->SetName(Form("%svertex_%d_%d%s", fType.Data(), fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")));
+    list->SetName(Form("%svertex_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)));
     outputlist->Add(list);
   }
 
+  // Get bin numbers and binning defined
+  Int_t nHBins = GetBinNumberSin();
+  Int_t nEtaBins = 48; 
+  if ((fFlags & k3Cor)) {
+    if ((fFlags & kFMD)) nEtaBins = 24;
+    else if ((fFlags & kVZERO)) nEtaBins = 19;
+  }
+  else if ((fFlags & kVZERO) && !fType.Contains("SPD")) nEtaBins = 11;
+  Double_t vzeroBins[12] = { -6, -3.7, -3.2, -2.7, -2.2, -1.7, 
+                             2.8, 3.4,  3.9,  4.5,  5.1, 6 };
+  Double_t vzeroBins2[20] = { -6, -3.7, -3.2, -2.7, -2.2, // VZERO
+                             -2.0, -1.5, -1.0, -0.5 , 0., 0.5, 1.0, 1.5, 2.0, // SPD
+                           2.8, 3.4,  3.9,  4.5,  5.1, 6 }; // VZERO
+  
   // We initiate the reference histogram
-  fCumuRef = new TH2D(Form("%s_v%d_%d_%d%s_ref", fType.Data(), fMoment, fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                        Form("%s_v%d_%d_%d%s_ref", fType.Data(), fMoment, fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                        2, -6., 6., 8, 0.5, 8.5);
-  fCumuRef->Sumw2();
-  //list->Add(fCumuRef);
+  fCumuRef = new TH2D(Form("%s_%d_%d%s_ref", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)), 
+                      Form("%s_%d_%d%s_ref", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)), 
+                       ((fFlags & k3Cor) ? 24 : ((fFlags & kEtaGap) || !(fFlags & kSymEta) ? 2 : 1)), -6., 6., 
+                        nHBins, 0.5, nHBins+0.5);
+  if ((fFlags & kVZERO) && (fFlags & k3Cor)) fCumuRef->GetXaxis()->Set(nEtaBins, vzeroBins2);
+  SetupNUALabels(fCumuRef->GetYaxis());
+  list->Add(fCumuRef);
 
   // We initiate the differential histogram
-  fCumuDiff = new TH2D(Form("%s_v%d_%d_%d%s_diff", fType.Data(), fMoment, fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                       Form("%s_v%d_%d_%d%s_diff", fType.Data(), fMoment, fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                       48, -6., 6., 8, 0.5, 8.5);
-  fCumuDiff->Sumw2();
-  //list->Add(fCumuDiff);
-
-  // Initiate the cumulant sum histogram
-  fCumuHist = new TH3D(Form("%sv%d_vertex_%d_%d%s_cumu", fType.Data(), fMoment, fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                       Form("%sv%d_vertex_%d_%d%s_cumu", fType.Data(), fMoment, fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                       48, -6., 6., 20, 0., 100., 29, 0.5, 29.5);
-  fCumuHist->Sumw2();
-  SetupCentAxis(fCumuHist->GetYaxis());
-
-  list->Add(fCumuHist);
-
-  // We check for diagnostics histograms (only done per type and moment, not vertexbin)
-  // If they are not found we create them.
-  TList* dList = (TList*)outputlist->FindObject("Diagnostics");
-  if (!dList) AliFatal("No diagnostics list found, what kind of game are you running here?!?!");
-
-  // Acceptance hists are shared over all moments
-  fdNdedpAcc = (TH2F*)dList->FindObject(Form("h%sdNdedpAcc_%d_%d%s", fType.Data(), fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")));
-  if (!fdNdedpAcc) {
-    fdNdedpAcc = new TH2F(Form("h%sdNdedpAcc_%d_%d%s", fType.Data(), fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")), 
-                          Form("%s acceptance map for %d cm < v_{z} < %d cm", fType.Data(), fVzMin, fVzMax),
-                          48, -6, 6, 20, 0, TMath::TwoPi());
-    fdNdedpAcc->Sumw2();
-    dList->Add(fdNdedpAcc);
+  fCumuDiff = new TH2D(Form("%s_%d_%d%s_diff", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+                       Form("%s_%d_%d%s_diff", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+                       nEtaBins, -6., 6., nHBins, 0.5, nHBins+0.5);
+  if ((fFlags & kVZERO)) {
+    if ((fFlags & k3Cor)) fCumuDiff->GetXaxis()->Set(nEtaBins, vzeroBins2);
+    else if (!fType.Contains("SPD")) fCumuDiff->GetXaxis()->Set(nEtaBins, vzeroBins);
+  }
+  SetupNUALabels(fCumuDiff->GetYaxis());
+  list->Add(fCumuDiff);
+
+  // Cumulants sum hists 
+  Int_t cBins = centAxis->GetNbins();
+  fCumuHists.ConnectList(Form("%sCumu_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)), list);
+  TH3D* cumuHist = 0;
+  Int_t nC2Bins = ((fFlags & kEtaGap) || (fFlags & k3Cor) ? kW2 : k3pWeight);
+  Int_t nC4Bins = ((fFlags & kEtaGap) ? kW2 : ((fFlags & k3Cor) ? kW4 : kSinphi1phi2phi3p));
+  for (Int_t n = 2; n <= fMaxMoment; n++) {
+    // Initiate the ref cumulant sum histogram
+    cumuHist = new TH3D(Form("%sv%d_vertex_%d_%d%s_cumuRef", fType.Data(), n, fVzMin, fVzMax, GetQCType(fFlags)),
+                       Form("%sv%d_vertex_%d_%d%s_cumuRef", fType.Data(), n, fVzMin, fVzMax, GetQCType(fFlags)), 
+                        ((fFlags & k3Cor) ? 24 : ((fFlags & kEtaGap) || !(fFlags & kSymEta) ? 2 : 1)), -6., 6., 
+                       cBins, 0., 100., nC2Bins, 0.5, nC2Bins+0.5);
+    if ((fFlags & kVZERO) && (fFlags & k3Cor)) cumuHist->GetXaxis()->Set(nEtaBins, vzeroBins2);
+    cumuHist->GetYaxis()->Set(cBins, centAxis->GetXbins()->GetArray());
+    fCumuHists.Add(cumuHist);
+    // Initiate the diff cumulant sum histogram
+    cumuHist = new TH3D(Form("%sv%d_vertex_%d_%d%s_cumuDiff", fType.Data(), n, fVzMin, fVzMax, GetQCType(fFlags)),
+                       Form("%sv%d_vertex_%d_%d%s_cumuDiff", fType.Data(), n, fVzMin, fVzMax, GetQCType(fFlags)),
+                       nEtaBins, -6., 6., cBins, 0., 100., nC4Bins, 0.5, nC4Bins+0.5);
+    if ((fFlags & kVZERO)) {
+      if ((fFlags & k3Cor)) cumuHist->GetXaxis()->Set(nEtaBins, vzeroBins2);
+      else if (!fType.Contains("SPD")) cumuHist->GetXaxis()->Set(nEtaBins, vzeroBins);
+    }
+    cumuHist->GetYaxis()->Set(cBins, centAxis->GetXbins()->GetArray());
+    fCumuHists.Add(cumuHist);
   }
 
-  if (!(fFlags & kEtaGap)) {
-    fOutliers = new TH2F(Form("hOutliers_%s_v%d_%d_%d", fType.Data(), fMoment, fVzMin, fVzMax),
-                       Form("Maximum #sigma from mean N_{ch} pr. bin - %s v_{%d}, %d < v_{z} < %d",
-                       fType.Data(), fMoment, fVzMin, fVzMax), 
-                       20, 0., 100., 500, 0., (fType.Contains("MC") ? 15. : 5.));
-    dList->Add(fOutliers);
+  // Common NUA histograms
+  fCumuNUARef = new TH3D(Form("%s_vertex_%d_%d%s_cumuNUARef", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+                        Form("%s_vertex_%d_%d%s_cumuNUARef", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+                        ((fFlags & k3Cor) ? 24 : ((fFlags & kEtaGap) || !(fFlags & kSymEta) ? 2 : 1)), -6., 6., 
+                          cBins, 0., 100., nHBins, 0.5, nHBins+0.5);
+  if ((fFlags & kVZERO) && (fFlags & k3Cor)) fCumuNUARef->GetXaxis()->Set(nEtaBins, vzeroBins2);
+  fCumuNUARef->GetYaxis()->Set(cBins, centAxis->GetXbins()->GetArray());
+  SetupNUALabels(fCumuNUARef->GetZaxis());
+  fCumuNUARef->Sumw2();
+  list->Add(fCumuNUARef);
+  
+  fCumuNUADiff = new TH3D(Form("%s_vertex_%d_%d%s_cumuNUADiff", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+                          Form("%s_vertex_%d_%d%s_cumuNUADiff", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+                          nEtaBins, -6., 6., cBins, 0., 100., nHBins, 0.5, nHBins+0.5);
+  if ((fFlags & kVZERO)) {
+    if ((fFlags & k3Cor)) fCumuNUADiff->GetXaxis()->Set(nEtaBins, vzeroBins2);
+    else if (!fType.Contains("SPD")) fCumuNUADiff->GetXaxis()->Set(nEtaBins, vzeroBins);
   }
+  fCumuNUADiff->GetYaxis()->Set(cBins, centAxis->GetXbins()->GetArray());
+  SetupNUALabels(fCumuNUADiff->GetZaxis());
+  fCumuNUADiff->Sumw2();
+  list->Add(fCumuNUADiff);
 
+  // We create diagnostic histograms.
+  TList* dList = (TList*)outputlist->FindObject("Diagnostics");
+  if (!dList) AliFatal("No diagnostics list found");
+
+  // Acceptance hist
+  Double_t nPhiBins = ((fFlags & kFMD) ? 20 : 8);
+  fdNdedpRefAcc = new TH2F(Form("h%sdNdedpRefAcc_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+    Form("%s reference flow acceptance map for %d cm < v_{z} < %d cm", fType.Data(), fVzMin, fVzMax),
+    nEtaBins, -6, 6, nPhiBins, 0, TMath::TwoPi());
+  if ((fFlags & kVZERO)) {
+    if ((fFlags & k3Cor)) fdNdedpRefAcc->GetXaxis()->Set(nEtaBins, vzeroBins2);
+    else if (!fType.Contains("SPD")) fdNdedpRefAcc->GetXaxis()->Set(nEtaBins, vzeroBins);
+  }
+  dList->Add(fdNdedpRefAcc);
+
+  fdNdedpDiffAcc = new TH2F(Form("h%sdNdedpDiffAcc_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+    Form("%s differential flow acceptance map for %d cm < v_{z} < %d cm", fType.Data(), fVzMin, fVzMax),
+    nEtaBins, -6, 6, nPhiBins, 0, TMath::TwoPi());
+  if ((fFlags & kVZERO)) {
+    if ((fFlags & k3Cor)) fdNdedpDiffAcc->GetXaxis()->Set(nEtaBins, vzeroBins2);
+    else if (!fType.Contains("SPD")) fdNdedpDiffAcc->GetXaxis()->Set(nEtaBins, vzeroBins);
+  }
+  dList->Add(fdNdedpDiffAcc);
+  
+  fOutliers = new TH2F(Form("hOutliers_%s_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)),
+                      Form("Maximum #sigma from mean N_{ch} pr. bin - %s, %d < v_{z} < %d",
+                      fType.Data(), fVzMin, fVzMax), 
+                      20, 0., 100., 500, 0., (fType.Contains("MC") ? 15. : 5.));
+  dList->Add(fOutliers);
+  
+  return;
 }
 //_____________________________________________________________________
-Bool_t AliForwardFlowTaskQC::VertexBin::FillHists(const TH2D& dNdetadphi, Double_t cent, EFillFlow mode) 
+Bool_t AliForwardFlowTaskQC::VertexBin::FillHists(TH2D& dNdetadphi, Double_t cent, UShort_t mode) 
 {
   // 
-  // Fill reference and differential eta-histograms
+  //  Fill reference and differential eta-histograms
   //
-  // Parameters:
-  //  dNdetadphi: 2D histogram with input data
+  //  Parameters:
+  //   dNdetadphi: 2D histogram with input data
+  //   cent: centrality
+  //   mode: filling mode: kFillRef/kFillDiff/kFillBoth
   //
-
   if (!fCumuRef) AliFatal("You have not called AddOutput() - Terminating!");
-
   Bool_t useEvent = kTRUE;
 
   // Fist we reset histograms
-  if ((mode & kFillRef)) fCumuRef->Reset();
-  fCumuDiff->Reset();
-
-  // Numbers to cut away bad events and acceptance.
-  Double_t runAvg = 0;
-  Double_t max = 0;
-  Int_t nInAvg = 0;
-  Double_t avgSqr = 0;
-  Int_t nBins = (dNdetadphi.GetNbinsX() * 6) / (fCumuDiff->GetNbinsX() * 5);
-  Int_t nInBin = 0;
-  Int_t nCurBin = 0, nPrevBin = 0;
-  Int_t nCurRefBin = 0, nPrevRefBin = 0;
-  Int_t nBadBins = 0;
-  Bool_t firstBin = kFALSE;
-  Double_t limit = 9999.;
-  Bool_t mc = fType.Contains("MC");
+  if ((mode & kReset)) {
+    if ((mode & kFillRef))  fCumuRef->Reset();
+    if ((mode & kFillDiff)) fCumuDiff->Reset();
+  }
 
   // Then we loop over the input and calculate sum cos(k*n*phi)
   // and fill it in the reference and differential histograms
-  Double_t eta, phi, weight;
-  Double_t dQnRe = 0, dQ2nRe = 0, dQnIm = 0, dQ2nIm = 0;
-
+  Int_t nBadBins = 0;
+  Double_t limit = 9999.;
   for (Int_t etaBin = 1; etaBin <= dNdetadphi.GetNbinsX(); etaBin++) {
-    eta = dNdetadphi.GetXaxis()->GetBinCenter(etaBin);
-    nCurBin = fCumuDiff->GetXaxis()->FindBin(eta);
-    nCurRefBin = fCumuRef->GetXaxis()->FindBin(eta);
-    // If we have moved to a new bin in the flow hist, and less than half the eta
-    // region has been covered by it we cut it away.
-    if (nPrevBin == 0) nPrevBin = nCurBin;
-    if (nPrevRefBin == 0) nPrevRefBin = nCurRefBin;
-    if (nCurBin != nPrevBin) {
-      if (nInBin <= nBins/2) {
-       for (Int_t qBin = 1; qBin <= fCumuDiff->GetNbinsY(); qBin++) {
-         Double_t removeContent = fCumuDiff->GetBinContent(nPrevBin, qBin);
-         Double_t removeEta = fCumuDiff->GetXaxis()->GetBinCenter(nPrevBin);
-         if (nCurRefBin != nPrevRefBin) {
-           if (!(fFlags & kEtaGap)) {
-             fCumuRef->Fill(removeEta, qBin, -removeContent);
-             if ((fFlags & kSymEta)) {
-               fCumuRef->Fill(-1.*removeEta, qBin, -removeContent);
-             }
-           }
-           if ((fFlags & kEtaGap)) {
-             switch(qBin) {
-               case kHmultA: fCumuRef->Fill(removeEta, qBin, removeContent);  break;
-               case kHQnReA: fCumuRef->Fill(removeEta, qBin, removeContent);  break;
-               case kHQnImA: fCumuRef->Fill(removeEta, qBin, removeContent);  break;
-               case kHmultB: fCumuRef->Fill(-removeEta, qBin, removeContent); break;
-               case kHQnReB: fCumuRef->Fill(-removeEta, qBin, removeContent); break;
-               case kHQnImB: fCumuRef->Fill(-removeEta, qBin, removeContent); break;
-               default: break;
-             }
-           }
-         }
-         fCumuDiff->SetBinContent(nPrevBin, qBin, 0);
-         fCumuDiff->SetBinError(nPrevBin, qBin, 0);
-       }
-      }
-      nInBin = 0;
-      nPrevBin = nCurBin;
-      if (nCurRefBin != nPrevRefBin) nPrevRefBin = nCurRefBin;
-    }
-    
-    Bool_t data = kFALSE;
+    Double_t eta = dNdetadphi.GetXaxis()->GetBinCenter(etaBin);
+    // Numbers to cut away bad events
+    Double_t runAvg = 0;
+    Double_t max = 0;
+    Int_t nInAvg = 0;
+    Double_t avgSqr = 0;
     for (Int_t phiBin = 0; phiBin <= dNdetadphi.GetNbinsY(); phiBin++) {
+      // Check for acceptance
       if (phiBin == 0) {
-       if (dNdetadphi.GetBinContent(etaBin, phiBin) == 0) break;
-       else data = kTRUE;
-       if ((fFlags & kEtaGap) && (mode & kFillRef) && TMath::Abs(eta) < fEtaGap) break;
+        if (dNdetadphi.GetBinContent(etaBin, 0) == 0) break;
+        // Central limit for eta gap break for reference flow
+       if ((fFlags & kEtaGap) && (mode & kFillRef) && 
+            TMath::Abs(eta) < fEtaGap) break;
+       // Backward and forward eta gap break for reference flow
        if ((fFlags & kEtaGap) && (mode & kFillRef) && TMath::Abs(eta) > TMath::Abs(limit)) break;
-       if (data && !firstBin) {
-         limit = dNdetadphi.GetXaxis()->GetBinLowEdge(etaBin);
-         firstBin = kTRUE;
-       }
+       if (limit > 1e3) limit = dNdetadphi.GetXaxis()->GetBinLowEdge(etaBin);
        continue;
-      }
-      phi = dNdetadphi.GetYaxis()->GetBinCenter(phiBin);
-      if ((fFlags & kEtaGap) && !mc && (phiBin == 7 || phiBin == 14 || phiBin == 15 || phiBin == 20)) continue;
-      weight = dNdetadphi.GetBinContent(etaBin, phiBin);
-
+      } // End of phiBin == 0
+      Double_t phi = dNdetadphi.GetYaxis()->GetBinCenter(phiBin);
+      Double_t weight = dNdetadphi.GetBinContent(etaBin, phiBin);
+        
       // We calculate the average Nch per. bin
       avgSqr += weight*weight;
       runAvg += weight;
       nInAvg++;
       if (weight == 0) continue;
       if (weight > max) max = weight;
-
-      dQnRe = weight*TMath::Cos(fMoment*phi);
-      dQnIm = weight*TMath::Sin(fMoment*phi);
-      dQ2nRe = weight*TMath::Cos(2.*fMoment*phi);
-      dQ2nIm = weight*TMath::Sin(2.*fMoment*phi);
-
-      // if we do not have an eta gap we fill the ref sums in eta
-      if (!(fFlags & kEtaGap)) {
-       if ((mode & kFillRef)){
-         fCumuRef->Fill(eta, kHmultA, weight);
-         fCumuRef->Fill(eta, kHQnReA, dQnRe);
-         fCumuRef->Fill(eta, kHQnImA, dQnIm);
-         fCumuRef->Fill(eta, kHmultB, weight);
-         fCumuRef->Fill(eta, kHQnReB, dQnRe);
-         fCumuRef->Fill(eta, kHQnImB, dQnIm);
-         
-         fCumuRef->Fill(eta, kHQ2nRe, dQ2nRe);
-         fCumuRef->Fill(eta, kHQ2nIm, dQ2nIm);
-       }
+      
+      // Fill into Cos() and Sin() hists
+      if ((mode & kFillRef)) {
+       fCumuRef->Fill(eta, 0., weight);// mult goes in underflowbin - no visual, but not needed?
+        fdNdedpRefAcc->Fill(eta, phi, weight);
       }
-      // if we have an eta gap or we symmetrize around eta = 0
-      // we fill in -eta
-      if ((fFlags & kEtaGap)){
-       if ((mode & kFillRef)){
-         fCumuRef->Fill(eta, kHmultA, weight);
-         fCumuRef->Fill(eta, kHQnReA, dQnRe);
-         fCumuRef->Fill(eta, kHQnImA, dQnIm);
-         
-         fCumuRef->Fill(-eta, kHmultB, weight);
-         fCumuRef->Fill(-eta, kHQnReB, dQnRe);
-         fCumuRef->Fill(-eta, kHQnImB, dQnIm);
-       }
+      if ((mode & kFillDiff)) {
+       fCumuDiff->Fill(eta, 0., weight);
+        fdNdedpDiffAcc->Fill(eta, phi, weight);
       }
-      
-      if ((fFlags & kSymEta)){
-       if ((mode & kFillRef)){
-         fCumuRef->Fill(-eta, kHmultA, weight);
-         fCumuRef->Fill(-eta, kHQnReA, dQnRe);
-         fCumuRef->Fill(-eta, kHQnImA, dQnIm);
-         fCumuRef->Fill(-eta, kHmultB, weight);
-         fCumuRef->Fill(-eta, kHQnReB, dQnRe);
-         fCumuRef->Fill(-eta, kHQnImB, dQnIm);
-         
-         fCumuRef->Fill(-eta, kHQ2nRe, dQ2nRe);
-         fCumuRef->Fill(-eta, kHQ2nIm, dQ2nIm);
+      for (Int_t n = 1; n <= 2*fMaxMoment; n++) {
+       Double_t cosBin = fCumuDiff->GetYaxis()->GetBinCenter(GetBinNumberCos(n));
+       Double_t sinBin = fCumuDiff->GetYaxis()->GetBinCenter(GetBinNumberSin(n));
+       Double_t cosnPhi = weight*TMath::Cos(n*phi);
+       Double_t sinnPhi = weight*TMath::Sin(n*phi);
+        // fill ref
+       if ((mode & kFillRef)) {
+         fCumuRef->Fill(eta, cosBin, cosnPhi);
+         fCumuRef->Fill(eta, sinBin, sinnPhi);
        }
-      }
-
-      // If we fill diff flow, we always fill it in eta
-      // This is filled always, to be able to remove edge effects
-      // It is reset both for kFillRef and kFillDiff to make the eta
-      // gap analysis work.
-      fCumuDiff->Fill(eta, kHmultA, weight);
-      fCumuDiff->Fill(eta, kHQnReA, dQnRe);
-      fCumuDiff->Fill(eta, kHQnImA, dQnIm);
-      fCumuDiff->Fill(eta, kHQ2nRe, dQ2nRe);
-      fCumuDiff->Fill(eta, kHQ2nIm, dQ2nIm);
-
-      // Fill acc. map
-      if ((mode & kFillDiff)) fdNdedpAcc->Fill(eta, phi, weight);
-    }
-    if (data) {
-      nInBin++;
-    }
+       // fill diff
+       if ((mode & kFillDiff)) {
+         fCumuDiff->Fill(eta, cosBin, cosnPhi);
+         fCumuDiff->Fill(eta, sinBin, sinnPhi);
+       }
+      } // End of NUA loop
+    } // End of phi loop
     // Outlier cut calculations
-    if (nInAvg > 3 && !(fFlags & kEtaGap)) {
+    if (nInAvg > 0) {
       runAvg /= nInAvg;
       avgSqr /= nInAvg;
-      Double_t stdev = TMath::Sqrt(nInAvg/(nInAvg-1))*TMath::Sqrt(avgSqr - runAvg*runAvg);
+      Double_t stdev = (nInAvg > 1 ? TMath::Sqrt(nInAvg/(nInAvg-1))*TMath::Sqrt(avgSqr - runAvg*runAvg) : 0);
       Double_t nSigma = (stdev == 0 ? 0 : (max-runAvg)/stdev);
-      if (fSigmaCut > 0. && nSigma >= fSigmaCut && cent <= 60) nBadBins++;
+      if (fSigmaCut > 0. && nSigma >= fSigmaCut && cent < 60) nBadBins++;
       else nBadBins = 0;
       fOutliers->Fill(cent, nSigma);
       // We still finish the loop, for fOutliers to make sense, 
-      // but we do no keep the event for analysis
+      // but we do no keep the event for analysis 
       if (nBadBins > 3) useEvent = kFALSE;
     }
-    runAvg = 0;
-    avgSqr = 0;
-    nInAvg = 0;
-    max = 0;
-  }
+  } // End of eta bin
 
   return useEvent;
 }
 //_____________________________________________________________________
-void AliForwardFlowTaskQC::VertexBin::CumulantsAccumulate(Double_t cent, Bool_t skipFourP) 
+Bool_t AliForwardFlowTaskQC::VertexBin::FillTracks(TObjArray* trList, UShort_t mode) 
 {
   // 
-  // Calculate the Q cumulant of order fMoment
+  //  Fill reference and differential eta-histograms
   //
-  // Parameters:
-  //  cent: Centrality of event
+  //  Parameters:
+  //   trList: list of tracks
+  //   mode: filling mode: kFillRef/kFillDiff/kFillBoth
   //
-
   if (!fCumuRef) AliFatal("You have not called AddOutput() - Terminating!");
 
-  // We create the objects needed for the analysis
-  Double_t dQnReA = 0, dQnImA = 0, multA; 
-  Double_t dQnReB = 0, dQnImB = 0, multB;
-  Double_t dQ2nRe = 0, dQ2nIm = 0;
-  Double_t pnRe = 0, p2nRe = 0, qnRe = 0, q2nRe = 0, pnIm = 0, p2nIm = 0, qnIm = 0, q2nIm = 0;
-  Double_t two = 0, four = 0, twoPrime = 0, fourPrime = 0;
-  Double_t cosPhi1Phi2 = 0, cosPhi1Phi2Phi3m = 0;
-  Double_t sinPhi1Phi2 = 0, sinPhi1Phi2Phi3m = 0;
-  Double_t cosPsi1Phi2 = 0, cosPsi1Phi2Phi3m = 0, cosPsi1Phi2Phi3p = 0;
-  Double_t sinPsi1Phi2 = 0, sinPsi1Phi2Phi3m = 0, sinPsi1Phi2Phi3p = 0;
-  Double_t eta = 0;
-  Double_t mp = 0, mq = 0;
-  Double_t w2 = 0, w4 = 0, w2p = 0, w4p = 0;
-  Int_t refEtaBin = 0;
+  // Fist we reset histograms
+  if ((mode & kReset)) {
+    if ((mode & kFillRef))  fCumuRef->Reset();
+    if ((mode & kFillDiff)) fCumuDiff->Reset();
+  }
 
-  // We loop over the data 1 time!
-  for (Int_t etaBin = 1; etaBin <= fCumuDiff->GetNbinsX(); etaBin++) {
-    eta = fCumuDiff->GetXaxis()->GetBinCenter(etaBin);
-    refEtaBin = fCumuRef->GetXaxis()->FindBin(eta);
-    // The values for each individual etaBin bins are reset
-    multA = 0;
-    multB = 0;
-    dQnReA = 0;
-    dQnImA = 0;
-    dQnReB = 0;
-    dQnImB = 0;
-    dQ2nRe = 0;
-    dQ2nIm = 0;
-    
-    mp = 0;
-    pnRe = 0;
-    pnIm = 0;
-    p2nRe = 0;
-    p2nIm = 0;
-
-    mq = 0;
-    qnRe = 0;
-    qnIm = 0;
-    q2nRe = 0;
-    q2nIm = 0;
-
-    // Reference flow
-    multA  = fCumuRef->GetBinContent(refEtaBin, kHmultA);
-    multB  = fCumuRef->GetBinContent(refEtaBin, kHmultB);
-    dQnReA = fCumuRef->GetBinContent(refEtaBin, kHQnReA);
-    dQnImA = fCumuRef->GetBinContent(refEtaBin, kHQnImA);
-    dQnReB = fCumuRef->GetBinContent(refEtaBin, kHQnReB);
-    dQnImB = fCumuRef->GetBinContent(refEtaBin, kHQnImB);
-    dQ2nRe = fCumuRef->GetBinContent(refEtaBin, kHQ2nRe);
-    dQ2nIm = fCumuRef->GetBinContent(refEtaBin, kHQ2nIm);
-    
-    // For each etaBin bin the necessary values for differential flow
-    // is calculated. .
-    mp = fCumuDiff->GetBinContent(etaBin, kHmultA);
-    pnRe = fCumuDiff->GetBinContent(etaBin, kHQnReA);
-    pnIm = fCumuDiff->GetBinContent(etaBin, kHQnImA);
-    p2nRe = fCumuDiff->GetBinContent(etaBin, kHQ2nRe);
-    p2nIm = fCumuDiff->GetBinContent(etaBin, kHQ2nIm);
-    
-    if (multA <= 3) continue; 
-    if (mp == 0) continue; 
-    
-    // The reference flow is calculated 
-    // 2-particle
-    if (!(fFlags & kEtaGap)) {
-      w2 = multA * (multA - 1.);
-      two = dQnReA*dQnReA + dQnImA*dQnImA - multA;
-    } else {
-      w2 = multA * multB;
-      two = dQnReA*dQnReB + dQnImA*dQnImB;
+  UShort_t input = AliForwardUtil::CheckForAOD();
+  // Then we loop over the input and calculate sum cos(k*n*phi)
+  // and fill it in the reference and differential histograms
+  Int_t nTr = trList->GetEntries();
+  if (nTr == 0) return kFALSE;
+  AliVTrack* tr = 0;
+  AliAODTrack* aodTr = 0;
+  // Cuts for AOD tracks (have already been applied to ESD tracks)
+  const Double_t pTMin = 0.5, pTMax = 20., etaMin = -0.8, etaMax = 0.8, minNCl = 50;
+  for (Int_t i = 0; i < nTr; i++) { // track loop
+    tr = (AliVTrack*)trList->At(i);
+    if (!tr) continue;
+    if (input == 1) { // If AOD input
+      // A dynamic cast would be more safe here, but this is faster...
+      aodTr = (AliAODTrack*)tr;
+      if (aodTr->GetID() > -1) continue;
+      if (!aodTr->TestFilterBit(128) || !aodTr->Pt() > pTMax || aodTr->Pt() < pTMin || 
+       aodTr->Eta() > etaMax || aodTr->Eta() < etaMin || aodTr->GetTPCNcls() < minNCl) continue;
     }
-    
-    fCumuHist->Fill(eta, cent, kW2Two, two);
-    fCumuHist->Fill(eta, cent, kW2, w2);
-
-    fCumuHist->Fill(eta, cent, kQnReA, dQnReA);
-    fCumuHist->Fill(eta, cent, kQnImA, dQnImA);
-    fCumuHist->Fill(eta, cent, kMA, multA);
-    
-    fCumuHist->Fill(eta, cent, kQnReB, dQnReB);
-    fCumuHist->Fill(eta, cent, kQnImB, dQnImB);
-    fCumuHist->Fill(eta, cent, kMB, multB);
-
-    // Differential flow calculations for each eta bin is done:
-    // 2-particle differential flow
-    if (!(fFlags & kEtaGap)) {
-      mq = mp;
-      qnRe = pnRe;
-      qnIm = pnIm;
-      q2nRe = p2nRe;
-      q2nIm = p2nIm;
+    // Track accepted
+    Double_t eta = tr->Eta();
+    Double_t phi = tr->Phi();
+    if ((mode & kFillRef)) {
+      fCumuRef->Fill(eta, 0.);// mult goes in underflowbin - no visual, but not needed?
+      fdNdedpRefAcc->Fill(eta, phi);
     }
+    if ((mode & kFillDiff)) {
+      fCumuDiff->Fill(eta, 0);
+      fdNdedpDiffAcc->Fill(eta, phi);
+    }
+    for (Int_t n = 1; n <= 2*fMaxMoment; n++) {
+      Double_t cosBin = fCumuDiff->GetYaxis()->GetBinCenter(GetBinNumberCos(n));
+      Double_t sinBin = fCumuDiff->GetYaxis()->GetBinCenter(GetBinNumberSin(n));
+      Double_t cosnPhi = TMath::Cos(n*phi);
+      Double_t sinnPhi = TMath::Sin(n*phi);
+      // fill ref
+      if ((mode & kFillRef)) {
+       fCumuRef->Fill(eta, cosBin, cosnPhi);
+       fCumuRef->Fill(eta, sinBin, sinnPhi);
+      }
+      // fill diff
+      if ((mode & kFillDiff)) {
+       fCumuDiff->Fill(eta, cosBin, cosnPhi);
+       fCumuDiff->Fill(eta, sinBin, sinnPhi);
+      }
+    } // End of NUA loop
+  } // End of track loop
+  return kTRUE;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::CumulantsAccumulate(Double_t cent) 
+{
+  // 
+  //  Calculate the Q cumulant up to order fMaxMoment
+  //
+  //  Parameters:
+  //   cent: centrality of event
+  //
+  if (!fCumuRef) AliFatal("You have not called AddOutput() - Terminating!");
 
-    w2p = mp * multB - mq;
-    twoPrime = pnRe*dQnReB + pnIm*dQnImB - mq;
-    
-    fCumuHist->Fill(eta, cent, kw2two, twoPrime);
-    fCumuHist->Fill(eta, cent, kw2, w2p);
-
-    fCumuHist->Fill(eta, cent, kpnRe, pnRe);
-    fCumuHist->Fill(eta, cent, kpnIm, pnIm);
-    fCumuHist->Fill(eta, cent, kmp, mp);
-
-    if ((fFlags & kEtaGap) || skipFourP) continue;
-    // The reference flow is calculated 
-    // 4-particle
-    w4 = multA * (multA - 1.) * (multA - 2.) * (multA - 3.);
-  
-    four = 2.*multA*(multA-3.) + TMath::Power((TMath::Power(dQnReA,2.)+TMath::Power(dQnImA,2.)),2.)
-             -4.*(multA-2.)*(TMath::Power(dQnReA,2.) + TMath::Power(dQnImA,2.))
-             -2.*(TMath::Power(dQnReA,2.)*dQ2nRe+2.*dQnReA*dQnImA*dQ2nIm-TMath::Power(dQnImA,2.)*dQ2nRe)
-             +(TMath::Power(dQ2nRe,2.)+TMath::Power(dQ2nIm,2.));
+  // Fill out NUA hists
+  for (Int_t etaBin = 1; etaBin <= fCumuRef->GetNbinsX(); etaBin++) {
+    Double_t eta = fCumuRef->GetXaxis()->GetBinCenter(etaBin);
+    if (fCumuRef->GetBinContent(etaBin, 0) == 0) continue;
+    for (Int_t qBin = 0; qBin <= fCumuRef->GetNbinsY(); qBin++) {
+      fCumuNUARef->Fill(eta, cent, Double_t(qBin), fCumuRef->GetBinContent(etaBin, qBin));
+    }
+  }
+  for (Int_t etaBin = 1; etaBin <= fCumuDiff->GetNbinsX(); etaBin++) {
+    Double_t eta = fCumuDiff->GetXaxis()->GetBinCenter(etaBin);
+    if (fCumuDiff->GetBinContent(etaBin, 0) == 0) continue;
+    for (Int_t qBin = 0; qBin <= fCumuDiff->GetNbinsY(); qBin++) {
+      fCumuNUADiff->Fill(eta, cent, Double_t(qBin), fCumuDiff->GetBinContent(etaBin, qBin));
+    }
+  }
 
-    fCumuHist->Fill(eta, cent, kW4Four, four);
-    fCumuHist->Fill(eta, cent, kW4, w4);
+  // We create the objects needed for the analysis
+  TH3D* cumuRef = 0; 
+  TH3D* cumuDiff = 0; 
+  // For each n we loop over the hists
+  for (Int_t n = 2; n <= fMaxMoment; n++) {
+    cumuRef  = (TH3D*)fCumuHists.Get('r',n);
+    cumuDiff = (TH3D*)fCumuHists.Get('d',n);
+    Int_t prevRefEtaBin = 0;
+
+    // Per mom. quantities
+    Double_t dQnReA = 0, dQnImA = 0, multA = 0; 
+    Double_t dQnReB = 0, dQnImB = 0, multB = 0;
+    Double_t dQ2nReA = 0, dQ2nImA = 0;
+    Double_t two = 0, w2 = 0, four = 0, w4 = 0;
+    Double_t cosPhi1Phi2 = 0, cosPhi1Phi2Phi3m = 0;
+    Double_t sinPhi1Phi2 = 0, sinPhi1Phi2Phi3m = 0;
+    for (Int_t etaBin = 1; etaBin <= fCumuDiff->GetNbinsX(); etaBin++) {
+      Double_t eta = fCumuDiff->GetXaxis()->GetBinCenter(etaBin);
+      Int_t refEtaBinA = fCumuRef->GetXaxis()->FindBin(eta);
+      Int_t refEtaBinB = fCumuRef->GetXaxis()->FindBin(-eta);
+      if (refEtaBinA != prevRefEtaBin) {
+       prevRefEtaBin = refEtaBinA;
+       // Reference flow
+       multA  = fCumuRef->GetBinContent(refEtaBinA, 0);
+       dQnReA = fCumuRef->GetBinContent(refEtaBinA, GetBinNumberCos(n));
+       dQnImA = fCumuRef->GetBinContent(refEtaBinA, GetBinNumberSin(n));
+       dQ2nReA = fCumuRef->GetBinContent(refEtaBinA, GetBinNumberCos(n*2));
+       dQ2nImA = fCumuRef->GetBinContent(refEtaBinA, GetBinNumberSin(n*2));
+       
+       multB  = fCumuRef->GetBinContent(refEtaBinB, 0);
+       dQnReB = fCumuRef->GetBinContent(refEtaBinB, GetBinNumberCos(n));
+       dQnImB = fCumuRef->GetBinContent(refEtaBinB, GetBinNumberSin(n));
+
+       if (multA <= 3 || multB <= 3) return; 
+       // The reference flow is calculated 
+       // 2-particle
+       if ((fFlags & kStdQC) && !(fFlags & kTPC)) {
+         w2 = multA * (multA - 1.);
+         two = dQnReA*dQnReA + dQnImA*dQnImA - multA;
+       } else {
+         w2 = multA * multB;
+         two = dQnReA*dQnReB + dQnImA*dQnImB;
+       }
+       cumuRef->Fill(eta, cent, kW2Two, two);
+       cumuRef->Fill(eta, cent, kW2, w2);
+
+       // The reference flow is calculated 
+       // 4-particle
+       if ((fFlags & kStdQC)) {
+         w4 = multA * (multA - 1.) * (multA - 2.) * (multA - 3.);
+       
+         four = 2.*multA*(multA-3.) + TMath::Power((TMath::Power(dQnReA,2.)+TMath::Power(dQnImA,2.)),2.)
+                  -4.*(multA-2.)*(TMath::Power(dQnReA,2.) + TMath::Power(dQnImA,2.))
+                  -2.*(TMath::Power(dQnReA,2.)*dQ2nReA+2.*dQnReA*dQnImA*dQ2nImA-TMath::Power(dQnImA,2.)*dQ2nReA)
+                  +(TMath::Power(dQ2nReA,2.)+TMath::Power(dQ2nImA,2.));
+
+         cumuRef->Fill(eta, cent, kW4Four, four);
+         cumuRef->Fill(eta, cent, kW4, w4);
+
+         // NUA
+         cosPhi1Phi2 = dQnReA*dQnReA - dQnImA*dQnImA - dQ2nReA;
+         sinPhi1Phi2 = 2.*dQnReA*dQnImA - dQ2nImA;
+
+         cosPhi1Phi2Phi3m = dQnReA*(TMath::Power(dQnReA,2)+TMath::Power(dQnImA,2))
+                             -dQnReA*dQ2nReA-dQnImA*dQ2nImA-2.*(multA-1)*dQnReA;
+
+         sinPhi1Phi2Phi3m = -dQnImA*(TMath::Power(dQnReA,2)+TMath::Power(dQnImA,2))
+                             +dQnReA*dQ2nImA-dQnImA*dQ2nReA+2.*(multA-1)*dQnImA; 
+
+         cumuRef->Fill(eta, cent, kCosphi1phi2, cosPhi1Phi2);
+         cumuRef->Fill(eta, cent, kSinphi1phi2, sinPhi1Phi2);
+         cumuRef->Fill(eta, cent, kCosphi1phi2phi3m, cosPhi1Phi2Phi3m);
+         cumuRef->Fill(eta, cent, kSinphi1phi2phi3m, sinPhi1Phi2Phi3m);
+         cumuRef->Fill(eta, cent, k3pWeight, multA*(multA-1.)*(multA-2.));
+       } // End of QC{4}
+      } // End of reference flow
+      // For each etaBin bin the necessary values for differential flow is calculated
+      Double_t mp = fCumuDiff->GetBinContent(etaBin, 0);
+      Double_t pnRe = fCumuDiff->GetBinContent(etaBin, GetBinNumberCos(n));
+      Double_t pnIm = fCumuDiff->GetBinContent(etaBin, GetBinNumberSin(n));
+      Double_t p2nRe = fCumuDiff->GetBinContent(etaBin, GetBinNumberCos(n*2));
+      Double_t p2nIm = fCumuDiff->GetBinContent(etaBin, GetBinNumberSin(n*2));
+      if (mp == 0) continue;
+      Double_t mq = 0;
+      Double_t qnRe = 0;
+      Double_t qnIm = 0;
+      Double_t q2nRe = 0;
+      Double_t q2nIm = 0;
+
+      // Differential flow calculations for each eta bin is done:
+      // 2-particle differential flow
+      if (!(fFlags & kEtaGap)) {
+       mq = mp;
+       qnRe = pnRe;
+       qnIm = pnIm;
+       q2nRe = p2nRe;
+       q2nIm = p2nIm;
+      }
 
-    cosPhi1Phi2 = dQnReA*dQnReA - dQnImA*dQnImA - dQ2nRe;
-    sinPhi1Phi2 = 2.*dQnReA*dQnImA - dQ2nIm;
+      Double_t w2p = mp * multB - mq;
+      Double_t twoPrime = pnRe*dQnReB + pnIm*dQnImB - mq;
       
-    cosPhi1Phi2Phi3m = dQnReA*(TMath::Power(dQnReA,2)+TMath::Power(dQnImA,2))-dQnReA*dQ2nRe-dQnImA*dQ2nIm-2.*(multA-1)*dQnReA;
-
-    sinPhi1Phi2Phi3m = -dQnImA*(TMath::Power(dQnReA,2)+TMath::Power(dQnImA,2))+dQnReA*dQ2nIm-dQnImA*dQ2nRe+2.*(multA-1)*dQnImA; 
-
-    fCumuHist->Fill(eta, cent, kCosphi1phi2, cosPhi1Phi2);
-    fCumuHist->Fill(eta, cent, kSinphi1phi2, sinPhi1Phi2);
-    fCumuHist->Fill(eta, cent, kCosphi1phi2phi3m, cosPhi1Phi2Phi3m);
-    fCumuHist->Fill(eta, cent, kSinphi1phi2phi3m, sinPhi1Phi2Phi3m);
-    fCumuHist->Fill(eta, cent, kMm1m2, multA*(multA-1.)*(multA-2.));
-
-    // Differential flow calculations for each eta bin bin is done:
-    // 4-particle differential flow
-    w4p = (mp * multA - 3.*mq)*(multA - 1.)*(multA - 2.);
-    fourPrime = (TMath::Power(dQnReA,2.)+TMath::Power(dQnImA,2.))*(pnRe*dQnReA+pnIm*dQnImA)
-                      - q2nRe*(TMath::Power(dQnReA,2.)-TMath::Power(dQnImA,2.))
-                      - 2.*q2nIm*dQnReA*dQnImA
-                      - pnRe*(dQnReA*dQ2nRe+dQnImA*dQ2nIm)
-                      + pnIm*(dQnImA*dQ2nRe-dQnReA*dQ2nIm)
-                      - 2.*multA*(pnRe*dQnReA+pnIm*dQnImA)
-                      - 2.*(TMath::Power(dQnReA,2.)+TMath::Power(dQnImA,2.))*mq                      
-                      + 6.*(qnRe*dQnReA+qnIm*dQnImA)                                            
-                      + 1.*(q2nRe*dQ2nRe+q2nIm*dQ2nIm)                      
-                      + 2.*(pnRe*dQnReA+pnIm*dQnImA)                       
-                      + 2.*mq*multA                      
-                      - 6.*mq; 
-
-    fCumuHist->Fill(eta, cent, kw4four, fourPrime);
-    fCumuHist->Fill(eta, cent, kw4, w4p);
-
-    cosPsi1Phi2 = pnRe*dQnReA - pnIm*dQnImA - q2nRe;
-    sinPsi1Phi2 = pnRe*dQnImA + pnIm*dQnReA - q2nIm;
-
-    cosPsi1Phi2Phi3p = pnRe*(TMath::Power(dQnImA,2.)+TMath::Power(dQnReA,2.)-multA)
-                          - 1.*(q2nRe*dQnReA+q2nIm*dQnImA)  
-                          - mq*dQnReA+2.*qnRe;
-    sinPsi1Phi2Phi3p = pnIm*(TMath::Power(dQnImA,2.)+TMath::Power(dQnReA,2.)-multA)
-                          - 1.*(q2nIm*dQnReA-q2nRe*dQnImA)  
-                          - mq*dQnImA+2.*qnIm; 
+      cumuDiff->Fill(eta, cent, kW2Two, twoPrime);
+      cumuDiff->Fill(eta, cent, kW2, w2p);
 
-    cosPsi1Phi2Phi3m = pnRe*(TMath::Power(dQnReA,2.)-TMath::Power(dQnImA,2.))+2.*pnIm*dQnReA*dQnImA
-                          - 1.*(pnRe*dQ2nRe+pnIm*dQ2nIm)  
-                          - 2.*mq*dQnReA+2.*qnRe;
-    sinPsi1Phi2Phi3m = pnIm*(TMath::Power(dQnReA,2.)-TMath::Power(dQnImA,2.))-2.*pnRe*dQnReA*dQnImA
-                          - 1.*(pnIm*dQ2nRe-pnRe*dQ2nIm)
-                          + 2.*mq*dQnImA-2.*qnIm;
+      if ((fFlags & kEtaGap)) continue;
+      // Differential flow calculations for each eta bin bin is done:
+      // 4-particle differential flow
+      Double_t w4p = (mp * multA - 3.*mq)*(multA - 1.)*(multA - 2.);
+   
+      Double_t fourPrime = (TMath::Power(dQnReA,2.)+TMath::Power(dQnImA,2.))*(pnRe*dQnReA+pnIm*dQnImA)
+                         - q2nRe*(TMath::Power(dQnReA,2.)-TMath::Power(dQnImA,2.))
+                         - 2.*q2nIm*dQnReA*dQnImA
+                         - pnRe*(dQnReA*dQ2nReA+dQnImA*dQ2nImA)
+                         + pnIm*(dQnImA*dQ2nReA-dQnReA*dQ2nImA)
+                         - 2.*multA*(pnRe*dQnReA+pnIm*dQnImA)
+                         - 2.*(TMath::Power(dQnReA,2.)+TMath::Power(dQnImA,2.))*mq 
+                         + 6.*(qnRe*dQnReA+qnIm*dQnImA)
+                         + 1.*(q2nRe*dQ2nReA+q2nIm*dQ2nImA)
+                         + 2.*(pnRe*dQnReA+pnIm*dQnImA) 
+                         + 2.*mq*multA 
+                         - 6.*mq; 
+
+      cumuDiff->Fill(eta, cent, kW4Four, fourPrime);
+      cumuDiff->Fill(eta, cent, kW4, w4p);
+
+      // NUA
+      Double_t cosPsi1Phi2 = pnRe*dQnReA - pnIm*dQnImA - q2nRe;
+      Double_t sinPsi1Phi2 = pnRe*dQnImA + pnIm*dQnReA - q2nIm;
+
+      Double_t cosPsi1Phi2Phi3p = pnRe*(TMath::Power(dQnImA,2.)+TMath::Power(dQnReA,2.)-multA)
+                           - 1.*(q2nRe*dQnReA+q2nIm*dQnImA)  
+                           - mq*dQnReA+2.*qnRe;
+   
+      Double_t sinPsi1Phi2Phi3p = pnIm*(TMath::Power(dQnImA,2.)+TMath::Power(dQnReA,2.)-multA)
+                           - 1.*(q2nIm*dQnReA-q2nRe*dQnImA)  
+                           - mq*dQnImA+2.*qnIm; 
+
+      Double_t cosPsi1Phi2Phi3m = pnRe*(TMath::Power(dQnReA,2.)-TMath::Power(dQnImA,2.))+2.*pnIm*dQnReA*dQnImA
+                           - 1.*(pnRe*dQ2nReA+pnIm*dQ2nImA)  
+                           - 2.*mq*dQnReA+2.*qnRe;
+   
+      Double_t sinPsi1Phi2Phi3m = pnIm*(TMath::Power(dQnReA,2.)-TMath::Power(dQnImA,2.))-2.*pnRe*dQnReA*dQnImA
+                           - 1.*(pnIm*dQ2nReA-pnRe*dQ2nImA)
+                           + 2.*mq*dQnImA-2.*qnIm;
+
+      cumuDiff->Fill(eta, cent, kCosphi1phi2, cosPsi1Phi2);
+      cumuDiff->Fill(eta, cent, kSinphi1phi2, sinPsi1Phi2);
+      cumuDiff->Fill(eta, cent, kCosphi1phi2phi3m, cosPsi1Phi2Phi3m);
+      cumuDiff->Fill(eta, cent, kSinphi1phi2phi3m, sinPsi1Phi2Phi3m);
+      cumuDiff->Fill(eta, cent, k3pWeight, (mp*multA-2.*mq)*(multA-1.));
+      cumuDiff->Fill(eta, cent, kCosphi1phi2phi3p, cosPsi1Phi2Phi3p);
+      cumuDiff->Fill(eta, cent, kSinphi1phi2phi3p, sinPsi1Phi2Phi3p); 
+    } // End of eta loop
+    // Event count
+    cumuRef->Fill(-7., cent, -0.5, 1.);
+  } // End of moment loop
+  return;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::GetLimits(Int_t bin, Int_t& aLow, Int_t& aHigh,
+                                                Int_t& bLow, Int_t& bHigh) const
+{
+  //
+  //  Get the limits for the 3 correlator method
+  //
+  //  Parameters: 
+  //   bin  : reference bin #
+  //   aLow : Lowest bin to be included in v_A calculations
+  //   aHigh: Highest bin to be included in v_A calculations
+  //   bLow : Lowest bin to be included in v_B calculations
+  //   bHigh: Highest bin to be included in v_B calculations
+  //
+  if ((fFlags & kFMD)) {
+    switch(bin) {
+      case 0:
+       aLow = 14; aHigh = 15;
+       bLow = 20; bHigh = 22;
+       break;
+      case 1:
+       aLow = 16; aHigh = 16;
+       bLow = 21; bHigh = 22;
+       break;
+      case 2:
+       aLow =  6; aHigh =  7;
+       bLow = 21; bHigh = 22;
+       break;
+      case 3:
+       aLow =  6; aHigh =  7;
+       bLow = 12; bHigh = 12; 
+       break;
+      case 4:
+       aLow =  6; aHigh =  8;
+       bLow = 13; bHigh = 14;
+       break;
+      default:
+       AliFatal(Form("No limits for this eta region! (%d)", bin));
+    }
+  } 
+  else if ((fFlags & kVZERO)) {
+    switch(bin) {
+      case 0:
+        aLow =  6; aHigh = 13;
+        bLow = 17; bHigh = 18;
+       break;
+      case 1:
+        aLow =  6; aHigh =  9;
+        bLow = 17; bHigh = 18;
+       break;
+      case 2:
+        aLow =  2; aHigh =  3;
+        bLow = 17; bHigh = 18;
+       break;
+      case 3:
+        aLow =  2; aHigh =  3;
+        bLow =  6; bHigh =  9;
+       break;
+      case 4:
+        aLow =  2; aHigh =  3;
+        bLow =  6; bHigh = 13;
+       break;
+      default:
+       AliFatal(Form("No limits for this eta region! (%d)", bin));
+    }
+  }
+  // Try to catch cases where fEtaLimits and these values do not correspond to each other
+  if (aHigh > fCumuNUARef->GetNbinsX() || bHigh > fCumuNUARef->GetNbinsX()) 
+    AliFatal(Form("Limits outside vtx range! (%d) - aHigh = %d, bHigh = %d, Nbins = %d", bin, aHigh, bHigh, fCumuNUARef->GetNbinsX()));
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::CumulantsAccumulate3Cor(Double_t cent) 
+{
+  // 
+  //  Calculate the Q cumulant up to order fMaxMoment
+  //
+  //  Parameters:
+  //   cent: centrality of event
+  //
+  if (!fCumuRef) AliFatal("You have not called AddOutput() - Terminating!");
 
-    fCumuHist->Fill(eta, cent, kCospsi1phi2, cosPsi1Phi2);
-    fCumuHist->Fill(eta, cent, kSinpsi1phi2, sinPsi1Phi2);
-    fCumuHist->Fill(eta, cent, kCospsi1phi2phi3m, cosPsi1Phi2Phi3m);
-    fCumuHist->Fill(eta, cent, kSinpsi1phi2phi3m, sinPsi1Phi2Phi3m);
-    fCumuHist->Fill(eta, cent, kmpmq, (mp*multA-2.*mq)*(multA-1.));
-    fCumuHist->Fill(eta, cent, kCospsi1phi2phi3p, cosPsi1Phi2Phi3p);
-    fCumuHist->Fill(eta, cent, kSinpsi1phi2phi3p, sinPsi1Phi2Phi3p); 
+  // Fill out NUA hists
+  for (Int_t etaBin = 1; etaBin <= fCumuRef->GetNbinsX(); etaBin++) {
+    Double_t eta = fCumuRef->GetXaxis()->GetBinCenter(etaBin);
+    if (fCumuRef->GetBinContent(etaBin, 0) == 0) continue;
+    for (Int_t qBin = 0; qBin <= fCumuRef->GetNbinsY(); qBin++) {
+      fCumuNUARef->Fill(eta, cent, Double_t(qBin), fCumuRef->GetBinContent(etaBin, qBin));
+    }
+  }
+  for (Int_t etaBin = 1; etaBin <= fCumuDiff->GetNbinsX(); etaBin++) {
+    Double_t eta = fCumuDiff->GetXaxis()->GetBinCenter(etaBin);
+    if (fCumuDiff->GetBinContent(etaBin, 0) == 0) continue;
+    for (Int_t qBin = 0; qBin <= fCumuDiff->GetNbinsY(); qBin++) {
+      fCumuNUADiff->Fill(eta, cent, Double_t(qBin), fCumuDiff->GetBinContent(etaBin, qBin));
+    }
   }
-  // Event count
-  fCumuHist->Fill(-7., cent, -0.5, 1.);
+
+  // We create the objects needed for the analysis
+  TH3D* cumuRef = 0; 
+  TH3D* cumuDiff = 0; 
+  // For each n we loop over the hists
+  for (Int_t n = 2; n <= fMaxMoment; n++) {
+    cumuRef  = (TH3D*)fCumuHists.Get('r',n);
+    cumuDiff = (TH3D*)fCumuHists.Get('d',n);
+
+    // Per mom. quantities
+    Int_t prevLim = 0;
+    Int_t aLow = 0, aHigh = 0, bLow = 0, bHigh = 0;
+    Double_t dQnReA = 0, dQnImA = 0, multA = 0; 
+    Double_t dQnReB = 0, dQnImB = 0, multB = 0;
+    Double_t two = 0, w2 = 0;
+    for (Int_t etaBin = 1; etaBin <= fCumuDiff->GetNbinsX(); etaBin++) {
+      Double_t eta = fCumuDiff->GetXaxis()->GetBinCenter(etaBin);
+      if (fEtaLims[prevLim] < eta) {
+        GetLimits(prevLim, aLow, aHigh, bLow, bHigh);
+       prevLim++;
+       multA = 0; dQnReA = 0; dQnImA = 0;
+       multB = 0; dQnReB = 0; dQnImB = 0;
+       // Reference flow
+        for (Int_t a = aLow; a <= aHigh; a++) {
+         multA  += fCumuRef->GetBinContent(a, 0);
+         dQnReA += fCumuRef->GetBinContent(a, GetBinNumberCos(n));
+         dQnImA += fCumuRef->GetBinContent(a, GetBinNumberSin(n));
+       }
+       for (Int_t b = bLow; b <= bHigh; b++) {
+         multB  += fCumuRef->GetBinContent(b, 0);
+         dQnReB += fCumuRef->GetBinContent(b, GetBinNumberCos(n));
+         dQnImB += fCumuRef->GetBinContent(b, GetBinNumberSin(n));
+       }
+       // The reference flow is calculated 
+       // 2-particle
+       w2 = multA * multB;
+       two = dQnReA*dQnReB + dQnImA*dQnImB;
+      } // End of reference flow
+      cumuRef->Fill(eta, cent, kW2Two, two);
+      cumuRef->Fill(eta, cent, kW2, w2);
+
+      // For each etaBin bin the necessary values for differential flow is calculated
+      Double_t mp = fCumuDiff->GetBinContent(etaBin, 0);
+      Double_t pnRe = fCumuDiff->GetBinContent(etaBin, GetBinNumberCos(n));
+      Double_t pnIm = fCumuDiff->GetBinContent(etaBin, GetBinNumberSin(n));
+      if (mp == 0) continue;
+
+      // Differential flow calculations for each eta bin is done:
+      // 2-particle differential flow
+      Double_t w2pA = mp * multA;
+      Double_t twoPrimeA = pnRe*dQnReA + pnIm*dQnImA;
+      cumuDiff->Fill(eta, cent, kW2Two, twoPrimeA);
+      cumuDiff->Fill(eta, cent, kW2, w2pA);
+
+      Double_t w2pB = mp * multB;
+      Double_t twoPrimeB = pnRe*dQnReB + pnIm*dQnImB;
+      cumuDiff->Fill(eta, cent, kW4Four, twoPrimeB);
+      cumuDiff->Fill(eta, cent, kW4, w2pB);
+     } // End of eta loop
+    // Event count
+    cumuRef->Fill(-7., cent, -0.5, 1.);
+  } // End of moment loop
+  return;
 
 }
 //_____________________________________________________________________
@@ -1104,365 +1667,1246 @@ void AliForwardFlowTaskQC::VertexBin::CumulantsTerminate(TList* inlist, TList* o
   //   inlist: input sumlist
   //   outlist: output result list 
   //
-
+  
   // Re-find cumulants hist if Terminate is called separately
-  if (!fCumuHist) {
-    TList* list = (TList*)inlist->FindObject(Form("%svertex_%d_%d%s", fType.Data(), fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")));
-    fCumuHist = (TH3D*)list->FindObject(Form("%sv%d_vertex_%d_%d%s_cumu", fType.Data(), fMoment, 
-                                        fVzMin, fVzMax, ((fFlags & kEtaGap) ? "_etaGap" : "")));
+  if (!fCumuHists.IsConnected()) {
+    TList* list = (TList*)inlist->FindObject(Form("%svertex_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)));
+    fCumuHists.ConnectList(Form("%sCumu_%d_%d%s", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)), list);
+
+    if (!fCumuNUARef) 
+      fCumuNUARef = (TH3D*)list->FindObject(Form("%s_vertex_%d_%d%s_cumuNUARef", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)));
+    if (!fCumuNUADiff) 
+      fCumuNUADiff = (TH3D*)list->FindObject(Form("%s_vertex_%d_%d%s_cumuNUADiff", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)));
   }
-
-  // Create outputs
+  // Clone to avoid normalization problems when redoing terminate locally
+  fCumuNUARef = (TH3D*)fCumuNUARef->Clone(Form("%s_vertex_%d_%d%s_cumuNUARefNorm", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)));
+  fCumuNUADiff = (TH3D*)fCumuNUADiff->Clone(Form("%s_vertex_%d_%d%s_cumuNUADiffNorm", fType.Data(), fVzMin, fVzMax, GetQCType(fFlags)));
+
+  // Diagnostics histograms
+  TH2I* quality = (TH2I*)outlist->FindObject(Form("hQCQuality%s%s", fType.Data(), GetQCType(fFlags)));
+  if (!quality) { 
+    quality = MakeQualityHist(Form("hQCQuality%s%s", fType.Data(), GetQCType(fFlags)));
+    outlist->Add(quality);
+  }
+  TH1D* cent = (TH1D*)outlist->FindObject(Form("%s%s_cent", fType.Data(), GetQCType(fFlags)));
+  if (!cent) {
+    cent = new TH1D(Form("%s%s_cent", fType.Data(), GetQCType(fFlags)), 
+                    Form("%s%s_cent", fType.Data(), GetQCType(fFlags)), 
+                fCumuNUARef->GetNbinsY(), fCumuNUARef->GetYaxis()->GetXmin(), fCumuNUARef->GetYaxis()->GetXmax());
+    cent->GetXaxis()->Set(fCumuNUARef->GetNbinsY(), fCumuNUARef->GetYaxis()->GetXbins()->GetArray());
+    outlist->Add(cent);
+  }
+  TH2D* dNdetaRef = (TH2D*)outlist->FindObject(Form("%s%s_dNdetaRef", fType.Data(), GetQCType(fFlags)));
+  if (!dNdetaRef) {
+    dNdetaRef = new TH2D(Form("%s%s_dNdetaRef", fType.Data(), GetQCType(fFlags)), 
+                               Form("%s%s_dNdetaRef", fType.Data(), GetQCType(fFlags)), 
+                fCumuNUARef->GetNbinsX(), fCumuNUARef->GetXaxis()->GetXmin(), fCumuNUARef->GetXaxis()->GetXmax(),
+                fCumuNUARef->GetNbinsY(), fCumuNUARef->GetYaxis()->GetXmin(), fCumuNUARef->GetYaxis()->GetXmax());
+    dNdetaRef->GetYaxis()->Set(fCumuNUARef->GetNbinsY(), fCumuNUARef->GetYaxis()->GetXbins()->GetArray());
+    dNdetaRef->Sumw2();
+    outlist->Add(dNdetaRef);
+  }
+  TH2D* dNdetaDiff = (TH2D*)outlist->FindObject(Form("%s%s_dNdetaDiff", fType.Data(), GetQCType(fFlags)));
+  if (!dNdetaDiff) {
+    dNdetaDiff = new TH2D(Form("%s%s_dNdetaDiff", fType.Data(), GetQCType(fFlags)), 
+                                Form("%s%s_dNdetaDiff", fType.Data(), GetQCType(fFlags)), 
+                fCumuNUADiff->GetNbinsX(), fCumuNUADiff->GetXaxis()->GetXmin(), fCumuNUADiff->GetXaxis()->GetXmax(),
+                fCumuNUADiff->GetNbinsY(), fCumuNUADiff->GetYaxis()->GetXmin(), fCumuNUADiff->GetYaxis()->GetXmax());
+    dNdetaDiff->GetYaxis()->Set(fCumuNUADiff->GetNbinsY(), fCumuNUADiff->GetYaxis()->GetXbins()->GetArray());
+    dNdetaDiff->Sumw2();
+    outlist->Add(dNdetaDiff);
+  }
+  
+  // Setting up outputs
+  // Create output lists and diagnostics
   TList* vtxList = (TList*)outlist->FindObject("vtxList");
   if (!vtxList) {
     vtxList = new TList();
     vtxList->SetName("vtxList");
     outlist->Add(vtxList);
   }
+  vtxList->Add(fCumuNUARef);
+  vtxList->Add(fCumuNUADiff);
+  // Setup output profiles
+  CumuHistos cumu2(fMaxMoment, ((fFlags & kNUAcorr) ? 2 : 0));
+  CumuHistos cumu4(fMaxMoment, ((fFlags & kNUAcorr) ? 1 : 0));
+
+  cumu2.ConnectList(Form("%sQC2_Cumu%s_vtx_%d_%d", fType.Data(), GetQCType(fFlags), fVzMin, fVzMax), vtxList);
+  if ((fFlags & kStdQC)) 
+    cumu4.ConnectList(Form("%sQC4_Cumu%s_vtx_%d_%d", fType.Data(), GetQCType(fFlags), fVzMin, fVzMax), vtxList);
+
+  for (Int_t n = 2; n <= fMaxMoment; n++) {
+    // 2-particle 
+    cumu2.Add(MakeOutputHist(2, n, "Ref", CumuHistos::kNoNUA));
+    if ((fFlags & k3Cor)){
+      cumu2.Add(MakeOutputHist(2, n, "DiffA", CumuHistos::kNoNUA));
+      cumu2.Add(MakeOutputHist(2, n, "DiffB", CumuHistos::kNoNUA));
+    } else {
+      cumu2.Add(MakeOutputHist(2, n, "Diff", CumuHistos::kNoNUA));
+    }
+    // 4-particle      
+    if ((fFlags & kStdQC)) {
+      cumu4.Add(MakeOutputHist(4, n, "Ref", CumuHistos::kNoNUA));
+      cumu4.Add(MakeOutputHist(4, n, "Diff", CumuHistos::kNoNUA));
+    }
+  } // End of v_n result loop
+  // NUA corrected
+  if ((fFlags & kNUAcorr)) {
+    for (Int_t n = 2; n <= fMaxMoment; n++) {
+      // 2-particle 
+      cumu2.Add(MakeOutputHist(2, n, "Ref", CumuHistos::kNUAOld));
+      if ((fFlags & k3Cor)) {
+        cumu2.Add(MakeOutputHist(2, n, "DiffA", CumuHistos::kNUAOld));
+        cumu2.Add(MakeOutputHist(2, n, "DiffB", CumuHistos::kNUAOld));
+      } else {
+       cumu2.Add(MakeOutputHist(2, n, "Diff", CumuHistos::kNUAOld));
+      }
+      // 4-particle      
+      if ((fFlags & kStdQC)) {
+       cumu4.Add(MakeOutputHist(4, n, "Ref", CumuHistos::kNUAOld));
+       cumu4.Add(MakeOutputHist(4, n, "Diff", CumuHistos::kNUAOld));
+      }   
+    }
+    for (Int_t n = 2; n <= fMaxMoment; n++) {
+      // 2-particle 
+      cumu2.Add(MakeOutputHist(2, n, "Ref", CumuHistos::kNUA));
+      if ((fFlags & k3Cor)) {
+       cumu2.Add(MakeOutputHist(2, n, "DiffA", CumuHistos::kNUA));
+       cumu2.Add(MakeOutputHist(2, n, "DiffB", CumuHistos::kNUA));
+      } else {
+       cumu2.Add(MakeOutputHist(2, n, "Diff", CumuHistos::kNUA));
+      }
+    }
+  }
+
+  // Calculating the cumulants
+  if ((fFlags & k3Cor)) {
+    Calculate3CorFlow(cumu2, quality, cent, dNdetaRef, dNdetaDiff);
+  } else {
+    CalculateReferenceFlow(cumu2, cumu4, quality, cent, dNdetaRef);
+    CalculateDifferentialFlow(cumu2, cumu4, quality, dNdetaDiff);
+  }
+  if ((fFlags & kNUAcorr)) {
+    SolveCoupledFlowEquations(cumu2, 'r');
+    if ((fFlags & k3Cor)) {
+      SolveCoupledFlowEquations(cumu2, 'a');
+      SolveCoupledFlowEquations(cumu2, 'b');
+    } else {
+      SolveCoupledFlowEquations(cumu2, 'd');
+    }
+  }
+  // Add to output for immediate viewing - individual vtx bins are used for final results
+  AddVertexBins(cumu2, outlist, ((fFlags & kNUAcorr) ? 2 : 0));
+  if ((fFlags & kStdQC)) AddVertexBins(cumu4, outlist, ((fFlags & kNUAcorr) ? 1 : 0));
+
+  // Setup NUA diagnoastics histograms
   TList* nualist = (TList*)outlist->FindObject("NUATerms");
   if (!nualist) {
     nualist = new TList();
     nualist->SetName("NUATerms");
     outlist->Add(nualist);
   }
-
-  TH1I* quality = (TH1I*)outlist->FindObject(Form("hQCQuality%s%s", fType.Data(), ((fFlags & kEtaGap) ? "_etaGap" : "")));
-
-  // Differential flow
-  TProfile2D* cumu2Sum = (TProfile2D*)outlist->FindObject(Form("%sQC2_v%d_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : ""))); 
-  TProfile2D* cumu4Sum = (TProfile2D*)outlist->FindObject(Form("%sQC4_v%d_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : ""))); 
-  if (!cumu2Sum) {
-    cumu2Sum = new TProfile2D(Form("%sQC2_v%d_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           Form("%sQC2_v%d_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-             fCumuHist->GetNbinsX(), fCumuHist->GetXaxis()->GetXmin(), fCumuHist->GetXaxis()->GetXmax(), 
-             fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(cumu2Sum->GetYaxis());
-    outlist->Add(cumu2Sum);
+  // Reference
+  TH2D* nuaRef = (TH2D*)nualist->FindObject(Form("%sReferenceNUA%s", fType.Data(), GetQCType(fFlags)));
+  TH2D* temp = 0;
+  if (!nuaRef) {
+    nuaRef = (TH2D*)fCumuNUARef->Project3D("yz");
+    nuaRef->Scale(1./fCumuNUARef->GetNbinsX());
+    nuaRef->SetName(Form("%sReferenceNUA%s", fType.Data(), GetQCType(fFlags)));
+    nuaRef->SetTitle(Form("%sReferenceNUA%s", fType.Data(), GetQCType(fFlags)));
+    nualist->Add(nuaRef);
+  } else {
+    temp = (TH2D*)fCumuNUARef->Project3D("yz");
+    temp->Scale(1./fCumuNUARef->GetNbinsX());
+    nuaRef->Add(temp);
+    delete temp;
   }
-  if (!cumu4Sum && !(fFlags & kEtaGap)) {
-    cumu4Sum = new TProfile2D(Form("%sQC4_v%d_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           Form("%sQC4_v%d_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-             fCumuHist->GetNbinsX(), fCumuHist->GetXaxis()->GetXmin(), fCumuHist->GetXaxis()->GetXmax(), 
-             fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(cumu4Sum->GetYaxis());
-    outlist->Add(cumu4Sum);
+  // Filling in underflow to make scaling possible in Terminate()
+  nuaRef->Fill(0., -1., 1.);
+  // Differential
+  TH2D* nuaDiff = (TH2D*)nualist->FindObject(Form("%sDifferentialNUA%s", fType.Data(), GetQCType(fFlags)));
+  if (!nuaDiff) {
+    nuaDiff = (TH2D*)fCumuNUADiff->Project3D("yz");
+    nuaDiff->SetName(Form("%sDifferentialNUA%s", fType.Data(), GetQCType(fFlags)));
+    nuaDiff->SetTitle(Form("%sDifferentialNUA%s", fType.Data(), GetQCType(fFlags)));
+    nualist->Add(nuaDiff);
+  } else {
+    temp = (TH2D*)fCumuNUADiff->Project3D("yz");
+    nuaDiff->Add(temp);
+    delete temp;
   }
-  TProfile2D* cumu2 = new TProfile2D(Form("%sQC2_v%d_unCorr%s_vtx%3.1f", fType.Data(), fMoment, 
-                         ((fFlags & kEtaGap) ? "_etaGap" : ""), (fVzMin+fVzMax)/2.),
-                        Form("%sQC2_v%d_unCorr%s_vtx%3.1f", fType.Data(), fMoment,
-                        ((fFlags & kEtaGap) ? "_etaGap" : ""), (fVzMin+fVzMax)/2.),
-           fCumuHist->GetNbinsX(), fCumuHist->GetXaxis()->GetXmin(), fCumuHist->GetXaxis()->GetXmax(), 
-           fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-  SetupCentAxis(cumu2->GetYaxis());
-  vtxList->Add(cumu2);
-  TProfile2D* cumu4 = 0;
-  if (!(fFlags & kEtaGap)) { 
-    cumu4 = new TProfile2D(Form("%sQC4_v%d_unCorr%s_vtx%3.1f", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : ""), (fVzMin+fVzMax)/2.),
-                           Form("%sQC4_v%d_unCorr%s_vtx%3.1f", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : ""), (fVzMin+fVzMax)/2.),
-             fCumuHist->GetNbinsX(), fCumuHist->GetXaxis()->GetXmin(), fCumuHist->GetXaxis()->GetXmax(), 
-             fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(cumu4->GetYaxis());
-    vtxList->Add(cumu4);
-  }
-
-  // Reference flow
-  TProfile2D* cumu2Ref = (TProfile2D*)outlist->FindObject(Form("%sQC2_v%d_ref_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : ""))); 
-  TProfile2D* cumu4Ref = (TProfile2D*)outlist->FindObject(Form("%sQC4_v%d_ref_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")));
-  if (!cumu2Ref) {
-    cumu2Ref = new TProfile2D(Form("%sQC2_v%d_ref_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           Form("%sQC2_v%d_ref_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-             fCumuHist->GetNbinsX(), fCumuHist->GetXaxis()->GetXmin(), fCumuHist->GetXaxis()->GetXmax(), 
-             fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(cumu2Ref->GetYaxis());
-    outlist->Add(cumu2Ref);
-  }
-  if (!cumu4Ref && !(fFlags & kEtaGap)) {
-    cumu4Ref = new TProfile2D(Form("%sQC4_v%d_ref_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           Form("%sQC4_v%d_ref_unCorr%s", fType.Data(), fMoment, ((fFlags & kEtaGap) ? "_etaGap" : "")),
-             fCumuHist->GetNbinsX(), fCumuHist->GetXaxis()->GetXmin(), fCumuHist->GetXaxis()->GetXmax(), 
-             fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(cumu4Ref->GetYaxis());
-    outlist->Add(cumu4Ref);
-  }
-
-  // NUA terms
-  TProfile2D* cosPhi = (TProfile2D*)nualist->FindObject(Form("%sCosPhi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")));
-  if (!cosPhi) {
-    cosPhi = new TProfile2D(Form("%sCosPhi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                                 Form("%sCosPhi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           48, -6, 6, 
-                           fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(cosPhi->GetYaxis());
-    nualist->Add(cosPhi);
-  }
-
-  TProfile2D* cosPsi = (TProfile2D*)nualist->FindObject(Form("%sCosPsi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")));
-  if (!cosPsi) {
-    cosPsi = new TProfile2D(Form("%sCosPsi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                                 Form("%sCosPsi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           48, -6, 6,
-                           fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(cosPsi->GetYaxis());
-    nualist->Add(cosPsi);
-  }
-
-  TProfile2D* sinPhi = (TProfile2D*)nualist->FindObject(Form("%sSinPhi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")));
-  if (!sinPhi) { 
-    sinPhi = new TProfile2D(Form("%sSinPhi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                                 Form("%sSinPhi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           48, -6, 6,
-                           fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(sinPhi->GetYaxis());
-    nualist->Add(sinPhi);
-  }
-
-  TProfile2D* sinPsi = (TProfile2D*)nualist->FindObject(Form("%sSinPsi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")));
-  if (!sinPsi) {
-    sinPsi = new TProfile2D(Form("%sSinPsi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                                 Form("%sSinPsi_v%d_unCorr%s", fType.Data(), fMoment, 
-                           ((fFlags & kEtaGap) ? "_etaGap" : "")),
-                           48, -6, 6,
-                           fCumuHist->GetNbinsY(), fCumuHist->GetYaxis()->GetXmin(), fCumuHist->GetYaxis()->GetXmax());
-    SetupCentAxis(sinPsi->GetYaxis());
-    nualist->Add(sinPsi);
+  // Filling in underflow to make scaling possible in Terminate()
+  nuaDiff->Fill(0., -1., 1.);
+
+  return;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::CalculateReferenceFlow(CumuHistos& cumu2h, CumuHistos& cumu4h, TH2I* quality, 
+                                                             TH1D* chist, TH2D* dNdetaRef) const  
+{
+  // 
+  //  Calculates the reference flow
+  //
+  //  Parameters:
+  //   cumu2h: CumuHistos object with QC{2} cumulants
+  //   cumu4h: CumuHistos object with QC{4} cumulants
+  //   quality: Histogram for success rate of cumulants
+  //   chist: Centrality histogram
+  //   dNdetaRef: dN/deta histogram for estimating multiplicity used for ref calculations
+  //
+
+  // Normalizing common NUA hists
+  for (Int_t cBin = 1; cBin <= fCumuNUARef->GetNbinsY(); cBin++) {
+    Double_t cent = fCumuNUARef->GetYaxis()->GetBinCenter(cBin);
+    for (Int_t eBin = 1; eBin <= fCumuNUARef->GetNbinsX(); eBin++) {
+      Double_t eta = fCumuNUARef->GetXaxis()->GetBinCenter(eBin);
+      Double_t mult = fCumuNUARef->GetBinContent(eBin, cBin, 0);
+      if (mult == 0) continue;
+      for (Int_t qBin = 1; qBin <= fCumuNUARef->GetNbinsZ(); qBin++) {
+       fCumuNUARef->SetBinContent(eBin, cBin, qBin, fCumuNUARef->GetBinContent(eBin, cBin, qBin)/mult);
+       fCumuNUARef->SetBinError(eBin, cBin, qBin, fCumuNUARef->GetBinError(eBin, cBin, qBin)/mult);
+      }
+      // Fill dN/deta diagnostics
+      dNdetaRef->Fill(eta, cent, mult);
+    }
   }
-  
+
   // For flow calculations
-  Double_t two = 0, qc2 = 0, vnTwo = 0, four = 0, qc4 = 0, vnFour = 0; 
-  Double_t twoPrime = 0, qc2Prime = 0, vnTwoDiff = 0, fourPrime = 0, qc4Prime = 0, vnFourDiff = 0;
-  Double_t w2 = 0, w4 = 0, w2p = 0, w4p = 0;
-  Double_t w2Two = 0, w2pTwoPrime = 0, w4Four = 0, w4pFourPrime = 0;
-  Double_t cosP1nPhiA = 0, sinP1nPhiA = 0, multA = 0;
-  Double_t cosP1nPhiB = 0, sinP1nPhiB = 0, multB = 0;
-  Double_t cosP1nPhi1P1nPhi2 = 0, sinP1nPhi1P1nPhi2 = 0;
-  Double_t cosP1nPhi1M1nPhi2M1nPhi3 = 0, sinP1nPhi1M1nPhi2M1nPhi3 = 0, multm1m2 = 0;
-  Double_t cosP1nPsi = 0, sinP1nPsi = 0, mp = 0, cosP1nPsi1P1nPhi2 = 0, sinP1nPsi1P1nPhi2 = 0;
-  Double_t cosP1nPsi1M1nPhi2M1nPhi3 = 0, sinP1nPsi1M1nPhi2M1nPhi3 = 0, mpqMult = 0;
-  Double_t cosP1nPsi1P1nPhi2M1nPhi3 = 0, sinP1nPsi1P1nPhi2M1nPhi3 = 0;
-
-  // Loop over cumulant histogram for final calculations   
-  // Centrality loop
-  for (Int_t cBin = 1; cBin <= fCumuHist->GetNbinsY(); cBin++) {
-    // for weighted avg.
-    Double_t cent = fCumuHist->GetYaxis()->GetBinCenter(cBin);
-    if (fDebug > 0) AliInfo(Form("%s - v_%d: centrality %3.1f:..", fType.Data(), fMoment, cent));
-    // Eta loop
-    for (Int_t etaBin = 1; etaBin <= fCumuHist->GetNbinsX(); etaBin++) {
-      Double_t eta = fCumuHist->GetXaxis()->GetBinCenter(etaBin);
-      // 2-particle reference flow
-      w2Two = fCumuHist->GetBinContent(etaBin, cBin, kW2Two);
-      w2 = fCumuHist->GetBinContent(etaBin, cBin, kW2);
-      multA = fCumuHist->GetBinContent(etaBin, cBin, kMA);
-      multB = fCumuHist->GetBinContent(etaBin, cBin, kMB);
-      if (w2 == 0 || multA == 0 || multB == 0) continue;
-      cosP1nPhiA = fCumuHist->GetBinContent(etaBin, cBin, kQnReA);
-      sinP1nPhiA = fCumuHist->GetBinContent(etaBin, cBin, kQnImA);
-      cosP1nPhiB = fCumuHist->GetBinContent(etaBin, cBin, kQnReB);
-      sinP1nPhiB = fCumuHist->GetBinContent(etaBin, cBin, kQnImB);
-        
-      cosP1nPhiA /= multA;
-      sinP1nPhiA /= multA;
-      cosP1nPhiB /= multB;
-      sinP1nPhiB /= multB;
-      two = w2Two / w2;
-      // With no eta gap the last two terms are <<cos(phi)>>^2 and <<sin(phi)>>^2,
-      // with eta gap the different coverage is taken into account. 
-      // The next line covers both cases.
-      qc2 = two - cosP1nPhiA*cosP1nPhiB - sinP1nPhiA*sinP1nPhiB;
-      if (qc2 <= 0) { 
-       if (fDebug > 0) AliInfo(Form("%s: QC_%d{2} = %1.3f for eta = %1.2f and centrality %3.1f - skipping", fType.Data(), fMoment, qc2, eta, cent));
-       quality->Fill((fMoment-2)*8+2);
-       continue;
-      }
-       vnTwo = TMath::Sqrt(qc2);
-      if (!TMath::IsNaN(vnTwo*multA)) { 
-       quality->Fill((fMoment-2)*8+1);
-       cumu2Ref->Fill(eta, cent, vnTwo);
-      }
+  TH3D* cumuRef = 0; 
+  TH2D* cumu2 = 0;
+  TH2D* cumu2NUAold = 0;
+  TH2D* cumu2NUA = 0;
+  TH2D* cumu4 = 0;
+  TH2D* cumu4NUA = 0;
+  Int_t qualityFactor = ((fFlags & kStdQC) ? 8 : 4); // used for correctly filling in quality hists
+  // Loop over cumulant histogram for final calculations 
+  for (Int_t n = 2; n <= fMaxMoment; n++) { // Moment loop begins
+    cumu2 = (TH2D*)cumu2h.Get('r', n, CumuHistos::kNoNUA);
+    if ((fFlags & kNUAcorr)) {
+      cumu2NUAold = (TH2D*)cumu2h.Get('r', n, CumuHistos::kNUAOld);
+      cumu2NUA = (TH2D*)cumu2h.Get('r', n, CumuHistos::kNUA);
+    }
+    if ((fFlags & kStdQC)) {
+      cumu4 = (TH2D*)cumu4h.Get('r', n, CumuHistos::kNoNUA);
+      if ((fFlags & kNUAcorr)) cumu4NUA = (TH2D*)cumu4h.Get('r', n, CumuHistos::kNUAOld);
+    }
+    cumuRef  = (TH3D*)fCumuHists.Get('r', n);
+    // Begin loops
+    for (Int_t cBin = 1; cBin <= cumuRef->GetNbinsY(); cBin++) { // Centrality loop begins
+      Double_t cent = cumuRef->GetYaxis()->GetBinCenter(cBin);
+      if (n == 2) chist->Fill(cent, cumuRef->GetBinContent(0, cBin, 0));
+      if (fDebug > 0) AliInfo(Form("%s - v_%d: centrality %3.1f:..", fType.Data(), n, cent));
+      for (Int_t etaBin = 1; etaBin <= cumuRef->GetNbinsX(); etaBin++) { // Eta loop begins
+       Double_t eta = cumuRef->GetXaxis()->GetBinCenter(etaBin);
+       Int_t refEtaBinA = fCumuNUARef->GetXaxis()->FindBin(eta);
+       Int_t refEtaBinB = fCumuNUARef->GetXaxis()->FindBin(-eta);
+       // 2-particle reference flow
+       Double_t w2Two = cumuRef->GetBinContent(refEtaBinA, cBin, kW2Two);
+       Double_t w2 = cumuRef->GetBinContent(refEtaBinA, cBin, kW2);
+       if (w2 == 0) continue;
+       Double_t cosP1nPhiA = fCumuNUARef->GetBinContent(refEtaBinA, cBin, GetBinNumberCos(n));
+       Double_t sinP1nPhiA = fCumuNUARef->GetBinContent(refEtaBinA, cBin, GetBinNumberSin(n));
+       Double_t cosP1nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberCos(n));
+       Double_t sinP1nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberSin(n));
+       Double_t cos2nPhiA = fCumuNUARef->GetBinContent(refEtaBinA, cBin, GetBinNumberCos(2*n));
+       Double_t sin2nPhiA = fCumuNUARef->GetBinContent(refEtaBinA, cBin, GetBinNumberSin(2*n));
+       Double_t cos2nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberCos(2*n));
+       Double_t sin2nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberSin(2*n));  
+       Double_t two = w2Two / w2; 
+       Double_t qc2 = two;
+        if (qc2 >= 0) cumu2->Fill(eta, cent, TMath::Sqrt(qc2));
+
+       if ((fFlags & kNUAcorr)) {
+         // Old NUA
+         // With no eta gap the last two terms are <<cos(phi)>>^2 and <<sin(phi)>>^2,
+         // with eta gap the different coverage is taken into account. 
+         // The next line covers both cases.
+         qc2 -= cosP1nPhiA*cosP1nPhiB + sinP1nPhiA*sinP1nPhiB;
+         // Extra NUA term from 2n cosines and sines
+         Double_t den = 1-(cos2nPhiA*cos2nPhiB + sin2nPhiA*sin2nPhiB);
+         if (den != 0) qc2 /= den;
+         else qc2 = 0;
+       }
+       if (qc2 <= 0) { 
+         if (fDebug > 0) 
+           AliInfo(Form("%s: QC_%d{2} = %1.3f for eta = %1.2f and centrality %3.1f - skipping", 
+           fType.Data(), n, qc2, eta, cent));
+         quality->Fill((n-2)*qualityFactor+2, Int_t(cent));
+         continue;
+       }
+       Double_t vnTwo = TMath::Sqrt(qc2);
+       if (!TMath::IsNaN(vnTwo)) { 
+         quality->Fill((n-2)*qualityFactor+1, Int_t(cent));
+         if ((fFlags & kNUAcorr)) cumu2NUAold->Fill(eta, cent, vnTwo);
+       }
 
-      // 2-particle differential flow
-      w2pTwoPrime = fCumuHist->GetBinContent(etaBin, cBin, kw2two);
-      w2p = fCumuHist->GetBinContent(etaBin, cBin, kw2);
-      mp = fCumuHist->GetBinContent(etaBin, cBin, kmp);
-      if (w2p == 0 || mp == 0) continue;
-      cosP1nPsi = fCumuHist->GetBinContent(etaBin, cBin, kpnRe);
-      sinP1nPsi = fCumuHist->GetBinContent(etaBin, cBin, kpnIm);
-
-      cosP1nPsi /= mp;
-      sinP1nPsi /= mp;
-      twoPrime = w2pTwoPrime / w2p;
-      qc2Prime = twoPrime - sinP1nPsi*sinP1nPhiB - cosP1nPsi*cosP1nPhiB;
-
-      cosPhi->Fill(eta, cent, cosP1nPhiB); 
-      cosPsi->Fill(eta, cent, cosP1nPsi); 
-      sinPhi->Fill(eta, cent, sinP1nPhiB); 
-      sinPsi->Fill(eta, cent, sinP1nPsi); 
-      vnTwoDiff = qc2Prime / TMath::Sqrt(qc2);
-      if (!TMath::IsNaN(vnTwoDiff*mp)) {
-       cumu2->Fill(eta, cent, vnTwoDiff);
-       quality->Fill((fMoment-2)*8+3);
-      }
-      else 
-       quality->Fill((fMoment-2)*8+4);
+       if (!(fFlags & kStdQC)) continue;
+       // 4-particle reference flow
+       Double_t w4Four = cumuRef->GetBinContent(refEtaBinA, cBin, kW4Four);
+       Double_t w4 = cumuRef->GetBinContent(refEtaBinA, cBin, kW4);
+       Double_t multm1m2 = cumuRef->GetBinContent(refEtaBinA, cBin, k3pWeight);
+       if (w4 == 0 || multm1m2 == 0) continue;
+       Double_t cosP1nPhi1P1nPhi2 = cumuRef->GetBinContent(refEtaBinA, cBin, kCosphi1phi2);
+       Double_t sinP1nPhi1P1nPhi2 = cumuRef->GetBinContent(refEtaBinA, cBin, kSinphi1phi2);
+       Double_t cosP1nPhi1M1nPhi2M1nPhi3 = cumuRef->GetBinContent(refEtaBinA, cBin, kCosphi1phi2phi3m);
+       Double_t sinP1nPhi1M1nPhi2M1nPhi3 = cumuRef->GetBinContent(refEtaBinA, cBin, kSinphi1phi2phi3m);
+
+       cosP1nPhi1P1nPhi2 /= w2;
+       sinP1nPhi1P1nPhi2 /= w2;
+       cosP1nPhi1M1nPhi2M1nPhi3 /= multm1m2;
+       sinP1nPhi1M1nPhi2M1nPhi3 /= multm1m2;
+       Double_t four = w4Four / w4;
+       Double_t qc4 = four-2.*TMath::Power(two,2.);
+        if (qc4 < 0) cumu4->Fill(eta, cent, TMath::Power(-qc4, 0.25));
+       
+       if ((fFlags & kNUAcorr)) {
+          qc4 += - 4.*cosP1nPhiA*cosP1nPhi1M1nPhi2M1nPhi3
+                 + 4.*sinP1nPhiA*sinP1nPhi1M1nPhi2M1nPhi3-TMath::Power(cosP1nPhi1P1nPhi2,2.)-TMath::Power(sinP1nPhi1P1nPhi2,2.)
+                 + 4.*cosP1nPhi1P1nPhi2*(TMath::Power(cosP1nPhiA,2.)-TMath::Power(sinP1nPhiA,2.))
+                 + 8.*sinP1nPhi1P1nPhi2*sinP1nPhiA*cosP1nPhiA
+                 + 8.*two*(TMath::Power(cosP1nPhiA,2.)+TMath::Power(sinP1nPhiA,2.))
+                 - 6.*TMath::Power((TMath::Power(cosP1nPhiA,2.)+TMath::Power(sinP1nPhiA,2.)),2.);
+       }
+       if (qc4 >= 0) {
+         if (fDebug > 0) 
+           AliInfo(Form("%s: QC_%d{4} = %1.3f for eta = %1.2f and centrality %3.1f - skipping", 
+           fType.Data(), n, qc2, eta, cent));
+         quality->Fill((n-2)*qualityFactor+6, Int_t(cent));
+         continue;
+       }
+       Double_t vnFour = TMath::Power(-qc4, 0.25);
+       if (!TMath::IsNaN(vnFour*multm1m2)) {
+         quality->Fill((n-2)*qualityFactor+5, Int_t(cent));
+         if ((fFlags & kNUAcorr)) cumu4NUA->Fill(eta, cent, vnFour);
+       }
+      } // End of eta
+    } // End of cent
+  } // End of moment
 
-      if (fDebug > 1) AliInfo(Form("%s: v_%d{2} = %1.3f for eta = %1.2f and centrality %3.1f", fType.Data(), fMoment, vnTwoDiff, eta, cent));
-      if ((fFlags & kEtaGap)) continue;
-      
-      // 4-particle reference flow
-      w4Four = fCumuHist->GetBinContent(etaBin, cBin, kW4Four);
-      w4 = fCumuHist->GetBinContent(etaBin, cBin, kW4);
-      multm1m2 = fCumuHist->GetBinContent(etaBin, cBin, kMm1m2);
-      if (w4 == 0 || multm1m2 == 0) continue;
-      cosP1nPhi1P1nPhi2 = fCumuHist->GetBinContent(etaBin, cBin, kCosphi1phi2);
-      sinP1nPhi1P1nPhi2 = fCumuHist->GetBinContent(etaBin, cBin, kSinphi1phi2);
-      cosP1nPhi1M1nPhi2M1nPhi3 = fCumuHist->GetBinContent(etaBin, cBin, kCosphi1phi2phi3m);
-      sinP1nPhi1M1nPhi2M1nPhi3 = fCumuHist->GetBinContent(etaBin, cBin, kSinphi1phi2phi3m);
-
-      cosP1nPhi1P1nPhi2 /= w2;
-      sinP1nPhi1P1nPhi2 /= w2;
-      cosP1nPhi1M1nPhi2M1nPhi3 /= multm1m2;
-      sinP1nPhi1M1nPhi2M1nPhi3 /= multm1m2;
-      four = w4Four / w4;
-      qc4 = four-2.*TMath::Power(two,2.)
-         - 4.*cosP1nPhiA*cosP1nPhi1M1nPhi2M1nPhi3
-         + 4.*sinP1nPhiA*sinP1nPhi1M1nPhi2M1nPhi3-TMath::Power(cosP1nPhi1P1nPhi2,2.)-TMath::Power(sinP1nPhi1P1nPhi2,2.)
-         + 4.*cosP1nPhi1P1nPhi2*(TMath::Power(cosP1nPhiA,2.)-TMath::Power(sinP1nPhiA,2.))
-         + 8.*sinP1nPhi1P1nPhi2*sinP1nPhiA*cosP1nPhiA
-         + 8.*two*(TMath::Power(cosP1nPhiA,2.)+TMath::Power(sinP1nPhiA,2.))
-         - 6.*TMath::Power((TMath::Power(cosP1nPhiA,2.)+TMath::Power(sinP1nPhiA,2.)),2.);
-      
-      if (qc4 >= 0) {
-       if (fDebug > 0) AliInfo(Form("%s: QC_%d{4} = %1.3f for eta = %1.2f and centrality %3.1f - skipping", fType.Data(), fMoment, qc2, eta, cent));
-       quality->Fill((fMoment-2)*8+6);
-       continue;
-      }
-      vnFour = TMath::Power(-qc4, 0.25);
-      if (!TMath::IsNaN(vnFour*multm1m2)) {
-       quality->Fill((fMoment-2)*8+5);
-        cumu4Ref->Fill(eta, cent, vnFour);
+  return;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::CalculateDifferentialFlow(CumuHistos& cumu2h, CumuHistos& cumu4h, 
+                                                                TH2I* quality, TH2D* dNdetaDiff) const  
+{
+  // 
+  //  Calculates the differential flow
+  //
+  //  Parameters:
+  //   cumu2h: CumuHistos object with QC{2} cumulants
+  //   cumu4h: CumuHistos object with QC{4} cumulants
+  //   quality: Histogram for success rate of cumulants
+  //   dNdetaDiff: dN/deta histogram for estimating multiplicity used for diff calculations
+  //
+
+  for (Int_t cBin = 1; cBin <= fCumuNUADiff->GetNbinsY(); cBin++) {
+    Double_t cent = fCumuNUADiff->GetYaxis()->GetBinCenter(cBin);
+    for (Int_t eBin = 1; eBin <= fCumuNUADiff->GetNbinsX(); eBin++) {
+      Double_t eta = fCumuNUADiff->GetXaxis()->GetBinCenter(eBin);
+      Double_t mult = fCumuNUADiff->GetBinContent(eBin, cBin, 0);
+      if (mult == 0) continue;
+      for (Int_t qBin = 1; qBin <= fCumuNUADiff->GetNbinsZ(); qBin++) {
+       fCumuNUADiff->SetBinContent(eBin, cBin, qBin, fCumuNUADiff->GetBinContent(eBin, cBin, qBin)/mult);
+       fCumuNUADiff->SetBinError(eBin, cBin, qBin, fCumuNUADiff->GetBinError(eBin, cBin, qBin)/mult);
       }
+      dNdetaDiff->Fill(eta, cent, mult);
+    }
+  }
 
-      // 4-particle differential flow
-      w4pFourPrime = fCumuHist->GetBinContent(etaBin, cBin, kw4four);
-      w4p = fCumuHist->GetBinContent(etaBin, cBin, kw4);
-      mpqMult = fCumuHist->GetBinContent(etaBin, cBin, kmpmq);
-      if (w4p == 0 || mpqMult == 0) continue;
-      cosP1nPsi1P1nPhi2 = fCumuHist->GetBinContent(etaBin, cBin, kCospsi1phi2);
-      sinP1nPsi1P1nPhi2 = fCumuHist->GetBinContent(etaBin, cBin, kSinpsi1phi2);
-      cosP1nPsi1M1nPhi2M1nPhi3 = fCumuHist->GetBinContent(etaBin, cBin, kCospsi1phi2phi3m);
-      sinP1nPsi1M1nPhi2M1nPhi3 = fCumuHist->GetBinContent(etaBin, cBin, kSinpsi1phi2phi3m);
-      cosP1nPsi1P1nPhi2M1nPhi3 = fCumuHist->GetBinContent(etaBin, cBin, kCospsi1phi2phi3p);
-      sinP1nPsi1P1nPhi2M1nPhi3 = fCumuHist->GetBinContent(etaBin, cBin, kSinpsi1phi2phi3p); 
-      
-      cosP1nPsi1P1nPhi2 /= w2p;
-      sinP1nPsi1P1nPhi2 /= w2p;
-      cosP1nPsi1M1nPhi2M1nPhi3 /= mpqMult;
-      sinP1nPsi1M1nPhi2M1nPhi3 /= mpqMult;
-      cosP1nPsi1P1nPhi2M1nPhi3 /= mpqMult;
-      sinP1nPsi1P1nPhi2M1nPhi3 /= mpqMult;
-
-      fourPrime = w4pFourPrime / w4p;
-
-      qc4Prime = fourPrime-2.*twoPrime*two
-                - cosP1nPsi*cosP1nPhi1M1nPhi2M1nPhi3
-                + sinP1nPsi*sinP1nPhi1M1nPhi2M1nPhi3
-                - cosP1nPhiA*cosP1nPsi1M1nPhi2M1nPhi3
-                + sinP1nPhiA*sinP1nPsi1M1nPhi2M1nPhi3
-                - 2.*cosP1nPhiA*cosP1nPsi1P1nPhi2M1nPhi3
-                - 2.*sinP1nPhiA*sinP1nPsi1P1nPhi2M1nPhi3
-                - cosP1nPsi1P1nPhi2*cosP1nPhi1P1nPhi2
-                - sinP1nPsi1P1nPhi2*sinP1nPhi1P1nPhi2
-                + 2.*cosP1nPhi1P1nPhi2*(cosP1nPsi*cosP1nPhiA-sinP1nPsi*sinP1nPhiA)
-                + 2.*sinP1nPhi1P1nPhi2*(cosP1nPsi*sinP1nPhiA+sinP1nPsi*cosP1nPhiA)
-                + 4.*two*(cosP1nPsi*cosP1nPhiA+sinP1nPsi*sinP1nPhiA)
-                + 2.*cosP1nPsi1P1nPhi2*(TMath::Power(cosP1nPhiA,2.)-TMath::Power(sinP1nPhiA,2.))
-                + 4.*sinP1nPsi1P1nPhi2*cosP1nPhiA*sinP1nPhiA
-                + 4.*twoPrime*(TMath::Power(cosP1nPhiA,2.)+TMath::Power(sinP1nPhiA,2.))
-                - 6.*(TMath::Power(cosP1nPhiA,2.)-TMath::Power(sinP1nPhiA,2.)) 
-                * (cosP1nPsi*cosP1nPhiA-sinP1nPsi*sinP1nPhiA)
-                - 12.*cosP1nPhiA*sinP1nPhiA
-                * (sinP1nPsi*cosP1nPhiA+cosP1nPsi*sinP1nPhiA);
-
-      vnFourDiff = - qc4Prime / TMath::Power(-qc4, 0.75);
-      if (!TMath::IsNaN(vnFourDiff*mpqMult) && vnFourDiff > 0) {
-       cumu4->Fill(eta, cent, vnFourDiff);
-       quality->Fill((fMoment-2)*8+7);
+  // For flow calculations
+  TH3D* cumuRef = 0; 
+  TH3D* cumuDiff = 0; 
+  TH2D* cumu2 = 0;
+  TH2D* cumu2NUAold = 0;
+  TH2D* cumu2NUA = 0;
+  TH2D* cumu4 = 0;
+  TH2D* cumu4NUA = 0;
+  Int_t qualityFactor = ((fFlags & kStdQC) ? 8 : 4); // used for correctly filling in quality hists
+  // Loop over cumulant histogram for final calculations 
+  for (Int_t n = 2; n <= fMaxMoment; n++) { // Moment loop begins
+    cumu2 = (TH2D*)cumu2h.Get('d', n, CumuHistos::kNoNUA);
+    if ((fFlags & kNUAcorr)) {
+      cumu2NUAold = (TH2D*)cumu2h.Get('d', n, CumuHistos::kNUAOld);
+      cumu2NUA = (TH2D*)cumu2h.Get('d', n, CumuHistos::kNUA);
+    }
+    if (!(fFlags & kEtaGap)) {
+      cumu4 = (TH2D*)cumu4h.Get('d',n);
+      if ((fFlags & kNUAcorr)) cumu4NUA = (TH2D*)cumu4h.Get('d', n, CumuHistos::kNUAOld);
+    }
+    cumuRef  = (TH3D*)fCumuHists.Get('r',n);
+    cumuDiff = (TH3D*)fCumuHists.Get('d',n);
+    for (Int_t cBin = 1; cBin <= cumuDiff->GetNbinsY(); cBin++) { // Centrality loop begins
+      Double_t cent = cumuDiff->GetYaxis()->GetBinCenter(cBin);
+      if (fDebug > 0) AliInfo(Form("%s - v_%d: centrality %3.1f:..", fType.Data(), n, cent));
+      for (Int_t etaBin = 1; etaBin <= cumuDiff->GetNbinsX(); etaBin++) { // Eta loop begins
+       Double_t eta = cumuDiff->GetXaxis()->GetBinCenter(etaBin);
+       Int_t refEtaBinA = fCumuNUARef->GetXaxis()->FindBin(eta);
+       Int_t refEtaBinB = fCumuNUARef->GetXaxis()->FindBin(-eta);
+
+        // Reference objects
+       Double_t w2 = cumuRef->GetBinContent(refEtaBinA, cBin, kW2);
+       if (w2 == 0) continue;
+       Double_t two = cumuRef->GetBinContent(refEtaBinA, cBin, kW2Two);
+        two /= w2;
+       Double_t cosP1nPhiA = fCumuNUARef->GetBinContent(refEtaBinA, cBin, GetBinNumberCos(n));
+       Double_t sinP1nPhiA = fCumuNUARef->GetBinContent(refEtaBinA, cBin, GetBinNumberSin(n));
+       Double_t cosP1nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberCos(n));
+       Double_t sinP1nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberSin(n));       
+       Double_t cos2nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberCos(2*n));
+       Double_t sin2nPhiB = fCumuNUARef->GetBinContent(refEtaBinB, cBin, GetBinNumberSin(2*n));  
+       
+       // 2-particle differential flow
+       Double_t w2pTwoPrime = cumuDiff->GetBinContent(etaBin, cBin, kW2Two);
+       Double_t w2p = cumuDiff->GetBinContent(etaBin, cBin, kW2);
+       if (w2p == 0) continue;
+       Double_t cosP1nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberCos(n));
+       Double_t sinP1nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberSin(n));
+       Double_t cos2nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberCos(2*n));
+       Double_t sin2nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberSin(2*n));
+       Double_t twoPrime = w2pTwoPrime / w2p;
+
+       Double_t qc2Prime = twoPrime;
+       cumu2->Fill(eta, cent, qc2Prime);
+       if ((fFlags & kNUAcorr)) {
+         // Old nua
+         qc2Prime -= cosP1nPsi*cosP1nPhiB + sinP1nPsi*sinP1nPhiB;
+         // Extra NUA term from 2n cosines and sines
+         qc2Prime /= (1.-(cos2nPsi*cos2nPhiB + sin2nPsi*sin2nPhiB));
+       }
+       if (!TMath::IsNaN(qc2Prime)) {
+         quality->Fill((n-2)*qualityFactor+3, Int_t(cent));
+         if ((fFlags & kNUAcorr)) cumu2NUAold->Fill(eta, cent, qc2Prime);
+       }
+       else 
+         quality->Fill((n-2)*qualityFactor+4, Int_t(cent));
+       if (fDebug > 1) 
+         AliInfo(Form("%s: QC'_%d{2} = %1.3f for eta = %1.2f and centrality %3.1f", 
+         fType.Data(), n, qc2Prime, eta, cent));
+
+        if (!(fFlags & kStdQC)) continue;
+        // Reference objects
+       Double_t cosP1nPhi1P1nPhi2 = cumuRef->GetBinContent(refEtaBinA, cBin, kCosphi1phi2);
+       Double_t sinP1nPhi1P1nPhi2 = cumuRef->GetBinContent(refEtaBinA, cBin, kSinphi1phi2);
+       Double_t cosP1nPhi1M1nPhi2M1nPhi3 = cumuRef->GetBinContent(refEtaBinA, cBin, kCosphi1phi2phi3m);
+       Double_t sinP1nPhi1M1nPhi2M1nPhi3 = cumuRef->GetBinContent(refEtaBinA, cBin, kSinphi1phi2phi3m);
+       Double_t multm1m2 = cumuRef->GetBinContent(refEtaBinA, cBin, k3pWeight);
+       cosP1nPhi1P1nPhi2 /= w2;
+       sinP1nPhi1P1nPhi2 /= w2;
+       cosP1nPhi1M1nPhi2M1nPhi3 /= multm1m2;
+       sinP1nPhi1M1nPhi2M1nPhi3 /= multm1m2;
+
+       // 4-particle differential flow
+       Double_t w4pFourPrime = cumuDiff->GetBinContent(etaBin, cBin, kW4Four);
+       Double_t w4p = cumuDiff->GetBinContent(etaBin, cBin, kW4);
+       Double_t mpqMult = cumuDiff->GetBinContent(etaBin, cBin, k3pWeight);
+       if (w4p == 0 || mpqMult == 0) continue;
+       Double_t cosP1nPsi1P1nPhi2 = cumuDiff->GetBinContent(etaBin, cBin, kCosphi1phi2);
+       Double_t sinP1nPsi1P1nPhi2 = cumuDiff->GetBinContent(etaBin, cBin, kSinphi1phi2);
+       Double_t cosP1nPsi1M1nPhi2M1nPhi3 = cumuDiff->GetBinContent(etaBin, cBin, kCosphi1phi2phi3m);
+       Double_t sinP1nPsi1M1nPhi2M1nPhi3 = cumuDiff->GetBinContent(etaBin, cBin, kSinphi1phi2phi3m);
+       Double_t cosP1nPsi1P1nPhi2M1nPhi3 = cumuDiff->GetBinContent(etaBin, cBin, kCosphi1phi2phi3p);
+       Double_t sinP1nPsi1P1nPhi2M1nPhi3 = cumuDiff->GetBinContent(etaBin, cBin, kSinphi1phi2phi3p); 
+       
+       cosP1nPsi1P1nPhi2 /= w2p;
+       sinP1nPsi1P1nPhi2 /= w2p;
+       cosP1nPsi1M1nPhi2M1nPhi3 /= mpqMult;
+       sinP1nPsi1M1nPhi2M1nPhi3 /= mpqMult;
+       cosP1nPsi1P1nPhi2M1nPhi3 /= mpqMult;
+       sinP1nPsi1P1nPhi2M1nPhi3 /= mpqMult;
+       
+       Double_t fourPrime = w4pFourPrime / w4p;
+       Double_t qc4Prime = fourPrime-2.*twoPrime*two; 
+       cumu4->Fill(eta, cent, qc4Prime);
+
+       if ((fFlags & kNUAcorr)) {
+         qc4Prime += - cosP1nPsi*cosP1nPhi1M1nPhi2M1nPhi3
+                     + sinP1nPsi*sinP1nPhi1M1nPhi2M1nPhi3
+                     - cosP1nPhiA*cosP1nPsi1M1nPhi2M1nPhi3
+                     + sinP1nPhiA*sinP1nPsi1M1nPhi2M1nPhi3
+                     - 2.*cosP1nPhiA*cosP1nPsi1P1nPhi2M1nPhi3
+                     - 2.*sinP1nPhiA*sinP1nPsi1P1nPhi2M1nPhi3
+                     - cosP1nPsi1P1nPhi2*cosP1nPhi1P1nPhi2
+                     - sinP1nPsi1P1nPhi2*sinP1nPhi1P1nPhi2
+                     + 2.*cosP1nPhi1P1nPhi2*(cosP1nPsi*cosP1nPhiA-sinP1nPsi*sinP1nPhiA)
+                     + 2.*sinP1nPhi1P1nPhi2*(cosP1nPsi*sinP1nPhiA+sinP1nPsi*cosP1nPhiA)
+                     + 4.*two*(cosP1nPsi*cosP1nPhiA+sinP1nPsi*sinP1nPhiA) 
+                     + 2.*cosP1nPsi1P1nPhi2*(TMath::Power(cosP1nPhiA,2.)-TMath::Power(sinP1nPhiA,2.))
+                     + 4.*sinP1nPsi1P1nPhi2*cosP1nPhiA*sinP1nPhiA
+                     + 4.*twoPrime*(TMath::Power(cosP1nPhiA,2.)+TMath::Power(sinP1nPhiA,2.))
+                     - 6.*(TMath::Power(cosP1nPhiA,2.)-TMath::Power(sinP1nPhiA,2.)) 
+                     * (cosP1nPsi*cosP1nPhiA-sinP1nPsi*sinP1nPhiA)
+                     - 12.*cosP1nPhiA*sinP1nPhiA
+                     * (sinP1nPsi*cosP1nPhiA+cosP1nPsi*sinP1nPhiA);
+       }
+//     Double_t vnFourDiff = - qc4Prime / TMath::Power(-qc4, 0.75);
+       if (!TMath::IsNaN(qc4Prime*mpqMult)) {
+         quality->Fill((n-2)*qualityFactor+7, Int_t(cent));
+         if ((fFlags & kNUAcorr)) cumu4NUA->Fill(eta, cent, qc4Prime);
+       }
+       else 
+         quality->Fill((n-2)*qualityFactor+8, Int_t(cent));
+       if (fDebug > 1) 
+         AliInfo(Form("%s: v_%d{4} = %1.3f for eta = %1.2f and centrality %3.1f", 
+         fType.Data(), n, qc4Prime, eta, cent));
+      } // End of eta loop
+    } // End of centrality loop
+  } // End of moment
+
+  return;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::Calculate3CorFlow(CumuHistos& cumu2h, TH2I* quality, TH1D* chist,
+                                                        TH2D* dNdetaRef, TH2D* dNdetaDiff) const  
+{
+  // 
+  //  Calculates the 3 sub flow
+  //
+  //  Parameters:
+  //   cumu2h: CumuHistos object with QC{2} cumulants
+  //   quality: Histogram for success rate of cumulants
+  //   chist: Centrality histogram
+  //   dNdetaDiff: dN/deta histogram for estimating multiplicity used for diff calculations
+  //
+
+  // For flow calculations
+  TH3D* cumuRef = 0; 
+  TH3D* cumuDiff = 0; 
+  TH2D* cumu2r = 0;
+  TH2D* cumu2rNUAold = 0;
+  TH2D* cumu2rNUA = 0;
+  TH2D* cumu2a = 0;
+  TH2D* cumu2aNUAold = 0;
+  TH2D* cumu2aNUA = 0;
+  TH2D* cumu2b = 0;
+  TH2D* cumu2bNUAold = 0;
+  TH2D* cumu2bNUA = 0;
+  // Loop over cumulant histogram for final calculations 
+  for (Int_t n = 2; n <= fMaxMoment; n++) { // Moment loop begins
+    cumu2r = (TH2D*)cumu2h.Get('r', n, CumuHistos::kNoNUA);
+    cumu2a = (TH2D*)cumu2h.Get('a', n, CumuHistos::kNoNUA);
+    cumu2b = (TH2D*)cumu2h.Get('b', n, CumuHistos::kNoNUA);
+    if ((fFlags & kNUAcorr)) {
+      cumu2rNUAold = (TH2D*)cumu2h.Get('r', n, CumuHistos::kNUAOld);
+      cumu2rNUA = (TH2D*)cumu2h.Get('r', n, CumuHistos::kNUA);
+      cumu2aNUAold = (TH2D*)cumu2h.Get('a', n, CumuHistos::kNUAOld);
+      cumu2aNUA = (TH2D*)cumu2h.Get('a', n, CumuHistos::kNUA);
+      cumu2bNUAold = (TH2D*)cumu2h.Get('b', n, CumuHistos::kNUAOld);
+      cumu2bNUA = (TH2D*)cumu2h.Get('b', n, CumuHistos::kNUA);
+    }
+    cumuRef  = (TH3D*)fCumuHists.Get('r',n);
+    cumuDiff = (TH3D*)fCumuHists.Get('d',n);
+    for (Int_t cBin = 1; cBin <= cumuRef->GetNbinsY(); cBin++) { // Centrality loop begins
+      Double_t cent = cumuRef->GetYaxis()->GetBinCenter(cBin);
+      if (n == 2) chist->Fill(cent, cumuRef->GetBinContent(0, cBin, 0));
+      if (fDebug > 0) AliInfo(Form("%s - v_%d: centrality %3.1f:..", fType.Data(), n, cent));
+      // Here it starts!
+      Int_t prevLim = 0;
+      Int_t aLow = 0, aHigh = 0, bLow = 0, bHigh = 0;
+      Double_t cosP1nPhiA = 0;
+      Double_t sinP1nPhiA = 0;
+      Double_t cos2nPhiA = 0;
+      Double_t sin2nPhiA = 0;
+      Double_t cosP1nPhiB = 0;
+      Double_t sinP1nPhiB = 0;
+      Double_t cos2nPhiB = 0;
+      Double_t sin2nPhiB = 0;
+      Double_t multA = 0;
+      Double_t multB = 0;
+
+      for (Int_t etaBin = 1; etaBin <= cumuDiff->GetNbinsX(); etaBin++) { // Eta loop begins
+       Double_t eta = cumuDiff->GetXaxis()->GetBinCenter(etaBin);
+       // 2-particle reference flow
+       Double_t w2Two = cumuRef->GetBinContent(etaBin, cBin, kW2Two);
+       Double_t w2 = cumuRef->GetBinContent(etaBin, cBin, kW2);
+       if (w2 == 0) continue;
+
+       // Update NUA for new range!
+       if (fEtaLims[prevLim] < eta) {
+         GetLimits(prevLim, aLow, aHigh, bLow, bHigh);
+         prevLim++;
+         cosP1nPhiA = 0; sinP1nPhiA = 0; cos2nPhiA = 0; sin2nPhiA = 0; multA = 0;
+         cosP1nPhiB = 0; sinP1nPhiB = 0; cos2nPhiB = 0; sin2nPhiB = 0; multB = 0;
+         for (Int_t a = aLow; a <= aHigh; a++) {
+           cosP1nPhiA += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberCos(n));
+           sinP1nPhiA += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberSin(n));
+           cos2nPhiA += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberCos(2*n));
+           sin2nPhiA += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberSin(2*n));
+           multA += fCumuNUARef->GetBinContent(a, cBin, 0);
+         }
+         for (Int_t b = bLow; b <= bHigh; b++) {
+           cosP1nPhiB += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberCos(n));
+           sinP1nPhiB += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberSin(n));
+           cos2nPhiB += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberCos(2*n));
+           sin2nPhiB += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberSin(2*n));
+           multB += fCumuNUARef->GetBinContent(b, cBin, 0);
+         }
+         if (multA == 0 || multB == 0) AliFatal("Empty NUA values for 3Cor!");
+         cosP1nPhiA /= multA;
+         sinP1nPhiA /= multA;
+         cos2nPhiA /= multA;
+         sin2nPhiA /= multA;
+         cosP1nPhiB /= multB;
+         sinP1nPhiB /= multB;
+         cos2nPhiB /= multB;
+         sin2nPhiB /= multB;
+
+         dNdetaRef->Fill(eta, cent, multA+multB);
+       }
+       Double_t two = w2Two / w2;
+  
+       Double_t qc2 = two;
+        if (qc2 >= 0) cumu2r->Fill(eta, cent, TMath::Sqrt(qc2));
+
+       if ((fFlags & kNUAcorr)) {
+         // Old nua
+         qc2 -= cosP1nPhiA*cosP1nPhiB + sinP1nPhiA*sinP1nPhiB;
+         // Extra NUA term from 2n cosines and sines
+         qc2 /= (1-(cos2nPhiA*cos2nPhiB + sin2nPhiA*sin2nPhiB));
+       }
+       if (qc2 <= 0) { 
+         if (fDebug > 0) 
+           AliInfo(Form("%s: QC_%d{2} = %1.3f for eta = %1.2f and centrality %3.1f - skipping", 
+           fType.Data(), n, qc2, eta, cent));
+         quality->Fill((n-2)*4+2, Int_t(cent));
+         continue;
+       }
+       Double_t vnTwo = TMath::Sqrt(qc2);
+       if (!TMath::IsNaN(vnTwo)) { 
+         quality->Fill((n-2)*4+1, Int_t(cent));
+         if ((fFlags & kNUAcorr)) cumu2rNUAold->Fill(eta, cent, vnTwo);
+       }
+
+       // 2-particle differential flow
+       Double_t w2pTwoPrimeA = cumuDiff->GetBinContent(etaBin, cBin, kW2Two);
+       Double_t w2pA = cumuDiff->GetBinContent(etaBin, cBin, kW2);
+       Double_t w2pTwoPrimeB = cumuDiff->GetBinContent(etaBin, cBin, kW4Four);
+       Double_t w2pB = cumuDiff->GetBinContent(etaBin, cBin, kW4);
+       if (w2pA == 0 || w2pB == 0) continue;
+       Double_t cosP1nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberCos(n));
+       Double_t sinP1nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberSin(n));
+       Double_t cos2nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberCos(2*n));
+       Double_t sin2nPsi = fCumuNUADiff->GetBinContent(etaBin, cBin, GetBinNumberSin(2*n));
+        Double_t mult = fCumuNUADiff->GetBinContent(etaBin, cBin, 0);
+        if (mult == 0) continue;
+        cosP1nPsi /= mult;
+        sinP1nPsi /= mult;
+        cos2nPsi /= mult;
+        sin2nPsi /= mult;
+       Double_t twoPrimeA = w2pTwoPrimeA / w2pA;
+       Double_t twoPrimeB = w2pTwoPrimeB / w2pB;
+       dNdetaDiff->Fill(eta, cent, mult);
+
+       Double_t qc2PrimeA = twoPrimeA;
+       Double_t qc2PrimeB = twoPrimeB;
+       if (qc2PrimeA*qc2PrimeB >= 0) {
+         cumu2a->Fill(eta, cent, qc2PrimeA);
+         cumu2b->Fill(eta, cent, qc2PrimeB);
+       }
+       if ((fFlags & kNUAcorr)) {
+         // Old nua
+         qc2PrimeA -= cosP1nPsi*cosP1nPhiA + sinP1nPsi*sinP1nPhiA;
+         qc2PrimeB -= cosP1nPsi*cosP1nPhiB + sinP1nPsi*sinP1nPhiB; // Is this OK?
+         // Extra NUA term from 2n cosines and sines
+         qc2PrimeA /= (1.-(cos2nPsi*cos2nPhiA + sin2nPsi*sin2nPhiA));
+         qc2PrimeB /= (1.-(cos2nPsi*cos2nPhiB + sin2nPsi*sin2nPhiB));
+       }
+       if (!TMath::IsNaN(qc2PrimeA) && !TMath::IsNaN(qc2PrimeB) && qc2 != 0) {
+       if (qc2PrimeA*qc2PrimeB >= 0) {
+         quality->Fill((n-2)*4+3, Int_t(cent));
+         if ((fFlags & kNUAcorr)) cumu2aNUAold->Fill(eta, cent, qc2PrimeA);
+         if ((fFlags & kNUAcorr)) cumu2bNUAold->Fill(eta, cent, qc2PrimeB);
+       }
       }
       else 
-       quality->Fill((fMoment-2)*8+8);
+       quality->Fill((n-2)*4+4, Int_t(cent));
+       if (fDebug > 1) 
+         AliInfo(Form("%s: QC'a_%d{2} = %1.3f, QC'b_%d{2} = %1.3f for eta = %1.2f and centrality %3.1f", 
+         fType.Data(), n, qc2PrimeA, n, qc2PrimeB, eta, cent));
+      } // End of eta loop
+    } // End of centrality loop
+  } // End of moment
 
-      if (fDebug > 1) AliInfo(Form("%s: v_%d{4} = %1.3f for eta = %1.2f and centrality %3.1f", fType.Data(), fMoment, vnFourDiff, eta, cent));
+  return;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::SolveCoupledFlowEquations(CumuHistos& cumu, const Char_t type) const  
+{
+  // 
+  //  Function to solve the coupled flow equations
+  //  We solve it by using matrix calculations:
+  //  A*v_n = V => v_n = A^-1*V
+  //  First we set up a TMatrixD container to make ROOT
+  //  do the inversions in an efficient way, we multiply the current <<2>> estimates.
+  //  Then we fill new TH2D's if the corrected <<2>>'s (cumuNUA object).
+  //
+  //  Parameters:
+  //   cumu: CumuHistos object - uncorrected
+  //   type: Reference ('r') or differential ('d') or ('a' or 'b') for 3 correlator
+  //
+
+  // We start by declaring Matrix and vector objects, as their constructors are quite heavy
+  TMatrixD mNUA(fMaxMoment-1, fMaxMoment-1);
+  TVectorD vQC2(fMaxMoment-1);
+
+  for (Int_t cBin = 1; cBin <= cumu.Get(type, 2, CumuHistos::kNUAOld)->GetNbinsY(); cBin++) { // cent loop
+    Double_t cent = cumu.Get(type, 2, CumuHistos::kNUAOld)->GetYaxis()->GetBinCenter(cBin);
+    for (Int_t eBin = 1; eBin <= cumu.Get(type, 2, CumuHistos::kNUAOld)->GetNbinsX(); eBin++) { // eta loop
+      Double_t eta = cumu.Get(type, 2, CumuHistos::kNUAOld)->GetXaxis()->GetBinCenter(eBin);
+      mNUA.Zero(); // reset matrix
+      vQC2.Zero(); // reset vector
+      for (Int_t n = 0; n < fMaxMoment-1; n++) { // moment loop
+       vQC2(n) = static_cast<TH2D*>(cumu.Get(type, n+2, CumuHistos::kNUAOld))->GetBinContent(eBin, cBin);
+       if (type == 'r' || type == 'R') vQC2(n) *= vQC2(n); // going back to <<2>>
+       for (Int_t m = 0; m < fMaxMoment-1; m++) { // cross moment
+         mNUA(n,m) = CalculateNUAMatrixElement(n, m, type, eBin, cBin);
+       } // End of cross moment loop
+      } // End of moment loop
+      // Invert matrix
+      Double_t det = 0;
+      mNUA.Invert(&det);
+      // If determinant is non-zero we go with corrected results
+      if (det != 0 ) vQC2 = mNUA*vQC2;
+      else AliWarning(Form("Determinant == 0 - cent: %d-%d, eta: %f, type: '%c', data: %s, vtx: %d-%d%s", 
+                     Int_t(cumu.Get(type, 2, CumuHistos::kNUAOld)->GetYaxis()->GetBinLowEdge(cBin)), 
+                     Int_t(cumu.Get(type, 2, CumuHistos::kNUAOld)->GetYaxis()->GetBinUpEdge(cBin)),
+                     cumu.Get(type, 2, CumuHistos::kNUAOld)->GetXaxis()->GetBinCenter(eBin), 
+                     type, fType.Data(), fVzMin, fVzMax, 
+                     ((fFlags & kEtaGap) ? ", eta-gap" : "")));
+      // Go back to v_n for ref. keep <<2'>> for diff. flow).
+      for (Int_t n = 0; n < fMaxMoment-1; n++) {
+       Double_t vnTwo = 0;
+        if (type == 'r' || type == 'R') 
+          vnTwo = (vQC2(n) > 0. ? TMath::Sqrt(vQC2(n)) : 0.);
+        else {
+          // is really more <<2'>> in this case
+         vnTwo = vQC2(n);
+       }
+        // Fill in corrected v_n
+       if (vnTwo != 0) static_cast<TH2D*>(cumu.Get(type, n+2, CumuHistos::kNUA))->Fill(eta, cent, vnTwo);
+      } // End of moment loop
     } // End of eta loop
   } // End of centrality loop
-  cumu2Sum->Add(cumu2);
-  if (!(fFlags & kEtaGap)) cumu4Sum->Add(cumu4);
-
   return;
 }
 //_____________________________________________________________________
-void AliForwardFlowTaskQC::VertexBin::SetupCentAxis(TAxis* axis)  
+Double_t AliForwardFlowTaskQC::VertexBin::CalculateNUAMatrixElement(Int_t n, Int_t m, Char_t type, Int_t binA, Int_t cBin) const  
 {
-  // 
-  // Setup centrality axis for histogram
+  //  
+  //  Calculates the (n,m)-th element in the NUA matrix: 1 if n == m, otherwise:
+  //               <<cos[(n-m)phi1]>>*<<cos[(n-m)phi2]>> + <<sin[(n-m)phi1]>>*<<sin[(n-m)phi2]>>
+  //    NUA(n,m) = -----------------------------------------------------------------------------
+  //                   1 + <<cos[2nphi1]>>*<<cos[2nphi2]>> + <<sin[2nphi1]>>*<<sin[2nphi2]>>
   //
-  // Parameters:
-  //  axis: centrality axis
+  //               <<cos[(n+m)phi1]>>*<<cos[(n+m)phi2]>> + <<sin[(n+m)phi1]>>*<<sin[(n+m)phi2]>>
+  //             + -----------------------------------------------------------------------------
+  //                   1 + <<cos[2nphi1]>>*<<cos[2nphi2]>> + <<sin[2nphi1]>>*<<sin[2nphi2]>>
   //
-  if (!axis) {
-    AliError("Null pointer passed for axis");
-    return;
+  //  Parameters:
+  //   n: row
+  //   m: coumn
+  //   type: Reference ('r') or differential ('d') or ('a' or 'b')
+  //   binA: eta bin of phi1
+  //   cBin: centrality bin
+  //
+  //  Return: NUA(n,m)
+  //
+  if (n == m) return 1.;
+  n += 2;
+  m += 2;
+
+  Double_t cosnMmPhi1 = 0, cosnMmPhi2 = 0, sinnMmPhi1 = 0, sinnMmPhi2 = 0;
+  Double_t cosnPmPhi1 = 0, cosnPmPhi2 = 0, sinnPmPhi1 = 0, sinnPmPhi2 = 0;
+  Double_t cos2nPhi1 = 0, cos2nPhi2 = 0, sin2nPhi1 = 0, sin2nPhi2 = 0;
+
+  // reference flow
+  if (type == 'r' || type == 'R') {
+    if ((fFlags & k3Cor)) {
+      Double_t eta = fCumuNUARef->GetXaxis()->GetBinCenter(binA);
+      Int_t i = 0;
+      while (fEtaLims[i] < eta) i++;
+      Int_t aLow = 0, aHigh = 0, bLow = 0, bHigh = 0;
+      GetLimits(i-1, aLow, aHigh, bLow, bHigh);
+      Double_t multA = 0, multB = 0;
+      for (Int_t a = aLow; a <= aHigh; a++) {
+       cosnMmPhi1 += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberCos(n-m));
+       sinnMmPhi1 += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberSin(n-m));
+       cosnPmPhi1 += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberCos(n+m));
+       sinnPmPhi1 += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberSin(n+m));
+       cos2nPhi1 += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberCos(2*n));
+       sin2nPhi1 += fCumuNUARef->GetBinContent(a, cBin, GetBinNumberSin(2*n));
+       multA += fCumuNUARef->GetBinContent(a, cBin, 0);
+      }
+       for (Int_t b = bLow; b <= bHigh; b++) {
+       cosnMmPhi2 += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberCos(n-m));
+       sinnMmPhi2 += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberSin(n-m));
+       cosnPmPhi2 += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberCos(n+m));
+       sinnPmPhi2 += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberSin(n+m));
+       cos2nPhi2 += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberCos(2*n));
+       sin2nPhi2 += fCumuNUARef->GetBinContent(b, cBin, GetBinNumberSin(2*n));
+       multB += fCumuNUARef->GetBinContent(b, cBin, 0);
+      }
+      if (multA == 0 || multB == 0) {
+        if (fDebug > 0) AliWarning("multA or multB == 0 in matrix elements, aborting NUA");
+        return 0.;
+      }
+      cosnMmPhi1 /= multA;
+      sinnMmPhi1 /= multA;
+      cosnPmPhi1 /= multA;
+      sinnPmPhi1 /= multA;
+      cos2nPhi1 /= multA; 
+      sin2nPhi1 /= multA;
+      cosnMmPhi2 /= multB;
+      sinnMmPhi2 /= multB;
+      cosnPmPhi2 /= multB;
+      sinnPmPhi2 /= multB;
+      cos2nPhi2 /= multB; 
+      sin2nPhi2 /= multB;
+    } else {
+      Int_t binB = fCumuNUARef->GetXaxis()->FindBin(-fCumuNUARef->GetXaxis()->GetBinCenter(binA));
+      cosnMmPhi1 = fCumuNUARef->GetBinContent(binA, cBin, GetBinNumberCos(n-m));
+      sinnMmPhi1 = fCumuNUARef->GetBinContent(binA, cBin, GetBinNumberSin(n-m));
+      cosnPmPhi1 = fCumuNUARef->GetBinContent(binA, cBin, GetBinNumberCos(n+m));
+      sinnPmPhi1 = fCumuNUARef->GetBinContent(binA, cBin, GetBinNumberSin(n+m));
+      cos2nPhi1 = fCumuNUARef->GetBinContent(binA, cBin, GetBinNumberCos(2*n));
+      sin2nPhi1 = fCumuNUARef->GetBinContent(binA, cBin, GetBinNumberSin(2*n));
+      cosnMmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberCos(n-m));
+      sinnMmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberSin(n-m));
+      cosnPmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberCos(n+m));
+      sinnPmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberSin(n+m));
+      cos2nPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberCos(2*n));
+      sin2nPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberSin(2*n));
+    }
+  } // differential flow
+  else if (type == 'd' || type == 'D') {
+    Int_t binB = fCumuNUARef->GetXaxis()->FindBin(-fCumuNUADiff->GetXaxis()->GetBinCenter(binA));
+    cosnMmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberCos(n-m));
+    sinnMmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberSin(n-m));
+    cosnPmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberCos(n+m));
+    sinnPmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberSin(n+m));
+    cos2nPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberCos(2*n));
+    sin2nPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberSin(2*n));
+    cosnMmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberCos(n-m));
+    sinnMmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberSin(n-m));
+    cosnPmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberCos(n+m));
+    sinnPmPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberSin(n+m));
+    cos2nPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberCos(2*n));
+    sin2nPhi2 = fCumuNUARef->GetBinContent(binB, cBin, GetBinNumberSin(2*n));
+  } // 3 correlator part a or b
+  else if (type == 'a' || type == 'A' || type == 'b' || type == 'B') {
+    Double_t mult1 = 0, mult2 = 0;
+    // POIs
+    cosnMmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberCos(n-m));
+    sinnMmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberSin(n-m));
+    cosnPmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberCos(n+m));
+    sinnPmPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberSin(n+m));
+    cos2nPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberCos(2*n));
+    sin2nPhi1 = fCumuNUADiff->GetBinContent(binA, cBin, GetBinNumberSin(2*n));
+    mult1 = fCumuNUADiff->GetBinContent(binA, cBin, 0);
+    // RPs
+    Double_t eta = fCumuNUADiff->GetXaxis()->GetBinCenter(binA);
+    Int_t i = 0;
+    while (fEtaLims[i] < eta) i++;
+    Int_t aLow = 0, aHigh = 0, bLow = 0, bHigh = 0;
+    GetLimits(i-1, aLow, aHigh, bLow, bHigh);
+    Int_t lLow = ((type == 'a' || type == 'A') ? aLow : bLow);
+    Int_t lHigh = ((type == 'a' || type == 'A') ? aHigh : bHigh);
+    for (Int_t l = lLow; l <= lHigh; l++) {
+      cosnMmPhi2 += fCumuNUARef->GetBinContent(l, cBin, GetBinNumberCos(n-m));
+      sinnMmPhi2 += fCumuNUARef->GetBinContent(l, cBin, GetBinNumberSin(n-m));
+      cosnPmPhi2 += fCumuNUARef->GetBinContent(l, cBin, GetBinNumberCos(n+m));
+      sinnPmPhi2 += fCumuNUARef->GetBinContent(l, cBin, GetBinNumberSin(n+m));
+      cos2nPhi2 += fCumuNUARef->GetBinContent(l, cBin, GetBinNumberCos(2*n));
+      sin2nPhi2 += fCumuNUARef->GetBinContent(l, cBin, GetBinNumberSin(2*n));
+      mult2 += fCumuNUARef->GetBinContent(l, cBin, 0);
+    }
+    if (mult1 == 0 || mult2 == 0) { 
+      if (fDebug > 0) AliWarning("mult1 or mult2 == 0 in matrix elements, aborting NUA");
+      return 0.;
+    }
+    cosnMmPhi1 /= mult1;
+    sinnMmPhi1 /= mult1;
+    cosnPmPhi1 /= mult1;
+    sinnPmPhi1 /= mult1;
+    cos2nPhi1 /= mult1; 
+    sin2nPhi1 /= mult1;
+    cosnMmPhi2 /= mult2;
+    sinnMmPhi2 /= mult2;
+    cosnPmPhi2 /= mult2;
+    sinnPmPhi2 /= mult2;
+    cos2nPhi2 /= mult2; 
+    sin2nPhi2 /= mult2;
   }
 
-  if ((fFlags & kSatVtx)) {
-    Double_t cent[3] = {0, 40, 100};
-    axis->Set(2, cent);
-  } else {
-    Double_t cent[13] = {0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100 };
-//    Double_t cent[13] = {0, 2.5, 15, 25, 50, 60, 70, 80, 90, 100, 110, 115, 120 };
-    axis->Set(12, cent);
+  // Actual calculation
+  Double_t e = cosnMmPhi1*cosnMmPhi2 + sinnMmPhi1*sinnMmPhi2 + cosnPmPhi1*cosnPmPhi2 + sinnPmPhi1*sinnPmPhi2;
+  Double_t den = 1 + cos2nPhi1*cos2nPhi2 + sin2nPhi1*sin2nPhi2;
+  if (den != 0) e /= den;
+  else return 0.;
+
+  return e;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::AddVertexBins(CumuHistos& cumu, TList* list, UInt_t nNUA) const  
+{
+  //
+  //  Add up vertex bins with flow results
+  //
+  //  Parameters:
+  //   cumu: CumuHistos object with vtxbin results
+  //   list: Outout list with added results
+  //   nNUA: # of NUA histograms to loop over
+  //
+  TH2D* vtxHist = 0;
+  TProfile2D* avgProf = 0;
+  TString name;
+  Int_t nT = ((fFlags & k3Cor) ? 3 : 2);
+  Char_t ct = '\0';
+  for (UInt_t nua = 0; nua <= nNUA; nua++) { // NUA loop
+    for (Int_t n = 2; n <= fMaxMoment; n++) { // moment loop
+      for (Int_t t = 0; t < nT; t++) { // type loop (r/d/a/b)
+        // Find type
+        switch (t) {
+          case 0: ct = 'r'; break;
+          case 1: ct = ((fFlags & k3Cor) ? 'a' : 'd'); break;
+          case 2: ct = 'b'; break;
+          default: ct = '\0'; break;
+       }
+       vtxHist = static_cast<TH2D*>(cumu.Get(ct,n,nua));
+       if (!vtxHist) {
+         AliWarning("VertexBin::AddVertexBins: vtxHist not found!");
+         continue;
+       }
+       name = vtxHist->GetName();
+       // Strip name of vtx info
+       Ssiz_t l = name.Last('x')-3;
+       name.Resize(l);
+       avgProf = (TProfile2D*)list->FindObject(name.Data());
+       // if no output profile yet, make one
+       if (!avgProf) {
+         avgProf = new TProfile2D(name.Data(), name.Data(), 
+             vtxHist->GetNbinsX(), vtxHist->GetXaxis()->GetXmin(), vtxHist->GetXaxis()->GetXmax(),
+             vtxHist->GetNbinsY(), vtxHist->GetYaxis()->GetXmin(), vtxHist->GetYaxis()->GetXmax());
+         if (vtxHist->GetXaxis()->IsVariableBinSize()) 
+           avgProf->GetXaxis()->Set(vtxHist->GetNbinsX(), vtxHist->GetXaxis()->GetXbins()->GetArray());
+         if (vtxHist->GetYaxis()->IsVariableBinSize()) 
+           avgProf->GetYaxis()->Set(vtxHist->GetNbinsY(), vtxHist->GetYaxis()->GetXbins()->GetArray());
+         list->Add(avgProf);
+       }
+       // Fill in, cannot be done with Add function.
+       for (Int_t e = 1; e <= vtxHist->GetNbinsX(); e++) { // eta loop
+         Double_t eta = vtxHist->GetXaxis()->GetBinCenter(e);
+         for (Int_t c = 1; c <= vtxHist->GetNbinsY(); c++) { // cent loop
+           Double_t cent = vtxHist->GetYaxis()->GetBinCenter(c);
+           Double_t cont = vtxHist->GetBinContent(e, c);
+           if (cont == 0) continue;
+           avgProf->Fill(eta, cent, cont);
+         } // End of cent loop
+       } //  End of eta loop
+      } // End of type loop
+    } // End of moment loop
+  } // End of nua loop
+}
+//_____________________________________________________________________
+Int_t AliForwardFlowTaskQC::VertexBin::GetBinNumberCos(Int_t n) const  
+{
+  //
+  //  Get the bin number of <<cos(nphi)>>
+  //
+  //  Parameters:
+  //   n: moment
+  //
+  //  Return: bin number
+  //
+  Int_t bin = 0;
+  n = TMath::Abs(n);
+  
+  if (n == 0) bin = fMaxMoment*4-1;
+  else        bin = n*2-1;
+  
+  return bin;
+}
+//_____________________________________________________________________
+Int_t AliForwardFlowTaskQC::VertexBin::GetBinNumberSin(Int_t n) const  
+{
+  //
+  //  Get the bin number of <<sin(nphi)>>
+  //
+  //  Parameters:
+  //   n: moment
+  //
+  //  Return: bin number
+  //
+  Int_t bin = 0;
+  n = TMath::Abs(n);
+  
+  if (n == 0) bin = fMaxMoment*4;
+  else        bin = n*2;
+
+  return bin;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::VertexBin::SetupNUALabels(TAxis* a) const
+{
+  // 
+  //  Setup NUA labels on axis
+  //
+  //  Parameters:
+  //   a: Axis to set up
+  //
+  if (a->GetNbins() != GetBinNumberSin()) AliFatal("SetupNUALabels: Wrong number of bins on axis");
+
+  Int_t i = 1, j= 1;
+  while (i <= a->GetNbins()) {
+    a->SetBinLabel(i++, Form("<<cos(%d#varphi)>>", j));
+    a->SetBinLabel(i++, Form("<<sin(%d#varphi)>>", j++));
   }
 
   return;
 }
 //_____________________________________________________________________
+TH2I* AliForwardFlowTaskQC::VertexBin::MakeQualityHist(const Char_t* name) const 
+{
+  //
+  //  Add a histogram for checking the analysis quality
+  //
+  //  Parameters:
+  //   const char*: name of data type
+  //
+  //  Return: histogram for tracking successful calculations
+  //
+  Int_t nBins = ((fFlags & kStdQC) ? 8 : 4);
+  TH2I* quality = new TH2I(name, name, (fMaxMoment-1)*nBins, 1, (fMaxMoment-1)*nBins+1, fCumuNUARef->GetNbinsY(), 
+                           fCumuNUARef->GetYaxis()->GetXmin(), fCumuNUARef->GetYaxis()->GetXmax());
+  quality->GetYaxis()->Set(fCumuNUARef->GetNbinsY(), fCumuNUARef->GetYaxis()->GetXbins()->GetArray());
+  for (Int_t i = 2, j = 1; i <= fMaxMoment; i++) {
+    quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{2} > 0", i));
+    quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{2} <= 0", i));
+    quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{2} > 0", i));
+    quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{2} <= 0", i));
+    if ((fFlags & kStdQC)) {
+      quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{4} < 0", i));
+      quality->GetXaxis()->SetBinLabel(j++, Form("QC_{%d}{4} >= 0", i));
+      quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{4} < 0", i));
+      quality->GetXaxis()->SetBinLabel(j++, Form("QC'_{%d}{4} >= 0", i));
+    }
+  }
+
+  return quality;
+}
+//_____________________________________________________________________
+TH2D* AliForwardFlowTaskQC::VertexBin::MakeOutputHist(Int_t qc, Int_t n, const Char_t* ctype, UInt_t nua) const
+{
+  //
+  //  Setup a TH2D for the output
+  //
+  //  Parameters:
+  //   qc   # of particle correlations
+  //   n    flow moment
+  //   ref  Type: r/d/a/b
+  //   nua  For nua corrected hists?
+  //
+  //  Return: 2D hist for results
+  //
+  Bool_t ref = ((ctype[0] == 'R') || (ctype[0] == 'r'));
+  TAxis* xAxis = (ref ? fCumuNUARef->GetXaxis() : fCumuNUADiff->GetXaxis());
+  TAxis* yAxis = (ref ? fCumuNUARef->GetYaxis() : fCumuNUADiff->GetYaxis());
+  TString ntype = "";
+  switch (nua) {
+    case CumuHistos::kNoNUA: ntype = "Un"; break;
+    case CumuHistos::kNUAOld: ntype = "NUAOld"; break;
+    case CumuHistos::kNUA: ntype = "NUA"; break;
+    default: break;
+  }
+  TH2D* h = new TH2D(Form("%sQC%d_v%d_%s_%sCorr%s_vtx_%d_%d", 
+                       fType.Data(), qc, n, ctype, ntype.Data(),
+                       GetQCType(fFlags), fVzMin, fVzMax),
+                     Form("%sQC%d_v%d_%s_%sCorr%s_vtx_%d_%d", 
+                       fType.Data(), qc, n, ctype, ntype.Data(),
+                       GetQCType(fFlags), fVzMin, fVzMax),
+                     xAxis->GetNbins(), xAxis->GetXmin(), xAxis->GetXmax(),
+                     yAxis->GetNbins(), yAxis->GetXmin(), yAxis->GetXmax());
+  if (xAxis->IsVariableBinSize()) h->GetXaxis()->Set(xAxis->GetNbins(), xAxis->GetXbins()->GetArray());
+  h->GetYaxis()->Set(yAxis->GetNbins(), yAxis->GetXbins()->GetArray());
+
+  return h;
+}
+//_____________________________________________________________________
 void AliForwardFlowTaskQC::PrintFlowSetup() const 
 {
   //
-  // Print the setup of the flow task
+  //  Print the setup of the flow task
   //
-  Printf("AliForwardFlowTaskQC::Print");
-  Printf("Number of bins in vertex axis   :\t%d", fVtxAxis->GetNbins());
-  Printf("Range of vertex axis            :\t[%3.1f,%3.1f]", 
+  Printf("=======================================================");
+  Printf("%s::Print", this->IsA()->GetName());
+  Printf("Forward detector:                 :\t%s", ((fFlowFlags & kFMD) ? "FMD" : "VZERO"));
+  Printf("Number of bins in vertex axis     :\t%d", fVtxAxis->GetNbins());
+  Printf("Range of vertex axis              :\t[%3.1f,%3.1f]", 
                          fVtxAxis->GetXmin(), fVtxAxis->GetXmax());
-  printf("Doing flow analysis for         :\t");
-  for (Int_t n  = 0; n < fV.GetSize(); n++) printf("v%d ", fV.At(n));
+  Printf("Number of bins in centrality axis :\t%d", fCentAxis->GetNbins());
+  printf("Centrality binning                :\t");
+  for (Int_t cBin = 1; cBin <= fCentAxis->GetNbins(); cBin++) {
+    printf("%02d-%02d%% ", Int_t(fCentAxis->GetBinLowEdge(cBin)), Int_t(fCentAxis->GetBinUpEdge(cBin)));
+    if (cBin == fCentAxis->GetNbins()) printf("\n");
+    else if (cBin % 4 == 0) printf("\n\t\t\t\t\t");
+  }
+  printf("Doing flow analysis for           :\t");
+  for (Int_t n  = 2; n <= fMaxMoment; n++) printf("v%d ", n);
   printf("\n");
-  Printf("Satellite vertex flag           :\t%s", ((fFlowFlags & kSatVtx) ? "true" : "false"));
-  Printf("Symmetrize ref. flow wrt eta = 0:\t%s", ((fFlowFlags & kSymEta) ? "true" : "false"));
-  Printf("Use an eta-gap for ref. flow    :\t%s", ((fFlowFlags & kEtaGap) ? "true" : "false"));
-  Printf("FMD sigma cut:                  :\t%f", fFMDCut);
-  Printf("SPD sigma cut:                  :\t%f", fSPDCut);
+  TString type = "Standard QC{2} and QC{4} calculations.";
+  if ((fFlowFlags & kTPC)) type.ReplaceAll(".", " with TPC tracks for reference.");
+  if ((fFlowFlags & kEtaGap)) type = "QC{2} with a rapidity gap.";
+  if ((fFlowFlags & k3Cor))   type = "QC{2} with 3 correlators.";
+  Printf("QC calculation type               :\t%s", type.Data());
+  Printf("Symmetrize ref. flow wrt. eta = 0 :\t%s", ((fFlowFlags & kSymEta) ? "true" : "false"));
+  Printf("Apply NUA correction terms        :\t%s", ((fFlowFlags & kNUAcorr) ? "true" : "false"));
+  Printf("Satellite vertex flag             :\t%s", ((fFlowFlags & kSatVtx) ? "true" : "false"));
+  Printf("FMD sigma cut:                    :\t%f", fFMDCut);
+  Printf("SPD sigma cut:                    :\t%f", fSPDCut);
   if ((fFlowFlags & kEtaGap)) 
-    Printf("Eta gap:                        :\t%f", fEtaGap);
+    Printf("Eta gap:                          :\t%f", fEtaGap);
+  Printf("=======================================================");
+}
+//_____________________________________________________________________
+const Char_t* AliForwardFlowTaskQC::GetQCType(UShort_t flags, Bool_t prependUS) 
+{
+  // 
+  //  Get the type of the QC calculations
+  //  Used for naming of objects in the VertexBin class, 
+  //  important to avoid memory problems when running multiple
+  //  initializations of the class with different setups
+  // 
+  //  Parameters:
+  //   flags: Flow flags for type determination
+  //   prependUS: Prepend an underscore (_) to the name
+  // 
+  //  Return: QC calculation type
+  //
+  TString type = "";
+  if      ((flags & kStdQC))  type = "StdQC";
+  else if ((flags & kEtaGap)) type = "EtaGap";
+  else if ((flags & k3Cor))   type = "3Cor";
+  else type = "UNKNOWN";
+  if (prependUS) type.Prepend("_");
+  if ((flags & kTPC)) type.Append("TPCTr");
+  return type.Data();
+}
+//_____________________________________________________________________
+TH1* AliForwardFlowTaskQC::CumuHistos::Get(const Char_t t, Int_t n, UInt_t nua) const
+{
+  //
+  //  Get histogram/profile for type t and moment n
+  //
+  //  Parameters:
+  //   t: type = 'r'/'d'
+  //   n: moment
+  //   nua: NUA type
+  //
+  n = GetPos(n, nua);
+  if (n < 0) AliFatal(Form("CumuHistos out of range: (%c,%d)", t, n));
+
+  TH1* h = 0;
+  Int_t pos = -1;
+  if      (t == 'r' || t == 'R') pos = n;    
+  else if (t == 'd' || t == 'D') pos = n;    
+  else if (t == 'a' || t == 'A') pos = 2*n;  
+  else if (t == 'b' || t == 'B') pos = 2*n+1;
+  else AliFatal(Form("CumuHistos wrong type: %c", t));
+
+  if (t == 'r' || t == 'R') {
+    if (pos < fRefHists->GetEntries()) {
+      h = (TH1*)fRefHists->At(pos);
+    }
+  } else if (pos < fDiffHists->GetEntries()) {
+    h = (TH1*)fDiffHists->At(pos);
+  }
+  if (!h) AliFatal(Form("No hist found in list %c at pos %d", t, pos));
+
+  return h;
+}
+//_____________________________________________________________________
+void AliForwardFlowTaskQC::CumuHistos::ConnectList(TString name, TList* l)
+{
+  //
+  //  Connect an output list with this object
+  //
+  //  Parameters:
+  //   name: base name
+  //   l: list to keep outputs in
+  //
+  TString ref = name;
+  ref.ReplaceAll("Cumu","CumuRef");
+  fRefHists = (TList*)l->FindObject(ref.Data());
+  if (!fRefHists) {
+    fRefHists = new TList();
+    fRefHists->SetName(ref.Data());
+    l->Add(fRefHists);
+  } else {
+    // Check that the list correspond to fMaxMoments
+    if (fRefHists->GetEntries() != (fMaxMoment-1.)*(fNUA+1)) 
+      AliError("CumuHistos::ConnectList Wrong number of hists in ref list,"
+               "you are doing something wrong!");
+  }
+  TString diff = name;
+  diff.ReplaceAll("Cumu","CumuDiff");
+  fDiffHists = (TList*)l->FindObject(diff.Data());
+  if (!fDiffHists) {
+    fDiffHists = new TList();
+    fDiffHists->SetName(diff.Data());
+    l->Add(fDiffHists);
+  } else {
+    // Check that the list correspond to fMaxMoment
+    if ((fDiffHists->GetEntries() != (fMaxMoment-1.)*(fNUA+1)) &&  
+        (fDiffHists->GetEntries() != 2*(fMaxMoment-1.)*(fNUA+1)))  
+      AliError(Form("CumuHistos::ConnectList Wrong number of hists in diff list,"
+               "you are doing something wrong! (%s)",name.Data()));
+  }
 
 }
 //_____________________________________________________________________
+void AliForwardFlowTaskQC::CumuHistos::Add(TH1* h) const
+{
+  //
+  //  Add a histogram to this objects lists
+  //
+  //  Parameters:
+  //   h: histogram/profile to add
+  //
+  TString name = h->GetName();
+  if (name.Contains("Ref")) {
+    if (fRefHists) fRefHists->Add(h);
+    // Check that the list correspond to fMaxMoments
+    if (fRefHists->GetEntries() > (fNUA+1)*(fMaxMoment-1.)) 
+      AliError("CumuHistos::Add wrong number of hists in ref list, "
+               "you are doing something wrong!");
+  }
+  else if (name.Contains("Diff")) {
+    if (fDiffHists) fDiffHists->Add(h);
+    // Check that the list correspond to fMaxMoment
+    if (fDiffHists->GetEntries() > 2*(fNUA+1)*(fMaxMoment-1.)) 
+      AliError("CumuHistos::Add wrong number of hists in diff list, "
+        "you are doing something wrong!");
+  }
+  return;
+}
+//_____________________________________________________________________
+Int_t AliForwardFlowTaskQC::CumuHistos::GetPos(Int_t n, UInt_t nua) const
+{
+  //
+  //  Get position in list of moment n objects
+  //  To take care of different numbering schemes
+  //
+  //  Parameters:
+  //   n: moment
+  //   nua: # of nua corrections applied
+  //
+  //  Return: position #
+  //
+  if (n > fMaxMoment) return -1;
+  else return (n-2)+nua*(fMaxMoment-1);
+}
+//_____________________________________________________________________
 //
 //
 // EOF
index 7a39fa2..897cb39 100644 (file)
@@ -9,18 +9,20 @@
  * 
  * @brief
  * 
- * 
  * @ingroup pwglf_forward_flow
  */
 #include "AliAnalysisTaskSE.h"
 #include "TString.h"
-#include "TArrayI.h"
+#include <TH2D.h>
 class AliAODForwardMult;
+class TH1I;
 class TH1D;
+class TH2I;
 class TH2F;
 class TH2D;
 class TH3D;
 class TAxis;
+class AliESDtrackCuts;
 /**
  * @defgroup pwglf_forward_tasks_flow Flow tasks 
  *
@@ -35,7 +37,7 @@ class TAxis;
  *   - AliAODEvent
  *
  * Outputs:
- *   - AnalysisResults.root
+ *   - forward_flow.root
  *
  * @ingroup pwglf_forward_tasks_flow
  * @ingroup pwglf_forward_flow
@@ -90,20 +92,24 @@ public:
    */
   TList* GetOutputList() { return fOutputList; }
   /**
-   * Set which flow moments to calculate.
-   * 
-   * @param  n Do @f$ v_{n}@f$
+   * Set max flow moment to calculate.
    * 
-   * @return void 
+   * @param  n Do v_2 to v_n
    */
-  void AddFlowMoment(Short_t n); 
+  void SetMaxFlowMoment(Short_t n) { fMaxMoment = n; } 
   /**
-   * Set non-default vertex binning and range
+   * Set vertex binning and range
    *
    * @param axis Use this vtx axis
    */
   void SetVertexAxis(TAxis* axis) { fVtxAxis = axis; }
   /**
+   * Set centrality/multiplicity binning and range
+   *
+   * @param axis Use this binning
+   */
+  void SetCentralityAxis(TAxis* axis) { fCentAxis = axis; }
+  /**
    * Set detector sigma cuts
    *
    * @param fmdCut FMD sigma cut
@@ -112,33 +118,173 @@ public:
   void SetDetectorCuts(Double_t fmdCut, Double_t spdCut) { fFMDCut = fmdCut; fSPDCut = spdCut; }
   /**
    * Set flow flags, @f$\eta@f$-gap, sym. around @f$\eta=0@f$ or
-   * sat. vtx. interactions
+   * sat. vtx. interactions, also sets which forward detector to use
    *
    * @param flags EFlowFlags 
    */
-  void SetFlowFlags(UShort_t flags) { fFlowFlags = flags; }
+  void SetFlowFlags(UShort_t flags);
   /**
-   * Enum for flow flags
-   */
-  enum EFlowFlags {
-    kEtaGap  = 0x1,
-    kSymEta  = 0x2,
-    kSatVtx  = 0x4
-  };
+    * Get QC type
+    *
+    * @param flags EFlowFlags
+    * @param prepensUS prepend an underscore
+    *
+    * @return type
+    */
+  static const Char_t* GetQCType(UShort_t flags, Bool_t prependUS = kTRUE);
   /**
    *  Set @f$|\eta|@f$ value to make cut for @f$\eta@f$ gap at
    *
    * @param eg gap value
    */
   void SetEtaGapValue(Double_t eg) { fEtaGap = eg; }
+  /**
+   * Enum for flow flags
+   */
+  enum EFlowFlags {
+    kStdQC   = 0x001, // Standard QC{2} and QC{4} calculations
+    kEtaGap  = 0x002, // QC{2} w/ an eta-gap
+    k3Cor    = 0x004, // 3 correlator method for QC{2} w/ an eta-gap
+    kSymEta  = 0x008, // Symmetrize ref flow in std. QC{2} and QC{4} around eta = 0
+    kSatVtx  = 0x010, // Do satellite vertex input (currently not implemented)
+    kNUAcorr = 0x020, // Apply full NUA correction
+    kFMD     = 0x040, // Use FMD for forward flow
+    kVZERO   = 0x080, // Use VZERO for forward flow
+    kTPC     = 0x100  // Use TPC tracks for reference flow
+  };
+  /**
+   * struct to handle cumulant calculations and control histograms
+   */
+  struct CumuHistos : public TObject
+  {
+  public:
+    /*
+     * Constructor
+     */
+    CumuHistos() : fMaxMoment(), fRefHists(), fDiffHists(), fNUA() {}
+    /**
+     * Constructor
+     * 
+     * @param n max flow moment contained
+     * @param nua Make room for NUA corrected histograms
+     */
+    CumuHistos(Int_t n, UInt_t nua) : fMaxMoment(n), fRefHists(), fDiffHists(), fNUA(nua) {}
+    /**
+     * Copy constructor 
+     * 
+     * @param o Object to copy from
+     * 
+     * @return CumuHistos
+     */
+    CumuHistos(const CumuHistos& o)
+      : TObject(o),
+        fMaxMoment(o.fMaxMoment), // Max moment to compute
+        fRefHists(o.fRefHists),   // List with ref hists
+        fDiffHists(o.fDiffHists), // List with diff hists
+        fNUA(o.fNUA)
+    {}
+    /**
+     * Assignment operator 
+     * 
+     * @param o Object to assing from
+     * 
+     * @return reference to this 
+     */
+    CumuHistos& operator=(const CumuHistos& o) 
+    { 
+      if (&o == this) return *this;
+      TObject::operator=(o);
+      fMaxMoment = o.fMaxMoment;
+      fRefHists  = o.fRefHists;
+      fDiffHists = o.fDiffHists;
+      fNUA       = o.fNUA;
+      return *this;
+    }
+    /**
+     * Destructor 
+     */
+    ~CumuHistos(){}
+    /**
+     * To access histograms
+     * main function of this class
+     *
+     * @param t (r)eference or (d)iff
+     * @param n    flow moment 
+     * @param nua  nua type
+     * 
+     * @return requested histogram
+     */
+    TH1* Get(const Char_t t, Int_t n, UInt_t nua = 0) const;
+    /**
+     * Connect internal lists to output
+     *
+     * @param name Name of VertexBin
+     * @param l    Output list
+     */
+    void ConnectList(TString name, TList* l);
+    /**
+     * Make histograms to one of the lists
+     *
+     * @param h Hist to add
+     */
+     void Add(TH1* h) const;
+    /** 
+     * Check to see of lists are connected, 
+     * needed for grid/proof
+     *
+     * @return is connected?
+     */
+    Bool_t IsConnected() { return (fRefHists && fDiffHists); }
+    /**
+     * enum for NUA histograms
+     */
+    enum {
+      kNoNUA = 0, // No NUA applied
+      kNUAOld,    // NUA correction from same moment applied
+      kNUA        // Full cross-moment NUA correction applied
+    };
+  protected:
+    /**
+     * Get position of histogram in list
+     *
+     * @param n moment to get position of
+     * @param nua nua type
+     * 
+     * @return position
+     */
+    Int_t GetPos(Int_t n, UInt_t nua) const;
+
+    Int_t  fMaxMoment;  // Max flow moment contained
+    TList* fRefHists;   // List of reference hists
+    TList* fDiffHists;  // List of diff hists
+    UInt_t fNUA;        // NUA tracker
+
+    ClassDef(CumuHistos, 1);
+  }; // End of struct
+
 protected:
   /**
-   * Enum for reference flow (eta-gap) mode
+   * Enum for filling flow histos
    */
-  enum EFillFlow {
-    kFillRef  = 0x1,
-    kFillDiff = 0x2,
-    kFillBoth = 0x3
+  enum {
+    kFillRef  = 0x1, // Fill only ref flow
+    kFillDiff = 0x2, // Fill only diff flow
+    kFillBoth = 0x3, // Fill both
+    kReset    = 0x4, // Reset hists (used with one of the above)
+  };
+  /**
+   * Enum for event diagnostics
+   */
+  enum {
+    kNoEvent = 1, // No event found
+    kNoForward,   // No forward object found
+    kNoCentral,   // No central object found
+    kNoTrigger,   // No (wrong) trigger
+    kNoCent,      // No centrality
+    kInvCent,     // Centrality outside range
+    kNoVtx,       // No vertex
+    kInvVtx,      // Vertex outside range
+    kOK           // Event OK!
   };
   // ----------------- Being nested class ---------------------
   /**
@@ -157,15 +303,15 @@ protected:
      * @param vLow Min vertex z-coordinate
      * @param vHigh Max vertex z-coordinate
      * @param moment Flow moment
-     * @param type Data type (FMD/SPD/FMDTR/SPDTR/MC)
+     * @param type Data type (FMD/VZERO/SPD/FMDTR/SPDTR/MC)
      * @param flags Flags
      * @param cut Cut value 
      * @param etaGap @f$\eta@f$ gap 
      */
     VertexBin(Int_t vLow, Int_t vHigh, 
               UShort_t moment, TString type,
-              UShort_t flags = kSymEta, 
-              Double_t cut = -1, Double_t etaGap = 2.);
+              UShort_t flags, 
+              Double_t cut = -1, Double_t etaGap = -1.);
     /**
      * Copy constructor 
      * 
@@ -190,12 +336,14 @@ protected:
      * Add vertex bin output to list
      * 
      * @param list Histograms are added to this list
+     * @param centAxis Axis to handle centrality binning
      * 
      * @return void 
      */
-    virtual void AddOutput(TList* list);
+    void AddOutput(TList* list, TAxis* centAxis);
     /**
      * Fill reference and differential flow histograms for analysis
+     * using histograms as input
      *
      * @param dNdetadphi 2D data histogram
      * @param cent Centrality
@@ -203,89 +351,183 @@ protected:
      *
      * @return false if bad event (det. hotspot)
      */
-    Bool_t FillHists(const TH2D& dNdetadphi, Double_t cent, EFillFlow mode = kFillBoth);
+    Bool_t FillHists(TH2D& dNdetadphi, Double_t cent, UShort_t mode);
+    /** 
+     * Fill reference and differential flow histograms for analysis 
+     * using tracks as input
+     *
+     * @param trList Array with tracks
+     * @param cent Centrality
+     * @param mode fill ref/diff or both
+     *
+     * @return false if bad event (det. hotspot)
+     */
+    Bool_t FillTracks(TObjArray* trList, UShort_t mode);
     /**
      * Do cumulants calculations for current event with 
      * centrality cent
      * 
      * @param cent Event centrality
-     * @param skipFourP Skip ?
+     */
+    void CumulantsAccumulate(Double_t cent);
+    /**
+     * Do 3 correlator cumulants calculations for current event with 
+     * centrality cent
+     * 
+     * @param cent Event centrality
+     */
+    void CumulantsAccumulate3Cor(Double_t cent);
+    /**
+     * Get limits to do reference flow calculations for 3 correlator method
      *
-     * @return void 
+     * @param bin Differential bin
+     * @param aLow Lowest bin to be used for v_A
+     * @param aHigh Highest bin to be used for v_A
+     * @param bLow Lowest bin to be used for v_B
+     * @param bHigh Highest bin to be used for v_B
      */
-    void CumulantsAccumulate(Double_t cent, Bool_t skipFourP = kFALSE);
+    void GetLimits(Int_t bin, Int_t& aLow, Int_t& aHigh, Int_t& bLow, Int_t& bHigh) const;
     /**
      * Finish cumulants calculations. Takes input and
      * output lists in case Terminate is called separately
      * 
      * @param inlist List with input histograms
      * @param outlist List with output histograms
-     * 
-     * @return void 
      */
     void CumulantsTerminate(TList* inlist, TList* outlist);
-
-  protected:
-    /*
-     * Enumeration for ref/diff histograms
-     */
-    enum { kHmultA = 1, kHmultB, kHQnReA, kHQnImA, kHQnReB, kHQnImB, kHQ2nRe, kHQ2nIm };
     /*
      * Enumeration for cumulant histograms
      */
-    enum { kW2Two = 1, 
-          kW2, 
-          kW4Four, 
-          kW4, 
-          kQnReA, 
-          kQnImA, 
-          kMA,
-          kQnReB, 
-          kQnImB, 
-          kMB,
-          kCosphi1phi2, 
-          kSinphi1phi2, 
-          kCosphi1phi2phi3m, 
-          kSinphi1phi2phi3m, 
-          kMm1m2, 
-          kw2two, 
-          kw2, 
-          kw4four, 
-          kw4, 
-          kpnRe, 
-          kpnIm, 
-          kmp, 
-          kCospsi1phi2, 
-          kSinpsi1phi2, 
-          kCospsi1phi2phi3m, 
-          kSinpsi1phi2phi3m,
-          kmpmq, 
-          kCospsi1phi2phi3p, 
-          kSinpsi1phi2phi3p };
+    enum { kW2Two = 1, // <w2*two>
+          kW2, // <w2>
+          kW4Four, // <w4*four>
+          kW4, // <w4>
+          kCosphi1phi2, // <cos(phi1+phi2)> 
+          kSinphi1phi2, // <sin(phi1+phi2)>
+          kCosphi1phi2phi3m, // <cos(phi1-phi2-phi3)>
+          kSinphi1phi2phi3m, // <sin(phi1-phi2-phi3)>
+          k3pWeight, // M(M-1)(M-1) or (mp*M-2mq)(M-1)
+          kCosphi1phi2phi3p, // <cos(phi1+phi2-phi3)>
+          kSinphi1phi2phi3p // <sin(phi1+phi2-phi3)>
+         };
+  protected:
+    /** 
+     * Calculate reference flow
+     *
+     * @param cumu2 QC2 histos
+     * @param cumu4 QC4 histos
+     * @param quality QC Quality diag. histo
+     * @param chist Centrality histogram
+     * @param dNdetaRef dN/deta histogram
+     */
+    void CalculateReferenceFlow(CumuHistos& cumu2h, CumuHistos& cumu4h, TH2I* quality, TH1D* chist, TH2D* dNdetaRef) const;
+    /** 
+     * Calculate differential flow
+     *
+     * @param cumu2 QC2 histos
+     * @param cumu4 QC4 histos
+     * @param quality QC Quality diag. histo
+     * @param dNdetaDiff dN/deta histogram
+     */
+    void CalculateDifferentialFlow(CumuHistos& cumu2h, CumuHistos& cumu4h, TH2I* quality, TH2D* dNdetaDiff) const;
+    /** 
+     * Calculate 3 correlator ref and fiff flow
+     *
+     * @param cumu2 QC2 histos
+     * @param quality QC Quality diag. histo
+     * @param chist Centrality histogram
+     * @param dNdetaRef dN/deta histogram
+     * @param dNdetaDiff dN/deta histogram
+     */
+    void Calculate3CorFlow(CumuHistos& cumu2h, TH2I* quality, TH1D* chist, TH2D* dNDetaRef, TH2D* dNdetaDiff) const;
+    /**
+     * Solve coupled eqs. to get v_n
+     * 
+     * @param cumu CumuHistos object with non-corrected flow results
+     * @param type reference of differential flow ('r'/'d'/'a'/'b')
+     */
+    void SolveCoupledFlowEquations(CumuHistos& cumu, Char_t type) const;
+    /**
+     * Calculate NUA matrix elements to fill into the matrix
+     * 
+     * @param n row
+     * @param m column
+     * @param type reference of differential flow ('r'/'d'/'a'/'b')
+     * @param binA Eta bin of phi1
+     * @param cBin Centrality bin
+     *
+     * @return maxtrix element
+     */
+    Double_t CalculateNUAMatrixElement(Int_t n, Int_t m, Char_t type, Int_t binA, Int_t cBin) const;
+    /**
+     * Adds up the vertex bins to master profiles
+     *
+     * @param cumu QC histos
+     * @param list output list
+     * @param nNUA number of nua calculations
+     */
+    void AddVertexBins(CumuHistos& cumu, TList* list, UInt_t nNUA) const;
     /**
-     * Set centrality axis
+     * Get the bin number of <<cos(nphi)>>
      *
-     * @param axis Centrality axis
+     * @param n moment
      *
-     * @return void
+     * @return bin number
      */
-    void SetupCentAxis(TAxis* axis);
+    Int_t GetBinNumberCos(Int_t n = 0) const;
+    /**
+     * Get the bin number of <<sin(nphi)>>
+     *
+     * @param n moment
+     *
+     * @return bin number
+     */
+    Int_t GetBinNumberSin(Int_t n = 0) const;
+    /**
+     * Setup NUA axis with labels
+     *
+     * @param axis NUA axis
+     */
+    void SetupNUALabels(TAxis* a) const;
+    /**
+     * Make diagnostics hitogram
+     *
+     * @param name Name
+     *
+     * @return hist
+     */
+    TH2I* MakeQualityHist(const Char_t* name) const;
+    /**
+     * Make output histogram
+     *
+     * @param qc   # of particle correlations
+     * @param n    flow moment
+     * @param ctype  Type of flow
+     * @param nua  For nua corrected hists
+     *
+     * @return hist
+     */
+    TH2D* MakeOutputHist(Int_t qc, Int_t n, const Char_t* ctype, UInt_t nua) const;
 
-    const UShort_t fMoment;        // flow moment 
-    const Int_t    fVzMin;         // z-vertex min must be in whole [cm]
-    const Int_t    fVzMax;         // z-vertex max must be in whoe [cm]
-    TString        fType;          // data type
-    const UShort_t fFlags;         // Flow flags, e.g., eta-gap sat. vtx
-    const Double_t fSigmaCut;      // Detector specific cut for outlier events
-    const Double_t fEtaGap;        // Eta gap value
-    TH2D*          fCumuRef;       // histogram for reference flow
-    TH2D*          fCumuDiff;      // histogram for differential flow
-    TH3D*          fCumuHist;      // histogram for cumulants calculations
-    TH2F*          fdNdedpAcc;     // Diagnostics histogram to make acc. maps
-    TH2F*          fOutliers;      // Sigma <M> histogram 
-    UShort_t       fDebug;         // Debug flag
+    UShort_t   fMaxMoment;     // Max flow moment 
+    Int_t      fVzMin;         // z-vertex min must be in whole [cm]
+    Int_t      fVzMax;         // z-vertex max must be in whole [cm]
+    TString    fType;          // Data type
+    UShort_t   fFlags;         // Flow flags, e.g., eta-gap or sat. vtx
+    Double_t   fSigmaCut;      // Detector specific cut for outlier events
+    Double_t   fEtaGap;        // Eta gap value
+    Double_t   fEtaLims[6];    // Limits for binning in 3Cor method
+    TH2D*      fCumuRef;       // Histogram for reference flow
+    TH2D*      fCumuDiff;      // Histogram for differential flow
+    CumuHistos fCumuHists;     // Array of histograms for cumulants calculations
+    TH3D*      fCumuNUARef;    // histogram for NUA terms
+    TH3D*      fCumuNUADiff;   // histogram for NUA terms
+    TH2F*      fdNdedpRefAcc;  // Diagnostics histogram for acc. maps
+    TH2F*      fdNdedpDiffAcc; // Diagnostics histogram for acc. maps
+    TH2F*      fOutliers;      // Sigma <M> histogram 
+    UShort_t   fDebug;         // Debug flag
 
-    ClassDef(VertexBin, 3); // object for cumulants ananlysis in FMD
+    ClassDef(VertexBin, 4); // object for eta dependent cumulants ananlysis
   };
   // ---------- End of nested class -------------
   /** 
@@ -324,10 +566,9 @@ protected:
    * @param list List of vertex bins
    * @param h dN/detadphi histogram
    * @param vtx Current vertex bin
-   *
-   * @return true on success
+   * @param flags Extra flags
    */
-  Bool_t FillVtxBinList(const TList& list, const TH2D& h, Int_t vtx) const;
+  void FillVtxBinList(const TList& list, TH2D& h1, Int_t vtx, UShort_t flags = 0x0) const;
   /**
    * Loops of vertex bins in list and runs analysis on those for current vertex
    *
@@ -335,11 +576,34 @@ protected:
    * @param href dN/detadphi histogram for ref flow
    * @param hdiff dN/detadphi histogram for diff flow
    * @param vtx Current vertex bin
+   * @param flags Extra flags
+   */
+  void FillVtxBinListEtaGap(const TList& list, TH2D& href, TH2D& hdiff, Int_t vtx, UShort_t flags = 0x0) const;
+  /**
+   * Loops of vertex bins in list and runs analysis on those for current vertex
    *
-   * @return true on success
+   * @param list List of vertex bins
+   * @param hcent dN/detadphi histogram for central barrel
+   * @param hfwd dN/detadphi histogram for fwd detectors
+   * @param vtx Current vertex bin
+   * @param flags Extra flags
    */
-  Bool_t FillVtxBinListEtaGap(const TList& list, const TH2D& href, const TH2D& hdiff, Int_t vtx) const;
-
+  void FillVtxBinList3Cor(const TList& list, TH2D& hcent, TH2D& hfwd, Int_t vtx, UShort_t flags = 0x0);
+  /** 
+   * Combine forward and central detector histograms to one histogram, to be used for 3 correlator method
+   *
+   * @param hcent Central data
+   * @param hfwd Forward data
+   *
+   * @return combined hist
+   */
+  TH2D& CombineHists(TH2D& hcent, TH2D& hfwd);
+  /**
+   * Get TPC tracks from ESD or AOD input event
+   *
+   * @return array of tracks
+   */
+  TObjArray* GetTracks() const;
   /**
    * Loops over VertexBin list and calls terminate on each
    *
@@ -347,80 +611,86 @@ protected:
    */
   void EndVtxBinList(const TList& list) const;
   /**
-   * Projects a list of TProfile2D's with flow
+   * Projects a list of TH2D's with flow
    * results to TH1's in centrality bins
    *
    * @param list List of flow results
-   *
-   * @return void
    */
-  void MakeCentralityHists(TList* list);
+  void MakeCentralityHists(TList* list) const;
   /**
    * Check AODevent object for trigger, vertex and centrality
+   * uses aod header if object is null
    * returns true if event is OK
    *
-   * @param aodfm AliAODForwardMultObject
+   * @param aodfm AliAODForwardMult object
    * 
    * @return Bool_t 
    */
   Bool_t CheckEvent(const AliAODForwardMult* aodfm);
   /**
    * Check trigger from AODForwardMult object
+   * uses aod header if object is null
    * returns true if offline trigger is present
    *
-   * @param aodfm AliAODForwardMultObject
+   * @param aodfm AliAODForwardMult object
    * 
    * @return Bool_t 
    */
   virtual Bool_t CheckTrigger(const AliAODForwardMult* aodfm) const;
   /**
    * Check for centrality in AliAODForwardMult object, 
+   * uses aod header if object is null
    * if present return true - also sets fCent value
    *
-   * @param aodfm AliAODForwardMultObject
+   * @param aodfm AliAODForwardMult object
    * 
    * @return Bool_t 
    */
   virtual Bool_t GetCentrality(const AliAODForwardMult* aodfm);
   /**
    * Check for vertex in AliAODForwardMult
+   * uses aod header if object is null
    * returns true if in range of fVtxAXis, also sets fVtx value
    *
-   * @param aodfm AliAODForwardMultObject
+   * @param aodfm AliAODForwardMult object
    * 
    * @return Bool_t 
    */
   virtual Bool_t GetVertex(const AliAODForwardMult* aodfm);
   /**
-   * Make diagnostics hitogram
+   * Fill VZERO d^2N/detadphi hist
    *
-   * @return void
+   * @param aodvzero: AliAODVZERO object
    */
-  void MakeQualityHist(const Char_t* name) const;
+  void FillVZEROHist(AliAODVZERO* aodVZero);
   /**
    * Print the setup of the task
-   *
-   * @return void
    */
-  virtual void PrintFlowSetup() const;
+  void PrintFlowSetup() const;
 
-  TAxis*         fVtxAxis;          //  Axis to control vertex binning
-  Double_t       fFMDCut;           //  FMD sigma cut for outlier events
-  Double_t       fSPDCut;           //  SPD sigma cut for outlier events
-  UShort_t       fFlowFlags;        //  Flow flags, e.g., eta-gap, sat. vtx.
-  Double_t       fEtaGap;           //  Eta gap value
-  TList          fBinsFMD;          //  list with FMD VertexBin objects 
-  TList          fBinsSPD;          //  list with SPD VertexBin objects
-  TList*         fSumList;          //  sum list
-  TList*         fOutputList;       //  Output list
-  AliAODEvent*   fAOD;              //  AOD event
-  TArrayI        fV;                //  Calculate v_{n} flag
-  Float_t       fVtx;              //  Z vertex bin
-  Double_t       fCent;             //  Centrality
-  TH1D*          fHistCent;         //  Diagnostics hist for centrality
-  TH1D*          fHistVertexSel;    //  Diagnostics hist for selected vertices
+  TAxis*           fVtxAxis;       //  Axis to control vertex binning
+  TAxis*           fCentAxis;      //  Axis to control centrality/multiplicity binning
+  Double_t         fFMDCut;        //  FMD sigma cut for outlier events
+  Double_t         fSPDCut;        //  SPD sigma cut for outlier events
+  UShort_t         fFlowFlags;     //  Flow flags, e.g., eta-gap, sat. vtx.
+  Double_t         fEtaGap;        //  Eta gap value
+  TList            fBinsForward;   //  List with forward VertexBin objects 
+  TList            fBinsCentral;   //  List with central VertexBin objects
+  TList*           fSumList;       //  Sum list
+  TList*           fOutputList;    //  Output list
+  AliAODEvent*     fAOD;           //  AOD event
+  AliESDtrackCuts* fESDTrackCuts;  //  ESD track cuts
+  Int_t            fMaxMoment;     //  Calculate v_{n} flag
+  Float_t          fVtx;           //  Z vertex bin
+  Double_t         fCent;          //  Centrality
+  TH2D             fHistdNdedpV0;  //  VZERO d^2N/detadphi histogram
+  TH2D             fHistdNdedp3Cor;//  VZERO d^2N/detadphi histogram
+  TH2D*            fHistFMDSPDCorr;//  Diagnostics hist for multiplicity correlations between FMD and SPD
+  TH1D*            fHistCent;      //  Diagnostics hist for centrality
+  TH1D*            fHistVertexSel; //  Diagnostics hist for selected vertices
+  TH1I*            fHistEventSel;  //  Diagnostics hist for event selection
 
-  ClassDef(AliForwardFlowTaskQC, 3); // Analysis task for FMD analysis
+  ClassDef(AliForwardFlowTaskQC, 4); // Analysis task for flow analysis
 };
 
 #endif
index dfd884e..f628d8a 100644 (file)
@@ -7,26 +7,17 @@
 // Outputs:
 //  - AnalysisResults.root
 //
-/**
- * @file   AliForwardMCFlowTaskQC.cxx
- * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
- * @date   Thu Feb  7 01:09:19 2013
- * 
- * @brief  
- * 
- * 
- * @ingroup pwglf_forward_flow
- */
 #include "AliForwardMCFlowTaskQC.h"
 #include "AliAODMCParticle.h"
 #include "AliAODMCHeader.h"
 #include "TGraph.h"
 #include "TF1.h"
-#include "TProfile2D.h"
 #include "AliAODEvent.h"
 #include "AliAODForwardMult.h"
 #include "AliAODCentralMult.h"
 #include "AliGenEventHeader.h"
+#include "AliAnalysisManager.h"
+#include "AliInputEventHandler.h"
 
 ClassImp(AliForwardMCFlowTaskQC)
 #if 0
@@ -35,18 +26,19 @@ ClassImp(AliForwardMCFlowTaskQC)
 //_____________________________________________________________________
 AliForwardMCFlowTaskQC::AliForwardMCFlowTaskQC() 
   : AliForwardFlowTaskQC(), 
-    fBinsFMDTR(),          // List of FMDTR analysis objects
-    fBinsSPDTR(),          // List of SPDTR analysis objects
-    fBinsMC(),             // List of MC truth analysis objects
-    fdNdedpMC(),           // MC truth d^2N/detadphi histogram
+    fBinsForwardTR(),      // List of FMDTR analysis objects
+    fBinsCentralTR(),      // List of SPDTR analysis objects
+    fBinsMC(),             // List of MC particle analysis objects
+    fHistdNdedpMC(),       // MC particle d^2N/detadphi histogram
+    fHistFMDMCCorr(),      // FMD MC correlation
+    fHistSPDMCCorr(),      // SPD MC correlation
     fWeights(),            // Flow weights
     fImpactParToCent(),    // Impact parameter to centrality graph
     fUseImpactPar(0),      // Use impact par for centrality
-    fFMDMinEta(-6),        // FMD min eta coverage for this vtx
-    fFMDMaxEta(6),         // FMD max eta coverage for this vtx
-    fAddFlow(0),           // Add flow to MC truth
-    fAddType(0),           // Add type of flow to MC truth
-    fAddOrder(0)           // Add order of flow to MC truth        
+    fUseMCVertex(0),       // Get vertex from MC header?
+    fAddFlow(0),           // Add flow to MC particles
+    fAddType(0),           // Add type of flow to MC particles
+    fAddOrder(0)           // Add order of flow to MC particles        
 {} 
   //
   // Default Constructor
@@ -54,18 +46,19 @@ AliForwardMCFlowTaskQC::AliForwardMCFlowTaskQC()
 //_____________________________________________________________________
 AliForwardMCFlowTaskQC::AliForwardMCFlowTaskQC(const char* name) 
   : AliForwardFlowTaskQC(name),
-    fBinsFMDTR(),          // List of FMDTR analysis objects
-    fBinsSPDTR(),          // List of SPDTR analysis objects
-    fBinsMC(),             // List of MC truth analysis objects
-    fdNdedpMC(),           // MC truth d^2N/detadphi histogram
+    fBinsForwardTR(),      // List of FMDTR analysis objects
+    fBinsCentralTR(),      // List of SPDTR analysis objects
+    fBinsMC(),             // List of MC particles analysis objects
+    fHistdNdedpMC(),       // MC particles d^2N/detadphi histogram
+    fHistFMDMCCorr(),      // FMD MC correlation
+    fHistSPDMCCorr(),      // SPD MC correlation
     fWeights(),            // Flow weights
     fImpactParToCent(),    // Impact parameter to centrality graph
     fUseImpactPar(0),      // Use impact par for centrality
-    fFMDMinEta(-6),        // FMD min eta coverage for this vtx
-    fFMDMaxEta(6),         // FMD max eta coverage for this vtx
-    fAddFlow(0),           // Add flow to MC truth
-    fAddType(0),           // Add type of flow to MC truth
-    fAddOrder(0)           // Add order of flow to MC truth        
+    fUseMCVertex(0),       // Get vertex from MC header?
+    fAddFlow(0),           // Add flow to MC particles
+    fAddType(0),           // Add type of flow to MC particles
+    fAddOrder(0)           // Add order of flow to MC particles        
 { 
   // 
   // Constructor
@@ -88,18 +81,19 @@ AliForwardMCFlowTaskQC::AliForwardMCFlowTaskQC(const char* name)
 //_____________________________________________________________________
 AliForwardMCFlowTaskQC::AliForwardMCFlowTaskQC(const AliForwardMCFlowTaskQC& o) 
   : AliForwardFlowTaskQC(o), 
-    fBinsFMDTR(),                          // List of FMDTR analysis objects
-    fBinsSPDTR(),                          // List of SPDTR analysis objects
-    fBinsMC(),                             // List of MC truth analysis objects
-    fdNdedpMC(o.fdNdedpMC),                // MC truth d^2N/detadphi histogram
+    fBinsForwardTR(),                      // List of FMDTR analysis objects
+    fBinsCentralTR(),                      // List of SPDTR analysis objects
+    fBinsMC(),                             // List of MC particles analysis objects
+    fHistdNdedpMC(o.fHistdNdedpMC),        // MC particles d^2N/detadphi histogram
+    fHistFMDMCCorr(o.fHistFMDMCCorr),      // FMD MC correlation
+    fHistSPDMCCorr(o.fHistSPDMCCorr),      // SPD MC correlation
     fWeights(o.fWeights),                  // Flow weights
     fImpactParToCent(o.fImpactParToCent),  // Impact parameter to centrality
     fUseImpactPar(o.fUseImpactPar),        // Use impact par for centrality
-    fFMDMinEta(o.fFMDMinEta),              // FMD min eta coverage for this vtx
-    fFMDMaxEta(o.fFMDMaxEta),              // FMD max eta coverage for this vtx
-    fAddFlow(o.fAddFlow),                  // Add flow to MC truth
-    fAddType(o.fAddType),                  // Add type of flow to MC truth
-    fAddOrder(o.fAddOrder)                 // Add order of flow to MC truth
+    fUseMCVertex(o.fUseMCVertex),          // Get vertex from MC header?
+    fAddFlow(o.fAddFlow),                  // Add flow to MC particles
+    fAddType(o.fAddType),                  // Add type of flow to MC particles
+    fAddOrder(o.fAddOrder)                 // Add order of flow to MC particles
 {
   //
   // Copy Constructor
@@ -115,12 +109,13 @@ AliForwardMCFlowTaskQC::operator=(const AliForwardMCFlowTaskQC& o)
   //    o Object to copy from 
   //
   if (&o == this) return *this;
-  fdNdedpMC        = o.fdNdedpMC;
+  fHistdNdedpMC    = o.fHistdNdedpMC;
+  fHistFMDMCCorr   = o.fHistFMDMCCorr;
+  fHistSPDMCCorr   = o.fHistSPDMCCorr;
   fWeights         = o.fWeights;
   fImpactParToCent = o.fImpactParToCent;
   fUseImpactPar    = o.fUseImpactPar;
-  fFMDMinEta       = o.fFMDMinEta;
-  fFMDMaxEta       = o.fFMDMaxEta;
+  fUseMCVertex     = o.fUseMCVertex;
   fAddFlow         = o.fAddFlow;
   fAddType         = o.fAddType;
   fAddOrder        = o.fAddOrder;
@@ -134,15 +129,21 @@ void AliForwardMCFlowTaskQC::InitVertexBins()
   //
   AliForwardFlowTaskQC::InitVertexBins();
 
-  Int_t moment = 0;
-  for(UShort_t n = 0; n < fV.GetSize(); n++) {
-    moment = fV.At(n);
-    for (Int_t v = 1; v <= fVtxAxis->GetNbins(); v++) {
-      Int_t vL = Int_t(fVtxAxis->GetBinLowEdge(v));
-      Int_t vH = Int_t(fVtxAxis->GetBinUpEdge(v));
-      fBinsFMDTR.Add(new VertexBin(vL, vH, moment, "FMDTR", fFlowFlags, fFMDCut, fEtaGap));
-      fBinsSPDTR.Add(new VertexBin(vL, vH, moment, "SPDTR", fFlowFlags, fSPDCut, fEtaGap));
-      fBinsMC.Add(new VertexBin(vL, vH, moment, "MC", fFlowFlags, -1, fEtaGap));
+  Bool_t isNUA = (fFlowFlags & kNUAcorr);
+  for (Int_t v = 1; v <= fVtxAxis->GetNbins(); v++) {
+    Int_t vL = Int_t(fVtxAxis->GetBinLowEdge(v));
+    Int_t vH = Int_t(fVtxAxis->GetBinUpEdge(v));
+    // FMD
+    if ((fFlowFlags & kFMD)) {
+      fBinsForwardTR.Add(new VertexBin(vL, vH, fMaxMoment, "FMDTR", fFlowFlags, fFMDCut, fEtaGap));
+      if (!(fFlowFlags & k3Cor)) fBinsCentralTR.Add(new VertexBin(vL, vH, fMaxMoment, "SPDTR", fFlowFlags, fSPDCut, fEtaGap));
+      if (isNUA) fFlowFlags ^= kNUAcorr;
+      fBinsMC.Add(new VertexBin(vL, vH, fMaxMoment, "MC-FMD", fFlowFlags, -1, fEtaGap));
+      if (isNUA) fFlowFlags ^= kNUAcorr;
+    }
+    // VZERO
+    else if ((fFlowFlags & kVZERO)) {
+      fBinsMC.Add(new VertexBin(vL, vH, fMaxMoment, "MC-VZERO", fFlowFlags, -1, fEtaGap));
     }
   }
 }
@@ -154,23 +155,34 @@ void AliForwardMCFlowTaskQC::InitHists()
   //
   AliForwardFlowTaskQC::InitHists();
 
-  fdNdedpMC = TH2D(Form("fdNdedpMC%s", ((fFlowFlags & kEtaGap) ? "_etaGap" : "")),
-                  Form("fdNdedpMC%s", ((fFlowFlags & kEtaGap) ? "_etaGap" : "")),
-                  48, -6., 6., 200, 0., 2.*TMath::Pi());
-  fdNdedpMC.Sumw2();
+  TString subDetName = ((fFlowFlags & kFMD) ? "FMD" : ((fFlowFlags & kVZERO) ? "VZERO" : "none"));
+  fHistdNdedpMC = TH2D(Form("fdNdedpMC%s%s", subDetName.Data(), GetQCType(fFlowFlags)),
+                  Form("fdNdedpMC%s%s", subDetName.Data(), GetQCType(fFlowFlags)),
+                  240, -6., 6., 200, 0., TMath::TwoPi());
+  
+  fHistFMDMCCorr = new TH2D("hFMDMCCorr", "hFMDMCCorr", 200, 0., 15000., 200, 0, 20000);
+  fHistSPDMCCorr = new TH2D("hSPDMCCorr", "hSPDMCCorr", 200, 0., 7500., 200, 0, 20000);
+  TList* dList = (TList*)fSumList->FindObject("Diagnostics");
+  if (!dList) {
+    dList = new TList();
+    dList->SetName("Diagnostics");
+    fSumList->Add(dList);
+  }
+  dList->Add(fHistFMDMCCorr);
+  dList->Add(fHistSPDMCCorr);
 
-  TIter nextFMDTR(&fBinsFMDTR);
+  TIter nextForwardTR(&fBinsForwardTR);
   VertexBin* bin = 0;
-  while ((bin = static_cast<VertexBin*>(nextFMDTR()))) {
-    bin->AddOutput(fSumList);
+  while ((bin = static_cast<VertexBin*>(nextForwardTR()))) {
+    bin->AddOutput(fSumList, fCentAxis);
   }
-  TIter nextSPDTR(&fBinsSPDTR);
-  while ((bin = static_cast<VertexBin*>(nextSPDTR()))) {
-    bin->AddOutput(fSumList);
+  TIter nextCentralTR(&fBinsCentralTR);
+  while ((bin = static_cast<VertexBin*>(nextCentralTR()))) {
+    bin->AddOutput(fSumList, fCentAxis);
   }
   TIter nextMC(&fBinsMC);
   while ((bin = static_cast<VertexBin*>(nextMC()))) {
-    bin->AddOutput(fSumList);
+    bin->AddOutput(fSumList, fCentAxis);
   }
 
   TList* wList = new TList();
@@ -189,36 +201,51 @@ Bool_t AliForwardMCFlowTaskQC::Analyze()
   if (!AliForwardFlowTaskQC::Analyze()) return kFALSE;
 
   // Run analysis on trackrefs from FMD and SPD
-  const AliAODForwardMult* aodfmult = 
-    static_cast<AliAODForwardMult*>(fAOD->FindListObject("ForwardMC"));
-  const AliAODCentralMult* aodcmult = 
-    static_cast<AliAODCentralMult*>(fAOD->FindListObject("CentralClustersMC"));
+  AliAODForwardMult* aodfmult = static_cast<AliAODForwardMult*>(fAOD->FindListObject("ForwardMC"));
+  AliAODCentralMult* aodcmult = static_cast<AliAODCentralMult*>(fAOD->FindListObject("CentralClustersMC"));
   Int_t vtx = fVtxAxis->FindBin(fVtx)-1;
   
   // if objects are present, get histograms
   if (aodfmult) {
-    const TH2D& fmdTRdNdetadphi = aodfmult->GetHistogram();
-    if ((fFlowFlags & kEtaGap)) {
-      FillVtxBinListEtaGap(fBinsFMDTR, fmdTRdNdetadphi, fmdTRdNdetadphi, vtx);
-    } else {
-      FillVtxBinList(fBinsFMDTR, fmdTRdNdetadphi, vtx);
+    TH2D& fmdTRdNdetadphi = aodfmult->GetHistogram();
+    if ((fFlowFlags & kStdQC)) {
+      FillVtxBinList(fBinsForwardTR, fmdTRdNdetadphi, vtx);
+    } else if ((fFlowFlags & kEtaGap)) {
+      FillVtxBinListEtaGap(fBinsForwardTR, fmdTRdNdetadphi, fmdTRdNdetadphi, vtx/*, kDoVtxCut*/);
     }
-    
     if (aodcmult) {
-      const TH2D& spdTRdNdetadphi = aodcmult->GetHistogram();
-      if ((fFlowFlags & kEtaGap)) {
-       FillVtxBinListEtaGap(fBinsSPDTR, fmdTRdNdetadphi, spdTRdNdetadphi, vtx);
-      } else {
-       FillVtxBinList(fBinsSPDTR, spdTRdNdetadphi, vtx);
+      TH2D& spdTRdNdetadphi = aodcmult->GetHistogram();
+      if ((fFlowFlags & kStdQC)) {
+       FillVtxBinList(fBinsCentralTR, spdTRdNdetadphi, vtx);
+      } else if ((fFlowFlags & kEtaGap)) {
+       FillVtxBinListEtaGap(fBinsCentralTR, fmdTRdNdetadphi, spdTRdNdetadphi, vtx/*, kDoVtxCut*/);
+      } else if ((fFlowFlags & k3Cor)) {
+       FillVtxBinList3Cor(fBinsForwardTR, spdTRdNdetadphi, fmdTRdNdetadphi, vtx);
       }
     }
   }
   // Run analysis on MC branch
-  if (!LoopAODMC()) return kFALSE;
-  if ((fFlowFlags & kEtaGap)) {
-    FillVtxBinListEtaGap(fBinsMC, fdNdedpMC, fdNdedpMC, vtx);
-  } else {
-    FillVtxBinList(fBinsMC, fdNdedpMC, vtx);
+  if (!FillMCHist()) return kFALSE;
+  if ((fFlowFlags & kStdQC)) {
+    FillVtxBinList(fBinsMC, fHistdNdedpMC, vtx);
+  } else if ((fFlowFlags & kEtaGap)) {
+    FillVtxBinListEtaGap(fBinsMC, fHistdNdedpMC, fHistdNdedpMC, vtx);
+  } else if ((fFlowFlags & k3Cor)) {
+    FillVtxBinList3Cor(fBinsMC, fHistdNdedpMC, fHistdNdedpMC, vtx);
+  }
+
+  // Mult correlation diagnostics
+  if (aodfmult && aodcmult) {
+    AliAODForwardMult* fmult = static_cast<AliAODForwardMult*>(fAOD->FindListObject("Forward"));
+    AliAODCentralMult* cmult = static_cast<AliAODCentralMult*>(fAOD->FindListObject("CentralClusters"));
+    const TH2D& fhist = fmult->GetHistogram();
+    const TH2D& chist = cmult->GetHistogram();
+
+    Double_t totForward = fhist.Integral(1, fhist.GetNbinsX(), 1, fhist.GetNbinsY());
+    Double_t totSPD = chist.Integral(1, chist.GetNbinsX(), 1, chist.GetNbinsY());
+    Double_t totMC = fHistdNdedpMC.Integral(1, fHistdNdedpMC.GetNbinsX(), 1, fHistdNdedpMC.GetNbinsY());
+    fHistFMDMCCorr->Fill(totForward, totMC);
+    fHistSPDMCCorr->Fill(totSPD, totMC);
   }
 
   return kTRUE;
@@ -231,8 +258,8 @@ void AliForwardMCFlowTaskQC::Finalize()
   //
   AliForwardFlowTaskQC::Finalize();
 
-  EndVtxBinList(fBinsFMDTR);
-  EndVtxBinList(fBinsSPDTR);
+  EndVtxBinList(fBinsForwardTR);
+  EndVtxBinList(fBinsCentralTR);
   EndVtxBinList(fBinsMC);
 
   return;
@@ -248,7 +275,10 @@ Bool_t AliForwardMCFlowTaskQC::CheckTrigger(const AliAODForwardMult* aodfm) cons
   //
   // Returns true if B trigger is present - for some reason this is the one we use in MC
   //
-  return aodfm->IsTriggerBits(AliAODForwardMult::kB);
+  if (aodfm) return aodfm->IsTriggerBits(AliAODForwardMult::kB);
+  else return (((AliInputEventHandler*)(AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler()))
+                 ->IsEventSelected() & AliVEvent::kMB);
+
 }
 // _____________________________________________________________________
 Bool_t AliForwardMCFlowTaskQC::GetCentrality(const AliAODForwardMult* aodfm)
@@ -262,44 +292,60 @@ Bool_t AliForwardMCFlowTaskQC::GetCentrality(const AliAODForwardMult* aodfm)
   //
   // Returns true when centrality is set.
   //
+//  fCent = 2.5;
+//  return kTRUE;
   if (fUseImpactPar) {
     fCent = GetCentFromB();
-    if (fCent != -1) return kTRUE;
-  }
-  return AliForwardFlowTaskQC::GetCentrality(aodfm);
+    if (fCentAxis->GetXmin() > fCent || fCent >= fCentAxis->GetXmax()) {
+      fHistEventSel->Fill(kInvCent);
+      return kFALSE;
+    }
+    if (fCent != 0) return kTRUE;
+    else {
+      fHistEventSel->Fill(kNoCent);
+      return kFALSE;
+    }
+  } else 
+    return AliForwardFlowTaskQC::GetCentrality(aodfm);
 }
 //_____________________________________________________________________
-void AliForwardMCFlowTaskQC::GetFMDLimits()
+Bool_t AliForwardMCFlowTaskQC::GetVertex(const AliAODForwardMult* aodfm)
 {
-
-  const AliAODForwardMult* aodfmult = 
-    static_cast<AliAODForwardMult*>(fAOD->FindListObject("Forward"));
-  const TH2D& h = aodfmult->GetHistogram();
-
-  for (Int_t e = 1; ; e++) {
-    if (h.GetBinContent(e, 0) != 0) { 
-      fFMDMinEta = h.GetXaxis()->GetBinLowEdge(e);
-      break;
-    }
-  }
-  for (Int_t e = h.GetNbinsX(); ; e--) {
-    if (h.GetBinContent(e, 0) != 0) { 
-      fFMDMaxEta = h.GetXaxis()->GetBinLowEdge(e);
-      break;
+  //
+  // Function to look for vertex determination in the event using the MC header.
+  //
+  // Parameters: 
+  //  AliAODForwardMult: Not used
+  //
+  // Returns true if vertex is determined
+  //
+  if (fUseMCVertex) {
+    AliAODMCHeader* header = 
+      static_cast<AliAODMCHeader*>(fAOD->FindListObject(AliAODMCHeader::StdBranchName()));
+    if (header) {
+      fVtx = header->GetVtxZ();
+      if (fVtx < fVtxAxis->GetXmin() || fVtx > fVtxAxis->GetXmax()) {
+        fHistEventSel->Fill(kInvVtx);
+       return kFALSE;
+      }
+      return kTRUE;
+    } else {
+      fHistEventSel->Fill(kNoVtx);
+      return kFALSE;
     }
-  }
-
-  return;
+  } else 
+    return AliForwardFlowTaskQC::GetVertex(aodfm);
 }
 //_____________________________________________________________________
-Bool_t AliForwardMCFlowTaskQC::LoopAODMC()  
+Bool_t AliForwardMCFlowTaskQC::FillMCHist()  
 {
   // 
   // Loop over AliAODParticle branch and fill d^2N/detadphi-histograms.
   // Add flow if set to do so in AddTask function
   //
-  fdNdedpMC.Reset();
-  GetFMDLimits();
+  fHistdNdedpMC.Reset();
+  Int_t minEta = -3.75;
+  Int_t maxEta = 5.;
 
   //retreive MC particles from event
   TClonesArray* mcArray = 
@@ -311,19 +357,21 @@ Bool_t AliForwardMCFlowTaskQC::LoopAODMC()
   }
 
   AliAODMCHeader* header = 
-    dynamic_cast<AliAODMCHeader*>(fAOD->FindListObject(
+    static_cast<AliAODMCHeader*>(fAOD->FindListObject(
                                   AliAODMCHeader::StdBranchName()));
   if (!header) 
     AliWarning("No header file found.");
-  
-  // Double_t rp = header->GetReactionPlaneAngle();
 
   Int_t ntracks = mcArray->GetEntriesFast();
-  // TODO: Make this bit smarter...
-  if (header->GetNCocktailHeaders() > 1) {
-    ntracks = header->GetCocktailHeader(0)->NProduced();
+//  Double_t rp = -1, b = -1;
+  if (header) {
+//    rp = header->GetReactionPlaneAngle();
+//    b = header->GetImpactParameter();
+    if (header->GetNCocktailHeaders() > 1) {
+      ntracks = header->GetCocktailHeader(0)->NProduced();
+    }
   }
-
+  
   UShort_t flowFlags = 0;
   if (fAddFlow.Length() > 1) {
     if (fAddFlow.Contains("pt"))   flowFlags |= AliForwardFlowWeights::kPt;
@@ -331,12 +379,9 @@ Bool_t AliForwardMCFlowTaskQC::LoopAODMC()
     if (fAddFlow.Contains("eta"))  flowFlags |= AliForwardFlowWeights::kEta;
     if (fAddFlow.Contains("cent")) flowFlags |= AliForwardFlowWeights::kCent;
   }
-  // Double_t b = header->GetImpactParameter();
 
-  // Track loop: chek how many particles will be accepted
-  Double_t weight = 0;
-  for (Int_t it = 0; it < ntracks; it++) {
-    weight = 1;
+  for (Int_t it = 0; it < ntracks; it++) { // Track loop
+    Double_t weight = 1;
     AliAODMCParticle* particle = (AliAODMCParticle*)mcArray->At(it);
     if (!particle) {
       AliError(Form("Could not receive track %d", it));
@@ -347,23 +392,26 @@ Bool_t AliForwardMCFlowTaskQC::LoopAODMC()
     //Double_t pT = particle->Pt();
     Double_t eta = particle->Eta();
     Double_t phi = particle->Phi();
-    if (eta >= fFMDMinEta && eta <= fFMDMaxEta) {
+    if (eta >= minEta && eta < maxEta) {
       // Add flow if it is in the argument
-      /* FLOW WEIGHTS DISABLED IN THE VERSION - COMING BACK SOON
-      if (flowFlags != 0) { 
+      // FLOW WEIGHTS DISABLED IN THE VERSION - COMING BACK SOON
+//      if (flowFlags != 0) { 
 //     weight = fWeights.CalcWeight(eta, pT, phi, particle->PdgCode(), 
 //                                  rp, fCent, fAddType, fAddOrder, 
 //                                  flowFlags) + 1;
-        weight = fWeights.CalcWeight(eta, pT, phi, particle->PdgCode(),
-                                    rp, b); 
+//        weight = fWeights.CalcWeight(eta, pT, phi, particle->PdgCode(),
+//                                    rp, b); 
 //      Printf("%f", weight);
-      }*/
-        fdNdedpMC.Fill(eta, phi, weight);
+//      }
+      fHistdNdedpMC.Fill(eta, phi, weight);
     }
   }
-  Int_t sBin = fdNdedpMC.GetXaxis()->FindBin(fFMDMinEta);
-  Int_t eBin = fdNdedpMC.GetXaxis()->FindBin(fFMDMaxEta);
-  for ( ; sBin < eBin; sBin++) fdNdedpMC.SetBinContent(sBin, 0, 1.);
+  // Set underflow bins for acceptance checks
+  Int_t sBin = fHistdNdedpMC.GetXaxis()->FindBin(minEta);
+  Int_t eBin = fHistdNdedpMC.GetXaxis()->FindBin(maxEta);
+  for ( ; sBin <= eBin; sBin++) {
+    fHistdNdedpMC.SetBinContent(sBin, 0, 1);
+  } // End of eta bin loop
 
   return kTRUE;
 }
@@ -379,37 +427,11 @@ Double_t AliForwardMCFlowTaskQC::GetCentFromB() const
                                                      StdBranchName()));
   if (!header) return cent;
   Double_t b = header->GetImpactParameter();
-
   cent = fImpactParToCent->Eval(b);
 
   return cent;
 }
 //_____________________________________________________________________
-void AliForwardMCFlowTaskQC::PrintFlowSetup() const  
-{
-  //
-  // Print the setup of the flow task
-  //
-  Printf("AliForwardMCFlowTaskQC::Print");
-  Printf("Number of bins in vertex axis:\t%d", fVtxAxis->GetNbins());
-  Printf("Range of vertex axis         :\t[%3.1f,%3.1f]", 
-                         fVtxAxis->GetXmin(), fVtxAxis->GetXmax());
-  printf("Doing flow analysis for      :\t");
-  for (Int_t n  = 0; n < fV.GetSize(); n++) printf("v%d ", fV.At(n));
-  printf("\n");
-  Printf("Satellite vertex flag           :\t%s", ((fFlowFlags & kSatVtx) ? 
-                                                  "true" : "false"));
-  Printf("Symmetrize ref. flow wrt eta = 0:\t%s", ((fFlowFlags & kSymEta) ? 
-                                                  "true" : "false"));
-  Printf("Use an eta-gap for ref. flow    :\t%s", ((fFlowFlags & kEtaGap) ? 
-                                                  "true" : "false"));
-  Printf("FMD sigma cut:               :\t%f", fFMDCut);
-  Printf("SPD sigma cut:               :\t%f", fSPDCut);
-  if ((fFlowFlags & kEtaGap)) 
-    Printf("Eta gap:                     :\t%f", fEtaGap);
-}
-//_____________________________________________________________________
 //
 //
 // EOF
-
index 4621395..7e12151 100644 (file)
@@ -9,12 +9,10 @@
  * 
  * @brief  
  * 
- * 
  * @ingroup pwglf_forward_flow
  */
 #include "AliForwardFlowTaskQC.h"
 #include "AliForwardFlowWeights.h"
-#include <TH2D.h>
 class TGraph;
 
 /**
@@ -24,7 +22,7 @@ class TGraph;
  *   - AliAODEvent
  *
  * Outputs:
- *   - AnalysisResults.root
+ *   - forward_flow.root
  *
  * @ingroup pwglf_forward_tasks_flow
  * @ingroup pwglf_forward_flow
@@ -48,32 +46,19 @@ public:
    */
   virtual ~AliForwardMCFlowTaskQC() {}
   /**
-   * Check trigger from AODForwardMult object
-   * returns true if B trigger is present
-   *
-   * @param aodfm AliAODForwardMultObject
-   * 
-   * @return Bool_t 
-   */
-  virtual Bool_t CheckTrigger(const AliAODForwardMult* aodfm) const;
-  /**
-   * Check for centrality in AliAODForwardMult object, 
-   * if present return true - also sets fCent value
-   * can be used to get centrality from impact parameter
+   * Set use parametrization from impact parameter for centrality
    *
-   * @param aodfm AliAODForwardMultObject
-   * 
-   * @return Bool_t 
+   * @param use Use impact par
    */
-  virtual Bool_t GetCentrality(const AliAODForwardMult* aodfm);
+  void SetUseImpactParameter(Bool_t use = kTRUE) { fUseImpactPar = use; }
   /**
-   * Set use parametrization from impact parameter for centrality
+   * Set to get vertex from MC header
    *
-   * @param use Use impact par
+   * @param use Get from MC header
    */
-  void SetUseImpactParameter(Bool_t use) { fUseImpactPar = use; }
+  void SetUseMCHeaderVertex(Bool_t use = kTRUE) { fUseMCVertex = use; }
   /**
-   * Set string to add flow to MC truth particles
+   * Set string to add flow to MC particles particles
    *
    * @param type String
    */
@@ -125,43 +110,62 @@ protected:
    */
   void Finalize();
   /**
-   * Find FMD coverage for this vtx, to make MC histogram match
+   * Check trigger from AODForwardMult object
+   * returns true if B trigger is present
+   *
+   * @param aodfm AliAODForwardMultObject
+   * 
+   * @return Bool_t 
+   */
+  virtual Bool_t CheckTrigger(const AliAODForwardMult* aodfm) const;
+  /**
+   * Check for centrality in AliAODForwardMult object, 
+   * if present return true - also sets fCent value
+   * can be used to get centrality from impact parameter
+   *
+   * @param aodfm AliAODForwardMultObject
+   * 
+   * @return Bool_t 
    */
-  void GetFMDLimits();
+  virtual Bool_t GetCentrality(const AliAODForwardMult* aodfm);
+  /**
+   * Check for vertex in MCHeader
+   * returns true if in range of fVtxAXis, also sets fVtx value
+   *
+   * @param aodfm Not used
+   * 
+   * @return Bool_t 
+   */
+  virtual Bool_t GetVertex(const AliAODForwardMult* aodfm);
   /**
    * Loop over AliAODMCParticle branch object and fill d^2N/detadphi histograms
    * add flow if arguments are set
    * 
    * @return true on success
    */
-  Bool_t LoopAODMC();
+  Bool_t FillMCHist();
   /**
    * Get centrality form MC impact parameter
    *
    * @return Centrality
    */
   Double_t GetCentFromB() const;
-  /**
-   * Print the setup of the task
-   *
-   * @return void
-   */
-  virtual void PrintFlowSetup() const;
   
-  TList         fBinsFMDTR;         //  List with FMDTR VertexBin objects
-  TList         fBinsSPDTR;         //  List with SPDTR VertexBin objects
-  TList         fBinsMC;            //  List with MC VertexBin objects
-  TH2D          fdNdedpMC;          //  d^2N/detadphi MC truth histogram
-  AliForwardFlowWeights fWeights;   //  Flow after burner 
-  TGraph*       fImpactParToCent;   //  Parametrization of b to centrality
-  Bool_t        fUseImpactPar;      //  Flag to use impact parameter for cent
-  Double_t      fFMDMinEta;         //  FMD min. eta coverage for this vtx
-  Double_t      fFMDMaxEta;         //  FMD max. eta coverage for this vtx
-  TString       fAddFlow;           //  Add flow string
-  Int_t         fAddType;           //  Add flow type #
-  Int_t         fAddOrder;          //  Add flow order
+  TList                 fBinsForwardTR;   //  List with FMDTR VertexBin objects
+  TList                 fBinsCentralTR;   //  List with SPDTR VertexBin objects
+  TList                 fBinsMC;          //  List with MC VertexBin objects
+  TH2D                  fHistdNdedpMC;    //  d^2N/detadphi MC particles histogram
+  TH2D*                 fHistFMDMCCorr;   //  Diagnostics for mult. corr. between FMD and MC
+  TH2D*                 fHistSPDMCCorr;   //  Diagnostics for mult. corr. between SPD and MC
+  AliForwardFlowWeights fWeights;         //  Flow after burner 
+  TGraph*               fImpactParToCent; //  Parametrization of b to centrality
+  Bool_t                fUseImpactPar;    //  Flag to use impact parameter for cent
+  Bool_t                fUseMCVertex;     //  Get vertex from MC header
+  TString               fAddFlow;         //  Add flow string
+  Int_t                 fAddType;         //  Add flow type #
+  Int_t                 fAddOrder;        //  Add flow order
 
-  ClassDef(AliForwardMCFlowTaskQC, 3); // FMD MC analysis task 
+  ClassDef(AliForwardMCFlowTaskQC, 4); // FMD MC analysis task 
 };
  
 #endif
index 4109afe..049259d 100644 (file)
@@ -1,32 +1,21 @@
 /**
  * @file   MakeFlow.C
  * @author Alexander Hansen 
- * @date   Wed Mar 23 12:11:33 2011
  * 
  * @brief  
  * 
- * @ingroup pwg2_forward_scripts_makers
+ * @ingroup pwglf_forward_scripts_makers
  * 
  */
 //====================================================================
 /**
  * Script to analyse AOD input for flow
  * 
- * Takes either a single (AOD) .root file as input or a .txt
- * The .txt file is expected to contain the path to the files 
- * from the current directory or the absolute path.
- * 
- * @par Inputs: 
- *  
- * 
- * @par Outputs: 
- * - 
- *
  * @param name     Name of train 
  * @param options  Options @see RunTrain 
  * @param mode     Which execution environment 
- * @param datadir  Data directory 
- * @param urlOpts  URL options 
+ * @param datadir  Data directory/proof path 
+ * @param urlOpts  URL options
  *
  * @ingroup pwglf_forward_flow
  */
@@ -42,7 +31,7 @@ void MakeFlow(TString name    = "flow",
   
   gROOT->LoadMacro("$ALICE_ROOT/PWGLF/FORWARD/trains/RunTrain.C");
 
-  if (!datadir.EndsWith("/")) datadir.Append("/");
+  if (!datadir.EndsWith("/") && !mode.Contains("proof")) datadir.Append("/");
   
   TUrl url(datadir.Data());
   url.SetProtocol(mode.Data());
index 34baf59..6ac1ee2 100644 (file)
@@ -1,7 +1,6 @@
 /**
  * @file   MakeFlowTrain.C
- * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
- * @date   Fri Jun  1 13:51:48 2012
+ * @author Alexander Hansen                                      
  * 
  * @brief  
  * 
@@ -12,7 +11,7 @@
 
 //====================================================================
 /**
- * Analysis train to make @f$ flow@f$
+ * Analysis train to make flow@
  * 
  *
  * @ingroup pwglf_forward_flow
@@ -22,27 +21,34 @@ class MakeFlowTrain : public TrainSetup
 {
 public:
   /** 
-   * Constructor.  Date and time must be specified when running this
-   * in Termiante mode on Grid
+   * Constructor.  
    * 
    * @param name     Name of train (free form)
    */
   MakeFlowTrain(const char* name)
   : TrainSetup(name)
   {
+    // General options
     fOptions.Add("mc", "Do MC analysis");
-    fOptions.Add("mom", "Flow moments to analyse", "234", "234");
-    fOptions.Add("eta-gap", "Whether to use an eta-gap", "[no,yes,both]", "both");
-    fOptions.Add("eg-value", "Set value in |eta| of the eta gap", "2.0");
+    fOptions.Add("max-mom", "2|3|4|5", "Max flow moment to analyse", "5");
     fOptions.Add("use-cent", "Whether to use the impact parameter for centrality");
-    fOptions.Add("afterburner", "What to afterburn", "[eta,phi,b,pid]", "");
-    fOptions.Add("ab-type", "Type of afterburner", "1|2|3|4", "");
-    fOptions.Add("ab-order", "Order of afterburner", "2|3|4|5|6", "");
-    fOptions.Add("sat-vtx", "Whether to use satellite interactions");
-    fOptions.Add("outlier-fmd", "Outlier cut for FMD", "NSIGMA", "4.0");
-    fOptions.Add("outlier-spd", "Outlier cut for SPD", "NSIGMA", "0.0");
+    fOptions.Add("mc-vtx", "Whether to get the vertex from the MC header");
+    fOptions.Add("afterburner", "[eta,phi,b,pid]", "What to afterburn", "");
+    fOptions.Add("ab-type", "1|2|3|4", "Type of afterburner", "");
+    fOptions.Add("ab-order", "2|3|4|5|6", "Order of afterburner", "");
+    fOptions.Add("fwd-dets", "[fmd,vzero]", "Forward detectors", "");
     fOptions.Set("type", "AOD");
     fOptions.Show(std::cout);
+    // QC specific options
+    fOptions.Add("QC", "Add QC tasks (requires AODs with FMD and SPD objects)");
+    fOptions.Add("qc-type", "[std,eta-gap,3cor,all]", "Which types of QC's to do", "both");
+    fOptions.Add("eg-value", "EGVALUE", "Set value in |eta| of the eta gap", "2.0");
+    fOptions.Add("tpc-tracks", "Whether to use TPC tracks for reference flow");
+    fOptions.Add("sat-vtx", "Whether to use satellite interactions");
+    fOptions.Add("outlier-fmd", "NSIGMA", "Outlier cut for FMD", "4.0");
+    fOptions.Add("outlier-spd", "NSIGMA", "Outlier cut for SPD", "4.0");
+    // EP specific options
+    fOptions.Add("EP", "Add EP tasks (requires VZERO AOD objects)");
   }
 protected:
   //__________________________________________________________________
@@ -54,7 +60,7 @@ protected:
   void CreateTasks(AliAnalysisManager* mgr)
   {
     // --- Output file name ------------------------------------------
-    AliAnalysisManager::SetCommonFileName("AnalysisResults.root");
+    AliAnalysisManager::SetCommonFileName("forward_flow.root");
 
     // --- Load libraries/pars ---------------------------------------
     fHelper->LoadLibrary("PWGLFforward2");
@@ -62,50 +68,99 @@ protected:
     // --- Set load path ---------------------------------------------
     gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
                             gROOT->GetMacroPath()));
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/ANALYSIS/macros",
+                             gROOT->GetMacroPath()));
+
+    // --- Add the tasks ---------------------------------------------
+    Bool_t doQC = fOptions.AsBool("QC");
+    Bool_t doEP = fOptions.AsBool("EP");
+    if (doQC) AddQCTasks();
+    if (doEP) AddEPTasks();
+    if (!doQC && !doEP) Fatal("CreateTasks", "No flow tasks were added");
 
+  }
+  //__________________________________________________________________
+  /**
+   * Add the QC task(s)
+   */
+  void AddQCTasks()
+  {
     // --- Get the parameters ----------------------------------------
-    TString  type    = fOptions.Get("mom");
-    TString  etaGap  = fOptions.Get("eta-gap");
-    Double_t egValue = fOptions.AsDouble("eg-value");
-    Bool_t   useCent = fOptions.AsBool("use-cent");
-    TString  addFlow = fOptions.Get("afterburner");
-    Int_t    abType  = fOptions.AsInt("ab-type");
-    Int_t    abOrder = fOptions.AsInt("ab-order");
-    Bool_t   satVtx  = fOptions.AsBool("sat-vtx");
-    Double_t fmdCut  = fOptions.AsDouble("outlier-fmd");
-    Double_t spdCut  = fOptions.AsDouble("outlier-spd");
-    Bool_t   mc      = fOptions.AsBool("mc"); 
+    Int_t    moment   = fOptions.AsInt("max-mom");
+    TString  fwdDets  = fOptions.Get("fwd-dets");
+    TString  types    = fOptions.Get("qc-type");
+    Double_t egValue  = fOptions.AsDouble("eg-value");
+    Bool_t   tpcTr    = fOptions.AsBool("tpc-tracks");
+    Bool_t   useCent  = fOptions.AsBool("use-cent");
+    Bool_t   useMCVtx = fOptions.AsBool("mc-vtx");
+    TString  addFlow  = fOptions.Get("afterburner");
+    Int_t    abType   = fOptions.AsInt("ab-type");
+    Int_t    abOrder  = fOptions.AsInt("ab-order");
+    Bool_t   satVtx   = fOptions.AsBool("sat-vtx");
+    Double_t fmdCut   = fOptions.AsDouble("outlier-fmd");
+    Double_t spdCut   = fOptions.AsDouble("outlier-spd");
+    Bool_t   mc       = fOptions.AsBool("mc"); 
 
-    // --- Add the task ----------------------------------------------
-    if (etaGap.Contains("no") || etaGap.Contains("false") ||
-        etaGap.Contains("both"))
-          gROOT->Macro(Form("AddTaskForwardFlow.C(\"%s\",%d,%d,%f,%f,%f,%d,%d,\"%s\",%d,%d)",
-                     type.Data(),
-                     kFALSE,
-                     mc, 
-                     fmdCut, 
-                     spdCut,
-                     egValue,
-                     useCent,
-                     satVtx, 
-                     addFlow.Data(), 
-                     abType, 
-                     abOrder));
+    types.ToLower();
+    fwdDets.ToUpper();
+    Bool_t doFMD = fwdDets.Contains("FMD");
+    Bool_t doVZERO = fwdDets.Contains("VZERO");
+
+    TString args(TString::Format("AddTaskForwardFlowQC.C(%d,\"%%s\",%%d,%%d,%d,%f,%f,%f,%%d,%d,%d,%d,\"%s\",%d,%d)",
+                       moment,
+                       mc, 
+                       fmdCut, 
+                       spdCut,
+                       egValue,
+                       useCent,
+                       useMCVtx,
+                       satVtx, 
+                       addFlow.Data(), 
+                       abType, 
+                       abOrder));
     
-    if (etaGap.Contains("yes") || etaGap.Contains("true") ||
-        etaGap.Contains("both"))
-          gROOT->Macro(Form("AddTaskForwardFlow.C(\"%s\",%d,%d,%f,%f,%f,%d,%d,\"%s\",%d,%d)",
-                     type.Data(),
-                     kTRUE,
-                     mc, 
-                     fmdCut, 
-                     spdCut, 
-                     egValue,
-                     useCent,
-                     satVtx, 
-                     addFlow.Data(), 
-                     abType, 
-                     abOrder));
+    // --- Add the task ----------------------------------------------
+    if (doFMD) {
+      if (types.Contains("std") || types.Contains("all")) {
+       gROOT->Macro(Form(args.Data(), "FMD", false, false, false));
+       if (tpcTr)
+         gROOT->Macro(Form(args.Data(), "FMD", false, false, true));
+      }
+      if (types.Contains("eta-gap") || types.Contains("all"))
+       gROOT->Macro(Form(args.Data(), "FMD", true, false, false));
+      if (types.Contains("3cor") || types.Contains("all"))
+       gROOT->Macro(Form(args.Data(), "FMD", false, true, false));
+    }
+    if (doVZERO) {
+      if (types.Contains("std") || types.Contains("all")) {
+       gROOT->Macro(Form(args.Data(), "VZERO", false, false, false));
+       if (tpcTr)
+         gROOT->Macro(Form(args.Data(), "VZERO", false, false, true));
+      }
+      if (types.Contains("eta-gap") || types.Contains("all"))
+       gROOT->Macro(Form(args.Data(), "VZERO", true, false, false));
+      if (types.Contains("3cor") || types.Contains("all"))
+       gROOT->Macro(Form(args.Data(), "VZERO", false, true, false));
+    }
+  }
+  //__________________________________________________________________
+  /**
+   * Add the EP task(s)
+   */
+  void AddEPTasks()
+  {
+    // --- Get the parameters ----------------------------------------
+    Int_t    moment   = fOptions.AsInt("max-mom");
+    TString  etaGap   = fOptions.Get("eta-gap");
+    TString  addFlow  = fOptions.Get("afterburner");
+    Int_t    abType   = fOptions.AsInt("ab-type");
+    Int_t    abOrder  = fOptions.AsInt("ab-order");
+    Bool_t   mc       = fOptions.AsBool("mc"); 
+    TString  fwdDets  = fOptions.Get("fwd-dets");
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro("AddTaskEventplane.C");
+    gROOT->Macro(Form("AddTaskForwardFlowEP.C(%d, %d, \"%s\")", mc, moment, fwdDets.Data()));
   }
   //__________________________________________________________________
   /** 
index ba0a8b5..68e637e 100644 (file)
 #endif
 #pragma link C++ class AliForwardFlowTaskQC+;
 #if ROOT_VERSION_CODE < 0x56300 // ROOT_VERSION(5,99,0)
+#pragma link C++ class AliForwardFlowTaskQC::CumuHistos+;
+#endif
+#if ROOT_VERSION_CODE < 0x56300 // ROOT_VERSION(5,99,0)
 #pragma link C++ class AliForwardFlowTaskQC::VertexBin+;
 #endif
 #pragma link C++ class AliForwardMCCorrectionsTask+;