More code clean up.
authorcholm <cholm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 16 Dec 2010 11:48:28 +0000 (11:48 +0000)
committercholm <cholm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 16 Dec 2010 11:48:28 +0000 (11:48 +0000)
Added missing correction object classes.
Removed dependence on old forward analysis code altogether -  still need correction creators

40 files changed:
PWG2/FORWARD/analysis2/AddTaskFMD.C
PWG2/FORWARD/analysis2/AliFMDCorrDoubleHit.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrDoubleHit.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrELossFit.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrELossFit.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrMergingEfficiency.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrMergingEfficiency.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrSecondaryMap.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrSecondaryMap.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrVertexBias.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrVertexBias.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDCorrections.cxx
PWG2/FORWARD/analysis2/AliFMDCorrections.h
PWG2/FORWARD/analysis2/AliFMDDensityCalculator.cxx
PWG2/FORWARD/analysis2/AliFMDDensityCalculator.h
PWG2/FORWARD/analysis2/AliFMDEnergyFitter.cxx
PWG2/FORWARD/analysis2/AliFMDEnergyFitter.h
PWG2/FORWARD/analysis2/AliFMDEnergyFitterTask.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDEnergyFitterTask.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDEventInspector.cxx
PWG2/FORWARD/analysis2/AliFMDEventInspector.h
PWG2/FORWARD/analysis2/AliFMDHistCollector.cxx
PWG2/FORWARD/analysis2/AliFMDHistCollector.h
PWG2/FORWARD/analysis2/AliFMDMCDensityCalculator.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDMCDensityCalculator.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliFMDSharingFilter.cxx
PWG2/FORWARD/analysis2/AliFMDSharingFilter.h
PWG2/FORWARD/analysis2/AliForwardCorrectionManager.cxx [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliForwardCorrectionManager.h [new file with mode: 0644]
PWG2/FORWARD/analysis2/AliForwardMCCorrectionsTask.cxx [moved from PWG2/FORWARD/analysis2/AliForwardMCCorrections.cxx with 75% similarity]
PWG2/FORWARD/analysis2/AliForwardMCCorrectionsTask.h [moved from PWG2/FORWARD/analysis2/AliForwardMCCorrections.h with 81% similarity]
PWG2/FORWARD/analysis2/AliForwardMultiplicityTask.cxx [moved from PWG2/FORWARD/analysis2/AliForwardMultiplicity.cxx with 67% similarity]
PWG2/FORWARD/analysis2/AliForwardMultiplicityTask.h [moved from PWG2/FORWARD/analysis2/AliForwardMultiplicity.h with 85% similarity]
PWG2/FORWARD/analysis2/AliForwardUtil.cxx
PWG2/FORWARD/analysis2/AliForwardUtil.h
PWG2/FORWARD/analysis2/DrawRes.C
PWG2/FORWARD/analysis2/Pass2.C
PWG2/FORWARD/analysis2/Run.sh
PWG2/FORWARD/analysis2/RunELossFitter.C [new file with mode: 0644]
PWG2/FORWARD/analysis2/RunManager.C

index ad79c03..74cf046 100644 (file)
@@ -13,10 +13,12 @@ AddTaskFMD()
   }   
 
   // --- Make the task and add it to the manager ---------------------
-  AliForwardMultiplicity* task = new AliForwardMultiplicity("FMD");
+  AliForwardMultiplicityTask* task = new AliForwardMultiplicityTask("FMD");
   mgr->AddTask(task);
 
   // --- Set parameters on the algorithms ----------------------------
+  // Whether to enable low flux specific code 
+  task->SetEnableLowFlux(kFALSE);
   // Set the number of SPD tracklets for which we consider the event a
   // low flux event
   task->GetEventInspector().SetLowFluxCut(1000); 
@@ -33,7 +35,9 @@ AddTaskFMD()
   // Set whether to use increasing bin sizes 
   task->GetEnergyFitter().SetUseIncreasingBins(true);
   // Set whether to do fit the energy distributions 
-  task->GetEnergyFitter().SetDoFits(kTRUE);
+  task->GetEnergyFitter().SetDoFits(kFALSE);
+  // Set whether to make the correction object 
+  task->GetEnergyFitter().SetDoMakeObject(kFALSE);
   // Set the low cut used for energy
   task->GetEnergyFitter().SetLowCut(0.4);
   // Set the number of bins to subtract from maximum of distributions
@@ -44,8 +48,14 @@ AddTaskFMD()
   // Set the minimum number of entries in the distribution before
   // trying to fit to the data
   task->GetEnergyFitter().SetMinEntries(1000);
-  // Set the low cut used for sharing 
-  task->GetSharingFilter().SetLowCut(0.3);
+  // Set the low cut used for sharing - overrides settings in eloss fits
+  // task->GetSharingFilter().SetLowCut(0.4);
+  // Set the number of xi's (width of landau peak) to stop at 
+  task->GetSharingFilter().SetNXi(1);
+  // Set the maximum number of particle to try to reconstruct 
+  task->GetDensityCalculator().SetMaxParticles(2);
+  // Set the lower multiplicity cut.  Overrides setting in energy loss fits.
+  // task->GetDensityCalculator().SetMultCut(0.4);
   // Set the number of extra bins (beyond the secondary map border) 
   task->GetHistCollector().SetNCutBins(1);
   // Set the correction cut, that is, when bins in the secondary map 
@@ -54,28 +64,37 @@ AddTaskFMD()
   // Set the overall debug level (1: some output, 3: a lot of output)
   task->SetDebug(0);
   // Set the debug level of a single algorithm 
-  task->GetEnergyFitter().SetDebug(3);
+  // task->GetEventInspector().SetDebug(4);
+  // --- Set limits on fits the energy -------------------------------
+  // Maximum relative error on parameters 
+  AliFMDCorrELossFit::ELossFit::fgMaxRelError = .12;
+  // Least weight to use 
+  AliFMDCorrELossFit::ELossFit::fgLeastWeight = 1e-5;
+  // Maximum value of reduced chi^2 
+  AliFMDCorrELossFit::ELossFit::fgMaxChi2nu   = 5;
+
   
-  // --- Set up the parameer manager ---------------------------------
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  // --- Set up the parameter manager ---------------------------------
+  // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
   AliMCEventHandler* mcHandler = 
     dynamic_cast<AliMCEventHandler*>(mgr->GetMCtruthEventHandler());
   Info("AddTaskFMD", "MC handler %p", mcHandler);
-  if(mcHandler) {
-    pars->SetRealData(kFALSE);
-    pars->SetProcessPrimary(kTRUE);
-    pars->SetProcessHits(kFALSE);
-  }
-  else {
-    pars->SetRealData(kTRUE);
-    pars->SetProcessPrimary(kFALSE);
-    pars->SetProcessHits(kFALSE);
-  }
-  pars->Init();
+  // if(mcHandler) {
+  //   pars->SetRealData(kFALSE);
+  //   pars->SetProcessPrimary(kTRUE);
+  //   pars->SetProcessHits(kFALSE);
+  // }
+  // else {
+  //   pars->SetRealData(kTRUE);
+  //   pars->SetProcessPrimary(kFALSE);
+  //   pars->SetProcessHits(kFALSE);
+  // }
+  // pars->Init();
   
-  // --- Makek the output container and connect it -------------------
+  // --- Make the output container and connect it --------------------
   TString outputfile = AliAnalysisManager::GetCommonFileName();
-  outputfile += Form(":%s",pars->GetDndetaAnalysisName());
+  // outputfile += ":PWG2forwardDnDeta"; 
+  // Form(":%s",pars->GetDndetaAnalysisName());
   AliAnalysisDataContainer* histOut = 
     mgr->CreateContainer("Forward", TList::Class(), 
                         AliAnalysisManager::kOutputContainer,outputfile);
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrDoubleHit.cxx b/PWG2/FORWARD/analysis2/AliFMDCorrDoubleHit.cxx
new file mode 100644 (file)
index 0000000..14640c6
--- /dev/null
@@ -0,0 +1,96 @@
+#include "AliFMDCorrDoubleHit.h"
+#include <TBrowser.h>
+#include <TH1D.h>
+#include <AliLog.h>
+#include <iostream>
+
+//____________________________________________________________________
+AliFMDCorrDoubleHit::AliFMDCorrDoubleHit()
+  : fCorrections()
+{
+  fCorrections.SetOwner(kTRUE);
+  fCorrections.SetName("doubleHit");
+}
+//____________________________________________________________________
+AliFMDCorrDoubleHit::AliFMDCorrDoubleHit(const AliFMDCorrDoubleHit& o)
+  : TObject(o), 
+    fCorrections(o.fCorrections)
+{
+}
+//____________________________________________________________________
+AliFMDCorrDoubleHit::~AliFMDCorrDoubleHit()
+{
+  fCorrections.Clear();
+}
+//____________________________________________________________________
+AliFMDCorrDoubleHit&
+AliFMDCorrDoubleHit::operator=(const AliFMDCorrDoubleHit& o)
+{
+  fCorrections   = o.fCorrections;
+
+  return *this;
+}
+//____________________________________________________________________
+TH1D*
+AliFMDCorrDoubleHit::GetCorrection(UShort_t d, Char_t r) const
+{
+  Int_t idx = GetRingIndex(d, r);
+  if (idx < 0) return 0;
+
+  TObject* o = fCorrections.At(idx);
+  if (!o) { 
+    AliWarning(Form("No double hit correction found for FMD%d%c", d, r));
+    return 0;
+  }
+  return static_cast<TH1D*>(o);
+}
+//____________________________________________________________________
+Int_t
+AliFMDCorrDoubleHit::GetRingIndex(UShort_t d, Char_t r) const
+{
+  switch (d) {
+  case 1:  return 0;
+  case 2:  return (r == 'I' || r == 'i' ? 1 : 2); break;  
+  case 3:  return (r == 'I' || r == 'i' ? 3 : 4); break;  
+  }
+  AliWarning(Form("Index for FMD%d%c not found", d, r));
+  return -1;
+}
+//____________________________________________________________________
+Bool_t
+AliFMDCorrDoubleHit::SetCorrection(UShort_t d, Char_t r, TH1D* h) 
+{
+  Int_t idx = GetRingIndex(d, r);
+  if (idx < 0) return kFALSE;
+
+  h->SetName(Form("FMD%d%c", d, r));
+  h->SetTitle(Form("Double hit correction for FMD%d%c", d,r));
+  h->SetXTitle("#eta");
+  h->SetYTitle("#sum_{i} N_{i,strips hit}(#eta)/"
+              "#sum_{i} N_{i,total hits}(#eta)");
+  // h->SetFillColor(Color(d,r));
+  h->SetFillStyle(3001);
+  h->SetDirectory(0);
+  h->SetStats(0);
+  
+  fCorrections.AddAtAndExpand(h, idx);
+  return kTRUE;
+}
+//____________________________________________________________________
+void
+AliFMDCorrDoubleHit::Browse(TBrowser* b)
+{
+  b->Add(&fCorrections);
+}
+//____________________________________________________________________
+void
+AliFMDCorrDoubleHit::Print(Option_t* option) const
+{
+  std::cout << "Double hit correction" << std::endl;
+  fCorrections.Print(option);
+}
+    
+//____________________________________________________________________
+//
+// EOF
+//
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrDoubleHit.h b/PWG2/FORWARD/analysis2/AliFMDCorrDoubleHit.h
new file mode 100644 (file)
index 0000000..0056c58
--- /dev/null
@@ -0,0 +1,129 @@
+//
+// This class contains the secondary correction and the double hit
+// correction used in low-flux events.
+//
+#ifndef ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRDOUBLEHIT_H
+#define ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRDOUBLEHIT_H
+#include <TObject.h>
+#include <TObjArray.h>
+class TH1D;
+
+/**
+ * This class contains double hit correction used in low-flux events.
+ *
+ *
+ * The double hit correction is given by 
+ * @f[
+ *   h_{r}(\eta) = \frac{\sum_i N_{i,strips hit}(\eta)}{
+ *                       \sum_i N_{i,total hits}(\eta)}
+ * @f]
+ *
+ * where @f$ N_{i,strips hit}(\eta)@f$ is the number of strips in the
+ * @f$\eta@f$ bin that had one or more hits in event @f$i@f$, and
+ * @f$N_{i,total hits}(\eta)@f$ is the total number hits in the
+ * @f$\eta@f$ bin. 
+ *
+ * These are generated from Monte-Carlo truth information. 
+ *
+ * @ingroup pwg2_forward_corr
+ * 
+ */
+class AliFMDCorrDoubleHit : public TObject 
+{
+public:
+  /** 
+   * Default constructor 
+   */
+  AliFMDCorrDoubleHit();
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliFMDCorrDoubleHit(const AliFMDCorrDoubleHit& o);
+  /**
+   * Destructor 
+   * 
+   */
+  virtual ~AliFMDCorrDoubleHit();
+  /** 
+   * Assignment operator 
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object 
+   */
+  AliFMDCorrDoubleHit& operator=(const AliFMDCorrDoubleHit& o);
+  /** 
+   * @{ 
+   * @name Get corrections and parameters 
+   */
+  /** 
+   * Get the double hit correction @f$ h_{r}(\eta)@f$ 
+   * 
+   * @param d Detector number 
+   * @param r Ring identifier 
+   * 
+   * @return @f$ h_{r}(\eta)@f$ 
+   */
+  TH1D* GetCorrection(UShort_t d, Char_t r) const;
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Set corrections and parameters 
+   */
+  /** 
+   * Set the double hit correction @f$ h_{r}(\eta)@f$. Note, that the
+   * object takes ownership of the passed pointer.
+   * 
+   * @param d  Detector number (1-3)
+   * @param r  Ring identifier (I or O)
+   * @param h  @f$ h_{r}(\eta)@f$ 
+   * 
+   * @return true if operation succeeded 
+   */
+  Bool_t SetCorrection(UShort_t d, Char_t r, TH1D* h);
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Auxiliary member functions 
+   */
+  /** 
+   * Declare this as a folder
+   * 
+   * @return Always true 
+   */
+  Bool_t IsFolder() const { return true; }
+  /** 
+   * Browse this object in the browser
+   * 
+   * @param b 
+   */
+  void Browse(TBrowser* b);
+  /** 
+   * Print this object 
+   * 
+   * @param option 
+   */  
+  void Print(Option_t* option="R") const; //*MENU*
+  /* @} */
+protected:
+  /** 
+   * Get the index corresponding to the given ring 
+   * 
+   * @param d Detector
+   * @param r Ring 
+   * 
+   * @return Index (0 based) or negative in case of errors
+   */
+  Int_t GetRingIndex(UShort_t d, Char_t r) const;
+
+  TObjArray fCorrections; // Array of per-ring double hit corr. 
+  ClassDef(AliFMDCorrDoubleHit,1); // 
+};
+#endif
+// Local Variables:
+//  mode: C++
+// End:
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrELossFit.cxx b/PWG2/FORWARD/analysis2/AliFMDCorrELossFit.cxx
new file mode 100644 (file)
index 0000000..862af38
--- /dev/null
@@ -0,0 +1,830 @@
+#include "AliFMDCorrELossFit.h"
+#include "AliForwardUtil.h"
+#include <TF1.h>
+#include <TBrowser.h>
+#include <TVirtualPad.h>
+#include <THStack.h>
+#include <TH1D.h>
+#include <AliLog.h>
+#include <TList.h>
+#include <iostream>
+#include <iomanip>
+
+Double_t AliFMDCorrELossFit::ELossFit::fgMaxRelError = .2;
+Double_t AliFMDCorrELossFit::ELossFit::fgLeastWeight = 1e-5;
+Double_t AliFMDCorrELossFit::ELossFit::fgMaxChi2nu   = 20;
+
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit::ELossFit()
+  : fN(0),
+    fNu(0),
+    fChi2(0),
+    fC(0),
+    fDelta(0),
+    fXi(0),
+    fSigma(0),
+    fSigmaN(0),
+    fA(0),
+    fEC(0),
+    fEDelta(0),
+    fEXi(0),
+    fESigma(0),
+    fESigmaN(0),
+    fEA(0),
+    fQuality(0), 
+    fDet(0), 
+    fRing('\0'),
+    fBin(0)
+{}
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit::ELossFit(Int_t quality, const TF1& f)
+  : fN(f.GetNpar() > AliForwardUtil::ELossFitter::kN ? 
+       f.GetParameter(AliForwardUtil::ELossFitter::kN) : 
+       1),
+    fNu(f.GetNDF()),
+    fChi2(f.GetChisquare()),
+    fC(f.GetParameter(AliForwardUtil::ELossFitter::kC)),
+    fDelta(f.GetParameter(AliForwardUtil::ELossFitter::kDelta)),
+    fXi(f.GetParameter(AliForwardUtil::ELossFitter::kXi)),
+    fSigma(f.GetParameter(AliForwardUtil::ELossFitter::kSigma)),
+    fSigmaN(f.GetParameter(AliForwardUtil::ELossFitter::kSigmaN)),
+    fA(0),
+    fEC(f.GetParError(AliForwardUtil::ELossFitter::kC)),
+    fEDelta(f.GetParError(AliForwardUtil::ELossFitter::kDelta)),
+    fEXi(f.GetParError(AliForwardUtil::ELossFitter::kXi)),
+    fESigma(f.GetParError(AliForwardUtil::ELossFitter::kSigma)),
+    fESigmaN(f.GetParError(AliForwardUtil::ELossFitter::kSigmaN)),
+    fEA(0),
+    fQuality(quality),
+    fDet(0), 
+    fRing('\0'),
+    fBin(0)
+{
+  if (fN <= 0) return;
+  fA  = new Double_t[fN];
+  fEA = new Double_t[fN];
+  for (Int_t i = 0; i < fN-1; i++) { 
+    fA[i]  = f.GetParameter(AliForwardUtil::ELossFitter::kA+i);
+    fEA[i] = f.GetParError(AliForwardUtil::ELossFitter::kA+i);
+  }
+  fA[fN-1]  = -9999;
+  fEA[fN-1] = -9999;
+}
+
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit::ELossFit(Int_t     quality,UShort_t  n, 
+                                      Double_t  chi2,   UShort_t  nu, 
+                                      Double_t  c,      Double_t  ec, 
+                                      Double_t  delta,  Double_t  edelta, 
+                                      Double_t  xi,     Double_t  exi,
+                                      Double_t  sigma,  Double_t  esigma, 
+                                      Double_t  sigman, Double_t  esigman, 
+                                      Double_t* a,      Double_t* ea)
+  : fN(n),
+    fNu(nu),
+    fChi2(chi2),
+    fC(c),
+    fDelta(delta),
+    fXi(xi),
+    fSigma(sigma),
+    fSigmaN(sigman),
+    fA(0),
+    fEC(ec),
+    fEDelta(edelta),
+    fEXi(exi),
+    fESigma(esigma),
+    fESigmaN(esigman),
+    fEA(0),
+    fQuality(quality),
+    fDet(0), 
+    fRing('\0'),
+    fBin(0)
+{
+  if (fN <= 0) return;
+  fA  = new Double_t[fN];
+  fEA = new Double_t[fN];
+  for (Int_t i = 0; i < fN-1; i++) { 
+    fA[i]  = a[i];
+    fEA[i] = ea[i];
+  }
+  fA[fN-1]  = -9999;
+  fEA[fN-1] = -9999;
+}
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit::ELossFit(const ELossFit& o)
+  : TObject(o), 
+    fN(o.fN),
+    fNu(o.fNu),
+    fChi2(o.fChi2),
+    fC(o.fC),
+    fDelta(o.fDelta),
+    fXi(o.fXi),
+    fSigma(o.fSigma),
+    fSigmaN(o.fSigmaN),
+    fA(0),
+    fEC(o.fEC),
+    fEDelta(o.fEDelta),
+    fEXi(o.fEXi),
+    fESigma(o.fESigma),
+    fESigmaN(o.fESigmaN),
+    fEA(0),
+    fQuality(o.fQuality),
+    fDet(o.fDet), 
+    fRing(o.fRing),
+    fBin(o.fBin)
+{
+  if (fN <= 0) return;
+  fA  = new Double_t[fN];
+  fEA = new Double_t[fN];
+  for (Int_t i = 0; i < fN-1; i++) { 
+    fA[i]  = o.fA[i];
+    fEA[i] = o.fEA[i];
+  }
+  fA[fN-1]  = -9999;
+  fEA[fN-1] = -9999;
+}
+
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit&
+AliFMDCorrELossFit::ELossFit::operator=(const ELossFit& o)
+{
+  fN      = o.fN;
+  fNu     = o.fNu;
+  fChi2           = o.fChi2;
+  fC      = o.fC;
+  fDelta   = o.fDelta;
+  fXi     = o.fXi;
+  fSigma   = o.fSigma;
+  fSigmaN  = o.fSigmaN;
+  fEC     = o.fEC;
+  fEDelta  = o.fEDelta;
+  fEXi    = o.fEXi;
+  fESigma  = o.fESigma;
+  fESigmaN = o.fESigmaN;
+  fQuality = o.fQuality;
+  fDet     = o.fDet; 
+  fRing    = o.fRing;
+  fBin     = o.fBin;
+  if (fA)  delete [] fA;
+  if (fEA) delete [] fEA; 
+  fA  = 0;
+  fEA = 0;
+
+  if (fN <= 0) return *this;
+  fA  = new Double_t[fN];
+  fEA = new Double_t[fN];
+  for (Int_t i = 0; i < fN; i++) { 
+    fA[i]  = o.fA[i];
+    fEA[i] = o.fEA[i];
+  }
+
+  return *this;
+}
+
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit::~ELossFit()
+{
+  if (fA)  delete[] fA;
+  if (fEA) delete[] fEA;
+}
+
+
+//____________________________________________________________________
+Int_t
+AliFMDCorrELossFit::ELossFit::FindMaxWeight(Double_t maxRelError, 
+                                           Double_t leastWeight, 
+                                           UShort_t  maxN) const
+{
+  Int_t n = TMath::Min(maxN, UShort_t(fN-1));
+  Int_t m = 1;
+  // fN is one larger than we have data 
+  for (Int_t i = 0; i < n-1; i++, m++) { 
+    if (fA[i] < leastWeight)  break;
+    if (fEA[i] / fA[i] > maxRelError) break;
+  }
+  return m;
+}
+
+//____________________________________________________________________
+Double_t 
+AliFMDCorrELossFit::ELossFit::Evaluate(Double_t x, 
+                                      UShort_t maxN) const
+{
+  return AliForwardUtil::NLandauGaus(x, fDelta, fXi, fSigma, fSigmaN, 
+                                    TMath::Min(maxN, UShort_t(fN)), fA);
+}
+
+//____________________________________________________________________
+Double_t 
+AliFMDCorrELossFit::ELossFit::EvaluateWeighted(Double_t x, 
+                                              UShort_t maxN) const
+{                                                                      
+  UShort_t n   = TMath::Min(maxN, UShort_t(fN-1));
+  Double_t num = 0;
+  Double_t den = 0;
+  for (Int_t i = 1; i <= n; i++) {
+    Double_t a = (i == 1 ? 1 : fA[i-1]);
+    if (fA[i-1] < 0) break;
+    Double_t f = AliForwardUtil::ILandauGaus(x,fDelta,fXi,fSigma,fSigmaN,i);
+    num += i * a * f;
+    den += a * f;
+  }
+  if (den <= 0) return 1;
+  return num / den;
+}
+
+
+#define OUTPAR(N,V,E)                  \
+  std::setprecision(9) <<               \
+  std::setw(12) << N << ": " <<        \
+  std::setw(14) << V << " +/- " <<     \
+  std::setw(14) << E << " (" <<        \
+  std::setprecision(-1) <<              \
+  std::setw(5)  << 100*(V>0?E/V:1) << "%)\n"
+  
+
+//____________________________________________________________________
+Int_t
+AliFMDCorrELossFit::ELossFit::Compare(const TObject* o) const
+{
+  const ELossFit* other = static_cast<const ELossFit*>(o);
+  if (this->fQuality < other->fQuality) return -1;
+  if (this->fQuality > other->fQuality) return +1;
+  Double_t chi2nu  = (fNu == 0 ? 1000 : fChi2 / fNu);
+  Double_t oChi2nu = (other->fNu == 0 ? 1000 : other->fChi2 / other->fNu);
+  if (TMath::Abs(chi2nu-1) < TMath::Abs(oChi2nu-1)) return +1;
+  if (TMath::Abs(chi2nu-1) > TMath::Abs(oChi2nu-1)) return -1;
+  return 0;
+}
+
+//____________________________________________________________________
+void
+AliFMDCorrELossFit::ELossFit::Print(Option_t*) const
+{
+  std::cout << GetName() << ":\n"
+           << " chi^2/nu = " << fChi2 << "/" << fNu << " = " 
+           << (fNu == 0 ? 999 : fChi2 / fNu) << "\n"
+           << "     Quality:   " << fQuality << "\n" 
+           << "  NParticles:   " << fN << "  (" << FindMaxWeight() << ")\n"
+           << OUTPAR("Delta", fDelta, fEDelta) 
+           << OUTPAR("xi", fXi, fEXi)
+           << OUTPAR("sigma", fSigma, fESigma)
+           << OUTPAR("sigma_n", fSigmaN, fESigmaN);
+  for (Int_t i = 0; i < fN-1; i++) 
+    std::cout << OUTPAR(Form("a%d", i+2), fA[i], fEA[i]);
+  std::cout << std::flush;
+}
+
+//____________________________________________________________________
+const Char_t*
+AliFMDCorrELossFit::ELossFit::GetName() const 
+{
+  return Form("FMD%d%c_etabin%03d", fDet, fRing, fBin);
+}
+
+//____________________________________________________________________
+void
+AliFMDCorrELossFit::ELossFit::Browse(TBrowser* b)
+{
+  // Draw this one 
+  Draw(b ? b->GetDrawOption() : "comp");
+  gPad->SetLogy();
+  gPad->Update();
+}
+     
+//____________________________________________________________________
+void
+AliFMDCorrELossFit::ELossFit::Draw(Option_t* option)
+{
+  TString opt(option);
+  opt.ToUpper();
+  bool comp = false;
+  if (opt.Contains("COMP")) { 
+    opt.ReplaceAll("COMP","");
+    comp = true;
+  }
+  if (!opt.Contains("SAME")) { 
+    gPad->Clear();
+  }
+
+  TObjArray cleanup;
+  TF1* tot = AliForwardUtil::MakeNLandauGaus(1, 
+                                            fDelta, fXi, 
+                                            fSigma, fSigmaN, 
+                                            fN,     fA, 
+                                            0.01,   10);
+  tot->SetLineColor(kBlack);
+  tot->SetLineWidth(2);
+  tot->SetLineStyle(1);
+  tot->SetTitle(GetName());
+  Double_t max = tot->GetMaximum();
+
+  if (!opt.Contains("SAME")) {
+    TH1* frame = new TH1F(GetName(), 
+                         Form("FMD%d%c, eta bin %d",fDet,fRing,fBin),
+                         100, 0, 10);
+    frame->SetMinimum(max/10000);
+    frame->SetMaximum(max*1.4);
+    frame->SetXTitle("#Delta / #Delta_{mip}");
+    frame->Draw();
+    opt.Append(" SAME");
+  }
+  tot->DrawCopy(opt.Data());
+  cleanup.Add(tot);
+
+  if (!comp) { 
+    gPad->cd();
+    return;
+  }
+
+  Double_t min = max;
+  opt.Append(" same");
+  Int_t maxW = FindMaxWeight();
+  for (Int_t i=1; i <= fN; i++) { 
+    TF1* f = AliForwardUtil::MakeILandauGaus((i == 1 ? 1 : fA[i-2]), 
+                                            fDelta, fXi, 
+                                            fSigma, fSigmaN, 
+                                            i,      0.01, 10);
+    f->SetLineWidth(2);
+    f->SetLineStyle(i > maxW ? 2 : 1);
+    min = TMath::Min(f->GetMaximum(), min);
+    f->DrawCopy(opt.Data());
+    cleanup.Add(f);
+  }
+  min /= 100;
+  tot->GetHistogram()->SetMaximum(max);
+  tot->GetHistogram()->SetMinimum(min);
+  tot->GetHistogram()->GetYaxis()->SetRangeUser(min, max);
+
+  gPad->cd();
+}
+
+                                                
+//____________________________________________________________________
+#define CHECKPAR(V,E,T) ((V > 0) && (E / V < T))
+
+//____________________________________________________________________
+void 
+AliFMDCorrELossFit::ELossFit::CalculateQuality(Double_t maxChi2nu, 
+                                              Double_t maxRelError, 
+                                              Double_t leastWeight)
+{
+  Int_t qual = 0;
+  if (fNu > 0 && fChi2 / fNu < maxChi2nu) qual += 4;;
+  if (CHECKPAR(fDelta,  fEDelta,  maxRelError)) qual++;
+  if (CHECKPAR(fXi,     fEXi,     maxRelError)) qual++;
+  if (CHECKPAR(fSigma,  fESigma,  maxRelError)) qual++;
+  if (CHECKPAR(fSigmaN, fESigmaN, maxRelError)) qual++;
+  qual += FindMaxWeight(1.5*maxRelError, leastWeight, fN);
+  fQuality = qual;
+}
+
+//____________________________________________________________________
+AliFMDCorrELossFit::AliFMDCorrELossFit()
+  : TObject(), 
+    fRings(), 
+    fEtaAxis(0,0,0), 
+    fLowCut(0)
+{
+  fRings.SetOwner(kTRUE);
+  fEtaAxis.SetTitle("#eta");
+  fEtaAxis.SetName("etaAxis");
+  fRings.SetName("rings");
+}
+
+//____________________________________________________________________
+AliFMDCorrELossFit::AliFMDCorrELossFit(const AliFMDCorrELossFit& o)
+  : TObject(o), 
+    fRings(o.fRings),
+    fEtaAxis(o.fEtaAxis.GetNbins(),o.fEtaAxis.GetXmin(),o.fEtaAxis.GetXmax()), 
+    fLowCut(0)
+{
+  fEtaAxis.SetTitle("#eta");
+  fEtaAxis.SetName("etaAxis");
+}
+
+//____________________________________________________________________
+AliFMDCorrELossFit::~AliFMDCorrELossFit()
+{
+  fRings.Clear();
+}
+
+//____________________________________________________________________
+AliFMDCorrELossFit&
+AliFMDCorrELossFit::operator=(const AliFMDCorrELossFit& o)
+{
+  fRings = o.fRings;
+  fLowCut = o.fLowCut;
+  SetEtaAxis(o.fEtaAxis.GetNbins(), o.fEtaAxis.GetXmin(), o.fEtaAxis.GetXmax());
+
+  return *this;
+}
+//____________________________________________________________________
+Int_t
+AliFMDCorrELossFit::FindEtaBin(Double_t eta) const
+{
+  if (fEtaAxis.GetXmin() == fEtaAxis.GetXmax() || fEtaAxis.GetNbins() == 0) {
+    AliWarning("No eta axis defined");
+    return -1;
+  }
+  Int_t bin = const_cast<TAxis&>(fEtaAxis).FindBin(eta);
+  if (bin <= 0 || bin > fEtaAxis.GetNbins()) return 0;
+  return bin;
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Int_t etaBin, ELossFit* fit)
+{
+  TObjArray* ringArray = GetOrMakeRingArray(d, r);
+  if (!ringArray) { 
+    AliError(Form("Failed to make ring array for FMD%d%c", d, r));
+    return kFALSE;
+  }
+  if (etaBin <= 0 || etaBin >= fEtaAxis.GetNbins()+1) { 
+    AliError(Form("bin=%d is out of range [%d,%d]", 
+                 etaBin, 1, fEtaAxis.GetNbins()));
+    return kFALSE;
+  }
+  // AliInfo(Form("Adding fit %p at %3d", fit, etaBin));
+  ringArray->AddAtAndExpand(fit, etaBin);
+  return kTRUE;
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Double_t eta, ELossFit* fit)
+{
+  Int_t bin = FindEtaBin(eta);
+  if (bin <= 0) { 
+    AliError(Form("eta=%f is out of range [%f,%f]", 
+                 eta, fEtaAxis.GetXmin(), fEtaAxis.GetXmax()));
+    return kFALSE;
+  }
+
+  return SetFit(d, r, bin, fit);
+}
+//____________________________________________________________________
+Bool_t
+AliFMDCorrELossFit::SetFit(UShort_t  d,      Char_t    r, 
+                          Double_t  eta, 
+                          Int_t     quality,UShort_t  n, 
+                          Double_t  chi2,   UShort_t  nu, 
+                          Double_t  c,      Double_t  ec, 
+                          Double_t  delta,  Double_t  edelta, 
+                          Double_t  xi,     Double_t  exi,
+                          Double_t  sigma,  Double_t  esigma, 
+                          Double_t  sigman, Double_t  esigman, 
+                          Double_t* a,      Double_t* ea)
+{
+  ELossFit* e = new ELossFit(quality, n, 
+                            chi2,    nu,
+                            c,       ec,
+                            delta,   edelta,
+                            xi,      exi,
+                            sigma,   esigma,
+                            sigman,  esigman,
+                            a,       ea);
+  if (!SetFit(d, r, eta, e)) { 
+    delete e;
+    return kFALSE;
+  }
+  return kTRUE;
+}
+//____________________________________________________________________
+Bool_t
+AliFMDCorrELossFit::SetFit(UShort_t  d, Char_t r, Double_t eta, 
+                          Int_t quality, const TF1& f)
+{
+  ELossFit* e = new ELossFit(quality, f);
+  if (!SetFit(d, r, eta, e)) { 
+    delete e;
+    return kFALSE;
+  }
+  return kTRUE;
+}
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit*
+AliFMDCorrELossFit::FindFit(UShort_t  d, Char_t r, Int_t etabin) const
+{
+  TObjArray* ringArray = GetRingArray(d, r);
+  if (!ringArray) { 
+    AliError(Form("Failed to make ring array for FMD%d%c", d, r));
+    return 0;
+  }
+  if (etabin <= 0 || etabin >= fEtaAxis.GetNbins()) { 
+    AliError(Form("Eta bin=%3d out of bounds [%d,%d] for FMD%d%c", 
+                 etabin, 1, fEtaAxis.GetNbins(), d, r));
+    return 0;
+  }
+  if (etabin > ringArray->GetEntriesFast()) { 
+    AliError(Form("Eta bin=%3d out of bounds [%d,%d] for FMD%d%c", 
+                 etabin, 1, ringArray->GetEntriesFast(), d, r));
+    return 0;
+  }
+  else if (etabin >= ringArray->GetEntriesFast()) { 
+    AliWarning(Form("Eta bin=%3d out of bounds by +1 [%d,%d] for FMD%d%c, " 
+                   "trying %3d", etabin, 1, ringArray->GetEntriesFast(), d, r,
+                   etabin-1));
+    etabin--;
+  }
+  else if (!ringArray->At(etabin)) { 
+    AliWarning(Form("Eta bin=%d has no fit for FMD%d%c, trying %03d", 
+                   etabin, d, r, etabin+1));
+    etabin++;
+  }
+  return static_cast<ELossFit*>(ringArray->At(etabin));
+}
+//____________________________________________________________________
+AliFMDCorrELossFit::ELossFit*
+AliFMDCorrELossFit::FindFit(UShort_t  d, Char_t r, Double_t eta) const
+{
+  Int_t etabin = FindEtaBin(eta);
+  return FindFit(d, r, etabin);
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrELossFit::GetRingArray(UShort_t d, Char_t r) const
+{
+  Int_t idx = -1;
+  switch (d) { 
+  case 1:   idx = 0; break;
+  case 2:   idx = (r == 'i' || r == 'I') ? 1 : 2; break;
+  case 3:   idx = (r == 'o' || r == 'I') ? 3 : 4; break;
+  }
+  if (idx < 0 || idx >= fRings.GetEntriesFast()) return 0;
+  return static_cast<TObjArray*>(fRings.At(idx));
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrELossFit::GetOrMakeRingArray(UShort_t d, Char_t r)
+{
+  Int_t idx = -1;
+  switch (d) { 
+  case 1:   idx = 0; break;
+  case 2:   idx = (r == 'i' || r == 'I') ? 1 : 2; break;
+  case 3:   idx = (r == 'o' || r == 'I') ? 3 : 4; break;
+  }
+  if (idx < 0) return 0;
+  if (idx >= fRings.GetEntriesFast() || !fRings.At(idx)) {
+    TObjArray* a = new TObjArray(0);
+    // TOrdCollection* a = new TOrdCollection(fEtaAxis.GetNbins());
+    a->SetName(Form("FMD%d%c", d, r));
+    a->SetOwner();
+    fRings.AddAtAndExpand(a, idx);
+  }
+  return static_cast<TObjArray*>(fRings.At(idx));
+}
+
+namespace { 
+  TH1D* MakeHist(const TAxis& axis, const char* name, const char* title, 
+                Int_t color)
+  {
+    TH1D* h = new TH1D(Form("%s_%s", name, title), 
+                      Form("%s %s", name, title), 
+                      axis.GetNbins(), axis.GetXmin(), axis.GetXmax());
+    h->SetDirectory(0);
+    h->SetMarkerStyle(20);
+    h->SetMarkerColor(color);
+    h->SetMarkerSize(0.5);
+    h->SetFillColor(color);
+    h->SetFillStyle(3001);
+    h->SetLineColor(color);
+    return h;
+  }
+}
+
+//____________________________________________________________________
+void
+AliFMDCorrELossFit::Draw(Option_t* option)
+{
+  TString opt(Form("nostack %s", option));
+  opt.ToLower();
+  Bool_t  rel = (opt.Contains("rel"));
+  Bool_t  err = (opt.Contains("err"));
+  if (rel) opt.ReplaceAll("rel","");
+  if (err) opt.ReplaceAll("err","");
+  Int_t    nRings = fRings.GetEntriesFast();
+  UShort_t maxN   = 0;
+  for (Int_t i = 0; i < nRings; i++) { 
+    if (!fRings.At(i)) continue;
+    TObjArray* a     = static_cast<TObjArray*>(fRings.At(i));
+    Int_t      nFits = a->GetEntriesFast();
+
+    for (Int_t j = 0; j < nFits; j++) {
+      ELossFit* fit = static_cast<ELossFit*>(a->At(j));
+      if (!fit) continue;
+      maxN          = TMath::Max(maxN, UShort_t(fit->fN));
+    }
+  }
+  // AliInfo(Form("Maximum N is %d", maxN));
+  Int_t nPad = 7+maxN-1; // 7 regular params, and maxN-1 weights
+  TVirtualPad* pad = gPad;
+  pad->Divide(2, (nPad+1)/2, 0.1, 0, 0);
+  
+  THStack* chi2nu;
+  THStack* c;
+  THStack* delta;
+  THStack* xi;
+  THStack* sigma;
+  THStack* sigman;
+  THStack* n;
+  TList stacks;
+  stacks.AddAt(chi2nu= new THStack("chi2",   "#chi^{2}/#nu"), 0);
+  stacks.AddAt(c     = new THStack("c",       "C"),           1);
+  stacks.AddAt(delta = new THStack("delta",  "#Delta_{mp}"),  2);
+  stacks.AddAt(xi    = new THStack("xi",     "#xi"),          3);
+  stacks.AddAt(sigma = new THStack("sigma",  "#sigma"),       4);
+  stacks.AddAt(sigman= new THStack("sigman", "#sigma_{n}"),   5);
+  stacks.AddAt(n     = new THStack("n",      "N"),            6);
+  for (Int_t i = 1; i <= maxN; i++) {
+    stacks.AddAt(new THStack(Form("a_%02d", i+1), Form("a_{%d}", i+1)), 6+i);
+  }
+
+  for (Int_t i = 0; i < nRings; i++) { 
+    if (!fRings.At(i)) continue;
+    TObjArray* a     = static_cast<TObjArray*>(fRings.At(i));
+    Int_t      nFits = a->GetEntriesFast();
+    Int_t      color = 0;
+    switch (i) { 
+    case 0: color = kRed+2;   break;
+    case 1: color = kGreen+2; break;
+    case 2: color = kGreen-2; break;
+    case 3: color = kBlue+2;  break;
+    case 4: color = kBlue-2;  break;
+    }
+
+    TH1D* hChi    = MakeHist(fEtaAxis,a->GetName(), "chi2",   color);
+    TH1D* hC      = MakeHist(fEtaAxis,a->GetName(), "c",      color);
+    TH1D* hDelta  = MakeHist(fEtaAxis,a->GetName(), "delta",  color);
+    TH1D* hXi     = MakeHist(fEtaAxis,a->GetName(), "xi",     color);
+    TH1D* hSigma  = MakeHist(fEtaAxis,a->GetName(), "sigma",  color);
+    TH1D* hSigmaN = MakeHist(fEtaAxis,a->GetName(), "sigman", color);
+    TH1D* hN      = MakeHist(fEtaAxis,a->GetName(), "n",      color);
+    TH1D* hA[maxN];
+    const char* ho = (rel || !err ? "hist" : "e");
+    chi2nu->Add(hChi,   "hist"); // 0
+    c     ->Add(hC,     ho);     // 1
+    delta ->Add(hDelta, ho);     // 2
+    xi    ->Add(hXi,    ho);     // 3
+    sigma ->Add(hSigma, ho);     // 4
+    sigman->Add(hSigmaN,ho);     // 5
+    n     ->Add(hN,     "hist"); // 6
+    hChi->SetFillColor(color);
+    hChi->SetFillStyle(3001);
+    hN->SetFillColor(color);
+    hN->SetFillStyle(3001);
+
+    for (Int_t k = 1; k <= maxN; k++) { 
+      hA[k-1] = MakeHist(fEtaAxis,a->GetName(), Form("a%02d",k+1), color);
+      static_cast<THStack*>(stacks.At(6+k))->Add(hA[k-1], ho);
+    }
+                         
+    for (Int_t j = 0; j < nFits; j++) {
+      ELossFit* f = static_cast<ELossFit*>(a->At(j));
+      if (!f) continue;
+
+      Int_t     b = f->fBin;
+      Int_t     nW = f->FindMaxWeight();
+      hChi   ->SetBinContent(b, (f->fNu <= 0 ? 0 : f->fChi2 / f->fNu));
+      hN     ->SetBinContent(b, nW);
+
+      if (rel) { 
+       hC     ->SetBinContent(b, f->fC     >0 ?f->fEC     /f->fC      :0);
+       hDelta ->SetBinContent(b, f->fDelta >0 ?f->fEDelta /f->fDelta  :0);
+       hXi    ->SetBinContent(b, f->fXi    >0 ?f->fEXi    /f->fXi     :0);
+       hSigma ->SetBinContent(b, f->fSigma >0 ?f->fESigma /f->fSigma  :0);
+       hSigmaN->SetBinContent(b, f->fSigmaN>0 ?f->fESigmaN/f->fSigmaN :0);
+      }
+      else {
+       hC     ->SetBinContent(b, f->fC);
+       hDelta ->SetBinContent(b, f->fDelta);
+       hXi    ->SetBinContent(b, f->fXi);
+       hSigma ->SetBinContent(b, f->fSigma);
+       hSigmaN->SetBinContent(b, f->fSigmaN);
+       hC     ->SetBinError(b, f->fEC);
+       hDelta ->SetBinError(b, f->fEDelta);
+       hXi    ->SetBinError(b, f->fEXi);
+       hSigma ->SetBinError(b, f->fESigma);
+       hSigmaN->SetBinError(b, f->fESigmaN);
+      }
+      for (Int_t k = 0; k < f->fN-1 && k < maxN; k++) { 
+       if (rel) 
+         hA[k]->SetBinContent(b, f->fA[k] > 0 ? f->fEA[k] / f->fA[k] : 0);
+       else {
+         hA[k]->SetBinContent(b, f->fA[k]);
+         hA[k]->SetBinError(b, f->fEA[k]);
+       }
+      }
+    }
+  }
+  Int_t nPad2 = (nPad+1) / 2;
+  for (Int_t i = 0; i < nPad; i++) {
+    Int_t iPad = 1 + i/nPad2 + 2 * (i % nPad2);
+    TVirtualPad* p = pad->cd(iPad);
+    p->SetLeftMargin(.15);
+    p->SetFillColor(0);
+    p->SetFillStyle(0);
+    p->SetGridx();
+    p->SetGridy();
+    if (rel && i != 0 && i != 6 && i != 5 && i != 4) p->SetLogy();
+
+    THStack* stack = static_cast<THStack*>(stacks.At(i));
+    // AliInfo(Form("Drawing %s (%d) in pad %d", stack->GetName(), i, iPad));
+    stack->Draw(opt.Data());
+
+    TString tit(stack->GetTitle());
+    if (rel && i != 0 && i != 6)
+      tit = Form("#delta %s/%s", tit.Data(), tit.Data());
+    TH1*   hist  = stack->GetHistogram();
+    TAxis* yaxis = hist->GetYaxis();
+    yaxis->SetTitle(tit.Data());
+    yaxis->SetTitleSize(0.15);
+    yaxis->SetLabelSize(0.08);
+    yaxis->SetTitleOffset(0.35);
+    yaxis->SetNdivisions(5);
+
+    TAxis* xaxis = stack->GetHistogram()->GetXaxis();
+    xaxis->SetTitle("#eta");
+    xaxis->SetTitleSize(0.15);
+    xaxis->SetLabelSize(0.08);
+    xaxis->SetTitleOffset(0.35);
+    xaxis->SetNdivisions(10);
+
+
+    if (!rel) {
+      switch (i) { 
+      case 0:                         break; // chi^2/nu 
+      case 1:                         break; // C 
+      case 2: stack->SetMinimum(0.4); break; // Delta 
+      case 3: stack->SetMinimum(0.02);break; // xi
+      case 4: stack->SetMinimum(0.05);break; // sigma
+      case 5:                         break; // sigmaN
+      case 6: 
+       stack->SetMinimum(-.1); 
+       stack->SetMaximum(maxN+.5); 
+       break;                              // N
+      default:                       break; // Weights
+      }
+    }
+    stack->DrawClone(opt.Data());
+  }
+  pad->cd();      
+}
+
+//____________________________________________________________________
+void
+AliFMDCorrELossFit::Print(Option_t* option) const
+{
+  TString opt(option);
+  opt.ToUpper();
+  Int_t nRings = fRings.GetEntriesFast();
+  bool recurse = opt.Contains("R");
+
+  std::cout << "Low cut in fit range: " << fLowCut << "\n"
+           << "Eta axis:             " << fEtaAxis.GetNbins() 
+           << " bins, range [" << fEtaAxis.GetXmin() << "," 
+           << fEtaAxis.GetXmax() << "]" << std::endl;
+  
+  for (Int_t i = 0; i < nRings; i++) { 
+    if (!fRings.At(i)) continue;
+    TObjArray* a     = static_cast<TObjArray*>(fRings.At(i));
+    Int_t      nFits = a->GetEntriesFast();
+
+    std::cout << a->GetName() << " [" << nFits << " entries]" 
+             << (recurse ? ":\n" : "\t");
+    Int_t min = fEtaAxis.GetNbins()+1;
+    Int_t max = 0;
+    for (Int_t j = 0; j < nFits; j++) {
+      if (!a->At(j)) continue;
+      
+      min = TMath::Min(j, min);
+      max = TMath::Max(j, max);
+
+      if (recurse) {
+       std::cout << "Bin # " << j << "\t";
+       ELossFit* fit = static_cast<ELossFit*>(a->At(j));
+       fit->Print(option);
+      }
+    }
+    if (!recurse) 
+      std::cout << " bin range: " << std::setw(3) << min 
+               << "-" << std::setw(3) << max << " " << std::setw(3) 
+               << (max-min+1) << " bins" << std::endl;
+  }
+}
+
+//____________________________________________________________________
+void
+AliFMDCorrELossFit::Browse(TBrowser* b)
+{
+  b->Add(&fRings);
+  b->Add(&fEtaAxis);
+}
+
+
+
+//____________________________________________________________________
+//
+// EOF
+//
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrELossFit.h b/PWG2/FORWARD/analysis2/AliFMDCorrELossFit.h
new file mode 100644 (file)
index 0000000..38933ee
--- /dev/null
@@ -0,0 +1,579 @@
+#ifndef ALIROOT_PWG2_FORWARD_ALIFMDCORRELOSSFIT_H
+#define ALIROOT_PWG2_FORWARD_ALIFMDCORRELOSSFIT_H
+#include <TObject.h>
+#include <TAxis.h>
+#include <TObjArray.h>
+class TF1;
+class TBrowser;
+
+/** 
+ * Object holding the Energy loss fit 'correction'
+ * 
+ * These are generated from Monte-Carlo or real ESDs. 
+ *
+ * @ingroup pwg2_forward_corr
+ */
+class AliFMDCorrELossFit : public TObject 
+{
+public:
+  /** 
+   * POD structure to hold data from fits 
+   * 
+   */
+  struct ELossFit : public TObject 
+  {
+    Int_t     fN;      // Number of peaks fitted
+    UShort_t  fNu;     // Number degrees of freedom
+    Double_t  fChi2;   // Chi square from fit
+    Double_t  fC;      // Scaling constant 
+    Double_t  fDelta;  // Most probable value 
+    Double_t  fXi;     // Width parameter of Landau 
+    Double_t  fSigma;  // Sigma on folded gaussian 
+    Double_t  fSigmaN; // Sigma of detector noise 
+    Double_t* fA;      // [fN] Weights 
+    Double_t  fEC;     // Error on C 
+    Double_t  fEDelta; // Error on Delta 
+    Double_t  fEXi;    // Error on Xi
+    Double_t  fESigma; // Error on sigma 
+    Double_t  fESigmaN;// Error on sigma (noise)
+    Double_t* fEA;     // [fN] Error on weights
+    Int_t     fQuality;// Assigned quality 
+    UShort_t  fDet;    // Detector 
+    Char_t    fRing;   // Ring
+    UShort_t  fBin;    // Eta bin
+
+    static Double_t fgMaxRelError;  // Global default max relative error
+    static Double_t fgLeastWeight;  // Global default least weight 
+    static Double_t fgMaxChi2nu;    // Global default maximum reduced chi^2
+    /**
+     * Default constructor 
+     * 
+     */
+    ELossFit();
+    /** 
+     * Construct from a function
+     * 
+     * @param quality Quality flag
+     * @param f       Function
+     */
+    ELossFit(Int_t quality,const TF1& f);
+    /** 
+     * Constructor with full parameter set
+     * 
+     * @param d         Detector number
+     * @param r         Ring identifier 
+     * @param quality   Quality flag
+     * @param n         @f$ N@f$ - Number of fitted peaks
+     * @param chi2      @f$ \chi^2 @f$
+     * @param nu        @f$ \nu @f$ - number degrees of freedom
+     * @param c         @f$ C2f$ - scale constant
+     * @param ec        @f$ \delta C@f$ - error on @f$ C@f$ 
+     * @param delta     @f$ \Delta2f$ - scale constant           
+     * @param edelta    @f$ \delta\Delta@f$ - error on @f$\Delta@f$ 
+     * @param xi        @f$ \xi2f$ - scale constant              
+     * @param exi       @f$ \delta\xi@f$ - error on @f$\xi@f$ 
+     * @param sigma     @f$ \sigma@f$ - scale constant            
+     * @param esigma    @f$ \delta\sigma@f$ - error on @f$\sigma@f$ 
+     * @param sigman    @f$ \sigma_n@f$ - scale constant                 
+     * @param esigman   @f$ \delta\sigma_n@f$ - error on @f$\sigma_n@f$ 
+     * @param a         Array of @f$ N-1@f$ weights @f$ a_i@f$ for 
+     *                  @f$ i=2,\ldots@f$ 
+     */
+    ELossFit(Int_t     quality,UShort_t  n, 
+            Double_t  chi2,   UShort_t  nu, 
+            Double_t  c,      Double_t  ec, 
+            Double_t  delta,  Double_t  edelta, 
+            Double_t  xi,     Double_t  exi,
+            Double_t  sigma,  Double_t  esigma, 
+            Double_t  sigman, Double_t  esigman, 
+            Double_t* a,      Double_t* ea);
+    /** 
+     * Copy constructor 
+     * 
+     * @param o Object to copy from 
+     */
+    ELossFit(const ELossFit& o);
+    /** 
+     * Assignment operator 
+     * 
+     * @param o Object to assign from 
+     * 
+     * @return Reference to this object 
+     */
+    ELossFit& operator=(const ELossFit& o);
+    /** 
+     * Destructor 
+     */
+    ~ELossFit();
+    /**
+     * @{
+     * @name Access to parameters 
+     */
+    /**
+     * @return Number of peaks fitted
+     */
+    Int_t GetN() const { return fN; }
+    /**
+     * @return Number degrees of freedom
+     */
+    UShort_t GetNu() const { return fNu; }
+    /**
+     * @return Chi square from fit
+     */
+    Double_t GetChi2() const { return fChi2; }
+    /**
+     * @return Scaling constant 
+     */
+    Double_t GetC() const { return fC; }
+    /**
+     * @return Most probable value 
+     */
+    Double_t GetDelta() const { return fDelta; }
+    /**
+     * @return Width parameter of Landau 
+     */
+    Double_t GetXi() const { return fXi; }
+    /**
+     * @return Sigma on folded gaussian 
+     */
+    Double_t GetSigma() const { return fSigma; }
+    /**
+     * @return Sigma of detector noise 
+     */
+    Double_t GetSigmaN() const { return fSigmaN; }
+    /**
+     * @return Weights 
+     */
+    Double_t* GetAs() const { return fA; }
+    /**
+     * @return Weights 
+     */
+    Double_t GetA(UShort_t i) const;    
+    /**
+     * @return Error on C 
+     */
+    Double_t GetEC() const { return fEC; }
+    /**
+     * @return Error on Delta 
+     */
+    Double_t GetEDelta() const { return fEDelta; }
+    /**
+     * @return Error on Xi
+     */
+    Double_t GetEXi() const { return fEXi; }
+    /**
+     * @return Error on sigma 
+     */
+    Double_t GetESigma() const { return fESigma; }
+    /**
+     * @return Error on sigma (noise)
+     */
+    Double_t GetESigmaN() const { return fESigmaN; }
+    /**
+     * @return Error on weights
+     */
+    Double_t* GetEAs() const { return fEA; }
+    /**
+     * @return Error on weights
+     */
+    Double_t GetEA(UShort_t i) const;
+    /**
+     * @return Assigned quality 
+     */
+    Int_t GetQuality() const { return fQuality; }
+    /**
+     * @return Detector 
+     */
+    UShort_t GetDet() const { return fDet; }
+    /**
+     * @return Ring
+     */
+    Char_t GetRing() const { return fRing; }
+    /**
+     * @return Eta bin
+     */
+    UShort_t GetBin() const { return fBin; }
+    /* @} */
+
+    /** 
+     * @{ 
+     * @name Evaluation 
+     */
+    /** 
+     * Evaluate 
+     * @f[ 
+     *  f_N(x;\Delta,\xi,\sigma') = 
+     *     \sum_{i=1}^{n} a_i f(x;\Delta_i,\xi_i,\sigma_i')
+     * @f] 
+     *
+     * (see AliForwardUtil::NLandauGaus) for the maximum @f$ N @f$
+     * that fulfills the requirements 
+     *
+     * @param x           Where to evaluate 
+     * @param maxN       @f$ \max{N}@f$    
+     * 
+     * @return @f$ f_N(x;\Delta,\xi,\sigma')@f$ 
+     */
+    Double_t Evaluate(Double_t x, 
+                     UShort_t maxN=999) const;
+    /** 
+     * Evaluate 
+     * @f[ 
+     *   f_W(x;\Delta,\xi,\sigma') = 
+     *   \frac{\sum_{i=1}^{n} i a_i f_i(x;\Delta,\xi,\sigma')}{
+     *     f_N(x;\Delta,\xi,\sigma')} = 
+     *   \frac{\sum_{i=1}^{n} i a_i f(x;\Delta_i,\xi_i,\sigma_i')}{
+     *     \sum_{i=1}^{n} a_i f(x;\Delta_i,\xi_i,\sigma_i')}
+     * @f] 
+     * where @f$ n@f$ fulfills the requirements (see FindMaxWeight). 
+     *
+     * If the denominator is zero, then 1 is returned. 
+     *
+     * See also AliForwardUtil::ILandauGaus and AliForwardUtil::NLandauGaus
+     * for more information on the evaluated functions. 
+     * 
+     * @param x           Where to evaluate 
+     * @param maxN       @f$ \max{N}@f$      
+     * 
+     * @return @f$ f_W(x;\Delta,\xi,\sigma')@f$.  
+     */
+    Double_t EvaluateWeighted(Double_t x, 
+                             UShort_t maxN=9999) const;
+    /** 
+     * Find the maximum weight to use.  The maximum weight is the
+     * largest i for which 
+     * 
+     * - @f$ i \leq \max{N}@f$ 
+     * - @f$ a_i > \min{a}@f$ 
+     * - @f$ \delta a_i/a_i > \delta_{max}@f$ 
+     * 
+     * @param maxRelError @f$ \min{a}@f$ 
+     * @param leastWeight @f$ \delta_{max}@f$ 
+     * @param maxN        @f$ \max{N}@f$      
+     * 
+     * @return The largest index @f$ i@f$ for which the above
+     * conditions hold.  Will never return less than 1. 
+     */
+    Int_t FindMaxWeight(Double_t maxRelError=2*fgMaxRelError, 
+                       Double_t leastWeight=fgLeastWeight, 
+                       UShort_t maxN=999) const;
+    /* @} */
+    /** 
+     * @{
+     * @name TObject Sortable interface 
+     */
+    /** 
+     * Declare this object as sortable 
+     * 
+     * @return Always true 
+     */
+    Bool_t IsSortable() const { return kTRUE; }
+    /** 
+     * Compare to another ELossFit object. 
+     * 
+     * - +1, if this quality is better (larger) than other objects quality
+     * - -1, if this quality is worse (smaller) than other objects quality
+     * - +1, if this @f$|\chi^2/\nu-1|@f$ is smaller than the same for other
+     * - -1, if this @f$|\chi^2/\nu-1|@f$ is larger than the same for other
+     * - 0 otherwise 
+     * 
+     * @param o Other object to compare to 
+     */
+    Int_t Compare(const TObject* o) const;
+    /* @} */
+    /** 
+     * @{ 
+     * name Auxiliary member functions  
+     */
+    /** 
+     * Information to standard output 
+     * 
+     * @param option Not used 
+     */
+    void Print(Option_t* option) const; // *MENU*
+    /** 
+     * Draw this fit 
+     * 
+     * @param option Options 
+     *  - COMP  Draw components too 
+     */
+    void Draw(Option_t* option="comp"); // *MENU*
+    /** 
+     * Browse this object 
+     * 
+     * @param b Browser
+     */
+    void Browse(TBrowser* b);
+    /** 
+     * Get the name of this object 
+     * 
+     * 
+     * @return 
+     */
+    const Char_t* GetName() const;
+    /** 
+     * Calculate the quality 
+     */
+    void CalculateQuality(Double_t maxChi2nu=fgMaxChi2nu, 
+                         Double_t maxRelError=fgMaxRelError, 
+                         Double_t leastWeight=fgLeastWeight);
+    /* @} */
+    ClassDef(ELossFit,1); // Result of fit 
+  };
+
+  /** 
+   * Default constructor 
+   */
+  AliFMDCorrELossFit();
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliFMDCorrELossFit(const AliFMDCorrELossFit& o);
+  /** 
+   * Destructor 
+   */
+  virtual ~AliFMDCorrELossFit(); 
+  /** 
+   * Assignment operator 
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object 
+   */
+  AliFMDCorrELossFit& operator=(const AliFMDCorrELossFit& o);
+
+  /** 
+   * @{ 
+   * @name Set fits 
+   */
+  /** 
+   * Set the fit parameters from a function 
+   * 
+   * @param d        Detector
+   * @param r        Ring 
+   * @param eta      Eta 
+   * @param quality  Quality flag
+   * @param f        Function from fit 
+   */  
+  Bool_t SetFit(UShort_t d, Char_t r, Double_t eta, Int_t quality, 
+               const TF1& f);
+  /** 
+   * Set the fit parameters from a function 
+   * 
+   * @param d    Detector
+   * @param r    Ring 
+   * @param eta  Eta 
+   * @param f    ELoss fit result - note, the object will take ownership
+   */  
+  Bool_t SetFit(UShort_t d, Char_t r, Double_t eta, ELossFit* f);
+  /** 
+   * Set the fit parameters from a function 
+   * 
+   * @param d    Detector
+   * @param r    Ring 
+   * @param eta  Eta (bin number, 1->nBins)
+   * @param f    ELoss fit result - note, the object will take ownership
+   */  
+  Bool_t SetFit(UShort_t d, Char_t r, Int_t etaBin, ELossFit* f);
+  /** 
+   * Set the fit parameters from a function 
+   * 
+   * @param d         Detector number
+   * @param r         Ring identifier 
+   * @param quality   Quality flag
+   * @param n         @f$ N@f$ - Number of fitted peaks
+   * @param chi2      @f$ \chi^2 @f$
+   * @param nu        @f$ \nu @f$ - number degrees of freedom
+   * @param c         @f$ C2f$ - scale constant
+   * @param ec        @f$ \delta C@f$ - error on @f$ C@f$ 
+   * @param delta     @f$ \Delta2f$ - scale constant             
+   * @param edelta    @f$ \delta\Delta@f$ - error on @f$\Delta@f$ 
+   * @param xi        @f$ \xi2f$ - scale constant                
+   * @param exi       @f$ \delta\xi@f$ - error on @f$\xi@f$ 
+   * @param sigma     @f$ \sigma@f$ - scale constant              
+   * @param esigma    @f$ \delta\sigma@f$ - error on @f$\sigma@f$ 
+   * @param sigman    @f$ \sigma_n@f$ - scale constant           
+   * @param esigman   @f$ \delta\sigma_n@f$ - error on @f$\sigma_n@f$ 
+   * @param a         Array of @f$ N-1@f$ weights @f$ a_i@f$ for 
+   *                  @f$ i=2,\ldots@f$ 
+   */
+  Bool_t SetFit(UShort_t  d,      Char_t    r, Double_t eta, 
+               Int_t     quality,UShort_t  n, 
+               Double_t  chi2,   UShort_t  nu, 
+               Double_t  c,      Double_t  ec, 
+               Double_t  delta,  Double_t  edelta, 
+               Double_t  xi,     Double_t  exi,
+               Double_t  sigma,  Double_t  esigma, 
+               Double_t  sigman, Double_t  esigman, 
+               Double_t* a,      Double_t* ea);
+  /* @} */
+  
+  /** 
+   * @{
+   * @name Set and get eta axis
+   */
+  /** 
+   * Set the eta axis to use 
+   * 
+   * @param axis Eta axis 
+   */
+  void SetEtaAxis(const TAxis& axis);
+  /** 
+   * Set the eta axis to use 
+   * 
+   * @param axis Eta axis 
+   */
+  void SetEtaAxis(Int_t nBins, Double_t min, Double_t max);
+  /** 
+   * Get the eta axis used
+   * 
+   * @return 
+   */
+  const TAxis& GetEtaAxis() const { return fEtaAxis; }
+  /** 
+   * Set the low cut used when fitting 
+   * 
+   * @param cut Cut value 
+   */
+  void SetLowCut(Double_t cut) { fLowCut = cut; }
+  /** 
+   * Get the low cut used when fitting 
+   * 
+   * @return Low cut used for fitting 
+   */
+  Double_t GetLowCut() const { return fLowCut; }
+  /** 
+   * Find the eta bin corresponding to the given eta 
+   * 
+   * @param eta  Eta value 
+   * 
+   * @return Bin (in @f$[1,N_{bins}]@f$) corresponding to the given
+   * eta, or 0 if out of range.
+   */
+  Int_t FindEtaBin(Double_t eta) const;
+  /* @} */
+
+  /**
+   * @{                                                
+   * @name Find fits 
+   */
+  /** 
+   * Find the fit corresponding to the specified parameters 
+   * 
+   * @param d   Detector 
+   * @param r   Ring 
+   * @param eta Eta value 
+   * 
+   * @return Fit parameters or null in case of problems 
+   */
+  ELossFit* FindFit(UShort_t d, Char_t r, Double_t eta) const;
+  /** 
+   * Find the fit corresponding to the specified parameters 
+   * 
+   * @param d      Detector 
+   * @param r      Ring 
+   * @param etabin Eta bin (1 based)
+   * 
+   * @return Fit parameters or null in case of problems 
+   */
+  ELossFit* FindFit(UShort_t d, Char_t r, Int_t etabin) const;
+  /* @} */
+
+  /**                                          
+   * @{ 
+   * @name Miscellaneous
+   */
+  /** 
+   * Get the ring array corresponding to the specified ring
+   * 
+   * @param d Detector 
+   * @param r Ring 
+   * 
+   * @return Pointer to ring array, or null in case of problems
+   */
+  TObjArray* GetRingArray(UShort_t d, Char_t r) const;
+  /** 
+   * Signal that this is a folder
+   * 
+   * @return Always true 
+   */
+  Bool_t IsFolder() const { return true; }
+  /** 
+   * Browse this object 
+   * 
+   * @param b 
+   */
+  void Browse(TBrowser* b);
+  /** 
+   * Draw this object 
+   *
+   * @param option Options.  Possible values are 
+   *  - err Plot error bars 
+   */
+  void Draw(Option_t* option=""); //*MENU*
+  /** 
+   * Print this object.  
+   * 
+   * @param option Options 
+   *   - R   Print recursive  
+   *
+   */
+  void Print(Option_t* option="R") const; //*MENU*
+  /* @} */
+protected:
+  /** 
+   * Get the ring array corresponding to the specified ring
+   * 
+   * @param d Detector 
+   * @param r Ring 
+   * 
+   * @return Pointer to ring array, or newly created container 
+   */
+  TObjArray* GetOrMakeRingArray(UShort_t d, Char_t r);
+
+  TObjArray  fRings;    // Array of rings
+  TAxis      fEtaAxis;  // Eta axis used
+  Double_t   fLowCut;   // Low cut used when fitting 
+
+  ClassDef(AliFMDCorrELossFit,2); 
+};
+
+//____________________________________________________________________
+inline void 
+AliFMDCorrELossFit::SetEtaAxis(Int_t nBins, Double_t min, Double_t max)
+{
+  fEtaAxis.Set(nBins, min, max);
+}
+//____________________________________________________________________
+inline void 
+AliFMDCorrELossFit::SetEtaAxis(const TAxis& e)
+{
+  fEtaAxis.Set(e.GetNbins(), e.GetXmin(), e.GetXmax());
+}
+//____________________________________________________________________
+inline Double_t
+AliFMDCorrELossFit::ELossFit::GetA(UShort_t i) const
+{
+  if (i <  1)   return 0;
+  if (i >  fN)  return 0;
+  if (i == 1)   return 1;
+  return fA[i-2];
+}
+//____________________________________________________________________
+inline Double_t
+AliFMDCorrELossFit::ELossFit::GetEA(UShort_t i) const
+{
+  if (i <  1)   return 0;
+  if (i >  fN)  return 0;
+  if (i == 1)   return 1;
+  return fEA[i-2];
+}
+
+
+#endif
+// Local Variables:
+//   mode: C++ 
+// End:
+
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrMergingEfficiency.cxx b/PWG2/FORWARD/analysis2/AliFMDCorrMergingEfficiency.cxx
new file mode 100644 (file)
index 0000000..8ac414f
--- /dev/null
@@ -0,0 +1,193 @@
+#include "AliFMDCorrMergingEfficiency.h"
+#include <TBrowser.h>
+#include <TH1D.h>
+#include <AliLog.h>
+#include <iostream>
+
+//____________________________________________________________________
+AliFMDCorrMergingEfficiency::AliFMDCorrMergingEfficiency()
+  : fRingArray(), 
+    fVertexAxis(0,0,0)
+{
+  fRingArray.SetOwner(kTRUE);
+  fRingArray.SetName("rings");
+  fVertexAxis.SetName("vtxAxis");
+  fVertexAxis.SetTitle("v_{z} [cm]");
+  
+}
+//____________________________________________________________________
+AliFMDCorrMergingEfficiency::AliFMDCorrMergingEfficiency(const 
+                                              AliFMDCorrMergingEfficiency& o)
+  : TObject(o), 
+    fRingArray(o.fRingArray), 
+    fVertexAxis(o.fVertexAxis.GetNbins(), o.fVertexAxis.GetXmin(), 
+               o.fVertexAxis.GetXmax())
+{
+  fVertexAxis.SetName("vtxAxis");
+  fVertexAxis.SetTitle("v_{z} [cm]");
+}
+//____________________________________________________________________
+AliFMDCorrMergingEfficiency::~AliFMDCorrMergingEfficiency()
+{
+  fRingArray.Clear();
+}
+//____________________________________________________________________
+AliFMDCorrMergingEfficiency&
+AliFMDCorrMergingEfficiency::operator=(const AliFMDCorrMergingEfficiency& o)
+{
+  fRingArray        = o.fRingArray;
+  SetVertexAxis(o.fVertexAxis);
+
+  return *this;
+}
+//____________________________________________________________________
+TH1D*
+AliFMDCorrMergingEfficiency::GetCorrection(UShort_t d, Char_t r, Double_t v) const
+{
+  Int_t b = FindVertexBin(v);
+  if (b <= 0) return 0;
+  return GetCorrection(d, r, UShort_t(b));
+}
+//____________________________________________________________________
+TH1D*
+AliFMDCorrMergingEfficiency::GetCorrection(UShort_t d, Char_t r, UShort_t b) const
+{
+  TObjArray* ringArray = GetRingArray(d, r);
+  if (!ringArray) return 0;
+
+  if (b <= 0 || b > ringArray->GetEntriesFast()) {
+    AliWarning(Form("vertex bin %d out of range [1,%d]", 
+                   b, ringArray->GetEntriesFast()));
+    return 0;
+  }
+
+  TObject* o = ringArray->At(b-1);
+  if (!o) { 
+    AliWarning(Form("No secondary map found for FMD%d%c in vertex bin %d",
+                   d,r,b));
+    return 0;
+  }
+  return static_cast<TH1D*>(o);
+}
+  
+//____________________________________________________________________
+Int_t
+AliFMDCorrMergingEfficiency::FindVertexBin(Double_t v) const
+{
+  if (fVertexAxis.GetNbins() <= 0) { 
+    AliWarning("No vertex array defined");
+    return 0;
+  }
+  Int_t bin = const_cast<TAxis&>(fVertexAxis).FindBin(v);
+  if (bin <= 0 || bin > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("vertex %+8.4f out of range [%+8.4f,%+8.4f]",
+                   v, fVertexAxis.GetXmin(), fVertexAxis.GetXmax()));
+    return 0;
+  }
+  return bin;
+}
+//____________________________________________________________________
+Int_t
+AliFMDCorrMergingEfficiency::GetRingIndex(UShort_t d, Char_t r) const
+{
+  switch (d) {
+  case 1:  return 0;
+  case 2:  return (r == 'I' || r == 'i' ? 1 : 2); break;  
+  case 3:  return (r == 'I' || r == 'i' ? 3 : 4); break;  
+  }
+  AliWarning(Form("Index for FMD%d%c not found", d, r));
+  return -1;
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrMergingEfficiency::GetRingArray(UShort_t d, Char_t r) const
+{
+  Int_t idx = GetRingIndex(d,r);
+  if (idx < 0) return 0;
+  
+  TObject* o = fRingArray.At(idx);
+  if (!o) { 
+    AliWarning(Form("No array found for FMD%d%c", d, r));
+    return 0;
+  }
+
+  return static_cast<TObjArray*>(o);
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrMergingEfficiency::GetOrMakeRingArray(UShort_t d, Char_t r)
+{
+  Int_t idx = GetRingIndex(d,r);
+  if (idx < 0) return 0;
+  
+  TObject* o = fRingArray.At(idx);
+  if (!o) { 
+    TObjArray* a = new TObjArray(fVertexAxis.GetNbins());
+    a->SetName(Form("FMD%d%c", d, r));
+    a->SetOwner(kTRUE);
+    fRingArray.AddAtAndExpand(a, idx);
+    return a;
+  }
+
+  return static_cast<TObjArray*>(fRingArray.At(idx));
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDCorrMergingEfficiency::SetCorrection(UShort_t d, Char_t r, 
+                                          UShort_t b, TH1D*  h) 
+{
+  TObjArray* ringArray = GetOrMakeRingArray(d, r);
+  if (!ringArray) return false;
+  
+  if (b <= 0 || b > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("Vertex bin %3d out of range [1,%3d]", 
+                   b, fVertexAxis.GetNbins()));
+    return false;
+  }
+  h->SetName(Form("FMD%d%c_vtxbin%03d", d, r, b));
+  h->SetTitle(Form("Secondary map correction for FMD%d%c "
+                  "in vertex bin %d [%+8.4f,%+8.4f]", 
+                  d, r, b, fVertexAxis.GetBinLowEdge(b), 
+                  fVertexAxis.GetBinUpEdge(b)));
+  h->SetXTitle("#eta");
+  h->SetYTitle("dN_{ch}/d#eta / sum_i N_{ch,i}");
+  h->SetFillStyle(3001);
+  h->SetDirectory(0);
+  h->SetStats(0);
+  ringArray->AddAtAndExpand(h, b-1);
+  return kTRUE;
+}
+//____________________________________________________________________
+Bool_t
+AliFMDCorrMergingEfficiency::SetCorrection(UShort_t d, Char_t r, 
+                                          Double_t v, TH1D*  h) 
+{
+  Int_t b = FindVertexBin(v);
+  if (b <= 0 || b > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("Vertex %+8.4f out of range [%+8.4f,%+8.4f]", 
+                   v, fVertexAxis.GetXmin(), fVertexAxis.GetXmax()));
+    return false;
+  }
+  return SetCorrection(d, r, UShort_t(b), h);
+}
+//____________________________________________________________________
+void
+AliFMDCorrMergingEfficiency::Browse(TBrowser* b)
+{
+  b->Add(&fRingArray);
+  b->Add(&fVertexAxis);
+}
+//____________________________________________________________________
+void
+AliFMDCorrMergingEfficiency::Print(Option_t* option) const
+{
+  std::cout << "Merging efficiency correction" << std::endl;
+  fRingArray.Print(option);
+  fVertexAxis.Print(option);
+}
+    
+//____________________________________________________________________
+//
+// EOF
+//
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrMergingEfficiency.h b/PWG2/FORWARD/analysis2/AliFMDCorrMergingEfficiency.h
new file mode 100644 (file)
index 0000000..470c574
--- /dev/null
@@ -0,0 +1,208 @@
+//
+// This class contains the secondary correction and the double hit
+// correction used in low-flux events.
+//
+#ifndef ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRMERGINGEFFICIENCY_H
+#define ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRMERGINGEFFICIENCY_H
+#include <TObject.h>
+#include <TObjArray.h>
+#include <TAxis.h>
+class TH1D;
+
+/**
+ * This class contains the merging efficiency correction.
+ *
+ * The secondary correction is given by 
+ * @f[
+ *   m_{r,v}(\eta) = 
+ * @f]
+ *
+ * These are generated from Monte-Carlo truth and ESD information. 
+ *
+ * @ingroup pwg2_forward_corr
+ */
+class AliFMDCorrMergingEfficiency : public TObject 
+{
+public:
+  /** 
+   * Default constructor 
+   */
+  AliFMDCorrMergingEfficiency();
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliFMDCorrMergingEfficiency(const AliFMDCorrMergingEfficiency& o);
+  /**
+   * Destructor 
+   * 
+   */
+  virtual ~AliFMDCorrMergingEfficiency();
+  /** 
+   * @{ 
+   * @name Get corrections and parameters 
+   */
+  /** 
+   * Assignment operator 
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object 
+   */
+  AliFMDCorrMergingEfficiency& operator=(const AliFMDCorrMergingEfficiency& o);
+  /** 
+   * Get the secondary correction @f$ c_{r,v}@f$ 
+   *
+   * @param d  Detector number (1-3)
+   * @param r  Ring identifier (I or O)
+   * @param v  Primary interaction point @f$z@f$ coordinate
+   * 
+   * @return The correction @f$ c_{r,v}@f$ 
+   */
+  TH1D* GetCorrection(UShort_t d, Char_t r, Double_t v) const;
+  /** 
+   * Get the secondary correction @f$ c_{r,v}@f$ 
+   *
+   * @param d  Detector number (1-3)
+   * @param r  Ring identifier (I or O)
+   * @param b  Bin corresponding to the primary interaction point 
+   *           @f$z@f$ coordinate (1 based)
+   * 
+   * @return The correction @f$ c_{r,v}@f$ 
+   */
+  TH1D* GetCorrection(UShort_t d, Char_t r, UShort_t b) const;
+  /** 
+   * Get the vertex axis used 
+   * 
+   * @return vertex axis 
+   */
+  const TAxis& GetVertexAxis() const { return fVertexAxis; }
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Set corrections and parameters 
+   */
+  /** 
+   * Set the secondary map correction @f$ m_{r,v}(\eta)@f$.
+   * Note, that the object takes ownership of the passed pointer.
+   * 
+   * @param d    Detector number (1-3)
+   * @param r    Ring identifier (I or O)
+   * @param v    Primary interaction point @f$z@f$ coordinate  
+   * @param h    @f$ m_{r,v}(\eta)@f$ 
+   * 
+   * @return true if operation succeeded 
+   */
+  Bool_t SetCorrection(UShort_t d, Char_t r, Double_t v, TH1D* h);
+  /** 
+   * Set the secondary map correction @f$ m_{r,v}(\eta)@f$ 
+   * Note, that the object takes ownership of the passed pointer.
+   * 
+   * @param d    Detector number (1-3)
+   * @param r    Ring identifier (I or O)
+   * @param b    Bin corresponding to the primary interaction point 
+   *             @f$z@f$ coordinate  (1 based)
+   * @param h    @f$ m_{r,v}(\eta)@f$ 
+   * 
+   * @return true if operation succeeded 
+   */
+  Bool_t SetCorrection(UShort_t d, Char_t r, UShort_t b, TH1D* h);
+  /** 
+   * Set the vertex axis to use 
+   * 
+   * @param axis Vertex axis 
+   */
+  void SetVertexAxis(const TAxis& axis);
+  /** 
+   * Set the vertex axis to use 
+   * 
+   * @param axis Vertex axis 
+   */
+  void SetVertexAxis(Int_t nBins, Double_t min, Double_t max);
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Auxiliary member functions 
+   */
+  /** 
+   * Declare this as a folder
+   * 
+   * @return Always true 
+   */
+  Bool_t IsFolder() const { return true; }
+  /** 
+   * Browse this object in the browser
+   * 
+   * @param b 
+   */
+  void Browse(TBrowser* b);
+  /** 
+   * Print this object 
+   * 
+   * @param option 
+   */  
+  void Print(Option_t* option="R") const; //*MENU*
+  /* @} */
+protected:
+  /** 
+   * Find the vertex bin that corresponds to the passed vertex 
+   * 
+   * @param vertex The interaction points @f$z@f$-coordinate 
+   * 
+   * @return Vertex bin in @f$[1,N_{\box{vertex}}]@f$ or negative if 
+   * out of range 
+   */
+  Int_t FindVertexBin(Double_t vertex) const;
+  /** 
+   * Get the index corresponding to the given ring 
+   * 
+   * @param d Detector
+   * @param r Ring 
+   * 
+   * @return Index (0 based) or negative in case of errors
+   */
+  Int_t GetRingIndex(UShort_t d, Char_t r) const;
+  /** 
+   * Get the ring array corresponding to the specified ring
+   * 
+   * @param d Detector 
+   * @param r Ring 
+   * 
+   * @return Pointer to ring array, or null in case of problems
+   */
+  TObjArray* GetRingArray(UShort_t d, Char_t r) const;
+  /** 
+   * Get the ring array corresponding to the specified ring
+   * 
+   * @param d Detector 
+   * @param r Ring 
+   * 
+   * @return Pointer to ring array, or newly created container 
+   */
+  TObjArray* GetOrMakeRingArray(UShort_t d, Char_t r);
+
+  TObjArray fRingArray;      // Array of per-ring, per-vertex 2nd map
+  TAxis     fVertexAxis;     // The vertex axis 
+  ClassDef(AliFMDCorrMergingEfficiency,1); // 
+};
+
+//____________________________________________________________________
+inline void 
+AliFMDCorrMergingEfficiency::SetVertexAxis(Int_t nBins, Double_t min, 
+                                          Double_t max)
+{
+  fVertexAxis.Set(nBins, min, max);
+}
+//____________________________________________________________________
+inline void 
+AliFMDCorrMergingEfficiency::SetVertexAxis(const TAxis& e)
+{
+  fVertexAxis.Set(e.GetNbins(), e.GetXmin(), e.GetXmax());
+}
+#endif
+// Local Variables:
+//  mode: C++
+// End:
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrSecondaryMap.cxx b/PWG2/FORWARD/analysis2/AliFMDCorrSecondaryMap.cxx
new file mode 100644 (file)
index 0000000..f92973a
--- /dev/null
@@ -0,0 +1,203 @@
+#include "AliFMDCorrSecondaryMap.h"
+#include <TBrowser.h>
+#include <TH2D.h>
+#include <AliLog.h>
+#include <iostream>
+
+//____________________________________________________________________
+AliFMDCorrSecondaryMap::AliFMDCorrSecondaryMap()
+  : fRingArray(), 
+    fVertexAxis(0,0,0),
+    fEtaAxis(0,0,0)
+{
+  fRingArray.SetOwner(kTRUE);
+  fRingArray.SetName("rings");
+  fVertexAxis.SetName("vertexAxis");
+  fVertexAxis.SetTitle("v_{z} [cm]");
+  fEtaAxis.SetName("etaAxis");
+  fEtaAxis.SetTitle("#eta");
+  
+}
+//____________________________________________________________________
+AliFMDCorrSecondaryMap::AliFMDCorrSecondaryMap(const 
+                                              AliFMDCorrSecondaryMap& o)
+  : TObject(o), 
+    fRingArray(o.fRingArray), 
+    fVertexAxis(o.fVertexAxis.GetNbins(), o.fVertexAxis.GetXmin(), 
+               o.fVertexAxis.GetXmax()),
+    fEtaAxis(o.fEtaAxis.GetNbins(), o.fEtaAxis.GetXmin(), 
+            o.fEtaAxis.GetXmax())
+{
+  fVertexAxis.SetName("vertexAxis");
+  fVertexAxis.SetTitle("v_{z} [cm]");
+  fEtaAxis.SetName("etaAxis");
+  fEtaAxis.SetTitle("v_{z} [cm]");
+}
+//____________________________________________________________________
+AliFMDCorrSecondaryMap::~AliFMDCorrSecondaryMap()
+{
+  fRingArray.Clear();
+}
+//____________________________________________________________________
+AliFMDCorrSecondaryMap&
+AliFMDCorrSecondaryMap::operator=(const AliFMDCorrSecondaryMap& o)
+{
+  fRingArray        = o.fRingArray;
+  SetVertexAxis(o.fVertexAxis);
+  SetEtaAxis(o.fEtaAxis);
+
+  return *this;
+}
+//____________________________________________________________________
+TH2D*
+AliFMDCorrSecondaryMap::GetCorrection(UShort_t d, Char_t r, Double_t v) const
+{
+  Int_t b = FindVertexBin(v);
+  if (b <= 0) return 0;
+  return GetCorrection(d, r, UShort_t(b));
+}
+//____________________________________________________________________
+TH2D*
+AliFMDCorrSecondaryMap::GetCorrection(UShort_t d, Char_t r, UShort_t b) const
+{
+  TObjArray* ringArray = GetRingArray(d, r);
+  if (!ringArray) return 0;
+
+  if (b <= 0 || b > ringArray->GetEntriesFast()) {
+    AliWarning(Form("vertex bin %d out of range [1,%d]", 
+                   b, ringArray->GetEntriesFast()));
+    return 0;
+  }
+
+  TObject* o = ringArray->At(b-1);
+  if (!o) { 
+    AliWarning(Form("No secondary map found for FMD%d%c in vertex bin %d",
+                   d,r,b));
+    return 0;
+  }
+  return static_cast<TH2D*>(o);
+}
+  
+//____________________________________________________________________
+Int_t
+AliFMDCorrSecondaryMap::FindVertexBin(Double_t v) const
+{
+  if (fVertexAxis.GetNbins() <= 0) { 
+    AliWarning("No vertex array defined");
+    return 0;
+  }
+  Int_t bin = const_cast<TAxis&>(fVertexAxis).FindBin(v);
+  if (bin <= 0 || bin > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("vertex %+8.4f out of range [%+8.4f,%+8.4f]",
+                   v, fVertexAxis.GetXmin(), fVertexAxis.GetXmax()));
+    return 0;
+  }
+  return bin;
+}
+//____________________________________________________________________
+Int_t
+AliFMDCorrSecondaryMap::GetRingIndex(UShort_t d, Char_t r) const
+{
+  switch (d) {
+  case 1:  return 0;
+  case 2:  return (r == 'I' || r == 'i' ? 1 : 2); break;  
+  case 3:  return (r == 'I' || r == 'i' ? 3 : 4); break;  
+  }
+  AliWarning(Form("Index for FMD%d%c not found", d, r));
+  return -1;
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrSecondaryMap::GetRingArray(UShort_t d, Char_t r) const
+{
+  Int_t idx = GetRingIndex(d,r);
+  if (idx < 0) return 0;
+  
+  TObject* o = fRingArray.At(idx);
+  if (!o) { 
+    AliWarning(Form("No array found for FMD%d%c", d, r));
+    return 0;
+  }
+
+  return static_cast<TObjArray*>(o);
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrSecondaryMap::GetOrMakeRingArray(UShort_t d, Char_t r)
+{
+  Int_t idx = GetRingIndex(d,r);
+  if (idx < 0) return 0;
+  
+  TObject* o = fRingArray.At(idx);
+  if (!o) { 
+    TObjArray* a = new TObjArray(fVertexAxis.GetNbins());
+    a->SetName(Form("FMD%d%c", d, r));
+    a->SetOwner(kTRUE);
+    fRingArray.AddAtAndExpand(a, idx);
+    return a;
+  }
+
+  return static_cast<TObjArray*>(fRingArray.At(idx));
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDCorrSecondaryMap::SetCorrection(UShort_t d, Char_t r, 
+                                     UShort_t b, TH2D*  h) 
+{
+  TObjArray* ringArray = GetOrMakeRingArray(d, r);
+  if (!ringArray) return false;
+  
+  if (b <= 0 || b > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("Vertex bin %3d out of range [1,%3d]", 
+                   b, fVertexAxis.GetNbins()));
+    return false;
+  }
+  h->SetName(Form("FMD%d%c_vtxbin%03d", d, r, b));
+  h->SetTitle(Form("Secondary map correction for FMD%d%c "
+                  "in vertex bin %d [%+8.4f,%+8.4f]", 
+                  d, r, b, fVertexAxis.GetBinLowEdge(b), 
+                  fVertexAxis.GetBinUpEdge(b)));
+  h->SetXTitle("#eta");
+  h->SetYTitle("#phi [radians]");
+  h->SetZTitle("#sum_{i} N_{ch,i,primary} / #sum_{i} N_{ch,i,FMD}");
+  h->SetDirectory(0);
+  h->SetStats(0);
+  ringArray->AddAtAndExpand(h, b-1);
+  return kTRUE;
+}
+//____________________________________________________________________
+Bool_t
+AliFMDCorrSecondaryMap::SetCorrection(UShort_t d, Char_t r, 
+                                     Double_t v, TH2D*  h) 
+{
+  Int_t b = FindVertexBin(v);
+  if (b <= 0 || b > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("Vertex %+8.4f out of range [%+8.4f,%+8.4f]", 
+                   v, fVertexAxis.GetXmin(), fVertexAxis.GetXmax()));
+    return false;
+  }
+  return SetCorrection(d, r, UShort_t(b), h);
+}
+//____________________________________________________________________
+void
+AliFMDCorrSecondaryMap::Browse(TBrowser* b)
+{
+  b->Add(&fRingArray);
+  b->Add(&fVertexAxis);
+  b->Add(&fEtaAxis);
+}
+//____________________________________________________________________
+void
+AliFMDCorrSecondaryMap::Print(Option_t* option) const
+{
+  std::cout << "Secondary correction map" << std::endl;
+  fRingArray.Print(option);
+  fVertexAxis.Print(option);
+  fEtaAxis.Print(option);
+}
+    
+//____________________________________________________________________
+//
+// EOF
+//
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrSecondaryMap.h b/PWG2/FORWARD/analysis2/AliFMDCorrSecondaryMap.h
new file mode 100644 (file)
index 0000000..1c7a430
--- /dev/null
@@ -0,0 +1,246 @@
+//
+// This class contains the secondary correction and the double hit
+// correction used in low-flux events.
+//
+#ifndef ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRSECONDARYMAP_H
+#define ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRSECONDARYMAP_H
+#include <TObject.h>
+#include <TObjArray.h>
+#include <TAxis.h>
+class TH2D;
+
+/**
+ * This class contains the secondary correction.
+ *
+ * The secondary correction is given by 
+ * @f[
+ *   c_{r,v}(\eta,\varphi) = 
+ *      \frac{\sum_i N_{ch,i,v,\mbox{primary}}(\eta,\varphi)}{
+ *            \sum_i N_{ch,i,r,v,\mbox{FMD}}(\eta,\varphi)}
+ * @f]
+ * where @f$N_{ch,i,v,\mbox{primary}}(\eta,\varphi)@f$ is the 
+ * is the number of primary charged particles that fall within
+ * the @f$(\eta,\varphi)@f$ bin in event @f$i@f$ with vertex @f$v@f$, 
+ * and is the total (primary <i>and</i> secondary) charged particles 
+ * that hit ring @f$r@f$ within @f$(\eta,\varphi)@f$ bin in event 
+ * @f$i@f$ with vertex @f$v@f$. 
+ *
+ * These are generated from Monte-Carlo truth information. 
+ *
+ * @ingroup pwg2_forward_corr
+ */
+class AliFMDCorrSecondaryMap : public TObject 
+{
+public:
+  /** 
+   * Default constructor 
+   */
+  AliFMDCorrSecondaryMap();
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliFMDCorrSecondaryMap(const AliFMDCorrSecondaryMap& o);
+  /**
+   * Destructor 
+   * 
+   */
+  virtual ~AliFMDCorrSecondaryMap();
+  /** 
+   * @{ 
+   * @name Get corrections and parameters 
+   */
+  /** 
+   * Assignment operator 
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object 
+   */
+  AliFMDCorrSecondaryMap& operator=(const AliFMDCorrSecondaryMap& o);
+  /** 
+   * Get the secondary correction @f$ c_{r,v}@f$ 
+   *
+   * @param d  Detector number (1-3)
+   * @param r  Ring identifier (I or O)
+   * @param v  Primary interaction point @f$z@f$ coordinate
+   * 
+   * @return The correction @f$ c_{r,v}@f$ 
+   */
+  TH2D* GetCorrection(UShort_t d, Char_t r, Double_t v) const;
+  /** 
+   * Get the secondary correction @f$ c_{r,v}@f$ 
+   *
+   * @param d  Detector number (1-3)
+   * @param r  Ring identifier (I or O)
+   * @param b  Bin corresponding to the primary interaction point 
+   *           @f$z@f$ coordinate (1 based)
+   * 
+   * @return The correction @f$ c_{r,v}@f$ 
+   */
+  TH2D* GetCorrection(UShort_t d, Char_t r, UShort_t b) const;
+  /** 
+   * Get the vertex axis used 
+   * 
+   * @return vertex axis 
+   */
+  const TAxis& GetVertexAxis() const { return fVertexAxis; }
+  /** 
+   * Get the eta axis used 
+   * 
+   * @return eta axis 
+   */
+  const TAxis& GetEtaAxis() const { return fEtaAxis; }
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Set corrections and parameters 
+   */
+  /** 
+   * Set the secondary map correction @f$ c_{r,v}(\eta,\varphi)@f$.
+   * Note, that the object takes ownership of the passed pointer.
+   * 
+   * @param d    Detector number (1-3)
+   * @param r    Ring identifier (I or O)
+   * @param v    Primary interaction point @f$z@f$ coordinate  
+   * @param h    @f$ c_{r,v}(\eta,\varphi)@f$ 
+   * 
+   * @return true if operation succeeded 
+   */
+  Bool_t SetCorrection(UShort_t d, Char_t r, Double_t v, TH2D* h);
+  /** 
+   * Set the secondary map correction @f$ c_{r,v}(\eta,\varphi)@f$ 
+   * Note, that the object takes ownership of the passed pointer.
+   * 
+   * @param d    Detector number (1-3)
+   * @param r    Ring identifier (I or O)
+   * @param b    Bin corresponding to the primary interaction point 
+   *             @f$z@f$ coordinate  (1 based)
+   * @param h    @f$ c_{r,v}(\eta,\varphi)@f$ 
+   * 
+   * @return true if operation succeeded 
+   */
+  Bool_t SetCorrection(UShort_t d, Char_t r, UShort_t b, TH2D* h);
+  /** 
+   * Set the vertex axis to use 
+   * 
+   * @param axis Vertex axis 
+   */
+  void SetVertexAxis(const TAxis& axis);
+  /** 
+   * Set the vertex axis to use 
+   * 
+   * @param axis Vertex axis 
+   */
+  void SetVertexAxis(Int_t nBins, Double_t min, Double_t max);
+  /** 
+   * Set the eta axis to use 
+   * 
+   * @param axis Eta axis 
+   */
+  void SetEtaAxis(const TAxis& axis);
+  /** 
+   * Set the eta axis to use 
+   * 
+   * @param axis Eta axis 
+   */
+  void SetEtaAxis(Int_t nBins, Double_t min, Double_t max);
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Auxiliary member functions 
+   */
+  /** 
+   * Declare this as a folder
+   * 
+   * @return Always true 
+   */
+  Bool_t IsFolder() const { return true; }
+  /** 
+   * Browse this object in the browser
+   * 
+   * @param b 
+   */
+  void Browse(TBrowser* b);
+  /** 
+   * Print this object 
+   * 
+   * @param option 
+   */  
+  void Print(Option_t* option="R") const; //*MENU*
+  /* @} */
+protected:
+  /** 
+   * Find the vertex bin that corresponds to the passed vertex 
+   * 
+   * @param vertex The interaction points @f$z@f$-coordinate 
+   * 
+   * @return Vertex bin in @f$[1,N_{\box{vertex}}]@f$ or negative if 
+   * out of range 
+   */
+  Int_t FindVertexBin(Double_t vertex) const;
+  /** 
+   * Get the index corresponding to the given ring 
+   * 
+   * @param d Detector
+   * @param r Ring 
+   * 
+   * @return Index (0 based) or negative in case of errors
+   */
+  Int_t GetRingIndex(UShort_t d, Char_t r) const;
+  /** 
+   * Get the ring array corresponding to the specified ring
+   * 
+   * @param d Detector 
+   * @param r Ring 
+   * 
+   * @return Pointer to ring array, or null in case of problems
+   */
+  TObjArray* GetRingArray(UShort_t d, Char_t r) const;
+  /** 
+   * Get the ring array corresponding to the specified ring
+   * 
+   * @param d Detector 
+   * @param r Ring 
+   * 
+   * @return Pointer to ring array, or newly created container 
+   */
+  TObjArray* GetOrMakeRingArray(UShort_t d, Char_t r);
+
+  TObjArray fRingArray;      // Array of per-ring, per-vertex 2nd map
+  TAxis     fVertexAxis;     // The vertex axis 
+  TAxis     fEtaAxis;        // The eta axis
+  ClassDef(AliFMDCorrSecondaryMap,1); // 
+};
+
+//____________________________________________________________________
+inline void 
+AliFMDCorrSecondaryMap::SetVertexAxis(Int_t nBins, Double_t min, Double_t max)
+{
+  fVertexAxis.Set(nBins, min, max);
+}
+//____________________________________________________________________
+inline void 
+AliFMDCorrSecondaryMap::SetVertexAxis(const TAxis& e)
+{
+  fVertexAxis.Set(e.GetNbins(), e.GetXmin(), e.GetXmax());
+}
+//____________________________________________________________________
+inline void 
+AliFMDCorrSecondaryMap::SetEtaAxis(Int_t nBins, Double_t min, Double_t max)
+{
+  fEtaAxis.Set(nBins, min, max);
+}
+//____________________________________________________________________
+inline void 
+AliFMDCorrSecondaryMap::SetEtaAxis(const TAxis& e)
+{
+  fEtaAxis.Set(e.GetNbins(), e.GetXmin(), e.GetXmax());
+}
+#endif
+// Local Variables:
+//  mode: C++
+// End:
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrVertexBias.cxx b/PWG2/FORWARD/analysis2/AliFMDCorrVertexBias.cxx
new file mode 100644 (file)
index 0000000..b1ed45f
--- /dev/null
@@ -0,0 +1,195 @@
+#include "AliFMDCorrVertexBias.h"
+#include <TBrowser.h>
+#include <TH2D.h>
+#include <AliLog.h>
+#include <iostream>
+
+//____________________________________________________________________
+AliFMDCorrVertexBias::AliFMDCorrVertexBias()
+  : fVertexArray(), 
+    fVertexAxis(0,0,0)
+{
+  fVertexArray.SetOwner(kTRUE);
+  fVertexArray.SetName("rings");
+  fVertexAxis.SetName("vtxAxis");
+  fVertexAxis.SetTitle("v_{z} [cm]");
+  
+}
+//____________________________________________________________________
+AliFMDCorrVertexBias::AliFMDCorrVertexBias(const AliFMDCorrVertexBias& o)
+  : TObject(o), 
+    fVertexArray(o.fVertexArray), 
+    fVertexAxis(o.fVertexAxis.GetNbins(), o.fVertexAxis.GetXmin(), 
+               o.fVertexAxis.GetXmax())
+{
+  fVertexAxis.SetName("vtxAxis");
+  fVertexAxis.SetTitle("v_{z} [cm]");
+}
+//____________________________________________________________________
+AliFMDCorrVertexBias::~AliFMDCorrVertexBias()
+{
+  fVertexArray.Clear();
+}
+//____________________________________________________________________
+AliFMDCorrVertexBias&
+AliFMDCorrVertexBias::operator=(const AliFMDCorrVertexBias& o)
+{
+  fVertexArray        = o.fVertexArray;
+  SetVertexAxis(o.fVertexAxis);
+
+  return *this;
+}
+//____________________________________________________________________
+TH2D*
+AliFMDCorrVertexBias::GetCorrection(Char_t r, Double_t v) const
+{
+  Int_t b = FindVertexBin(v);
+  if (b <= 0) return 0;
+  return GetCorrection(r, UShort_t(b));
+}
+//____________________________________________________________________
+TH2D*
+AliFMDCorrVertexBias::GetCorrection(Char_t r, UShort_t b) const
+{
+  TObjArray* vertexarray = GetVertexArray(b);
+  if (!vertexarray) return 0;
+
+  Int_t idx = -1;
+  switch (r) { 
+  case 'i': case 'I': idx = 0; break;
+  case 'o': case 'O': idx = 1; break;
+  }
+  if (idx < 0) {
+    AliWarning(Form("Unknown ting type %c, not one of [iIoO]", r));
+    return 0;
+  }
+
+  TObject* o = vertexarray->At(idx);
+  if (!o) { 
+    AliWarning(Form("No vertex bias found for ring type %c in vertex bin %d",
+                   r,b));
+    return 0;
+  }
+  return static_cast<TH2D*>(o);
+}
+  
+//____________________________________________________________________
+Int_t
+AliFMDCorrVertexBias::FindVertexBin(Double_t v) const
+{
+  if (fVertexAxis.GetNbins() <= 0) { 
+    AliWarning("No vertex array defined");
+    return 0;
+  }
+  Int_t bin = const_cast<TAxis&>(fVertexAxis).FindBin(v);
+  if (bin <= 0 || bin > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("vertex %+8.4f out of range [%+8.4f,%+8.4f]",
+                   v, fVertexAxis.GetXmin(), fVertexAxis.GetXmax()));
+    return 0;
+  }
+  return bin;
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrVertexBias::GetVertexArray(UShort_t v) const
+{
+  if (v <= 0 || v > fVertexAxis.GetNbins()) {
+    AliWarning(Form("vertex bin %d out of range [1,%d]",
+                   v, fVertexAxis.GetNbins()));
+    return 0;
+  }
+  
+  TObject* o = fVertexArray.At(v-1);
+  if (!o) { 
+    AliWarning(Form("No array found for vertex bin %d", v));
+    return 0;
+  }
+
+  return static_cast<TObjArray*>(o);
+}
+//____________________________________________________________________
+TObjArray*
+AliFMDCorrVertexBias::GetOrMakeVertexArray(UShort_t v)
+{
+  if (v <= 0 || v > fVertexAxis.GetNbins()) {
+    AliWarning(Form("vertex bin %d out of range [1,%d]",
+                   v, fVertexAxis.GetNbins()));
+    return 0;
+  }
+    
+  TObject* o = fVertexArray.At(v-1);
+  if (!o) { 
+    TObjArray* a = new TObjArray(fVertexAxis.GetNbins());
+    a->SetName(Form("vertexbin%02d", v));
+    a->SetOwner(kTRUE);
+    fVertexArray.AddAtAndExpand(a, v-1);
+    return a;
+  }
+
+  return static_cast<TObjArray*>(fVertexArray.At(v-1));
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDCorrVertexBias::SetCorrection(Char_t r, UShort_t b, TH2D*  h) 
+{
+  TObjArray* vertexarray = GetOrMakeVertexArray(b);
+  if (!vertexarray) return false;
+  
+
+  Int_t idx = -1;
+  switch (r) { 
+  case 'i': case 'I': idx = 0; break;
+  case 'o': case 'O': idx = 1; break;
+  }
+  if (idx < 0) {
+    AliWarning(Form("Unknown ting type %c, not one of [iIoO]", r));
+    return false;
+  }
+  h->SetName(Form("FMDX%c", r));
+  h->SetTitle(Form("Vertex bias correction for %c rings "
+                  "in vertex bin %d [%+8.4f,%+8.4f]", 
+                  r, b, fVertexAxis.GetBinLowEdge(b), 
+                  fVertexAxis.GetBinUpEdge(b)));
+  h->SetXTitle("#eta");
+  h->SetYTitle("#phi [radians]");
+  h->SetZTitle("1/N_{t}#sum_{i}^{N_{tv}} N_{ch,i,primary} / "
+              "1/N_{v}#sum_{i}^{N_{v}} N_{ch,i,primary}");
+  h->SetDirectory(0);
+  h->SetStats(0);
+
+  vertexarray->AddAtAndExpand(h, idx);
+  return kTRUE;
+}
+//____________________________________________________________________
+Bool_t
+AliFMDCorrVertexBias::SetCorrection(Char_t r, Double_t v, TH2D*  h) 
+{
+  Int_t b = FindVertexBin(v);
+  if (b <= 0 || b > fVertexAxis.GetNbins()) { 
+    AliWarning(Form("Vertex %+8.4f out of range [%+8.4f,%+8.4f]", 
+                   v, fVertexAxis.GetXmin(), fVertexAxis.GetXmax()));
+    return false;
+  }
+  return SetCorrection(r, UShort_t(b), h);
+}
+//____________________________________________________________________
+void
+AliFMDCorrVertexBias::Browse(TBrowser* b)
+{
+  b->Add(&fVertexArray);
+  b->Add(&fVertexAxis);
+}
+//____________________________________________________________________
+void
+AliFMDCorrVertexBias::Print(Option_t* option) const
+{
+  std::cout << "Vertex bias correction" << std::endl;
+  fVertexArray.Print(option);
+  fVertexAxis.Print(option);
+}
+    
+//____________________________________________________________________
+//
+// EOF
+//
diff --git a/PWG2/FORWARD/analysis2/AliFMDCorrVertexBias.h b/PWG2/FORWARD/analysis2/AliFMDCorrVertexBias.h
new file mode 100644 (file)
index 0000000..570dad4
--- /dev/null
@@ -0,0 +1,203 @@
+//
+// This class contains the secondary correction and the double hit
+// correction used in low-flux events.
+//
+#ifndef ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRVERTEXBIAS_H
+#define ALIROOT_PWG2_FORWARD_ANALYSIS_ALIFMDCORRVERTEXBIAS_H
+#include <TObject.h>
+#include <TObjArray.h>
+#include <TAxis.h>
+class TH2D;
+
+/**
+ * This class contains the correction for the bias introduced by
+ * different vertex bins
+ *
+ * The correction is given by 
+ * @f[
+ *   b_{v}(\eta,\varphi) = \frac{1/N_{t}\sum_i^{N_{tv}} N_{ch,i,primary}}{
+ *                               1/N_{v}\sum_i^{N_{v}} N_{ch,i,primary}}
+ * @f]
+ *
+ * where @f$N_{ch,i,primary}@f$ is the number of primary particles in
+ * the given @f$(\eta,\varphi)@f$, and where the denominator sum runs
+ * over all events with a vertex within the given vertex bin, and the
+ * sum in the numerator runs over only events that have a valid
+ * trigger and reconstructed vertex.  @f$ N_{t}@f$ is the number of
+ * events with a valid trigger (but not necessarily a valid vertex).
+ * The vertex information used @f$v@f$ is in all cases the MC truth
+ * vertex
+ *
+ * These are generated from Monte-Carlo truth and ESD information. 
+ *
+ * @ingroup pwg2_forward_corr
+ */
+class AliFMDCorrVertexBias : public TObject 
+{
+public:
+  /** 
+   * Default constructor 
+   */
+  AliFMDCorrVertexBias();
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliFMDCorrVertexBias(const AliFMDCorrVertexBias& o);
+  /**
+   * Destructor 
+   * 
+   */
+  virtual ~AliFMDCorrVertexBias();
+  /** 
+   * @{ 
+   * @name Get corrections and parameters 
+   */
+  /** 
+   * Assignment operator 
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object 
+   */
+  AliFMDCorrVertexBias& operator=(const AliFMDCorrVertexBias& o);
+  /** 
+   * Get the vertex bias correction @f$ b_{v}@f$ 
+   *
+   * @param r  Ring type (I or O)
+   * @param v  Primary interaction point @f$z@f$ coordinate
+   * 
+   * @return The correction @f$ b_{v}@f$ 
+   */
+  TH2D* GetCorrection(Char_t r, Double_t v) const;
+  /** 
+   * Get the vertex bias correction @f$ b_{v}@f$ 
+   *
+   * @param r  Ring type (I or O)
+   * @param b  Bin corresponding to the primary interaction point 
+   *           @f$z@f$ coordinate (1 based)
+   * 
+   * @return The correction @f$ b_{v}@f$ 
+   */
+  TH2D* GetCorrection(Char_t r, UShort_t b) const;
+  /** 
+   * Get the vertex axis used 
+   * 
+   * @return vertex axis 
+   */
+  const TAxis& GetVertexAxis() const { return fVertexAxis; }
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Set corrections and parameters 
+   */
+  /** 
+   * Set the vertex bias correction @f$ b_{v}(\eta,\varphi)@f$.
+   * Note, that the object takes ownership of the passed pointer.
+   * 
+   * @param r    Ring type (I or O)
+   * @param v    Primary interaction point @f$z@f$ coordinate  
+   * @param h    @f$ b_{v}(\eta,\varphi)@f$ 
+   * 
+   * @return true if operation succeeded 
+   */
+  Bool_t SetCorrection(Char_t r, Double_t v, TH2D* h);
+  /** 
+   * Set the vertex bias correction @f$ b_{v}(\eta,\varphi)@f$ 
+   * Note, that the object takes ownership of the passed pointer.
+   * 
+   * @param r    Ring type (I or O)
+   * @param b    Bin corresponding to the primary interaction point 
+   *             @f$z@f$ coordinate  (1 based)
+   * @param h    @f$ b_{v}(\eta,\varphi)@f$ 
+   * 
+   * @return true if operation succeeded 
+   */
+  Bool_t SetCorrection(Char_t r, UShort_t b, TH2D* h);
+  /** 
+   * Set the vertex axis to use 
+   * 
+   * @param axis Vertex axis 
+   */
+  void SetVertexAxis(const TAxis& axis);
+  /** 
+   * Set the vertex axis to use 
+   * 
+   * @param axis Vertex axis 
+   */
+  void SetVertexAxis(Int_t nBins, Double_t min, Double_t max);
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Auxiliary member functions 
+   */
+  /** 
+   * Declare this as a folder
+   * 
+   * @return Always true 
+   */
+  Bool_t IsFolder() const { return true; }
+  /** 
+   * Browse this object in the browser
+   * 
+   * @param b 
+   */
+  void Browse(TBrowser* b);
+  /** 
+   * Print this object 
+   * 
+   * @param option 
+   */  
+  void Print(Option_t* option="R") const; //*MENU*
+  /* @} */
+protected:
+  /** 
+   * Find the vertex bin that corresponds to the passed vertex 
+   * 
+   * @param vertex The interaction points @f$z@f$-coordinate 
+   * 
+   * @return Vertex bin in @f$[1,N_{\box{vertex}}]@f$ or negative if 
+   * out of range 
+   */
+  Int_t FindVertexBin(Double_t vertex) const;
+  /** 
+   * Get the vertex array corresponding to the specified ring
+   * 
+   * @param v vertex bin (1 based)
+   * 
+   * @return Pointer to vertex array, or null in case of problems
+   */
+  TObjArray* GetVertexArray(UShort_t v) const;
+  /** 
+   * Get the vertex array corresponding to the specified ring
+   * 
+   * @param v vertex bin (1 based)
+   * 
+   * @return Pointer to vertex array, or newly created container 
+   */
+  TObjArray* GetOrMakeVertexArray(UShort_t v);
+
+  TObjArray fVertexArray;    // Array of per-ring, per-vertex 2nd map
+  TAxis     fVertexAxis;     // The vertex axis 
+  ClassDef(AliFMDCorrVertexBias,1); // 
+};
+
+//____________________________________________________________________
+inline void 
+AliFMDCorrVertexBias::SetVertexAxis(Int_t nBins, Double_t min, Double_t max)
+{
+  fVertexAxis.Set(nBins, min, max);
+}
+//____________________________________________________________________
+inline void 
+AliFMDCorrVertexBias::SetVertexAxis(const TAxis& e)
+{
+  fVertexAxis.Set(e.GetNbins(), e.GetXmin(), e.GetXmax());
+}
+#endif
+// Local Variables:
+//  mode: C++
+// End:
index 06dc4d1..4db648a 100644 (file)
@@ -3,9 +3,13 @@
 #include <TAxis.h>
 #include <TList.h>
 #include <TMath.h>
-#include "AliFMDAnaParameters.h"
+#include "AliForwardCorrectionManager.h"
+// #include "AliFMDAnaParameters.h"
 #include "AliLog.h"
 #include <TH2D.h>
+#include <TROOT.h>
+#include <iostream>
+#include <iomanip>
 
 ClassImp(AliFMDCorrections)
 #if 0
@@ -16,7 +20,6 @@ ClassImp(AliFMDCorrections)
 AliFMDCorrections::AliFMDCorrections()
   : TNamed(), 
     fRingHistos(),
-    fMultCut(0.3),
     fDebug(0)
 {}
 
@@ -24,7 +27,6 @@ AliFMDCorrections::AliFMDCorrections()
 AliFMDCorrections::AliFMDCorrections(const char* title)
   : TNamed("fmdCorrections", title), 
     fRingHistos(), 
-    fMultCut(0.3),
     fDebug(0)
 {
   fRingHistos.SetName(GetName());
@@ -39,7 +41,6 @@ AliFMDCorrections::AliFMDCorrections(const char* title)
 AliFMDCorrections::AliFMDCorrections(const AliFMDCorrections& o)
   : TNamed(o), 
     fRingHistos(), 
-    fMultCut(o.fMultCut),
     fDebug(o.fDebug)
 {
   TIter    next(&o.fRingHistos);
@@ -59,7 +60,6 @@ AliFMDCorrections::operator=(const AliFMDCorrections& o)
 {
   TNamed::operator=(o);
 
-  fMultCut = o.fMultCut;
   fDebug   = o.fDebug;
   fRingHistos.Delete();
   TIter    next(&o.fRingHistos);
@@ -87,26 +87,30 @@ AliFMDCorrections::GetRingHistos(UShort_t d, Char_t r) const
 //____________________________________________________________________
 Bool_t
 AliFMDCorrections::Correct(AliForwardUtil::Histos& hists,
-                          Int_t                   vtxbin)
+                          UShort_t                vtxbin)
 {
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
 
+  UShort_t uvb = vtxbin;
   for (UShort_t d=1; d<=3; d++) { 
     UShort_t nr = (d == 1 ? 1 : 2);
     for (UShort_t q=0; q<nr; q++) { 
       Char_t      r = (q == 0 ? 'I' : 'O');
       TH2D*       h = hists.Get(d,r);
       RingHistos* rh= GetRingHistos(d,r);
-      TH2F*       bg= pars->GetBackgroundCorrection(d, r, vtxbin);
-      TH2F*       ef= pars->GetEventSelectionEfficiency("INEL",vtxbin,r);
+      //TH2F*       bg= pars->GetBackgroundCorrection(d, r, vtxbin);
+      //TH2F*       ef= pars->GetEventSelectionEfficiency("INEL",vtxbin,r);
+      TH2D* bg = fcm.GetSecondaryMap()->GetCorrection(d,r,uvb);
+      TH2D* ef = fcm.GetVertexBias()->GetCorrection(r, uvb);
       if (!bg) { 
        AliWarning(Form("No secondary correction for FMDM%d%c in vertex bin %d",
-                       d, r, vtxbin));
+                       d, r, uvb));
        continue;
       }
       if (!ef) { 
-       AliWarning(Form("No event %s selection efficiency in vertex bin %d",
-                       "INEL", vtxbin));
+       AliWarning(Form("No event vertex bias correction in vertex bin %d",
+                       uvb));
        continue;
       }
 
@@ -116,12 +120,23 @@ AliFMDCorrections::Correct(AliForwardUtil::Histos& hists,
       // Divide by the event selection efficiency 
       h->Divide(ef);
 
-      if(!pars->SharingEffPresent()) { 
-       AliWarning("No sharing efficiencies");
+      
+      // if(!pars->SharingEffPresent()) { 
+      //   AliWarning("No sharing efficiencies");
+      //   continue;
+      // }
+      // TH1F* sf = pars->GetSharingEfficiencyTrVtx(d,r,vtxbin); 
+      if (!fcm.GetMergingEfficiency()) { 
+       AliWarning("No merging efficiencies");
+       continue;
+      }
+      TH1D* sf = fcm.GetMergingEfficiency()->GetCorrection(d,r,uvb);
+      if (!fcm.GetMergingEfficiency()->GetCorrection(d,r,uvb)) { 
+       AliWarning(Form("No merging efficiency for FMD%d%c at vertex bin %d",
+                       d, r, uvb));
        continue;
       }
 
-      TH1F* sf = pars->GetSharingEfficiencyTrVtx(d,r,vtxbin); 
       
       for (Int_t ieta = 1; ieta <= h->GetNbinsX(); ieta++) {
        Float_t c  = sf->GetBinContent(ieta);
@@ -174,6 +189,16 @@ AliFMDCorrections::DefineOutput(TList* dir)
   }
 }
 
+//____________________________________________________________________
+void
+AliFMDCorrections::Print(Option_t* /* option */) const
+{
+  char ind[gROOT->GetDirLevel()+1];
+  for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
+  ind[gROOT->GetDirLevel()] = '\0';
+  std::cout << ind << "AliFMDCorrections: " << GetName() <<  std::endl;
+}
+
 //====================================================================
 AliFMDCorrections::RingHistos::RingHistos()
   : AliForwardUtil::RingHistos(), 
index b0e54d5..26b8de9 100644 (file)
@@ -63,7 +63,7 @@ public:
    * 
    * @return true on successs 
    */
-  virtual Bool_t Correct(AliForwardUtil::Histos& hists, Int_t vtxBin);
+  virtual Bool_t Correct(AliForwardUtil::Histos& hists, UShort_t vtxBin);
   /** 
    * Scale the histograms to the total number of events 
    * 
@@ -83,6 +83,12 @@ public:
    * @param dbg Debug level 
    */
   void SetDebug(Int_t dbg=1) { fDebug = dbg; }
+  /** 
+   * Print information
+   * 
+   * @param option Not used 
+   */
+  void Print(Option_t* option="") const;
 protected:
   /** 
    * Internal data structure to keep track of the histograms
@@ -145,7 +151,6 @@ protected:
   RingHistos* GetRingHistos(UShort_t d, Char_t r) const;
 
   TList    fRingHistos;    // List of histogram containers
-  Double_t fMultCut;       // Low cut on scaled energy loss
   Int_t    fDebug;         //  Debug level 
 
   ClassDef(AliFMDCorrections,1); // Calculate Nch density 
index a40651d..6f056c7 100644 (file)
@@ -3,9 +3,14 @@
 #include <TAxis.h>
 #include <TList.h>
 #include <TMath.h>
-#include "AliFMDAnaParameters.h"
+#include "AliForwardCorrectionManager.h"
+// #include "AliFMDAnaParameters.h"
 #include "AliLog.h"
 #include <TH2D.h>
+#include <TProfile.h>
+#include <TROOT.h>
+#include <iostream>
+#include <iomanip>
 
 ClassImp(AliFMDDensityCalculator)
 #if 0
@@ -16,10 +21,13 @@ ClassImp(AliFMDDensityCalculator)
 AliFMDDensityCalculator::AliFMDDensityCalculator()
   : TNamed(), 
     fRingHistos(),
-    fMultCut(0.3),
+    fMultCut(0),
     fSumOfWeights(0),
     fWeightedSum(0),
     fCorrections(0),
+    fMaxParticles(5),
+    fAccI(0),
+    fAccO(0),
     fDebug(0)
 {}
 
@@ -27,10 +35,13 @@ AliFMDDensityCalculator::AliFMDDensityCalculator()
 AliFMDDensityCalculator::AliFMDDensityCalculator(const char* title)
   : TNamed("fmdDensityCalculator", title), 
     fRingHistos(), 
-    fMultCut(0.3),
+    fMultCut(0),
     fSumOfWeights(0),
     fWeightedSum(0),
     fCorrections(0),
+    fMaxParticles(5),
+    fAccI(0),
+    fAccO(0),
     fDebug(0)
 {
   fRingHistos.SetName(GetName());
@@ -41,11 +52,19 @@ AliFMDDensityCalculator::AliFMDDensityCalculator(const char* title)
   fRingHistos.Add(new RingHistos(3, 'O'));
   fSumOfWeights = new TH1D("sumOfWeights", "Sum of Landau weights",
                           200, 0, 20);
+  fSumOfWeights->SetFillColor(kRed+1);
+  fSumOfWeights->SetXTitle("#sum_{i} a_{i} f_{i}(#Delta)");
   fWeightedSum  = new TH1D("weightedSum", "Weighted sum of Landau propability",
                           200, 0, 20);
+  fWeightedSum->SetFillColor(kBlue+1);
+  fWeightedSum->SetXTitle("#sum_{i} i a_{i} f_{i}(#Delta)");
   fCorrections  = new TH1D("corrections", "Distribution of corrections", 
                           100, 0, 10);
+  fCorrections->SetFillColor(kBlue+1);
+  fCorrections->SetXTitle("correction");
 
+  fAccI = GenerateAcceptanceCorrection('I');
+  fAccO = GenerateAcceptanceCorrection('O');
 }
 
 //____________________________________________________________________
@@ -57,6 +76,9 @@ AliFMDDensityCalculator::AliFMDDensityCalculator(const
     fSumOfWeights(o.fSumOfWeights),
     fWeightedSum(o.fWeightedSum),
     fCorrections(o.fCorrections),
+    fMaxParticles(o.fMaxParticles),
+    fAccI(o.fAccI),
+    fAccO(o.fAccO),
     fDebug(o.fDebug)
 {
   TIter    next(&o.fRingHistos);
@@ -76,8 +98,11 @@ AliFMDDensityCalculator::operator=(const AliFMDDensityCalculator& o)
 {
   TNamed::operator=(o);
 
-  fMultCut = o.fMultCut;
-  fDebug   = o.fDebug;
+  fMultCut      = o.fMultCut;
+  fDebug        = o.fDebug;
+  fMaxParticles = o.fMaxParticles;
+  fAccI         = o.fAccI;
+  fAccO         = o.fAccO;
 
   fRingHistos.Delete();
   TIter    next(&o.fRingHistos);
@@ -103,10 +128,21 @@ AliFMDDensityCalculator::GetRingHistos(UShort_t d, Char_t r) const
 }
     
 //____________________________________________________________________
+Double_t
+AliFMDDensityCalculator::GetMultCut() const
+{
+  if (fMultCut > 0) return fMultCut;
+
+  AliForwardCorrectionManager&  fcm = AliForwardCorrectionManager::Instance();
+  AliFMDCorrELossFit* fits = fcm.GetELossFit();
+  return fits->GetLowCut();
+}
+  
+//____________________________________________________________________
 Bool_t
 AliFMDDensityCalculator::Calculate(const AliESDFMD&        fmd,
                                   AliForwardUtil::Histos& hists,
-                                  Int_t                   vtxbin, 
+                                  UShort_t                vtxbin, 
                                   Bool_t                  lowFlux)
 {
   for (UShort_t d=1; d<=3; d++) { 
@@ -129,11 +165,14 @@ AliFMDDensityCalculator::Calculate(const AliESDFMD&        fmd,
          
          Float_t n = NParticles(mult,d,r,s,t,vtxbin,eta,lowFlux);
          rh->fEvsN->Fill(mult,n);
+         rh->fEtaVsN->Fill(eta, n);
 
          Float_t c = Correction(d,r,s,t,vtxbin,eta,lowFlux);
          fCorrections->Fill(c);
          if (c > 0) n /= c;
          rh->fEvsM->Fill(mult,n);
+         rh->fEtaVsM->Fill(eta, n);
+         rh->fCorr->Fill(eta, c);
 
          h->Fill(eta,phi,n);
          rh->fDensity->Fill(eta,phi,n);
@@ -152,15 +191,38 @@ AliFMDDensityCalculator::NParticles(Float_t  mult,
                                    Char_t   r, 
                                    UShort_t /*s*/, 
                                    UShort_t /*t*/, 
-                                   Int_t    /*v*/, 
+                                   UShort_t /*v*/, 
                                    Float_t  eta,
                                    Bool_t   lowFlux) const
 {
-  if (mult <= fMultCut) return 0;
+  if (mult <= GetMultCut()) return 0;
   if (lowFlux) return 1;
+  
+  // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  AliForwardCorrectionManager&  fcm = AliForwardCorrectionManager::Instance();
+  AliFMDCorrELossFit::ELossFit* fit = fcm.GetELossFit()->FindFit(d,r,eta);
+  if (!fit) { 
+    AliWarning(Form("No energy loss fit for FMD%d%c at eta=%f", d, r, eta));
+    return 0;
+  }
+  
+  Int_t    m   = fit->FindMaxWeight();
+  if (m < 1) { 
+    AliWarning(Form("No good fits for FMD%d%c at eta=%f", d, r, eta));
+    return 0;
+  }
+  UShort_t n   = TMath::Min(fMaxParticles, UShort_t(m));
+  Double_t ret = fit->EvaluateWeighted(mult, n);
+
+  if (fDebug > 10) {
+    AliInfo(Form("FMD%d%c, eta=%7.4f, %8.5f -> %8.5f", d, r, eta, mult, ret));
+  }
 
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  fWeightedSum->Fill(ret);
+  fSumOfWeights->Fill(ret);
 
+  return ret;
+#if 0
   Float_t mpv  = pars->GetMPV(d,r,eta);
   Float_t w    = pars->GetSigma(d,r,eta);
   Float_t w2   = pars->Get2MIPWeight(d,r,eta);
@@ -178,63 +240,178 @@ AliFMDDensityCalculator::NParticles(Float_t  mult,
   fWeightedSum->Fill(wsum);
   fSumOfWeights->Fill(sum);
   return (sum > 0) ? wsum / sum : 1;
+#endif
 }
 
 //_____________________________________________________________________
 Float_t 
-AliFMDDensityCalculator::Correction(UShort_t d, Char_t r, UShort_t /*s*/, 
-                                   UShort_t t, Int_t v, Float_t eta,
-                                   Bool_t lowFlux) const
+AliFMDDensityCalculator::Correction(UShort_t d, 
+                                   Char_t   r, 
+                                   UShort_t /*s*/, 
+                                   UShort_t t, 
+                                   UShort_t /*v*/, 
+                                   Float_t  eta,
+                                   Bool_t   lowFlux) const
 {
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  AliForwardCorrectionManager&  fcm = AliForwardCorrectionManager::Instance();
 
   Float_t correction = AcceptanceCorrection(r,t);
   if (lowFlux) { 
-    TH1F* dblHitCor = pars->GetDoubleHitCorrection(d,r);
+    // TH1F* dblHitCor = pars->GetDoubleHitCorrection(d,r);
+    TH1D* dblHitCor = 0;
+    if (fcm.GetDoubleHit()) 
+      dblHitCor = fcm.GetDoubleHit()->GetCorrection(d,r);
+
     if (dblHitCor) {
-      Float_t dblC = dblHitCor->GetBinContent(dblHitCor->FindBin(eta));
-      if (dblC > 0) 
-       correction *= dblC;
+      Double_t dblC = dblHitCor->GetBinContent(dblHitCor->FindBin(eta));
+      if (dblC > 0) correction *= dblC;
     }
-    else 
+    else {
       AliWarning(Form("Missing double hit correction for FMD%d%c",d,r));
+    }
   }
   
+#if 0
   TH1F* deadCor = pars->GetFMDDeadCorrection(v);
   if (deadCor) { 
     Float_t deadC = deadCor->GetBinContent(deadCor->FindBin(eta));
     if (deadC > 0) 
       correction *= deadC; 
   }
-  
+#endif  
+
   return correction;
 }
 
+//_____________________________________________________________________
+TH1D*
+AliFMDDensityCalculator::GenerateAcceptanceCorrection(Char_t r) const
+{
+  const Double_t ic1[] = { 4.9895, 15.3560 };
+  const Double_t ic2[] = { 1.8007, 17.2000 };
+  const Double_t oc1[] = { 4.2231, 26.6638 };
+  const Double_t oc2[] = { 1.8357, 27.9500 };
+  const Double_t* c1   = (r == 'I' || r == 'i' ? ic1      : oc1);
+  const Double_t* c2   = (r == 'I' || r == 'i' ? ic2      : oc2);
+  Double_t  minR       = (r == 'I' || r == 'i' ?   4.5213 :  15.4);
+  Double_t  maxR       = (r == 'I' || r == 'i' ?  17.2    :  28.0);
+  Int_t     nStrips    = (r == 'I' || r == 'i' ? 512      : 256);
+  Int_t     nSec       = (r == 'I' || r == 'i' ?  20      :  40);
+  Float_t   basearc    = 2 * TMath::Pi() / nSec;
+  Double_t  rad        = maxR - minR;
+  Float_t   segment    = rad / nStrips;
+  Float_t   cr         = TMath::Sqrt(c1[0]*c1[0]+c1[1]*c1[1]);
+
+  // Numbers used to find end-point of strip.
+  // (See http://mathworld.wolfram.com/Circle-LineIntersection.html)
+  Float_t D            = c1[0] * c2[1] - c1[1] * c2[0];
+  Float_t dx           = c2[0] - c1[0];
+  Float_t dy           = c2[1] - c1[1];
+  Float_t dr           = TMath::Sqrt(dx*dx+dy*dy);
+
+  TH1D* ret = new TH1D(Form("acc%c", r), 
+                      Form("Acceptance correction for FMDx%c", r), 
+                      nStrips, -.5, nStrips-.5);
+  ret->SetXTitle("Strip");
+  ret->SetYTitle("#varphi acceptance");
+  ret->SetDirectory(0);
+  ret->SetFillColor(r == 'I' || r == 'i' ? kRed+1 : kBlue+1);
+  ret->SetFillStyle(3001);
+
+  for (Int_t t = 0; t < nStrips; t++) { 
+    Float_t   radius     = minR + t * segment;
+    
+    // If the radius of the strip is smaller than the radius corresponding 
+    // to the first corner we have a full strip length 
+    if (radius <= cr) {
+      ret->SetBinContent(t+1, 1);
+      continue;
+    }
+
+    // Next, we should find the end-point of the strip - that is, 
+    // the coordinates where the line from c1 to c2 intersects a circle 
+    // with radius given by the strip. 
+    // (See http://mathworld.wolfram.com/Circle-LineIntersection.html)
+    // Calculate the determinant 
+    Float_t det = radius * radius * dr * dr - D*D;
+
+    if (det <=  0) { 
+      // <0 means No intersection
+      // =0 means Exactly tangent
+      ret->SetBinContent(t+1, 1);
+      continue;
+    }
+
+    // Calculate end-point and the corresponding opening angle 
+    Float_t x   = (+D * dy + dx * TMath::Sqrt(det)) / dr / dr;
+    Float_t y   = (-D * dx + dy * TMath::Sqrt(det)) / dr / dr;
+    Float_t th  = TMath::ATan2(x, y);
+
+    ret->SetBinContent(t+1, th / basearc);
+  }
+  return ret;
+}
 
 //_____________________________________________________________________
 Float_t 
 AliFMDDensityCalculator::AcceptanceCorrection(Char_t r, UShort_t t) const
 {
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
-  
-  //AliFMDRing fmdring(ring);
-  //fmdring.Init();
-  Float_t   rad       = pars->GetMaxR(r)-pars->GetMinR(r);
-  Float_t   slen      = pars->GetStripLength(r,t);
-  Float_t   sblen     = pars->GetBaseStripLength(r,t);
-  Float_t   nstrips   = (r == 'I' ? 512 : 256);
-  Float_t   segment   = rad / nstrips;
-  Float_t   radius    = pars->GetMinR(r) + segment*t;
+  TH1D* acc = (r == 'I' || r == 'i' ? fAccI : fAccO);
+  return acc->GetBinContent(t+1);
+
+#if 0
+  const Double_t ic1[] = { 4.9895, 15.3560 };
+  const Double_t ic2[] = { 1.8007, 17.2000 };
+  const Double_t oc1[] = { 4.2231, 26.6638 };
+  const Double_t oc2[] = { 1.8357, 27.9500 };
+  const Double_t* c1   = (r == 'I' ? ic1      : oc1);
+  const Double_t* c2   = (r == 'I' ? ic2      : oc2);
+  Double_t  minR       = (r == 'I' ?   4.5213 :  15.4);
+  Double_t  maxR       = (r == 'I' ?  17.2    :  28.0);
+  Int_t     nStrips    = (r == 'I' ? 512      : 256);
+  Int_t     nSec       = (r == 'I' ?  20      :  40);
+  Float_t   basearc    = 2 * TMath::Pi() / nSec;
+  Double_t  rad        = maxR - minR;
+  Float_t   segment    = rad / nStrips;
+  Float_t   radius     = minR + t * segment;
+
+  // Old method - calculate full strip area and take ratio to extended
+  // strip area
+  Float_t   baselen    = basearc * radius;
+  Float_t   slope      = (c1[1] - c2[1]) / (c1[0] - c2[0]);
+  Float_t   constant   = (c2[1] * c1[0] - c2[0] * c1[1]) / (c1[0]-c2[0]);
+  Float_t   d          = (TMath::Power(TMath::Abs(radius*slope),2) + 
+                         TMath::Power(radius,2) - TMath::Power(constant,2));
+
+  // If below corners return 1
+  if (d >= 0) return 1;
+  Float_t   x         = ((-TMath::Sqrt(d) - slope * constant) / 
+                        (1+TMath::Power(slope, 2)));
+  Float_t   y         = slope*x + constant;
+
+  // If x is larger than corner x or y less than corner y, we have full
+  // length strip
+  if(x >= c1[0] || y <= c1[1]) return 1;
+
+  //One sector since theta is by definition half-hybrid
+  Float_t   theta     = TMath::ATan2(x,y);
+  Float_t   arclen    = radius * theta;
   
-  Float_t   basearea1 = 0.5*sblen*TMath::Power(radius,2);
-  Float_t   basearea2 = 0.5*sblen*TMath::Power((radius-segment),2);
+  // Calculate the area of a strip with no cut
+  Float_t   basearea1 = 0.5 * baselen * TMath::Power(radius,2);
+  Float_t   basearea2 = 0.5 * baselen * TMath::Power((radius-segment),2);
   Float_t   basearea  = basearea1 - basearea2;
-  
-  Float_t   area1     = 0.5*slen*TMath::Power(radius,2);
-  Float_t   area2     = 0.5*slen*TMath::Power((radius-segment),2);
+
+  // Calculate the area of a strip with cut
+  Float_t   area1     = 0.5 * arclen * TMath::Power(radius,2);
+  Float_t   area2     = 0.5 * arclen * TMath::Power((radius-segment),2);
   Float_t   area      = area1 - area2;
   
+  // Acceptance is ratio 
   return area/basearea;
+#endif
 }
 
 //____________________________________________________________________
@@ -261,18 +438,36 @@ AliFMDDensityCalculator::DefineOutput(TList* dir)
   d->Add(fWeightedSum);
   d->Add(fSumOfWeights);
   d->Add(fCorrections);
+  d->Add(fAccI);
+  d->Add(fAccO);
+
   TIter    next(&fRingHistos);
   RingHistos* o = 0;
   while ((o = static_cast<RingHistos*>(next()))) {
     o->Output(d);
   }
 }
+//____________________________________________________________________
+void
+AliFMDDensityCalculator::Print(Option_t*) const
+{
+  char ind[gROOT->GetDirLevel()+1];
+  for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
+  ind[gROOT->GetDirLevel()] = '\0';
+  std::cout << ind << "AliFMDDensityCalculator: " << GetName() << '\n'
+           << ind << " Multiplicity cut:       " << fMultCut << '\n'
+           << ind << " Max(particles):         " << fMaxParticles 
+           << std::endl;
+}
 
 //====================================================================
 AliFMDDensityCalculator::RingHistos::RingHistos()
   : AliForwardUtil::RingHistos(),
     fEvsN(0), 
     fEvsM(0), 
+    fEtaVsN(0),
+    fEtaVsM(0),
+    fCorr(0),
     fDensity(0)
 {}
 
@@ -281,26 +476,57 @@ AliFMDDensityCalculator::RingHistos::RingHistos(UShort_t d, Char_t r)
   : AliForwardUtil::RingHistos(d,r),
     fEvsN(0), 
     fEvsM(0),
+    fEtaVsN(0),
+    fEtaVsM(0),
+    fCorr(0),
     fDensity(0)
 {
   fEvsN = new TH2D(Form("%s_Eloss_N_nocorr", fName.Data()), 
-                  Form("Energy loss vs uncorrected inclusive "
+                  Form("#Delta E/#Delta E_{mip} vs uncorrected inclusive "
                        "N_{ch} in %s", fName.Data()), 
-                  100, -.5, 24.5, 100, -.5, 24.5);
+                  2500, -.5, 24.5, 2500, -.5, 24.5);
   fEvsM = new TH2D(Form("%s_Eloss_N_corr", fName.Data()), 
-                  Form("Energy loss vs corrected inclusive N_{ch} in %s",
-                       fName.Data()), 100, -.5, 24.5, 100, -.5, 24.5);
+                  Form("#Delta E/#Delta E_{mip} vs corrected inclusive "
+                       "N_{ch} in %s", fName.Data()), 
+                  2500, -.5, 24.5, 2500, -.5, 24.5);
   fEvsN->SetXTitle("#Delta E/#Delta E_{mip}");
   fEvsN->SetYTitle("Inclusive N_{ch} (uncorrected)");
   fEvsN->Sumw2();
   fEvsN->SetDirectory(0);
-  fEvsN->SetXTitle("#Delta E/#Delta E_{mip}");
-  fEvsN->SetYTitle("Inclusive N_{ch} (corrected)");
+  fEvsM->SetXTitle("#Delta E/#Delta E_{mip}");
+  fEvsM->SetYTitle("Inclusive N_{ch} (corrected)");
   fEvsM->Sumw2();
   fEvsM->SetDirectory(0);
 
+  fEtaVsN = new TProfile(Form("%s_Eta_N_nocorr", fName.Data()),
+                        Form("Average inclusive N_{ch} vs #eta (uncorrected) "
+                             "in %s", fName.Data()), 200, -4, 6);
+  fEtaVsM = new TProfile(Form("%s_Eta_N_corr", fName.Data()),
+                        Form("Average inclusive N_{ch} vs #eta (corrected) "
+                             "in %s", fName.Data()), 200, -4, 6);
+  fEtaVsN->SetXTitle("#eta");
+  fEtaVsN->SetYTitle("#LT N_{ch,incl}#GT (uncorrected)");
+  fEtaVsN->SetDirectory(0);
+  fEtaVsN->SetLineColor(Color());
+  fEtaVsN->SetFillColor(Color());
+  fEtaVsM->SetXTitle("#eta");
+  fEtaVsM->SetYTitle("#LT N_{ch,incl}#GT (corrected)");
+  fEtaVsM->SetDirectory(0);
+  fEtaVsM->SetLineColor(Color());
+  fEtaVsM->SetFillColor(Color());
+
+
+  fCorr = new TProfile(Form("%s_corr", fName.Data()),
+                        Form("Average correction in %s", fName.Data()), 
+                      200, -4, 6);
+  fCorr->SetXTitle("#eta");
+  fCorr->SetYTitle("#LT correction#GT");
+  fCorr->SetDirectory(0);
+  fCorr->SetLineColor(Color());
+  fCorr->SetFillColor(Color());
+
   fDensity = new TH2D(Form("%s_Incl_Density", fName.Data()), 
-                     Form("Inclusive N_{ch} densitu in %s", fName.Data()), 
+                     Form("Inclusive N_{ch} density in %s", fName.Data()), 
                      200, -4, 6, (r == 'I' || r == 'i' ? 20 : 40), 
                      0, 2*TMath::Pi());
   fDensity->SetDirectory(0);
@@ -313,6 +539,9 @@ AliFMDDensityCalculator::RingHistos::RingHistos(const RingHistos& o)
   : AliForwardUtil::RingHistos(o), 
     fEvsN(o.fEvsN), 
     fEvsM(o.fEvsM),
+    fEtaVsN(o.fEtaVsN),
+    fEtaVsM(o.fEtaVsM),
+    fCorr(o.fCorr),
     fDensity(o.fDensity)
 {}
 
@@ -324,10 +553,16 @@ AliFMDDensityCalculator::RingHistos::operator=(const RingHistos& o)
   
   if (fEvsN)    delete  fEvsN;
   if (fEvsM)    delete  fEvsM;
+  if (fEtaVsN)  delete  fEtaVsN;
+  if (fEtaVsM)  delete  fEtaVsM;
+  if (fCorr)    delete  fCorr;
   if (fDensity) delete fDensity;
   
   fEvsN    = static_cast<TH2D*>(o.fEvsN->Clone());
   fEvsM    = static_cast<TH2D*>(o.fEvsM->Clone());
+  fEtaVsN  = static_cast<TProfile*>(o.fEtaVsN->Clone());
+  fEtaVsM  = static_cast<TProfile*>(o.fEtaVsM->Clone());
+  fCorr    = static_cast<TProfile*>(o.fCorr->Clone());
   fDensity = static_cast<TH2D*>(o.fDensity->Clone());
   
   return *this;
@@ -337,6 +572,9 @@ AliFMDDensityCalculator::RingHistos::~RingHistos()
 {
   if (fEvsN)    delete fEvsN;
   if (fEvsM)    delete fEvsM;
+  if (fEtaVsN)  delete fEtaVsN;
+  if (fEtaVsM)  delete fEtaVsM;
+  if (fCorr)    delete fCorr;
   if (fDensity) delete fDensity;
 }
 
@@ -347,6 +585,9 @@ AliFMDDensityCalculator::RingHistos::Output(TList* dir)
   TList* d = DefineOutputList(dir);
   d->Add(fEvsN);
   d->Add(fEvsM);
+  d->Add(fEtaVsN);
+  d->Add(fEtaVsM);
+  d->Add(fCorr);
   d->Add(fDensity);
 }
 
index 47dae71..20a1cef 100644 (file)
@@ -6,6 +6,7 @@
 class AliESDFMD;
 class TH2D;
 class TH1D;
+class TProfile;
 
 /** 
  * This class calculates the inclusive charged particle density
@@ -68,7 +69,7 @@ public:
    */
   virtual Bool_t Calculate(const AliESDFMD& fmd, 
                           AliForwardUtil::Histos& hists, 
-                          Int_t vtxBin, Bool_t lowFlux);
+                          UShort_t vtxBin, Bool_t lowFlux);
   /** 
    * Scale the histograms to the total number of events 
    * 
@@ -88,6 +89,33 @@ public:
    * @param dbg Debug level 
    */
   void SetDebug(Int_t dbg=1) { fDebug = dbg; }
+  /** 
+   * Maximum particle weight to use 
+   * 
+   * @param m 
+   */
+  void SetMaxParticles(UShort_t m) { fMaxParticles = m; }  
+  /** 
+   * Set the lower multiplicity cut.  This overrides the setting in
+   * the energy loss fits.
+   * 
+   * @param cut Cut to use 
+   */
+  void SetMultCut(Double_t cut) { fMultCut = cut; }
+  /** 
+   * Get the multiplicity cut.  If the user has set fMultCut (via
+   * SetMultCut) then that value is used.  If not, then the lower
+   * value of the fit range for the enery loss fits is returned.
+   * 
+   * @return Lower cut on multiplicity
+   */
+  Double_t GetMultCut() const;
+  /** 
+   * Print information 
+   * 
+   * @param option Not used
+   */
+  void Print(Option_t* option="") const;
 protected:
   /** 
    * Get the number of particles corresponding to the signal mult
@@ -105,7 +133,7 @@ protected:
    */
   virtual Float_t NParticles(Float_t mult, 
                             UShort_t d, Char_t r, UShort_t s, UShort_t t, 
-                            Int_t v, Float_t eta, Bool_t lowFlux) const;
+                            UShort_t v, Float_t eta, Bool_t lowFlux) const;
   /** 
    * Get the inverse correction factor.  This consist of
    * 
@@ -124,7 +152,7 @@ protected:
    * @return 
    */
   virtual Float_t Correction(UShort_t d, Char_t r, UShort_t s, UShort_t t, 
-                            Int_t v, Float_t eta, Bool_t lowFlux) const;
+                            UShort_t v, Float_t eta, Bool_t lowFlux) const;
   /** 
    * Get the acceptance correction for strip @a t in an ring of type @a r
    * 
@@ -134,7 +162,14 @@ protected:
    * @return Inverse acceptance correction 
    */
   virtual Float_t AcceptanceCorrection(Char_t r, UShort_t t) const;
-
+  /** 
+   * Generate the acceptance corrections 
+   * 
+   * @param r Ring to generate for 
+   * 
+   * @return Newly allocated histogram of acceptance corrections
+   */
+  virtual TH1D*   GenerateAcceptanceCorrection(Char_t r) const;
   /** 
    * Internal data structure to keep track of the histograms
    */
@@ -184,6 +219,9 @@ protected:
     void ScaleHistograms(TList* dir, Int_t nEvents);
     TH2D*     fEvsN;         // Correlation of Eloss vs uncorrected Nch
     TH2D*     fEvsM;         // Correlation of Eloss vs corrected Nch
+    TProfile* fEtaVsN;       // Average uncorrected Nch vs eta
+    TProfile* fEtaVsM;       // Average corrected Nch vs eta
+    TProfile* fCorr;         // Average correction vs eta
     TH2D*     fDensity;      // Distribution inclusive Nch
     ClassDef(RingHistos,1);
   };
@@ -202,6 +240,9 @@ protected:
   TH1D*    fSumOfWeights;  //! Histogram
   TH1D*    fWeightedSum;   //! Histogram
   TH1D*    fCorrections;   //! Histogram
+  UShort_t fMaxParticles;  //  Maximum particle weight to use 
+  TH1D*    fAccI;          //  Acceptance correction for inner rings
+  TH1D*    fAccO;          //  Acceptance correction for outer rings
   Int_t    fDebug;         //  Debug level 
 
   ClassDef(AliFMDDensityCalculator,1); // Calculate Nch density 
index 219d925..7657547 100644 (file)
@@ -2,22 +2,28 @@
 // Class to do the energy correction of FMD ESD data
 //
 #include "AliFMDEnergyFitter.h"
+#include "AliForwardCorrectionManager.h"
 #include <AliESDFMD.h>
 #include <TAxis.h>
 #include <TList.h>
 #include <TH1.h>
 #include <TF1.h>
 #include <TMath.h>
-#include "AliFMDAnaParameters.h"
 #include <AliLog.h>
 #include <TClonesArray.h>
 #include <TFitResult.h>
 #include <THStack.h>
+#include <TROOT.h>
+#include <iostream>
+#include <iomanip>
 
 ClassImp(AliFMDEnergyFitter)
 #if 0
 ; // This is for Emacs
 #endif 
+namespace {
+  const char* fgkEDistFormat = "%s_etabin%03d";
+}
 
 
 //____________________________________________________________________
@@ -29,12 +35,14 @@ AliFMDEnergyFitter::AliFMDEnergyFitter()
     fMinEntries(100),
     fFitRangeBinWidth(4),
     fDoFits(false),
+    fDoMakeObject(false),
     fEtaAxis(),
     fMaxE(10),
     fNEbins(300), 
     fUseIncreasingBins(true),
     fMaxRelParError(.25),
     fMaxChi2PerNDF(20), 
+    fMinWeight(1e-7),
     fDebug(0)
 {}
 
@@ -47,12 +55,14 @@ AliFMDEnergyFitter::AliFMDEnergyFitter(const char* title)
     fMinEntries(100),
     fFitRangeBinWidth(4),
     fDoFits(false),
+    fDoMakeObject(false),
     fEtaAxis(0,0,0),
     fMaxE(10),
     fNEbins(300), 
     fUseIncreasingBins(true),
     fMaxRelParError(.25),
-    fMaxChi2PerNDF(20), 
+    fMaxChi2PerNDF(20),  
+    fMinWeight(1e-7),
     fDebug(3)
 {
   fEtaAxis.SetName("etaAxis");
@@ -73,12 +83,14 @@ AliFMDEnergyFitter::AliFMDEnergyFitter(const AliFMDEnergyFitter& o)
     fMinEntries(o.fMinEntries),
     fFitRangeBinWidth(o.fFitRangeBinWidth),
     fDoFits(o.fDoFits),
+    fDoMakeObject(o.fDoMakeObject),
     fEtaAxis(o.fEtaAxis),
     fMaxE(o.fMaxE),
     fNEbins(o.fNEbins), 
     fUseIncreasingBins(o.fUseIncreasingBins),
     fMaxRelParError(o.fMaxRelParError),
     fMaxChi2PerNDF(o.fMaxChi2PerNDF), 
+    fMinWeight(o.fMinWeight),
     fDebug(o.fDebug)
 {
   TIter    next(&o.fRingHistos);
@@ -103,8 +115,12 @@ AliFMDEnergyFitter::operator=(const AliFMDEnergyFitter& o)
   fMinEntries    = o.fMinEntries;
   fFitRangeBinWidth= o.fFitRangeBinWidth;
   fDoFits        = o.fDoFits;
+  fDoMakeObject  = o.fDoMakeObject;
   fEtaAxis.Set(o.fEtaAxis.GetNbins(),o.fEtaAxis.GetXmin(),o.fEtaAxis.GetXmax());
   fDebug         = o.fDebug;
+  fMaxRelParError= o.fMaxRelParError;
+  fMaxChi2PerNDF = o.fMaxChi2PerNDF;
+  fMinWeight     = o.fMinWeight;
 
   fRingHistos.Delete();
   TIter    next(&o.fRingHistos);
@@ -229,6 +245,34 @@ AliFMDEnergyFitter::Fit(TList* dir)
       stack[i % nStack]->Add(static_cast<TH1*>(l->At(i))); 
     }
   }
+
+  if (!fDoMakeObject) return;
+
+  MakeCorrectionsObject(d);
+}
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitter::MakeCorrectionsObject(TList* d)
+{
+  AliForwardCorrectionManager& mgr = AliForwardCorrectionManager::Instance();
+    
+  AliFMDCorrELossFit* obj = new AliFMDCorrELossFit;
+  obj->SetEtaAxis(fEtaAxis);
+  obj->SetLowCut(fLowCut);
+
+  TIter    next(&fRingHistos);
+  RingHistos* o = 0;
+  while ((o = static_cast<RingHistos*>(next()))) {
+    o->FindBestFits(d, *obj, fEtaAxis, fMaxRelParError, 
+                   fMaxChi2PerNDF, fMinWeight);
+  }
+  
+  TString oName(mgr.GetObjectName(AliForwardCorrectionManager::kELossFits));
+  TString fileName(mgr.GetFilePath(AliForwardCorrectionManager::kELossFits));
+  AliInfo(Form("Object %s created in output - should be extracted and copied "
+              "to %s", oName.Data(), fileName.Data()));
+  d->Add(obj, oName.Data());
 }
 
 //____________________________________________________________________
@@ -255,6 +299,32 @@ AliFMDEnergyFitter::SetDebug(Int_t dbg)
   while ((o = static_cast<RingHistos*>(next())))
     o->fDebug = dbg;
 }  
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitter::Print(Option_t*) const
+{
+  char ind[gROOT->GetDirLevel()+1];
+  for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
+  ind[gROOT->GetDirLevel()] = '\0';
+  std::cout << ind << "AliFMDEnergyFitter: " << GetName() << '\n'
+           << ind << " Low cut:                " << fLowCut << " E/E_mip\n"
+           << ind << " Max(particles):         " << fNParticles << '\n'
+           << ind << " Min(entries):           " << fMinEntries << '\n'
+           << ind << " Fit range:              " 
+           << fFitRangeBinWidth << " bins\n"
+           << ind << " Make fits:              " 
+           << (fDoFits ? "yes\n" : "no\n")
+           << ind << " Make object:            " 
+           << (fDoMakeObject ? "yes\n" : "no\n")
+           << ind << " Max E/E_mip:            " << fMaxE << '\n'
+           << ind << " N bins:                 " << fNEbins << '\n'
+           << ind << " Increasing bins:        " 
+           << (fUseIncreasingBins ?"yes\n" : "no\n")
+           << ind << " max(delta p/p):         " << fMaxRelParError << '\n'
+           << ind << " max(chi^2/nu):          " << fMaxChi2PerNDF << '\n'
+           << ind << " min(a_i):               " << fMinWeight << std::endl;
+}
   
 //====================================================================
 AliFMDEnergyFitter::RingHistos::RingHistos()
@@ -263,6 +333,7 @@ AliFMDEnergyFitter::RingHistos::RingHistos()
     fEmpty(0),
     fEtaEDists(), 
     fList(0),
+    fFits("AliFMDCorrELossFit::ELossFit"),
     fDebug(0)
 {}
 
@@ -273,6 +344,7 @@ AliFMDEnergyFitter::RingHistos::RingHistos(UShort_t d, Char_t r)
     fEmpty(0),
     fEtaEDists(), 
     fList(0),
+    fFits("AliFMDCorrELossFit::ELossFit"),
     fDebug(0)
 {
   fEtaEDists.SetName("EDists");
@@ -284,8 +356,10 @@ AliFMDEnergyFitter::RingHistos::RingHistos(const RingHistos& o)
     fEmpty(o.fEmpty),
     fEtaEDists(), 
     fList(0),
+    fFits("AliFMDCorrELossFit::ELossFit"),
     fDebug(0)
 {
+  fFits.Clear();
   TIter next(&o.fEtaEDists);
   TObject* obj = 0;
   while ((obj = next())) fEtaEDists.Add(obj->Clone());
@@ -307,6 +381,7 @@ AliFMDEnergyFitter::RingHistos::operator=(const RingHistos& o)
   if (fEmpty) delete fEmpty;
   fEtaEDists.Delete();
   if (fList) fList->Delete();
+  fFits.Clear();
 
   fEDist = static_cast<TH1D*>(o.fEDist->Clone());
   fEmpty = static_cast<TH1D*>(o.fEmpty->Clone());
@@ -383,7 +458,7 @@ AliFMDEnergyFitter::RingHistos::Make(Int_t    ieta,
                                     Bool_t   incr)
 {
   TH1D* h = 0;
-  TString name  = Form("%s_etabin%03d", fName.Data(), ieta);
+  TString name  = Form(fgkEDistFormat, fName.Data(), ieta);
   TString title = Form("#DeltaE/#DeltaE_{mip} for %s %+5.3f#leq#eta<%+5.3f "
                       "(#eta bin %d)", fName.Data(), emin, emax, ieta);
   if (!incr) 
@@ -476,13 +551,14 @@ AliFMDEnergyFitter::RingHistos::Init(const TAxis& eAxis,
 }
 //____________________________________________________________________
 TObjArray*
-AliFMDEnergyFitter::RingHistos::Fit(TList* dir, const TAxis& eta,
-                                   Double_t lowCut, 
-                                   UShort_t nParticles,
-                                   UShort_t minEntries,
-                                   UShort_t minusBins, 
-                                   Double_t relErrorCut, 
-                                   Double_t chi2nuCut) const
+AliFMDEnergyFitter::RingHistos::Fit(TList*           dir, 
+                                   const TAxis&     eta,
+                                   Double_t         lowCut, 
+                                   UShort_t         nParticles,
+                                   UShort_t         minEntries,
+                                   UShort_t         minusBins, 
+                                   Double_t         relErrorCut, 
+                                   Double_t         chi2nuCut) const
 {
   // Get our ring list from the output container 
   TList* l = GetOutputList(dir);
@@ -535,17 +611,23 @@ AliFMDEnergyFitter::RingHistos::Fit(TList* dir, const TAxis& eta,
     
     // Normalize peak to 1 
     Double_t max = dist->GetMaximum(); 
+    if (max <= 0) continue;
     dist->Scale(1/max);
     
     // Check that we have enough entries 
-    if (dist->GetEntries() <= minEntries) continue;
+    if (dist->GetEntries() <= minEntries) { 
+      AliWarning(Form("Histogram at %3d (%s) has too few entries (%d <= %d)",
+                     i, dist->GetName(), Int_t(dist->GetEntries()), 
+                     minEntries));
+      continue;
+    }
 
     // Now fit 
     TF1* res = FitHist(dist,lowCut,nParticles,minusBins,
                       relErrorCut,chi2nuCut);
     if (!res) continue;
     // dist->GetListOfFunctions()->Add(res);
-    
+
     // Store eta limits 
     low   = TMath::Min(low,i+1);
     high  = TMath::Max(high,i+1);
@@ -580,6 +662,14 @@ AliFMDEnergyFitter::RingHistos::Fit(TList* dir, const TAxis& eta,
   // Fit the full-ring histogram 
   TH1* total = GetOutputHist(l, Form("%s_edist", fName.Data()));
   if (total && total->GetEntries() >= minEntries) { 
+
+    // Scale to the bin-width
+    total->Scale(1., "width");
+    
+    // Normalize peak to 1 
+    Double_t max = total->GetMaximum(); 
+    if (max > 0) total->Scale(1/max);
+
     TF1* res = FitHist(total,lowCut,nParticles,minusBins,
                       relErrorCut,chi2nuCut);
     if (res) { 
@@ -621,8 +711,17 @@ AliFMDEnergyFitter::RingHistos::Fit(TList* dir, const TAxis& eta,
   TObjLink* lnk = dists->FirstLink();
   while (lnk) {
     TH1* h = static_cast<TH1*>(lnk->GetObject());
-    if (h->GetEntries() <= 0 || 
-       h->GetListOfFunctions()->GetEntries() <= 0) {
+    bool remove = false;
+    if (h->GetEntries() <= 0) { 
+      // AliWarning(Form("No entries in %s - removing", h->GetName()));
+      remove = true;
+    }
+    else if (h->GetListOfFunctions()->GetEntries() <= 0) {
+      // AliWarning(Form("No fuctions associated with %s - removing",
+      //            h->GetName()));
+      remove = true;
+    }
+    if (remove) {
       TObjLink* keep = lnk->Next();
       dists->Remove(lnk);
       lnk = keep;
@@ -692,9 +791,9 @@ AliFMDEnergyFitter::RingHistos::FitHist(TH1*     dist,
     break;
   }
   // Give a warning if we're using fall-back 
-  if (ret == f.fFunctions.At(0))
+  if (ret == f.fFunctions.At(0)) {
     AliWarning("Choosing fall-back 1 particle fit");
-
+  }
   // Copy our result and return (the functions are owned by the fitter)
   TF1* fret = new TF1(*ret);
   return fret;
@@ -716,10 +815,10 @@ AliFMDEnergyFitter::RingHistos::CheckResult(TFitResult* r,
   
   // Check that the reduced chi square isn't larger than 5
   if (ndf <= 0 || chi2 / ndf > chi2nuCut) { 
-    if (fDebug > 2)
+    if (fDebug > 2) {
       AliWarning(Form("%s: chi^2/ndf=%12.5f/%3d=%12.5f>%12.5f", 
                      n.Data(), chi2, ndf, (ndf<0 ? 0 : chi2/ndf),
-                     chi2nuCut));
+                     chi2nuCut)); }
     ret = kFALSE;
   }
     
@@ -737,12 +836,12 @@ AliFMDEnergyFitter::RingHistos::CheckResult(TFitResult* r,
     Double_t re  = e / v;
     Double_t cut = relErrorCut * (i < kN ? 1 : 2);
     if (re > cut) { 
-      if (fDebug > 2)
+      if (fDebug > 2) {
        AliWarning(Form("%s: Delta %s/%s=%9.5f/%9.5f=%5.1f%%>%5.1f%%",
                        n.Data(), r->ParName(i).c_str(), 
                        r->ParName(i).c_str(), e, v, 
                        100*(v == 0 ? 0 : e/v),
-                       100*(cut)));
+                       100*(cut))); }
       ret = kFALSE;
     }
   }
@@ -753,9 +852,9 @@ AliFMDEnergyFitter::RingHistos::CheckResult(TFitResult* r,
     // Check that the last particle has a significant contribution 
     Double_t lastScale = r->Parameter(nPar-1);
     if (lastScale <= 1e-7) { 
-      if (fDebug)
+      if (fDebug) {
        AliWarning(Form("%s: %s=%9.6f<1e-7", 
-                       n.Data(), r->ParName(nPar-1).c_str(), lastScale));
+                       n.Data(), r->ParName(nPar-1).c_str(), lastScale)); }
       ret = kFALSE;
     }
   }
@@ -763,6 +862,71 @@ AliFMDEnergyFitter::RingHistos::CheckResult(TFitResult* r,
 }
 
 
+//__________________________________________________________________
+void
+AliFMDEnergyFitter::RingHistos::FindBestFits(TList*              d, 
+                                            AliFMDCorrELossFit& obj,
+                                            const TAxis&        eta,     
+                                            Double_t            relErrorCut, 
+                                            Double_t            chi2nuCut,
+                                            Double_t            minWeightCut)
+{
+  // Get our ring list from the output container 
+  TList* l = GetOutputList(d);
+  if (!l) return; 
+
+  // Get the energy distributions from the output container 
+  TList* dists = static_cast<TList*>(l->FindObject("EDists"));
+  if (!dists) { 
+    AliWarning(Form("Didn't find %s_EtaEDists in %s", 
+                   fName.Data(), l->GetName()));
+    l->ls();
+    return;
+  }
+  Int_t nBin = eta.GetNbins();
+
+  for (Int_t b = 1; b <= nBin; b++) { 
+    TString n(Form(fgkEDistFormat, fName.Data(), b));
+    TH1D*   dist = static_cast<TH1D*>(dists->FindObject(n));
+    // Ignore empty histograms altoghether 
+    if (!dist || dist->GetEntries() <= 0) continue; 
+    
+    AliFMDCorrELossFit::ELossFit* best = FindBestFit(dist,
+                                                    relErrorCut,
+                                                    chi2nuCut,  
+                                                    minWeightCut);
+    best->fDet  = fDet; 
+    best->fRing = fRing;
+    best->fBin  = b; // 
+    // Double_t eta = fAxis->GetBinCenter(b);
+    obj.SetFit(fDet, fRing, b, new AliFMDCorrELossFit::ELossFit(*best));
+  }
+}
+
+//__________________________________________________________________
+AliFMDCorrELossFit::ELossFit* 
+AliFMDEnergyFitter::RingHistos::FindBestFit(TH1* dist,
+                                           Double_t relErrorCut, 
+                                           Double_t chi2nuCut,
+                                           Double_t minWeightCut) 
+{
+  TList* funcs = dist->GetListOfFunctions();
+  TIter  next(funcs);
+  TF1*   func = 0;
+  fFits.Clear();
+  Int_t  i = 0;
+  // Info("FindBestFit", "%s", dist->GetName());
+  while ((func = static_cast<TF1*>(next()))) { 
+    AliFMDCorrELossFit::ELossFit* fit = 
+      new(fFits[i++]) AliFMDCorrELossFit::ELossFit(0,*func);
+    fit->CalculateQuality(chi2nuCut, relErrorCut, minWeightCut);
+  }
+  fFits.Sort(false);
+  // fFits.Print();
+  return static_cast<AliFMDCorrELossFit::ELossFit*>(fFits.At(0));
+}
+
+
 //____________________________________________________________________
 void
 AliFMDEnergyFitter::RingHistos::Output(TList* dir)
index 70649dd..18758eb 100644 (file)
@@ -5,6 +5,8 @@
 #include <TAxis.h>
 #include <TList.h>
 #include <TObjArray.h>
+#include <TClonesArray.h>
+#include "AliFMDCorrELossFit.h"
 #include "AliForwardUtil.h"
 class AliESDFMD;
 class TFitResult;
@@ -120,6 +122,13 @@ public:
    */
   void SetDoFits(Bool_t doFit=kTRUE) { fDoFits = doFit; }
   /** 
+   * Set whether to make the corrections object on the output.  Note,
+   * fits should be enable for this to have any effect.
+   * 
+   * @param doMake If true (false is default), do make the corrections object. 
+   */
+  void SetDoMakeObject(Bool_t doMake=kTRUE) { fDoMakeObject = doMake; }
+  /** 
    * Set how many particles we will try to fit at most to the data
    * 
    * @param n Max number of particle to try to fit 
@@ -144,8 +153,9 @@ public:
    * @param x Number of energy loss bins 
    */
   void SetNEbins(Int_t x) { fNEbins = x; }
-  void SetMaxRelativeParameterError(Double_t e) { fMaxRelParError = e; }
-  void SetMaxChi2PerNDF(Double_t c) { fMaxChi2PerNDF = c; }
+  void SetMaxRelativeParameterError(Double_t e=0.2) { fMaxRelParError = e; }
+  void SetMaxChi2PerNDF(Double_t c=10) { fMaxChi2PerNDF = c; }
+  void SetMinWeight(Double_t c=1e-7) { fMinWeight = c; }
   /**
    * Set wheter to use increasing bin sizes 
    *
@@ -168,6 +178,7 @@ public:
    * @param dir Where the histograms are  
    */
   void Fit(TList* dir);
+  void MakeCorrectionsObject(TList* dir);
   
   /** 
    * Define the output histograms.  These are put in a sub list of the
@@ -183,6 +194,12 @@ public:
    * @param dbg Debug level 
    */
   void SetDebug(Int_t dbg=1);
+  /** 
+   * Print information
+   * 
+   * @param option Not used 
+   */
+  void Print(Option_t* option="") const;
 protected:
   /** 
    * Internal data structure to keep track of the histograms
@@ -298,6 +315,42 @@ protected:
                 Double_t relErrorCut, 
                 Double_t chi2nuCut) const;
     /** 
+     * Find the best fits 
+     * 
+     * @param d              Parent list
+     * @param obj            Object to add fits to
+     * @param eta            Eta axis 
+     * @param relErrorCut    Cut applied to relative error of parameter. 
+     *                       Note, for multi-particle weights, the cut 
+     *                       is loosend by a factor of 2 
+     * @param chi2nuCut      Cut on @f$ \chi^2/\nu@f$ - 
+     *                       the reduced @f$\chi^2@f$ 
+     * @param minWeightCut   Least valid @f$ a_i@f$ 
+     */
+    void FindBestFits(TList*              d, 
+                     AliFMDCorrELossFit& obj,
+                     const TAxis&        eta,     
+                     Double_t            relErrorCut, 
+                     Double_t            chi2nuCut,
+                     Double_t            minWeightCut);
+    /** 
+     * Find the best fit 
+     * 
+     * @param dist           Histogram 
+     * @param relErrorCut    Cut applied to relative error of parameter. 
+     *                       Note, for multi-particle weights, the cut 
+     *                       is loosend by a factor of 2 
+     * @param chi2nuCut      Cut on @f$ \chi^2/\nu@f$ - 
+     *                       the reduced @f$\chi^2@f$ 
+     * @param minWeightCut   Least valid @f$ a_i@f$ 
+     * 
+     * @return Best fit 
+     */
+    AliFMDCorrELossFit::ELossFit* FindBestFit(TH1* dist,
+                                             Double_t relErrorCut, 
+                                             Double_t chi2nuCut,
+                                             Double_t minWeightCut);
+    /** 
      * Check the result of the fit. Returns true if 
      * - @f$ \chi^2/\nu < \max{\chi^2/\nu}@f$
      * - @f$ \Delta p_i/p_i < \delta_e@f$ for all parameters.  Note, 
@@ -365,11 +418,12 @@ protected:
                    Int_t high, 
                    Double_t val, 
                    Double_t err) const;
-    TH1D*     fEDist;        // Ring energy distribution 
-    TH1D*     fEmpty;        // Ring energy distribution for empty events
-    TList     fEtaEDists;    // Energy distributions per eta bin. 
-    TList*    fList;
-    Int_t     fDebug;
+    TH1D*        fEDist;        // Ring energy distribution 
+    TH1D*        fEmpty;        // Ring energy distribution for empty events
+    TList        fEtaEDists;    // Energy distributions per eta bin. 
+    TList*       fList;
+    TClonesArray fFits;
+    Int_t        fDebug;
     ClassDef(RingHistos,1);
   };
   /** 
@@ -387,14 +441,17 @@ protected:
   UShort_t fNParticles;    // Number of landaus to try to fit 
   UShort_t fMinEntries;    // Minimum number of entries
   UShort_t fFitRangeBinWidth;// Number of bins to subtract from found max
-  Bool_t   fDoFits;        // Wheter to actually do the fits 
+  Bool_t   fDoFits;        // Whether to actually do the fits 
+  Bool_t   fDoMakeObject;  // Whether to make corrections object
   TAxis    fEtaAxis;       // Eta axis 
   Double_t fMaxE;          // Maximum energy loss to consider 
   Int_t    fNEbins;        // Number of energy loss bins 
   Bool_t   fUseIncreasingBins; // Wheter to use increasing bin sizes 
   Double_t fMaxRelParError;// Relative error cut
   Double_t fMaxChi2PerNDF; // chi^2/nu cit
+  Double_t fMinWeight;     // Minimum weight value 
   Int_t    fDebug;         // Debug level 
+  
 
   ClassDef(AliFMDEnergyFitter,1); //
 };
diff --git a/PWG2/FORWARD/analysis2/AliFMDEnergyFitterTask.cxx b/PWG2/FORWARD/analysis2/AliFMDEnergyFitterTask.cxx
new file mode 100644 (file)
index 0000000..c8905a8
--- /dev/null
@@ -0,0 +1,197 @@
+#include "AliFMDEnergyFitterTask.h"
+#include "AliLog.h"
+// #include "AliFMDAnaParameters.h"
+#include "AliESDEvent.h"
+#include "AliAODForwardMult.h"
+#include "AliForwardCorrectionManager.h"
+#include "AliAnalysisManager.h"
+#include <TH1.h>
+#include <TDirectory.h>
+#include <TTree.h>
+
+//====================================================================
+AliFMDEnergyFitterTask::AliFMDEnergyFitterTask()
+  : AliAnalysisTaskSE(),
+    fFirstEvent(true),
+    fEventInspector(),
+    fEnergyFitter(),
+    fList(0)
+{
+}
+
+//____________________________________________________________________
+AliFMDEnergyFitterTask::AliFMDEnergyFitterTask(const char* name)
+  : AliAnalysisTaskSE(name), 
+    fFirstEvent(true),
+    fEventInspector("event"),
+    fEnergyFitter("energy"),
+    fList(0)
+{
+  DefineOutput(1, TList::Class());
+}
+
+//____________________________________________________________________
+AliFMDEnergyFitterTask::AliFMDEnergyFitterTask(const AliFMDEnergyFitterTask& o)
+  : AliAnalysisTaskSE(o),
+    fFirstEvent(o.fFirstEvent),
+    fEventInspector(o.fEventInspector),
+    fEnergyFitter(o.fEnergyFitter),
+    fList(o.fList) 
+{
+  DefineOutput(1, TList::Class());
+}
+
+//____________________________________________________________________
+AliFMDEnergyFitterTask&
+AliFMDEnergyFitterTask::operator=(const AliFMDEnergyFitterTask& o)
+{
+  AliAnalysisTaskSE::operator=(o);
+
+  fFirstEvent        = o.fFirstEvent;
+  fEventInspector    = o.fEventInspector;
+  fEnergyFitter      = o.fEnergyFitter;
+  fList              = o.fList;
+
+  return *this;
+}
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitterTask::SetDebug(Int_t dbg)
+{
+  fEventInspector.SetDebug(dbg);
+  fEnergyFitter.SetDebug(dbg);
+}
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitterTask::Init()
+{
+  fFirstEvent = true;
+}
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitterTask::InitializeSubs()
+{
+
+  // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  // pars->Init(kTRUE);
+
+  AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
+  fcm.Init(fEventInspector.GetCollisionSystem(), 
+          fEventInspector.GetEnergy(),
+          fEventInspector.GetField(), 0);
+  TAxis eAxis(0,0,0);
+  TAxis vAxis(10,-10,10);
+  fEnergyFitter.Init(eAxis);
+  fEventInspector.Init(vAxis);
+}
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitterTask::UserCreateOutputObjects()
+{
+  fList = new TList;
+
+  fEventInspector.DefineOutput(fList);
+  fEnergyFitter.DefineOutput(fList);
+
+  PostData(1, fList);
+}
+//____________________________________________________________________
+void
+AliFMDEnergyFitterTask::UserExec(Option_t*)
+{
+  // static Int_t cnt = 0;
+  // cnt++;
+  // Get the input data 
+  AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());
+  // AliInfo(Form("Event # %6d (esd=%p)", cnt, esd));
+  if (!esd) { 
+    AliWarning("No ESD event found for input event");
+    return;
+  }
+
+  // On the first event, initialize the parameters 
+  if (fFirstEvent && esd->GetESDRun()) { 
+    fEventInspector.ReadRunDetails(esd);
+    
+    AliInfo(Form("Initializing with parameters from the ESD:\n"
+                "         AliESDEvent::GetBeamEnergy()   ->%f\n"
+                "         AliESDEvent::GetBeamType()     ->%s\n"
+                "         AliESDEvent::GetCurrentL3()    ->%f\n"
+                "         AliESDEvent::GetMagneticField()->%f\n"
+                "         AliESDEvent::GetRunNumber()    ->%d\n",
+                esd->GetBeamEnergy(), 
+                esd->GetBeamType(),
+                esd->GetCurrentL3(), 
+                esd->GetMagneticField(),
+                esd->GetRunNumber()));
+
+             
+
+    // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+    // pars->SetParametersFromESD(esd);
+    // pars->PrintStatus();
+    fFirstEvent = false;
+
+    InitializeSubs();
+  }
+  Bool_t   lowFlux  = kFALSE;
+  UInt_t   triggers = 0;
+  UShort_t ivz      = 0;
+  Double_t vz       = 0;
+  UInt_t   found    = fEventInspector.Process(esd, triggers, lowFlux, ivz, vz);
+  if (found & AliFMDEventInspector::kNoEvent)    return;
+  if (found & AliFMDEventInspector::kNoTriggers) return;
+  if (found & AliFMDEventInspector::kNoSPD)     return;
+  if (found & AliFMDEventInspector::kNoFMD)     return;
+  if (found & AliFMDEventInspector::kNoVertex)  return;
+  if (found & AliFMDEventInspector::kBadVertex) return;
+
+  // Get FMD data 
+  AliESDFMD* esdFMD = esd->GetFMDData();
+  // Do the energy stuff 
+  if (!fEnergyFitter.Accumulate(*esdFMD, triggers & AliAODForwardMult::kEmpty)){
+    AliWarning("Energy fitter failed");
+    return;
+  }
+  PostData(1, fList);
+}
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitterTask::Terminate(Option_t*)
+{
+  TList* list = dynamic_cast<TList*>(GetOutputData(1));
+  if (!list) {
+    AliError(Form("No output list defined (%p)", GetOutputData(1)));
+    if (GetOutputData(1)) GetOutputData(1)->Print();
+    return;
+  }
+  
+  // Get our histograms from the container 
+  TH1I* hEventsTr    = 0;//static_cast<TH1I*>(list->FindObject("nEventsTr"));
+  TH1I* hEventsTrVtx = 0;//static_cast<TH1I*>(list->FindObject("nEventsTrVtx"));
+  TH1I* hTriggers    = 0;
+  if (!fEventInspector.FetchHistograms(list, hEventsTr, 
+                                      hEventsTrVtx, hTriggers)) { 
+    AliError(Form("Didn't get histograms from event selector "
+                 "(hEventsTr=%p,hEventsTrVtx=%p)", 
+                 hEventsTr, hEventsTrVtx));
+    list->ls();
+    return;
+  }
+  fEnergyFitter.Fit(list);
+}
+
+//____________________________________________________________________
+void
+AliFMDEnergyFitterTask::Print(Option_t*) const
+{
+}
+
+//
+// EOF
+//
diff --git a/PWG2/FORWARD/analysis2/AliFMDEnergyFitterTask.h b/PWG2/FORWARD/analysis2/AliFMDEnergyFitterTask.h
new file mode 100644 (file)
index 0000000..6caef7d
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef ALIROOT_PWG2_FORWARD_ALIFMDENERGYFITTERTASK_H
+#define ALIROOT_PWG2_FORWARD_ALIFMDENERGYFITTERTASK_H
+#include <AliAnalysisTaskSE.h>
+#include "AliForwardUtil.h"
+#include "AliFMDEventInspector.h"
+#include "AliFMDEnergyFitter.h"
+#include <AliESDFMD.h>
+#include <TH1I.h>
+class AliESDEvent;
+class TH2D;
+class TList;
+class TTree;
+
+
+/** 
+ * @mainpage ALICE PWG2 Forward Multiplcity Analysis 
+ */
+/** 
+ * @defgroup pwg2_forward_analysis PWG2 Forward analysis
+ *
+ * Code to do the multiplicity analysis in the forward psuedo-rapidity
+ * regions
+ *
+ */
+/** 
+ * Histogram and fit the energy loss distributions for the FMD
+ * 
+ * @par Inputs: 
+ *   - AliESDEvent 
+ *
+ * @par Outputs: 
+ *   - None
+ * 
+ * @par Histograms 
+ *   
+ * @par Corrections used 
+ *   - None
+ * 
+ * @ingroup pwg2_forward_analysis 
+ * 
+ */
+class AliFMDEnergyFitterTask : public AliAnalysisTaskSE
+{
+public:
+  /** 
+   * Constructor 
+   * 
+   * @param name Name of task 
+   */
+  AliFMDEnergyFitterTask(const char* name);
+  /** 
+   * Constructor
+   */
+  AliFMDEnergyFitterTask();
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliFMDEnergyFitterTask(const AliFMDEnergyFitterTask& o);
+  /** 
+   * Assignment operator 
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object 
+   */
+  AliFMDEnergyFitterTask& operator=(const AliFMDEnergyFitterTask& o);
+  /** 
+   * @{ 
+   * @name Interface methods 
+   */
+  /** 
+   * Initialize the task 
+   * 
+   */
+  virtual void Init();
+  /** 
+   * Create output objects 
+   * 
+   */
+  virtual void UserCreateOutputObjects();
+  /** 
+   * Process each event 
+   *
+   * @param option Not used
+   */  
+  virtual void UserExec(Option_t* option);
+  /** 
+   * End of job
+   * 
+   * @param option Not used 
+   */
+  virtual void Terminate(Option_t* option);
+  /** 
+   * @} 
+   */
+  /** 
+   * Print information 
+   * 
+   * @param option Not used
+   */
+  void Print(Option_t* option="") const;
+  /** 
+   * @{ 
+   * @name Access to sub-algorithms 
+   */
+  /**
+   * Get reference to the EventInspector algorithm 
+   * 
+   * @return Reference to AliFMDEventInspector object 
+   */
+  AliFMDEventInspector& GetEventInspector() { return fEventInspector; }
+  /**
+   * Get reference to the EnergyFitter algorithm 
+   * 
+   * @return Reference to AliFMDEnergyFitter object 
+   */
+  AliFMDEnergyFitter& GetEnergyFitter() { return fEnergyFitter; }
+  /** 
+   * @} 
+   */
+  void SetDebug(Int_t dbg);
+protected: 
+  /** 
+   * Initialise the sub objects and stuff.  Called on first event 
+   * 
+   */
+  virtual void   InitializeSubs();
+
+  Bool_t               fFirstEvent;     // Whether the event is the first seen 
+  AliFMDEventInspector fEventInspector; // Algorithm
+  AliFMDEnergyFitter   fEnergyFitter;   // Algorithm
+  TList*               fList;           // Output list 
+
+  ClassDef(AliFMDEnergyFitterTask,1) // Forward multiplicity class
+};
+
+#endif
+// Local Variables:
+//  mode: C++
+// End:
+
index 28744e4..d457bbc 100644 (file)
@@ -7,9 +7,13 @@
 #include "AliTriggerAnalysis.h"
 #include "AliPhysicsSelection.h"
 #include "AliAODForwardMult.h"
+#include "AliForwardUtil.h"
 #include <TH1.h>
 #include <TList.h>
 #include <TDirectory.h>
+#include <TROOT.h>
+#include <iostream>
+#include <iomanip>
 
 //====================================================================
 AliFMDEventInspector::AliFMDEventInspector()
@@ -17,9 +21,13 @@ AliFMDEventInspector::AliFMDEventInspector()
     fHEventsTr(0), 
     fHEventsTrVtx(0),
     fHTriggers(0),
+    fHType(0),
     fLowFluxCut(1000),
     fMaxVzErr(0.1),
     fList(0),
+    fEnergy(0),
+    fField(999), 
+    fCollisionSystem(kUnknown),
     fDebug(0)
 {
 }
@@ -30,9 +38,13 @@ AliFMDEventInspector::AliFMDEventInspector(const char* name)
     fHEventsTr(0), 
     fHEventsTrVtx(0), 
     fHTriggers(0),
+    fHType(0),
     fLowFluxCut(1000),
     fMaxVzErr(0.1),
     fList(0),
+    fEnergy(0),
+    fField(999), 
+    fCollisionSystem(kUnknown),
     fDebug(0)
 {
 }
@@ -43,9 +55,13 @@ AliFMDEventInspector::AliFMDEventInspector(const AliFMDEventInspector& o)
     fHEventsTr(o.fHEventsTr), 
     fHEventsTrVtx(o.fHEventsTrVtx), 
     fHTriggers(o.fHTriggers),
+    fHType(o.fHType),
     fLowFluxCut(o.fMaxVzErr),
     fMaxVzErr(o.fMaxVzErr),
     fList(o.fList),
+    fEnergy(o.fEnergy),
+    fField(o.fField), 
+    fCollisionSystem(o.fCollisionSystem),
     fDebug(0)
 {
 }
@@ -56,6 +72,7 @@ AliFMDEventInspector::~AliFMDEventInspector()
   if (fHEventsTr)    delete fHEventsTr;
   if (fHEventsTrVtx) delete fHEventsTrVtx;
   if (fHTriggers)    delete fHTriggers;  
+  if (fHType)        delete fHType;
   if (fList)         delete fList;
 }
 //____________________________________________________________________
@@ -66,15 +83,20 @@ AliFMDEventInspector::operator=(const AliFMDEventInspector& o)
   fHEventsTr         = o.fHEventsTr;
   fHEventsTrVtx      = o.fHEventsTrVtx;
   fHTriggers         = o.fHTriggers;
+  fHType             = o.fHType;
   fLowFluxCut        = o.fLowFluxCut;
   fMaxVzErr          = o.fMaxVzErr;
   fDebug             = o.fDebug;
   fList              = (o.fList ? new TList : 0);
+  fEnergy            = o.fEnergy;
+  fField             = o.fField;
+  fCollisionSystem   = o.fCollisionSystem;
   if (fList) { 
     fList->SetName(GetName());
     if (fHEventsTr)    fList->Add(fHEventsTr);
     if (fHEventsTrVtx) fList->Add(fHEventsTrVtx);
     if (fHTriggers)    fList->Add(fHTriggers);
+    if (fHType)        fList->Add(fHType);
   }
   return *this;
 }
@@ -145,6 +167,17 @@ AliFMDEventInspector::Init(const TAxis& vtxAxis)
   fHTriggers->GetXaxis()->SetBinLabel(9,         "spare1");
   fHTriggers->GetXaxis()->SetBinLabel(10,        "spare2");
   fList->Add(fHTriggers);
+
+  fHType = new TH1I("type", Form("Event type (cut: SPD mult>%d)", 
+                                fLowFluxCut), 2, -.5, 1.5);
+  fHType->SetFillColor(kRed+1);
+  fHType->SetFillStyle(3001);
+  fHType->SetStats(0);
+  fHType->SetDirectory(0);
+  fHType->GetXaxis()->SetBinLabel(1,"Low-flux");
+  fHType->GetXaxis()->SetBinLabel(2,"High-flux");
+  fList->Add(fHType);
+  
 }
 
 //____________________________________________________________________
@@ -161,7 +194,7 @@ UInt_t
 AliFMDEventInspector::Process(const AliESDEvent* event, 
                              UInt_t&            triggers,
                              Bool_t&            lowFlux,
-                             Int_t&             ivz, 
+                             UShort_t&          ivz, 
                              Double_t&          vz)
 {
   // Check that we have an event 
@@ -172,24 +205,26 @@ AliFMDEventInspector::Process(const AliESDEvent* event,
 
   // Read trigger information from the ESD and store in AOD object
   if (!ReadTriggers(event, triggers)) { 
-    if (fDebug > 2) 
-      AliWarning("Failed to read triggers from ESD");
+    if (fDebug > 2) {
+      AliWarning("Failed to read triggers from ESD"); }
     return kNoTriggers;
   }
 
   // Check if this is a high-flux event 
   const AliMultiplicity* testmult = event->GetMultiplicity();
   if (!testmult) {
-    if (fDebug > 3) 
-      AliWarning("No central multiplicity object found");
+    if (fDebug > 3) {
+      AliWarning("No central multiplicity object found"); }
     return kNoSPD;
   }
   lowFlux = testmult->GetNumberOfTracklets() < fLowFluxCut;
+  
+  fHType->Fill(lowFlux ? 0 : 1);
 
   // Check the FMD ESD data 
   if (!event->GetFMDData()) { 
-    if (fDebug > 3) 
-      AliWarning("No FMD data found in ESD");
+    if (fDebug > 3) {
+      AliWarning("No FMD data found in ESD"); }
     return kNoFMD;
   }
 
@@ -199,20 +234,20 @@ AliFMDEventInspector::Process(const AliESDEvent* event,
 
   fHEventsTr->Fill(vz);
   if (!vzOk) { 
-    if (fDebug > 3) 
-      AliWarning("Failed to read vertex from ESD");
+    if (fDebug > 3) {
+      AliWarning("Failed to read vertex from ESD"); }
     return kNoVertex;
   }
   fHEventsTrVtx->Fill(vz);
 
   // Get the vertex bin 
-  ivz = fHEventsTr->GetXaxis()->FindBin(vz)-1;
-  if (ivz < 0 || ivz >= fHEventsTr->GetXaxis()->GetNbins()) { 
-    if (fDebug > 3) 
+  ivz = fHEventsTr->GetXaxis()->FindBin(vz);
+  if (ivz <= 0 || ivz > fHEventsTr->GetXaxis()->GetNbins()) { 
+    if (fDebug > 3) {
       AliWarning(Form("Vertex @ %f outside of range [%f,%f]", 
                      vz, fHEventsTr->GetXaxis()->GetXmin(), 
-                     fHEventsTr->GetXaxis()->GetXmax()));
-    ivz = -1;
+                     fHEventsTr->GetXaxis()->GetXmax())); }
+    ivz = 0;
     return kBadVertex;
   }
   return kOk;
@@ -318,25 +353,25 @@ AliFMDEventInspector::ReadVertex(const AliESDEvent* esd, Double_t& vz)
   // Get the vertex 
   const AliESDVertex* vertex = esd->GetPrimaryVertexSPD();
   if (!vertex) { 
-    if (fDebug > 2) 
-      AliWarning("No SPD vertex found in ESD");
+    if (fDebug > 2) {
+      AliWarning("No SPD vertex found in ESD"); }
     return kFALSE;
   }
   
   // Check that enough tracklets contributed 
   if(vertex->GetNContributors() <= 0) {
-    if (fDebug > 2)
+    if (fDebug > 2) {
       AliWarning(Form("Number of contributors to vertex is %d<=0",
-                     vertex->GetNContributors()));
+                     vertex->GetNContributors())); }
     vz = 0;
     return kFALSE;
   }
 
   // Check that the uncertainty isn't too large 
   if (vertex->GetZRes() > fMaxVzErr) { 
-    if (fDebug > 2)
+    if (fDebug > 2) {
       AliWarning(Form("Uncertaintity in Z of vertex is too large %f > %f", 
-                     vertex->GetZRes(), fMaxVzErr));
+                     vertex->GetZRes(), fMaxVzErr)); }
     return kFALSE;
   }
 
@@ -344,6 +379,52 @@ AliFMDEventInspector::ReadVertex(const AliESDEvent* esd, Double_t& vz)
   vz = vertex->GetZ();
   return kTRUE;
 }
+
+//____________________________________________________________________
+Bool_t
+AliFMDEventInspector::ReadRunDetails(const AliESDEvent* esd)
+{
+  fCollisionSystem = 
+    AliForwardUtil::ParseCollisionSystem(esd->GetBeamType());
+  fEnergy          = 
+    AliForwardUtil::ParseCenterOfMassEnergy(fCollisionSystem,  
+                                             2 * esd->GetBeamEnergy());
+  fField           = 
+    AliForwardUtil::ParseMagneticField(esd->GetMagneticField());
+  
+  if (fCollisionSystem   == AliForwardUtil::kUnknown || 
+      fEnergy            <= 0                        || 
+      TMath::Abs(fField) >  10) 
+    return kFALSE;
+
+  return kTRUE;
+}
+
+//____________________________________________________________________
+void
+AliFMDEventInspector::Print(Option_t*) const
+{
+  char ind[gROOT->GetDirLevel()+1];
+  for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
+  ind[gROOT->GetDirLevel()] = '\0';
+  TString sNN(AliForwardUtil::CenterOfMassEnergyString(fEnergy));
+  sNN.Strip(TString::kBoth, '0');
+  sNN.ReplaceAll("GeV", " GeV");
+  TString field(AliForwardUtil::MagneticFieldString(fField));
+  field.ReplaceAll("p",  "+");
+  field.ReplaceAll("m",  "-");
+  field.ReplaceAll("kG", " kG");
+  
+  std::cout << ind << "AliFMDEventInspector: " << GetName() << '\n'
+           << ind << " Low flux cut:           " << fLowFluxCut << '\n'
+           << ind << " Max(delta v_z):         " << fMaxVzErr << " cm\n"
+           << ind << " System:                 " 
+           << AliForwardUtil::CollisionSystemString(fCollisionSystem) << '\n'
+           << ind << " CMS energy per nucleon: " << sNN << '\n'
+           << ind << " Field:                  " <<  field << std::endl;
+}
+
+  
 //
 // EOF
 //
index a2fce6f..1dddd3e 100644 (file)
@@ -62,6 +62,14 @@ public:
     kE
   };
   /** 
+   * Collision systems
+   */
+  enum ECollisionSystem { 
+    kUnknown,
+    kPP, 
+    kPbPb
+  };
+  /** 
    * Constructor 
    */
   AliFMDEventInspector();
@@ -100,10 +108,12 @@ public:
    * Process the event 
    * 
    * @param event     Input event 
+   * @param first     True on first event
    * @param triggers  On return, the triggers fired 
    * @param lowFlux   On return, true if the event is considered a low-flux 
    *                  event (according to the setting of fLowFluxCut) 
-   * @param ivz       On return, the found vertex bin (zero-based)
+   * @param ivz       On return, the found vertex bin (1-based).  A zero
+   *                  means outside of the defined vertex range
    * @param vz        On return, the z position of the interaction
    * 
    * @return 0 (or kOk) on success, otherwise a bit mask of error codes 
@@ -111,7 +121,7 @@ public:
   UInt_t Process(const AliESDEvent* event, 
                 UInt_t&            triggers,
                 Bool_t&            lowFlux,
-                Int_t&             ivz, 
+                UShort_t&          ivz, 
                 Double_t&          vz);
   /** 
    * Define the output histograms.  These are put in a sub list of the
@@ -154,6 +164,39 @@ public:
                         TH1I*& hEventsTr, 
                         TH1I*& hEventsTrVtx, 
                         TH1I*& hTriggers) const;
+  /** 
+   * Read the collision system, collision energy, and L3 field setting
+   * from the ESD
+   * 
+   * @param esd ESD to get information from 
+   * 
+   * @return true on success, false 
+   */
+  Bool_t ReadRunDetails(const AliESDEvent* esd);
+  /** 
+   * Get the collision system (one of the value in ECollisionSystem)
+   * 
+   * @return Collision system 
+   */
+  UShort_t GetCollisionSystem() const { return fCollisionSystem; }
+  /** 
+   * Get the center of mass energy (per nucleon pair) in GeV 
+   * 
+   * @return center of mass energy (per nucleon pair) in GeV 
+   */
+  UShort_t GetEnergy() const { return fEnergy; }
+  /** 
+   * Get the magnetic field setting of the L3 magnet in kilo Gauss. 
+   * 
+   * @return The magnetic field setting 
+   */
+  Short_t  GetField() const { return fField; }
+  /** 
+   * Print information
+   * 
+   * @param option Not used 
+   */
+  void Print(Option_t* option="") const;
 protected:
   /** 
    * Read the trigger information from the ESD event 
@@ -177,9 +220,13 @@ protected:
   TH1I*    fHEventsTr;    //! Histogram of events w/trigger
   TH1I*    fHEventsTrVtx; //! Events w/trigger and vertex 
   TH1I*    fHTriggers;    //! Triggers
+  TH1I*    fHType;        //! Type (low/high flux) of event
   Int_t    fLowFluxCut;   //  Low flux cut
   Double_t fMaxVzErr;     //  Maximum error on v_z
   TList*   fList;         //! Histogram container 
+  UShort_t fEnergy;       // CMS energy (per nucleon pair) [GeV]
+  Short_t  fField;        // L3 magnetic field [kG]
+  UShort_t fCollisionSystem; //  
   Int_t    fDebug;        //  Debug level 
   ClassDef(AliFMDEventInspector,1); // Inspect the event 
 };
index 13840f5..43d7e79 100644 (file)
@@ -1,16 +1,20 @@
-
+// Calculate the total energy loss 
 #include "AliFMDHistCollector.h"
 #include <AliESDFMD.h>
 #include <TAxis.h>
 #include <TList.h>
 #include <TMath.h>
-#include "AliFMDAnaParameters.h"
+// #include "AliFMDAnaParameters.h"
+#include "AliForwardCorrectionManager.h"
 #include "AliLog.h"
 #include <TH2D.h>
 #include <TH1I.h>
 #include <TProfile.h>
 #include <TProfile2D.h>
 #include <TArrayI.h>
+#include <TROOT.h>
+#include <iostream>
+#include <iomanip>
 
 ClassImp(AliFMDHistCollector)
 #if 0
@@ -37,14 +41,15 @@ AliFMDHistCollector::operator=(const AliFMDHistCollector& o)
 void
 AliFMDHistCollector::Init(const TAxis& vtxAxis)
 {
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
 
-  Int_t nVz = vtxAxis.GetNbins();
+  UShort_t nVz = vtxAxis.GetNbins();
   fFirstBins.Set(5*nVz);
   fLastBins.Set(5*nVz);
 
   // Find the eta bin ranges 
-  for (Int_t iVz = 0; iVz < nVz; iVz++) {
+  for (UShort_t iVz = 1; iVz <= nVz; iVz++) {
     // Find the first and last eta bin to use for each ring for 
     // each vertex bin.   This is instead of using the methods 
     // provided by AliFMDAnaParameters 
@@ -54,7 +59,8 @@ AliFMDHistCollector::Init(const TAxis& vtxAxis)
       GetDetRing(iIdx, d, r);
       
       // Get the background object 
-      TH2F* bg    = pars->GetBackgroundCorrection(d,r,iVz);
+      // TH2F* bg    = pars->GetBackgroundCorrection(d,r,iVz);
+      TH2D* bg    = fcm.GetSecondaryMap()->GetCorrection(d,r,iVz);
       Int_t nEta  = bg->GetNbinsX();
       Int_t first = nEta+1;
       Int_t last  = 0;
@@ -79,8 +85,8 @@ AliFMDHistCollector::Init(const TAxis& vtxAxis)
       }
       
       // Store the result for later use 
-      fFirstBins[iVz*5+iIdx] = first;
-      fLastBins[iVz*5+iIdx]  = last;
+      fFirstBins[(iVz-1)*5+iIdx] = first;
+      fLastBins[(iVz-1)*5+iIdx]  = last;
     } // for j 
   }
 }
@@ -114,14 +120,15 @@ AliFMDHistCollector::GetDetRing(Int_t idx, UShort_t& d, Char_t& r) const
 
 //____________________________________________________________________
 void
-AliFMDHistCollector::GetFirstAndLast(Int_t idx, Int_t vtxbin, 
+AliFMDHistCollector::GetFirstAndLast(Int_t idx, UShort_t vtxbin, 
                                     Int_t& first, Int_t& last) const
 {
   first = 0; 
   last  = 0;
   
-  if (idx < 0) return;
-  idx += vtxbin * 5;
+  if (idx    <  0) return;
+  if (vtxbin <= 0) return;
+  idx += (vtxbin-1) * 5;
       
   if (idx < 0 || idx >= fFirstBins.GetSize()) return;
   
@@ -131,7 +138,7 @@ AliFMDHistCollector::GetFirstAndLast(Int_t idx, Int_t vtxbin,
 
 //____________________________________________________________________
 Int_t
-AliFMDHistCollector::GetFirst(Int_t idx, Int_t v) const 
+AliFMDHistCollector::GetFirst(Int_t idx, UShort_t v) const 
 {
   Int_t f, l;
   GetFirstAndLast(idx,v,f,l);
@@ -141,7 +148,7 @@ AliFMDHistCollector::GetFirst(Int_t idx, Int_t v) const
 
 //____________________________________________________________________
 Int_t
-AliFMDHistCollector::GetLast(Int_t idx, Int_t v) const 
+AliFMDHistCollector::GetLast(Int_t idx, UShort_t v) const 
 {
   Int_t f, l;
   GetFirstAndLast(idx,v,f,l);
@@ -151,7 +158,7 @@ AliFMDHistCollector::GetLast(Int_t idx, Int_t v) const
 //____________________________________________________________________
 Int_t 
 AliFMDHistCollector::GetOverlap(UShort_t d, Char_t r, 
-                               Int_t bin, Int_t vtxbin) const
+                               Int_t bin,  UShort_t vtxbin) const
 {
   // Get the possibly overlapping histogram 
   Int_t other = -1;
@@ -176,7 +183,7 @@ AliFMDHistCollector::GetOverlap(UShort_t d, Char_t r,
 }
 //____________________________________________________________________
 Int_t
-AliFMDHistCollector::GetOverlap(Int_t idx, Int_t bin, Int_t vtxbin) const
+AliFMDHistCollector::GetOverlap(Int_t idx, Int_t bin, UShort_t vtxbin) const
 {
   UShort_t d = 0; 
   Char_t   r = '\0';
@@ -190,7 +197,7 @@ AliFMDHistCollector::GetOverlap(Int_t idx, Int_t bin, Int_t vtxbin) const
 //____________________________________________________________________
 Bool_t
 AliFMDHistCollector::Collect(AliForwardUtil::Histos& hists,
-                            Int_t                   vtxbin, 
+                            UShort_t                vtxbin, 
                             TH2D&                   out)
 {
   for (UShort_t d=1; d<=3; d++) { 
@@ -323,6 +330,40 @@ AliFMDHistCollector::Collect(AliForwardUtil::Histos& hists,
   return kTRUE;
 }
 
+//____________________________________________________________________
+void
+AliFMDHistCollector::Print(Option_t* /* option */) const
+{
+  char ind[gROOT->GetDirLevel()+1];
+  for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
+  ind[gROOT->GetDirLevel()] = '\0';
+  std::cout << ind << "AliFMDHistCollector: " << GetName() << '\n'
+           << ind << " # of cut bins:          " << fNCutBins << '\n'
+           << ind << " Correction cut:         " << fCorrectionCut << '\n'
+           << ind << " Bin ranges:\n" << ind << "  v_z bin";
+  Int_t nVz = fFirstBins.fN / 5;
+  for (UShort_t iVz = 1; iVz <= nVz; iVz++) 
+    std::cout << " | " << std::setw(7) << iVz;
+  std::cout << '\n' << ind << "  / ring ";
+  for (UShort_t iVz = 1; iVz <= nVz; iVz++) 
+    std::cout << "-+--------";
+  std::cout << std::endl;
+    
+  for (Int_t iIdx = 0; iIdx < 5; iIdx++) {
+    UShort_t d = 0;
+    Char_t   r = 0;
+    GetDetRing(iIdx, d, r);
+    
+    std::cout << ind << "  FMD" << d << r << "  ";
+    for (UShort_t iVz = 1; iVz <= nVz; iVz++) {
+      Int_t first, last;
+      GetFirstAndLast(iIdx, iVz, first, last);
+      std::cout << " | " << std::setw(3) << first << "-" 
+               << std::setw(3) << last;
+    }
+    std::cout << std::endl;
+  }
+}
 
 //____________________________________________________________________
 //
index ad2c3b6..4dc7a24 100644 (file)
@@ -73,12 +73,12 @@ public:
    * Do the calculations 
    * 
    * @param hists    Cache of histograms 
-   * @param vtxBin   Vertex bin 
+   * @param vtxBin   Vertex bin (1 based)
    * @param out      Output histogram
    * 
    * @return true on successs 
    */
-  virtual Bool_t Collect(AliForwardUtil::Histos& hists, Int_t vtxBin, 
+  virtual Bool_t Collect(AliForwardUtil::Histos& hists, UShort_t vtxBin, 
                         TH2D& out);
   /** 
    * Set the number of extra bins (beyond the secondary map border) 
@@ -101,66 +101,72 @@ public:
    * @param dbg Debug level 
    */
   void SetDebug(Int_t dbg=1) { fDebug = dbg; }
+  /** 
+   * Print information 
+   * 
+   * @param option Not used
+   */
+  void Print(Option_t* option="") const;
 protected:
   /** 
    * Get the first and last eta bin to use for a given ring and vertex 
    * 
    * @param d        Detector
    * @param r        Ring 
-   * @param vtxBin   Vertex bin 
+   * @param vtxBin   Vertex bin (1 based)
    * @param first    On return, the first eta bin to use 
    * @param last     On return, the last eta bin to use 
    */
-  virtual void GetFirstAndLast(UShort_t d, Char_t r, Int_t vtxBin, 
+  virtual void GetFirstAndLast(UShort_t d, Char_t r, UShort_t vtxBin, 
                               Int_t& first, Int_t& last) const;
   /** 
    * Get the first and last eta bin to use for a given ring and vertex 
    * 
    * @param idx      Ring index as given by GetIdx
-   * @param vtxBin   Vertex bin 
+   * @param vtxBin   Vertex bin (1 based) 
    * @param first    On return, the first eta bin to use 
    * @param last     On return, the last eta bin to use 
    */
-  virtual void GetFirstAndLast(Int_t idx, Int_t vtxBin, 
+  virtual void GetFirstAndLast(Int_t idx, UShort_t vtxBin, 
                               Int_t& first, Int_t& last) const;
   /** 
    * Get the first eta bin to use for a given ring and vertex 
    * 
    * @param d Detector 
    * @param r Ring 
-   * @param v vertex bin
+   * @param v vertex bin (1 based)
    * 
    * @return First eta bin to use, or -1 in case of problems 
    */  
-  Int_t GetFirst(UShort_t d, Char_t r, Int_t v) const; 
+  Int_t GetFirst(UShort_t d, Char_t r, UShort_t v) const; 
   /** 
    * Get the first eta bin to use for a given ring and vertex 
    * 
    * @param idx Ring index as given by GetIdx
-   * @param v vertex bin
+   * @param v vertex bin (1 based)
    * 
    * @return First eta bin to use, or -1 in case of problems 
    */  
-  Int_t GetFirst(Int_t idx, Int_t v) const; 
+  Int_t GetFirst(Int_t idx, UShort_t v) const; 
   /** 
    * Get the last eta bin to use for a given ring and vertex 
    * 
    * @param d Detector 
    * @param r Ring 
-   * @param v vertex bin
+   * @param v vertex bin (1 based)
    * 
    * @return Last eta bin to use, or -1 in case of problems 
    */  
-  Int_t GetLast(UShort_t d, Char_t r, Int_t v) const;
+  Int_t GetLast(UShort_t d, Char_t r, UShort_t v) const;
   /** 
    * Get the last eta bin to use for a given ring and vertex 
    * 
    * @param idx Ring index as given by GetIdx
-   * @param v vertex bin
+   * @param v vertex bin (1 based)
    * 
    * @return Last eta bin to use, or -1 in case of problems 
    */  
-  Int_t GetLast(Int_t idx, Int_t v) const; 
+  Int_t GetLast(Int_t idx, UShort_t v) const; 
   /** 
    * Get the detector and ring from the ring index 
    * 
@@ -185,22 +191,22 @@ protected:
    * @param d Detector
    * @param r Ring 
    * @param e Eta bin
-   * @param v Vertex bin
+   * @param v Vertex bin (1 based)
    *
    * @return Overlapping histogram index or -1
    */
-  Int_t GetOverlap(UShort_t d, Char_t r, Int_t e, Int_t v) const;
+  Int_t GetOverlap(UShort_t d, Char_t r, Int_t e, UShort_t v) const;
   /** 
    * Get the possibly overlapping histogram of eta bin @a e in 
    * detector and ring 
    * 
    * @param i Ring index
    * @param e Eta bin
-   * @param v Vertex bin
+   * @param v Vertex bin (1 based)
    *
    * @return Overlapping histogram index or -1
    */
-  Int_t GetOverlap(Int_t i, Int_t e, Int_t v) const;
+  Int_t GetOverlap(Int_t i, Int_t e, UShort_t v) const;
   /** 
    * Check if there's an overlapping histogram with this eta bin of
    * the detector and ring
@@ -208,11 +214,11 @@ protected:
    * @param d Detector 
    * @param r Ring 
    * @param e eta bin
-   * @param v Vertex bin
+   * @param v Vertex bin (1 based)
    * 
    * @return True if there's an overlapping histogram 
    */
-  Bool_t HasOverlap(UShort_t d, Char_t r, Int_t e, Int_t v) const;
+  Bool_t HasOverlap(UShort_t d, Char_t r, Int_t e, UShort_t v) const;
   /** 
    * Check if there's an overlapping histogram with this eta bin of
    * ring
@@ -223,7 +229,7 @@ protected:
    * 
    * @return True if there's an overlapping histogram 
    */
-  Bool_t HasOverlap(Int_t i, Int_t e, Int_t v) const;
+  Bool_t HasOverlap(Int_t i, Int_t e, UShort_t v) const;
 
 
   Int_t       fNCutBins;        // Number of additional bins to cut away
@@ -237,32 +243,32 @@ protected:
 
 //____________________________________________________________________
 inline void
-AliFMDHistCollector::GetFirstAndLast(UShort_t d, Char_t r, Int_t vtxbin, 
+AliFMDHistCollector::GetFirstAndLast(UShort_t d, Char_t r, UShort_t vtxbin, 
                                     Int_t& first, Int_t& last) const
 {
   GetFirstAndLast(GetIdx(d,r), vtxbin, first, last);
 }
 //____________________________________________________________________
 inline Int_t
-AliFMDHistCollector::GetFirst(UShort_t d, Char_t r, Int_t v) const 
+AliFMDHistCollector::GetFirst(UShort_t d, Char_t r, UShort_t v) const 
 {
   return GetFirst(GetIdx(d,r), v);
 }
 //____________________________________________________________________
 inline Int_t
-AliFMDHistCollector::GetLast(UShort_t d, Char_t r, Int_t v) const 
+AliFMDHistCollector::GetLast(UShort_t d, Char_t r, UShort_t v) const 
 {
   return GetLast(GetIdx(d, r), v);
 }
 //____________________________________________________________________
 inline Bool_t
-AliFMDHistCollector::HasOverlap(UShort_t d, Char_t r, Int_t e, Int_t v) const
+AliFMDHistCollector::HasOverlap(UShort_t d, Char_t r, Int_t e, UShort_t v) const
 {
   return GetOverlap(d,r,e,v) >= 0;
 }
 //____________________________________________________________________
 inline Bool_t
-AliFMDHistCollector::HasOverlap(Int_t i, Int_t e, Int_t v) const
+AliFMDHistCollector::HasOverlap(Int_t i, Int_t e, UShort_t v) const
 {
   return GetOverlap(i,e,v) >= 0;
 }
diff --git a/PWG2/FORWARD/analysis2/AliFMDMCDensityCalculator.cxx b/PWG2/FORWARD/analysis2/AliFMDMCDensityCalculator.cxx
new file mode 100644 (file)
index 0000000..7810d52
--- /dev/null
@@ -0,0 +1,96 @@
+#include "AliFMDMCDensityCalculator.h"
+#include <TMath.h>
+#include "AliForwardCorrectionManager.h"
+#include "AliFMDStripIndex.h"
+#include "AliMCEvent.h"
+// #include "AliFMDAnaParameters.h"
+#include "AliLog.h"
+#include <TH2D.h>
+
+ClassImp(AliFMDMCDensityCalculator)
+#if 0
+; // For Emacs
+#endif 
+
+
+//____________________________________________________________________
+AliFMDMCDensityCalculator&
+AliFMDMCDensityCalculator::operator=(const AliFMDMCDensityCalculator& o)
+{
+  AliFMDDensityCalculator::operator=(o);
+  return *this;
+}
+
+    
+//____________________________________________________________________
+Bool_t
+AliFMDMCDensityCalculator::CalculateMC(const AliMCEvent&       event,
+                                      AliForwardUtil::Histos& hists,
+                                      Double_t                vz,
+                                      UShort_t                vtxbin)
+{
+  Int_t nTracks = event.GetNumberOfTracks();
+  for (Int_t iTr = 0; iTr < nTracks; iTr++) { 
+    AliMCParticle* particle = 
+      static_cast<AliMCParticle*>(event.GetTrack(iTr));
+    
+    // Check the returned particle 
+    if (!particle) continue;
+    
+    // Check if this charged and a primary 
+    Bool_t isCharged = particle->Charge() != 0;
+    if (!isCharged) continue;
+
+    Int_t nTrRef = particle->GetNumberOfTrackReferences();
+    for (Int_t iTrRef = 0; iTrRef < nTrRef; iTrRef++) { 
+      AliTrackReference* ref = particle->GetTrackReference(iTrRef);
+      
+      // Check existence 
+      if (!ref) continue;
+
+      // Check that we hit an FMD element 
+      if (ref->DetectorId() != AliTrackReference::kFMD) 
+       continue;
+
+      // Get the detector coordinates 
+      UShort_t d, s, t;
+      Char_t r;
+      AliFMDStripIndex::Unpack(ref->UserId(), d, r, s, t);
+
+      Double_t x    = ref->X();
+      Double_t y    = ref->Y();
+      Double_t z    = ref->Z()-vz;
+      Double_t rr   = TMath::Sqrt(x*x+y*y);
+      Double_t phi  = TMath::ATan2(y,x);
+      Double_t theta= TMath::ATan2(rr,z);
+      Double_t eta  = -TMath::Log(TMath::Tan(theta/2));
+
+      Float_t  c    = Correction(d,r,s,t,vtxbin,eta,false);
+      fCorrections->Fill(c);
+      
+      TH2D*    h    = hists.Get(d,r);
+      h->Fill(eta,phi, 1 * c);
+    }
+  }
+  return kTRUE;
+}
+
+//____________________________________________________________________
+Bool_t
+AliFMDMCDensityCalculator::Calculate(const AliESDFMD&,
+                                    AliForwardUtil::Histos&,
+                                    UShort_t,
+                                    Bool_t)
+{
+  AliWarning("Method Calculate disabled for this class. If you need this, "
+            "make an AliFMDDensityCalculator object instead");
+  return kFALSE;
+}
+
+//____________________________________________________________________
+//
+// EOF
+//
+         
+
+
diff --git a/PWG2/FORWARD/analysis2/AliFMDMCDensityCalculator.h b/PWG2/FORWARD/analysis2/AliFMDMCDensityCalculator.h
new file mode 100644 (file)
index 0000000..cf50606
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef ALIROOT_PWG2_FORWARD_ANALYSIS2_ALIFMDMCDENSITYCALCULATOR_H
+#define ALIROOT_PWG2_FORWARD_ANALYSIS2_ALIFMDMCDENSITYCALCULATOR_H
+#include "AliFMDDensityCalculator.h"
+#include <TList.h>
+#include "AliForwardUtil.h"
+class AliMCEvent;
+class TH2D;
+class TH1D;
+
+/** 
+ * This class calculates the inclusive charged particle density
+ * in each for the 5 FMD rings based on the MC truth.
+ *
+ * @par Input:
+ *   - AliMCEvent  MC truth event infromation
+ *
+ * @par Output:
+ *   - None
+ *
+ * @par Corrections used: 
+ *   - None
+ *
+ * @ingroup pwg2_forward_analysis 
+ */
+class AliFMDMCDensityCalculator : public AliFMDDensityCalculator
+{
+public:
+  /** 
+   * Constructor 
+   */
+  AliFMDMCDensityCalculator() : AliFMDDensityCalculator() {}
+  /** 
+   * Constructor 
+   * 
+   * @param name Name of object
+   */
+  AliFMDMCDensityCalculator(const char* name) 
+   : AliFMDDensityCalculator(name)
+  {}
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliFMDMCDensityCalculator(const AliFMDMCDensityCalculator& o)
+   : AliFMDDensityCalculator(o) 
+  {}
+  /** 
+   * Destructor 
+   */
+  virtual ~AliFMDMCDensityCalculator() {}
+  /** 
+   * Assignement operator
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object
+   */
+  AliFMDMCDensityCalculator& operator=(const AliFMDMCDensityCalculator&);
+  /** 
+   * Do the calculations 
+   * 
+   * @param fmd      AliESDFMD object (possibly) corrected for sharing
+   * @param hists    Histogram cache
+   * @param vtxBin   Vertex bin 
+   * @param lowFlux  Low flux flag. 
+   * 
+   * @return true on successs 
+   */
+  virtual Bool_t Calculate(const AliESDFMD& fmd, 
+                          AliForwardUtil::Histos& hists, 
+                          UShort_t vtxBin, Bool_t lowFlux);
+  /** 
+   * Calculate the charged particle density from the MC track references. 
+   * 
+   * @param event  MC event
+   * @param hists  Histograms to fill
+   * @param vz     Interaction z coordinate @f$ v_z@f$
+   * @param vtxBin bin corresponding to @f$ v_z@f$
+   * 
+   * @return true on success
+   */
+  virtual Bool_t CalculateMC(const AliMCEvent& event, 
+                            AliForwardUtil::Histos& hists, 
+                            Double_t vz,
+                            UShort_t vtxBin);                       
+protected:
+
+  ClassDef(AliFMDMCDensityCalculator,1); // Calculate Nch density 
+};
+
+#endif
+// Local Variables:
+//   mode: C++
+// End:
+
index a3f07c4..ac6fc56 100644 (file)
@@ -7,8 +7,12 @@
 #include <TList.h>
 #include <TH1.h>
 #include <TMath.h>
-#include "AliFMDAnaParameters.h"
+#include "AliForwardCorrectionManager.h"
+// #include "AliFMDAnaParameters.h"
 #include <AliLog.h>
+#include <TROOT.h>
+#include <iostream>
+#include <iomanip>
 
 ClassImp(AliFMDSharingFilter)
 #if 0
@@ -20,8 +24,9 @@ ClassImp(AliFMDSharingFilter)
 AliFMDSharingFilter::AliFMDSharingFilter()
   : TNamed(), 
     fRingHistos(),
-    fLowCut(0.3),
+    fLowCut(0.),
     fCorrectAngles(kFALSE), 
+    fNXi(1),
     fDebug(0)
 {}
 
@@ -29,8 +34,9 @@ AliFMDSharingFilter::AliFMDSharingFilter()
 AliFMDSharingFilter::AliFMDSharingFilter(const char* title)
   : TNamed("fmdSharingFilter", title), 
     fRingHistos(), 
-    fLowCut(0.3),
+    fLowCut(0.),
     fCorrectAngles(kFALSE), 
+    fNXi(1),
     fDebug(0)
 {
   fRingHistos.Add(new RingHistos(1, 'I'));
@@ -46,6 +52,7 @@ AliFMDSharingFilter::AliFMDSharingFilter(const AliFMDSharingFilter& o)
     fRingHistos(), 
     fLowCut(o.fLowCut),
     fCorrectAngles(o.fCorrectAngles), 
+    fNXi(o.fNXi),
     fDebug(o.fDebug)
 {
   TIter    next(&o.fRingHistos);
@@ -67,6 +74,7 @@ AliFMDSharingFilter::operator=(const AliFMDSharingFilter& o)
 
   fLowCut        = o.fLowCut;
   fCorrectAngles = o.fCorrectAngles;
+  fNXi           = o.fNXi;
   fDebug         = o.fDebug;
 
   fRingHistos.Delete();
@@ -100,7 +108,8 @@ AliFMDSharingFilter::Filter(const AliESDFMD& input,
 {
   output.Clear();
   TIter    next(&fRingHistos);
-  RingHistos* o = 0;
+  RingHistos* o      = 0;
+  Double_t    lowCut = GetLowCut();
   while ((o = static_cast<RingHistos*>(next())))
     o->Clear();
 
@@ -151,7 +160,7 @@ AliFMDSharingFilter::Filter(const AliESDFMD& input,
          Double_t mergedEnergy = MultiplicityOfStrip(mult,eta,prevE,nextE,
                                                      lowFlux,d,r,s,t, 
                                                      usedPrev,usedThis);
-         if (mergedEnergy > fLowCut) histos->Incr();
+         if (mergedEnergy > lowCut) histos->Incr();
          histos->fAfter->Fill(mergedEnergy);
 
          output.SetMultiplicity(d,r,s,t,mergedEnergy);
@@ -185,21 +194,41 @@ AliFMDSharingFilter::SignalInStrip(const AliESDFMD& input,
     mult = DeAngleCorrect(mult, input.Eta(d,r,s,t));
   return mult;
 }
+//_____________________________________________________________________
+Double_t 
+AliFMDSharingFilter::GetLowCut() const
+{
+  if (fLowCut > 0) return fLowCut;
+  AliForwardCorrectionManager&  fcm = AliForwardCorrectionManager::Instance();
+  AliFMDCorrELossFit* fits = fcm.GetELossFit();
+  return fits->GetLowCut();
+}
                        
 //_____________________________________________________________________
 Double_t 
 AliFMDSharingFilter::GetHighCut(UShort_t d, Char_t r, Double_t eta) const
 {
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  AliForwardCorrectionManager&  fcm = AliForwardCorrectionManager::Instance();
+
  
   // Get the high cut.  The high cut is defined as the 
   // most-probably-value peak found from the energy distributions, minus 
   // 2 times the width of the corresponding Landau.
-  Double_t mpv     = pars->GetMPV(d,r,eta);
-  Double_t w       = pars->GetSigma(d,r,eta);
-  if (mpv > 100) 
-    AliWarning(Form("FMD%d%c, eta=%f, MPV=%f, W=%f", d, r, eta, mpv, w));
-  Double_t highCut = (mpv - 2 * w);
+  AliFMDCorrELossFit::ELossFit* fit = fcm.GetELossFit()->FindFit(d,r,eta);
+  Double_t delta = 1024;
+  Double_t xi    = 1024;
+  if (!fit) {
+    AliError(Form("No energy loss fit for FMD%d%c at eta=%f", d, r, eta));
+  }
+  else {
+    delta = fit->fDelta;
+    xi    = fit->fXi;
+  }
+
+  if (delta > 100) {
+    AliWarning(Form("FMD%d%c, eta=%f, Delta=%f, xi=%f", d, r, eta, delta, xi));
+  }
+  Double_t highCut = (delta - fNXi * xi);
   return highCut;
 }
           
@@ -219,7 +248,8 @@ AliFMDSharingFilter::MultiplicityOfStrip(Double_t mult,
 {
   // IF the multiplicity is very large, or below the cut, reject it, and 
   // flag it as candidate for sharing 
-  if(mult > 12 || mult < fLowCut) {
+  Double_t    lowCut = GetLowCut();
+  if(mult > 12 || mult < lowCut) {
     usedThis      = kFALSE;
     usedPrev      = kFALSE;
     return 0;
@@ -235,7 +265,7 @@ AliFMDSharingFilter::MultiplicityOfStrip(Double_t mult,
 
   //analyse and perform sharing on one strip
   
-  // Calculate the total energy loss 
+  // Get the high cut 
   Double_t highCut = GetHighCut(d, r, eta);
 
   // If this signal is smaller than the next, and the next signal is smaller 
@@ -257,7 +287,7 @@ AliFMDSharingFilter::MultiplicityOfStrip(Double_t mult,
   // If the previous signal was larger than the low cut, and 
   // the previous was smaller than high cut, and the previous signal 
   // isn't marked as used, then add it's energy to this signal 
-  if (prevE > fLowCut && 
+  if (prevE > lowCut && 
       prevE < highCut && 
       !usedPrev) 
     totalE += prevE;
@@ -265,7 +295,7 @@ AliFMDSharingFilter::MultiplicityOfStrip(Double_t mult,
   // If the next signal is larger than the low cut, and 
   // the next signal is smaller than the low cut, then add the next signal 
   // to this, and marked the next signal as used 
-  if(nextE > fLowCut && nextE < highCut ) {
+  if(nextE > lowCut && nextE < highCut ) {
     totalE      += nextE;
     usedThis =  kTRUE;
   }
@@ -341,6 +371,19 @@ AliFMDSharingFilter::DefineOutput(TList* dir)
     o->Output(d);
   }
 }
+//____________________________________________________________________
+void
+AliFMDSharingFilter::Print(Option_t* /*option*/) const
+{
+  char ind[gROOT->GetDirLevel()+1];
+  for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
+  ind[gROOT->GetDirLevel()] = '\0';
+  std::cout << ind << "AliFMDSharingFilter: " << GetName() << '\n'
+           << ind << " Low cut:                " << fLowCut << '\n'
+           << ind << " N xi factor:            " << fNXi    << '\n'
+           << ind << " Use corrected angles:   " 
+           << (fCorrectAngles ? "yes" : "no") << std::endl;
+}
   
 //====================================================================
 AliFMDSharingFilter::RingHistos::RingHistos()
index 2122102..7d8ba99 100644 (file)
@@ -70,7 +70,12 @@ public:
    * 
    * @param lowCut Low cut
    */
-  void SetLowCut(Double_t lowCut=0.3) { fLowCut = lowCut; }
+  void SetLowCut(Double_t lowCut=0) { fLowCut = lowCut; }
+  /** 
+   * Reset the low cut for sharing to use the fit range lower cut 
+   * 
+   */
+  void UnsetLowCut() { fLowCut = 0; }
   /** 
    * Set the debug level.  The higher the value the more output 
    * 
@@ -87,6 +92,13 @@ public:
    */
   void UseAngleCorrectedSignals(Bool_t use) { fCorrectAngles = use; }
   /** 
+   * Set the number of landau width to subtract from the most probably
+   * value to get the high cut for the merging algorithm.
+   * 
+   * @param n Number of @f$ \xi@f$ 
+   */
+  void SetNXi(Short_t n) { fNXi = n; }
+  /** 
    * Filter the input AliESDFMD object
    * 
    * @param input     Input 
@@ -114,6 +126,12 @@ public:
    * @param dir Directory to add to 
    */
   void DefineOutput(TList* dir);
+  /** 
+   * Print information
+   * 
+   * @param option Not used 
+   */
+  void Print(Option_t* option="") const;
 protected:
   /** 
    * Internal data structure to keep track of the histograms
@@ -259,10 +277,18 @@ protected:
    * 2 times the width of the corresponding Landau.
    */
   virtual Double_t GetHighCut(UShort_t d, Char_t r, Double_t eta) const;
+  /**
+   * Get the low cut.  Normally, the low cut is taken to be the lower
+   * value of the fit range used when generating the energy loss fits.
+   * However, if fLowCut is set (using SetLowCit) to a value greater
+   * than 0, then that value is used.
+   */
+  virtual Double_t GetLowCut() const;
 
   TList    fRingHistos;    // List of histogram containers
   Double_t fLowCut;        // Low cut on sharing
   Bool_t   fCorrectAngles; // Whether to work on angle corrected signals
+  Short_t  fNXi;           // Number of xi's from Delta to stop merging
   Int_t    fDebug;         // Debug level 
 
   ClassDef(AliFMDSharingFilter,1); //
diff --git a/PWG2/FORWARD/analysis2/AliForwardCorrectionManager.cxx b/PWG2/FORWARD/analysis2/AliForwardCorrectionManager.cxx
new file mode 100644 (file)
index 0000000..41b5330
--- /dev/null
@@ -0,0 +1,460 @@
+#include "AliForwardCorrectionManager.h"
+#include "AliForwardUtil.h"
+#include <TString.h>
+#include <AliLog.h>
+#include <TFile.h>
+#include <TSystem.h>
+
+    
+//____________________________________________________________________
+AliForwardCorrectionManager* AliForwardCorrectionManager::fgInstance = 0;
+const char* AliForwardCorrectionManager::fgkSecondaryMapSkel = "secondary";
+const char* AliForwardCorrectionManager::fgkDoubleHitSkel    = "doublehit";
+const char* AliForwardCorrectionManager::fgkELossFitsSkel    = "elossfits";
+const char* AliForwardCorrectionManager::fgkVertexBiasSkel   = "vertexbias";
+const char* AliForwardCorrectionManager::fgkMergingEffSkel   = "merging";
+
+#define PREFIX "$(ALICE_ROOT)/PWG2/FORWARD/corrections/"
+
+//____________________________________________________________________
+AliForwardCorrectionManager& AliForwardCorrectionManager::Instance()
+{
+  if (!fgInstance) fgInstance= new AliForwardCorrectionManager;
+  return *fgInstance;
+}
+
+//____________________________________________________________________
+AliForwardCorrectionManager::AliForwardCorrectionManager()
+  : TObject(), 
+    fInit(kFALSE),
+    fSys(0),
+    fSNN(0),
+    fField(999),
+    fELossFitsPath(PREFIX "ELossFits"),
+    fMergingEffPath(PREFIX "MergingEfficiency"), 
+    fSecondaryMapPath(PREFIX "SecondaryMap"),
+    fDoubleHitPath(PREFIX "DoubleHit"),
+    fVertexBiasPath(PREFIX "VertexBias"),
+    fELossFit(0),
+    fSecondaryMap(0),
+    fDoubleHit(0),
+    fVertexBias(0),
+    fMergingEfficiency(0)
+{
+}
+//____________________________________________________________________
+AliForwardCorrectionManager::AliForwardCorrectionManager(const AliForwardCorrectionManager& o)
+  : TObject(o),
+    fInit(o.fInit),
+    fSys(o.fSys),
+    fSNN(o.fSNN),
+    fField(o.fField),
+    fELossFitsPath(o.fELossFitsPath),
+    fMergingEffPath(o.fMergingEffPath), 
+    fSecondaryMapPath(o.fSecondaryMapPath),
+    fDoubleHitPath(o.fDoubleHitPath),
+    fVertexBiasPath(o.fVertexBiasPath),
+    fELossFit(o.fELossFit),
+    fSecondaryMap(o.fSecondaryMap),
+    fDoubleHit(o.fDoubleHit),
+    fVertexBias(o.fVertexBias),
+    fMergingEfficiency(o.fMergingEfficiency)
+
+{
+}
+//____________________________________________________________________
+AliForwardCorrectionManager&
+AliForwardCorrectionManager::operator=(const AliForwardCorrectionManager& o)
+{
+  fInit             = o.fInit;
+  fSys              = o.fSys;
+  fSNN              = o.fSNN;
+  fField            = o.fField;
+  fELossFitsPath    = o.fELossFitsPath;
+  fMergingEffPath   = o.fMergingEffPath;
+  fSecondaryMapPath = o.fSecondaryMapPath;
+  fDoubleHitPath    = o.fDoubleHitPath;
+  fVertexBiasPath   = o.fVertexBiasPath;
+  fELossFit         = o.fELossFit;
+  fSecondaryMap     = o.fSecondaryMap;
+  fDoubleHit        = o.fDoubleHit;
+  fVertexBias       = o.fVertexBias;
+  fMergingEfficiency= o.fMergingEfficiency;
+  return *this;
+}
+
+//____________________________________________________________________
+Bool_t
+AliForwardCorrectionManager::Init(const char* cms, 
+                                 Float_t     sNN, 
+                                 Float_t     field,
+                                 Bool_t      mc,
+                                 UInt_t      what,
+                                 Bool_t      force)
+{
+  UShort_t col = AliForwardUtil::ParseCollisionSystem(cms);
+  return Init(col, 
+             AliForwardUtil::ParseCenterOfMassEnergy(col, sNN),
+             AliForwardUtil::ParseMagneticField(field), 
+             mc, what, force);
+}
+
+//____________________________________________________________________
+Bool_t
+AliForwardCorrectionManager::Init(UShort_t cms, 
+                                 UShort_t sNN, 
+                                 Short_t  field,
+                                 Bool_t   mc,
+                                 UInt_t   what,
+                                 Bool_t   force)
+{
+  if (force) fInit = kFALSE;
+  if (fInit) return kTRUE;
+
+  Bool_t ret = kTRUE;
+  if (fSys == cms && TMath::Abs(fSNN - sNN) < 10 && fField == field) { 
+    // We're already initialised for these settings - do nothing and return
+    fInit = kTRUE;
+    return ret;
+  }
+  // Set cached parameters 
+  fSys   = cms;
+  fSNN   = sNN;
+  fField = field;
+              
+  // Read secondary map if requested 
+  if (what & kSecondaryMap) {
+    if (!ReadSecondaryMap(cms, sNN, field)) {
+      AliWarning(Form("Failed to read in secondary map for "
+                     "cms=%d, sNN=%dGeV, field=%dkG", cms, sNN, field));
+      ret = kFALSE;
+    }
+  }
+  // Read double hit if requested 
+  if (what & kDoubleHit) {
+    if (!ReadDoubleHit(cms, sNN, field)) {
+      AliWarning(Form("Failed to read in double hit correction for "
+                     "cms=%d, sNN=%dGeV, field=%dkG", cms, sNN, field));
+      ret = kFALSE;
+    }
+  }
+  // Read energy loss fits if requested 
+  if (what & kELossFits) {
+    if (!ReadELossFits(cms, sNN, field, mc)) {
+      AliWarning(Form("Failed to read in energy loss fits for "
+                     "cms=%d, sNN=%dGeV, field=%dkG, %s", 
+                     cms, sNN, field, mc ? "MC" : "real"));
+      ret = kFALSE;
+    }
+  }
+  // Read event selection efficiencies if requested 
+  if (what & kVertexBias) {
+    if (!ReadVertexBias(cms, sNN, field)) {
+      AliWarning(Form("Failed to read in event selection efficiency for "
+                     "cms=%d, sNN=%dGeV, field=%dkG", cms, sNN, field));
+      ret = kFALSE;
+    }
+  }
+  // Read merging efficiencies if requested 
+  if (what & kMergingEfficiency) {
+    if (!ReadMergingEfficiency(cms, sNN, field)) {
+      AliWarning(Form("Failed to read in hit merging efficiency for "
+                     "cms=%d, sNN=%dGeV, field=%dkG", 
+                     cms, sNN, field));
+      ret = kFALSE;
+    }
+  }
+  fInit = kTRUE;
+  return ret;
+}
+
+//____________________________________________________________________
+TString 
+AliForwardCorrectionManager::GetFileName(ECorrection what, 
+                                        UShort_t    sys, 
+                                        UShort_t    sNN,
+                                        Short_t     field,
+                                        Bool_t      mc) const
+{
+  TString fname = "";
+  fname = GetObjectName(what);
+  fname.Append(Form("_%s_%04dGeV_%c%1dkG_%s.root", 
+                   AliForwardUtil::CollisionSystemString(sys), 
+                   sNN, (field < 0 ? 'm' : 'p'), TMath::Abs(field), 
+                   (mc ? "MC" : "real")));
+  return fname;
+}
+//____________________________________________________________________
+TString
+AliForwardCorrectionManager::GetFileName(ECorrection what) const
+{
+  if (!fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return "";
+  }
+  return GetFileName(what, fSys, fSNN, fField, false);
+}
+
+//____________________________________________________________________
+const Char_t*
+AliForwardCorrectionManager::GetFileDir(ECorrection what) const
+{
+  if      (what & kSecondaryMap)        return fSecondaryMapPath;
+  else if (what & kDoubleHit)           return fDoubleHitPath;
+  else if (what & kELossFits)           return fELossFitsPath;
+  else if (what & kVertexBias)          return fVertexBiasPath;
+  else if (what & kMergingEfficiency)   return fMergingEffPath;
+
+  AliWarning(Form("Unknown correction: %d", what));
+  return 0;
+}
+
+//____________________________________________________________________
+TString 
+AliForwardCorrectionManager::GetFilePath(ECorrection what, 
+                                        UShort_t    sys, 
+                                        UShort_t    sNN,
+                                        Short_t     field,
+                                        Bool_t      mc) const
+{
+  TString path = "";
+  const Char_t* dir = GetFileDir(what);
+  if (!dir) return path;
+  
+  TString fname(GetFileName(what, sys, sNN, field, mc));
+  if (fname.IsNull()) return path;
+
+  path = gSystem->ConcatFileName(gSystem->ExpandPathName(dir), fname);
+  
+  return path;
+}
+//____________________________________________________________________
+TString
+AliForwardCorrectionManager::GetFilePath(ECorrection what) const
+{
+  if (!fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return "";
+  }
+  return GetFilePath(what, fSys, fSNN, fField, false);
+}
+
+//____________________________________________________________________
+TFile*
+AliForwardCorrectionManager::GetFile(ECorrection what, 
+                                    UShort_t    sys, 
+                                    UShort_t    sNN, 
+                                    Short_t     field, 
+                                    Bool_t      mc, 
+                                    Bool_t      rw, 
+                                    Bool_t      newfile) const
+{
+  TString path = GetFilePath(what, sys, sNN, field, mc);
+  if (path.IsNull()) return 0;
+  
+  TString opt;
+  if (newfile) opt="RECREATE";
+  else {
+    if (gSystem->AccessPathName(path.Data(), 
+                               (rw ? kWritePermission : kReadPermission))) {
+      AliWarning(Form("file %s cannot be found or insufficient permissions", 
+                     path.Data()));
+      return 0;
+    }
+    opt=(rw ? "UPDATE" : "READ");
+  }
+  TFile* file = TFile::Open(path.Data(), opt.Data());
+  if (!file) { 
+    AliWarning(Form("file %s cannot be opened in mode %s", 
+                   path.Data(), opt.Data()));
+    return 0;
+  }
+  return file;
+}
+//____________________________________________________________________
+TFile*
+AliForwardCorrectionManager::GetFile(ECorrection what) const
+{
+  if (!fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return 0;
+  }
+  return GetFile(what, fSys, fSNN, fField, false);
+}
+
+//____________________________________________________________________
+const Char_t*
+AliForwardCorrectionManager::GetObjectName(ECorrection what) const
+{
+  if      (what & kSecondaryMap)       return fgkSecondaryMapSkel;
+  else if (what & kDoubleHit)          return fgkDoubleHitSkel;
+  else if (what & kELossFits)          return fgkELossFitsSkel;
+  else if (what & kVertexBias)         return fgkVertexBiasSkel;
+  else if (what & kMergingEfficiency)  return fgkMergingEffSkel;
+  return 0;
+}
+
+//____________________________________________________________________
+TObject*
+AliForwardCorrectionManager::CheckObject(TFile* file, ECorrection what) const
+{
+  TObject* o = file->Get(GetObjectName(what));
+  if (!o) { 
+    AliWarning(Form("Object %s not found in %s", 
+                   GetObjectName(what), file->GetName()));
+    file->Close();
+    return 0;
+  }
+  return o;
+}
+  
+//____________________________________________________________________
+TObject*
+AliForwardCorrectionManager::GetObject(ECorrection what, 
+                                      UShort_t    sys, 
+                                      UShort_t    sNN, 
+                                      Short_t     field,
+                                      Bool_t      mc) const
+{
+  TFile* file = GetFile(what, sys, sNN, field, mc, false, false);
+  if (!file) return 0;
+  
+  return CheckObject(file, what);
+}
+//____________________________________________________________________
+TObject*
+AliForwardCorrectionManager::GetObject(ECorrection what) const
+{
+  if (!fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return 0;
+  }
+  return GetObject(what, fSys, fSNN, fField, false);
+}
+
+
+//____________________________________________________________________
+Bool_t 
+AliForwardCorrectionManager::ReadSecondaryMap(UShort_t sys, UShort_t sNN, 
+                                             Short_t field)
+{
+  if (fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return kFALSE;
+  }
+
+  TObject* o = GetObject(kSecondaryMap, sys, sNN, field, false);
+  if (!o) return kFALSE;
+
+  fSecondaryMap = dynamic_cast<AliFMDCorrSecondaryMap*>(o);
+  if (!fSecondaryMap) {
+    AliWarning(Form("Object %s (%p) is not an AliFMDCorrSecondaryMap object, "
+                   "but %s", fgkSecondaryMapSkel, o, o->ClassName())); 
+    return kFALSE;
+  }
+
+  // file->Close();
+  return kTRUE;
+}
+//____________________________________________________________________
+Bool_t 
+AliForwardCorrectionManager::ReadDoubleHit(UShort_t sys, UShort_t sNN, 
+                                          Short_t field)
+{
+  if (fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return kFALSE;
+  }
+
+  TObject* o = GetObject(kDoubleHit, sys, sNN, field, false);
+  if (!o) return kFALSE;
+
+  fDoubleHit = dynamic_cast<AliFMDCorrDoubleHit*>(o);
+  if (!fDoubleHit) {
+    AliWarning(Form("Object %s (%p) is not an AliFMDCorrDoubleHit object, "
+                   "but %s", fgkDoubleHitSkel, o, o->ClassName())); 
+    return kFALSE;
+  }
+
+  // file->Close();
+  return kTRUE;
+}
+
+//____________________________________________________________________
+Bool_t 
+AliForwardCorrectionManager::ReadELossFits(UShort_t sys, UShort_t sNN, 
+                                          Short_t field, Bool_t mc)
+{
+  if (fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return kFALSE;
+  }
+
+  TObject* o = GetObject(kELossFits, sys, sNN, field, mc);
+  if (!o) return kFALSE;
+
+  fELossFit = dynamic_cast<AliFMDCorrELossFit*>(o);
+  if (!fELossFit) {
+    AliWarning(Form("Object %s (%p) is not an AliFMDCorrELossFit object, "
+                   "but %s", fgkELossFitsSkel, o, o->ClassName()));
+    return kFALSE;
+  }
+
+  // file->Close();
+  return kTRUE;
+}
+
+//____________________________________________________________________
+Bool_t 
+AliForwardCorrectionManager::ReadVertexBias(UShort_t sys, 
+                                           UShort_t sNN, 
+                                           Short_t field)
+{
+  if (fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return kFALSE;
+  }
+
+  TObject* o = GetObject(kVertexBias, sys, sNN, field, false);
+  if (!o) return kFALSE;
+
+  fVertexBias = dynamic_cast<AliFMDCorrVertexBias*>(o);
+  if (!fVertexBias) {
+    AliWarning(Form("Object %s (%p) is not an AliFMDCorrVertexBias object, "
+                   "but %s", fgkVertexBiasSkel, o, o->ClassName()));
+    return kFALSE;
+  }
+
+  // file->Close();
+  return kTRUE;
+}
+
+//____________________________________________________________________
+Bool_t 
+AliForwardCorrectionManager::ReadMergingEfficiency(UShort_t sys, 
+                                                  UShort_t sNN, 
+                                                  Short_t field)
+{
+  if (fInit) { 
+    AliWarning("Corrections manager initialised, do a forced Init(...)");
+    return kFALSE;
+  }
+
+  TObject* o = GetObject(kMergingEfficiency, sys, sNN, field, false);
+  if (!o) return kFALSE;
+
+  fMergingEfficiency = dynamic_cast<AliFMDCorrMergingEfficiency*>(o);
+  if (!fMergingEfficiency) {
+    AliWarning(Form("Object %s (%p) is not an AliFMDCorrMergingEfficiency "
+                   "object, but %s", fgkMergingEffSkel, o, o->ClassName()));
+    return kFALSE;
+  }
+
+  // file->Close();
+  return kTRUE;
+}
+
+//____________________________________________________________________
+//
+// EOF
+//
diff --git a/PWG2/FORWARD/analysis2/AliForwardCorrectionManager.h b/PWG2/FORWARD/analysis2/AliForwardCorrectionManager.h
new file mode 100644 (file)
index 0000000..7df8838
--- /dev/null
@@ -0,0 +1,346 @@
+#ifndef ALIROOT_PWG2_FORWARD_ALIFORWARDCORRECTIONMANAGER_H
+#define ALIROOT_PWG2_FORWARD_ALIFORWARDCORRECTIONMANAGER_H
+#include <TObject.h>
+#include "AliFMDCorrELossFit.h"
+#include "AliFMDCorrSecondaryMap.h"
+#include "AliFMDCorrDoubleHit.h"
+#include "AliFMDCorrVertexBias.h"
+#include "AliFMDCorrMergingEfficiency.h"
+#include <TString.h>
+class TFile;
+
+class AliForwardCorrectionManager : public TObject
+{
+public:
+  /**
+   * Enumeration of things that can be read in 
+   */
+  enum ECorrection { 
+    kSecondaryMap              = 0x01, 
+    kELossFits                 = 0x02, 
+    kVertexBias                = 0x04, 
+    kMergingEfficiency         = 0x08,
+    kDoubleHit                 = 0x10,
+    kAll                       = (kSecondaryMap| 
+                                 kELossFits|
+                                 kVertexBias|
+                                 kMergingEfficiency|
+                                 kDoubleHit)
+  };
+  /** 
+   * Access to the singleton object 
+   * 
+   * @return Reference to the singleton object 
+   */
+  static AliForwardCorrectionManager& Instance();
+  /** 
+   * Read in corrections based on the parameters given 
+   * 
+   * @param collisionSystem Collision system
+   * @param cmsNN           Center of mass energy per nuclean pair [GeV]
+   * @param field           Magnetic field setting [kG]
+   * @param what            What to read in. 
+   * @param force           Force (re-)reading of specified things
+   * 
+   * @return 
+   */
+  Bool_t Init(UShort_t collisionSystem, 
+             UShort_t cmsNN, 
+             Short_t  field, 
+             Bool_t   mc=false,
+             UInt_t   what=kAll,
+             Bool_t   force=false);
+  Bool_t Init(const char* collisionSystem, 
+             Float_t     cmsNN, 
+             Float_t     field, 
+             Bool_t      mc=false,
+             UInt_t      what=kAll,
+             Bool_t      force=false);
+  /** 
+   * Get the eta axis 
+   * 
+   * @return Eta axis or null
+   */
+  const TAxis* GetEtaAxis() const;
+  /** 
+   * Get the vertex axis 
+   * 
+   * @return The vertex axis or null
+   */
+  const TAxis* GetVertexAxis() const;
+  /** 
+   * Get the energy loss fit correction object. 
+   * 
+   * @return Get the energy loss fits corrections object or null pointer
+   */
+  AliFMDCorrELossFit* GetELossFit() const { return fELossFit; }
+  /** 
+   * Get the secondary correction map
+   * 
+   * @return Get the secondary correction map object or null
+   */
+  AliFMDCorrSecondaryMap* GetSecondaryMap() const { return fSecondaryMap; }
+  /** 
+   * Get the double hit correction object
+   * 
+   * @return Get the double hit correction object or null 
+   */
+  AliFMDCorrDoubleHit* GetDoubleHit() const { return fDoubleHit; }
+  /** 
+   * Get the vertex bias correction object
+   * 
+   * @return Get the vertex bias correction object or null 
+   */
+  AliFMDCorrVertexBias* GetVertexBias() const { return fVertexBias; }
+  AliFMDCorrMergingEfficiency* GetMergingEfficiency() const 
+  {
+    return fMergingEfficiency;
+  }
+  /** 
+   * @{ 
+   * @name Path, file, and object access utilities 
+   */
+  /** 
+   * Get the path to the specified object 
+   *
+   * @param what  Which stuff to get the path for 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * @param mc    Whether the correction objects should be valid for MC
+   * 
+   * @return The full path or null 
+   */
+  TString GetFileName(ECorrection what, 
+                     UShort_t    sys, 
+                     UShort_t    sNN, 
+                     Short_t     field,
+                     Bool_t      mc) const;
+  TString GetFileName(ECorrection what) const;
+  /** 
+   * Get the path to the specified object 
+   *
+   * @param what  Which stuff to get the path for 
+   * 
+   * @return The full path or null 
+   */
+  const Char_t* GetFileDir(ECorrection what) const;
+  /** 
+   * Get the path to the specified object 
+   *
+   * @param what  Which stuff to get the path for 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * @param mc    Whether the correction objects should be valid for MC
+   * 
+   * @return The full path or null 
+   */
+  TString GetFilePath(ECorrection what, 
+                     UShort_t    sys, 
+                     UShort_t    sNN, 
+                     Short_t     field,
+                     Bool_t      mc) const;
+  TString GetFilePath(ECorrection what) const;
+  /** 
+   * Open the file that contains the correction object specified 
+   * 
+   * @param what  Which stuff to get the path for 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * @param mc    Whether the correction objects should be valid for MC
+   * @param rw    Whether to open the file in read/write
+   * @param newfile Wheter to make the file if it doesn't exist
+   * 
+   * @return The file that contains the correction object or null 
+   */
+  TFile* GetFile(ECorrection what, 
+                UShort_t    sys, 
+                UShort_t    sNN, 
+                Short_t     field,
+                Bool_t      mc=false, 
+                Bool_t      rw=false, 
+                Bool_t      newfile=false) const;
+  TFile* GetFile(ECorrection what) const;
+  /** 
+   * Get the object name corresponding to correction type 
+   * 
+   * @param what Correction 
+   * 
+   * @return Object name or null
+   */
+  const Char_t* GetObjectName(ECorrection what) const;
+  /** 
+   * Check if the specified objet exists in the file, and return it
+   * 
+   * @param file File to query 
+   * @param what Correction type 
+   * 
+   * @return Object found, or null
+   */
+  TObject* CheckObject(TFile* file,  ECorrection what) const;
+  /** 
+   * Get the path to the specified object 
+   *
+   * @param what  Which stuff to get the path for 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * @param mc    Whether the correction objects should be valid for MC
+   * 
+   * @return The full path or null 
+   */
+  TObject* GetObject(ECorrection what, 
+                    UShort_t    sys, 
+                    UShort_t    sNN, 
+                    Short_t     field,
+                    Bool_t      mc) const;
+  TObject* GetObject(ECorrection what) const;
+  /* 
+   * @} 
+   */
+private:
+  /** 
+   * Default constructor 
+   */
+  AliForwardCorrectionManager();
+  /** 
+   * Copy constructor 
+   * 
+   * @param o Object to copy from 
+   */
+  AliForwardCorrectionManager(const AliForwardCorrectionManager& o);
+  /** 
+   * Assignment operator 
+   * 
+   * @param o Object to assign from 
+   * 
+   * @return Reference to this object 
+   */
+  AliForwardCorrectionManager& operator=(const AliForwardCorrectionManager& o);
+  /** 
+   * @{ 
+   * @name Read in corrections 
+   */
+  /** 
+   * Read in the secondary map 
+   * 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * 
+   * @return True on success, false otherwise 
+   */
+  Bool_t ReadSecondaryMap(UShort_t sys, UShort_t sNN, Short_t field);
+  /** 
+   * Read in the double hit correction
+   * 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * 
+   * @return True on success, false otherwise 
+   */
+  Bool_t ReadDoubleHit(UShort_t sys, UShort_t sNN, Short_t field);
+  /** 
+   * Read in the energy loss fits 
+   * 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * @param mc    Whether the correction objects should be valid for MC
+   * 
+   * @return True on success, false otherwise 
+   */
+  Bool_t ReadELossFits(UShort_t sys, UShort_t sNN, Short_t field, Bool_t mc);
+  /** 
+   * Read in the event selection efficiency 
+   * 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * 
+   * @return True on success, false otherwise 
+   */
+  Bool_t ReadVertexBias(UShort_t sys, UShort_t sNN, Short_t field);
+  /** 
+   * Read in the merging efficiency 
+   * 
+   * @param sys   Collision system
+   * @param sNN   Center of mass energy [GeV]
+   * @param field Magnetic field in the L3 magnet [kG]
+   * 
+   * @return True on success, false otherwise 
+   */
+  Bool_t ReadMergingEfficiency(UShort_t sys, UShort_t sNN, Short_t field);
+  /* 
+   * @} 
+   */
+  
+  /** Static singleton instance */
+  static AliForwardCorrectionManager* fgInstance;
+  Bool_t    fInit;  // whether we have been initialised 
+  UShort_t  fSys;   // Collision System
+  UShort_t  fSNN;   // Collision energy per nucleon (GeV)
+  Short_t   fField; // L3 magnetic field (kG)
+  
+  /** 
+   * @{
+   * @name Paths 
+   */ 
+  TString fELossFitsPath;    // Path to energy loss fit correction 
+  TString fMergingEffPath;   // Path to sharing efficiency correction 
+  TString fSecondaryMapPath; // Path to secondary efficiency correction
+  TString fDoubleHitPath;    // Path to double hit correction
+  TString fVertexBiasPath;   // Path to event selection efficiency correction
+  /* 
+   * @}
+   */
+  /** 
+   * @{ 
+   * @name Object name 
+   */
+  static const Char_t* fgkSecondaryMapSkel;  // Name of correction object 
+  static const Char_t* fgkDoubleHitSkel;     // Name of correction object 
+  static const Char_t* fgkELossFitsSkel;     // Name of correction object 
+  static const Char_t* fgkVertexBiasSkel;    // Name of correction object 
+  static const Char_t* fgkMergingEffSkel;    // Name of correction object 
+  /* 
+   * @} 
+   */
+  /** 
+   * @{ 
+   * @name Correction objects 
+   */
+  AliFMDCorrELossFit*     fELossFit;     // Energy loss fits 
+  AliFMDCorrSecondaryMap* fSecondaryMap; // Secondary particle correction
+  AliFMDCorrDoubleHit*    fDoubleHit;    // Double hit correction (low flux)
+  AliFMDCorrVertexBias*   fVertexBias;   // Vertex bias correction
+  AliFMDCorrMergingEfficiency* fMergingEfficiency;
+  /* 
+   * @}
+   */
+
+  ClassDef(AliForwardCorrectionManager,1) // Manager of corrections 
+};
+//____________________________________________________________________
+inline const TAxis* 
+AliForwardCorrectionManager::GetEtaAxis() const
+{
+  if (!fSecondaryMap) return 0;
+  return &(fSecondaryMap->GetEtaAxis());
+}
+//____________________________________________________________________
+inline const TAxis* 
+AliForwardCorrectionManager::GetVertexAxis() const
+{
+  if (!fSecondaryMap) return 0;
+  return &(fSecondaryMap->GetVertexAxis());
+}
+
+#endif
+// Local Variables:
+//   mode: C++ 
+// End: 
+
@@ -1,13 +1,19 @@
-#include "AliForwardMCCorrections.h"
+#include "AliForwardMCCorrectionsTask.h"
 #include "AliTriggerAnalysis.h"
 #include "AliPhysicsSelection.h"
 #include "AliLog.h"
-#include "AliFMDAnaParameters.h"
+// #include "AliFMDAnaParameters.h"
+#include "AliHeader.h"
+#include "AliGenEventHeader.h"
 #include "AliESDEvent.h"
 #include "AliAODHandler.h"
 #include "AliMultiplicity.h"
 #include "AliInputEventHandler.h"
+#include "AliStack.h"
+#include "AliMCEvent.h"
+#include "AliFMDStripIndex.h"
 #include <TH1.h>
+#include <TH3D.h>
 #include <TDirectory.h>
 #include <TTree.h>
 
@@ -15,7 +21,7 @@
 namespace {
   const char* GetEventName(Bool_t tr, Bool_t vtx) 
   {
-    return Form("nEvents%s%s", (tr ? "Tr" : ""), (vtx ? "Vtx", ""));
+    return Form("nEvents%s%s", (tr ? "Tr" : ""), (vtx ? "Vtx" : ""));
   }
   const char* GetHitsName(UShort_t d, Char_t r) 
   {
@@ -34,62 +40,113 @@ namespace {
 }
 
 //====================================================================
-AliForwardMCCorrections::AliForwardMCCorrections()
+AliForwardMCCorrectionsTask::AliForwardMCCorrectionsTask()
   : AliAnalysisTaskSE(),
+    fHEvents(0), 
     fHEventsTr(0), 
     fHEventsTrVtx(0),
+    fHEventsVtx(0), 
     fHTriggers(0),
+    fPrimaryInnerAll(0),   
+    fPrimaryOuterAll(0),   
+    fPrimaryInnerTrVtx(0), 
+    fPrimaryOuterTrVtx(0), 
+    fHitsFMD1i(0),         
+    fHitsFMD2i(0),         
+    fHitsFMD2o(0),         
+    fHitsFMD3i(0),         
+    fHitsFMD3o(0),         
+    fStripsFMD1i(0),       
+    fStripsFMD2i(0),       
+    fStripsFMD2o(0),       
+    fStripsFMD3i(0),       
+    fStripsFMD3o(0),       
     fVtxAxis(),
-    fEtaAxis()
+    fEtaAxis(),
+    fList()
 {
 }
 
 //____________________________________________________________________
-AliForwardMCCorrections::AliForwardMCCorrections(const char* name)
+AliForwardMCCorrectionsTask::AliForwardMCCorrectionsTask(const char* name)
   : AliAnalysisTaskSE(name), 
+    fHEvents(0), 
     fHEventsTr(0), 
-    fHEventsTrVtx(0), 
+    fHEventsTrVtx(0),
+    fHEventsVtx(0), 
     fHTriggers(0),
+    fPrimaryInnerAll(0),   
+    fPrimaryOuterAll(0),   
+    fPrimaryInnerTrVtx(0), 
+    fPrimaryOuterTrVtx(0), 
+    fHitsFMD1i(0),         
+    fHitsFMD2i(0),         
+    fHitsFMD2o(0),         
+    fHitsFMD3i(0),         
+    fHitsFMD3o(0),         
+    fStripsFMD1i(0),       
+    fStripsFMD2i(0),       
+    fStripsFMD2o(0),       
+    fStripsFMD3i(0),       
+    fStripsFMD3o(0),       
     fVtxAxis(10,-10,10), 
-    fEtaAxis(200,-4,6)
+    fEtaAxis(200,-4,6),
+    fList()
 {
   DefineOutput(1, TList::Class());
 }
 
 //____________________________________________________________________
-AliForwardMCCorrections::AliForwardMCCorrections(const AliForwardMCCorrections& o)
+AliForwardMCCorrectionsTask::AliForwardMCCorrectionsTask(const AliForwardMCCorrectionsTask& o)
   : AliAnalysisTaskSE(o),
+    fHEvents(o.fHEvents), 
     fHEventsTr(o.fHEventsTr), 
-    fHEventsTrVtx(o.fHEventsTrVtx), 
+    fHEventsTrVtx(o.fHEventsTrVtx),
+    fHEventsVtx(o.fHEventsVtx), 
     fHTriggers(o.fHTriggers),
-    fVtxAxis(o.fVtxAxis),
-    fEtaAxis(o.fEtaAxis)
+    fPrimaryInnerAll(o.fPrimaryInnerAll),   
+    fPrimaryOuterAll(o.fPrimaryOuterAll),   
+    fPrimaryInnerTrVtx(o.fPrimaryInnerTrVtx), 
+    fPrimaryOuterTrVtx(o.fPrimaryOuterTrVtx), 
+    fHitsFMD1i(o.fHitsFMD1i),         
+    fHitsFMD2i(o.fHitsFMD2i),         
+    fHitsFMD2o(o.fHitsFMD2o),         
+    fHitsFMD3i(o.fHitsFMD3i),         
+    fHitsFMD3o(o.fHitsFMD3o),         
+    fStripsFMD1i(o.fStripsFMD1i),       
+    fStripsFMD2i(o.fStripsFMD2i),       
+    fStripsFMD2o(o.fStripsFMD2o),       
+    fStripsFMD3i(o.fStripsFMD3i),       
+    fStripsFMD3o(o.fStripsFMD3o),       
+    fVtxAxis(o.fVtxAxis.GetNbins(), o.fVtxAxis.GetXmin(), o.fVtxAxis.GetXmax()),
+    fEtaAxis(o.fEtaAxis.GetNbins(), o.fEtaAxis.GetXmin(), o.fEtaAxis.GetXmax()),
+    fList(o.fList)
 {
 }
 
 //____________________________________________________________________
-AliForwardMCCorrections&
-AliForwardMCCorrections::operator=(const AliForwardMCCorrections& o)
+AliForwardMCCorrectionsTask&
+AliForwardMCCorrectionsTask::operator=(const AliForwardMCCorrectionsTask& o)
 {
   fHEventsTr         = o.fHEventsTr;
   fHEventsTrVtx      = o.fHEventsTrVtx;
   fHTriggers         = o.fHTriggers;
-  fHData             = o.fHData;
-  fVtxAxis           = o.fVtxAxis;
-  fEtaAxis           = o.fEtaAxis;
+  SetVertexAxis(o.fVtxAxis);
+  SetEtaAxis(o.fEtaAxis);
 
   return *this;
 }
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::Init()
+AliForwardMCCorrectionsTask::Init()
 {
 }
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::SetVertexAxis(Int_t nBin, Double_t min, Double_t max)
+AliForwardMCCorrectionsTask::SetVertexAxis(Int_t nBin, Double_t min, 
+                                          Double_t max)
 {
   if (max < min) max = -min;
   if (min < max) { 
@@ -105,14 +162,14 @@ AliForwardMCCorrections::SetVertexAxis(Int_t nBin, Double_t min, Double_t max)
 }
 //____________________________________________________________________
 void
-AliForwardMCCorrections::SetVertexAxis(const TAxis& axis)
+AliForwardMCCorrectionsTask::SetVertexAxis(const TAxis& axis)
 {
   SetVertexAxis(axis.GetNbins(),axis.GetXmin(),axis.GetXmax());
 }
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::SetEtaAxis(Int_t nBin, Double_t min, Double_t max)
+AliForwardMCCorrectionsTask::SetEtaAxis(Int_t nBin, Double_t min, Double_t max)
 {
   if (max < min) max = -min;
   if (min < max) { 
@@ -128,20 +185,14 @@ AliForwardMCCorrections::SetEtaAxis(Int_t nBin, Double_t min, Double_t max)
 }
 //____________________________________________________________________
 void
-AliForwardMCCorrections::SetVertexAxis(const TAxis& axis)
+AliForwardMCCorrectionsTask::SetEtaAxis(const TAxis& axis)
 {
   SetEtaAxis(axis.GetNbins(),axis.GetXmin(),axis.GetXmax());
 }
   
 //____________________________________________________________________
-void
-AliForwardMCCorrections::InitializeSubs()
-{
-}
-
-//____________________________________________________________________
 TH3D*
-AliForwardMCCorrections::Make3D(const char* name, const char* title,
+AliForwardMCCorrectionsTask::Make3D(const char* name, const char* title,
                               Int_t nPhi) const
 {
   TH3D* ret = new TH3D(name, title,
@@ -163,7 +214,7 @@ AliForwardMCCorrections::Make3D(const char* name, const char* title,
 }
 //____________________________________________________________________
 TH1D*
-AliForwardMCCorrections::Make1D(const char* name, const char* title) const
+AliForwardMCCorrectionsTask::Make1D(const char* name, const char* title) const
 {
   TH1D* ret = new TH1D(name, title,
                       fEtaAxis.GetNbins(), 
@@ -181,16 +232,16 @@ AliForwardMCCorrections::Make1D(const char* name, const char* title) const
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::UserCreateOutputObjects()
+AliForwardMCCorrectionsTask::UserCreateOutputObjects()
 {
   fList = new TList;
   fList->SetName(GetName());
 
-  fHEvents = new TH1I(GetEventsName(false,false),
+  fHEvents = new TH1I(GetEventName(false,false),
                      "Number of all events", 
-                     fAxis.GetNbins(), 
-                     fAxis.GetXmin(), 
-                     fAxis.GetXmax());
+                     fVtxAxis.GetNbins(), 
+                     fVtxAxis.GetXmin(), 
+                     fVtxAxis.GetXmax());
   fHEvents->SetXTitle("v_{z} [cm]");
   fHEvents->SetYTitle("# of events");
   fHEvents->SetFillColor(kBlue+1);
@@ -198,7 +249,8 @@ AliForwardMCCorrections::UserCreateOutputObjects()
   fHEvents->SetDirectory(0);
   fList->Add(fHEvents);
 
-  fHEventsTr = new TH1I(GetEventsName(true, false), 
+  fHEventsTr = new TH1I(GetEventName(true, false), 
+                       "Number of triggered events",
                        fVtxAxis.GetNbins(), 
                        fVtxAxis.GetXmin(), 
                        fVtxAxis.GetXmax());
@@ -209,7 +261,7 @@ AliForwardMCCorrections::UserCreateOutputObjects()
   fHEventsTr->SetDirectory(0);
   fList->Add(fHEventsTr);
 
-  fHEventsTrVtx = new TH1I(GetEventsName(true,true),
+  fHEventsTrVtx = new TH1I(GetEventName(true,true),
                           "Number of events w/trigger and vertex", 
                           fVtxAxis.GetNbins(), 
                           fVtxAxis.GetXmin(), 
@@ -220,8 +272,8 @@ AliForwardMCCorrections::UserCreateOutputObjects()
   fHEventsTrVtx->SetFillStyle(3001);
   fHEventsTrVtx->SetDirectory(0);
   fList->Add(fHEventsTrVtx);
-
-  fHEventsVtx = new TH1I(GetEventsName(false,true),
+  
+  fHEventsVtx = new TH1I(GetEventName(false,true),
                         "Number of events w/vertex", 
                         fVtxAxis.GetNbins(), 
                         fVtxAxis.GetXmin(), 
@@ -298,11 +350,11 @@ AliForwardMCCorrections::UserCreateOutputObjects()
 }
 //____________________________________________________________________
 void
-AliForwardMCCorrections::UserExec(Option_t*)
+AliForwardMCCorrectionsTask::UserExec(Option_t*)
 {
   // Get the input data - MC event
   AliMCEvent*  mcEvent = MCEvent();
-  if (mcevent) { 
+  if (mcEvent) { 
     AliWarning("No MC event found");
     return;
   }
@@ -319,23 +371,30 @@ AliForwardMCCorrections::UserExec(Option_t*)
 
   // Get the event generate header 
   AliHeader*          mcHeader  = mcEvent->Header();
-  AliGenEventHeader*  genHeader = mcHeader->GetCenEventHeader();
+  AliGenEventHeader*  genHeader = mcHeader->GenEventHeader();
   
   // Get the generator vertex 
   TArrayF mcVertex;
-  genHeader->PrimaryVertex();
+  genHeader->PrimaryVertex(mcVertex);
   Double_t mcVtxZ = mcVertex.At(2);
 
   // Check the MC vertex is in range 
-  Int_t mcVtxBin = fVtxAxis.FindBin(vZ);
-  if (vZ < 1 || vZ > fVtxAxis.GetNbins()) {
+  Int_t mcVtxBin = fVtxAxis.FindBin(mcVtxZ);
+  if (mcVtxBin < 1 || mcVtxBin > fVtxAxis.GetNbins()) {
 #ifdef VERBOSE 
     AliWarning(Form("MC v_z=%f is out of rante [%,%f]", 
-                   vZ, fVtxAxis.GetXmin(), fVtxAxis.GetXmax()));
+                   mcVtxBin, fVtxAxis.GetXmin(), fVtxAxis.GetXmax()));
 #endif
     return;
   }
 
+  UInt_t   triggers;
+  Bool_t   gotTrigggers;
+  Bool_t   gotInel;
+  Double_t vZ;
+  Bool_t   gotVertex;
+#if 0
+  // Use event inspector instead 
   // Get the triggers 
   UInt_t triggers = 0;
   Bool_t gotTriggers = AliForwardUtil::ReadTriggers(esd,triggers,fHTriggers);
@@ -344,7 +403,8 @@ AliForwardMCCorrections::UserExec(Option_t*)
   // Get the ESD vertex 
   Double_t vZ = -1000000;
   Bool_t gotVertex = AliForwardUtil::ReadVertex(esd,vZ);
-  
+#endif
+
 
   // Fill the event count histograms 
   if (gotInel)              fHEventsTr->Fill(mcVtxZ);
@@ -371,29 +431,29 @@ AliForwardMCCorrections::UserExec(Option_t*)
 
     // Fill (eta,phi) of the particle into histograsm for b
     Double_t eta = particle->Eta();
-    Double_t phi = partcile->Phi();
+    Double_t phi = particle->Phi();
     
     if (isCharged && isPrimary) 
       FillPrimary(gotInel, gotVertex, mcVtxZ, eta, phi);
     
     // For the rest, ignore non-collisions, and events out of vtx range 
-    if (!gotInel || gotVtx) continue;
+    if (!gotInel || gotVertex) continue;
     
     Int_t nTrRef = particle->GetNumberOfTrackReferences();
     for (Int_t iTrRef = 0; iTrRef < nTrRef; iTrRef++) { 
       AliTrackReference* trackRef = particle->GetTrackReference(iTrRef);
       
       // Check existence 
-      if (!ret) continue;
+      if (!trackRef) continue;
 
       // Check that we hit an FMD element 
-      if (ref->DetectorId() != AliTrackReference::kFMD) 
+      if (trackRef->DetectorId() != AliTrackReference::kFMD) 
        continue;
 
       // Get the detector coordinates 
       UShort_t d, s, t;
       Char_t r;
-      AliFMDStripIndex::Unpack(ref->UserId(), d, r, s, t);
+      AliFMDStripIndex::Unpack(trackRef->UserId(), d, r, s, t);
       
       // Check if mother (?) is charged and that we haven't dealt with it 
       // already
@@ -403,11 +463,11 @@ AliForwardMCCorrections::UserExec(Option_t*)
       // Increase counter of hits per strip 
       hitsByStrip(d,r,s,t) += 1;
 
-      Double_t trRefEta = esd->GetFMDData()->Eta(d,r,s,t);
-      Double_t trRefPhi = esd->GetFMDData()->Phi(d,r,s,t);
+      // Double_t trRefEta = esd->GetFMDData()->Eta(d,r,s,t);
+      // Double_t trRefPhi = esd->GetFMDData()->Phi(d,r,s,t);
 
       // Fill strip information into histograms 
-      FillStrip(mcVtxZ, eta, phi, hitsByStrip(d,r,s,t) == 1);
+      FillStrip(d, r, mcVtxZ, eta, phi, hitsByStrip(d,r,s,t) == 1);
 
       // Set the last processed track number - marking it as done for
       // this strip
@@ -423,7 +483,7 @@ AliForwardMCCorrections::UserExec(Option_t*)
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::FillPrimary(Bool_t gotInel, Bool_t gotVtx, 
+AliForwardMCCorrectionsTask::FillPrimary(Bool_t gotInel, Bool_t gotVtx, 
                                    Double_t vz, Double_t eta, Double_t phi) 
 {
   if (gotInel && gotVtx) {
@@ -440,16 +500,16 @@ AliForwardMCCorrections::FillPrimary(Bool_t gotInel, Bool_t gotVtx,
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::FillStrip(UShort_t d, Char_t r, 
+AliForwardMCCorrectionsTask::FillStrip(UShort_t d, Char_t r, 
                                  Double_t vz, Double_t eta, Double_t phi,
                                  Bool_t first) 
 {
   // Number of hit strips per eta bin 
-  TH1D* hits   = 0; 
+  TH1D* strips = 0; 
   // All hits per ring, vertex in eta,phi bins.  This takes the place
   // of hHits_FMD<d><r>_vtx<v> and DoubleHits_FMD<d><r> (the later
   // being just the 2D projection over the X bins)
-  TH3D* strips = 0; 
+  TH3D* hits   = 0; 
   switch (d) { 
   case 1: 
     hits   = fHitsFMD1i; 
@@ -473,7 +533,7 @@ AliForwardMCCorrections::FillStrip(UShort_t d, Char_t r,
 
 //____________________________________________________________________
 TH2D*
-AliForwardMCCorrections::GetVertexProj(Int_t v, TH3D* src) const
+AliForwardMCCorrectionsTask::GetVertexProj(Int_t v, TH3D* src) const
 {
   Int_t nX = src->GetNbinsX();
   if (v > nX || v < 1) return 0;
@@ -492,7 +552,7 @@ AliForwardMCCorrections::GetVertexProj(Int_t v, TH3D* src) const
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::Terminate(Option_t*)
+AliForwardMCCorrectionsTask::Terminate(Option_t*)
 {
   TList* list = dynamic_cast<TList*>(GetOutputData(1));
   if (!list) {
@@ -510,13 +570,13 @@ AliForwardMCCorrections::Terminate(Option_t*)
   }
 
   TH1I* eventsAll = 
-    static_cast<TH1I*>(list->FindObject(GetEventsName(false,false)));
+    static_cast<TH1I*>(list->FindObject(GetEventName(false,false)));
   TH1I* eventsTr = 
-    static_cast<TH1I*>(list->FindObject(GetEventsName(true,false)));
+    static_cast<TH1I*>(list->FindObject(GetEventName(true,false)));
   TH1I* eventsVtx = 
-    static_cast<TH1I*>(list->FindObject(GetEventsName(false,true)));
+    static_cast<TH1I*>(list->FindObject(GetEventName(false,true)));
   TH1I* eventsTrVtx = 
-    static_cast<TH1I*>(list->FindObject(GetEventsName(true,true)));
+    static_cast<TH1I*>(list->FindObject(GetEventName(true,true)));
   if (!eventsAll || !eventsTr || !eventsVtx || !eventsTrVtx) {
     AliError(Form("Could not find all event histograms in %s "
                  "(a=%p,t=%p,v=%p,tv=%p)", list->GetName(), 
@@ -565,9 +625,9 @@ AliForwardMCCorrections::Terminate(Option_t*)
 
   // Calculate the over-all event selection efficiency 
   TH1D* selEff = new TH1D("selEff", "Event selection efficiency", 
-                         fVtxArray.GetNbins(), 
-                         fVtxArray.GetXmin(),  
-                         fVtxArray.GetXmax());
+                         fVtxAxis.GetNbins(), 
+                         fVtxAxis.GetXmin(),  
+                         fVtxAxis.GetXmax());
   selEff->Sumw2();
   selEff->SetDirectory(0);
   selEff->SetFillColor(kMagenta+1);
@@ -580,14 +640,14 @@ AliForwardMCCorrections::Terminate(Option_t*)
   for (Int_t v = 1; v <= fVtxAxis.GetNbins(); v++) {
     // Make a sub-list in the output 
     TList* vl = new TList;
-    vl->SetName("vtx%02d", v);
+    vl->SetName(Form("vtx%02d", v));
     list->Add(vl);
 
     // Get event counts 
-    Int_t nEventsAll   = eventsAll->GetEntries(v);
-    Int_t nEventsTr    = eventsTr->GetEntries(v);
-    Int_t nEventsVtx   = eventsVtx->GetEntries(v);
-    Int_t nEventsTrVtx = eventsTrVtx->GetEntries(v);
+    Int_t nEventsAll   = eventsAll->GetBinContent(v);
+    Int_t nEventsTr    = eventsTr->GetBinContent(v);
+    Int_t nEventsVtx   = eventsVtx->GetBinContent(v);
+    Int_t nEventsTrVtx = eventsTrVtx->GetBinContent(v);
 
     // Project event histograms, set names, and store  
     TH2D* primIAllV   = GetVertexProj(v, primIAll);
@@ -599,14 +659,16 @@ AliForwardMCCorrections::Terminate(Option_t*)
     vl->Add(primITrVtxV);
     vl->Add(primOTrVtxV);
     
-    primIAllV->Scale(1. / nEventAll);
-    primOAllV->Scale(1. / nEventAll);
-    primITrVtxV->Scale(1. / nEventTr);
-    primOTrVtxV->Scale(1. / nEventTr);
+    primIAllV->Scale(1. / nEventsAll);
+    primOAllV->Scale(1. / nEventsAll);
+    primITrVtxV->Scale(1. / nEventsTr);
+    primOTrVtxV->Scale(1. / nEventsTr);
 
     // Calculate the vertex bias on the d^2N/detadphi 
-    TH2D* selBiasI = static_cast<TH2D*>(primITrVtxV->Clone("selBiasI%02d",v));
-    TH2D* selBiasO = static_cast<TH2D*>(primOTrVtxV->Clone("selBiasO%02d",v));
+    TH2D* selBiasI = 
+      static_cast<TH2D*>(primITrVtxV->Clone(Form("selBiasI%02d",v)));
+    TH2D* selBiasO = 
+      static_cast<TH2D*>(primOTrVtxV->Clone(Form("selBiasO%02d",v)));
     selBiasI->SetTitle(Form("Event selection bias in vertex bin %d", v));
     selBiasO->SetTitle(Form("Event selection bias in vertex bin %d", v));
     selBiasI->Divide(primIAllV);
@@ -637,11 +699,11 @@ AliForwardMCCorrections::Terminate(Option_t*)
        
        // Do the double hit correction (only done once per ring in
        // the vertex loop)
-       TH1D* strips = 0;
+       TH1D* hStrips = 0;
        switch (d) { 
-       case 1: strips = strips1i; break;
-       case 2: strips = (q == 0 ? strips2i : strips2o); break;
-       case 3: strips = (q == 0 ? strips3i : strips3o); break;
+       case 1: hStrips = strips1i; break;
+       case 2: hStrips = (q == 0 ? strips2i : strips2o); break;
+       case 3: hStrips = (q == 0 ? strips3i : strips3o); break;
        }
 
        TH2D* hits2D    = GetVertexProj(v, hits3D);
@@ -651,7 +713,7 @@ AliForwardMCCorrections::Terminate(Option_t*)
        doubleHit->SetFillColor(kGreen+1);
        doubleHit->SetFillStyle(3001);
        doubleHit->Sumw2();
-       doubleHit->Divide(strips);
+       doubleHit->Divide(hStrips);
        list->Add(doubleHit);
       }
     }
@@ -660,7 +722,7 @@ AliForwardMCCorrections::Terminate(Option_t*)
 
 //____________________________________________________________________
 void
-AliForwardMCCorrections::Print(Option_t*) const
+AliForwardMCCorrectionsTask::Print(Option_t*) const
 {
 }
 
@@ -12,6 +12,7 @@
 class AliFMDAnaParameters;
 class AliESDEvent;
 class TH2D;
+class TH3D;
 class TList;
 class TTree;
 
@@ -32,7 +33,7 @@ class TTree;
  * @ingroup pwg2_forward_analysis 
  * 
  */
-class AliForwardMCCorrections : public AliAnalysisTaskSE
+class AliForwardMCCorrectionsTask : public AliAnalysisTaskSE
 {
 public:
   /** 
@@ -40,17 +41,17 @@ public:
    * 
    * @param name Name of task 
    */
-  AliForwardMCCorrections(const char* name);
+  AliForwardMCCorrectionsTask(const char* name);
   /** 
    * Constructor
    */
-  AliForwardMCCorrections();
+  AliForwardMCCorrectionsTask();
   /** 
    * Copy constructor 
    * 
    * @param o Object to copy from 
    */
-  AliForwardMCCorrections(const AliForwardMCCorrections& o);
+  AliForwardMCCorrectionsTask(const AliForwardMCCorrectionsTask& o);
   /** 
    * Assignment operator 
    * 
@@ -58,7 +59,7 @@ public:
    * 
    * @return Reference to this object 
    */
-  AliForwardMCCorrections& operator=(const AliForwardMCCorrections& o);
+  AliForwardMCCorrectionsTask& operator=(const AliForwardMCCorrectionsTask& o);
   /** 
    * @{ 
    * @name Interface methods 
@@ -96,7 +97,13 @@ public:
   void SetEtaAxis(const TAxis& axis);
 protected: 
   TH2D*  GetVertexProj(Int_t v, TH3D* src) const;
-
+  TH3D* Make3D(const char* name, const char* title, Int_t nPhi) const;
+  TH1D* Make1D(const char* name, const char* title) const;
+  void  FillPrimary(Bool_t gotInel, Bool_t gotVtx, 
+                   Double_t vz, Double_t eta, Double_t phi);
+  void FillStrip(UShort_t d, Char_t r, 
+                Double_t vz, Double_t eta, Double_t phi,
+                Bool_t first);
   TH1I*  fHEvents;           // All Events
   TH1I*  fHEventsTr;         // Histogram of events w/trigger
   TH1I*  fHEventsTrVtx;      // Events w/trigger and vertex 
@@ -121,7 +128,7 @@ protected:
 
   TList* fList; // Output list 
 
-  ClassDef(AliForwardMCCorrections,1) // Forward corrections class
+  ClassDef(AliForwardMCCorrectionsTask,1) // Forward corrections class
 };
 
 #endif
@@ -1,19 +1,25 @@
-#include "AliForwardMultiplicity.h"
+#include "AliForwardMultiplicityTask.h"
 #include "AliTriggerAnalysis.h"
 #include "AliPhysicsSelection.h"
 #include "AliLog.h"
-#include "AliFMDAnaParameters.h"
+// #include "AliFMDAnaParameters.h"
 #include "AliESDEvent.h"
 #include "AliAODHandler.h"
 #include "AliMultiplicity.h"
 #include "AliInputEventHandler.h"
+#include "AliForwardCorrectionManager.h"
+#include "AliAnalysisManager.h"
 #include <TH1.h>
 #include <TDirectory.h>
 #include <TTree.h>
+#include <TROOT.h>
+#include <iostream>
+#include <iomanip>
 
 //====================================================================
-AliForwardMultiplicity::AliForwardMultiplicity()
+AliForwardMultiplicityTask::AliForwardMultiplicityTask()
   : AliAnalysisTaskSE(),
+    fEnableLowFlux(true),
     fHData(0),
     fFirstEvent(true),
     fESDFMD(),
@@ -30,8 +36,9 @@ AliForwardMultiplicity::AliForwardMultiplicity()
 }
 
 //____________________________________________________________________
-AliForwardMultiplicity::AliForwardMultiplicity(const char* name)
+AliForwardMultiplicityTask::AliForwardMultiplicityTask(const char* name)
   : AliAnalysisTaskSE(name), 
+    fEnableLowFlux(true),
     fHData(0),
     fFirstEvent(true),
     fESDFMD(),
@@ -49,8 +56,9 @@ AliForwardMultiplicity::AliForwardMultiplicity(const char* name)
 }
 
 //____________________________________________________________________
-AliForwardMultiplicity::AliForwardMultiplicity(const AliForwardMultiplicity& o)
+AliForwardMultiplicityTask::AliForwardMultiplicityTask(const AliForwardMultiplicityTask& o)
   : AliAnalysisTaskSE(o),
+    fEnableLowFlux(o.fEnableLowFlux),
     fHData(o.fHData),
     fFirstEvent(true),
     fESDFMD(o.fESDFMD),
@@ -64,14 +72,16 @@ AliForwardMultiplicity::AliForwardMultiplicity(const AliForwardMultiplicity& o)
     fHistCollector(o.fHistCollector),
     fList(o.fList) 
 {
+  DefineOutput(1, TList::Class());
 }
 
 //____________________________________________________________________
-AliForwardMultiplicity&
-AliForwardMultiplicity::operator=(const AliForwardMultiplicity& o)
+AliForwardMultiplicityTask&
+AliForwardMultiplicityTask::operator=(const AliForwardMultiplicityTask& o)
 {
   AliAnalysisTaskSE::operator=(o);
 
+  fEnableLowFlux     = o.fEnableLowFlux;
   fHData             = o.fHData;
   fFirstEvent        = o.fFirstEvent;
   fEventInspector    = o.fEventInspector;
@@ -89,7 +99,7 @@ AliForwardMultiplicity::operator=(const AliForwardMultiplicity& o)
 
 //____________________________________________________________________
 void
-AliForwardMultiplicity::SetDebug(Int_t dbg)
+AliForwardMultiplicityTask::SetDebug(Int_t dbg)
 {
   fEventInspector.SetDebug(dbg);
   fEnergyFitter.SetDebug(dbg);
@@ -101,43 +111,88 @@ AliForwardMultiplicity::SetDebug(Int_t dbg)
 
 //____________________________________________________________________
 void
-AliForwardMultiplicity::Init()
+AliForwardMultiplicityTask::Init()
 {
   fFirstEvent = true;
 }
 
 //____________________________________________________________________
 void
-AliForwardMultiplicity::InitializeSubs()
+AliForwardMultiplicityTask::InitializeSubs()
 {
-  AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
-  pars->Init(kTRUE);
 
+  // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+  // pars->Init(kTRUE);
+
+  AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
+  fcm.Init(fEventInspector.GetCollisionSystem(), 
+          fEventInspector.GetEnergy(),
+          fEventInspector.GetField());
+  // Check that we have the energy loss fits, needed by 
+  //   AliFMDSharingFilter 
+  //   AliFMDDensityCalculator 
+  if (!fcm.GetELossFit()) { 
+    AliFatal(Form("No energy loss fits"));
+    return;
+  }
+  // Check that we have the double hit correction - (optionally) used by 
+  //  AliFMDDensityCalculator 
+  if (!fcm.GetDoubleHit()) {
+    AliWarning("No double hit corrections"); 
+  }
+  // Check that we have the secondary maps, needed by 
+  //   AliFMDCorrections 
+  //   AliFMDHistCollector
+  if (!fcm.GetSecondaryMap()) {
+    AliFatal("No secondary corrections");
+    return;
+  }
+  // Check that we have the vertex bias correction, needed by 
+  //   AliFMDCorrections 
+  if (!fcm.GetVertexBias()) { 
+    AliFatal("No event vertex bias corrections");
+    return;
+  }
+  // Check that we have the merging efficiencies, optionally used by 
+  //   AliFMDCorrections 
+  if (!fcm.GetMergingEfficiency()) {
+    AliWarning("No merging efficiencies");
+  }
+
+
+  const TAxis* pe = fcm.GetEtaAxis();
+  const TAxis* pv = fcm.GetVertexAxis();
+  if (!pe) AliFatal("No eta axis defined");
+  if (!pv) AliFatal("No vertex axis defined");
 
-  TAxis e(pars->GetNetaBins(),  pars->GetEtaMin(),  pars->GetEtaMax());
-  TAxis v(pars->GetNvtxBins(), -pars->GetVtxCutZ(), pars->GetVtxCutZ());
-                       
-  fHistos.Init(e);
-  fAODFMD.Init(e);
+  // TAxis e(pars->GetNetaBins(),  pars->GetEtaMin(),  pars->GetEtaMax());
+  // TAxis v(pars->GetNvtxBins(), -pars->GetVtxCutZ(), pars->GetVtxCutZ());
+  // pv->Dump();
+
+  fHistos.Init(*pe);
+  fAODFMD.Init(*pe);
 
   fHData = static_cast<TH2D*>(fAODFMD.GetHistogram().Clone("d2Ndetadphi"));
   fHData->SetStats(0);
   fHData->SetDirectory(0);
   fList->Add(fHData);
 
-  fEnergyFitter.Init(e);
-  fEventInspector.Init(v);
-  fHistCollector.Init(v);
+  fEnergyFitter.Init(*pe);
+  fEventInspector.Init(*pv);
+  fHistCollector.Init(*pv);
+
+  this->Print();
 }
 
 //____________________________________________________________________
 void
-AliForwardMultiplicity::UserCreateOutputObjects()
+AliForwardMultiplicityTask::UserCreateOutputObjects()
 {
   fList = new TList;
 
   AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
-  AliAODHandler*      ah = dynamic_cast<AliAODHandler*>(am->GetOutputEventHandler());
+  AliAODHandler*      ah = 
+    dynamic_cast<AliAODHandler*>(am->GetOutputEventHandler());
   if (!ah) AliFatal("No AOD output handler set in analysis manager");
     
     
@@ -149,13 +204,18 @@ AliForwardMultiplicity::UserCreateOutputObjects()
   fSharingFilter.DefineOutput(fList);
   fDensityCalculator.DefineOutput(fList);
   fCorrections.DefineOutput(fList);
+
+  PostData(1, fList);
 }
 //____________________________________________________________________
 void
-AliForwardMultiplicity::UserExec(Option_t*)
+AliForwardMultiplicityTask::UserExec(Option_t*)
 {
+  // static Int_t cnt = 0;
+  // cnt++;
   // Get the input data 
   AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());
+  // AliInfo(Form("Event # %6d (esd=%p)", cnt, esd));
   if (!esd) { 
     AliWarning("No ESD event found for input event");
     return;
@@ -163,7 +223,8 @@ AliForwardMultiplicity::UserExec(Option_t*)
 
   // On the first event, initialize the parameters 
   if (fFirstEvent && esd->GetESDRun()) { 
-    AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+    fEventInspector.ReadRunDetails(esd);
+    
     AliInfo(Form("Initializing with parameters from the ESD:\n"
                 "         AliESDEvent::GetBeamEnergy()   ->%f\n"
                 "         AliESDEvent::GetBeamType()     ->%s\n"
@@ -175,8 +236,12 @@ AliForwardMultiplicity::UserExec(Option_t*)
                 esd->GetCurrentL3(), 
                 esd->GetMagneticField(),
                 esd->GetRunNumber()));
-    pars->SetParametersFromESD(esd);
-    pars->PrintStatus();
+
+             
+
+    // AliFMDAnaParameters* pars = AliFMDAnaParameters::Instance();
+    // pars->SetParametersFromESD(esd);
+    // pars->PrintStatus();
     fFirstEvent = false;
 
     InitializeSubs();
@@ -188,7 +253,7 @@ AliForwardMultiplicity::UserExec(Option_t*)
 
   Bool_t   lowFlux  = kFALSE;
   UInt_t   triggers = 0;
-  Int_t    ivz      = -1;
+  UShort_t ivz      = 0;
   Double_t vz       = 0;
   UInt_t   found    = fEventInspector.Process(esd, triggers, lowFlux, ivz, vz);
   if (found & AliFMDEventInspector::kNoEvent)    return;
@@ -205,6 +270,9 @@ AliForwardMultiplicity::UserExec(Option_t*)
 
   if (found & AliFMDEventInspector::kBadVertex) return;
 
+  // We we do not want to use low flux specific code, we disable it here. 
+  if (!fEnableLowFlux) lowFlux = false;
+
   // Get FMD data 
   AliESDFMD* esdFMD = esd->GetFMDData();
   // Apply the sharing filter (or hit merging or clustering if you like)
@@ -244,7 +312,7 @@ AliForwardMultiplicity::UserExec(Option_t*)
 
 //____________________________________________________________________
 void
-AliForwardMultiplicity::Terminate(Option_t*)
+AliForwardMultiplicityTask::Terminate(Option_t*)
 {
   TList* list = dynamic_cast<TList*>(GetOutputData(1));
   if (!list) {
@@ -276,7 +344,7 @@ AliForwardMultiplicity::Terminate(Option_t*)
   
   // TH1D* dNdeta = fHData->ProjectionX("dNdeta", 0, -1, "e");
   TH1D* dNdeta = hData->ProjectionX("dNdeta", 1, -1, "e");
-  TH1D* norm   = hData->ProjectionX("dNdeta", 0, 1,  "");
+  TH1D* norm   = hData->ProjectionX("norm",   0,  1,  "");
   dNdeta->SetTitle("dN_{ch}/d#eta in the forward regions");
   dNdeta->SetYTitle("#frac{1}{N}#frac{dN_{ch}}{d#eta}");
   dNdeta->Divide(norm);
@@ -284,6 +352,7 @@ AliForwardMultiplicity::Terminate(Option_t*)
   dNdeta->Scale(Double_t(hEventsTrVtx->GetEntries())/hEventsTr->GetEntries(),
                "width");
   list->Add(dNdeta);
+  list->Add(norm);
 
   fEnergyFitter.Fit(list);
   fSharingFilter.ScaleHistograms(list,hEventsTr->Integral());
@@ -293,7 +362,7 @@ AliForwardMultiplicity::Terminate(Option_t*)
 
 //____________________________________________________________________
 void
-AliForwardMultiplicity::MarkEventForStore() const
+AliForwardMultiplicityTask::MarkEventForStore() const
 {
   // Make sure the AOD tree is filled 
   AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
@@ -307,8 +376,19 @@ AliForwardMultiplicity::MarkEventForStore() const
 
 //____________________________________________________________________
 void
-AliForwardMultiplicity::Print(Option_t*) const
+AliForwardMultiplicityTask::Print(Option_t* option) const
 {
+  std::cout << "AliForwardMultiplicityTask: " << GetName() << "\n" 
+           << "  Enable low flux code:   " << (fEnableLowFlux ? "yes" : "no")
+           << std::endl;
+  gROOT->IncreaseDirLevel();
+  fEventInspector   .Print(option);
+  fEnergyFitter     .Print(option);    
+  fSharingFilter    .Print(option);
+  fDensityCalculator.Print(option);
+  fCorrections      .Print(option);
+  fHistCollector    .Print(option);
+  gROOT->DecreaseDirLevel();
 }
 
 //
@@ -45,7 +45,7 @@ class TTree;
  * @ingroup pwg2_forward_analysis 
  * 
  */
-class AliForwardMultiplicity : public AliAnalysisTaskSE
+class AliForwardMultiplicityTask : public AliAnalysisTaskSE
 {
 public:
   /** 
@@ -53,17 +53,17 @@ public:
    * 
    * @param name Name of task 
    */
-  AliForwardMultiplicity(const char* name);
+  AliForwardMultiplicityTask(const char* name);
   /** 
    * Constructor
    */
-  AliForwardMultiplicity();
+  AliForwardMultiplicityTask();
   /** 
    * Copy constructor 
    * 
    * @param o Object to copy from 
    */
-  AliForwardMultiplicity(const AliForwardMultiplicity& o);
+  AliForwardMultiplicityTask(const AliForwardMultiplicityTask& o);
   /** 
    * Assignment operator 
    * 
@@ -71,7 +71,7 @@ public:
    * 
    * @return Reference to this object 
    */
-  AliForwardMultiplicity& operator=(const AliForwardMultiplicity& o);
+  AliForwardMultiplicityTask& operator=(const AliForwardMultiplicityTask& o);
   /** 
    * @{ 
    * @name Interface methods 
@@ -101,8 +101,18 @@ public:
   /** 
    * @} 
    */
+  /** 
+   * Print information 
+   * 
+   * @param option Not used
+   */
   void Print(Option_t* option="") const;
-
+  /** 
+   * Whether to enable low-flux code 
+   * 
+   * @param use IF true, enable low-flux code 
+   */
+  void SetEnableLowFlux(Bool_t use=true) { fEnableLowFlux = use; }
   /** 
    * @{ 
    * @name Access to sub-algorithms 
@@ -159,6 +169,7 @@ protected:
    */
   virtual void MarkEventForStore() const;
 
+  Bool_t                 fEnableLowFlux;// Whether to use low-flux specific code
   TH2D*                  fHData;        // Summed 1/Nd^2N_{ch}/dphideta
   Bool_t                 fFirstEvent;   // Whether the event is the first seen 
   AliESDFMD              fESDFMD;       // Sharing corrected ESD object
@@ -174,7 +185,7 @@ protected:
 
   TList* fList; // Output list 
 
-  ClassDef(AliForwardMultiplicity,1) // Forward multiplicity class
+  ClassDef(AliForwardMultiplicityTask,1) // Forward multiplicity class
 };
 
 #endif
index 3636dca..a4867c0 100644 (file)
 #include <TError.h>
 
 //====================================================================
+UShort_t
+AliForwardUtil::ParseCollisionSystem(const char* sys)
+{
+  TString s(sys);
+  s.ToLower();
+  if (s.Contains("p-p")   || s.Contains("pp"))   return AliForwardUtil::kPP; 
+  if (s.Contains("pb-pb") || s.Contains("pbpb")) return AliForwardUtil::kPbPb;
+  if (s.Contains("a-a")   || s.Contains("aa"))   return AliForwardUtil::kPbPb;
+  return AliForwardUtil::kUnknown;
+}
+//____________________________________________________________________
+const char*
+AliForwardUtil::CollisionSystemString(UShort_t sys)
+{
+  switch (sys) { 
+  case AliForwardUtil::kPP:   return "pp";
+  case AliForwardUtil::kPbPb: return "PbPb";
+  }
+  return "unknown";
+}
+//____________________________________________________________________
+UShort_t
+AliForwardUtil::ParseCenterOfMassEnergy(UShort_t sys, Float_t v)
+{
+  Float_t energy = v; 
+  if (sys != AliForwardUtil::kPP) energy = energy / 208 * 82;
+  if (TMath::Abs(energy - 900.)   < 10)  return 900;
+  if (TMath::Abs(energy - 2400.)  < 10)  return 2400;
+  if (TMath::Abs(energy - 2750.)  < 10)  return 2750;
+  if (TMath::Abs(energy - 5500.)  < 40)  return 5500;
+  if (TMath::Abs(energy - 7000.)  < 10)  return 7000;
+  if (TMath::Abs(energy - 10000.) < 10)  return 10000;
+  if (TMath::Abs(energy - 14000.) < 10)  return 14000;
+  return 0;
+}
+//____________________________________________________________________
+const char* 
+AliForwardUtil::CenterOfMassEnergyString(UShort_t cms)
+{
+  return Form("%04dGeV", cms);
+}
+//____________________________________________________________________
+Short_t
+AliForwardUtil::ParseMagneticField(Float_t v)
+{
+  if (TMath::Abs(v - 5.) < 1 ) return +5;
+  if (TMath::Abs(v + 5.) < 1 ) return -5;
+  if (TMath::Abs(v) < 1)       return 0;
+  return 999;
+}
+//____________________________________________________________________
+const char* 
+AliForwardUtil::MagneticFieldString(Short_t f)
+{
+  return Form("%01dkG", f);
+}
+
+
+//====================================================================
 Int_t    AliForwardUtil::fgConvolutionSteps  = 100;
 Double_t AliForwardUtil::fgConvolutionNSigma = 5;
 namespace {
@@ -59,6 +118,21 @@ namespace {
     return constant * AliForwardUtil::NLandauGaus(x, delta, xi, sigma, sigma_n,
                                                  n, a);
   }
+  /** 
+   * Utility function to use in TF1 defintition 
+   */
+  Double_t landauGausI(Double_t* xp, Double_t* pp) 
+  {
+    Double_t x         = xp[0];
+    Double_t constant  = pp[AliForwardUtil::ELossFitter::kC];
+    Double_t delta     = pp[AliForwardUtil::ELossFitter::kDelta];
+    Double_t xi        = pp[AliForwardUtil::ELossFitter::kXi];
+    Double_t sigma     = pp[AliForwardUtil::ELossFitter::kSigma];
+    Double_t sigma_n   = pp[AliForwardUtil::ELossFitter::kSigmaN];
+    Int_t    i         = Int_t(pp[AliForwardUtil::ELossFitter::kN]);
+
+    return constant * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigma_n,i);
+  }
 
 
 }
@@ -93,21 +167,157 @@ AliForwardUtil::LandauGaus(Double_t x, Double_t delta, Double_t xi,
 
 //____________________________________________________________________
 Double_t 
+AliForwardUtil::ILandauGaus(Double_t x, Double_t delta, Double_t xi, 
+                           Double_t sigma, Double_t sigma_n, Int_t i)
+{
+  Double_t delta_i =  (i == 1 ? delta : i * (delta + xi * TMath::Log(i)));
+  Double_t xi_i    =  i * xi;
+  Double_t sigma_i =  (i == 1 ? sigma : TMath::Sqrt(Double_t(i))*sigma);
+  if (sigma_i < 1e-10) { 
+    // Fall back to landau 
+    return AliForwardUtil::Landau(x, delta_i, xi_i);
+  }
+  return AliForwardUtil::LandauGaus(x, delta_i, xi_i, sigma_i, sigma_n);
+}
+
+//____________________________________________________________________
+Double_t 
+AliForwardUtil::IdLandauGausdPar(Double_t x, 
+                                UShort_t par,   Double_t dPar, 
+                                Double_t delta, Double_t xi, 
+                                Double_t sigma, Double_t sigma_n, 
+                                Int_t    i)
+{
+  if (dPar == 0) return 0;
+  Double_t dp      = dPar;
+  Double_t d2      = dPar / 2;
+  Double_t delta_i =  i * (delta + xi * TMath::Log(i));
+  Double_t xi_i    =  i * xi;
+  Double_t si      =  TMath::Sqrt(Double_t(i));
+  Double_t sigma_i =  si*sigma;
+  Double_t y1      = 0;
+  Double_t y2      = 0;
+  Double_t y3      = 0;
+  Double_t y4      = 0;
+  switch (par) {
+  case 0: 
+    y1 = ILandauGaus(x, delta_i+i*dp, xi_i, sigma_i, sigma_n, i);
+    y2 = ILandauGaus(x, delta_i+i*d2, xi_i, sigma_i, sigma_n, i);
+    y3 = ILandauGaus(x, delta_i-i*d2, xi_i, sigma_i, sigma_n, i);
+    y4 = ILandauGaus(x, delta_i-i*dp, xi_i, sigma_i, sigma_n, i);
+    break;
+  case 1: 
+    y1 = ILandauGaus(x, delta_i, xi_i+i*dp, sigma_i, sigma_n, i);
+    y2 = ILandauGaus(x, delta_i, xi_i+i*d2, sigma_i, sigma_n, i);
+    y3 = ILandauGaus(x, delta_i, xi_i-i*d2, sigma_i, sigma_n, i);
+    y4 = ILandauGaus(x, delta_i, xi_i-i*dp, sigma_i, sigma_n, i);
+    break;
+  case 2: 
+    y1 = ILandauGaus(x, delta_i, xi_i, sigma_i+si*dp, sigma_n, i);
+    y2 = ILandauGaus(x, delta_i, xi_i, sigma_i+si*d2, sigma_n, i);
+    y3 = ILandauGaus(x, delta_i, xi_i, sigma_i-si*d2, sigma_n, i);
+    y4 = ILandauGaus(x, delta_i, xi_i, sigma_i-si*dp, sigma_n, i);
+    break;
+  case 3: 
+    y1 = ILandauGaus(x, delta_i, xi_i, sigma_i, sigma_n+dp, i);
+    y2 = ILandauGaus(x, delta_i, xi_i, sigma_i, sigma_n+d2, i);
+    y3 = ILandauGaus(x, delta_i, xi_i, sigma_i, sigma_n-d2, i);
+    y4 = ILandauGaus(x, delta_i, xi_i, sigma_i, sigma_n-dp, i);
+    break;
+  default:
+    return 0;
+  } 
+  
+  Double_t d0  = y1 - y4;
+  Double_t d1  = 2 * (y2 - y3);
+  
+  Double_t g   = 1/(2*dp) * (4*d1 - d0) / 3;
+   
+  return g;
+}
+
+//____________________________________________________________________
+Double_t 
 AliForwardUtil::NLandauGaus(Double_t x, Double_t delta, Double_t xi, 
                            Double_t sigma, Double_t sigma_n, Int_t n, 
                            Double_t* a)
 {
-  Double_t result = LandauGaus(x, delta, xi, sigma, sigma_n);
-  for (Int_t i = 2; i <= n; i++) { 
-    Double_t delta_i =  i * (delta + xi * TMath::Log(i));
-    Double_t xi_i    =  i * xi;
-    Double_t sigma_i =  TMath::Sqrt(Double_t(n))*sigma;
-    Double_t a_i     =  a[i-2];
-    result           += a_i * AliForwardUtil::LandauGaus(x, delta_i, xi_i, 
-                                                        sigma_i, sigma_n);
-  }
+  Double_t result = ILandauGaus(x, delta, xi, sigma, sigma_n, 1);
+  for (Int_t i = 2; i <= n; i++) 
+    result += a[i-2] * AliForwardUtil::ILandauGaus(x,delta,xi,sigma,sigma_n,i);
   return result;
 }
+namespace { 
+  const Int_t kColors[] = { kRed+1, 
+                           kPink+3, 
+                           kMagenta+2, 
+                           kViolet+2, 
+                           kBlue+1, 
+                           kAzure+3, 
+                           kCyan+1, 
+                           kTeal+2, 
+                           kGreen+2, 
+                           kSpring+3, 
+                           kYellow+2, 
+                           kOrange+2 };
+}
+
+//____________________________________________________________________
+TF1*
+AliForwardUtil::MakeNLandauGaus(Double_t  c, 
+                               Double_t  delta, Double_t xi, 
+                               Double_t  sigma, Double_t sigma_n, Int_t n, 
+                               Double_t* a, 
+                               Double_t  xmin, Double_t xmax)
+{
+  Int_t npar       = AliForwardUtil::ELossFitter::kN+n;
+  TF1* landaun     = new TF1(Form("nlandau%d", n), &landauGausN,xmin,xmax,npar);
+  // landaun->SetLineStyle(((n-2) % 10)+2); // start at dashed
+  landaun->SetLineColor(kColors[((n-1) % 12)]); // start at red
+  landaun->SetLineWidth(2);
+  landaun->SetNpx(500);
+  landaun->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "N");
+
+  // Set the initial parameters from the seed fit 
+  landaun->SetParameter(AliForwardUtil::ELossFitter::kC,      c);       
+  landaun->SetParameter(AliForwardUtil::ELossFitter::kDelta,  delta);   
+  landaun->SetParameter(AliForwardUtil::ELossFitter::kXi,     xi);      
+  landaun->SetParameter(AliForwardUtil::ELossFitter::kSigma,  sigma);   
+  landaun->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigma_n); 
+  landaun->FixParameter(AliForwardUtil::ELossFitter::kN,      n);       
+
+  // Set the range and name of the scale parameters 
+  for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit 
+    landaun->SetParameter(AliForwardUtil::ELossFitter::kA+i-2, a[i-2]);
+    landaun->SetParName(AliForwardUtil::ELossFitter::kA+i-2, Form("a_{%d}", i));
+  }
+  return landaun;
+}
+//____________________________________________________________________
+TF1*
+AliForwardUtil::MakeILandauGaus(Double_t  c, 
+                               Double_t  delta, Double_t xi, 
+                               Double_t  sigma, Double_t sigma_n, Int_t i, 
+                               Double_t  xmin, Double_t xmax)
+{
+  Int_t npar       = AliForwardUtil::ELossFitter::kN+1;
+  TF1* landaui     = new TF1(Form("ilandau%d", i), &landauGausI,xmin,xmax,npar);
+  // landaui->SetLineStyle(((i-2) % 10)+2); // start at dashed
+  landaui->SetLineColor(kColors[((i-1) % 12)]); // start at red
+  landaui->SetLineWidth(1);
+  landaui->SetNpx(500);
+  landaui->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "i");
+
+  // Set the initial parameters from the seed fit 
+  landaui->SetParameter(AliForwardUtil::ELossFitter::kC,      c);       
+  landaui->SetParameter(AliForwardUtil::ELossFitter::kDelta,  delta);   
+  landaui->SetParameter(AliForwardUtil::ELossFitter::kXi,     xi);      
+  landaui->SetParameter(AliForwardUtil::ELossFitter::kSigma,  sigma);   
+  landaui->SetParameter(AliForwardUtil::ELossFitter::kSigmaN, sigma_n); 
+  landaui->FixParameter(AliForwardUtil::ELossFitter::kN,      i);       
+
+  return landaui;
+}
 
 //====================================================================
 AliForwardUtil::ELossFitter::ELossFitter(Double_t lowCut, 
@@ -156,7 +366,7 @@ AliForwardUtil::ELossFitter::Fit1Particle(TH1* dist, Double_t sigman)
   dist->GetXaxis()->SetRangeUser(0, fMaxRange);
   
   // Define the function to fit 
-  TF1*          landau1 = new TF1("landau1", landauGaus1, minE,maxEE,kSigmaN+1);
+  TF1* landau1 = new TF1("landau1", landauGaus1, minE,maxEE,kSigmaN+1);
 
   // Set initial guesses, parameter names, and limits  
   landau1->SetParameters(1,0.5,0.07,0.1,sigman);
@@ -199,34 +409,27 @@ AliForwardUtil::ELossFitter::FitNParticle(TH1* dist, UShort_t n,
   Double_t maxEi   = n * (delta1 + xi1 * TMath::Log(n)) + 2 * n * xi1;
   Double_t minE    = f->GetXmin();
 
+  // Array of weights 
+  TArrayD a(n-1);
+  for (UShort_t i = 2; i <= n; i++) 
+    a.fArray[i-2] = (n == 2 ? 0.05 : 0.000001);
   // Make the fit function 
-  TF1* landaun     = new TF1(Form("landau%d", n), &landauGausN,minE,maxEi,kN+n);
-  landaun->SetLineStyle(((n-2) % 10)+2); // start at dashed
-  landaun->SetLineColor(((n-2) % 10)+2); // start at red
-  landaun->SetLineWidth(1);
-  landaun->SetNpx(500);
-  landaun->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}", "N");
-
-  // Set the initial parameters from the seed fit 
-  landaun->SetParameter(kC,      r->Parameter(kC));      // Constant
-  landaun->SetParameter(kDelta,  r->Parameter(kDelta));  // Delta 
-  landaun->SetParameter(kXi,     r->Parameter(kXi));     // xi
-  landaun->SetParameter(kSigma,  r->Parameter(kSigma));  // sigma
-  landaun->SetParameter(kSigmaN, r->Parameter(kSigmaN)); // sigma_n
+  TF1* landaun     = MakeNLandauGaus(r->Parameter(kC),
+                                    r->Parameter(kDelta),
+                                    r->Parameter(kXi),
+                                    r->Parameter(kSigma),
+                                    r->Parameter(kSigmaN),
+                                    n,a.fArray,minE,maxEi);
   landaun->SetParLimits(kDelta,  minE, fMaxRange);       // Delta
   landaun->SetParLimits(kXi,     0.00, fMaxRange);       // xi
   landaun->SetParLimits(kSigma,  0.01, 1);            // sigma
   // Check if we're using the noise sigma 
   if (sigman <= 0)  landaun->FixParameter(kSigmaN, 0);
   else              landaun->SetParLimits(kSigmaN, 0, fMaxRange);
-  // Fix the number parameter 
-  landaun->FixParameter(kN, n);               // N
 
   // Set the range and name of the scale parameters 
   for (UShort_t i = 2; i <= n; i++) {// Take parameters from last fit 
-    landaun->SetParameter(kA+i-2, n == 2 ? 0.05 : 0.000001);
     landaun->SetParLimits(kA+i-2, 0,1);
-    landaun->SetParName(kA+i-2, Form("a_{%d}", i));
   }
 
   // Do the fit 
index 61a2bab..938678b 100644 (file)
@@ -18,6 +18,86 @@ class AliESDEvent;
 class AliForwardUtil : public TObject
 {
 public:
+  //==================================================================
+  /** 
+   * @{ 
+   * @nane Collision/run parameters 
+   */
+  /**                                          
+   * Defined collision types 
+   */
+  enum ECollisionSystem {
+    kUnknown, 
+    kPP, 
+    kPbPb
+  };
+  //__________________________________________________________________
+  /** 
+   * Parse a collision system spec given in a string.   Known values are 
+   * 
+   *  - "pp", "p-p" which returns kPP 
+   *  - "PbPb", "Pb-Pb", "A-A", which returns kPbPb 
+   *  - Everything else gives kUnknown 
+   * 
+   * @param sys Collision system spec 
+   * 
+   * @return Collision system id 
+   */
+  static UShort_t ParseCollisionSystem(const char* sys);
+  /** 
+   * Get a string representation of the collision system 
+   * 
+   * @param sys  Collision system 
+   * - kPP -> "pp"
+   * - kPbPb -> "PbPb" 
+   * - anything else gives "unknown"
+   * 
+   * @return String representation of the collision system 
+   */
+  static const char* CollisionSystemString(UShort_t sys);
+  //__________________________________________________________________
+  /** 
+   * Parse the center of mass energy given as a float and return known 
+   * values as a unsigned integer
+   * 
+   * @param sys  Collision system (needed for AA)
+   * @param cms  Center of mass energy * total charge 
+   * 
+   * @return Center of mass energy per nucleon
+   */
+  static UShort_t ParseCenterOfMassEnergy(UShort_t sys, Float_t cms);
+  /** 
+   * Get a string representation of the center of mass energy per nuclean
+   * 
+   * @param sys  Collision system 
+   * @param sNN  Center of mass energy per nucleon
+   * 
+   * @return String representation of the center of mass energy per nuclean
+   */
+  static const char* CenterOfMassEnergyString(UShort_t cms);
+  //__________________________________________________________________
+  /** 
+   * Parse the magnetic field (in kG) as given by a floating point number
+   * 
+   * @param field  Magnetic field in kG 
+   * 
+   * @return Short integer value of magnetic field in kG 
+   */
+  static Short_t ParseMagneticField(Float_t field);
+  /** 
+   * Get a string representation of the magnetic field
+   * 
+   * @param field Magnetic field in kG
+   * 
+   * @return String representation of the magnetic field
+   */
+  static const char* MagneticFieldString(Short_t field);
+  /* @} */
+
+  /** 
+   * @{ 
+   * @name Energy stragling functions 
+   */
   //__________________________________________________________________
   /**
    * Number of steps to do in the Landau, Gaussiam convolution 
@@ -82,13 +162,78 @@ public:
    */
   static Double_t LandauGaus(Double_t x, Double_t delta, Double_t xi, 
                             Double_t sigma, Double_t sigma_n);
-  
+
+  //------------------------------------------------------------------
+  /** 
+   * Evaluate 
+   * @f[ 
+   *    f_i(x;\Delta,\xi,\sigma') = f(x;\Delta_i,\xi_i,\sigma_i')
+   * @f] 
+   * corresponding to @f$ i@f$ particles i.e., with the substitutions 
+   * @f[ 
+   *    \Delta    \rightarrow \Delta_i    = i(\Delta + \xi\log(i))\\
+   *    \xi       \rightarrow \xi_i       = i \xi\\
+   *    \sigma    \rightarrow \sigma_i    = \sqrt{i}\sigma\\
+   *    \sigma'^2 \rightarrow \sigma_i'^2 = \sigma_n^2 + \sigma_i^2
+   * @f] 
+   * 
+   * @param x        Where to evaluate 
+   * @param delta    @f$ \Delta@f$ 
+   * @param xi       @f$ \xi@f$ 
+   * @param sigma    @f$ \sigma@f$ 
+   * @param sigma_n  @f$ \sigma_n@f$
+   * @param i        @f$ i@f$
+   * 
+   * @return @f$ f_i@f$ evaluated
+   */  
+  static Double_t ILandauGaus(Double_t x, Double_t delta, Double_t xi, 
+                             Double_t sigma, Double_t sigma_n, Int_t i);
+
+  //------------------------------------------------------------------
+  /** 
+   * Numerically evaluate 
+   * @f[ 
+   *    \left.\frac{\partial f_i}{\partial p_i}\right|_{x}
+   * @f] 
+   * where @f$ p_i@f$ is the @f$ i^{\mbox{th}}@f$ parameter.  The mapping 
+   * of the parameters is given by 
+   *
+   * - 0: @f$\Delta@f$ 
+   * - 1: @f$\xi@f$ 
+   * - 2: @f$\sigma@f$ 
+   * - 3: @f$\sigma_n@f$ 
+   *
+   * This is the partial derivative with respect to the parameter of
+   * the response function corresponding to @f$ i@f$ particles i.e.,
+   * with the substitutions
+   * @f[ 
+   *    \Delta    \rightarrow \Delta_i    = i(\Delta + \xi\log(i))\\
+   *    \xi       \rightarrow \xi_i       = i \xi\\
+   *    \sigma    \rightarrow \sigma_i    = \sqrt{i}\sigma\\
+   *    \sigma'^2 \rightarrow \sigma_i'^2 = \sigma_n^2 + \sigma_i^2
+   * @f] 
+   * 
+   * @param x        Where to evaluate 
+   * @param ipar     Parameter number 
+   * @param dp       @f$ \esilon\delta p_i@f$ for some value of @f$\epsilon@f$
+   * @param delta    @f$ \Delta@f$ 
+   * @param xi       @f$ \xi@f$ 
+   * @param sigma    @f$ \sigma@f$ 
+   * @param sigma_n  @f$ \sigma_n@f$
+   * @param i        @f$ i@f$
+   * 
+   * @return @f$ f_i@f$ evaluated
+   */  
+  static Double_t IdLandauGausdPar(Double_t x, UShort_t ipar, Double_t dp,
+                                  Double_t delta, Double_t xi, 
+                                  Double_t sigma, Double_t sigma_n, Int_t i);
+
   //------------------------------------------------------------------
   /** 
    * Evaluate 
    * @f[ 
-      f_N(x;\Delta,\xi,\sigma') = \sum_{i=1}^N a_i f(x;\Delta_i,\xi_i,\sigma'_i)
-     @f] 
+   *   f_N(x;\Delta,\xi,\sigma') = \sum_{i=1}^N a_i f_i(x;\Delta,\xi,\sigma'a)
+   * @f] 
    * 
    * where @f$ f(x;\Delta,\xi,\sigma')@f$ is the convolution of a
    * Landau with a Gaussian (see LandauGaus).  Note that 
@@ -114,6 +259,47 @@ public:
   static Double_t NLandauGaus(Double_t x, Double_t delta, Double_t xi, 
                              Double_t sigma, Double_t sigma_n, Int_t n, 
                              Double_t* a);
+  /** 
+   * Generate a TF1 object of @f$ f_I@f$ 
+   * 
+   * @param c        Constant
+   * @param delta    @f$ \Delta@f$ 
+   * @param xi       @f$ \xi_1@f$             
+   * @param sigma    @f$ \sigma_1@f$          
+   * @param sigma_n  @f$ \sigma_n@f$          
+   * @param i       @f$ i@f$ - the number of particles
+   * @param xmin     Least value of range
+   * @param xmax     Largest value of range
+   * 
+   * @return Newly allocated TF1 object
+   */
+  static TF1* MakeILandauGaus(Double_t c, 
+                             Double_t delta, Double_t xi, 
+                             Double_t sigma, Double_t sigma_n,
+                             Int_t    i, 
+                             Double_t xmin,  Double_t  xmax);
+  /** 
+   * Generate a TF1 object of @f$ f_N@f$ 
+   * 
+   * @param c         Constant                        
+   * @param delta     @f$ \Delta@f$                   
+   * @param xi               @f$ \xi_1@f$                     
+   * @param sigma     @f$ \sigma_1@f$                 
+   * @param sigma_n   @f$ \sigma_n@f$                 
+   * @param n        @f$ N@f$ - how many particles to sum to
+   * @param a         Array of size @f$ N-1@f$ of the weights @f$ a_i@f$ for 
+   *                  @f$ i > 1@f$ 
+   * @param xmin      Least value of range  
+   * @param xmax      Largest value of range
+   * 
+   * @return Newly allocated TF1 object
+   */
+  static TF1* MakeNLandauGaus(Double_t c, 
+                             Double_t delta, Double_t  xi, 
+                             Double_t sigma, Double_t  sigma_n,
+                             Int_t    n,     Double_t* a, 
+                             Double_t xmin,  Double_t  xmax);
+                                                   
   //__________________________________________________________________
   /** 
    * Structure to do fits to the energy loss spectrum 
@@ -179,9 +365,14 @@ public:
     TObjArray fFitResults;      // Array of fit results 
     TObjArray fFunctions;       // Array of functions 
   };
+  /* @} */
       
 
-  //__________________________________________________________________
+  //==================================================================
+  /** 
+   * @{
+   * @name Convenience containers 
+   */
   /** 
    * Structure to hold histograms 
    *
@@ -293,6 +484,7 @@ public:
 
     ClassDef(RingHistos,1) 
   };
+  /* @} */
     
 };
 
index c9ca2ad..859711e 100644 (file)
@@ -500,7 +500,7 @@ public:
     Bool_t hasOther = (other && other->GetListOfGraphs() && 
                       other->GetListOfGraphs()->GetEntries() > 0);
     Bool_t hasHhd   = (hhd && hhdsym);
-    if (!hasOther || !hasHhd) return 0;
+    if (!hasOther && !hasHhd) return 0;
 
     THStack* ratios = new THStack("ratios", "Ratios");
     if (hasOther) {
index 3b453a9..4e75693 100644 (file)
@@ -22,10 +22,10 @@ Pass2(const char* file="AliAODs.root",
       Double_t    vzMax=10, 
       Int_t       rebin=5, 
       const char* title="",
-      bool        hhd=false,
+      bool        hhd=true,
       bool        comp=true)
 {
-  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/Compile.C"); 
+  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/Compile.C"); 
   Compile("$ALICE_ROOT/PWG2/FORWARD/analysis2/DrawRes.C","g"); 
   
   Int_t trgMask; 
@@ -46,7 +46,9 @@ Pass2(const char* file="AliAODs.root",
     trgMask = 1;
     trgs.Append("INEL");
   }
-  
+  TString tit(title);
+  tit.ReplaceAll("@", " ");
+
   printf("--------------------------------------\n"
          "Settings for this:\n"
          "  Input AOD:    %s\n" 
@@ -58,13 +60,13 @@ Pass2(const char* file="AliAODs.root",
         "  HHD comp.:    %s\n"
         "  Other comp.:  %s\n"
          "--------------------------------------\n",
-        file, vzMin, vzMax, rebin, trgMask, trgs.Data(), energy, title,
+        file, vzMin, vzMax, rebin, trgMask, trgs.Data(), energy, tit.Data(),
         hhd ? "yes" : "no", comp ? "yes" : "no");
   
   DrawRes dr;
   TStopwatch t;
   t.Start();
-  dr.Run(file, vzMin, vzMax, rebin, trgMask, energy, title, hhd, comp);
+  dr.Run(file, vzMin, vzMax, rebin, trgMask, energy, tit.Data(), hhd, comp);
   t.Stop();
   t.Print();  
 }
index 46b67af..10d62f8 100755 (executable)
@@ -1,5 +1,6 @@
 #!/bin/bash 
 
+ana=$ALICE_ROOT/PWG2/FORWARD/analysis2
 nev=10000
 noanal=0
 nodraw=0
@@ -90,6 +91,7 @@ redir=
 if test $batch -gt 0 ; then 
     opts="-l -b -q -x" 
     redir="2>&1 | tee ${base}.log"
+    echo "redir=$redir"
 fi 
 if test $noanal -lt 1 ; then 
     rm -f AnalysisResult.root AliAODs.root
@@ -112,9 +114,16 @@ if test $noanal -lt 1 ; then
     if test $gdb -gt 0 ; then 
        export PROOF_WRAPPERCMD="gdb -batch -x $ALICE_ROOT/PWG2/FORWARD/analysis2/gdb_cmds --args"
     fi
-    aliroot $opts $ALICE_ROOT/PWG2/FORWARD/analysis2/Pass1.C\(\".\",$nev,$af\) \
-       $redir 
-    rm -f event_stat.root EventStat_temp.root outputs_valid
+    echo "Running aliroot ${opts} ${ana}/Pass1.C\(\".\",$nev,$af\) $redir"
+    if test $batch -gt 0 ; then 
+       aliroot $opts ${ana}/Pass1.C\(\".\",$nev,$af\) 2>&1 | tee ${base}.log
+    else 
+       aliroot $opts ${ana}/Pass1.C\(\".\",$nev,$af\)
+    fi
+    rm -f event_stat.root \
+       EventStat_temp.root \
+       outputs_valid \
+       `printf %09d.stat $nev` 
     if test ! -f AnalysisResults.root || test ! -f AliAODs.root ; then 
        echo "Analysis failed" 
        exit 1
@@ -125,11 +134,10 @@ fi
 if test $nodraw -lt 1 ; then
     rm -f result.root 
     if test "x$tit" = "x" ; then 
-       tit="$nev\ events,\ v_{z}#in[$vzmin,$vzmax],\ $type"
-    else 
-       tit=`echo $tit | tr ' ' '\ '` 
+       tit="$nev events, v_{z}#in[$vzmin,$vzmax], $type"
     fi
-    aliroot ${opts} $ALICE_ROOT/PWG2/FORWARD/analysis2/Pass2.C\(\"AliAODs.root\",\"$type\",$cms,$vzmin,$vzmax,$rebin,\"$tit\",$hhd,$comp\)
+    tit=`echo $tit | tr ' ' '@'` 
+    aliroot ${opts} ${ana}/Pass2.C\(\"AliAODs.root\",\"$type\",$cms,$vzmin,$vzmax,$rebin,\"$tit\",$hhd,$comp\)
 fi
 
 
diff --git a/PWG2/FORWARD/analysis2/RunELossFitter.C b/PWG2/FORWARD/analysis2/RunELossFitter.C
new file mode 100644 (file)
index 0000000..e0bc0de
--- /dev/null
@@ -0,0 +1,128 @@
+/** 
+ * Flags for the analysis
+ *
+ * @ingroup pwg2_forward_analysis_scripts
+ */
+/** 
+ * Run a pass on ESD data to produce the energ loss fits 
+ * 
+ *
+ * @ingroup pwg2_forward_analysis_scripts
+ */
+void RunELossFitter(const char* esddir, 
+                   Int_t       nEvents=1000, 
+                   Bool_t      mc=false,
+                   Bool_t      proof=false)
+{
+  // --- Libraries to load -------------------------------------------
+  gROOT->Macro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadLibs.C");
+
+  // --- Check for proof mode, and possibly upload pars --------------
+  if (proof) 
+    gROOT->Macro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadPars.C");
+  
+  // --- Our data chain ----------------------------------------------
+  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/MakeESDChain.C");
+  TChain* chain = MakeESDChain(esddir);
+  // If 0 or less events is select, choose all 
+  if (nEvents <= 0) nEvents = chain->GetEntries();
+  Info("RunELossFitter", "Will analyse %d events", nEvents);
+
+  // --- Creating the manager and handlers ---------------------------
+  AliAnalysisManager *mgr  = new AliAnalysisManager("Analysis Train", 
+                                                   "FMD analysis train");
+
+  AliESDInputHandler *esdHandler = new AliESDInputHandler();
+  esdHandler->SetInactiveBranches("AliESDACORDE "
+                                 "AliRawDataErrorLogs "
+                                 "CaloClusters "
+                                 "Cascades "
+                                 "EMCALCells "
+                                 "EMCALTrigger "
+                                 "Kinks "
+                                 "Cascades "
+                                 "MuonTracks "
+                                 "TrdTracks "
+                                 "CaloClusters "
+                                 "HLTGlobalTrigger");
+  mgr->SetInputEventHandler(esdHandler);      
+  
+  // AOD output handler
+  AliAODHandler* aodHandler   = new AliAODHandler();
+  mgr->SetOutputEventHandler(aodHandler);
+  aodHandler->SetOutputFileName("AliAODs.root");
+
+  // --- Add tasks ---------------------------------------------------
+  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskFMD.C");
+  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
+  AddTaskPhysicsSelection(mc, kTRUE, kTRUE);
+  AliFMDEnergyFitterTask* task = new AliFMDEnergyFitterTask("fmdEnergyFitter");
+  mgr->AddTask(task);
+
+  // --- Make the output container and connect it --------------------
+  TString outputfile = "energyFits.root";
+  AliAnalysisDataContainer* histOut = 
+    mgr->CreateContainer("Forward", TList::Class(), 
+                        AliAnalysisManager::kOutputContainer,outputfile);
+  mgr->ConnectInput(task, 0, mgr->GetCommonInputContainer());
+  mgr->ConnectOutput(task, 1, histOut);
+
+  // --- Set parameters on the algorithms ----------------------------
+  // Set the number of SPD tracklets for which we consider the event a
+  // low flux event
+  task->GetEventInspector().SetLowFluxCut(1000); 
+  // Set the maximum error on v_z [cm]
+  task->GetEventInspector().SetMaxVzErr(0.2);
+  // Set the eta axis to use - note, this overrides whatever is used
+  // by the rest of the algorithms - but only for the energy fitter
+  // algorithm. 
+  task->GetEnergyFitter().SetEtaAxis(200, -4, 6);
+  // Set maximum energy loss to consider 
+  task->GetEnergyFitter().SetMaxE(10); 
+  // Set number of energy loss bins 
+  task->GetEnergyFitter().SetNEbins(300);
+  // Set whether to use increasing bin sizes 
+  task->GetEnergyFitter().SetUseIncreasingBins(true);
+  // Set whether to do fit the energy distributions 
+  task->GetEnergyFitter().SetDoFits(kTRUE);
+  // Set whether to make the correction object 
+  task->GetEnergyFitter().SetDoMakeObject(kTRUE);
+  // Set the low cut used for energy
+  task->GetEnergyFitter().SetLowCut(0.4);
+  // Set the number of bins to subtract from maximum of distributions
+  // to get the lower bound of the fit range
+  task->GetEnergyFitter().SetFitRangeBinWidth(4);
+  // Set the maximum number of landaus to try to fit (max 5)
+  task->GetEnergyFitter().SetNParticles(5);
+  // Set the minimum number of entries in the distribution before
+  // trying to fit to the data
+  task->GetEnergyFitter().SetMinEntries(1000);
+  // --- Set limits on fits the energy -------------------------------
+  // Maximum relative error on parameters 
+  AliFMDCorrELossFit::ELossFit::fgMaxRelError = .12;
+  // Least weight to use 
+  AliFMDCorrELossFit::ELossFit::fgLeastWeight = 1e-5;
+  // Maximum value of reduced chi^2 
+  AliFMDCorrELossFit::ELossFit::fgMaxChi2nu   = 5;
+  
+  // --- Run the analysis --------------------------------------------
+  TStopwatch t;
+  if (!mgr->InitAnalysis()) {
+    Error("RunManager", "Failed to initialize analysis train!");
+    return;
+  }
+  // Some informative output 
+  mgr->PrintStatus();
+  // mgr->SetDebugLevel(3);
+  if (mgr->GetDebugLevel() < 1 && !proof) mgr->SetUseProgressBar(kTRUE);
+
+  // Run the train 
+  t.Start();
+  Printf("=== RUNNING ANALYSIS ==================================");
+  mgr->StartAnalysis(proof ? "proof" : "local", chain, nEvents);
+  t.Stop();
+  t.Print();
+}
+//
+// EOF
+//
index 7440384..ea5e09c 100644 (file)
@@ -49,61 +49,17 @@ void RunManager(const char* esddir,
                UShort_t    flags=kFull)
 {
   // --- Libraries to load -------------------------------------------
-  gSystem->Load("libVMC");
-  gSystem->Load("libTree");
-  
-  gSystem->Load("libSTEERBase");
-  
-  gSystem->Load("libESD") ;
-  gSystem->Load("libAOD") ;
-  gSystem->Load("libANALYSIS");
-  gSystem->Load("libANALYSISalice");
-  
-  gSystem->Load("libPhysics");
-  gSystem->Load("libPWG0base");
-  gSystem->Load("libPWG0dep");
-  gSystem->Load("libPWG2forward");
-  gSystem->Load("libPWG2forward2");
+  gROOT->Macro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadLibs.C");
 
   // --- Check for proof mode, and possibly upload pars --------------
-  if (flags & kProof) { 
-    TProof::Open("workers=2");
-    const char* pkgs[] = { "STEERBase", "ESD", "AOD", "ANALYSIS", 
-                          "ANALYSISalice", "PWG2forward", "PWG2forward2", 0};
-    const char** pkg = pkgs;
-    while (*pkg) { 
-      gProof->UploadPackage(Form("${ALICE_ROOT}/%s.par",*pkg));
-      gProof->EnablePackage(*pkg);    
-      pkg++;
-    }
-  }
+  if (flags & kProof) 
+    gROOT->Macro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadPars.C");
   
   // --- Our data chain ----------------------------------------------
-  TChain* chain = new TChain("esdTree");
-
-  // --- Get list of ESDs --------------------------------------------
-  // Open source directory, and make sure we go back to were we were 
-  TString oldDir(gSystem->WorkingDirectory());
-  TSystemDirectory d(esddir, esddir);
-  TList* files = d.GetListOfFiles();
-  gSystem->ChangeDirectory(oldDir);
-
-  // Sort list of files and check if we should add it 
-  files->Sort();
-  TIter next(files);
-  TSystemFile* file = 0;
-  while ((file = static_cast<TSystemFile*>(next()))) {
-    if (file->IsDirectory()) continue;
-    TString name(file->GetName());
-    if (!name.EndsWith(".root")) continue;
-    if (!name.Contains("AliESDs")) continue;
-    TString esd(Form("%s/%s", file->GetTitle(), name.Data()));
-    Info("RunManager", "Adding %s to chain", esd.Data());
-    chain->Add(esd);
-  }  
+  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/MakeESDChain.C");
+  TChain* chain = MakeESDChain(esddir);
   // If 0 or less events is select, choose all 
   if (nEvents <= 0) nEvents = chain->GetEntries();
-    
 
   // --- Creating the manager and handlers ---------------------------
   AliAnalysisManager *mgr  = new AliAnalysisManager("Analysis Train", 
@@ -140,10 +96,10 @@ void RunManager(const char* esddir,
   gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskFMD.C");
   gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
   AliAnalysisTask* task = AddTaskFMD();
-  mgr->ConnectOutput(task, 0, mgr->GetCommonOutputContainer());
+  // mgr->ConnectOutput(task, 0, mgr->GetCommonOutputContainer());
 
   task = AddTaskPhysicsSelection((flags & kMC), kTRUE, kTRUE);
-  mgr->ConnectOutput(task, 0, mgr->GetCommonOutputContainer());
+  // mgr->ConnectOutput(task, 0, mgr->GetCommonOutputContainer());
   
   // --- Run the analysis --------------------------------------------
   TStopwatch t;
@@ -163,10 +119,13 @@ void RunManager(const char* esddir,
 
   // Run the train 
   t.Start();
-  if (!(flags & kTerminate))
+  if (!(flags & kTerminate)) {
+    Printf("=== RUNNING ANALYSIS ==================================");
     mgr->StartAnalysis((flags & kProof) ? "proof" : "local", chain, nEvents);
+  }
   else {
-    mgr->ImportWrappers();
+    Printf("=== RUNNING TERMINATE =================================");
+    // mgr->ImportWrappers(0);
     mgr->Terminate();
   }
   t.Stop();