Added ignores
authorcholm <cholm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Wed, 17 Oct 2012 17:06:47 +0000 (17:06 +0000)
committercholm <cholm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Wed, 17 Oct 2012 17:06:47 +0000 (17:06 +0000)
29 files changed:
PWGLF/FORWARD/trains/AAFHelper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/AAFPluginHelper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/AvailableSoftware.C [new file with mode: 0644]
PWGLF/FORWARD/trains/ChainBuilder.C [new file with mode: 0644]
PWGLF/FORWARD/trains/CreateFileCollection.C [new file with mode: 0644]
PWGLF/FORWARD/trains/GridHelper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/Helper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/LiteHelper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/LocalHelper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakeAODTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakeFMDELossTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakeFMDEventPlaneTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakeFlowTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakeFullTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakeMCCorrTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakeQATrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MakedNdetaTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MyAnalysis.C [new file with mode: 0644]
PWGLF/FORWARD/trains/MyTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/Option.C [new file with mode: 0644]
PWGLF/FORWARD/trains/OutputUtilities.C [new file with mode: 0644]
PWGLF/FORWARD/trains/ParUtilities.C [new file with mode: 0644]
PWGLF/FORWARD/trains/PluginHelper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/ProofHelper.C [new file with mode: 0644]
PWGLF/FORWARD/trains/QATrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/RunTrain.C [new file with mode: 0644]
PWGLF/FORWARD/trains/TrainSetup.C [new file with mode: 0644]
PWGLF/FORWARD/trains/test.sh [new file with mode: 0755]
PWGLF/FORWARD/trains/trainMain.cxx [new file with mode: 0644]

diff --git a/PWGLF/FORWARD/trains/AAFHelper.C b/PWGLF/FORWARD/trains/AAFHelper.C
new file mode 100644 (file)
index 0000000..d1928f0
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * @file   AAFHelper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 19:02:14 2012
+ * 
+ * @brief  AAF analysis helper
+ * 
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef AAFHELPER_C
+#define AAFHELPER_C
+#include "ProofHelper.C"
+#ifndef __CINT__
+# include "AvailableSoftware.C"
+# include <TUrl.h>
+# include <TString.h>
+# include <TProof.h>
+# include <AliAnalysisManager.h>
+#else
+class TUrl;
+class AliAnalysisAlien;
+#endif
+
+// ===================================================================
+/**
+ * Handle analysis on an Alice Analysis Facility (AAF)
+ * 
+ * This helper is triggered by a URL of the form 
+ *
+ * @code
+ * proof://[<user>@]<host>[:<port>]/<dsname>[?<options>][#<treename>]
+ * @endcode 
+ * where &lt;host@gt; is a known AAF (e.g., <tt>alice-caf.cern.ch</tt>)
+ * <dl>
+ *   <dt>&lt;user@gt;</dt>
+ *   <dd>Optional user name</dd>
+ *   <dt>&lt;host@gt;</dt>
+ *   <dd>PROOF cluster master host</dd>
+ *   <dt>&lt;port@gt;</dt>
+ *   <dd>Optional PROOF cluster port on master host</dd>
+ *   <dt>&lt;dsname@gt;</dt>
+ *   <dd>Data set name</dd>
+ *   <dt>&lt;treename@gt;</dt>
+ *   <dd>Optional tree name in data set, often <tt>esdTree</tt> or
+ *   <tt>aodTree</tt></dd>
+ *   <dt>&lt;options@gt;</dt>
+ *   <dd>List of options separated by an &amp;
+ *     <dl>
+ *       <dt><tt>dsname</tt>[=&lt;output dataset&gt;]</dt>
+ *       <dd>Register tree output (e.g., AOD) as a new data set on the
+ *         PROOF cluster. If &lt;output dataset&gt; is not specified, take
+ *         the name of the train.</dd>
+ *       <dt><tt>storage=&lt;url&gt;</tt></dt>
+ *       <dd>Specify a non-default storage location for special output
+ *         (e.g., AOD trees).  &lt;url&gt; should be a valid XRootd 
+ *         server URI accessible to the slaves - e.g., 
+ *         <tt>root://lxplus.cern.ch:10930//tmp</tt>.</dd>
+ *       <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
+ *       <dd>Set the AliROOT mode.  If not specified <tt>default</tt> 
+ *         is assumed</tt>.  See also CreateAliROOTPar</dd>
+ *       <dt><tt>par</tt></dt>
+ *       <dd> Use par files </dd>
+ *     </dl>
+ *   </dd>
+ * </dl>  
+ *
+ * Note, this helper does not use the AliAnalysisAlien plugin
+ *
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct AAFHelper : public ProofHelper
+{
+  /** 
+   * Constructor 
+   * 
+   * @param url  Url 
+   * @param opts Options 
+   */
+  AAFHelper(const TUrl& url, Int_t verbose)
+    : ProofHelper(url, verbose)
+  {
+    fOptions.Add("aliroot", "VERSION", "AliROOT version", "last");
+    fOptions.Add("root",    "VERISON", "ROOT version", "last");
+  }
+  virtual ~AAFHelper() {}
+  /** 
+   * Get the name of the AliROOT par file to use 
+   * 
+   * @return String 
+   */
+  virtual const char* AliROOTParName() const
+  {
+    return Form("VO_ALICE@AliRoot::%s", fOptions.Get("aliroot").Data());
+  }
+  virtual Bool_t CreateAliROOTPar()
+  {
+    return true;
+  }
+  /** 
+   * Set-up done before task set-ups. Overload ProofHelper::PreSetup
+   * to specify the ROOT version using TProofMgr::SetROOTVersion
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t PreSetup() 
+  {
+    TString aliroot("last");
+    TString root("last");
+    if (fOptions.Has("aliroot")) aliroot = fOptions.Get("aliroot");
+    if (fOptions.Has("root"))    root    = fOptions.Get("root");
+
+    AvailableSoftware::Check(aliroot, root);
+    fOptions.Set("aliroot", aliroot);
+    fOptions.Set("root", root);
+
+    fBasePars = false;
+
+    TProof::Mgr(fUrl.GetHost())
+      ->SetROOTVersion(Form("VO_ALICE@ROOT::%s", root.Data()));
+
+    return ProofHelper::PreSetup();
+  }
+  /** 
+   * @return URI help string 
+   */
+  virtual const Char_t* UrlHelp() const 
+  {
+    return "proof://<host>/<dataset>?[&<options>][#<treename>]";
+  }
+  /** 
+   * @return short description
+   */
+  virtual const char* Desc() const { return "AAF"; }
+};
+#endif
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/AAFPluginHelper.C b/PWGLF/FORWARD/trains/AAFPluginHelper.C
new file mode 100644 (file)
index 0000000..b55b7b7
--- /dev/null
@@ -0,0 +1,166 @@
+/**
+ * @file   AAFPluginHelper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 19:01:45 2012
+ * 
+ * @brief  AAF (using AliAnalysisAlien) analysis helper
+ * 
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef AAFPLUGINHELPER_C
+#define AAFPLUGINHELPER_C
+#include "PluginHelper.C"
+#ifndef __CINT__
+# include <TUrl.h>
+# include <TString.h>
+# include <AliAnalysisManager.h>
+# include <AliAnalysisAlien.h>
+#else
+class TUrl;
+class AliAnalysisAlien;
+#endif
+
+// ===================================================================
+/**
+ * Handle analysis on an Alice Analysis Facility (AAF)
+ * 
+ * This helper is triggered by a URL of the form 
+ *
+ * @code
+ * proof://[<user>@]<host>[:<port>]/<dsname>[?<options>][#<treename>]
+ * @endcode 
+ * where &lt;host@gt; is a known AAF (e.g., <tt>alice-caf.cern.ch</tt>),
+ * and the &lt;options&gt; contains <tt>plugin</tt>
+ * <dl>
+ *   <dt>&lt;user@gt;</dt>
+ *   <dd>Optional user name</dd>
+ *   <dt>&lt;host@gt;</dt>
+ *   <dd>PROOF cluster master host</dd>
+ *   <dt>&lt;port@gt;</dt>
+ *   <dd>Optional PROOF cluster port on master host</dd>
+ *   <dt>&lt;dsname@gt;</dt>
+ *   <dd>Data set name</dd>
+ *   <dt>&lt;treename@gt;</dt>
+ *   <dd>Optional tree name in data set, often <tt>esdTree</tt> or
+ *   <tt>aodTree</tt></dd>
+ *   <dt>&lt;options@gt;</dt>
+ *   <dd>List of options separated by an &amp;
+ *     <dl>
+ *       <dt><tt>dsname</tt>[=&lt;output dataset&gt;]</dt>
+ *       <dd>Register tree output (e.g., AOD) as a new data set on the
+ *         PROOF cluster. If &lt;output dataset&gt; is not specified, take
+ *         the name of the train.</dd>
+ *       <dt><tt>storage=&lt;url&gt;</tt></dt>
+ *       <dd>Specify a non-default storage location for special output
+ *         (e.g., AOD trees).  &lt;url&gt; should be a valid XRootd 
+ *         server URI accessible to the slaves - e.g., 
+ *         <tt>root://lxplus.cern.ch:10930//tmp</tt>.</dd>
+ *       <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
+ *       <dd>Set the AliROOT mode.  If not specified <tt>default</tt> 
+ *         is assumed</tt>.  See also CreateAliROOTPar</dd>
+ *       <dt><tt>par</tt></dt>
+ *       <dd> Use PAR files</dd>
+ *       <dt><tt>workers=</tt><i>N</i><tt>[x]</tt></dt>
+ *       <dd>Set the number of workers to use.  If <tt>x</tt> is appended, 
+ *         then it's maximum number of workers per slave</dd>
+ *     </dl>
+ *   </dd>
+ * </dl>  
+ *
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct AAFPluginHelper : public PluginHelper
+{
+  /** 
+   * Constructor 
+   * 
+   * @param url  Url 
+   * @param opts Options 
+   */
+  AAFPluginHelper(const TUrl& url, Int_t verbose)
+    : PluginHelper(url, verbose)
+  {
+    fOptions.Add("workers", "N[x]", "Number of workers to use", "0");
+    fOptions.Add("dsname",  "NAME", "Make output dataset", "");
+
+  }
+  /** 
+   * Destructor
+   */
+  virtual ~AAFPluginHelper() {}
+  /** 
+   * Called before setting up 
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t PreSetup()
+  {
+    TString root = fOptions.Get("root");
+    fHandler->SetRootVersionForProof(Form("VO_ALICE@ROOT::%s", root.Data()));
+    fHandler->SetProofCluster(fUrl.GetHost());
+    fHandler->SetProofDataSet(fUrl.GetFile());
+    if (fOptions.Has("workers")) {
+      TString nwork = fOptions.Get("workers");
+      if (nwork.EndsWith("x")) 
+       fHandler->SetNproofWorkersPerSlave(nwork.Atoi());
+      else 
+       fHandler->SetNproofWorkers(nwork.Atoi());
+    }
+    return PluginHelper::PreSetup();
+  }
+  /** 
+   * Set-up done after the task set-ups 
+   *
+   * @return true on success 
+   */
+  virtual Bool_t PostSetup() 
+  {
+    if (!PluginHelper::PostSetup()) return false;
+    if (fOptions.Has("dsname")) 
+      OutputUtilities::RegisterDataset(fOptions.Get("dsname"));
+
+    return true;
+  };
+  /** 
+   * Get the mode identifier 
+   * 
+   * @return Always kProof
+   */
+  virtual UShort_t Mode() const { return kProof; }
+  /**
+   * Get the mode string used for AliAnalysisManager::StartAnalysis
+   */
+  virtual const char* ModeString() const { return "proof"; }
+  /** 
+   * Start the analysis 
+   * 
+   * @param nEvents Number of events to analyse 
+   * 
+   * @return The return value of AliAnalysisManager::StartAnalysis
+   */
+  virtual Long64_t Run(Long64_t nEvents=-1) 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    
+    TString dsName(fUrl.GetFile());
+    if (fUrl.GetAnchor() && fUrl.GetAnchor()[0] != '\0') 
+      dsName.Append(Form("#%s", fUrl.GetAnchor()));
+    return mgr->StartAnalysis(fUrl.GetProtocol(), dsName, nEvents);
+  }
+  /** 
+   * @return URI help string 
+   */
+  virtual const Char_t* UrlHelp() const 
+  {
+    return "proof://<host>/<dataset>?plugin[&<options>][#<treename>]";
+  }
+  /**
+   * @return Short description
+   */
+  virtual const char* Desc() const { return "CAF w/plugin"; }
+};
+#endif
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/AvailableSoftware.C b/PWGLF/FORWARD/trains/AvailableSoftware.C
new file mode 100644 (file)
index 0000000..28ea49a
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ * @file   AvailableSoftware.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 17:54:11 2012
+ * 
+ * @brief  Find available packages
+ * 
+ * @ingroup pwglf_forward_trains_util
+ */
+
+#ifndef AVAILABLESOFTWARE_C
+#define AVAILABLESOFTWARE_C
+#ifndef __CINT__
+# include <TString.h>
+# include <TSystem.h>
+# include <TError.h>
+# include <TObjArray.h>
+#else
+class TString;
+#endif
+
+/**
+ * Helper code to find available packages on Grid
+ * 
+ *
+ * @ingroup pwglf_forward_trains_util
+ */
+struct AvailableSoftware
+{
+  static Bool_t Check(TString& aliroot, TString& root)
+  {
+    // Figure out what to do.  
+    // If mode == 0, then do nothing. 
+    // If bit 0 is set in mode (0x1), then list and exit 
+    // If bit 1 is set in mode (0x2), select last AliROOT/ROOT version 
+    // If bit 2 is set in mode (0x4), select ROOT corresponding to AliROOT
+    UShort_t mode = 0; 
+
+    TString c("wget -q http://alimonitor.cern.ch/packages/ -O - | "
+             "sed -n -e '/<tr/,/<\\/tr>/ p' | "
+             "sed -n '/<a.*VO_ALICE@AliRoot::/,/VO_ALICE@ROOT::/ p' | "
+             "sed -n -e 's/.*VO_ALICE@AliRoot::\\([-0-9a-zA-Z]*\\).*/%\\1%/p' "
+             "  -e 's/.*VO_ALICE@ROOT::\\([-0-9a-zA-Z]*\\).*/\\1@/p' | "
+             "tr -d '\\n' | tr '@' '\\n' | tr '%' '\\t' ");
+
+    if (aliroot.EqualTo("list", TString::kIgnoreCase) ||
+       root.EqualTo("list", TString::kIgnoreCase) || 
+       aliroot.IsNull()) {
+      Warning("AvaliableSoftware::Check", "No AliROOT/ROOT version specified, "
+             "available packages are:\n" 
+             "\tAliROOT \tROOT:");
+      gSystem->Exec(c);
+      return false;
+    }
+
+    if (aliroot.EqualTo("last", TString::kIgnoreCase)) 
+      mode |= 0x2;
+    else if (!aliroot.IsNull()) 
+      mode |= 0x4; 
+
+    // Nothing to do 
+    if (mode == 0) return true; 
+    
+
+    TString    values = gSystem->GetFromPipe(c);
+    TObjArray* tokens = values.Tokenize(" \t\n");
+    Int_t      n      = tokens->GetEntries();
+
+    // If we asked to select the last possible version, do so here and get out
+    if (mode & 0x2) { 
+      aliroot = tokens->At(n-2)->GetName();
+      root    = tokens->At(n-1)->GetName();
+      Info("AvaliableSoftware::Check", 
+          "Selecting lastest possible AliROOT/ROOT: %s/%s", 
+          aliroot.Data(), root.Data());
+      delete tokens;
+      return true;
+    }
+    
+    // We get here if we're asked to find a ROOT version compatible
+    // with the selected AliROOT version. 
+    for (Int_t i = 0; i < n; i += 2) {
+      if (aliroot.EqualTo(tokens->At(i)->GetName(), 
+                                 TString::kIgnoreCase)) { 
+       root = tokens->At(i+1)->GetName();
+       Info("AvaliableSoftware::Check",
+            "Found ROOT version compatible with AliROOT %s: %s",
+            aliroot.Data(), root.Data());
+       delete tokens;
+       return true;
+      }
+    }
+    // If we get here, then we didn't find a ROOT version compatible
+    // with the selected AliROOT, and we should fail. 
+    Warning("AvaliableSoftware::Check",
+           "Didn't find a ROOT version compatible with AliROOT %s", 
+           aliroot.Data());
+    delete tokens; 
+    return false;
+  }
+};
+#endif
diff --git a/PWGLF/FORWARD/trains/ChainBuilder.C b/PWGLF/FORWARD/trains/ChainBuilder.C
new file mode 100644 (file)
index 0000000..cdeb531
--- /dev/null
@@ -0,0 +1,421 @@
+/**
+ * @file   ChainBuilder.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 17:54:26 2012
+ * 
+ * @brief  Build a chain
+ * 
+ * @ingroup pwglf_forward_trains_util
+ */
+
+#ifndef CHAINBUILDER_C
+#define CHAINBUILDER_C
+#ifndef __CINT__
+# include <TString.h>
+# include <TChain.h>
+# include <TSystemDirectory.h>
+# include <TSystem.h>
+# include <TFile.h>
+# include <TList.h>
+# include <TError.h>
+# include <TROOT.h>
+# include <TGridCollection.h>
+# include <TFileCollection.h>
+# include <THashList.h>
+# include <TKey.h>
+# include <fstream>
+#else 
+class TString;
+class TChain;
+class TSystemDirectory;
+#endif
+
+// ===================================================================
+/**
+ * Build a chain 
+ *
+ * @ingroup pwglf_forward_trains_util
+ */
+struct ChainBuilder 
+{
+  enum { 
+    kInvalid,
+    kDirectory, 
+    kXML, 
+    kAscii, 
+    kROOT
+  };
+  //------------------------------------------------------------------
+  static UShort_t CheckSource(TString& src)
+  {
+    // Local copy 
+    TString tmp(src);
+
+    // --- Normalize the path ----------------------------------------
+    if (tmp == ".") tmp = "";
+    if (!tmp.BeginsWith("/")) tmp.Prepend("../");
+    if (gSystem->ExpandPathName(tmp)) { 
+      Error("ChainBuilder::CheckSource", 
+           "Failed to expand source %s", src.Data());
+      return kInvalid;
+    }
+
+    // --- Stat the file ---------------------------------------------
+    FileStat_t stat; 
+    if (gSystem->GetPathInfo(tmp, stat)) return kInvalid;
+    src = tmp;
+
+    // --- Check if directory or file --------------------------------
+    if (R_ISDIR(stat.fMode)) return kDirectory;
+
+    // --- check file type -------------------------------------------
+    TString type(gSystem->GetFromPipe(Form("file -b %s", src.Data())));
+    if      (type.Contains("ROOT"))  return kROOT;
+    else if (type.Contains("XML"))   return kXML;
+    else if (type.Contains("ASCII")) return kAscii;
+
+    Error("ChainBuilder::CheckSource", 
+         "Do not now how to process %s of type %s", 
+         src.Data(), type.Data());
+    return kInvalid;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create the chain.  User is owner. 
+   * 
+   * @return Null in case of problems, chain otherwise 
+   */
+  static TChain* Create(const TString& src, 
+                       const TString& treeName, 
+                       const TString& pattern, 
+                       Bool_t         mc, 
+                       Bool_t         recursive)
+  {
+    TString tmp(src);
+    UShort_t type = CheckSource(tmp);
+
+    return Create(type, tmp, treeName, pattern, mc, recursive);
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create the chain.  User is owner. 
+   * 
+   * @return Null in case of problems, chain otherwise 
+   */
+  static TChain* Create(UShort_t       type, 
+                       const TString& src, 
+                       const TString& treeName, 
+                       const TString& pattern, 
+                       Bool_t         mc, 
+                       Bool_t         recursive)
+  {
+    // --- check input -----------------------------------------------
+    if (type == kInvalid) {
+      Error("ChainBuilder::Create", "Source %s isn't a file or directory",
+           src.Data());
+      return 0;
+    }
+    TString tN(treeName);
+    if (tN.IsNull()) 
+      Warning("ChainBuilder::Create", "No tree name specified, assuming T");
+
+    TString pat(pattern);
+    if (pat.IsNull()) {
+      if      (tN.EqualTo("esdTree")) pat = "AliESD";
+      else if (tN.EqualTo("aodTree")) pat = "AliAOD";
+    }
+      
+    // --- Create output ---------------------------------------------
+    TChain* chain = new TChain(tN);
+
+    // --- execute based on type 
+    Bool_t ret = true;
+    switch (type) { 
+    case kROOT:      ret = CreateFromFile(chain, src); break;
+    case kXML:       ret = CreateFromXML(chain,  src); break;
+    case kAscii:     ret = CreateFromList(chain, src); break;
+    case kDirectory: ret = CreateFromDirectory(chain, src, 
+                                              pat, mc, 
+                                              recursive); break;
+    default:         ret = false;
+    }
+
+    // --- Clean-up --------------------------------------------------
+    if (chain->GetListOfFiles()->GetEntries() <= 0) ret = false;
+    if (!ret) { 
+      delete chain;
+      chain = 0;
+    }
+    return chain;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create a chain consiting of a single file 
+   * 
+   * @param fn File name. 
+   * 
+   * @return Chain or null
+   */
+  static Bool_t CreateFromFile(TChain* chain, const TString& src)
+  {
+    // Info("CreateFromFile", "Making from single file %s", src.Data());
+    if (!CheckFile(src, chain)) return false;
+    return true;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create a chain from an XML containing an collection
+   * 
+   * @return Newly allocated chain or null
+   */
+  static Bool_t CreateFromXML(TChain* chain, const TString& src) 
+  {
+    Long_t ret = gROOT->ProcessLine(Form("TAlienCollection(\"%s\")", 
+                                        src.Data()));
+    if (!ret) { 
+      Error("ChainBuilder::CreateFromXML", 
+           "Cannot create AliEn collection from XML file %s", src.Data());
+      return false;
+    }
+    
+    TGridCollection* collection = reinterpret_cast<TGridCollection*>(ret);
+    if (!collection) { 
+      Error("ChainBuilder::CreateFromXML", 
+           "Cannot create AliEn collection from XML file %s", src.Data());
+      return false;
+    }
+    
+    collection->Reset();
+    while (collection->Next()) chain->Add(collection->GetTURL(""));
+    
+    return true;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create a chain from a file containing a list of files
+   * 
+   * @return Newly allocated chain or null
+   */
+  static Bool_t CreateFromList(TChain* chain, const TString& src) 
+  {
+    std::ifstream in(src.Data());
+    if (!in) { 
+      Error("ChainBuilder::CreateFromList", 
+           "Failed to open list %s", src.Data());
+      return false;
+    }
+    
+    while (in.good()) { 
+      TString line;
+      line.ReadToDelim(in);
+      TString l(line.Strip(TString::kBoth));
+      if (l.IsWhitespace() || l.BeginsWith("#")) continue;
+      
+      if (!CheckFile(l, chain))
+       Warning("ChainBuilder::CreateFromList", 
+               "Failed to add %s to chain", l.Data());
+    }
+    return true;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Make a chain from a base directory, pattern, and treename -
+   * possibly recursively
+   * 
+   * @return true on success 
+   */
+  static Bool_t CreateFromDirectory(TChain* chain, 
+                                   const TString& src, 
+                                   const TString& pattern, 
+                                   Bool_t         mc, 
+                                   Bool_t         recursive) 
+  {
+    // Info("", "Scanning src=%s, pattern=%s, mc=%d recursive=%d", 
+    //       src.Data(), pattern.Data(), mc, recursive);
+    // Save current directory 
+    TString savdir(gSystem->WorkingDirectory());
+    TSystemDirectory d(gSystem->BaseName(src.Data()), src.Data());
+    // Info("", "Will scan %s", d.GetTitle());
+    if (!ScanDirectory(chain, &d, pattern, mc, recursive)) return false;
+    // Go back to the saved directory 
+    gSystem->ChangeDirectory(savdir);
+    
+    return true;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Check if we can add a file to the chain 
+   * 
+   * @param path   Full path to file 
+   * @param chain  Chain 
+   * 
+   * @return true on success, false otherwise
+   */
+  static Bool_t CheckFile(const TString& path, TChain* chain)
+  {
+    // Info("", "Checking %s", path.Data());
+    gSystem->RedirectOutput("/dev/null", "w");
+    TFile* test = TFile::Open(path, "READ");
+    gSystem->RedirectOutput(0);
+    if (!test) { 
+      Warning("ChainBuilder::CheckFile", "Failed to open %s", path.Data());
+      return false;
+    }
+
+    TObject* o = test->Get(chain->GetName());
+    if (!o) {
+      // Let's try to find a TFileCollection 
+      TList* l = test->GetListOfKeys();
+      TIter next(l);
+      TKey* k = 0;
+      Bool_t ok = false;
+      while ((k = static_cast<TKey*>(next()))) {
+       TString cl(k->GetClassName());
+       if (!cl.EqualTo("TFileCollection")) continue;
+       TFileCollection* fc = dynamic_cast<TFileCollection*>(k->ReadObj());
+       Info("", "Adding file collection");
+       chain->AddFileInfoList(fc->GetList());
+       ok = true;
+      }
+      if (ok) { 
+       test->Close();
+       return true;
+      }
+    }
+    else if (dynamic_cast<TTree*>(o)) {
+      test->Close();
+      chain->Add(path);
+      return true;
+    }
+    
+    Warning("ChainBuilder::CheckFile", 
+           "The file %s does not contain the tree %s or a file collection", 
+           path.Data(), chain->GetName());
+    
+    return false;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Scan directory @a dir (possibly recursive) for tree files to add
+   * to the chain.    This does not follow sym-links
+   * 
+   * @param dir        Directory to scan
+   * @param chain      Chain to add to
+   *
+   * @return true if any files where added 
+   */
+  static Bool_t ScanDirectory(TChain*           chain, 
+                             TSystemDirectory* dir,
+                             const TString&    pattern,
+                             Bool_t            mc,
+                             Bool_t            recursive)
+  {
+    // Assume failure 
+    Bool_t ret = false;
+
+    // Get list of files, and go back to old working directory
+    TString oldDir(gSystem->WorkingDirectory());
+    TList*  files = dir->GetListOfFiles();
+    if (!gSystem->ChangeDirectory(oldDir)) { 
+      Error("ChainBuilder::ScanDirectory", "Failed to go back to %s", 
+           oldDir.Data());
+      return false;
+    }
+    if (!files) {
+      Warning("ChainBuilder::ScanDirectory", "No files");
+      return false;
+    }
+
+    TList toAdd;
+    toAdd.SetOwner();
+    Bool_t hasGAlice = (!(mc) ? true : false);
+    Bool_t hasKine   = (!(mc) ? true : false);
+    Bool_t hasTrRef  = (!(mc) ? true : false);
+    
+    // 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()))) {
+      TString name(file->GetName());
+      TString title(file->GetTitle());
+      TString full(gSystem->ConcatFileName(file->GetTitle(), name.Data()));
+      // Info("", "Got file %s", full.Data());
+      if (file->IsA()->InheritsFrom(TSystemDirectory::Class())) full = title;
+      // Ignore special links 
+      if (name == "." || name == "..") { 
+       // Info("ChainBuilder::ScanDirectory", "Ignoring %s", name.Data());
+       continue;
+      }
+      // Info("", "Got file %s", full.Data());
+
+      FileStat_t fs;
+      if (gSystem->GetPathInfo(full.Data(), fs)) {
+       Warning("ChainBuilder::ScanDirectory", "Cannot stat %s (%s)", 
+               full.Data(), gSystem->WorkingDirectory());
+       continue;
+      }
+      // Check if this is a directory 
+      if (file->IsDirectory(full)) { 
+       // Info("", "Recursive scan of %s", full.Data());
+       if (recursive) {
+         // if (title[0] == '/') 
+         TSystemDirectory* d = new TSystemDirectory(file->GetName(),
+                                                    full.Data());
+         if (ScanDirectory(chain, d, pattern, mc, recursive)) 
+           ret = true;
+         delete d;
+       }
+        continue;
+      }
+    
+      // If this is not a root file, ignore 
+      if (!name.EndsWith(".root")) {
+       // Info("ScanDirectory", "File %s does not end in .root", name.Data());
+       continue;
+      }
+
+      // If this file does not contain AliESDs, ignore 
+      if (!name.Contains(pattern)) { 
+       // Info("ChainBuilder::ScanDirectory", "%s does not match pattern %s", 
+       //      name.Data(), pattern.Data());
+       if (mc) {
+         if (name.CompareTo("galice.root") == 0)     hasGAlice = true;
+         if (name.CompareTo("Kinematics.root") == 0) hasKine   = true;
+         if (name.CompareTo("TrackRefs.root")  == 0) hasTrRef = true;
+       }
+       continue;
+      }
+    
+      // Add 
+      // Info("ChainBuilder::ScanDirectory", "Adding %s", full.Data());
+      toAdd.Add(new TObjString(full));
+    }
+
+    if (mc && toAdd.GetEntries() > 0 && 
+       (!hasGAlice || !hasKine || !hasTrRef)) { 
+      Warning("ChainBuilder::ScanDirectory", 
+             "one or more of {galice,Kinematics,TrackRefs}.root missing from "
+             "%s, not adding anything from this directory", 
+             dir->GetTitle());
+      toAdd.Delete();
+    }
+
+    TIter nextAdd(&toAdd);
+    TObjString* s = 0;
+    Int_t added = 0;
+    while ((s = static_cast<TObjString*>(nextAdd()))) {
+      // Info("ChainBuilder::ScanDirectory", 
+      //      "Adding %s", s->GetString().Data());
+      TString fn = s->GetString();
+      if (!CheckFile(fn, chain)) continue;
+
+      added++;
+    }
+    if (added > 0) ret = true;
+
+    gSystem->ChangeDirectory(oldDir);
+    return ret;
+  }
+};
+#endif
diff --git a/PWGLF/FORWARD/trains/CreateFileCollection.C b/PWGLF/FORWARD/trains/CreateFileCollection.C
new file mode 100644 (file)
index 0000000..52484b8
--- /dev/null
@@ -0,0 +1,49 @@
+void
+CreateFileCollection(const TString& dir="/data/alice/data/ppb/LHC12g/pass1/188359/",
+                    const TString& tN="esdTree", 
+                    const TString& pa="AliESD", 
+                    Bool_t mc=false, 
+                    Bool_t recursive=false)
+)
+{
+  gROOT->LoadMacro("ChainBuilder.C+");
+  
+  UShort_t type = ChainBuilder::CheckSource(dir);
+  Info("", "type=%d", type);
+  TChain* chain = ChainBuilder::Create(dir, tN, pa, mc, recursive);
+  if (!chain) { 
+    Error("CreateFileCollection", "Failed to make chain");
+    return;
+  }
+  Int_t port;
+  TString host;
+  { 
+    TUrl u(Form("root://%s//foo", gSystem->HostName()));
+    port = u.GetPort() * 10;
+    host = u.GetHostFQDN();
+  }
+  
+
+  TFileCollection* fc  = new TFileCollection("files");
+  TObjArray*       cEs = chain->GetListOfFiles();
+  TChainElement*   cE  = 0;
+  TIter            next(cEs);
+  while ((cE= static_cast<TChainElement*>(next()))) {
+    TString fN(cE->GetTitle());
+    TFile* f = TFile::Open(fN, "READ");
+    TTree* t = static_cast<TTree*>(f->Get(tN));
+    
+    fN.Prepend(Form("root://%s:%d/", host.Data(), port));
+    TFileInfo* fi = new TFileInfo(Form("%s tree:%s,%d", 
+                                      fN.Data(), tN.Data(), t->GetEntries()),
+                                 f->GetSize());
+    f->Close();
+    fc->Add(fi);
+  }
+  fc->Print("F");
+  
+  TFile* files = TFile::Open("files.root", "RECREATE");
+  fc->Write();
+  files->Close();
+  
+}
diff --git a/PWGLF/FORWARD/trains/GridHelper.C b/PWGLF/FORWARD/trains/GridHelper.C
new file mode 100644 (file)
index 0000000..4aa5d08
--- /dev/null
@@ -0,0 +1,443 @@
+/**
+ * @file   GridHelper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 19:01:27 2012
+ * 
+ * @brief  Grid Analysis Helper
+ * 
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef GRIDHELPER_C
+#define GRIDHELPER_C
+#include "PluginHelper.C"
+#ifndef __CINT__
+# include <TUrl.h>
+# include <TString.h>
+# include <TGrid.h>
+# include <AliAnalysisManager.h>
+# include <AliAnalysisAlien.h>
+#else
+class TUrl;
+class AliAnalysisAlien;
+#endif
+
+// ===================================================================
+/**
+ * Handle analysis on an the Grid
+ * 
+ * This helper is triggered by a URL of the form 
+ *
+ * @code
+ * alien:///<directory>[?<options>][#<pattern>]
+ * @endcode 
+ * where 
+ * <dl>
+ *   <dt>&lt;directory@gt;</dt>
+ *   <dd>Grid directory that holds the data</dd>
+ *   <dt>&lt;treeName@gt;</dt>
+ *   <dd>Tree to loop over</dd>
+ *   <dt>&lt;options@gt;</dt>
+ *   <dd>List of options separated by an &amp;
+ *     <dl>
+ *       <dt><tt>storage=&lt;url&gt;</tt></dt>
+ *       <dd>Specify a non-default storage location for special output
+ *         (e.g., AOD trees).  &lt;url&gt; should be a valid XRootd 
+ *         server URI accessible to the slaves - e.g., 
+ *         <tt>root://lxplus.cern.ch:10930//tmp</tt>.</dd>
+ *       <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
+ *       <dd>Set the AliROOT mode.  If not specified <tt>default</tt> 
+ *         is assumed</tt>.  See also CreateAliROOTPar</dd>
+ *       <dt><tt>par</tt></dt>
+ *       <dd> Use PAR files</dd>
+ *       <dt><tt>runs=[list or file]</tt></dt>
+ *       <dd>Comma separated list of run numbers, or file(s) containing 
+ *         run numbers</dd> 
+ *       <dt><tt>oper=[FULL,TERMINATE,SUBMIT,OFFLINE,TEST]</tt></dt>
+ *       <dd>How to run the analysis</dd>
+ *       <dt><tt>split=&lt;N&gt;</tt></dt>
+ *       <dd>Maximum number of files per split</dd>
+ *       <dt><tt>merge=&lt;N&gt;</tt></dt>
+ *       <dd>Maximum number of files per merger</dd>
+ *       <dt><tt>mc</tt></dt>
+ *       <dd>Scan also for MC files (<tt>galice.root</tt>, 
+ *          <tt>Kinematics.root</tt>, and <tt>TrackRefs.root</tt>) when 
+ *          scanning &lt;datadir&gt;</dd>
+ *       <dt><tt>pattern=&lt;GLOB&gt;</tt></dt>
+ *       <dd>Shell glob pattern that files must check when scanning 
+ *         &lt;datadir&gt;</dd>
+ *     </dl>
+ *   </dd>
+ * </dl>  
+ *
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct GridHelper : public PluginHelper
+{
+  /** 
+   * Constructor 
+   * 
+   * @param url  Url 
+   * @param opts Options 
+   */
+  GridHelper(const TUrl& url, Int_t verbose)
+    : PluginHelper(url, verbose)
+  {
+    fOptions.Add("oper", "FULL|TERMINATE|SUBMIT", "Analysis operation", "FULL");
+    fOptions.Add("split",  "N", "Maximum number of files before split", "max");
+    fOptions.Add("merge",  "N", "Maximum number of files for merge", "max");
+    fOptions.Add("run",    "RUNS", "Range, list, and/or file of runs", "");
+    fOptions.Add("pattern","GLOB", "File/directory name pattern", "");
+    fOptions.Add("mc", "Assume MC input");
+  }
+  virtual ~GridHelper() {}
+  /** 
+   * Get the mode identifier 
+   * 
+   * @return Always kProof
+   */
+  virtual UShort_t Mode() const { return kGrid; }
+  /**
+   * Get the mode string used for AliAnalysisManager::StartAnalysis
+   */
+  virtual const char* ModeString() const { return "grid"; }
+  /** 
+   * Set-up done before task set-ups 
+   * 
+   * @return true on success 
+   */
+  virtual UShort_t Operation() const 
+  {
+    if (!fOptions.Has("oper")) return kFull;
+    const TString& oper = fOptions.Get("oper");
+    if      (oper.EqualTo("FULL",      TString::kIgnoreCase)) return kFull;
+    else if (oper.EqualTo("OFFLINE",   TString::kIgnoreCase)) return kOffline;
+    else if (oper.EqualTo("SUBMIT",    TString::kIgnoreCase)) return kSubmit;
+    else if (oper.EqualTo("TERMINATE", TString::kIgnoreCase)) return kTerminate;
+    else if (oper.EqualTo("TEST",      TString::kIgnoreCase)) return kTest;
+    return kFull;
+  }
+  /**
+   * Read run numbers 
+   *
+   * @return Number of registered runs 
+   */
+  virtual Int_t RegisterRuns()
+  {
+    if (!fOptions.Find("run")) {
+      Error("GridHelper::RegisterRuns", "No runs specified");
+      return -1;
+    }
+    Int_t       nRuns  = 0;
+    TString     runs   = fOptions.Get("runs");
+    TObjArray*  tokens = runs.Tokenize(",");
+    TObjString* part   = 0;
+    TIter       next(tokens);
+    Bool_t      range  = false;
+    Bool_t      individual = false;
+    while ((part = static_cast<TObjString*>(next()))) {
+      TString& s = part->String();
+      if (s.Contains("-")) { // Run range 
+       if (range) { 
+         Warning("GridHelper::RegisterRuns", "Run range already specified, "
+                 "ignoring %s", s.Data());
+         continue;
+       }
+       if (individual) { 
+         Warning("GridHelper::RegisterRuns", 
+                 "Run ranges and individual run specs do not mix, "
+                 "ignoring %s", s.Data());
+         continue;
+       }
+       TObjArray* ranges = s.Tokenize("-");
+       if (ranges->GetEntriesFast() > 2) { 
+         Warning("GridHelper::RegisterRuns", "Invalid run range: %s", 
+                 s.Data());
+         ranges->Delete();
+         continue;
+       }
+       Int_t first = static_cast<TObjString*>(ranges->At(0))->String().Atoi();
+       Int_t last  = static_cast<TObjString*>(ranges->At(1))->String().Atoi();
+       nRuns       = last-first+1;
+       fHandler->SetRunRange(first, last);
+       ranges->Delete();
+       range = true;
+       continue;
+      }
+      if (s.IsDigit()) { // single run
+       if (range) { 
+         Warning("GridHelper::RegisterRuns", 
+                 "Run ranges and individual run specs do not mix, "
+                 "ignoring %s", s.Data());
+         continue;
+       }
+       fHandler->AddRunNumber(s.Data());
+       nRuns++;
+       individual = true;
+       continue;
+      }
+       if (range) { 
+         Warning("GridHelper::RegisterRuns", "Run ranges and list file "
+                 "do not mix, ignoring %s", s.Data());
+         continue;
+       }
+
+      // We assume this part is a file 
+      std::ifstream in(s.Data());
+      if (!in) { 
+       Warning("GridHelper::RegisterRuns", "Failed to open %s", s.Data());
+       continue;
+      }
+      while (!in.eof()) { 
+       Int_t r;
+       in >> r;
+       fHandler->AddRunNumber(r);
+       nRuns++;
+       Char_t c;
+       in >> c;
+       if (in.bad()) break;
+      }
+      individual = true;
+      in.close();
+    }
+    return nRuns;
+  }
+  /** 
+   * Executed before setting up tasks 
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t PreSetup() 
+  {
+    if (!PluginHelper::PreSetup()) return false;
+
+    // --- Open a connection to the grid -----------------------------
+    TGrid::Connect(Form("%s://", fUrl.GetProtocol()));
+    if (!gGrid || !gGrid->IsConnected()) { 
+      Error("GridHelper::PreSetup", "Failed to connect to AliEN");
+      return false;
+    }
+
+    return true;
+  }
+  /** 
+   * Set-up done after the task set-ups 
+   *
+   * @return true on success 
+   */
+  virtual Bool_t PostSetup() 
+  {
+    if (!PluginHelper::PostSetup()) return false;
+
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    TString name(mgr->GetName());
+
+    // --- Set the operation to do (TEST, SUBMIT, TERMINATE, FULL) ---
+    TString operation("FULL");
+    if (fOptions.Has("oper")) operation = fOptions.Get("oper");
+    fHandler->SetRunMode(operation);
+
+    // --- Do not test copying ---------------------------------------
+    fHandler->SetCheckCopy(false);
+    
+    // --- Set output to be per run ----------------------------------
+    fHandler->SetOutputToRunNo(true); 
+
+    // --- Set the job tag -------------------------------------------
+    fHandler->SetJobTag(name);
+
+    // --- Set number of test files - used in test mode only ---------
+    fHandler->SetNtestFiles(1);
+
+    // --- Set the Time-To-Live --------------------------------------
+    fHandler->SetTTL(70000);
+    
+    // --- Re-submit failed jobs as long as the ratio of failed jobs -
+    // --- is this percentage.
+    fHandler->SetMasterResubmitThreshold(95);
+
+    // --- Set the input format --------------------------------------
+    fHandler->SetInputFormat("xml-single");
+
+    // --- Set names of generated files ------------------------------
+    fHandler->SetAnalysisMacro(Form("%s.C", name.Data()));
+    fHandler->SetJDLName(Form("%s.jdl", name.Data()));
+    fHandler->SetExecutable(Form("%s.sh", name.Data()));
+    
+    // ---- Set the job price !? -------------------------------------
+    fHandler->SetPrice(1);
+
+    // --- Set whether to merge via JDL ------------------------------
+    fHandler->SetMergeViaJDL(true);
+    
+    // --- Fast read otion -------------------------------------------
+    fHandler->SetFastReadOption(false);
+
+    // --- Whether to overwrite existing output ----------------------
+    fHandler->SetOverwriteMode(true);
+
+    // --- Set the executable binary name and options ----------------
+    fHandler->SetExecutableCommand("aliroot -b -q -x");
+
+    // --- Split by storage element - must be lower case! ------------
+    fHandler->SetSplitMode("se");
+
+    // --- How much to split -----------------------------------------
+    if (fOptions.Has("split")) { 
+      if (!fOptions.Get("split").EqualTo("max")) {
+       fHandler->SetSplitMaxInputFileNumber(fOptions.Get("split").Atoi());
+      }
+    }
+    
+    // --- Enable default outputs ------------------------------------
+    fHandler->SetDefaultOutputs(true);
+
+    // --- Merge parameters ------------------------------------------
+    if (fOptions.Has("merge")) { 
+      if (!fOptions.Get("merge").EqualTo("max")) { 
+       fHandler->SetMaxMergeFiles(fOptions.Get("merge").Atoi());
+      }
+    }
+    fHandler->SetMergeExcludes("AliAOD.root *EventStat*.root "
+                              "*event_stat*.root");
+
+    // --- Keep log files ------------------------------------------
+    fHandler->SetKeepLogs();
+
+    // --- Set the working directory to be the trains name (with -----
+    // --- special characters replaced by '_' and the date appended),
+    // --- and also set the output directory (relative to working
+    // --- directory)
+    fHandler->SetGridWorkingDir(name.Data());
+    fHandler->SetGridOutputDir("output");
+    fHandler->SetGridDataDir(fUrl.GetFile());
+
+    // --- Get the tree name and set the file pattern ----------------
+    TString pattern;
+    if (fOptions.Has("pattern")) pattern = fOptions.Get("pattern");
+    else {
+      TString treeName(fUrl.GetAnchor());
+      if (treeName.IsNull()) { 
+       Warning("GridHelper::PreSetup", "No tree name specified, assuming T");
+       treeName = "T";
+      }
+      if      (treeName.EqualTo("esdTree")) pattern = "AliESD";
+      else if (treeName.EqualTo("aodTree")) pattern = "AliAOD";
+    }
+    fHandler->SetDataPattern(pattern);
+    fHandler->SetRunPrefix(mgr->GetMCtruthEventHandler() ? "" : "000");
+
+    // --- Add the run numbers ---------------------------------------
+    Int_t nRun = RegisterRuns();
+
+    // --- Set number of runs per master - set to one to per run -----
+    fHandler->SetNrunsPerMaster(fOptions.Has("run-merge") ? 1 : nRun+1);
+
+    // --- Loop over defined containers in the analysis manager, and -
+    // --- declare these as outputs
+    TString listOfAODs  = "";
+    TString listOfHists = "";
+
+    AliAnalysisDataContainer* cont = 0;
+    TIter nextCont(mgr->GetOutputs());
+    while ((cont = static_cast<AliAnalysisDataContainer*>(nextCont()))) {
+      TString outName(cont->GetFileName());
+      TString& list = (outName == "default" ? listOfAODs : listOfHists);
+      if (outName == "default") { 
+       if (!mgr->GetOutputEventHandler()) continue; 
+
+       outName = mgr->GetOutputEventHandler()->GetOutputFileName();
+      }
+      if (list.Contains(outName)) continue;
+      if (!list.IsNull()) list.Append(",");
+      list.Append(outName);
+    }
+    if (!mgr->GetExtraFiles().IsNull()) { 
+      if (!listOfAODs.IsNull()) listOfAODs.Append("+");
+      TString extra = mgr->GetExtraFiles();
+      extra.ReplaceAll(" ", ",");
+      listOfAODs.Append(extra);
+   }
+
+    Int_t nReplica = 2;
+    TString outArchive = Form("stderr, stdout@disk=%d", nReplica);
+    if (!listOfHists.IsNull()) 
+      outArchive.Append(Form(" hist_archive.zip:%s@disk=%d", 
+                            listOfHists.Data(), nReplica));
+    if (!listOfAODs.IsNull()) 
+      outArchive.Append(Form(" aod_archive.zip:%s@disk=%d", 
+                            listOfAODs.Data(), nReplica));
+    if (listOfAODs.IsNull() && listOfHists.IsNull()) 
+      Fatal("PostSetup", "No outputs defined");
+    
+    return true;
+  };
+  /** 
+   * Start the analysis 
+   * 
+   * @param nEvents Number of events to analyse 
+   * 
+   * @return The return value of AliAnalysisManager::StartAnalysis
+   */
+  virtual Long64_t Run(Long64_t nEvents=-1) 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    
+    return mgr->StartAnalysis("grid", nEvents);
+  }
+  /** 
+   * Link an auxilary file to working directory 
+   * 
+   * @param name Name of the file
+   * 
+   * @return true on success
+   */
+  virtual Bool_t AuxFile(const TString& name)
+  {
+    if (!Helper::AuxFile(name)) return false;
+    // We need to add this file as an additional 'library', so that the 
+    // file is uploaded to the users Grid working directory. 
+    fHandler->AddAdditionalLibrary(gSystem->BaseName(name.Data()));
+    return true;
+  }
+  /** 
+   * Get the output (directory)
+   *
+   */
+  virtual TString OutputPath() const
+  {
+    TString ret;
+    if (!fHandler) {
+      Warning("GridHelper::OutputLocation", "No AliEn handler");
+      return ret;
+    }
+    ret = fHandler->GetGridOutputDir();
+    if (ret.BeginsWith("/")) return ret;
+
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    if (!mgr) { 
+      Warning("GridHelper::OutputLocation", "No analysis manager");
+      return ret;
+    }
+    ret.Prepend(Form("%s/",  mgr->GetName()));
+    if (gGrid) 
+      ret.Prepend(Form("%s/", gGrid->GetHomeDirectory())); 
+    
+    return ret;
+  }
+  /** 
+   * @return URL help string
+   */
+  virtual const Char_t* UrlHelp() const 
+  {
+    return "alien:///<datadir>[?<options>][#<treeName>]";
+  }
+  /** 
+   * @return Short description
+   */
+  virtual const char* Desc() const { return "AliEn"; }
+};
+#endif
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/Helper.C b/PWGLF/FORWARD/trains/Helper.C
new file mode 100644 (file)
index 0000000..b46b7a2
--- /dev/null
@@ -0,0 +1,522 @@
+/**
+ * @defgroup pwglf_forward_trains_helper Analysis helpers
+ *
+ * @ingroup pwglf_forward_trains
+ * 
+ * 
+ */
+/**
+ * @file   Helper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 19:00:17 2012
+ * 
+ * @brief  Base class for analysis helpers
+ * 
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef TRAIN_HELPER_C
+#define TRAIN_HELPER_C
+#ifndef __CINT__
+# include "Option.C"
+# include <TUrl.h>
+# include <TString.h>
+# include <TMap.h>
+# include <TObjString.h>
+# include <TSystem.h>
+# include <TROOT.h>
+# include <TError.h>
+# include <TObjArray.h>
+# include <AliAnalysisManager.h>
+# include <iostream>
+#else 
+class TString;
+class TUrl;
+class TMap;
+class Option;
+class OptionList;
+#endif
+
+/**
+ * Helper class to set-up an analysis using a train 
+ *
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct Helper 
+{
+  enum EMode { 
+    kLocal, 
+    kProof, 
+    kGrid
+  };
+  enum EOperation { 
+    kTest,
+    kOffline,
+    kSubmit,
+    kTerminate, 
+    kFull
+  };
+  enum EInput { 
+    kESD, 
+    kAOD, 
+    kUser
+  };
+  Helper(const Helper& o) 
+    : fUrl(o.fUrl), fOptions(o.fOptions), fVerbose(o.fVerbose)
+  {}
+  Helper& operator=(const Helper&) { return *this; }
+  /** 
+   * Create a helper object. 
+   * 
+   * @param url Url describing the job. 
+   *
+   * - Local mode: 
+   *
+   * @code
+   * local://<path>[#<treeName>][?[recursive[&]]]
+   * @endcode 
+   *
+   * &lt;path&gt; can be a single ROOT file, a text file with one
+   * entry per file to add to the chain, or a directory containing the
+   * files. If &lt;path&gt; does not start with a '/' then it is
+   * interpreted as a relative path.
+   *
+   * - Grid mode: 
+   *
+   * @code 
+   * alien:///<path>#<pattern>
+   * @endcode
+   *
+   * - PROOF mode: 
+   * 
+   * Several options 
+   *
+   * @code 
+   * lite:///<path>[?[recursive[&]][workers=<n>]][#treeName]
+   * proof:///<path>[?[recursive[&]][workers=<n>]][#treeName]
+   * @endcode 
+   *
+   * @code 
+   * proof://<host>/<dsname>[?[workers=<n>[&]][dsname[=<outname>]]][#treeName]
+   * @endcode 
+   *
+   * Note, if &lt;host&gt; is recognised as an Alice Analysis
+   * Facility, then the Grid handler (AliAnalysisAlien) is used unless
+   * the option <tt>plain</tt> was given. 
+   * 
+   * @return Newly allocated helper or null 
+   */
+  static Helper* Create(const TUrl& url, Int_t verbose=0);
+  /** 
+   * Load a library 
+   * 
+   * @param name   Name of library 
+   * @param slave  If true also load on slaves
+   * 
+   * @return true on success, false otherwise 
+   */
+  virtual Bool_t LoadLibrary(const TString& name, 
+                            Bool_t slave=true) = 0;
+  /** 
+   * Load a source file, and compile it 
+   * 
+   * @param name Name of the source file 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t LoadSource(const TString& name)
+  {
+    if (!AuxFile(name)) return false;
+    TString base(gSystem->BaseName(name));
+    gROOT->LoadMacro(Form("%s++g", base.Data()));
+    return true;
+  }
+  /** 
+   * Load auxillary file - not compiled or sourced.  Just copied to
+   * working directory
+   * 
+   * @param name Extra file name 
+   *
+   * @return true on success 
+   */
+  virtual Bool_t LoadAux(const TString& name)
+  {
+    if (!AuxFile(name)) return false;
+    return true;
+  }
+
+  /** 
+   * Load needed ROOT libaries 
+   */
+  virtual Bool_t LoadROOT()
+  {
+    if (gSystem->Load("libTree.so")    < 0) return false;
+    if (gSystem->Load("libGeom.so")    < 0) return false;
+    if (gSystem->Load("libVMC.so")     < 0) return false;
+    if (gSystem->Load("libPhysics.so") < 0) return false;
+    if (gSystem->Load("libMinuit.so")  < 0) return false;
+    return true;
+  }
+  /** 
+   * Set-up to load the AliROOT libraries 
+   * 
+   * @param par Whether to use PAR files 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t LoadAliROOT()
+  {
+    if (!gSystem->Getenv("ALICE_ROOT")) { 
+      Error("Helper::LoadAliROOT", "Local AliROOT not available");
+      return false;
+    }
+    if (!LoadLibrary("STEERBase"))     return false;
+    if (!LoadLibrary("ESD"))           return false;
+    if (!LoadLibrary("AOD"))           return false;
+    if (!LoadLibrary("ANALYSIS"))      return false;
+    if (!LoadLibrary("OADB"))          return false;
+    if (!LoadLibrary("ANALYSISalice")) return false;
+    return true;
+  }
+  /** 
+   * Get the execution mode 
+   * 
+   * @return Execution mode set in set-up URL
+   */
+  virtual UShort_t Mode() const = 0;
+  /** 
+   * Get the operation - this only makes sense for Grid jobs
+   * 
+   * @return Operation type
+   */
+  virtual UShort_t Operation() const { return kFull; }
+  /** 
+   * Get the input data type 
+   *
+   * @return Input data type 
+   */
+  virtual Short_t InputType() const
+  {
+    UShort_t ret = DeduceType(fUrl.GetAnchor());
+    if (ret != kUser) return ret;
+
+    if (fOptions.Has("pattern")) ret = DeduceType(fOptions.Get("pattern"));
+    if (ret != kUser) return ret;
+    
+    ret = DeduceType(fUrl.GetFile());
+    return ret;
+  }
+  /** 
+   * The file part of tehe output URL - overwritten by derived classes. 
+   * 
+   * 
+   * @return File part of output URL
+   */
+  virtual TString OutputPath() const { return ""; }
+  /** 
+   * Get the location of the output data.  Use ful to define second pass 
+   * scripts, etc. 
+   * 
+   * 
+   * @return Url string 
+   */
+  virtual TString OutputLocation() const 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    if (!mgr || !mgr->GetOutputEventHandler()) return "";
+
+    TString path(OutputPath());
+    if (path.IsNull()) {
+      path = gSystem->WorkingDirectory(); 
+      // mgr->GetName();
+    }
+
+    TUrl u(fUrl);
+    u.SetFile(path);
+    u.SetAnchor("aodTree");
+    TString opt(u.GetOptions());
+    opt.ReplaceAll("AliESDs", "AliAOD");
+    u.SetOptions(opt);
+
+    return u.GetUrl();
+  }
+  /** 
+   * Set-up done before task setup 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t PreSetup() = 0;
+  /** 
+   * Set-up done after task setup 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t PostSetup() = 0;
+  /** 
+   * Run the analysis
+   * 
+   * @param nEvents Number of events to analyse 
+   * 
+   * @return The return value of AliAnalysisManager::StartAnalysis
+   */
+  virtual Long64_t Run(Long64_t nEvents=-1) = 0;
+  /** 
+   * Print information to standard output 
+   * 
+   * @param option 
+   * 
+   * @return 
+   */
+  virtual void Print(Option_t* ="") const
+  {
+    std::cout << "Url: " << fUrl.GetUrl() << std::endl;
+    fOptions.Show(std::cout);
+  }
+  /** 
+   * @return URL help string 
+   */
+  virtual const Char_t* UrlHelp() const  = 0;
+  /** 
+   * @return Short description string 
+   */
+  virtual const char* Desc() const = 0;
+  /** 
+   * Get the input URL 
+   * 
+   * @return Input URL 
+   */
+  const TUrl& Url() const { return fUrl; }
+  /** 
+   * Get the list of options 
+   * 
+   * @return Reference to list of options 
+   */
+  const OptionList& Options() const { return fOptions; }
+  /** 
+   * Create an instance of a helper class 
+   */
+  static Helper* CreateObject(const TString& cl, 
+                             const TUrl&    url, 
+                             Int_t verbose=0)
+  {
+    if (verbose > 3) gSystem->RedirectOutput("/dev/null","w");
+    if (cl.Contains("proof", TString::kIgnoreCase) || 
+       cl.Contains("lite",  TString::kIgnoreCase) || 
+       cl.Contains("aaf",   TString::kIgnoreCase)) {
+      gSystem->Load("libProof");
+      gSystem->Load("libProofPlayer");
+    }
+    gROOT->LoadMacro(Form("%s.C+",cl.Data()));
+    Long_t ptr = gROOT->ProcessLine(Form("new %s(\"%s\", %d);", 
+                                        cl.Data(), url.GetUrl(), verbose));
+    if (verbose > 3) gSystem->RedirectOutput(0);
+    if (!ptr) { 
+      Warning("Helper::CreateObject", "Failed to instantize a %s", cl.Data());
+      return 0;
+    }
+    Helper* h = reinterpret_cast<Helper*>(ptr);
+    return h;
+  }
+  /** 
+   * Show help on URL using the interpreter 
+   * 
+   * @param cl Helper class 
+   */
+  static void ShowUrlHelp(const TString& cl)
+  {
+    Helper* h = CreateObject(cl, "", true);
+    if (!h) return;
+
+    std::cout << "   " << h->UrlHelp() << std::endl;
+  }
+  /** 
+   * Show help on URL and options using the interpreter 
+   * 
+   * @param cl Helper class 
+   */
+  static void ShowFullHelp(const TString& cl) 
+  {
+    Helper* h = CreateObject(cl, "", true);
+    if (!h) return;
+    
+    std::cout << h->Desc() << ":\n" 
+             << "==============\n"
+             << "  " << h->UrlHelp() << "\n\n"
+             << "Options: " << std::endl;
+    h->Options().Help(std::cout);
+    std::cout << std::endl;
+  }
+protected:
+  /** 
+   * Constructor 
+   * 
+   * @param url Set-up URL
+   * @param opts Pre-parsed options 
+   */
+  Helper(const TUrl& url, Int_t verbose) 
+    : fUrl(url), fOptions(), fVerbose(verbose)
+  {
+  }
+
+  virtual Bool_t ParseOptions()
+  {
+    return fOptions.Parse(fUrl.GetOptions(), "&");
+  }
+  /** 
+   * Destructor 
+   */
+  virtual ~Helper()
+  {
+  }
+  /** 
+   * Normalize a library name
+   * 
+   * @param name 
+   * 
+   * @return 
+   */
+  const TString& MakeLibraryName(const TString& name)
+  {
+    static TString libName;
+
+    libName = name;
+
+    if (!libName.BeginsWith("lib")) { 
+      // Check if the library corresponds to a compiled macro 
+      if (!gSystem->AccessPathName(Form("%s_C.so", libName.Data()))) 
+       libName.Append("_C");
+      else if (!gSystem->AccessPathName(Form("../%s_C.so", libName.Data()))) 
+       libName = Form("../%s_C", libName.Data());
+      else 
+       libName = Form("lib%s", libName.Data());
+    }
+    if (!libName.EndsWith(".so"))   libName.Append(".so");
+
+    return libName;
+  }
+  /** 
+   * Link an auxilary file to working directory 
+   * 
+   * @param name Name of the file
+   * 
+   * @return true on success
+   */
+  virtual Bool_t AuxFile(const TString& name)
+  {
+    TString path(gSystem->ExpandPathName(name.Data()));
+    // If not absolute, prepend up-one
+    if (!path.BeginsWith("/")) path.Prepend("../");
+    if (gSystem->AccessPathName(path.Data())) { 
+      // File not accessible
+      Warning("Helper::LoadSource", "File %s not accessible", path.Data());
+      return false;
+    }
+    gSystem->Exec(Form("ln -s %s .", path.Data()));
+    return true;
+  }
+  /** 
+   * Deduce the top of job from a string 
+   * 
+   * @param str String 
+   * 
+   * @return Job type
+   */
+  static UShort_t DeduceType(const TString& str)
+  {
+    if (str.IsNull()) return kUser;
+    if (str.Contains("aod", TString::kIgnoreCase)) return kAOD;
+    if (str.Contains("esd", TString::kIgnoreCase)) return kESD;
+    return kUser;
+  }
+  // --- Data members ------------------------------------------------
+  TUrl        fUrl;     // The URI
+  OptionList  fOptions; 
+  Int_t       fVerbose;
+};
+
+
+
+
+// ===================================================================
+Helper* 
+Helper::Create(const TUrl& url, Int_t verbose)
+{
+  if (!url.IsValid()) { 
+    Warning("Helper::Create", "URL is invalid");
+    return 0;
+  }
+
+  TString prot(url.GetProtocol());
+  prot.ToLower();
+
+  TUrl tmp(url);
+  TString opts(tmp.GetOptions());
+  TString host(url.GetHost());
+  TString cl = "";
+  if (prot.EqualTo("alien")) { 
+    // Create an AliEn helper 
+    cl = "GridHelper";
+  }
+  else if (prot.EqualTo("local")) { 
+    // Create Lite helper 
+    cl = "LocalHelper";
+  }
+  else if (prot.EqualTo("proof")) { 
+    // Create a Proof helper 
+    if (host.IsNull()) 
+      cl = "LiteHelper";
+    else if (host.BeginsWith("alice-caf")) { 
+      // AAF 
+      cl = opts.Contains("plugin") ? "AAFPluginHelper" : "AAFHelper";
+    }
+    else 
+      cl = "ProofHelper";
+  }
+  else if (prot.EqualTo("lite")) { 
+    // Create a Proof helper 
+    cl = "LiteHelper";
+  }
+  else if (prot.EqualTo("help")) {
+    // Special HELP protocol
+    if (host.Contains("options")) {
+      std::cout << "Possible URL types and options are:" << std::endl;
+      ShowFullHelp("LocalHelper");
+      ShowFullHelp("ProofHelper");
+      ShowFullHelp("LiteHelper");
+      ShowFullHelp("AAFHelper");
+      ShowFullHelp("AAFPluginHelper");
+      ShowFullHelp("GridHelper");
+      return 0;
+    }
+    std::cout << "Possible URL types are:" << std::endl;
+    ShowUrlHelp("LocalHelper");
+    ShowUrlHelp("ProofHelper");
+    ShowUrlHelp("LiteHelper");
+    ShowUrlHelp("AAFHelper");
+    ShowUrlHelp("AAFPluginHelper");
+    ShowUrlHelp("GridHelper");
+    return 0;
+  }
+  // --- Check if we got a scheme ------------------------------------
+  if (cl.IsNull()) {
+    Error("Helper::Create", "Unknown scheme: %s", prot.Data());
+    return 0;
+  }
+
+  // --- Use interpreter to make our object --------------------------
+  Helper* helper = CreateObject(cl, url, verbose);
+  if (!helper) {
+    Error("Helper::Create", "Failed to make object of class %s", cl.Data());
+    return 0;
+  }
+
+  // --- Parse options -----------------------------------------------
+  if (!helper->ParseOptions()) {
+    delete helper;
+    helper = 0;
+  }
+
+  return helper;
+}
+
+#endif
diff --git a/PWGLF/FORWARD/trains/LiteHelper.C b/PWGLF/FORWARD/trains/LiteHelper.C
new file mode 100644 (file)
index 0000000..163d774
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+ * @file   LiteHelper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 18:59:59 2012
+ * 
+ * @brief  Proof-Lite analysis helper
+ * 
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef LITEHELPER_C
+#define LITEHELPER_C
+#include "ProofHelper.C"
+#ifndef __CINT__
+# include "ChainBuilder.C"
+# include <TUrl.h>
+# include <TString.h>
+# include <TChain.h>
+# include <AliAnalysisManager.h>
+#else
+class TChain;
+class TUrl;
+#endif
+
+// ===================================================================
+/**
+ * Handler of analysis in Proof-Lite.  This is triggered by URIs of the 
+ * form 
+ * 
+ * @code 
+ * local:///<datadir>[?<options>][#treeName]
+ * local:///<collection>[?<options>][#treeName]
+ * local:///<file>[?<options>][#treeName]
+ * @endcode 
+ *
+ * where 
+ *
+ * <dl>
+ *   <dt><tt>&lt;datadir&gt;</tt></dt>
+ *   <dd>is the base directory holding data files </dd>
+ *   <dt><tt>&lt;collection&gt;</tt></dt>
+ *   <dd>is an ASCII or XML list of input sources</dd>
+ *   <dt><tt>&lt;file&gt;</tt></dt>
+ *   <dd>is a single ROOT file</dd>
+ *   <dt><tt>&lt;options&gt;</tt></dt>
+ *   <dd>A &amp; separated list of options
+ *     <dl>
+ *       <dt><tt>recursive</tt></dt>
+ *       <dd>Scan &lt;datadir&gt; recursively</dd>
+ *       <dt><tt>mc</tt></dt>
+ *       <dd>Scan also for MC files (<tt>galice.root</tt>, 
+ *          <tt>Kinematics.root</tt>, and <tt>TrackRefs.root</tt>) when 
+ *          scanning &lt;datadir&gt;</dd>
+ *       <dt><tt>pattern=&lt;GLOB&gt;</tt></dt>
+ *       <dd>Shell glob pattern that files must check when scanning 
+ *         &lt;datadir&gt;</dd>
+ *       <dt><tt>workers=N[x]</tt></dt>
+ *       <dd>Set the number of workers to use.  If <tt>x</tt> is appended, 
+ *         then it's maximum number of workers per slave</dd>
+ *       <dt><tt>par[=all]</tt></dt>
+ *       <dd>Use PAR files.  If the value <tt>all</tt> is given, then also 
+ *         PAR files of STEERBase, ESD, AOD, ANALYSIS, OADB, ANALYSISalice 
+ *         are used. </dd>
+ *       <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
+ *       <dd>Set the AliROOT mode.  If not specified <tt>default</tt> 
+ *         is assumed</tt>.  See also CreateAliROOTPar</dd>
+ *      </dl>
+ *   </dd>
+ * </dl>
+ *       
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct LiteHelper : public ProofHelper
+{
+  /** 
+   * Constructor 
+   * 
+   * @param url   Url 
+   * @param opts  Options 
+   */
+  LiteHelper(const TUrl& url, Int_t verbose)
+    : ProofHelper(url, verbose), fChain(0)
+  {
+    fOptions.Add("mc",       "Scan for MC files (galice,kinematics,trackrefs)");
+    fOptions.Add("recursive","Recursive scan");
+    fOptions.Add("pattern",  "GLOB", "File name pattern", "*.root");
+    fOptions.Remove("dsname");
+    fOptions.Remove("storage");
+  }
+  /** 
+   * Set-up done before task set-ups 
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t PreSetup() 
+  {
+    fUrl.SetProtocol("lite");
+    Bool_t ret = ProofHelper::PreSetup();
+    return ret;
+  }
+  /** 
+   * Set-up done after task set-ups
+   * 
+   * @return true on success
+   */
+  virtual Bool_t PostSetup()
+  {
+    // -- Check for local chain --------------------------------------
+    TString  pattern   = (fOptions.Has("pattern") ?fOptions.Get("pattern") :"");
+    TString  treeName  = fUrl.GetAnchor();
+    Bool_t   recursive = fOptions.Has("recursive");
+    Bool_t   mc        = fOptions.Has("mc");
+    TString  src       = fUrl.GetFile();
+    UShort_t type      = ChainBuilder::CheckSource(src);
+    if (type == ChainBuilder::kInvalid) {
+      Error("LiteHelper", "Cannot generate TChain from %s", src.Data());
+      return false;
+    }
+
+    // --- Create the chain ------------------------------------------
+    fChain = ChainBuilder::Create(type, src, treeName, pattern, mc, recursive);
+    if (!fChain) { 
+      Error("PreSetup", "No chain defined");
+      return false;
+    }
+
+    return ProofHelper::PostSetup();
+  }
+  /** 
+   * Start the analysis 
+   * 
+   * @param nEvents Number of events to analyse 
+   * 
+   * @return The return value of AliAnalysisManager::StartAnalysis
+   */
+  virtual Long64_t Run(Long64_t nEvents=-1) 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    gProof->SetLogLevel(TMath::Max(fVerbose-2,0), 
+                       /* TProofDebug::kPacketizer| */
+                       TProofDebug::kLoop|
+                       /* TProofDebug::kSelector|
+                       TProofDebug::kOutput|
+                       TProofDebug::kInput|
+                       TProofDebug::kGlobal|*/
+                       TProofDebug::kPackage);
+    if (nEvents < 0) nEvents = fChain->GetEntries();
+    Long64_t ret = mgr->StartAnalysis("proof", fChain, nEvents);
+    
+    if (fVerbose > 2) 
+      TProof::Mgr(fUrl.GetUrl())->GetSessionLogs()->Save("*","lite.log");
+    return ret;
+  }
+
+  /** 
+   * @return URL help string
+   */
+  virtual const Char_t* UrlHelp() const 
+  {
+    return "lite://<datadir_or_list>[?<options>][#<treeName]";
+  }
+  /** 
+   * @return The short description
+   */
+  virtual const char* Desc() const { return "PROOF-lite"; }
+  /** Our chain */
+  TChain* fChain;
+};
+#endif
+//
+// EOF
+//
+
diff --git a/PWGLF/FORWARD/trains/LocalHelper.C b/PWGLF/FORWARD/trains/LocalHelper.C
new file mode 100644 (file)
index 0000000..d5f8017
--- /dev/null
@@ -0,0 +1,167 @@
+/**
+ * @file   LocalHelper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 18:59:42 2012
+ * 
+ * @brief  Local analysis helper
+ * 
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef LOCALHELPER_C
+#define LOCALHELPER_C
+#ifndef __CINT__
+# include "Helper.C"
+# include "ChainBuilder.C"
+# include <TUrl.h>
+# include <TString.h>
+# include <TSystem.h>
+# include <AliAnalysisManager.h>
+#else
+class TChain;
+class Helper;
+class TUrl;
+#endif
+
+// ===================================================================
+/** 
+ * Handle local analysis jobs 
+ *
+ * This is triggered by URIs of the form 
+ *
+ * @code 
+ * local:///<datadir>[?<options>][#treeName]
+ * local:///<collection>[?<options>][#treeName]
+ * local:///<file>[?<options>][#treeName]
+ * @endcode 
+ *
+ * where 
+ *
+ * <dl>
+ *   <dt><tt>&lt;datadir&gt;</tt></dt>
+ *   <dd>is the base directory holding data files </dd>
+ *   <dt><tt>&lt;collection&gt;</tt></dt>
+ *   <dd>is an ASCII or XML list of input sources</dd>
+ *   <dt><tt>&lt;file&gt;</tt></dt>
+ *   <dd>is a single ROOT file</dd>
+ *   <dt><tt>&lt;options&gt;</tt></dt>
+ *   <dd>A &amp; separated list of options
+ *     <dl>
+ *       <dt><tt>recursive</tt></dt>
+ *       <dd>Scan &lt;datadir&gt; recursively</dd>
+ *       <dt><tt>mc</tt></dt>
+ *       <dd>Scan also for MC files (<tt>galice.root</tt>, 
+ *          <tt>Kinematics.root</tt>, and <tt>TrackRefs.root</tt>) when 
+ *          scanning &lt;datadir&gt;</dd>
+ *       <dt><tt>pattern=&lt;GLOB&gt;</tt></dt>
+ *       <dd>Shell glob pattern that files must check when scanning 
+ *         &lt;datadir&gt;</dd>
+ *      </dl>
+ *   </dd>
+ * </dl>
+ *       
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct LocalHelper : public Helper
+{
+  /** 
+   * Constructor 
+   * 
+   * @param url   Url 
+   * @param opts  Options 
+   */
+  LocalHelper(const TUrl& url, Int_t verbose)
+    : Helper(url, verbose), fChain(0)
+  {
+    fOptions.Add("mc",       "Scan for MC files (galice,kinematics,trackrefs)");
+    fOptions.Add("recursive","Scan recursive");
+    fOptions.Add("pattern",  "GLOB", "File name pattern", "*.root");
+  }
+  /** 
+   * Destructor 
+   */
+  virtual ~LocalHelper() {}
+  /** 
+   * Load a library 
+   * 
+   * @param name    Name of library 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t LoadLibrary(const TString& name, Bool_t)
+  {
+    Int_t ret = gSystem->Load(MakeLibraryName(name));
+    return ret >= 0;
+  }
+  /** 
+   * Get the execution mode 
+   *
+   * @return Always kLocal
+   */
+  virtual UShort_t Mode() const { return kLocal; }
+  /**
+   * Get the mode string used for AliAnalysisManager::StartAnalysis
+   */
+  virtual const char* ModeString() const { return "local"; }
+  /** 
+   * Set-up done before task set-ups 
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t PreSetup() 
+  {
+    return true;
+  }
+  /** 
+   * Set-up done after the task set-ups 
+   *
+   * @return true on success 
+   */
+  virtual Bool_t PostSetup() 
+  {
+    TString treeName(fUrl.GetAnchor());
+    TString pattern(fOptions.Has("pattern") ? fOptions.Get("pattern") : "");
+    Bool_t  recursive = fOptions.Has("recursive");
+    Bool_t  mc        = fOptions.Has("mc");
+
+    fChain = ChainBuilder::Create(fUrl.GetFile(), treeName, 
+                                 pattern, mc, recursive);
+
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    if (!mgr) { 
+      Error("PostSetup", "No analysis manager defined");
+      return false;
+    }
+    return true;
+  };
+  /** 
+   * Start the analysis 
+   * 
+   * @param nEvents Number of events to analyse 
+   * 
+   * @return The return value of AliAnalysisManager::StartAnalysis
+   */
+  virtual Long64_t Run(Long64_t nEvents=-1) 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    
+    if (nEvents < 0) nEvents = fChain->GetEntries();
+    return mgr->StartAnalysis(fUrl.GetProtocol(), fChain, nEvents);
+  }
+  /** 
+   * @return URL help string
+   */
+  virtual const Char_t* UrlHelp() const 
+  {
+    return "local://<datadir or list>[?<options>][#<treeName>]";
+  }
+  /** 
+   * @return Short description 
+   */
+  virtual const char* Desc() const { return "Local"; }
+  TChain* fChain; // Our chain
+};
+#endif
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakeAODTrain.C b/PWGLF/FORWARD/trains/MakeAODTrain.C
new file mode 100644 (file)
index 0000000..b3eb10c
--- /dev/null
@@ -0,0 +1,189 @@
+/**
+ * @file   MakeAODTrain.C
+ * @author Christian Holm Christensen <cholm@dalsgaard.hehi.nbi.dk>
+ * @date   Tue Jul 12 10:05:30 2011
+ * 
+ * @brief  Run first pass analysis - make AOD tree
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+#include "TrainSetup.C"
+
+//====================================================================
+/**
+ * Analysis train to make Forward and Central multiplicity
+ * 
+ *
+ * @ingroup pwglf_forward_aod
+ * @ingroup pwglf_forward_trains_specific
+ */
+class MakeAODTrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor. 
+   * 
+   * @param name     Name of train (free form)
+   */
+  MakeAODTrain(const  TString& name) 
+    : TrainSetup(name)
+  {
+    fOptions.Add("sys",   "SYSTEM",  "1:pp, 2:PbPb, 3:pPb", "");
+    fOptions.Add("snn",   "ENERGY",  "Center of mass energy in GeV", "");
+    fOptions.Add("field", "STRENGTH","L3 field strength in kG", "");
+    fOptions.Add("cent",  "Use centrality");
+    fOptions.Add("tpc-ep", "Use TPC event plane");
+    fOptions.Add("forward-config", "FILE", "Forward configuration", 
+                "ForwardAODConfig.C");
+    fOptions.Add("central-config", "FILE", "Forward configuration", 
+                "CentralAODConfig.C");
+    fOptions.Add("satelitte", "Use satelitte interactions");
+    fOptions.Set("type", "ESD");
+  }
+protected:
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   * @param mgr  Analysis manager 
+   */
+  void CreateTasks(AliAnalysisManager* mgr)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("forward.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    fHelper->LoadLibrary("PWGLFforward2");
+    
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/ANALYSIS/macros",
+                            gROOT->GetMacroPath()));
+
+    // --- Check if this is MC ---------------------------------------
+    Bool_t mc = mgr->GetMCtruthEventHandler() != 0;
+    
+    // --- Add TPC eventplane task
+    if (fOptions.Has("tpc-ep")) gROOT->Macro("AddTaskEventplane.C");
+
+    // --- Task to copy header information ---------------------------
+    gROOT->Macro("AddTaskCopyHeader.C");
+
+    // --- Get options -----------------------------------------------
+    UShort_t sys = fOptions.AsInt("sys", 0);
+    UShort_t sNN = fOptions.AsInt("snn", 0);
+    UShort_t fld = fOptions.AsInt("field", 0);
+    
+    // --- Add the task ----------------------------------------------
+    TString fwdConfig = fOptions.Get("forward-config");
+    gROOT->Macro(Form("AddTaskForwardMult.C(%d,%d,%d,%d,\"%s\")", 
+                     mc, sys, sNN, fld, fwdConfig.Data()));
+    fHelper->LoadAux(gSystem->Which(gROOT->GetMacroPath(), fwdConfig));
+
+    // --- Add the task ----------------------------------------------
+    TString cenConfig = fOptions.Get("central-config");
+    gROOT->Macro(Form("AddTaskCentralMult.C(%d,%d,%d,%d,\"%s\")", 
+                     mc, sys, sNN, fld, cenConfig.Data()));
+    fHelper->LoadAux(gSystem->Which(gROOT->GetMacroPath(), cenConfig));
+
+    // --- Add MC particle task --------------------------------------
+    if (mc) gROOT->Macro("AddTaskMCParticleFilter.C");
+
+  }
+  //__________________________________________________________________
+  /** 
+   * Create physics selection , and add to manager
+   * 
+   * @param mc Whether this is for MC 
+   * @param mgr Manager 
+   */
+  void CreatePhysicsSelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    TrainSetup::CreatePhysicsSelection(mc, mgr);
+
+    // --- Get input event handler -----------------------------------
+    AliInputEventHandler* ih =
+      dynamic_cast<AliInputEventHandler*>(mgr->GetInputEventHandler());
+    if (!ih) 
+      Fatal("CreatePhysicsSelection", "Couldn't get input handler (%p)", ih);
+    
+    // --- Get Physics selection -------------------------------------
+    AliPhysicsSelection* ps = 
+      dynamic_cast<AliPhysicsSelection*>(ih->GetEventSelection());
+    if (!ps) 
+      Fatal("CreatePhysicsSelection", "Couldn't get PhysicsSelection (%p)",ps);
+
+    // --- Special for pPb pilot run Sep. 2012 -----------------------
+    UShort_t sys = fOptions.AsInt("sys", 0);
+    if (sys == 3) { 
+      Warning("CreatePhysicsSelection", 
+             "Special setup for pPb pilot run September, 2012");
+      gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/ANALYSIS/macros",
+                              gROOT->GetMacroPath()));
+      gROOT->LoadMacro("PhysicsSelectionOADB_CINT5_pA.C");
+      gROOT->ProcessLine(Form("((AliPhysicsSelection*)%p)"
+                             "->SetCustomOADBObjects("
+                             "OADBSelection_CINT5_V0A(),0);", ps));
+      ps->SetSkipTriggerClassSelection(true);
+    }
+    // --- Ignore trigger class when selecting events.  This means ---
+    // --- that we get offline+(A,C,E) events too --------------------
+    // ps->SetSkipTriggerClassSelection(true);
+  }
+  //__________________________________________________________________
+  /** 
+   * Create the centrality selection only if requested
+   * 
+   * @param mc  Monte-Carlo truth flag 
+   * @param mgr Manager
+   */
+  void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    if (!fOptions.Has("cent")) return;
+    TrainSetup::CreateCentralitySelection(mc, mgr);
+  }
+  //__________________________________________________________________
+  const char* ClassName() const { return "MakeAODTrain"; }
+  //__________________________________________________________________
+  /** 
+   * Overloaded to create new dNdeta.C and dndeta.sh in the output 
+   * directory
+   * 
+   * @param asShellScript 
+   */
+  void SaveSetup(Bool_t asShellScript)
+  {
+    TrainSetup::SaveSetup(asShellScript);
+    
+    TString cls("MakedNdetaTrain");
+    TString name(fName); name.Append("_dndeta");
+    OptionList opts(fOptions);
+    opts.Remove("forward-config");
+    opts.Remove("central-config");
+    opts.Remove("sys");
+    opts.Remove("snn");
+    opts.Remove("field");
+    opts.Remove("bare-ps");
+    opts.Remove("tpc-ep");
+    opts.Add("trig", "TRIGGER", "Trigger type", "");
+    opts.Add("vzMin", "CENTIMETER", "Lower bound on Ip Z", "-10");
+    opts.Add("vzMax", "CENTIMETER", "Upper bound on Ip Z", "+10");
+    opts.Add("scheme", "FLAGS", "Normalization scheme", "EVENT BACKGROUND");
+    opts.Add("cut-edges", "Cut edges of acceptance");
+    opts.Add("trigEff", "EFFICIENCY", "Trigger efficiency", "1");
+    opts.Add("trigEff0", "EFFICIENCY", "0-bin trigger efficiency", "1");
+    TString out = fHelper->OutputLocation();
+    if (out.IsNull()) out = fEscapedName;
+    opts.Set("url", out);
+    opts.Set("type", "AOD");
+    // opts.Show(std::cout);
+
+    SaveSetupROOT("dNdeta", cls, name, opts);
+    if (asShellScript) 
+      SaveSetupShell("dndeta", cls, name, opts);
+  }
+};
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakeFMDELossTrain.C b/PWGLF/FORWARD/trains/MakeFMDELossTrain.C
new file mode 100644 (file)
index 0000000..278b51e
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+ * @file   MakeFMDELossTrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:53:02 2012
+ * 
+ * @brief  
+ * 
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+#include "TrainSetup.C"
+
+//====================================================================
+/**
+ * Analysis train to do energy loss fits
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ * @ingroup pwglf_forward_eloss
+ */
+class MakeFMDELossTrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor.  
+   * 
+   * @param name     Name of train 
+   */
+  MakeFMDELossTrain(const char* name  = "FMD Energy Loss")
+    : TrainSetup(name)
+  {
+    fOptions.Add("cent", "Use centrality");
+  }
+protected:
+  //------------------------------------------------------------------
+  /** 
+   * Create the analysis manager 
+   * 
+   * @param name Name of the analysis 
+   * 
+   * @return Created analysis manager 
+   */
+  virtual AliAnalysisManager* CreateAnalysisManager(const char* name)
+  {
+    AliAnalysisManager* mgr = TrainSetup::CreateAnalysisManager(name);
+    // mgr->SetAutoBranchLoading(false);
+    return mgr;
+  }
+  //__________________________________________________________________
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   * @param mgr  Analysis manager 
+   */
+  void CreateTasks(AliAnalysisManager* mgr)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("forward_eloss.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    LoadLibrary("PWGLFforward2");
+    
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+
+    // --- Check if this is MC ---------------------------------------
+    Bool_t mc   = mgr->GetMCtruthEventHandler() != 0;
+    Bool_t cent = fOptions.Has("cent");
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskFMDELoss.C(%d,%d)", mc, cent));
+  }
+  /** 
+   * Create entrality selection if enabled 
+   * 
+   * @param mc   Whether this is MC or not
+   * @param mgr  Analysis manager 
+   */
+  virtual void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    if (!fOptions.Has("cent")) return;
+
+    const char* name = "CentralitySelection";
+    gROOT->Macro("AddTaskCentrality.C");
+    AliCentralitySelectionTask* ctask = 
+      dynamic_cast<AliCentralitySelectionTask*>(mgr->GetTask(name));
+    if (!ctask) return;
+    // ctask->SetPass(fESDPass);
+    if (mc) ctask->SetMCInput();
+  }
+  /** 
+   * Crete output handler - we don't want one here. 
+   * 
+   * @return 0
+   */
+  AliVEventHandler* CreateOutputHandler(UShort_t) { return 0; }
+  //__________________________________________________________________
+  const char* ClassName() const { return "MakeFMDElossTrain"; }
+};
+
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakeFMDEventPlaneTrain.C b/PWGLF/FORWARD/trains/MakeFMDEventPlaneTrain.C
new file mode 100644 (file)
index 0000000..bae336e
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * @file   MakeFMDEventPlaneTrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:52:39 2012
+ * 
+ * @brief  
+ * 
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+#include "TrainSetup.C"
+
+//====================================================================
+/**
+ * Analysis train to make @f$ \Psi_R@f$
+ * 
+ *
+ * @ingroup pwglf_forward_flow
+ * @ingroup pwglf_forward_trains_specific
+ */
+class MakeFMDEventPlaneTrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor.  
+   * 
+   * @param name     Name of train (free form)
+   */
+  MakeFMDEventPlaneTrain(const char* name) 
+  : TrainSetup(name)
+  {
+    fOptions.Set("type", "AOD");
+  }
+protected:
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   */
+  void CreateTasks(AliAnalysisManager*)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("AnalysisResults.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    LoadLibrary("PWGLFforward2)");
+    
+    Bool_t mc   = mgr->GetMCtruthEventHandler() != 0;
+
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2:"
+                            "$ALICE_ROOT/ANALYSIS/macros",
+                            gROOT->GetMacroPath()));
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskFMDEventPlane.C(%d)", mc));
+  }
+  /** 
+   * Do not the centrality selection
+   */
+  void CreateCentralitySelection(Bool_t, AliAnalysisManager*) {}
+  /** 
+   * Crete output handler - we don't want one here. 
+   * 
+   * @return 0
+   */
+  AliVEventHandler* CreateOutputHandler(UShort_t) { return 0; }
+  //__________________________________________________________________
+  const char* ClassName() const { return "MakeFMDEventPlaneTrain"; }
+};
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakeFlowTrain.C b/PWGLF/FORWARD/trains/MakeFlowTrain.C
new file mode 100644 (file)
index 0000000..9e21941
--- /dev/null
@@ -0,0 +1,114 @@
+/**
+ * @file   MakeFlowTrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:51:48 2012
+ * 
+ * @brief  
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ * 
+ */
+#include "TrainSetup.C"
+
+//====================================================================
+/**
+ * Analysis train to make @f$ flow@f$
+ * 
+ *
+ * @ingroup pwglf_forward_flow
+ * @ingroup pwglf_forward_trains_specific
+ */
+class MakeFlowTrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor.  Date and time must be specified when running this
+   * in Termiante mode on Grid
+   * 
+   * @param name     Name of train (free form)
+   */
+  MakeFlowTrain(const char* name)
+  : TrainSetup(name),
+    fType("123456"), 
+    fOutlierCutFMD(4.1), 
+    fOutlierCutSPD(4.1),
+    fAddFlow(""),
+      fAddFType(0),
+    fAddFOrder(0)
+  {
+    fOptions.Add("mom", "MOMENTS", "Flow moments to determine", "123456");
+    fOptions.Add("outlier-fmd", "NSIGMA", "Cut on outliers in FMD", "4.1");
+    fOptions.Add("outlier-spd", "NSIGMA", "Cut on outliers in SPD", "4.1");
+    fOptions.Add("afterburner", "WHAT", "What to afterburn", "eta phi b pid");
+    fOptions.Add("ab-type", "1|2|3|4", "Type of afterburner", "");
+    fOptions.Add("ab-order", "1|2|3|4|5|6", "Order used by afterburner", "");
+    fOptions.Add("satelitte", "Whether to use satelitte interactions");
+  }
+protected:
+  //__________________________________________________________________
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   */
+  void CreateTasks(AliAnalysisManager* mgr)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("AnalysisResults.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    LoadLibrary("PWGLFforward2");
+    
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+
+    // --- Get the parameters ----------------------------------------
+    TString  type        = fOptions.Get("mom");
+    Bool_t   mc          =  mgr->GetMCtruthEventHandler() != 0;
+    Bool_t   satelitte   = fOptions.Has("satelitte");
+    Double_t outlierFMD  = fOptions.AsDouble("outlier-fmd");
+    Double_t outlierSPD  = fOptions.AsDouble("outlier-spd");
+    TString  afterburner = fOptions.Get("afterburner");
+    Int_t    abType      = fOptions.Get("ab-type");
+    Int_t    abOrder     = fOptions.Get("ab-order");
+    
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskForwardFlow.C(\"%s\",%d,%d,%f,%f,\"%s\",%d,%d)",
+                     type.Data(), mc, satelitte, outlierFMD, outlierSPD,
+                     afterburner.Data(), abType, abOrder));
+  }
+  //__________________________________________________________________
+  /** 
+   * Do not the centrality selection
+   */
+  void CreateCentralitySelection(Bool_t, AliAnalysisManager*) {}
+  //__________________________________________________________________
+  /** 
+   * Crete output handler - we don't want one here. 
+   * 
+   * @return 0
+   */
+  AliVEventHandler* CreateOutputHandler(UShort_t) { return 0; }
+  //__________________________________________________________________
+  /** 
+   * Create MC input handler.  Since this train does not use the MC
+   * information from @c galice.root, @c Kinematics.root, and @c
+   * TrackRefs.root directly, we define this member function to return
+   * null even when doing MC analysis.  This train _only_ looks at the
+   * AOD object of the _processed_ MC data.
+   * 
+   * @return Always 0
+   */
+  AliVEventHandler* CreateMCHandler(UShort_t, bool) { return 0; }
+  //__________________________________________________________________
+  /** 
+   * Get the class name of the train setup 
+   * 
+   * @return Class name 
+   */
+  const char* ClassName() const { return "MakeFlowTrain"; }
+};
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakeFullTrain.C b/PWGLF/FORWARD/trains/MakeFullTrain.C
new file mode 100644 (file)
index 0000000..db86cfd
--- /dev/null
@@ -0,0 +1,209 @@
+#include "TrainSetup.C"
+/**
+ * @file   MakeFullTrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:53:43 2012
+ * 
+ * @brief  
+ * 
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+
+//====================================================================
+/**
+ * Analysis train to make Forward and Central multiplicity, @f$
+ * dN/d\eta@f$, flow and @f$\Psi_R@f$ in one loop over the ESDs 
+ *
+ * @ingroup pwglf_forward_aod
+ * @ingroup pwglf_forward_dndete
+ * @ingroup pwglf_forward_flow
+ * @ingroup pwglf_forward_trains_specific
+ */
+class MakeFullTrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor.  Date and time must be specified when running this
+   * in Termiante mode on Grid
+   * 
+   * @param name     Name of train (free form)
+   */
+  MakeFullTrain(const  char* name) 
+    : TrainSetup(name)
+  {
+    fOptions.Add("sys",   "SYSTEM",  "1:pp, 2:PbPb, 3:pPb", "");
+    fOptions.Add("snn",   "ENERGY",  "Center of mass energy in GeV", "");
+    fOptions.Add("field", "STRENGTH","L3 field strength in kG", "");
+    fOptions.Add("cent",  "Use centrality");
+    fOptions.Add("tpc-ep", "Use TPC event plane");
+    fOptions.Add("forward-config", "FILE", "Forward configuration", 
+                "ForwardAODConfig.C");
+    fOptions.Add("central-config", "FILE", "Forward configuration", 
+                "CentralAODConfig.C");
+    fOptions.Add("satelitte", "Use satelitte interactions");
+    fOptions.Add("trig",     "TYPE", "Trigger type", "INEL");
+    fOptions.Add("vzMin",    "CENTIMETER", "Min Ip Z", "-10");
+    fOptions.Add("vzMax",    "CENTIMETER", "Max Ip Z", "+10");
+    fOptions.Add("scheme",   "SCHEME", "Normalization scheme", "");
+    fOptions.Add("trigEff",  "EFFICENCY", "Trigger effeciency", "1");
+    fOptions.Add("trigEff0", "EFFICENCY", "0-bin trigger effeciency", "1");
+    fOptions.Add("cut-edges", "Cut acceptance edges");
+    fOptions.Add("mom", "MOMENTS", "Flow moments to determine", "123456");
+    fOptions.Add("outlier-fmd", "NSIGMA", "Cut on outliers in FMD", "4.1");
+    fOptions.Add("outlier-spd", "NSIGMA", "Cut on outliers in SPD", "4.1");
+    fOptions.Add("afterburner", "WHAT", "What to afterburn", "eta phi b pid");
+    fOptions.Add("ab-type", "1|2|3|4", "Type of afterburner", "");
+    fOptions.Add("ab-order", "1|2|3|4|5|6", "Order used by afterburner", "");
+
+    fOptions.Set("type", "ESD");
+  }
+protected:
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   * @param mgr  Analysis manager 
+   */
+  void CreateTasks(AliAnalysisManager* mgr)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("forward.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    LoadLibrary("PWGLFforward2");
+    
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/ANALYSIS/macros",
+                            gROOT->GetMacroPath()));
+
+    // --- Check if this is MC ---------------------------------------
+    Bool_t mc = mgr->GetMCtruthEventHandler() != 0;
+    
+    // --- Add TPC eventplane task -----------------------------------
+    if (fOptions.Has("tpc-ep")) gROOT->Macro("AddTaskEventplane.C");
+
+    // --- Task to copy header information ---------------------------
+    gROOT->Macro("AddTaskCopyHeader.C");
+
+    // --- Get options -----------------------------------------------
+    UShort_t sys = fOptions.AsInt("sys", 0);
+    UShort_t sNN = fOptions.AsInt("snn", 0);
+    UShort_t fld = fOptions.AsInt("field", 0);
+    
+    // --- Add the task ----------------------------------------------
+    TString fwdConfig = fOptions.Get("forward-config");
+    gROOT->Macro(Form("AddTaskForwardMult.C(%d,%d,%d,%d,\"%s\")", 
+                     mc, sys, sNN, fld, fwdConfig.Data()));
+    fHelper->LoadAux(gSystem->Which(gROOT->GetMacroPath(), fwdConfig));
+
+    // --- Add the task ----------------------------------------------
+    TString cenConfig = fOptions.Get("central-config");
+    gROOT->Macro(Form("AddTaskCentralMult.C(%d,%d,%d,%d,\"%s\")", 
+                     mc, sys, sNN, fld, cenConfig.Data()));
+    fHelper->LoadAux(gSystem->Which(gROOT->GetMacroPath(), cenConfig));
+
+    // --- Get parameters --------------------------------------------
+    TString  trig   = fOptions.Get("trig");
+    TString  scheme = fOptions.Get("scheme");
+    Double_t vzMin  = fOptions.AsDouble("vzmin", -10);
+    Double_t vzMax  = fOptions.AsDouble("vzmax", +10);
+    Double_t effT   = fOptions.AsDouble("trigEff", 1);
+    Double_t effT0  = fOptions.AsDouble("trigEff0", 1);
+    Bool_t   cent   = fOptions.Has("cent");
+    Bool_t   edges  = fOptions.Has("cut-edges");
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskForwarddNdeta.C(\"%s\",%f,%f,%d,\"%s\")",
+                     trig.Data(), vzMin, vzMax, cent, scheme.Data(),
+                     edges, trigEff, trigEff0));
+
+    gROOT->Macro(Form("AddTaskCentraldNdeta.C(\"%s\",%f,%f,%d,\"%s\")",
+                     trig.Data(), vzMin, vzMax, cent, scheme.Data()),
+                     edges, trigEff, trigEff0);
+
+    gROOT->Macro(Form("AddTaskMCTruthdNdeta.C(\"%s\",%f,%f,%d,\"%s\")",
+                     trig.Data(), vzMin, vzMax, cent, scheme.Data()),
+                     edges, trigEff, trigEff0);
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskFMDEventPlane.C(%d)", mc));
+
+    // --- Add MC particle task --------------------------------------
+    if (mc) gROOT->Macro("AddTaskMCParticleFilter.C");
+
+    // --- Get the parameters ----------------------------------------
+    TString  type        = fOptions.Get("mom");
+    Bool_t   satelitte   = fOptions.Has("satelitte");
+    Double_t outlierFMD  = fOptions.AsDouble("outlier-fmd");
+    Double_t outlierSPD  = fOptions.AsDouble("outlier-spd");
+    TString  afterburner = fOptions.Get("afterburner");
+    Int_t    abType      = fOptions.Get("ab-type");
+    Int_t    abOrder     = fOptions.Get("ab-order");
+    
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskForwardFlow.C(\"%s\",%d,%d,%f,%f,\"%s\",%d,%d)",
+                     type.Data(), mc, satelitte, outlierFMD, outlierSPD,
+                     afterburner.Data(), abType, abOrder));
+  }
+  //__________________________________________________________________
+  /** 
+   * Create physics selection , and add to manager
+   * 
+   * @param mc Whether this is for MC 
+   * @param mgr Manager 
+   */
+  void CreatePhysicsSelection(Bool_t mc,
+                             AliAnalysisManager* mgr)
+  {
+    TrainSetup::CreatePhysicsSelection(mc, mgr);
+
+    // --- Get input event handler -----------------------------------
+    AliInputEventHandler* ih =
+      dynamic_cast<AliInputEventHandler*>(mgr->GetInputEventHandler());
+    if (!ih) 
+      Fatal("CreatePhysicsSelection", "Couldn't get input handler (%p)", ih);
+    
+    // --- Get Physics selection -------------------------------------
+    AliPhysicsSelection* ps = 
+      dynamic_cast<AliPhysicsSelection*>(ih->GetEventSelection());
+    if (!ps) 
+      Fatal("CreatePhysicsSelection", "Couldn't get PhysicsSelection (%p)",ps);
+
+    // --- Special for pPb pilot run Sep. 2012 -----------------------
+    UShort_t sys = fOptions.AsInt("sys", 0);
+    if (sys == 3) { 
+      Warning("CreatePhysicsSelection", 
+             "Special setup for pPb pilot run September, 2012");
+      gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/ANALYSIS/macros",
+                              gROOT->GetMacroPath()));
+      gROOT->LoadMacro("PhysicsSelectionOADB_CINT5_pA.C");
+      gROOT->ProcessLine(Form("((AliPhysicsSelection*)%p)"
+                             "->SetCustomOADBObjects("
+                             "OADBSelection_CINT5_V0A(),0);", ps));
+      ps->SetSkipTriggerClassSelection(true);
+    }
+    // --- Ignore trigger class when selecting events.  This means ---
+    // --- that we get offline+(A,C,E) events too --------------------
+    // ps->SetSkipTriggerClassSelection(true);
+  }
+  //__________________________________________________________________
+  /** 
+   * Create the centrality selection only if requested
+   * 
+   * @param mc  Monte-Carlo truth flag 
+   * @param mgr Manager
+   */
+  void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    if (!fOptions.Has("cent")) return;
+    TrainSetup::CreateCentralitySelection(mc, mgr);
+  }
+  //__________________________________________________________________
+  const char* ClassName() const { return "MakeFullTrain"; }
+};
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakeMCCorrTrain.C b/PWGLF/FORWARD/trains/MakeMCCorrTrain.C
new file mode 100644 (file)
index 0000000..9065243
--- /dev/null
@@ -0,0 +1,103 @@
+/**
+ * @file   MakeMCCorrTrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:54:47 2012
+ * 
+ * @brief  
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+#include "TrainSetup.C"
+
+//====================================================================
+/**
+ * Analysis train to make Forward and Central MC corrections
+ * 
+ *
+ * @ingroup pwglf_forward_mc
+ * @ingroup pwglf_forward_trains_specific
+ */
+class MakeMCCorrTrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor.  Date and time must be specified when running this
+   * in Termiante mode on Grid
+   * 
+   * @param name     Name of train (free form)
+   */
+  MakeMCCorrTrain(const  char* name) 
+  : TrainSetup(name)
+  {
+    fOptions.Set("type", "ESD");
+  }
+protected:
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   * @param mgr  Analysis manager 
+   */
+  void CreateTasks(AliAnalysisManager* mgr)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("forward_mccorr.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    LoadLibrary("PWGLFforward2");
+    
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+
+    // --- Check if this is MC ---------------------------------------
+    if (!mgr->GetMCtruthEventHandler()) return;
+    
+    // --- Task to copy header information ---------------------------
+    gROOT->Macro("AddTaskCopyHeader.C");
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro("AddTaskForwardMCCorr.C"); 
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro("AddTaskCentralMCCorr.C");
+  }
+  //__________________________________________________________________
+  /** 
+   * Create physics selection , and add to manager
+   * 
+   * @param mc Whether this is for MC 
+   * @param mgr Manager 
+   */
+  void CreatePhysicsSelection(Bool_t mc,
+                             AliAnalysisManager* mgr)
+  {
+    TrainSetup::CreatePhysicsSelection(mc, mgr);
+
+    // --- Get input event handler -----------------------------------
+    AliInputEventHandler* ih =
+      dynamic_cast<AliInputEventHandler*>(mgr->GetInputEventHandler());
+    if (!ih) 
+      Fatal("CreatePhysicsSelection", "Couldn't get input handler (%p)", ih);
+    
+    // --- Get Physics selection -------------------------------------
+    AliPhysicsSelection* ps = 
+      dynamic_cast<AliPhysicsSelection*>(ih->GetEventSelection());
+    if (!ps) 
+      Fatal("CreatePhysicsSelection", "Couldn't get PhysicsSelection (%p)", ps);
+
+    // --- Ignore trigger class when selecting events.  This means ---
+    // --- that we get offline+(A,C,E) events too --------------------
+    // ps->SetSkipTriggerClassSelection(true);
+  }
+  /** 
+   * Do not the centrality selection
+   */
+  // void CreateCentralitySelection(Bool_t, AliAnalysisManager*) {}
+  //__________________________________________________________________
+  const char* ClassName() const { return "MakeMCCorrTrain"; }
+};
+
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakeQATrain.C b/PWGLF/FORWARD/trains/MakeQATrain.C
new file mode 100644 (file)
index 0000000..c79f94b
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * @file   MakeQATrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:55:02 2012
+ * 
+ * @brief  
+ * 
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+#include "TrainSetup.C"
+
+//====================================================================
+/**
+ * Analysis train to do Quality assurance
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ * @ingroup pwglf_forward_qa
+ */
+class MakeQATrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor.  Date and time must be specified when running this
+   * in Termiante mode on Grid
+   * 
+   * @param name     Name of train 
+   */
+  MakeQATrain(const char* name  = "Forward QA") 
+    : TrainSetup(name)
+  {
+    fOptions.Add("cent", "Use centrality");
+    fOptions.Set("type", "ESD");
+  }
+protected:
+  //__________________________________________________________________
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   * @param mgr  Analysis manager 
+   */
+  void CreateTasks(AliAnalysisManager* mgr)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("forward_qa.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    LoadLibrary("PWGLFforward2");
+    
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+
+    // --- Check if this is MC ---------------------------------------
+    Bool_t mc = mgr->GetMCtruthEventHandler() != 0;
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskForwardQA.C(%d,%d)", mc, fOptions.Has("cent")));
+  }
+  /** 
+   * Create entrality selection if enabled 
+   * 
+   * @param mc   Whether this is MC or not
+   * @param mgr  Analysis manager 
+   */
+  virtual void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    if (!fOptions.Has("cent")) return;
+
+    gROOT->Macro("AddTaskCentrality.C");
+    const char* cname = "CentralitySelection";
+    AliCentralitySelectionTask* ctask = 
+      dynamic_cast<AliCentralitySelectionTask*>(mgr->GetTask(cname));
+    if (!ctask) return;
+    // ctask->SetPass(fESDPass);
+    if (mc) ctask->SetMCInput();
+  }
+  /** 
+   * Crete output handler - we don't want one here. 
+   * 
+   * @return 0
+   */
+  AliVEventHandler* CreateOutputHandler(UShort_t) { return 0; }
+  //__________________________________________________________________
+  const char* ClassName() const { return "MakeQATrain"; }
+};
+
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MakedNdetaTrain.C b/PWGLF/FORWARD/trains/MakedNdetaTrain.C
new file mode 100644 (file)
index 0000000..90bc8d6
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * @file   MakedNdetaTrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:51:26 2012
+ * 
+ * @brief  
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ * 
+ */
+
+#include "TrainSetup.C"
+
+//====================================================================
+/**
+ * Analysis train to make @f$ dN/d\eta@f$
+ * 
+ *
+ * @ingroup pwglf_forward_dndeta
+ * @ingroup pwglf_forward_trains_specific
+ */
+class MakedNdetaTrain : public TrainSetup
+{
+public:
+  /** 
+   * Constructor.  
+   * 
+   * @param name     Name of train (free form)
+   */
+  MakedNdetaTrain(const char* name)
+  : TrainSetup(name)
+  {
+    fOptions.Add("trig",     "TYPE", "Trigger type", "INEL");
+    fOptions.Add("vzMin",    "CENTIMETER", "Min Ip Z", "-10");
+    fOptions.Add("vzMax",    "CENTIMETER", "Max Ip Z", "+10");
+    fOptions.Add("scheme",   "SCHEME", "Normalization scheme", "");
+    fOptions.Add("trigEff",  "EFFICENCY", "Trigger effeciency", "1");
+    fOptions.Add("trigEff0", "EFFICENCY", "0-bin trigger effeciency", "1");
+    fOptions.Add("cent",     "Use centrality");
+    fOptions.Add("cut-edges", "Cut acceptance edges");
+  }
+protected:
+  /** 
+   * Create the tasks 
+   * 
+   * @param par  Whether to use par files 
+   */
+  void CreateTasks(AliAnalysisManager*)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("forward_dndeta.root");
+
+    // --- Load libraries/pars ---------------------------------------
+    fHelper->LoadLibrary("PWGLFforward2");
+    
+    // --- Set load path ---------------------------------------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+
+    // --- Get parameters --------------------------------------------
+    TString  trig   = fOptions.Get("trig");
+    TString  scheme = fOptions.Get("scheme");
+    Double_t vzMin  = fOptions.AsDouble("vzmin", -10);
+    Double_t vzMax  = fOptions.AsDouble("vzmax", +10);
+    Double_t effT   = fOptions.AsDouble("trigEff", 1);
+    Double_t effT0  = fOptions.AsDouble("trigEff0", 1);
+    Bool_t   cent   = fOptions.Has("cent");
+    Bool_t   edges  = fOptions.Has("cut-edges");
+
+    // --- Add the task ----------------------------------------------
+    gROOT->Macro(Form("AddTaskForwarddNdeta.C(\"%s\",%f,%f,%d,\"%s\",%d,%g,%g)",
+                     trig.Data(), vzMin, vzMax, cent, scheme.Data(),
+                     edges, effT, effT0));
+
+    gROOT->Macro(Form("AddTaskCentraldNdeta.C(\"%s\",%f,%f,%d,\"%s\",%d,%g,%g)",
+                     trig.Data(), vzMin, vzMax, cent, scheme.Data(),
+                     edges, effT, effT0));
+
+    gROOT->Macro(Form("AddTaskMCTruthdNdeta.C(\"%s\",%f,%f,%d,\"%s\",%d,%g,%g)",
+                     trig.Data(), vzMin, vzMax, cent, scheme.Data(),
+                     edges, effT, effT0));
+  }
+  //__________________________________________________________________
+  /** 
+   * Do not the centrality selection
+   */
+  void CreateCentralitySelection(Bool_t, AliAnalysisManager*) {}
+  //__________________________________________________________________
+  /** 
+   * Crete output handler - we don't want one here. 
+   * 
+   * @return 0
+   */
+  AliVEventHandler* CreateOutputHandler(UShort_t) { return 0; }
+  //__________________________________________________________________
+  const char* ClassName() const { return "MakedNdetaTrain"; }
+};
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/MyAnalysis.C b/PWGLF/FORWARD/trains/MyAnalysis.C
new file mode 100644 (file)
index 0000000..81f342c
--- /dev/null
@@ -0,0 +1,132 @@
+// MyAnalysis.C 
+#ifndef __CINT__
+# include <AliAnalysisManager.h>
+# include <AliESDEvent.h>
+# include <AliMultiplicity.h>
+# include <AliESDVertex.h>
+# include <TH1D.h>
+# include <TH2D.h>
+#else 
+class TH1D;
+class TH2D;
+#endif 
+#include <AliAnalysisTaskSE.h>
+class MyAnalysis : public AliAnalysisTaskSE
+{
+public:
+  MyAnalysis() 
+    : AliAnalysisTaskSE(), fList(0), fMult(0), fVz(0)
+  {}
+  MyAnalysis(const char* name) 
+  : AliAnalysisTaskSE(name), fList(0), fMult(0), fVz(0)
+  {
+    DefineOutput(1, TList::Class());
+    DefineOutput(2, TList::Class()); // For output from Terminate
+    fBranchNames = "AliMultiplicity.,SPDVertex.,PrimaryVertex.";
+  }
+  MyAnalysis(const MyAnalysis& o) 
+  : AliAnalysisTaskSE(o), fList(o.fList), fMult(o.fMult), fVz(o.fVz)
+  {}
+  virtual ~MyAnalysis() {}
+  MyAnalysis& operator=(const MyAnalysis&) { return *this; }
+  virtual void UserCreateOutputObjects()
+  {
+    fList = new TList();
+    fList->SetName("Sums");
+    fList->SetOwner();
+
+    fMult = new TH2D("mult", "SPD tracklets", 80, -2, 2, 10, -10, 10);
+    fMult->SetXTitle("#eta");
+    fMult->SetYTitle("v_{z} [cm]");
+    fMult->Sumw2();
+    fMult->SetDirectory(0); // Disassociate from file 
+    
+    fVz = new TH1D("vz", "Interaction point", 10, -10, 10);
+    fVz->SetXTitle("v_{z} [cm]");
+    fVz->Sumw2();
+    fVz->SetDirectory(0); // Disassociate from file 
+
+    fList->Add(fMult);
+    fList->Add(fVz);
+
+    PostData(1, fList);
+  }
+  virtual void UserExec(Option_t* )
+  {
+    AliESDEvent* event = dynamic_cast<AliESDEvent*>(InputEvent());
+    if (!event) return;
+    if (event->IsPileupFromSPD(3,0.8))   return;
+
+    const AliESDVertex* vtx = event->GetPrimaryVertexSPD();
+    if (!vtx || !vtx->GetStatus()) return;
+    if (vtx->IsFromVertexerZ() && 
+        (vtx->GetDispersion() > 0.2 ||  vtx->GetZRes() > 1.25 * 0.2))
+      return;
+
+    const AliMultiplicity* mult = event->GetMultiplicity();
+    if (!mult) return;
+    
+    Double_t vz = vtx->GetZ();
+    fVz->Fill(vz);
+
+    Int_t nTracklets = mult->GetNumberOfTracklets();
+    for (Int_t i = 0; i < nTracklets; i++) 
+      fMult->Fill(mult->GetEta(i), vz);
+
+    PostData(1, fList);
+  }
+  void  Terminate(Option_t *)
+  {
+    TList* l = dynamic_cast<TList*>(GetOutputData(1));
+    if (!l) {
+      Warning("Terminate", "No out data # 1 found");
+      return;
+    }
+    TH2D* mult = static_cast<TH2D*>(l->FindObject("mult"));
+    TH1D* vz   = static_cast<TH1D*>(l->FindObject("vz"));
+    if (!mult || !vz) {
+      Warning("Terminate", "Either 'mult' (%p) or 'vz' (%p) or both not found",
+              mult, vz);
+      return;
+    }
+
+    TList* output = new TList;   // Needed for new output from Terminate
+    output->SetName("Results");  // 1st output re-opened read-only
+    output->SetOwner();
+
+    TH2D* out = static_cast<TH2D*>(mult->Clone("dndeta"));
+    out->SetTitle("dN_{ch}/d#eta from SPD tracklets per vertex bin");
+    out->SetZTitle("#frac{1}{N}#frac{dN_{ch}}{d#eta}");
+    out->SetDirectory(0); // Disassociate from file 
+    Int_t    nVz  = mult->GetNbinsY();
+    Int_t    nEta = mult->GetNbinsX();
+    for (Int_t iVz = 1; iVz <= nVz; iVz++) { 
+      Double_t nEv = vz->GetBinContent(iVz);
+      Double_t e1  = vz->GetBinError(iVz);
+      Double_t sca = (nEv == 0 ? 0 : 1. / nEv);
+      for (Int_t iEta = 1; iEta <= nEta; iEta++) { 
+        Double_t c  = mult->GetBinContent(iEta,iVz);
+        Double_t e  = mult->GetBinError(iEta,iVz);
+        Double_t ee = TMath::Sqrt(c*c * e1*e1 + nEv*nEv * e*e) * sca*sca;
+        out->SetBinContent(iEta, iVz, sca * c);
+        out->SetBinError(iEta, iVz, ee);
+      }
+    }
+    Double_t etaMin = mult->GetXaxis()->GetXmin();
+    Double_t etaMax = mult->GetXaxis()->GetXmax();
+    out->Scale(Double_t(nEta) / (etaMax-etaMin));
+
+    output->Add(out);
+    PostData(2, output);
+  }
+protected:
+  TList*  fList;
+  TH2D*   fMult;
+  TH1D*   fVz;
+  ClassDef(MyAnalysis, 1);  
+};
+//
+// EOF
+//
+
diff --git a/PWGLF/FORWARD/trains/MyTrain.C b/PWGLF/FORWARD/trains/MyTrain.C
new file mode 100644 (file)
index 0000000..6e4fba2
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __CINT__
+# include <AliAnalysisManager.h>
+#else 
+class AliAnalysisManager;
+#endif
+#include "TrainSetup.C"
+class MyTrain : public TrainSetup
+{
+public:
+  MyTrain(const char* name="myTest") : TrainSetup(name) 
+  { 
+    fOptions.Set("type", "ESD");
+  }
+  void CreateTasks(AliAnalysisManager* mgr)
+  {
+    if (!ParUtilities::MakeScriptPAR(fHelper::Mode() != Helper::kLocal, 
+                                    "MyAnalysis.C", 
+                                    "STEERBase,ESD,AOD,ANALYSIS,"
+                                    "OADB,ANALYSISalice"))
+      Fatal("CreateTasks", "Failed to create PAR file");
+    LoadLibrary("MyAnalysis");
+    
+    Long_t             r = gROOT->ProcessLine("new MyAnalysis(\"test\")");
+    AliAnalysisTaskSE* t = reinterpret_cast<AliAnalysisTaskSE*>(r);
+    if (!t) Fatal("CreateTasks", "Failed to make task");
+    mgr->AddTask(t);
+    
+    AliAnalysisDataContainer* sums = 
+      mgr->CreateContainer("Sums", TList::Class(), 
+                           AliAnalysisManager::kOutputContainer,
+                           AliAnalysisManager::GetCommonFileName());
+    AliAnalysisDataContainer* results = // Needed for output from Terminate
+      mgr->CreateContainer("Results", TList::Class(), 
+                          AliAnalysisManager::kParamContainer, // Important!
+                          AliAnalysisManager::GetCommonFileName());
+    
+    mgr->ConnectOutput(t, 1, sums);
+    mgr->ConnectOutput(t, 2, results);
+    mgr->ConnectInput(t, 0, mgr->GetCommonInputContainer());
+  }
+  void CreateCentralitySelection(Bool_t, AliAnalysisManager*) {}
+  AliVEventHandler* CreateOutputHandler(UShort_t type) { return 0; }
+  const char* ClassName() const { return "MyTrain"; }
+};
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/Option.C b/PWGLF/FORWARD/trains/Option.C
new file mode 100644 (file)
index 0000000..7a384e5
--- /dev/null
@@ -0,0 +1,783 @@
+/**
+ * @file   Option.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 18:59:04 2012
+ * 
+ * @brief  
+ * 
+ * 
+ * @ingroup pwglf_forward_trains_util
+ */
+#ifndef OPTION_C
+#define OPTION_C
+#include <TNamed.h>
+#include <iomanip>
+#ifndef __CINT__
+# include <TString.h>
+# include <TList.h>
+# include <TObjArray.h>
+# include <TObjString.h>
+# include <TMath.h>
+# include <iostream>
+# include <iomanip>
+# include <cstdarg>
+# include <cstdio>
+#else
+class TString;
+class TList;
+class TObjArray;
+#endif
+
+/** 
+ * An option.  The value is stored as a string 
+ *
+ * @ingroup pwglf_forward_trains_util
+ */
+struct Option /* : public TNamed */
+{
+  /** 
+   * Constructor 
+   * 
+   * @param name           Name of option
+   * @param arg            Dummy argument (possibly null)
+   * @param description    Description
+   * @param value          Default value 
+   */
+  Option(const TString& name, 
+        const TString& arg, 
+        const TString& description,
+        const TString& value)
+    : fName(name), fDescription(description), 
+      fValue(value), fArg(arg), fIsSet(false)
+  {}
+  /** 
+   * Copy constructor 
+   * 
+   * @param other Object to copy from 
+   */
+  Option(const Option& other)
+    : fName(other.fName), 
+      fDescription(other.fDescription),
+      fValue(other.fValue), 
+      fArg(other.fArg), 
+      fIsSet(other.fIsSet)
+  {}
+  /** 
+   * Assignment operator 
+   * 
+   * @param other Object to assign from 
+   *
+   * @return Reference to this object
+   */
+  Option& operator=(const Option& other)
+  {
+    if (&other == this) return *this;
+    
+    fName        = other.fName;
+    fDescription = other.fDescription;
+    fValue       = other.fValue;
+    fArg         = other.fArg;
+    fIsSet       = other.fIsSet;
+    
+    return *this;
+  }
+  /** 
+   * Set the value 
+   * 
+   * @param val New value 
+   */
+  void Set(const TString& val) { fIsSet = true; fValue = val; }
+  /** 
+   * Set the value
+   */
+  void Set() 
+  { 
+    if (HasArg()) { 
+      Error("Option::Set", "Option %s needs an argument", fName.Data());
+      return;
+    }
+    Set("");
+  }
+  /** 
+   * Reset the set flag
+   * 
+   */
+  void Reset() { fIsSet = false; }
+  /**
+   * @return constant reference to value 
+   */
+  const TString& Get() const { return fValue; }
+  /**
+   * @return true if this option was set externally
+   */
+  Bool_t IsSet() const { return fIsSet; }
+  /**
+   * @return true if this option needs an argument
+   */
+  Bool_t HasArg() const { return !fArg.IsNull(); }
+  /**
+   * @return value as a boolean value
+   */
+  Bool_t AsBool() const { return fIsSet; }
+  /**
+   * @return value as an integer value
+   */
+  Int_t    AsInt() const { return fValue.Atoi(); }
+  /**
+   * @return value as a long integer value
+   */
+  Long64_t AsLong() const { return fValue.Atoll(); } 
+  /**
+   * @return value as a double precision value
+   */
+  Double_t AsDouble() const { return fValue.Atof(); } 
+  /**
+   * @return value as a C string
+   */
+  const char* AsString() const { return fValue.Data(); } 
+  /** 
+   * @return Width of the name 
+   */
+  Int_t NameWidth() const { return fName.IsNull() ? 0 : fName.Length(); }
+  /** 
+   * @return the width of the dummy argument
+   */
+  Int_t ArgWidth() const { return fArg.IsNull() ? 0 : fArg.Length(); }
+  /** 
+   * Show help 
+   * 
+   * @param o Output stream 
+   * @param w With of option plus argument 
+   */
+  void Help(std::ostream& o, Int_t w=-1) const
+  {
+    TString tmp(fName);
+    if (HasArg()) { 
+      tmp.Append("=");
+      tmp.Append(fArg);
+    }
+    if (w <= 0) w = NameWidth() + ArgWidth() + 1;
+    std::ios::fmtflags oldf = o.setf(std::ios::left);
+    o << std::setw(w) << tmp << "  " << fDescription << " [";
+    if (!HasArg()) o << (IsSet() ? "true" : "false");
+    else           o << fValue;
+    o << "]" << std::endl;
+    o.setf(oldf);
+  }
+  /** 
+   * Show the option
+   * 
+   * @param o Output stream
+   * @param w With of name 
+   */
+  void Show(std::ostream& o, Int_t w=-1) const 
+  {
+    if (w <= 0) w = NameWidth();
+    std::ios::fmtflags oldf = o.setf(std::ios::left);
+    o << std::setw(w) << fName << ": ";
+    if (!HasArg()) o << (IsSet() ? "true" : "false");
+    else           o << fValue;
+    o << std::endl;
+    o.setf(oldf);
+  }
+  /** 
+   * Store option and possible value 
+   * 
+   * @param o Output stream
+   */
+  void Store(std::ostream& o, bool quote=true) const 
+  {
+    o << fName;
+    if (!HasArg()) return;
+    o << "=" << (quote ? "\"" : "") << fValue << (quote ? "\"" : "");
+  }
+  TString fName;        // Name 
+  TString fDescription; // Description
+  TString fValue;       // Value 
+  TString fArg;         // Argument dummy 
+  Bool_t  fIsSet;       // True if this option was set 
+  
+  // ClassDef(Option,1) // Option 
+};
+
+/** 
+ * A List of options 
+ */
+struct OptionList 
+{
+  // Linked list element
+  struct Link 
+  {
+    Link*   fPrev;
+    Link*   fNext;
+    Option* fThis;
+    Link() : fPrev(0), fNext(0), fThis(0) {}
+    Link(Link* next, Option* opt)
+      : fPrev(next ? next->fPrev : 0), // Set previous 
+       fNext(next), // Set next link
+       fThis(opt) // Set data
+    {
+      if (fPrev) fPrev->fNext = this; // Set forward link
+      if (fNext) fNext->fPrev = this; // Set previous link
+    }
+    ~Link() { 
+      if (fPrev) fPrev->fNext = fNext;
+      if (fNext) fNext->fPrev = fPrev;
+      delete fThis;
+    }
+  };
+  /** 
+   * Constructor 
+   */
+  OptionList() : fList(0) { }
+  /** 
+   * Copy constructor 
+   *
+   * @param other Object to copy from 
+   */
+  OptionList(const OptionList& other) 
+    : fList(0)
+  { 
+    // fList.SetOwner(); 
+    // TIter next(&other.fList);
+    // Option* o = 0;
+    // while ((o = static_cast<Option*>(next()))) 
+    //   fList.Add(new Option(*o));
+    Copy(other);
+  }
+  /** 
+   * Destructor 
+   */
+  ~OptionList() { Delete(); }
+
+  /** 
+   * Remove all options 
+   */
+  void Delete()
+  { 
+    Link* cur = fList;
+    while (cur) {
+      Link* tmp = cur->fNext;
+      delete cur;
+      cur = tmp;
+      // Remove(cur->fThis->fName);
+      // cur = tmp;
+    }
+    fList = 0;
+  }
+  /** 
+   * Assignment operator 
+   *
+   * @param other  Object to assign from 
+   *
+   * @return reference to this 
+   */
+  OptionList& operator=(const OptionList& other) 
+  { 
+    if (&other == this) return *this;
+    Delete();
+    Copy(other);
+    
+    return *this; 
+  }
+  /** 
+   * Copy list from other object
+   * 
+   * @param other Object to copy from 
+   */
+  void Copy(const OptionList& other)
+  {
+    Delete();
+    const Link* ocur = other.fList;
+    Link*       cur  = fList;
+    Link*       prev = fList;
+    while (ocur) { 
+      cur        = new Link;
+      cur->fThis = new Option(*(ocur->fThis));
+      cur->fNext = 0;
+      cur->fPrev = prev;
+      if (fList == 0) fList = cur;
+      if (prev)       prev->fNext = cur;
+      prev = cur;
+      ocur = ocur->fNext;
+    }
+  }
+  void DebugLink(const Link* link) const
+  {
+    std::cout << "Link=" << link;
+    if (link) {
+      std::cout << " prev=" << link->fPrev 
+               << " next=" << link->fNext
+               << " obj=" << link->fThis;
+      if (link->fThis) 
+        std::cout << " name=" << link->fThis->fName;
+    }
+    std::cout <<std::endl;
+  }
+  /** 
+   * Find an optio by name 
+   * 
+   * @param name Name of option to find
+   * 
+   * @return Pointer to option or null
+   */
+  Option* Find(const TString& name) const
+  {
+    const Link* cur = fList;
+    // DebugLink(cur);
+    while (cur && cur->fThis) { 
+      if (name.EqualTo(cur->fThis->fName)) return cur->fThis;
+      cur = cur->fNext;
+    }
+    return 0;
+  }
+  /** 
+   * Add an option with argument 
+   * 
+   * @param name Name of option
+   * @param arg  Dummy argument
+   * @param desc Description
+   * @param val  Default value 
+   * 
+   * @return Newly added option 
+   */
+  Option* Add(const TString& name, 
+             const TString& arg, 
+             const TString& desc, 
+             const TString& val)
+  {
+    Option* o = Find(name);
+    if (o) { 
+      Warning("OptionList::Add", "Option %s already registered", name.Data());
+      return o;
+    }
+    o = new Option(name, arg, desc, val);
+    Link*  cur  = fList;
+    if (!cur) { 
+      cur = new Link;
+      cur->fThis = o;
+      cur->fNext = 0;
+      cur->fPrev = 0;
+      fList      = cur;
+    }
+    else {
+      Link* n = 0;
+      Link* l = 0;
+      while (cur) { 
+       if (cur->fThis->fName.CompareTo(name) < 0) { 
+         l   = cur;
+         cur = cur->fNext;
+         continue;
+       }
+       n = new Link(cur, o);
+       if (cur == fList) fList = n;
+       break;
+      }
+      if (!n) { 
+       n = new Link;
+       l->fNext = n;
+       n->fPrev = l;
+       n->fNext = 0;
+       n->fThis = o;
+      }
+    }
+    return o;
+  }
+  /** 
+   * Add an option with no argument
+   * 
+   * @param name Name of option
+   * @param desc Description 
+   * 
+   * @return Newly created option 
+   */
+  Option* Add(const TString& name, 
+             const TString& desc)
+  {
+    return Add(name, "", desc, "");
+  }
+  /** 
+   * Remove an option 
+   * 
+   * @param name Name of option to remove 
+   */
+  void Remove(const TString& name)
+  {
+    Link* cur = fList;
+    while (cur) { 
+      if (!cur->fThis->fName.EqualTo(name)) {
+       cur = cur->fNext;
+       continue;
+      }
+      if (fList == cur) fList = cur->fNext;
+      delete cur;
+      break;
+    }
+  }
+  /** 
+   * Check if a given option was set externally
+   * 
+   * @param name Name of option
+   * 
+   * @return true if option exists and was set externally 
+   */
+  Bool_t Has(const TString& name) const
+  {
+    Option* o = Find(name);
+    return (o && o->IsSet());
+  }
+  /** 
+   * Get the value of an option
+   * 
+   * @param name Name of option
+   * 
+   * @return Value of option, or empty string 
+   */
+  const TString& Get(const TString& name) const
+  {
+    static TString null("");
+    Option* o = Find(name);
+    if (!o) return null;
+    return o->Get();
+  }
+  /** 
+   * Get a value using a format statement. Remember argument(s) must
+   * be passed by address (as pointers)
+   * 
+   * @param name Name of option @param format Format statement.
+   * Remeber, double and long needs the "l" modifier
+   * 
+   * @return true on success
+   */
+  Bool_t GetF(const TString& name, const Char_t* format, ...) const
+  {
+    Option* o = Find(name);
+    if (!o) return false;
+    
+    va_list ap;
+    va_start(ap, format);
+    int ret = vsscanf(o->fValue.Data(), format, ap);
+    va_end(ap);
+    
+    return ret > 0;
+  }
+  /** 
+   * Get value of an option as a boolean 
+   * 
+   * @param name Name of 
+   * 
+   * @return Value or false if not found
+   */
+  Bool_t AsBool(const TString& name) const 
+  {
+    Option* o = Find(name);
+    if (!o) return false;
+    return o->AsBool();
+  }
+  /** 
+   * Return value of an option as an integer
+   * 
+   * @param name Name of option 
+   * @param def  Default value if options isn't found 
+   * 
+   * @return Value or default value 
+   */
+  Int_t AsInt(const TString& name, Int_t def=0) const
+  {
+    Option* o = Find(name);
+    if (!o) return def;
+    return o->AsInt();
+  }
+  /** 
+   * Return value of an option as an integer
+   * 
+   * @param name Name of option 
+   * @param def  Default value if options isn't found 
+   * 
+   * @return Value or default value 
+   */
+  Long64_t AsLong(const TString& name, Long64_t def=0) const
+  {
+    Option* o = Find(name);
+    if (!o) return def;
+    return o->AsLong();
+  }
+  /** 
+   * Return value of an option as a double precision real number
+   * 
+   * @param name Name of option 
+   * @param def  Default value if options isn't found 
+   * 
+   * @return Value or default value 
+   */
+  Double_t AsDouble(const TString& name, Double_t def=0) const
+  {
+    Option* o = Find(name);
+    if (!o) return def;
+    return o->AsDouble();
+  }
+  /** 
+   * Set value using a format statement 
+   * 
+   * @param name   Name of option.
+   * @param format Format statement
+   */
+  void SetF(const TString& name, const Char_t* format, ...)
+  {
+    Option* o = Find(name);
+    if (!o) return;
+    
+    static char buf[1024];
+    va_list ap;
+    
+    va_start(ap, format);
+    vsnprintf(buf, 1023, format, ap);
+    buf[1023] = '\0';
+    va_end(ap);
+    
+    o->Set(buf);
+  }
+  /** 
+   * Set an option
+   * 
+   * @param name   Name of option
+   * @param value  Value of option
+   */
+  void Set(const TString& name, const TString& value)
+  {
+    Option* o = Find(name);
+    if (!o) return;
+    o->Set(value);
+  }
+  /** 
+   * Set a flag 
+   * 
+   * @param name Name of flag 
+   */
+  void Set(const TString& name)
+  {
+    Option* o = Find(name);
+    if (!o) return;
+    o->Set();
+  }   
+  /** 
+   * Set long integer value 
+   * 
+   * @param name Name of option
+   * @param val  Value 
+   */
+  void Set(const TString& name, Int_t val, Bool_t asHex=false)
+  {
+    if (asHex) Set(name, Form("0x%x", val));
+    else       Set(name, Form("%d", val));
+  }
+  /** 
+   * Set long integer value 
+   * 
+   * @param name Name of option
+   * @param val  Value 
+   */
+  void Set(const TString& name, Long64_t val, Bool_t asHex=false)
+  {
+    ULong64_t uval = val;
+    if (asHex) Set(name, Form("0x%llx", uval));
+    else       Set(name, Form("%lld", val));
+  }
+  /** 
+   * Set double precision floating point value 
+   * 
+   * @param name Name of option
+   * @param val  Value 
+   */
+  void Set(const TString& name, Double_t val) 
+  {
+    Set(name, Form("%lg", val));
+  }
+  /** 
+   * Parse the options given in tmp 
+   * 
+   * @param tmp     String to pass
+   * @param delims  Delimiters 
+   * 
+   * @return true on success 
+   */
+  Bool_t Parse(const TString& tmp, const TString& delims)
+  {
+    TObjArray* opts = tmp.Tokenize(delims);
+    // Info("OptionList::Parse", "Parsing options %s", tmp.Data());
+    Bool_t ret = Parse(opts);
+    opts->Delete();
+    return ret;
+  }
+  /** 
+   * Parse options given in a collection 
+   * 
+   * @param opts List of arguments 
+   * 
+   * @return true on success
+   */
+  Bool_t Parse(const TCollection* opts, Bool_t ignoreUnknown=false)
+  {
+    // Info("OptionList::Parse", "List of options");
+    // opts->ls();
+    TIter       next(opts);
+    TObjString* o = 0;
+    while ((o = static_cast<TObjString*>(next()))) { 
+      TString& s   = o->String();
+      TString  key = s;
+      TString  val = "";
+      Int_t    eq  = s.Index("=");
+      if (eq != kNPOS) {
+       key = s(0, eq);
+       val = s(eq+1, s.Length()-eq-1);
+      }
+
+      // Info("OptionList::Parse", "Looking for key=%s", key.Data());
+      Option*  opt = Find(key);
+      if (!opt) { 
+       if (!ignoreUnknown)
+         Warning("OptionList::Parse", "Unknown option: \"%s\"", s.Data());
+       continue;
+      }
+      if (opt->HasArg() && val.IsNull()) { 
+       Warning("OptionList::Parse", 
+               "Option %s needs an argument, using default %s", 
+               key.Data(), opt->fValue.Data());
+       val = opt->fValue;
+       // return false;
+      }
+      opt->Set(val);
+    }
+    return true;
+  }
+  /** 
+   * Find the widest name and dummy argument
+   * 
+   * @param nWidth On return, the largest width of option names 
+   * @param aWidth On return, the largest width of option dummy args
+   */
+  void Widest(Int_t& nWidth, Int_t& aWidth) const 
+  {
+    nWidth = 0;
+    aWidth = 0;
+    const Link* cur = fList;
+    while (cur) { 
+      Option* opt = cur->fThis;
+      nWidth = TMath::Max(nWidth, opt->NameWidth());
+      aWidth = TMath::Max(aWidth, opt->ArgWidth());
+      cur = cur->fNext;
+    }
+
+    // while ((opt = static_cast<Option*>(next()))) {
+    // }
+  }
+  /** 
+   * Display option help
+   * 
+   * @param o Output stream 
+   * @param prefix Prefix for each option.
+   */
+  void Help(std::ostream& o, const char* prefix="  ") const 
+  {
+    Int_t nWidth, aWidth;
+    Widest(nWidth, aWidth);
+    if (aWidth > 0) nWidth += aWidth+1;
+
+    const Link* cur = fList;
+    while (cur) { 
+      Option* opt = cur->fThis;
+      o << prefix;
+      opt->Help(o, nWidth);
+      cur = cur->fNext;
+    }
+  }
+  /** 
+   * Show the values of options 
+   * 
+   * @param o Output stream
+   * @param prefix Prefix for each option
+   */
+  void Show(std::ostream& o, const char* prefix="  ") const 
+  {
+    Int_t nWidth, aWidth;
+    Widest(nWidth, aWidth);
+
+
+    const Link* cur = fList;
+    while (cur) { 
+      Option* opt = cur->fThis;
+      o << prefix;
+      opt->Show(o, nWidth);
+      cur = cur->fNext;
+    }
+  }
+  /** 
+   * Show the values of options 
+   * 
+   * @param o Output stream
+   * @param prefix Prefix for each option
+   */
+  void Store(std::ostream& o, const char* prefix="", 
+            const char* delim=",", bool quote=true) const 
+  {
+    Int_t nWidth, aWidth;
+    Widest(nWidth, aWidth);
+
+    const Link* cur = fList;
+    while (cur) { 
+      Option* opt = cur->fThis;
+      if (!opt->HasArg() && !opt->IsSet()) {
+       cur = cur->fNext;
+       continue;
+      }
+      o << prefix;
+      opt->Store(o, quote);
+      o << delim;
+      cur = cur->fNext;
+    }
+  }
+  // Our linked list
+  Link* fList;
+
+  static void Test()
+  {
+    OptionList l;
+    l.Add("int", "NUMBER", "Integer", "42");
+    l.Add("float", "NUMBER", "Floating point", "3.14");
+    l.Add("bool", "Flag");
+    l.Add("hex", "NUMBER", "Hexadecimal", "0xdead");
+    l.Add("string", "STRING", "A string", "Hello, world");
+    l.Show(std::cout, "\t");
+    
+    std::cout << "Find" << std::endl;
+    Option* b = l.Find("bool");
+    b->Show(std::cout);
+
+    std::cout << "SetF" << std::endl;
+    l.SetF("float", "%f", 2.17);
+    l.Show(std::cout, "\t");
+    
+    std::cout << "GetF" << std::endl;
+    Float_t f;
+    l.GetF("float", "%f", &f);
+    std::cout << "\tf=" << f << std::endl;
+    std::cout << "Remove" << std::endl;
+    l.Remove("float");
+    l.Show(std::cout, "\t");
+
+    std::cout << "Set" << std::endl;
+    l.Set("int", "10");
+    l.Set("hex", 0xbeef, true);
+    l.Show(std::cout, "\t");
+
+    std::cout << "Copy" << std::endl;
+    OptionList c(l);
+    c.Show(std::cout, "\t");
+
+    std::cout << "End of test" << std::endl;
+  }
+  // TList fList;
+};
+
+#endif
+
diff --git a/PWGLF/FORWARD/trains/OutputUtilities.C b/PWGLF/FORWARD/trains/OutputUtilities.C
new file mode 100644 (file)
index 0000000..4f2d95d
--- /dev/null
@@ -0,0 +1,151 @@
+/** 
+ * @defgroup pwglf_forward_trains_util Utilities for Train setups
+ *
+ * @ingroup pwglf_forward_trains
+ */
+/**
+ * @file   OutputUtilities.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 17:55:32 2012
+ * 
+ * @brief  Special output handling
+ * 
+ * @ingroup pwglf_forward_trains_util
+ */
+#ifndef TREEOUTPUTHELPER_C
+#define TREEOUTPUTHELPER_C
+#ifndef __CINT__
+# include <TString.h>
+# include <TError.h>
+# include <AliAnalysisManager.h>
+# include <AliAnalysisDataContainer.h>
+# include <AliVEventHandler.h>
+#else
+class TString;
+#endif
+
+// ===================================================================
+/**
+ * Special output handling - data sets and remote storage
+ *
+ * @ingroup pwglf_forward_trains_util
+ */
+struct OutputUtilities
+{
+  /** 
+   * Register output data set 
+   * 
+   * @param dsname Data set name 
+   * 
+   * @return true on success
+   */
+  static Bool_t RegisterDataset(const TString& dsname)
+  {
+    // Get the manager
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    
+    // If we are asked to make a data-set, get the output handler and
+    // common output container.
+    AliVEventHandler*         handler = mgr->GetOutputEventHandler();
+    if (!handler) return true;
+
+    // Get the container 
+    AliAnalysisDataContainer* cont    = mgr->GetCommonOutputContainer();
+    if (!cont) { 
+      Warning("OutputUtilities::RegisterDataset", 
+             "No common output container defined");
+      return false;
+    }
+
+    // Make the name 
+    TString nme(dsname);
+    if (nme.IsNull()) nme = mgr->GetName();
+    if (nme.IsNull()) { 
+      Error("OutputUtilities::RegisterDataset", "No data set name specified");
+      return false;
+    }
+
+    // Flag for data-set creation
+    cont->SetRegisterDataset(true);
+
+    handler->SetOutputFileName(nme);
+    // cont->SetFileName(nme);
+
+    TString base(handler->GetOutputFileName());
+    base.ReplaceAll(".root","");
+    Info("OutputUtilities::RegisterDataset", 
+        "Will register tree output AODs (%s%s) as dataset",
+        base.Data(), cont->GetTitle());
+
+    return true;
+  }
+  /** 
+   * Get the name of the registered data set
+   * 
+   * 
+   * @return Name of the registered data set
+   */
+  static TString RegisteredDataset()
+  {
+    TString ret;
+
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    AliVEventHandler*   oh  = mgr->GetOutputEventHandler();
+    if (!oh) { 
+      Warning("OutputUtilities::GetOutputDataSet", 
+             "No outout event handler defined");
+      return ret;
+    }
+    AliAnalysisDataContainer* co  = mgr->GetCommonOutputContainer();
+    if (!co) { 
+      Warning("OutputUtilities::GetOutputDataSet", 
+             "No common output container defined");
+      return ret;
+    }
+    if (!co->IsRegisterDataset()) { 
+      Info("OutputUtilities::GetOutputDataSet", 
+          "Common output is not registered as dataset");
+      return ret;
+    }
+    ret = oh->GetOutputFileName();
+    // ret.ReplaceAll("TTree", "");
+    ret.ReplaceAll(".root", "");
+    // ret.Append(co->GetTitle());
+
+    return ret;
+  }
+  /** 
+   * Register special putput storage 
+   * 
+   * @param url Url (root://host/full_path)
+   * 
+   * @return true on success
+   */
+  static Bool_t RegisterStorage(const TString& url)
+  {
+    if (url.IsNull()) { 
+      Error("OutputUtilities::RegisterStorage", "No storage URI specified");
+      return false;
+    }
+
+    // Get the manager
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    
+    // Get the container 
+    AliAnalysisDataContainer* cont    = mgr->GetCommonOutputContainer();
+    if (!cont) { 
+      Warning("OutputUtilities::RegisterStorage", 
+             "No common output container defined");
+      return false;
+    }
+
+    cont->SetSpecialOutput();
+    mgr->SetSpecialOutputLocation(url);
+
+    return true;
+  }
+};
+#endif
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/ParUtilities.C b/PWGLF/FORWARD/trains/ParUtilities.C
new file mode 100644 (file)
index 0000000..1432462
--- /dev/null
@@ -0,0 +1,475 @@
+/**
+ * @file   ParUtilities.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 17:51:10 2012
+ * 
+ * @brief  PAR file utilities 
+ * 
+ * @ingroup pwglf_forward_trains_util
+ * 
+ */
+#ifndef PARHELPER_C
+#define PARHELPER_C
+#ifndef __CINT__
+# include <TString.h>
+# include <TProof.h>
+# include <TSystem.h>
+# include <TError.h>
+# include <TFile.h>
+# include <TSystem.h>
+# include <TROOT.h>
+# include <fstream>
+# include <cstdlib>
+#else
+class TString;
+#endif
+
+// ===================================================================
+/**
+ * Helper to set-up and load PARs
+ *
+ * @ingroup pwglf_forward_trains_util
+ */
+struct ParUtilities
+{
+  /** 
+   * Find PAR file (either in current or parent directory or directly 
+   * in $ALICE_ROOT), and copy/link here
+   * 
+   * @param what PAR file name (sans .par)
+   * 
+   * @return true on success
+   */
+  static Bool_t Find(const TString& what)
+  {
+    if (what.IsNull()) return false;
+    
+    TString parFile(what);
+    if (!parFile.EndsWith(".par")) parFile.Append(".par");
+    if (gSystem->AccessPathName(parFile.Data())) { 
+      // If not found
+      if (gSystem->AccessPathName(Form("../%s.par", parFile.Data()))) { 
+       // If not found 
+       TString aliParFile = 
+         gSystem->ExpandPathName(Form("$(ALICE_ROOT)/%s", parFile.Data()));
+       if (gSystem->AccessPathName(aliParFile.Data())) { 
+         Error("ParUtilities::Find", 
+               "PAR file %s not found in current or parent "
+               "directory nor in $(ALICE_ROOT)", parFile.Data());
+         return false;
+       }
+       // Copy to current directory 
+       TFile::Cp(aliParFile, parFile);
+      }
+      else 
+       gSystem->Exec(Form("ln -s %s .", parFile.Data()));
+    }
+    return true;
+  }
+  static Bool_t Load(const TString& name) 
+  {
+    if (name.IsNull()) return true;
+    if (!gProof) { 
+      Error("ParUtilities::Load", "No connection to a Proof cluster");
+      return false;
+    }
+
+    // Load par library 
+    TString fn(name);
+    Info("ParUtilities::LoadLibrary", "Uploading %s", name.Data());
+    
+    // First check in current directory
+    Int_t ret = gProof->UploadPackage(fn, TProof::kRemoveOld);
+    
+    if (ret < 0)  {
+      // IF not found there, then check parent directory 
+      fn.Prepend("../");
+      gSystem->ExpandPathName(fn);
+      ret = gProof->UploadPackage(fn);
+    }
+
+    if (ret < 0) {     
+      // If not found in current or parent directory, try the 
+      // the ALICE_ROOT directory 
+      fn  = Form("$ALICE_ROOT/%s.par", name.Data());
+      gSystem->ExpandPathName(fn);
+      ret = gProof->UploadPackage(fn);
+    }
+    
+    if (ret < 0) {
+      // IF not found, bark 
+      Error("ParUtilities::Load", 
+           "Could not find module %s.par in current or parent directory "
+           "nor in $ALICE_ROOT", name.Data());
+      return false;
+    }
+    
+    ret = gProof->EnablePackage(name);
+    Info("ParUtilities::Load", "Enabled package %s (from %s)", 
+        name.Data(), fn.Data());
+    
+    return true;
+  }
+  /** 
+   * Unpack, build, and load a PAR file. 
+   * 
+   * @param what Which PAR file 
+   * 
+   * @return 
+   */
+  static Bool_t Build(const TString& what)
+  {
+    if (what.IsNull()) return false;
+    
+    TString parFile(what);
+    if (!parFile.EndsWith(".par")) parFile.Append(".par");
+
+    // Extract archive 
+    gSystem->Exec(Form("tar xzf %s", parFile.Data()));
+    
+    // Change directory into par archive
+    TString cwd = gSystem->WorkingDirectory();
+    
+    TString dir(what);
+    if (dir.EndsWith(".par")) dir.ReplaceAll(".par", "");
+    if (!gSystem->ChangeDirectory(dir)) { 
+      Error("ParUtilities::Setup", "Failed to change directory to %s", 
+           dir.Data());
+      return false;
+    }
+    
+    // Test the build 
+    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
+      Info("ParUtilities::Setup", "Building in PAR archive %s", parFile.Data());
+      if (gSystem->Exec("PROOF-INF/BUILD.sh")) { 
+       Error("ParUtilities::Setup", "Failed to build in PAR directory %s", 
+             dir.Data());
+       gSystem->ChangeDirectory(cwd.Data());
+       return false;
+      }
+    }
+    
+    // Check for setup script
+    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
+      // Info("ParUtilities::SetupPAR", "Setting up for PAR %s", what);
+      gROOT->Macro("PROOF-INF/SETUP.C");
+    }
+    if (!gSystem->ChangeDirectory(cwd.Data())) return false;
+
+    return true;
+  }
+  //__________________________________________________________________
+  /** 
+   * @{ 
+   * @name PAR generation from script 
+   */
+  /** 
+   * Service function to make a PAR out of a script.  
+   * 
+   * The script should contain can contain a sub-class of AliAnalysisTask. 
+   * The script will be compiled on the slaves before loading the 
+   * AliAnalysisManager.  Parts to (not) be compiled can be protected like 
+   * 
+   * @code 
+   * #ifdef BUILD_PAR
+   * // This will _only_ be compiled in the servers 
+   * #endif
+   * #ifndef BUILD_PAR
+   * // This will not be compiled in the servers 
+   * #endif
+   * @endcode
+   * 
+   * @param mode   Execution mode (Grid, PROOF, Local)
+   * @param script Script to upload and compile in the PAR
+   * @param deps   Dependency pars 
+   * 
+   * @return true on success. 
+   */
+  static Bool_t MakeScriptPAR(Bool_t isLocal, 
+                             const TString& script, 
+                             const TString& deps)
+  {
+    // --- In local mode, just AcLic and load ------------------------
+    if (isLocal) { 
+      if (gROOT->LoadMacro(Form("%s++g", script.Data())) < 0)
+       return false;
+      return true;
+    }
+
+    // --- Get the base name -----------------------------------------
+    Info("ParUtilities::MakeScriptPAR", "Making par file for %s", 
+        script.Data());
+    TString base(gSystem->BaseName(script));
+    Int_t   idx = base.Last('.');
+    if (idx != kNPOS) base.Remove(idx);
+
+    // --- Check name of script file ---------------------------------
+    TString scr(script);
+    TString ext;
+    if      (script.EndsWith(".C"))   ext = "C"; 
+    else if (script.EndsWith(".cxx")) ext = "cxx";
+    else                              { ext = "C"; scr.Append(".C"); }
+    
+    // --- Check if we can access the file ---------------------------
+    TString path = TString::Format(".:%s", TROOT::GetMacroPath());
+    char*   loc  = gSystem->Which(path, scr);
+    if (!loc) {
+      Error("ParUtilities::MakeScriptPAR", 
+           "Script %s not found in %s", scr.Data(), path.Data());
+      return false;
+    }
+    TString full(loc);
+
+    // --- Create our temporary directory ----------------------------
+    TString tmpdir(gSystem->TempDirectory());
+    int     ltempl = tmpdir.Length() + 1 + 5 + 6 + 1;
+    char*   templ  = new char[ltempl];
+    snprintf(templ, ltempl, "%s/trainXXXXXX", tmpdir.Data());
+    if (!mkdtemp(templ)) {
+      Error("ParUtilities::MakeScriptPAR", 
+           "Failed to generate temporary directory from template %s", 
+           templ);
+      return false;
+    }
+
+    Bool_t retVal = false;
+    try {
+      // --- Make directories for package ------------------------------
+      TString dir = TString::Format("%s/%s", templ, base.Data());
+      // Set-up directories 
+      if (gSystem->MakeDirectory(dir) < 0) 
+       throw TString::Format("Could not make directory '%s'", base.Data());
+      if (gSystem->MakeDirectory(Form("%s/PROOF-INF", dir.Data()))) 
+       throw TString::Format("Could not make directory %s/PROOF-INF", 
+                             base.Data());
+      
+      // --- Copy the script to the setup directory --------------------
+      TString dest = TString::Format("%s/%s.%s", dir.Data(),
+                                    base.Data(), ext.Data());
+      Int_t ret = gSystem->CopyFile(full, dest, true);
+      switch (ret) { 
+      case -1: throw TString::Format("Couldn't open %s for copy", scr.Data());
+      case -2: throw TString::Format("File %s exists", dest.Data());
+      case -3: throw TString::Format("Error while copying %s", scr.Data());
+      }
+      
+      // --- Make scripts, etc. ----------------------------------------
+      TObjArray* depList = deps.Tokenize(", ");
+      if (!MakeBuildScript(dir, base)) 
+       throw TString::Format("Failed to make build script");
+      if (!MakeUtilityScript(dir)) 
+       throw TString::Format("Failed to make utility script");
+      if (!MakeBuildMacro(dir, base, ext, depList)) 
+       throw TString::Format("Failed to make build macro");
+      if (!MakeSetupMacro(dir, base, ext, depList)) 
+       throw TString::Format("Failed to setup macro");
+
+      // --- Pack up the archive ---------------------------------------
+      ret = gSystem->Exec(Form("(cd %s && tar -czf %s.par %s)", 
+                              templ, base.Data(),base.Data()));
+      if (ret != 0) 
+       throw TString::Format("Failed to create PAR file %s.PAR from %s", 
+                             base.Data(), dir.Data());
+
+      // --- Move PAR file to here -------------------------------------
+      ret = gSystem->Exec(Form("mv -f %s/%s.par %s.par", templ, base.Data(), 
+                              base.Data()));
+      if (ret != 0) 
+       throw TString::Format("Failed to rename %s/%s.par to %s.par: %s", 
+                             templ, base.Data(), base.Data(), 
+                             gSystem->GetError());
+      retVal = true;
+    }
+    catch (TString& e) {
+      Error("ParUtilities::MakeScriptPAR", e.Data());
+      retVal = false;
+    }
+    
+    // --- Remove temporary directory --------------------------------
+    gSystem->Exec(Form("rm -rf %s", templ));
+
+    return retVal;
+  }
+  /** 
+   * Write a build script
+   * 
+   * @param dir Directory to put it in
+   * 
+   * @return true on success
+   */
+  static Bool_t MakeBuildScript(const TString& dir, 
+                               const TString& base)
+  {
+    // Make our build file 
+    std::ofstream out(Form("%s/PROOF-INF/BUILD.sh", dir.Data()));
+    if (!out) {
+      Error("ParUtilities::MakeBuildScript", "Failed to open out shell script");
+      return false;
+    }
+    out << "#!/bin/sh\n"
+       << "if test x$ALICE_ROOT != x ; then\n"
+       << "  if test x$ALICE_TARGET = x ; then\n"
+       << "    export ALICE_TARGET=`$ROOTSYS/bin/root-config --arch`\n"
+       << "  fi\n"
+       << "  export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:"
+       << "${ALICE_ROOT}/lib/tgt_${ALICE_TARGET}\n"
+       << "fi\n"
+       << "echo BUILD.sh@`hostname`: Building " << base << "\n"
+       << "root.exe -l -out -q PROOF-INF/BUILD.C 2>&1 | tee " 
+       << base << ".log\n"
+       << "echo BUILD.sh@`hostname`: done: $?\n"
+       << std::endl;
+    out.close();
+    if (gSystem->Chmod(Form("%s/PROOF-INF/BUILD.sh", dir.Data()), 0755) != 0) {
+      Error("ParUtilities::MakeBuildScript", 
+           "Failed to set exectuable flags on %s/PROOF-INF/BUILD.sh", 
+           dir.Data());
+      return false;
+    }
+    return true;
+  }
+  /** 
+   * Write a build macro 
+   * 
+   * @param dir   Directory to put macro in
+   * @param deps  Dependencies
+   * @param base  Base name of script to compile
+   * 
+   * @return true on success
+   */
+  static Bool_t MakeBuildMacro(const TString& dir, 
+                              const TString& base, 
+                              const TString& ext,
+                              const TCollection* deps)  {
+    std::ofstream out(Form("%s/PROOF-INF/BUILD.C", dir.Data()));
+    if (!out) {
+      Error("ParUtilities::MakeBuildMacro", "Failed to open build script");
+      return false;
+    }
+    out << "void BUILD() {\n"
+       << "  gSystem->AddIncludePath(\"-DBUILD_PAR=1\");\n"
+       << "  gROOT->LoadMacro(\"PROOF-INF/UTIL.C\");\n"
+       << "  LoadROOTLibs();\n"
+       << "  AddAliROOT();\n";
+    if (deps) {
+      TIter       next(deps);
+      TObject*    dep = 0;
+      while ((dep = next())) {
+       out << "  AddDep(\"" << dep->GetName() << "\");\t"
+           << "  LoadDep(\"" << dep->GetName() << "\");\n";
+      }
+    }
+    out << "  // gDebug = 5;\n"
+       << "  int ret = gROOT->LoadMacro(\"" 
+       << base << "." << ext << "++g\");\n"
+       << "  if (ret != 0) Fatal(\"BUILD\",\"Failed to build\");\n"
+       << "  // else Info(\"BUILD\", \"Made " << base << "\");\n"
+       << "}\n"
+       << std::endl;
+    out.close();
+
+    return true;
+  }
+  /** 
+   * Make a utility macro 
+   * 
+   * @param dir Directory to put the macro in
+   * 
+   * @return true on success
+   */
+  static Bool_t MakeUtilityScript(const TString& dir)
+  {
+    std::ofstream out(Form("%s/PROOF-INF/UTIL.C", dir.Data()));
+    if (!out) {
+      Error("ParUtilities::MakeUtilityScript", "Failed to open utility script");
+      return false;
+    }
+    out << "void LoadROOTLibs() {\n"
+       << "  gSystem->Load(\"libVMC\");\n"
+       << "  gSystem->Load(\"libNet\");\n"
+       << "  gSystem->Load(\"libTree\");\n"
+       << "  gSystem->Load(\"libPhysics\");\n"
+       << "  gSystem->Load(\"libMinuit\");\n"
+       << "}\n\n"
+       << "void AddAliROOT() {\n"
+       << "  TString val(gSystem->Getenv(\"ALICE_ROOT\"));\n"
+       << "  if (val.IsNull())\n"
+       << "    Warning(\"Add\",\"ALICE_ROOT not defined\");\n"
+       << "  else\n"
+       << "    gSystem->AddIncludePath(Form(\"-I%s/include\",val.Data()));\n"
+       << "}\n\n"
+       << "void AddDep(const char* env) {\n"
+       << "  TString val(gSystem->Getenv(Form(\"%s_INCLUDE\",env)));\n"
+       << "  if (val.IsNull())\n"
+       << "    Warning(\"Add\",\"%s_INCLUDE not defined\", env);\n"
+       << "  else {\n"
+       << "    gSystem->AddIncludePath(Form(\"-I../%s\",val.Data()));\n"
+       << "  }\n"
+       << "}\n\n"
+       << "void LoadDep(const char* name) {\n"
+       << "  gSystem->AddDynamicPath(Form(\"../%s\",name));\n"
+       << "  char* full = gSystem->DynamicPathName(name,true);\n"
+       << "  if (!full) \n"
+       << "   full = gSystem->DynamicPathName(Form(\"lib%s\",name),true);\n"
+       << "  if (!full) \n"
+       << "   full = gSystem->DynamicPathName(Form(\"lib%s.so\",name),true);\n"
+       << "  if (!full) {\n"
+       << "    Warning(\"LoadDep\",\"Module %s not found\", name);\n"
+       << "    return;\n"
+       << "  }\n"
+       << "  gSystem->Load(full);\n"
+       << "}\n"
+       << std::endl;
+    out.close();
+    return true;
+  }
+  /** 
+   * Make a setup script 
+   * 
+   * @param dir   Directory to put it in 
+   * @param base  Base name of target script 
+   * @param ext   Extension of target script 
+   * @param deps  Dependencies 
+   * 
+   * @return true on success
+   */
+  static Bool_t MakeSetupMacro(const TString& dir, 
+                              const TString& base, 
+                              const TString& ext,
+                              const TCollection* deps)
+  {
+    // Make our set-up script 
+    std::ofstream out(Form("%s/PROOF-INF/SETUP.C", dir.Data()));
+    if (!out) {
+      Error("ParUtilities::MakeSetupMacro", "Failed to open setup script");
+      return false;
+    }
+    out << "void SETUP() {\n"
+       << "  gROOT->LoadMacro(\"PROOF-INF/UTIL.C\");\n"
+       << "  LoadROOTLibs();\n"
+       << "  // Info(\"SETUP\",\"Loading libraries\");\n";
+    if (deps) {
+      TIter next(deps);
+      TObject* dep = 0;
+      while ((dep = next())) 
+       out << "  LoadDep(\"" << dep->GetName() << "\");\n";
+    }
+    out << "  // gDebug = 5;\n"
+       << "  // Info(\"SETUP\",\"Loading " << base <<"_"<< ext << ".so\");\n"
+       << "  gSystem->Load(\"" << base << "_" << ext << ".so\");\n"
+       << "  // gDebug = 0;\n"
+       << "  gROOT->ProcessLine(\".include " << base << "\");\n"
+       << "  gSystem->Setenv(\"" << base << "_INCLUDE\",\"" 
+       << base << "\");\n"
+       << "  // Info(\"SETUP\", \"Done\");\n"
+       << "}\n"
+       << std::endl;
+    out.close();
+    return true;
+  }
+  /* @} */
+};
+#endif
+// 
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/PluginHelper.C b/PWGLF/FORWARD/trains/PluginHelper.C
new file mode 100644 (file)
index 0000000..98707b3
--- /dev/null
@@ -0,0 +1,247 @@
+/**
+ * @file   PluginHelper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 18:57:18 2012
+ * 
+ * @brief  Base class for helpers using the AliAnalysisAlien plugin
+ *
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef PLUGINHELPER_C
+#define PLUGINHELPER_C
+#include "Helper.C"
+#ifndef __CINT__
+# include "AvailableSoftware.C"
+# include "ParUtilities.C"
+# include "OutputUtilities.C"
+# include <TUrl.h>
+# include <TString.h>
+# include <TEnv.h>
+# include <TProof.h>
+# include <AliAnalysisManager.h>
+# include <AliAnalysisAlien.h>
+#else
+class TUrl;
+class AliAnalysisAlien;
+#endif
+
+// ===================================================================
+/**
+ * Handle analysis on using the AliAnalysisAlien plugin - i.e., AAF or Grid 
+ * 
+ * This helper is triggered by a URL of the form 
+ *
+ * @code
+ * <protocol>://[<user>@][<host>][:<port>]/[<file>][?<options>][#<anchor>]
+ * @endcode 
+ * where &lt;options&gt; contains <tt>plugin</tt>
+ * <dl>
+ *   <dt>&lt;options@gt;</dt>
+ *   <dd>List of options separated by an &amp;
+ *     <dl>
+ *       <dt><tt>storage=&lt;url&gt;</tt></dt>
+ *       <dd>Specify a non-default storage location for special output
+ *         (e.g., AOD trees).  &lt;url&gt; should be a valid XRootd 
+ *         server URI accessible to the slaves - e.g., 
+ *         <tt>root://lxplus.cern.ch:10930//tmp</tt>.</dd>
+ *       <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
+ *       <dd>Set the AliROOT mode.  If not specified <tt>default</tt> 
+ *         is assumed</tt>.  See also CreateAliROOTPar</dd>
+ *       <dt><tt>par</tt></dt>
+ *       <dd>Use par files</dd>
+ *       <dt><tt>aliroot=&lt;version&gt;</tt></dt>
+ *       <dd>Set AliROOT version to use </dd>
+ *       <dt><tt>root=&lt;version&gt;</tt></dt>
+ *       <dd>Set ROOT version to use </dd>
+ *     </dl>
+ *   </dd>
+ * </dl>  
+ *
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct PluginHelper : public Helper
+{
+  /** 
+   * Constructor 
+   * 
+   * @param url  Url 
+   * @param opts Options 
+   */
+  PluginHelper(const TUrl& url, Int_t verbose)
+    : Helper(url, verbose), fHandler(0), fUsePars(false)
+  {
+    fHandler = new AliAnalysisAlien();
+
+    fOptions.Add("aliroot", "VERSION", "AliROOT version", "last");
+    fOptions.Add("root",    "VERSION", "ROOT version", "last");
+    fOptions.Add("par", "Use par files");
+    fOptions.Add("mode", "default|rec|sim", "AliROOT mode", "default");
+    fOptions.Add("storage", "URL", "Location for external storage", "");    
+    fOptions.Add("plugin", "Use AliEn handler");
+  }
+  virtual ~PluginHelper() {}
+  /** 
+   * Load a library/PAR/script 
+   * 
+   * @param name   Name 
+   * @param par    If true, upload & enable PAR 
+   * @param slaves If true, also load on slaves
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t LoadLibrary(const TString& name, 
+                            Bool_t slaves=true)
+  {
+    if (!fUsePars) {
+      TString fullName(MakeLibraryName(name));
+      Int_t ret = gSystem->Load(fullName);
+      if (ret < 0) return false;
+      if (slaves) fHandler->AddAdditionalLibrary(fullName);
+    }
+    else { 
+      if (!ParUtilities::Find(name)) { 
+       Error("PluginHelper::LoadLibrary", "Failed to find PAR file %s", 
+             name.Data());
+       return false;
+      }
+      if (!ParUtilities::Build(name)) { 
+       Error("PluginHelper::LoadLibrary", "Failed to build PAR file %s", 
+             name.Data());
+       return false;
+      }
+      fHandler->EnablePackage(name);
+    }
+    return true;
+  }
+  /** 
+   * Load a source file, and compile it 
+   * 
+   * @param name Name of the source file 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t LoadSource(const TString& name)
+  {
+    static TString s;
+    if (!Helper::LoadSource(name)) return false;
+    s.Append(Form(" %s", gSystem->BaseName(name.Data())));
+    fHandler->SetAnalysisSource(s);
+    return true;
+  }
+  
+  /** 
+   * Set-up to load the AliROOT libraries 
+   * 
+   * @param par Whether to use PAR files 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t LoadAliROOT()
+  {
+    if (!gSystem->Getenv("ALICE_ROOT")) { 
+      Error("PluginHelper::LoadAliROOT", "Local AliROOT not available");
+      return false;
+    }
+    Bool_t tmp = fUsePars;
+    fUsePars   = false;
+    
+    if (!LoadLibrary("STEERBase"))     return false;
+    if (!LoadLibrary("ESD"))           return false;
+    if (!LoadLibrary("AOD"))           return false;
+    if (!LoadLibrary("ANALYSIS"))      return false;
+    if (!LoadLibrary("OADB"))          return false;
+    if (!LoadLibrary("ANALYSISalice")) return false;
+    fUsePars = tmp;
+
+    return true;
+  }
+  /** 
+   * Set-up done before task set-ups 
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t PreSetup() 
+  {
+    // --- Set prefered GSI method ---------------------------------
+    gEnv->SetValue("XSec.GSI.DelegProxy", "2");
+
+    TString aliroot("last");
+    TString root("last");
+    if (fOptions.Has("aliroot")) aliroot = fOptions.Get("aliroot");
+    if (fOptions.Has("root"))    root    = fOptions.Get("root");
+
+    AvailableSoftware::Check(aliroot, root);
+    fOptions.Set("aliroot", aliroot);
+    fOptions.Set("root", root);
+
+    fUsePars = fOptions.Has("par");
+
+    fHandler->SetROOTVersion(root);
+    fHandler->SetAliROOTVersion(aliroot);
+    if (fOptions.Has("mode"))
+      fHandler->SetAliRootMode(fOptions.Get("mode"));
+    else 
+      fHandler->SetAliRootMode("default");
+    
+    return true;
+  }
+  /** 
+   * Set-up done after the task set-ups 
+   *
+   * @return true on success 
+   */
+  virtual Bool_t PostSetup() 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    if (!mgr) { 
+      Error("PluginHelper::PostSetup", "No analysis manager defined");
+      return false;
+    }
+    mgr->SetGridHandler(fHandler);
+
+    fHandler->SetJobTag(mgr->GetName());
+    fHandler->SetAnalysisMacro(Form("%s.C", mgr->GetName()));
+
+    if (fOptions.Has("storage"))
+      OutputUtilities::RegisterStorage(fOptions.Get("storage"));
+
+    return true;
+  };
+  /** 
+   * Pure virtual overload
+   * 
+   * @param Long64_t 
+   * 
+   * @return 
+   */
+  virtual Long64_t Run(Long64_t) = 0;
+  /** 
+   * Pure virtual overload 
+   * 
+   * @return Short description
+   */
+  virtual const char* Desc() const = 0;
+  /** 
+   * Pure virtual overload 
+   * 
+   * @return URI help string 
+   */
+  virtual const Char_t* UrlHelp() const = 0;
+  /** 
+   * Overload 
+   * 
+   * @param option Options 
+   */
+  virtual void Print(Option_t* option="") const 
+  {
+    Helper::Print(option);
+    fHandler->Print(option);
+  }
+  AliAnalysisAlien* fHandler;
+  Bool_t fUsePars;
+};
+#endif
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/ProofHelper.C b/PWGLF/FORWARD/trains/ProofHelper.C
new file mode 100644 (file)
index 0000000..b0d55f7
--- /dev/null
@@ -0,0 +1,542 @@
+/**
+ * @file   ProofHelper.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 18:58:37 2012
+ * 
+ * @brief  
+ * 
+ *
+ * @ingroup pwglf_forward_trains_helper
+ * 
+ */
+#ifndef PROOFHELPER_C
+#define PROOFHELPER_C
+#include "Helper.C"
+#ifndef __CINT__
+# include "OutputUtilities.C"
+# include "ParUtilities.C"
+# include "ChainBuilder.C"
+# include <TUrl.h>
+# include <TString.h>
+# include <TProof.h>
+# include <TProofLog.h>
+# include <TProofDebug.h>
+# include <AliAnalysisManager.h>
+# include <TEnv.h>
+# include <TChain.h>
+#else
+class TUrl;
+class TChain;
+#endif
+
+// ===================================================================
+/**
+ * Handle analysis on a Proof farm. 
+ * 
+ * This helper is triggered by URIs of the form 
+ *
+ * @code
+ * proof://[<user>@]<host>[:<port>]/<dsname>[?<options>][#<treename>]
+ * @endcode 
+ * where 
+ * <dl>
+ *   <dt>&lt;user@gt;</dt>
+ *   <dd>Optional user name</dd>
+ *   <dt>&lt;host@gt;</dt>
+ *   <dd>PROOF cluster master host</dd>
+ *   <dt>&lt;port@gt;</dt>
+ *   <dd>Optional PROOF cluster port on master host</dd>
+ *   <dt>&lt;dsname@gt;</dt>
+ *   <dd>Data set name</dd>
+ *   <dt><tt>&lt;datadir&gt;</tt></dt>
+ *   <dd>is the base directory holding data files </dd>
+ *   <dt><tt>&lt;collection&gt;</tt></dt>
+ *   <dd>is an ASCII or XML list of input sources</dd>
+ *   <dt><tt>&lt;file&gt;</tt></dt>
+ *   <dd>is a single ROOT file</dd>
+ *   <dt>&lt;treename@gt;</dt>
+ *   <dd>Optional tree name in data set, often <tt>esdTree</tt> or
+ *   <tt>aodTree</tt></dd>
+ *   <dt>&lt;options@gt;</dt>
+ *   <dd>List of options separated by an &amp;
+ *     <dl>
+ *       <dt><tt>workers=N[x]</tt></dt>
+ *       <dd>Set the number of workers to use.  If <tt>x</tt> is appended, 
+ *         then it's maximum number of workers per slave</dd>
+ *       <dt><tt>dsname</tt>[=&lt;output dataset&gt;]</dt>
+ *       <dd>Register tree output (e.g., AOD) as a new data set on the
+ *         PROOF cluster. If &lt;output dataset&gt; is not specified, take
+ *         the name of the train.</dd>
+ *       <dt><tt>par[=all]</tt></dt>
+ *       <dd>Use PAR files.  If the value <tt>all</tt> is given, then also 
+ *         PAR files of STEERBase, ESD, AOD, ANALYSIS, OADB, ANALYSISalice 
+ *         are used. </dd>
+ *       <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
+ *       <dd>Set the AliROOT mode.  If not specified <tt>default</tt> 
+ *         is assumed</tt>.  See also CreateAliROOTPar</dd>
+ *       <dt><tt>storage=&lt;url&gt;</tt></dt>
+ *       <dd>Specify a non-default storage location for special output
+ *         (e.g., AOD trees).  &lt;url&gt; should be a valid XRootd 
+ *         server URI accessible to the slaves - e.g., 
+ *         <tt>root://lxplus.cern.ch:10930//tmp</tt>.</dd>
+ *     </dl>
+ *   </dd>
+ * </dl>  
+ *
+ * @ingroup pwglf_forward_trains_helper
+ */
+struct ProofHelper : public Helper
+{
+  /** 
+   * Constructor 
+   * 
+   * @param url  Url 
+   * @param opts Options 
+   */
+  ProofHelper(const TUrl& url, Int_t verbose)
+    : Helper(url, verbose), 
+      fUsePars(false), 
+      fBasePars(false)
+  {
+    fOptions.Add("workers",  "N[x]", "Number of workers to use", "0");
+    fOptions.Add("dsname",   "NAME", "Make output dataset", "");
+    fOptions.Add("par",      "tasks|all", "Use par files",           "tasks");
+    fOptions.Add("mode",     "default|rec|sim", "AliROOT mode",      "default");
+    fOptions.Add("storage",  "URL", "Location for external storage", "");    
+
+    if (!fUrl.GetUser() || fUrl.GetUser()[0] == '\0') 
+      fUrl.SetUser(gSystem->GetUserInfo()->fUser);
+  }
+  virtual ~ProofHelper() {}
+  /** 
+   * Load a library/PAR/script 
+   * 
+   * @param name   Name 
+   * @param par    If true, upload & enable PAR 
+   * @param slaves If true, also load on slaves
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t LoadLibrary(const TString& name, 
+                            Bool_t slaves=true)
+  {
+    if (!fUsePars) {
+      Int_t ret = gSystem->Load(MakeLibraryName(name));
+      if (ret < 0) return false;
+      if (slaves) fExtraLibs.Append(Form(":%s", name.Data()));
+    }
+    else { 
+      if (!ParUtilities::Find(name)) { 
+       Error("ProofHelper::LoadLibrary", "Failed to find PAR file %s", 
+             name.Data());
+       return false;
+      }
+      if (!ParUtilities::Build(name)) { 
+       Error("ProofHelper::LoadLibrary", "Failed to build PAR file %s", 
+             name.Data());
+       return false;
+      }
+      if (gProof->UploadPackage(name.Data(), TProof::kRemoveOld) < 0) {
+       Error("ProofHelper::LoadLibrary", "Failed to upload PAR file %s", 
+             name.Data());
+       return false;
+      }
+      fExtraPars.Append(Form(":%s", name.Data()));
+    }
+    return true;
+  }
+  /** 
+   * Load a source file, and compile it 
+   * 
+   * @param name Name of the source file 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t LoadSource(const TString& name)
+  {
+    if (!Helper::LoadSource(name)) return false;
+    fExtraSrcs.Append(Form(":%s", gSystem->BaseName(name.Data())));
+    return true;
+  }
+  /** 
+   * Set-up to load the AliROOT libraries 
+   * 
+   * @param par Whether to use PAR files 
+   * 
+   * @return true on success
+   */
+  virtual Bool_t LoadAliROOT()
+  {
+    if (!gSystem->Getenv("ALICE_ROOT")) { 
+      Error("ProofHelper::LoadAliROOT", "Local AliROOT not available");
+      return false;
+    }
+
+    Bool_t tmp = fUsePars;
+    fUsePars   = fBasePars;
+    if (!LoadLibrary("STEERBase"))     return false;
+    if (!LoadLibrary("ESD"))           return false;
+    if (!LoadLibrary("AOD"))           return false;
+    if (!LoadLibrary("ANALYSIS"))      return false;
+    if (!LoadLibrary("OADB"))          return false;
+    if (!LoadLibrary("ANALYSISalice")) return false;
+    fUsePars = tmp;
+
+    return CreateAliROOTPar();
+  }
+  /** 
+   * Get the name of the AliROOT par file to use 
+   * 
+   * @return String 
+   */
+  virtual const char* AliROOTParName() const
+  {
+    return "ALIROOT";
+  }
+  /** 
+   * Create an AliROOT par file from the executing AliROOT.  This PAR
+   * file basically uses the environment of the client - that is, we
+   * assume that the used AliROOT is accessible on the slaves - e.g.,
+   * via an NFS export.
+   * 
+   * Note, the SETUP.C script take one argument - a TList of TNamed
+   * parameters.  Parameters processed are     
+   *
+   * - ALIROOT_MODE=[default,aliroot,rec,sim,train]
+   *   - default: Load base analysis libraries 
+   *   - aliroot: Load $ALICE_ROOT/macros/loadlibs.C
+   *   - rec:     Load $ALICE_ROOT/macros/loadlibsrec.C
+   *   - sim:     Load $ALICE_ROOT/macros/loadlibssim.C
+   * - ALIROOT_EXTRA_LIBS Colon separated list of additional (Ali)ROOT
+   *   libraries to load on the slaves.
+   * 
+   * The generated PAR file is uploaded but not enabled until we have 
+   * populated fExtraLibs.  The enabling takes place at the end of the 
+   * set-up. 
+   * 
+   * @return true on success, false otherwise.     */
+  virtual Bool_t CreateAliROOTPar()
+  {
+    if (fBasePars) return true;
+
+    TString parName(AliROOTParName());
+    // Set-up directories 
+    if (gSystem->MakeDirectory(parName) < 0) {
+      Error("ProofHelper::CreateAliROOTPar", "Could not make directory '%s'", 
+           parName.Data());
+      return false;
+    }
+    
+    if (gSystem->MakeDirectory(Form("%s/PROOF-INF", parName.Data()))) {
+      Error("ProofHelper::CreateAliROOTPar", 
+           "Could not make directory %s/PROOF-INF", 
+           parName.Data());
+      return false;
+    }
+
+    std::ofstream b(Form("%s/PROOF-INF/BUILD.sh",parName.Data()));
+    if (!b) { 
+      Error("ProofHelper::CreateAliROOTPar", 
+           "Failed to make BUILD.sh shell script");
+      return false;
+    }
+    b << "#!/bin/sh\n\n"
+      << "# echo Nothing to do\n"
+      << "exit 0\n"
+      << std::endl;
+    b.close();
+    gSystem->Exec(Form("chmod a+x %s/PROOF-INF/BUILD.sh",parName.Data()));
+
+    std::ofstream s(Form("%s/PROOF-INF/SETUP.C", parName.Data()));
+    if (!s) { 
+      Error("ProofHelper::CreateAliROOTPar", 
+           "Failed to make SETUP.C ROOT script");
+      return false;
+    }
+    s << "void SETUP(TList* opts) {\n"
+      << "  gSystem->Setenv(\"ALICE\",\"" 
+      << gSystem->Getenv("ALICE") << "\");\n"
+      << "  gSystem->Setenv(\"ALICE_ROOT\",\"" 
+      << gSystem->Getenv("ALICE_ROOT") << "\");\n"
+      << "  gSystem->Setenv(\"ALICE_TARGET\",\"" 
+      << gSystem->Getenv("ALICE_TARGET") << "\");\n"
+      << "  gSystem->AddDynamicPath("
+      << "\"$(ALICE_ROOT)/lib/tgt_$(ALICE_TARGET)\");\n";
+    if (gSystem->Getenv("OADB_PATH")) 
+      s << "  gSystem->Setenv(\"OADB_PATH\",\"" 
+       << gSystem->Getenv("OADB_PATH") << "\");\n";
+    s << "  \n"
+      << "  // Info(\"SETUP\",\"Loading ROOT libraries\");\n"
+      << "  gSystem->Load(\"libTree\");\n"
+      << "  gSystem->Load(\"libGeom\");\n"
+      << "  gSystem->Load(\"libVMC\");\n"
+      << "  gSystem->Load(\"libPhysics\");\n"
+      << "  gSystem->Load(\"libMinuit\");\n"
+      << "  \n";
+    s << "  // Info(\"SETUP\",\"Parameter list:\");\n"
+      << "  if (!opts) return;\n"
+      << "  //opts->ls();\n"
+      << "  \n";
+    s << "  TObject* par = opts->FindObject(\"ALIROOT_MODE\");\n"
+      << "  if (par) {\n"
+      << "    // Info(\"SETUP\",\"ALIROOT mode: %s\", par->GetTitle());\n"
+      << "    TString mode(par->GetTitle());\n"
+      << "    if (mode.EqualTo(\"default\",TString::kIgnoreCase)) {\n"
+      << "      gSystem->Load(\"libSTEERBase\");\n"
+      << "      gSystem->Load(\"libESD\");\n"
+      << "      gSystem->Load(\"libAOD\");\n"
+      << "      gSystem->Load(\"libANALYSIS\");\n"
+      << "      gSystem->Load(\"libOADB\");\n"
+      << "      gSystem->Load(\"libANALYSISalice\");\n"
+      << "    }\n"
+      << "    else if (mode.EqualTo(\"aliroot\",TString::kIgnoreCase)) \n"
+      << "      gROOT->Macro(\"$ALICE_ROOT/macros/loadlibs.C\");\n"
+      << "    else if (mode.EqualTo(\"rec\",TString::kIgnoreCase)) \n"
+      << "      gROOT->Macro(\"$ALICE_ROOT/macros/loadlibsrec.C\");\n"
+      << "    else if (mode.EqualTo(\"sim\",TString::kIgnoreCase)) \n"
+      << "      gROOT->Macro(\"$ALICE_ROOT/macros/loadlibssim.C\");\n"
+      << "    else if (mode.EqualTo(\"train\",TString::kIgnoreCase)) \n"
+      << "      gROOT->Macro(\"$ALICE_ROOT/macros/loadlibstrain.C\");\n"
+      << "    else if (mode.EqualTo(\"custom\",TString::kIgnoreCase)) \n"
+      << "      gROOT->Macro(\"$ALICE_ROOT/macros/loadlibstrain.C\");\n"
+      << "  }\n"
+      << "  \n";
+    s << "  par = opts->FindObject(\"ALIROOT_EXTRA_LIBS\");\n"
+      << "  if (par) {\n"
+      << "    Info(\"SETUP\",\"Libaries to load: %s\n\",par->GetTitle());\n"
+      << "    TString tit(par->GetTitle());\n"
+      << "    TObjArray* tokens = tit.Tokenize(\":\");\n"
+      << "    TObject*   lib    = 0;\n"
+      << "    TIter      next(tokens);\n"
+      << "    while ((lib = next())) {\n"
+      << "      TString libName(lib->GetName());\n"
+      << "      if (!libName.BeginsWith(\"lib\")) libName.Prepend(\"lib\");\n"
+      << "      // Info(\"SETUP\",\"Loading %s ...\",libName.Data());\n"
+      << "      gSystem->Load(Form(\"lib%s\",lib->GetName()));\n"
+      << "    }\n"
+      << "  }\n"
+      << "}\n"
+      << std::endl;
+    s.close();
+
+    Int_t ret = gSystem->Exec(Form("tar -czf %s.par %s",
+                                  parName.Data(), parName.Data()));
+    if (ret != 0) { 
+      Error("ProofHelper::CreateAliROOTPar", "Failed to pack up PAR files");
+      return false;
+    }
+
+    ret = gProof->UploadPackage(Form("./%s.par", parName.Data()),
+                               TProof::kRemoveOld);
+    if (ret != 0) { 
+      Error("ProofHelper::CreateAliROOTPar", 
+           "Failed to upload the AliROOT PAR file");
+      return false;
+    }
+    // Note, the PAR isn't enabled until much later when we've
+    // collected all the needed libraries in fExtraLibs
+    return true;
+  }
+  /** 
+   * Get the mode identifier 
+   * 
+   * @return Always kProof
+   */
+  virtual UShort_t Mode() const { return kProof; }
+  /**
+   * Get the mode string used for AliAnalysisManager::StartAnalysis
+   */
+  virtual const char* ModeString() const { return "proof"; }
+  /** 
+   * Set-up done before task set-ups 
+   * 
+   * @return true on success 
+   */
+  virtual Bool_t PreSetup()
+  {
+    // --- Set prefered GSI method ---------------------------------
+    gEnv->SetValue("XSec.GSI.DelegProxy", "2");
+
+      // --- Add ALICE_ROOT directory to search path for packages ----
+    Info("ProofHelper::PreSetup", "Set location of packages");
+    gEnv->SetValue("Proof.GlobalPackageDirs", 
+                  Form("%s:%s", 
+                       gEnv->GetValue("Proof.GlobalPackageDirs", "."), 
+                       gSystem->Getenv("ALICE_ROOT")));
+
+    // --- PAR parameters --------------------------------------------
+    fUsePars  = fOptions.Has("par");
+    fBasePars = (fUsePars && 
+                fOptions.Get("par").EqualTo("all",TString::kIgnoreCase));
+
+    // --- Connect to the cluster ------------------------------------
+    TUrl connect(fUrl);
+    connect.SetAnchor("");
+    connect.SetFile("");
+    connect.SetOptions("");
+    TString opts;
+    if (fOptions.Has("workers")) 
+      opts.Append(Form("workers=%s", fOptions.Get("workers").Data()));
+      
+    Info("ProofHelper::PreSetup", "Connecting to %s with %soptions %s", 
+        connect.GetUrl(), 
+        opts.IsNull() ? "no " : "", 
+        opts.Data());
+    TString proto(connect.GetProtocol());
+    if (proto.BeginsWith("lite") && fOptions.Has("workers")) 
+      TProof::Open(opts);
+    else 
+      TProof::Open(connect.GetUrl(), opts);
+    // TProof::Open(connect.GetHost(), opts);
+    if (!gProof) { 
+      Error("ProofHelper::PreSetup", "Failed to open Proof connection %s", 
+           connect.GetUrl());
+      return false;
+    }
+    Info("ProofHelper::PreSetup", "Using progress dialog=%d",   
+        gProof->TestBit(TProof::kUseProgressDialog));
+    return true;
+  }
+  /** 
+   * Set-up done after the task set-ups 
+   *
+   * @return true on success 
+   */
+  virtual Bool_t PostSetup() 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    if (!mgr) { 
+      Error("ProofHelper::PostSetup", "No analysis manager defined");
+      return false;
+    }
+
+    // --- Check for output ------------------------------------------
+    if (fOptions.Has("dsname")) 
+      OutputUtilities::RegisterDataset(fOptions.Get("dsname"));
+    if (fOptions.Has("storage"))
+      OutputUtilities::RegisterStorage(fOptions.Get("storage"));
+
+    // --- If we are not using PARs for Base, enable special PAR -----
+    if (!fBasePars) {
+      TString tmp(fExtraLibs.Strip(TString::kBoth,':'));
+      TList* params = new TList;
+      params->SetOwner(true);
+      params->Add(new TNamed("ALIROOT_EXTRA_LIBS", tmp.Data()));
+      if (fOptions.Has("mode"))
+       params->Add(new TNamed("ALIROOT_MODE", fOptions.Get("mode").Data()));
+      else
+       params->Add(new TNamed("ALIROOT_MODE", "default"));
+      Int_t ret = gProof->EnablePackage(AliROOTParName(), params, true);
+      if (ret < 0) {
+       Error("ProofHelper::EnableAliROOT", "Failed to enable AliROOT PAR %s", 
+             AliROOTParName());
+       return false;
+      }
+    }
+    
+    // --- Load par files --------------------------------------------
+    TString    tmp  = fExtraPars.Strip(TString::kBoth,':');
+    TObjArray* pars = tmp.Tokenize(":");
+    TObject*   obj  = 0;
+    TIter      next(pars);
+    while ((obj = next())) { 
+      Int_t ret = gProof->EnablePackage(obj->GetName());
+      if (ret < 0) { 
+       Error("ProofHelper::PostSetup", "Failed to enable PAR %s",
+             obj->GetName());
+       return false;
+      }
+    }
+    
+    // --- Load extra sources ----------------------------------------
+    TString    tmp2 = fExtraSrcs.Strip(TString::kBoth, ':');
+    TObjArray* srcs = tmp2.Tokenize(":");
+    TIter      next2(srcs);
+    while ((obj = next())) { 
+      Int_t ret = gProof->Load(Form("%s++g", obj->GetName()), true);
+      if (ret < 0) { 
+       Error("ProofHelper::PostSetup", "Failed to compile %s", obj->GetName());
+       return false;
+      }
+    }
+    return true;
+  }
+  /** 
+   * Start the analysis 
+   * 
+   * @param nEvents Number of events to analyse 
+   * 
+   * @return The return value of AliAnalysisManager::StartAnalysis
+   */
+  virtual Long64_t Run(Long64_t nEvents=-1) 
+  {
+    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
+    gProof->SetLogLevel(TMath::Max(fVerbose-2,0), 
+                       /* TProofDebug::kPacketizer| */
+                       TProofDebug::kLoop|
+                       /* TProofDebug::kSelector|
+                       TProofDebug::kOutput|
+                       TProofDebug::kInput|
+                       TProofDebug::kGlobal|*/
+                       TProofDebug::kPackage);
+    TString dsName(fUrl.GetFile());
+    // if (fUrl.GetAnchor() && fUrl.GetAnchor()[0] != '\0') 
+    //   dsName.Append(Form("#%s", fUrl.GetAnchor()));
+    Long64_t ret = mgr->StartAnalysis(fUrl.GetProtocol(), dsName, nEvents);
+    
+    if (fVerbose > 2) 
+      TProof::Mgr(fUrl.GetUrl())->GetSessionLogs()->Save("*","proof.log");
+    return ret;
+  }
+  /** 
+   * Print information to standard output
+   * 
+   * @param option 
+   */
+  virtual void Print(Option_t* option="") const 
+  {
+    Helper::Print(option);
+    std::cout << std::boolalpha 
+             << "  --- Other settings -------\n"
+             << "  Extra libraries  : " << fExtraLibs << "\n"
+             << "  Extra PARs       : " << fExtraPars << "\n"
+             << "  Extra sources    : " << fExtraSrcs << "\n"
+             << "  Use PARs of tasks: " << fUsePars   << "\n"
+             << "  Use PARs of base : " << fBasePars  
+             << std::noboolalpha << std::endl;
+  }
+  /** 
+   * Path of output 
+   * 
+   * @return Path to output - possibly a data set
+   */
+  virtual TString OutputPath() const 
+  {
+    TString ret;
+    if (fOptions.Has("dsname")) {
+      ret = Form("/%s/%s/", gProof->GetGroup(), gProof->GetUser());
+      ret.Append(OutputUtilities::RegisteredDataset());
+    }
+    return ret;
+  }
+  /** 
+   * @return URL help string
+   */
+  virtual const Char_t* UrlHelp() const 
+  {
+    return "proof://<host>[:<port>]/[<dataset>|<path>][?<options>][#<treeName>]";
+  }
+  /** 
+   * @return Short description 
+   */
+  virtual const char* Desc() const { return "PROOF"; }
+  TString fExtraLibs;
+  TString fExtraPars;
+  TString fExtraSrcs;
+  Bool_t  fUsePars;
+  Bool_t  fBasePars;
+};
+#endif
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/QATrain.C b/PWGLF/FORWARD/trains/QATrain.C
new file mode 100644 (file)
index 0000000..3040e56
--- /dev/null
@@ -0,0 +1,377 @@
+/**
+ * @file   QATrain.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Fri Jun  1 13:55:50 2012
+ * 
+ * @brief  
+ * 
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+
+#include "TrainSetup.C"
+#include <AliESDInputHandlerRP.h>
+#include <AliCDBManager.h>
+
+//====================================================================
+/**
+ * Analysis train to do full Quality Assurance train
+ * 
+ * @ingroup pwglf_forward_trains_specific
+ */
+class QATrain : public TrainSetup
+{
+public:
+  enum { 
+    kCDBConnect = 0x1, 
+    kEventStats = 0x2,  // Event Statistics (Jan Fiete)
+    kCentrality = 0x4,  // Centrality (A. Toia)
+    kDefaultFlags = (kCDBConnect|kEventStats|kCentrality)
+  };
+  enum { 
+    kVertex     = 0x000001,  // Vertexing (A. Dainese)
+    kSymmetric  = 0x000002,  // TPC QA (E. Sicking)
+    kVZERO      = 0x000004,  // VZERO QA  (C. Cheshkov)
+    kTPC        = 0x000008,  // TPC (Jacek Otwinowski & Michael Knichel)
+    kSPD        = 0x000010,  // SPD (A. Mastroserio) - Needs RP
+    kSDD        = 0x000020,  // SDD (F. Prino) Needs RP
+    kSSD        = 0x000040,  // SSD dEdx (Marek Chojnacki)
+    kITS        = 0x000080,  // 
+    kITSSA      = 0x000100,  // ITS saTracks (F.Prino)
+    kITSAlign   = 0x000200,  // ITS align (F.Prino)
+    kTRD        = 0x000400,  // TRD (Alex Bercuci, M. Fasel) 
+    kZDC        = 0x000800,  // ZDC (Chiara Oppedisano) 
+    kCALO       = 0x001000,  // Calorimetry (Gustavo Conesa)
+    kMUONTRG    = 0x002000,  // Muon Trigger
+    kMUONEff    = 0x004000,  // Muon Efficiency (not used) Need geo 
+    kV0         = 0x008000,  // V0-Decay Reconstruction (Ana Marin)
+                            // (not used) Need MC truth 
+    kBRes       = 0x010000,  // Impact parameter resolution
+                            // (xianbao.yuan@pd.infn.it,
+                            // andrea.dainese@pd.infn.it) 
+    kMUON       = 0x020000,  // MUON QA (Philippe Pillot)
+    kTOF        = 0x040000,  // TOF (Francesca Bellini)
+    kPIDRes     = 0x080000,  // PIDResponse (Jens)
+    kPID        = 0x100000,  // PIDqa (Jens)
+    kHMPID      = 0x200000,  // HMPID QA (Giacomo Volpe)
+    kT0         = 0x400000,  // T0 QA (Alla Mayevskaya)
+    kFMD        = 0x800000,  // FMD QA (Christian Holm Christiansen)
+    kDefaultModules  = (kVertex|kSymmetric|kVZERO|kTPC|kSPD|kSDD|kSSD|kITS|
+                       kITSSA|kITSAlign|kTRD|kZDC|kCALO|kMUONTRG|kBRes|
+                       kMUON|kTOF|kPIDRes|kPID|kHMPID|kT0|kFMD)
+  };
+    
+    
+
+  /** 
+   * Constructor.  Date and time must be specified when running this
+   * in Termiante mode on Grid
+   * 
+   * @param name     Name of train 
+   */
+  QATrain(const char* name="PilotAnalysis")
+    : TrainSetup(name, false, 0, 0, 0, 0, 0), 
+      fRun(0),
+      fFlags(kDefaultFlags), 
+      fModules(kDefaultModules), 
+      fTriggerMask(AliVEvent::kAnyINT), 
+      fTriggerHM(AliVEvent::kHighMult),
+      fTriggerEMC(AliVEvent::kEMC7), 
+      fTriggerMUONBarrel(AliVEvent::kMUU7),
+      fCollisionType(0) // 0: pp, 1: PbPb
+  {}
+  void SetFlags(UShort_t flags) { fFlags = flags; }
+  void SetRun(UInt_t run) { fRun = run; }
+  void SetModules(UInt_t m) { fModules = m; }
+protected:
+  AliVEventHandler* CreateInputHandler(EType type)
+  {
+    if (type != kESD) return 0;
+    AliAnalysisManager::GetAnalysisManager()->SetRunFromPath(fRun);
+    
+    AliESDInputHandlerRP* ih = new AliESDInputHandlerRP();
+    ih->SetReadFriends(kTRUE);
+    ih->SetActiveBranches("ESDfriend");
+    return ih;
+  }
+  AliAnalysisTaskSE* CreateTaskAndSetCollisionCandidates(const char* macro)
+  {
+    Long_t ret = gROOT->Macro(macro);
+    if (!ret) return 0;
+    AliAnalysisTaskSE* task = reinterpret_cast<AliAnalysisTaskSE*>(ret);
+    task->SelectCollisionCandidates(fTriggerMask);
+    return task;
+  }
+  void CreateCDBConnect()
+  {                                 
+    ::Info("CreateCDBConnect", "Loading CDB connect w/run=%d", fRun);
+    Long_t ret = gROOT->Macro(Form("AddTaskCDBconnect.C(%d)", fRun));
+    ::Info("CreateCDBConnect", "Loaded %p", fRun);
+    if (!ret) return;
+    AliCDBManager::Instance()->SetDefaultStorage("raw://");
+  }
+  void CreatePhysicsSelection(Bool_t mc,
+                             AliAnalysisManager* mgr)
+  {
+    // Event Statistics (Jan Fiete)
+    if (!(fFlags & kEventStats)) return;
+    TrainSetup::CreatePhysicsSelection(mc, mgr);
+  }
+  void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    // Centrality (A. Toia)
+    if (!(fFlags & kCentrality)) return;
+    TrainSetup::CreateCentralitySelection(mc, mgr);
+  } 
+  void CreateVertex()
+  {
+    // Vertexing (A. Dainese)
+    gROOT->Macro(Form("AddTaskVertexESD.C(kFALSE,0x%x)", fTriggerMask));
+  }
+  void CreateSymmetric()
+  {
+    // TPC QA (E. Sicking)
+    gROOT->Macro(Form("AddTaskQAsym.C(0,0x%x,0x%x,0x%x,0x%x)",
+                     fTriggerMask, fTriggerHM, fTriggerEMC, 
+                     fTriggerMUONBarrel));
+  }
+  void CreateVZERO()
+  {
+    //  VZERO QA  (C. Cheshkov)
+    gROOT->Macro("AddTaskVZEROQA.C(0)");
+  }
+  void CreateTPC()
+  {
+    // TPC (Jacek Otwinowski & Michael Knichel)
+    //
+    // Optionally MC information can be used by setting the 1st
+    // argument to true 
+    // 
+    // Optionally friends information can be switched off by setting
+    // the 2st argument to false
+    // 
+    // Optionally highMult axis can be used by setting the 3st
+    // argument to true (for PbPb)
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGPP/TPC/macros",
+                            gROOT->GetMacroPath()));
+    CreateTaskAndSetCollisionCandidates("AddTaskPerformanceTPCdEdxQA.C(kFALSE,kTRUE,kFALSE)");
+  }
+  void CreateSPD()
+  {
+    // SPD (A. Mastroserio)
+    CreateTaskAndSetCollisionCandidates("AddTaskSPDQA.C");
+    // AliAnalysisTask* task = 
+    //   CreateTaskAndSetCollisionCandidates("AddTaskSPDQA.C");
+    // if (!task) return;
+    // task->SetOCDBInfo(fRun, "raw://");
+  }
+  void CreateSDD()
+  {
+    // SDD (F. Prino)
+    CreateTaskAndSetCollisionCandidates("AddSDDPoints.C");
+  }
+  void CreateSSD()
+  {
+    // SSD dEdx (Marek Chojnacki)
+    CreateTaskAndSetCollisionCandidates("AddTaskdEdxSSDQA.C");
+  }
+  void CreateITS()
+  {
+    gROOT->Macro("AddTaskPerformanceITS.C(kFALSE)");
+    if (fCollisionType == 0) return;
+
+    gROOT->ProcessLine("AddTaskPerformanceITS(kFALSE,kFALSE,kFALSE,3500,10000)");
+    gROOT->ProcessLine("AddTaskPerformanceITS(kFALSE,kFALSE,kFALSE,590,1570)");
+    gROOT->ProcessLine("AddTaskPerformanceITS(kFALSE,kFALSE,kFALSE,70,310)");
+  }
+  void CreateITSSA() 
+  {
+    // ITS saTracks, align (F.Prino)
+    CreateTaskAndSetCollisionCandidates("AddTaskITSsaTracks.C(kFALSE,kFALSE)");
+  }
+  void CreateITSAlign()
+  {
+    // ITS saTracks, align (F.Prino)
+    gROOT->Macro("AddTaskITSAlign.C(0,2011");
+  }
+  void CreateTRD()
+  {
+    // TRD (Alex Bercuci, M. Fasel) 
+    gSystem->AddIncludePath("-I${ALICE_ROOT}/PWGPP/TRD");
+    gROOT->Macro("AddTrainPerformanceTRD.C(\"ESD DET EFF RES PID\")"); 
+  }
+  void CreateZDC()
+  {
+    // ZDC (Chiara Oppedisano)
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGPP/ZDC",
+                            gROOT->GetMacroPath()));
+    CreateTaskAndSetCollisionCandidates("AddTaskZDCQA.C");
+  }
+  void CreateCALO(EMode mode, Bool_t par)
+  {
+    // Calorimetry (Gustavo Conesa)
+    LoadLibrary("EMCALUtils", mode, par, true);
+    LoadLibrary("PHOSUtils", mode, par, true);
+    LoadLibrary("PWG4PartCorrBase", mode, par, true);
+    LoadLibrary("PWG4PartCorrDep", mode, par, true);
+    
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWG4/macros/QA",
+                            gROOT->GetMacroPath()));
+    CreateTaskAndSetCollisionCandidates("AddTaskCalorimeterQA.C(\"ESD\",20011,kFALSE,kFALSE)");
+    Long_t ret = gROOT->ProcessLine("AddTaskCalorimeterQA(\"ESD\",2011,kFALSE,kFALSE,\"\",\"EMC7\")");
+    if (!ret) return;
+    AliAnalysisTaskSE* task = reinterpret_cast<AliAnalysisTaskSE*>(ret);
+    task->SelectCollisionCandidates(fTriggerEMC);
+  }
+  void CreateMUONTRG(EMode mode, Bool_t par)
+  {
+    // Muon Trigger
+    LoadLibrary("PWG3base", mode, par, true);
+    LoadLibrary("PWG3muon", mode, par, true);
+    LoadLibrary("PWG3muondep", mode, par, true);
+    
+    gROOT->Macro("AddTaskMTRchamberEfficiency.C");
+  }
+  void CreateMUONEff()
+  {
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWG3/muondep",
+                            gROOT->GetMacroPath()));
+    gROOT->Macro("AddTaskMUONTrackingEfficiency.C");
+  }
+  void CreateV0()
+  {
+    // V0-Decay Reconstruction (Ana Marin) (not used)
+    gROOT->Macro("AddTaskV0QA.C(kFALSE)");
+  }
+  void CreateBRes()
+  {
+    // Impact parameter resolution (xianbao.yuan@pd.infn.it,
+    // andrea.dainese@pd.infn.it) 
+    CreateTaskAndSetCollisionCandidates(Form("AddTaskImpParRes.C(%s)", 
+                                            fCollisionType == 0 ? 
+                                            "" : 
+                                            "kFALSE,-1,kFALSE,kFALSE"));
+  }
+  void CreateMUON(EMode mode, Bool_t par)
+  {
+    // MUON QA (Philippe Pillot)
+    LoadLibrary("PWG3base", mode, par, true);
+    LoadLibrary("PWG3muon", mode, par, true);
+    LoadLibrary("PWG3muondep", mode, par, true);
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWG3/muon",
+                            gROOT->GetMacroPath()));
+    gROOT->Macro("AddTaskMuonQA.C");
+  }
+  void CreateTOF()
+  {
+    // TOF (Francesca Bellini)
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGPP/TOF",
+                            gROOT->GetMacroPath()));
+    CreateTaskAndSetCollisionCandidates("AddTaskTOFQA.C");
+  }
+  void CreatePIDRes()
+  {
+    // PIDResponse (Jens)
+    CreateTaskAndSetCollisionCandidates("AddTaskPIDResponse.C");
+  }
+
+  void CreatePID()
+  {
+    // PIDqa (Jens)
+    CreateTaskAndSetCollisionCandidates("AddTaskPIDqa.C");
+  }
+  void CreateHMPID()
+  {
+    // HMPID QA (Giacomo Volpe)
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGPP/HMPID",
+                            gROOT->GetMacroPath()));
+    CreateTaskAndSetCollisionCandidates("AddTaskHmpidQA.C");
+  }
+  void CreateT0()
+  {
+    // T0 QA (Alla Mayevskaya)
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGPP/T0",
+                            gROOT->GetMacroPath()));
+    CreateTaskAndSetCollisionCandidates("AddTaskT0QA.C");
+  }
+  void CreateFMD(EMode mode, Bool_t par)
+  {
+    // FMD QA (Christian Holm Christiansen)
+    LoadLibrary("PWGLFforward2", mode, par, true);
+    Bool_t mc = AliAnalysisManager::GetAnalysisManager()
+      ->GetMCtruthEventHandler() != 0;
+    gROOT->Macro(Form("AddTaskForwardQA.C(%d,%d)", mc, (fFlags & kCentrality)));
+  }
+  //__________________________________________________________________
+  /** 
+   * Create the tasks 
+   * 
+   * @param mode Processing mode
+   * @param par  Whether to use par files 
+   * @param mgr  Analysis manager 
+   */
+  void CreateTasks(EMode mode, Bool_t par, AliAnalysisManager* mgr)
+  {
+    // --- Output file name ------------------------------------------
+    AliAnalysisManager::SetCommonFileName("QAResults.root");
+
+    LoadLibrary("CORRFW", mode, par);
+    LoadLibrary("TENDER", mode, par);
+    LoadLibrary("PWG0base", mode, par);
+    LoadLibrary("PWG0dep", mode, par);
+    LoadLibrary("PWG0selectors", mode, par);
+    LoadLibrary("PWGPP", mode, par);    
+
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGPP/PilotTrain"
+                            ":$(ALICE_ROOT)/PWGPP/macros",
+                            gROOT->GetMacroPath()));   
+    mgr->AddStatisticsTask(fTriggerMask);
+    if (fFlags   & kCDBConnect) CreateCDBConnect();
+    if (fModules & kVertex)     CreateVertex();
+    if (fModules & kSymmetric)  CreateSymmetric();
+    if (fModules & kVZERO)      CreateVZERO();
+    if (fModules & kTPC)        CreateTPC();
+    if (fModules & kSPD)        CreateSPD();
+    if (fModules & kSDD)        CreateSDD();
+    if (fModules & kSSD)        CreateSSD();
+    if (fModules & kITS)        CreateITS();
+    if (fModules & kITSSA)      CreateITSSA();
+    if (fModules & kITSAlign)   CreateITSAlign();
+    if (fModules & kTRD)        CreateTRD(); 
+    if (fModules & kZDC)        CreateZDC(); 
+    if (fModules & kCALO)       CreateCALO(mode, par); 
+    if (fModules & kMUONTRG)    CreateMUONTRG(mode, par); 
+    if (fModules & kMUONEff)    CreateMUONEff(); 
+    if (fModules & kV0)         CreateV0(); 
+    if (fModules & kBRes)       CreateBRes(); 
+    if (fModules & kMUON)       CreateMUON(mode, par); 
+    if (fModules & kTOF)        CreateTOF(); 
+    if (fModules & kPIDRes)     CreatePIDRes(); 
+    if (fModules & kPID)        CreatePID(); 
+    if (fModules & kHMPID)      CreateHMPID(); 
+    if (fModules & kT0)         CreateT0(); 
+    if (fModules & kFMD)        CreateFMD(mode, par); 
+  }
+  /** 
+   * Crete output handler - we don't want one here. 
+   * 
+   * @return 0
+   */
+  AliVEventHandler* CreateOutputHandler(EType) { return 0; }
+  UInt_t   fRun; // Run number 
+  UShort_t fFlags; // Flags 
+  UInt_t   fModules; // Modules to load 
+  UInt_t   fTriggerMask; 
+  UInt_t   fTriggerHM;
+  UInt_t   fTriggerEMC;
+  UInt_t   fTriggerMUONBarrel;
+  UShort_t fCollisionType; // 0: pp, 1: PbPb 
+  
+  
+  Bool_t fUseCent; // Whether to use centrality or not 
+};
+
+//
+// EOF
+//
diff --git a/PWGLF/FORWARD/trains/RunTrain.C b/PWGLF/FORWARD/trains/RunTrain.C
new file mode 100644 (file)
index 0000000..6e394f1
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * @file   RunTrain.C
+ * @author Christian Holm Christensen <cholm@nbi.dk>
+ * @date   Tue Oct 16 17:49:49 2012
+ * 
+ * @brief  Script to run a train 
+ *
+ * @ingroup pwglf_forward_trains
+ */
+/** 
+ * Build a script 
+ * 
+ * @param name     Name of script 
+ * @param verbose  Whether to be verbose 
+ * @param force    Whether to force re-compilation 
+ * @param debug    Whether to enable debug symbols  
+ * 
+ * @return true on success 
+ *
+ * @ingroup pwglf_forward_trains
+ */
+Bool_t
+BuildScript(const char* name, Bool_t verbose, Bool_t force, Bool_t debug)
+{
+  const char opt[] = { (force ? '+' : debug ? 'g' : '\0'), 
+                      (force && debug ? 'g' : '\0'), '\0' };
+  if (verbose) Printf("Building %s ...",name);
+  Int_t error;
+  Int_t ret = gROOT->LoadMacro(Form("%s.C+%s", name, opt), &error);
+  if (ret < 0 || error) { 
+    Error("BuildScript", "Failed to build %s: %d", error);
+    return false;
+  }
+  return true;
+  
+}
+
+/** 
+ * Build all helper classes 
+ * 
+ * @param verbose Whether to be verbose 
+ * @param force   Whether to force re-builds
+ * @param debug   Whether to enable debug symbols 
+ * 
+ * @return true on success 
+ *
+ * @ingroup pwglf_forward_trains
+ */
+Bool_t
+BuildHelpers(Bool_t verbose, Bool_t force, Bool_t debug)
+{
+  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
+  gSystem->Load("libANALYSIS");
+  gSystem->Load("libANALYSISalice");
+  const char* scripts[] = { "AvailableSoftware", 
+                           "ChainBuilder", 
+                           "ParUtilities",
+                           "OutputUtilities", 
+                           "Option",
+                           "Helper", 
+                           "LocalHelper", 
+                           "ProofHelper", 
+                           "LiteHelper",
+                           "AAFHelper", 
+                           "PluginHelper",
+                           "AAFPluginHelper", 
+                           "GridHelper",
+                           "TrainSetup",
+                           0 };
+  const char** ptr = scripts;
+  while ((*ptr)) {
+    if (!BuildScript(*ptr, verbose, force, debug)) return false;
+    ptr++;
+  }
+  return true;
+}
+
+/** 
+ * Show the usage 
+ * 
+ *
+ * @ingroup pwglf_forward_trains
+ */
+void PlainUsage()
+{
+  std::cout << "Usage: .x RunTrain.C(NAME,CLASS,OPTIONS)\n\n"
+           << "  NAME       Name of train (free form)\n"
+           << "  CLASS      Name of class implementing TrainSetup\n"
+           << "  OPTIONS    Comma separated list of options\n"
+           << std::endl;
+}
+
+/** 
+ * Function to run a train.  
+ * 
+ * @param name  Name of the train. 
+ * @param cls   class name of train setup
+ * @param opts  Optons 
+ * 
+ * @return true on success
+ *
+ * @ingroup pwglf_forward_trains
+ */
+Bool_t RunTrain(const TString& name, const TString& cls, 
+               const TString& uri,  const TString& opts)
+{
+  // Check for help 
+  if (name.IsNull() || name.EqualTo("help", TString::kIgnoreCase) || 
+      cls.IsNull()  || cls.EqualTo("help", TString::kIgnoreCase)) {
+    PlainUsage();
+    return true;
+  }
+  
+  Bool_t verb = opts.Contains("verbose");
+  // Build our helpers 
+  if (!BuildHelpers(verb, false, true)) return false;
+
+  // Tokenize options 
+  if (!opts.EndsWith(",")) opts.Append(",");
+  opts.Append("url="); 
+  opts.Append(uri);
+  TObjArray* optList = opts.Tokenize(",");
+  return TrainSetup::Main(name, cls, optList);
+}
+/*
+ * EOF
+ */    
+    
diff --git a/PWGLF/FORWARD/trains/TrainSetup.C b/PWGLF/FORWARD/trains/TrainSetup.C
new file mode 100644 (file)
index 0000000..aee24c3
--- /dev/null
@@ -0,0 +1,643 @@
+/**
+ * @defgroup pwglf_forward_trains Trains
+ * 
+ * Train specifications 
+ *
+ * @ingroup pwglf_forward
+ */
+/**
+ * @file   TrainSetup.C
+ * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
+ * @date   Tue Oct 16 17:56:57 2012
+ * 
+ * @brief  Base classs for train specifications 
+ * 
+ * @ingroup pwglf_forward_trains
+ */
+#ifndef TRAINSETUP_C
+#define TRAINSETUP_C
+#ifndef __CINT__
+# include "Helper.C"
+# include "Option.C"
+# include <TDatime.h>
+# include <TUrl.h>
+# include <TString.h>
+# include <TApplication.h>
+# include <AliAnalysisManager.h>
+# include <AliVEventHandler.h>
+# include <AliPhysicsSelection.h>
+# include <AliPhysicsSelectionTask.h>
+# include <AliCentralitySelectionTask.h>
+# include <AliESDInputHandler.h>
+# include <AliAODInputHandler.h>
+# include <AliAODHandler.h>
+# include <AliMCEventHandler.h>
+#else 
+struct Helper;
+struct OptionList;
+class TDatime;
+class TUrl;
+class TString;
+class AliVEventHandler;
+class AliAnalysisManager;
+class AliInputEventHandler;
+#endif
+
+//====================================================================
+/** 
+ * Generic set-up of an analysis train using the grid-handler (AliEn plugin). 
+ *
+ * See also @ref train_setup_doc
+ *
+ * @ingroup pwglf_forward_trains
+ * 
+ */
+struct TrainSetup
+{
+  /** 
+   * Constructor 
+   * 
+   * @param name Name of the train
+   */
+  TrainSetup(const TString& name)
+    : fName(name), 
+      fEscapedName(name),
+      fHelper(0)
+  {
+    fOptions.Add("help", "Show help");
+    fOptions.Add("date", "YYYY-MM-DD HH:MM", "Set date", "now");
+    fOptions.Add("mc", "Assume MC input");
+    fOptions.Add("bare-ps", "Use bare physics selection w/o task");
+    fOptions.Add("verbose", "LEVEL", "Set verbosity level", "0");
+    fOptions.Add("url", "URL", "Job location & input URL", "");
+    fOptions.Add("overwrite", "Allow overwrite");
+    fOptions.Add("events", "N", "Number of events to analyse", "-1");
+    fOptions.Add("type", "ESD|AOD|USER", "Input data stype", "");
+    fEscapedName = EscapeName(fName, "");
+  }
+  /** 
+   * Destructor
+   */
+  virtual ~TrainSetup() {}
+  /* @} */
+  //__________________________________________________________________
+  /** 
+   * @{ 
+   * @name Execution 
+   */
+  /** 
+   * Initialize 
+   * 
+   * @return true on success 
+   */
+  Bool_t Init()
+  {
+    // --- Create the helper -----------------------------------------
+    TString  url     = fOptions.Get("url");
+    Int_t    verbose = fOptions.AsInt("verbose");
+    Bool_t   mc      = fOptions.AsBool("mc");
+
+    fHelper = Helper::Create(url.Data(), verbose);
+    if (!fHelper) { 
+      Error("Init", "Failed to make the worker for URL %s", url.Data());
+      return false;
+    }
+
+    UShort_t type    = fHelper->InputType();
+    if (fOptions.Has("type")) { 
+      const TString& it = fOptions.Get("type");
+      if      (it.EqualTo("ESD",TString::kIgnoreCase)) type = Helper::kESD;
+      else if (it.EqualTo("AOD",TString::kIgnoreCase)) type = Helper::kAOD;
+      else if (it.EqualTo("user",TString::kIgnoreCase)) 
+       type = Helper::kUser;
+    }
+
+    // --- Get current directory and set-up sub-directory ------------
+    TString cwd = gSystem->WorkingDirectory();
+    if (!SetupWorkingDirectory()) return false;
+
+    // --- Do initial helper setup -----------------------------------
+    if (!fHelper->PreSetup()) return false;
+
+    // --- Load ROOT libraries ---------------------------------------
+    if (!fHelper->LoadROOT()) return false;
+    
+    // --- Load AliROOT libraries ------------------------------------
+    if (!fHelper->LoadAliROOT()) return false;
+
+    // --- Create analysis manager -----------------------------------
+    AliAnalysisManager *mgr  = CreateAnalysisManager(fName);
+
+    // In test mode, collect system information on every event 
+    // if (oper == kTest)  mgr->SetNSysInfo(1); 
+    if (verbose  >  0)      mgr->SetDebugLevel(verbose);
+    if (fHelper->Mode() == Helper::kLocal) 
+      mgr->SetUseProgressBar(kTRUE, 100);
+   
+    // --- ESD input handler ------------------------------------------
+    AliVEventHandler*  inputHandler = CreateInputHandler(type);
+    if (inputHandler) mgr->SetInputEventHandler(inputHandler);
+    
+    // --- Monte-Carlo ------------------------------------------------
+    AliVEventHandler*  mcHandler = CreateMCHandler(type,mc);
+    if (mcHandler) mgr->SetMCtruthEventHandler(mcHandler);
+    
+    // --- AOD output handler -----------------------------------------
+    AliVEventHandler*  outputHandler = CreateOutputHandler(type);
+    if (outputHandler) mgr->SetOutputEventHandler(outputHandler);
+
+    // --- Include analysis macro path in search path ----------------
+    gROOT->SetMacroPath(Form("%s:%s:$ALICE_ROOT/ANALYSIS/macros",
+                            cwd.Data(), gROOT->GetMacroPath()));
+
+    // --- Physics selction - only for ESD ---------------------------
+    if (type == Helper::kESD) CreatePhysicsSelection(mc, mgr);
+    
+    // --- Create centrality task ------------------------------------
+    CreateCentralitySelection(mc, mgr);
+
+    // --- Create tasks ----------------------------------------------
+    CreateTasks(mgr);
+
+    // --- Post set-up initialization of helper ----------------------
+    if (!fHelper->PostSetup()) return false;
+
+    // --- Set debug level on defined tasks --------------------------
+    if (verbose > 0) {
+      TIter next(mgr->GetTasks());
+      AliAnalysisTask* sub = 0;
+      while ((sub = static_cast<AliAnalysisTask*>(next()))) { 
+       AliAnalysisTaskSE* se = dynamic_cast<AliAnalysisTaskSE*>(sub);
+       if (!se) continue;
+       se->SetDebugLevel(verbose);
+      }
+    }
+
+    // --- Print this setup ------------------------------------------
+    Print();
+
+    // --- Initialise the train --------------------------------------
+    if (!mgr->InitAnalysis())  {
+      gSystem->ChangeDirectory(cwd.Data());
+      Error("Init","Failed to initialise train");
+      return false;
+    }
+
+    // --- Enable progress bar ---------------------------------------
+    if (fHelper->Mode() != Helper::kGrid) 
+      mgr->SetUseProgressBar(true, 100);
+
+    // --- Save setup to disk ----------------------------------------
+    SaveSetup(true);
+
+    // Some information
+    mgr->PrintStatus();
+
+    return true;
+  }
+  Bool_t Run(Bool_t doExit=false)
+  {
+    TString cwd = gSystem->WorkingDirectory();
+    Bool_t status = false;
+    try {
+      if (!Init()) throw TString("Failed to intialize the train");
+
+      // if (r) SaveSetup(*r, nEvents, asShell);
+      
+      Long64_t nEvents = fOptions.AsLong("events", -1);
+      Long64_t ret     = fHelper->Run(nEvents);
+      
+      // Make sure we go back 
+      gSystem->ChangeDirectory(cwd.Data());
+      
+      // Return. 
+      if (ret < 0) throw TString("Analysis failed");
+
+      status = true;
+    }
+    catch (TString& e) {
+      Error("Main", e);
+      status = false;
+    }
+    if (gApplication && doExit) {
+      gSystem->Sleep(3);
+      gApplication->Terminate(status ? 0 : 1);
+    }
+    return true;
+  }
+  /** 
+   * Get the options 
+   * 
+   * 
+   * @return Reference ot the options 
+   */
+  OptionList& Options() { return fOptions; }
+  /** 
+   * Print information to standard output 
+   * 
+   */
+  void Print(Option_t* ="") const
+  {
+    std::cout << "Train: " << fName << " (" << fEscapedName << ")" 
+             << std::endl;
+    fOptions.Show(std::cout);
+    if (fHelper) fHelper->Print();
+  }
+  /** 
+   * Show the help 
+   * 
+   * @param o 
+   * 
+   * @return 
+   */
+  Bool_t Help(std::ostream& o=std::cout, bool asProg=false)
+  {
+    if (!fOptions.Has("help")) return true;
+
+    if (asProg) 
+      o << "Usage: runTrain --name=NAME --class=CLASS [OPTIONS]";
+    else 
+      o << "Usage: RunTrain(NAME, CLASS, OPTIONS)";
+    
+    o << "\n\nOptions:\n\n";
+    if (asProg) {
+      OptionList tmp(fOptions);
+      tmp.Add("name", "STRING", "Name of train", fName);
+      tmp.Add("class", "NAME", "Name of setup class", "");
+      tmp.Help(o,"  --");
+    }
+    else 
+      fOptions.Help(o, "  ");
+    
+    o << "\n";
+
+    if (!fHelper && fOptions.Has("url")) {
+      TString url = fOptions.Get("url");
+      fHelper = Helper::Create(url.Data());
+    }
+    if (fHelper) { 
+      o << fHelper->Desc() << " URL form:\n\n"
+       << "    " << fHelper->UrlHelp() << "\n\n"
+       << "Options:\n";
+      fHelper->Options().Help(o, "    ");
+      o << "\n";
+    }
+    else { 
+      o << "Possible URL forms:\n\n";
+      Helper::ShowUrlHelp("LocalHelper");
+      Helper::ShowUrlHelp("ProofHelper");
+      Helper::ShowUrlHelp("LiteHelper");
+      Helper::ShowUrlHelp("AAFHelper");
+      Helper::ShowUrlHelp("AAFPluginHelper");
+      Helper::ShowUrlHelp("GridHelper");
+      o << "\n";
+    }
+    return false;
+  }
+  /** 
+   * Run train.  This will AcLic compile the setup script, create
+   * an object of that type with the given name, and then pass the 
+   * options to it.  Then, it will run the setup.
+   * 
+   * @param name  Train name 
+   * @param cls   Class name 
+   * @param opts  Comma seperated list of options
+   * 
+   * @return true on success
+   */
+  static Bool_t Main(const TString& name, const TString& cls, 
+                    const TCollection* opts, 
+                    Bool_t asProg=true)
+  {
+    if (cls.IsNull()) { 
+      Error("Main", "No class name specified");
+      return false;
+    }
+    if (name.IsNull()) { 
+      Error("Main", "No train name specified");
+      return false;
+    }
+    Int_t error = 0;
+    Int_t r1 = gROOT->LoadMacro(Form("%s.C++g", cls.Data()), &error);
+    if (r1 < 0 || error) { 
+      Error("Main", "Failed to load setup %s: %d", cls.Data(), error);
+      return false;
+    }
+
+    // Make our object using the interpreter 
+    TString create = TString::Format("new %s(\"%s\")", 
+                                  cls.Data(), name.Data());
+    gROOT->ProcessLine("gSystem->RedirectOutput(\"/dev/null\",\"w\");");
+    Long_t ret = gROOT->ProcessLine(create, &error);
+    gROOT->ProcessLine("gSystem->RedirectOutput(0);");
+    if (!ret || error) { 
+      Error("Main", "Failed to make object of class %s: 0x%08lx/%d\n\t%s", 
+           cls.Data(), ret, error, create.Data());
+      return false;
+    }
+    TrainSetup* train = reinterpret_cast<TrainSetup*>(ret);
+    
+    // Now parse the options 
+    if (!train->Options().Parse(opts)) { 
+      Error("Main", "Failed to parse options");
+      return false;
+    }
+
+    // Check if we got a help request
+    if (train->Options().Has("help")) { 
+      train->Help(std::cout, asProg);
+      return true;
+    }
+    // return train->Init();
+    return train->Run(asProg);
+  }
+protected:
+  //__________________________________________________________________
+  /** 
+   * @{ 
+   * @Name Overloadable behaviour 
+   */
+  //------------------------------------------------------------------
+  /** 
+   * Create the analysis manager 
+   * 
+   * @param name Name of the analysis 
+   * 
+   * @return Created analysis manager 
+   */
+  virtual AliAnalysisManager* CreateAnalysisManager(const char* name)
+  {
+    return new AliAnalysisManager(name,"Analysis Train");
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create input handler 
+   * 
+   * @param type 
+   * 
+   * @return 
+   */
+  virtual AliVEventHandler* CreateInputHandler(UShort_t type)
+  {
+    switch (type) {
+    case Helper::kESD:  return new AliESDInputHandler(); 
+    case Helper::kAOD:  return new AliAODInputHandler(); 
+    case Helper::kUser: return 0;
+    }
+    return 0;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create MC input handler 
+   * 
+   * @param type  Run type (ESD or AOD)
+   * @param mc    Assume monte-carlo input 
+   * 
+   * @return 
+   */
+  virtual AliVEventHandler* CreateMCHandler(UShort_t /*type*/, bool mc)
+  {
+    if (!mc) return 0;
+    AliMCEventHandler* mcHandler = new AliMCEventHandler();
+    mcHandler->SetReadTR(true); 
+    return mcHandler;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create output event handler 
+   * 
+   * @param type 
+   * 
+   * @return 
+   */
+  virtual AliVEventHandler* CreateOutputHandler(UShort_t type)
+  {
+    AliAODHandler* ret = new AliAODHandler();
+    switch (type) { 
+    case Helper::kESD: 
+      ret->SetOutputFileName("AliAOD.root");
+      break;
+    case Helper::kAOD: 
+      ret->SetOutputFileName("AliAOD.pass2.root");
+      break;
+    case Helper::kUser: 
+      break;
+    }
+    
+    return ret;
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create physics selection, and add to manager
+   * 
+   * @param mc Whether this is for MC 
+   * @param mgr Manager
+   */
+  virtual void CreatePhysicsSelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    if (fOptions.Has("bare-ps")) {
+      AliInputEventHandler* input = 
+       dynamic_cast<AliInputEventHandler*> (mgr->GetInputEventHandler());
+      if (!input) return;
+
+      AliPhysicsSelection* ps = new AliPhysicsSelection();
+      if (mc) ps->SetAnalyzeMC();
+
+      input->SetEventSelection(ps);
+
+      return;
+    }
+    gROOT->Macro(Form("AddTaskPhysicsSelection.C(%d)", mc));
+    mgr->RegisterExtraFile("event_stat.root");
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create centrality selection, and add to manager
+   * 
+   * @param mc Whether this is for MC 
+   * @param mgr Manager
+   */
+  virtual void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
+  {
+    gROOT->Macro("AddTaskCentrality.C");
+    const char* name = "CentralitySelection";
+    AliCentralitySelectionTask* ctask = 
+      dynamic_cast<AliCentralitySelectionTask*>(mgr->GetTask(name));
+    if (!ctask) return;
+    if (mc) ctask->SetMCInput();
+  }
+  //------------------------------------------------------------------
+  /** 
+   * Create analysis tasks.  Must be overloaded by sub-class
+   * 
+   * @param mgr  Manager
+   */
+  virtual void CreateTasks(AliAnalysisManager* mgr)=0;
+  virtual const Char_t* ClassName() const = 0;
+  /* @} */
+  //__________________________________________________________________
+  /** 
+   * @{ 
+   * @name Utility functions 
+   */
+  /** 
+   * Escape bad elements of the name 
+   * 
+   * @param name   Name to escape 
+   * @param datime Date and Time 
+   * 
+   * @return escaped name 
+   */  
+  static TString EscapeName(const char* name, const TString& datimeStr)
+  {
+    TString escaped = name;
+    char  c[] = { ' ', '/', '@', 0 };
+    char* p   = c;
+    while (*p) { 
+      escaped.ReplaceAll(Form("%c", *p), "_");
+      p++;
+    }
+    if (!datimeStr.IsNull()) {
+      TDatime datime;
+      if (datimeStr.EqualTo("now", TString::kIgnoreCase)) 
+       datime.Set();
+      else 
+       datime.Set(datimeStr.Data());
+      if (datime.GetYear() <= 1995 ||
+         datime.GetMonth() == 0 || 
+         datime.GetDay() == 0) return escaped;
+      escaped.Append(Form("_%04d%02d%02d_%02d%02d", 
+                         datime.GetYear(), 
+                         datime.GetMonth(), 
+                         datime.GetDay(), 
+                         datime.GetHour(), 
+                         datime.GetMinute()));
+    }
+    return escaped;
+  }    
+  /** 
+   * Make our working directory if so requested 
+   * 
+   * @return true on success
+   */
+  Bool_t SetupWorkingDirectory()
+  {
+    // Get the name of the target directory 
+    TString& nam = fEscapedName;
+
+    // Check if the directory exists already 
+    Bool_t exists = gSystem->AccessPathName(nam.Data()) == 0;
+    if (fHelper->Operation() == Helper::kTerminate && !exists) {
+      Error("SetupWorkingDirectory", "File/directory %s does not exists", 
+           nam.Data());
+      return false;
+    }
+
+    Bool_t overwrite = fOptions.Has("overwrite");
+    // If we're not allowed to overwrite, then complain
+    if (!overwrite && exists) {
+      Error("SetupWorkingDirectory", "File/directory %s already exists", 
+           nam.Data());
+      return false;
+    }
+
+    // Make the target directory if it doesn't exists 
+    if (!exists) {
+      if (gSystem->MakeDirectory(nam.Data())) {
+       Error("SetupWorkingDirectory", "Failed to make directory '%s'", 
+             nam.Data());
+       return false;
+      }
+    }
+      
+    // Change directory to target directory 
+    if (!gSystem->ChangeDirectory(nam.Data())) { 
+      Error("SetupWorkingDirectory", "Failed to change directory to %s", 
+           nam.Data());
+      return false;
+    }
+    Info("SetupWorkingDirectory", "Made subdirectory %s, and cd'ed there", 
+        nam.Data());
+    return true;
+  }
+  /** 
+   * Save the setup as a ROOT script and possibly also a shell script
+   * 
+   * @param asShellScript If true, also save as shell script
+   */
+  virtual void SaveSetup(Bool_t asShellScript)
+  {
+    if (asShellScript) 
+      SaveSetupShell("rerun", ClassName(), fName, fOptions);
+    SaveSetupROOT("ReRun", ClassName(), fName, fOptions);
+  }
+  /** 
+   * Save a setup as a shell script 
+   * 
+   * @param out   Output name of shell script 
+   * @param cls   Class of the train 
+   * @param name  Name of the train
+   * @param opts  Option list
+   */
+  static void SaveSetupShell(const TString& out, const TString& cls,
+                             const TString& name, const OptionList& opts)
+  {
+    std::ofstream o(Form("%s.sh", out.Data()));
+    o << "#!/bin/bash\n\n"
+      << "class=\"" << cls << "\"\n"
+      << "name=\"" << name << "\"\n\n"
+      << "# Available options\n"
+      << "# \n";
+    opts.Help(o, "#    --");
+    o << "#\n"
+      << "opts=(--class=$class \\\n"
+      << "  --name=$name";
+    opts.Store(o, " \\\n  --", "", true);
+    o << ")\n\n"
+      << "echo \"Running runTrain ${opts[@]} $@\"\n"
+      << "runTrain \"${opts[@]}\" $@\n\n"
+      << "# EOF" << std::endl;
+    o.close();
+    gSystem->Exec(Form("chmod a+x %s.sh", out.Data()));
+  }
+  /** 
+   * Save a setup as a ROOT script 
+   * 
+   * @param out   Output name of shell script 
+   * @param cls   Class of the train 
+   * @param name  Name of the train
+   * @param opts  Option list
+   */
+  static void SaveSetupROOT(const TString& out, const TString& cls,
+                           const TString& name, const OptionList& opts)
+  {
+    OptionList tmp(opts);
+    tmp.Remove("url");
+    std::ofstream o(Form("%s.C", out.Data()));
+    o << "/* Available options:\n"
+      << " *\n";
+    tmp.Help(o, " *    ");
+    o << " */\n"
+      << "Bool_t " << out << "()\n"
+      << "{\n"
+      << "  TString name(\"" << name << "\");\n"
+      << "  TString cls(\"" << cls << "\");\n"
+      << "  TString uri(\"" << opts.Get("url") << "\");\n"
+      << "  TString opts(";
+    tmp.Store(o, "\"", ",\"\n               ", false);
+    o << ");\n\n"
+      << "  gROOT->LoadMacro(\"RunTrain.C\");\n\n"
+      << "  return RunTrain(name, cls, uri, opts);\n"
+      << "}\n" 
+      << "//\n"
+      << "// EOF\n" 
+      << "//" << std::endl;
+    o.close();
+  }    
+  /* @} */
+  TString      fName;
+  TString      fEscapedName;
+  OptionList   fOptions;
+  Helper*      fHelper;
+};
+#endif
diff --git a/PWGLF/FORWARD/trains/test.sh b/PWGLF/FORWARD/trains/test.sh
new file mode 100755 (executable)
index 0000000..cb7cac9
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+type=
+proto=
+host=
+file=
+opts=
+anchor="esdTree"
+dbg=
+ex=
+par=0
+dir=/data/alice/data/ppb/LHC12g/pass1/188359/
+
+usage()
+{
+cat<<EOF
+Usage: $0 -t TYPE [OPTIONS]
+
+Options:
+       -t,--type  TYPE       Set type of job [$type]
+       -v,--verbose LEVEL    Set verbosity
+       -d,--debug            Run in debugger [$dbg]
+       -b,--batch            Run batch mode [$ex]
+       -p,--par              Run with PAR files [$par]
+        -h,--help             Show this help
+
+TYPE is one of 
+
+       local        Run over local files 
+       lite         Run in Proof-lite
+       hehi         Run on hehi Proof farm
+       caf          Run on CAF 
+       caf plugin   Run on CAF using plugin 
+       grid         Run in AliEn - Real data
+       grid hijing  Run in AliEn - Hijing simulation
+       grid dpmjet  Run in AliEn - DPMJet simulation
+EOF
+}
+
+while test $# -gt 0 ; do 
+    case $1 in 
+       -t|--type) type=$2 ; shift ;; 
+       -d|--debug) dbg="gdb --args" ;; 
+       -b|--batch) ex="$ex --batch" ;; 
+       -v|--verbose) ex="$ex --verbose=$2" ; shift ;; 
+       -p|--par)   par=1 ;;
+       -h|--help)  usage ; exit 0 ;;
+    esac
+    shift 
+done
+case $type in 
+    local|lite) 
+       proto=$type
+       file="$dir"
+       if test "x$type" = "xlite" ; then opts="workers=10" ; fi
+       ;;
+    hehi*)
+       proto=proof
+       host="hehi00.nbi.dk";
+       file="/default/cholm/LHC12g_pass1_uncalibrated_ESD_188359_partial";
+       opts="mode=default&dsname"
+       if test $par -gt 0 ; then opts="$opts&par=tasks" ; fi
+       ;;
+    caf*)
+       proto=proof
+       host="alice-caf.cern.ch";
+       file="/alice/data/LHC12g_000188359_ESDs_p1_uncalibrated";
+       opts="mode=default&workers=60&aliroot=v5-03-68-AN&dsname"
+       if test $par -gt 0 ; then opts="$opts&par=tasks" ; fi
+       case $type in 
+           *plugin*) opts="${opts}&plugin" ;;
+       esac
+       ;;
+    grid*)
+       proto=alien
+       opts="run=188359-188359"
+       case $type in 
+           *hijing*)
+               file="/alice/sim/2012/LHC12g1/";
+               opts="$opts&pattern=*/AliESDs.root&mc"
+               ;;
+           *dpmjet*)
+               file="/alice/sim/2012/LHC12g4a/";
+               opts="$opts&pattern=*/AliESDs.root&mc"
+               ;;
+           *)
+               file="/alice/data/2012/LHC12g";
+               opts="$opts&pattern=ESDs/pass1_uncalibrated/*/AliESDs.root"
+               ;;
+       esac
+       if test $par -gt 0 ; then opts="$opts&par=tasks" ; fi
+       ;;
+    help*)
+       ;;
+esac
+
+echo "Building runTrain ..."
+bld="g++ -g `root-config --cflags --glibs` \
+    -lVMC -lGeom -lMinuit -lXMLIO -lTree -lTreePlayer \
+    -I$ALICE_ROOT/include -L$ALICE_ROOT/lib/tgt_${ALICE_TARGET} \
+    -lSTEERBase -lESD -lAOD -lANALYSIS -lOADB -lANALYSISalice \
+    trainMain.cxx -o runTrain"
+echo $bld
+$bld || exit 1
+
+echo "Cleaning previous run ($name) ..."
+name=test_`echo $type | tr ' \t&/' '_'`
+rm -rf $name
+
+echo "Running the job ..."
+cmd="./runTrain --class=MakeAODTrain --name=$name \
+    --url=${proto}://${host}/${file}?${opts}#${anchor} \
+    --sys=3 --snn=5023 --field=-5  --cent \
+    $ex $@"
+echo "$dbg $cmd"
+$dbg $cmd
+
+echo "done"
diff --git a/PWGLF/FORWARD/trains/trainMain.cxx b/PWGLF/FORWARD/trains/trainMain.cxx
new file mode 100644 (file)
index 0000000..3c06f95
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+  To compile, do 
+
+  rootcint -f OptionDict.C -c Option.C 
+  g++ `root-config --cflags --libs` \
+    -lVMC -lGeom -lMinuit -lXMLIO -lTree -lTreePlayer \
+    -I$ALICE_ROOT/include -L$ALICE_ROOT/lib/tgt_${ALICE_TARGET} \
+    -lSTEERBase -lESD -lAOD -lANALYSIS -lOADB -lANALYSISalice \
+    trainMain.cxx -o runTrain
+*/
+#include "AvailableSoftware.C" 
+#include "ChainBuilder.C" 
+#include "ParUtilities.C"
+#include "OutputUtilities.C" 
+#include "Option.C"
+#include "Helper.C" 
+#include "LocalHelper.C" 
+#include "ProofHelper.C" 
+#include "LiteHelper.C"
+#include "AAFHelper.C" 
+#include "PluginHelper.C"
+#include "AAFPluginHelper.C" 
+#include "GridHelper.C"
+#include "TrainSetup.C"
+
+#include <TGApplication.h>
+#include <TROOT.h>
+#include <TList.h>
+#include <TObjString.h>
+#include <TString.h>
+
+#include <iostream>
+#include <iomanip>
+
+/** 
+ * Custom timer to do a deferred start after the application 
+ * has been started 
+ */
+struct Deferred : public TTimer
+{
+  Deferred(const TString& name, const TString& cls, 
+          const TCollection* opts)
+    : TTimer(1000, false), 
+      fName(name), 
+      fClass(cls), 
+      fOptions(opts)
+  {
+    Start(1000, true);
+  }
+  Bool_t Notify()
+  {
+    // gSystem->RemoveTimer(this);
+    Info("Notify", "Will run train setup: %s (%s)", 
+        fName.Data(), fClass.Data());
+    return TrainSetup::Main(fName, fClass, fOptions);
+  }
+  TString fName;
+  TString fClass;
+  const TCollection* fOptions;
+};
+
+/** 
+ * Append directory to header and script search path
+ * 
+ * @param dir Directory
+ * 
+ * @ingroup pwglf_forward_trains_run
+ */
+void AppendPath(const char* dir)
+{
+  gROOT->SetMacroPath(Form("%s:%s",gROOT->GetMacroPath(), dir));
+  gSystem->AddIncludePath(Form("-I%s", dir));
+}
+/** 
+ * Print a fake option description.  Used for options specific to this
+ * program.
+ * 
+ * @param o    Output stream 
+ * @param opt  Option (including meta argument)
+ * @param desc Option description.
+ * 
+ * @ingroup pwglf_forward_trains_run
+ */
+void PrintFakeOption(std::ostream& o, const char* opt, const char* desc)
+{
+  o << "  --" << std::left << std::setw(30) << opt << " " << desc << std::endl;
+}
+
+/** 
+ * Print usage information 
+ * 
+ * @param progname Program name 
+ * @param o        Output stream
+ * @param r        Optional runner. 
+ * 
+ * @ingroup pwglf_forward_trains_run
+ */
+void Usage(const char* progname, std::ostream& o)
+{
+  o << "Usage: " << progname << " --class=CLASS --name=NAME [OPTIONS]\n\n"
+    << "PROGRAM OPTIONS:\n";
+  PrintFakeOption(o, "class=CLASS",       "Train class");
+  PrintFakeOption(o, "name=NAME",         "Name of train");
+  PrintFakeOption(o, "include=DIRECTORY", "Append dir to macro/header path");
+  PrintFakeOption(o, "batch",             "Batch mode");
+}
+
+int
+main(int argc, char** argv)
+{
+  TList optList;
+  TString name;
+  TString cls;
+  Bool_t  batch = false;
+  Bool_t  help  = false;
+
+  // --- Parse options -----------------------------------------------
+  for (int i = 1; i < argc; i++) { 
+    if (argv[i][0] == '-' && argv[i][1] == '-') { 
+      TString arg(argv[i]);
+      TString val("");
+      arg.ReplaceAll("\"'", "");
+      Int_t   eq = arg.Index("=");
+      if (eq != kNPOS) val = arg(eq+1, arg.Length()-eq-1);
+      if      (arg.BeginsWith("--class"))   cls  = val;
+      else if (arg.BeginsWith("--name"))    name = val;
+      else if (arg.BeginsWith("--include")) AppendPath(val);
+      else if (arg.BeginsWith("--batch"))   batch = true;
+      else if (arg.BeginsWith("--help"))    help  = true;
+      else optList.Add(new TObjString(&(argv[i][2])));
+    }
+  }
+  // --- check for help ----------------------------------------------
+  if (help && cls.IsNull()) {
+    if (cls.IsNull()) {
+      Usage(argv[0], std::cout);
+      return 0;
+    }
+    optList.Add(new TObjString("help"));
+  }
+
+  // --- Check name and class ----------------------------------------
+  if (name.IsNull()) { 
+    Error("main", "No name specified");
+    return 1;
+  }
+  if (cls.IsNull()) { 
+    Error("main", "No class specified");
+    return 1;
+  }
+
+  // --- Setup script path -------------------------------------------
+  const char* aliPath  = gSystem->ExpandPathName("$ALICE_ROOT");
+  const char* fwdPath  = gSystem->ExpandPathName("$ALICE_ROOT/PWGLF/FORWARD/");
+  AppendPath(aliPath);
+  AppendPath(Form("%s/include",   aliPath));
+  AppendPath(Form("%s/trains",    fwdPath));
+  AppendPath(Form("%s/analysis2", fwdPath));
+
+
+  // --- Set-up Application ------------------------------------------
+  TApplication* app = 0;
+  gROOT->SetBatch(true);
+  if (!batch) { 
+    gROOT->SetBatch(false);
+    app = new TGApplication("runTrain", 0, 0);
+    app->InitializeGraphics();
+  }
+
+  // --- run, possibly in a timer ------------------------------------
+  Bool_t ret = true;
+  if (batch) 
+    ret = TrainSetup::Main(name, cls, &optList);
+  else {
+    new Deferred(name, cls, &optList);
+    Info("main", "Running application (%s)", gROOT->IsBatch() 
+        ? "batch" : "normal");
+    gApplication->Run();
+  }
+
+  // --- Return ------------------------------------------------------
+  return ret ? 0 : 1;
+}
+//
+// EOF
+//
+
+       
+