ROOT logo
/**
 * @file   GridRailway.C
 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
 * @date   Tue Oct 16 19:01:27 2012
 * 
 * @brief  Grid Analysis Railway
 * 
 * @ingroup pwglf_forward_trains_helper
 * 
 */
#ifndef GRIDHELPER_C
#define GRIDHELPER_C
#include "PluginRailway.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.  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 GridRailway : public PluginRailway
{
  /** 
   * Constructor 
   * 
   * @param url  Url 
   * @param verbose Verbosity level
   */
  GridRailway(const TUrl& url, Int_t verbose)
    : PluginRailway(url, verbose), fRuns()
  {
    // Note, split, merge, and ttl are by default set to values
    // optimized for AOD production on real PbPb data.
    //
    // TTL shouldn't be much smaller than 4h10m.  Split and merge
    // shouldn't be much larger than 75, but probably not smaller than
    // 50.
    fOptions.Add("oper", "FULL|TERMINATE|SUBMIT", "Analysis operation", "FULL");
    fOptions.Add("split",  "N|max",  "Max number of files before split","50");
    fOptions.Add("merge",  "N|max",  "Max number of files for merge",   "50");
    fOptions.Add("run",    "RUNS",   "Range, list, and/or file of runs", "");
    fOptions.Add("alien",  "VERSION","Alien API version",              "V1.1x");
    fOptions.Add("ttl",    "N|max",  "Time to live",                   "6h");
    fOptions.Add("pattern","GLOB",   "File/directory name pattern", "");
    fOptions.Add("concat", "Concatenate all runs");
    fOptions.Add("exclude", "GLOB","Comma separated list of merge excludes","");
  }
  GridRailway(const GridRailway& o)
    : PluginRailway(o), fRuns()
  {}
  GridRailway& operator=(const GridRailway& o)
  {
    if (&o == this) return *this;
    PluginRailway::operator=(o);
    return *this;
  }
  virtual ~GridRailway() {}
  /** 
   * 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;
  }
  void StoreRun(Int_t r)
  {
    TObject* o = new TObject;
    o->SetUniqueID(r);
    fRuns.Add(o);
  }
  /**
   * Read run numbers 
   *
   * @return Number of registered runs 
   */
  virtual Int_t RegisterRuns()
  {
    if (!fOptions.Find("run")) {
      Error("GridRailway::RegisterRuns", "No runs specified");
      return -1;
    }
    Int_t       nRuns  = 0;
    TString     runs   = fOptions.Get("run");
    TObjArray*  tokens = runs.Tokenize(",+:");
    TObjString* part   = 0;
    TIter       next(tokens);
    Bool_t      range  = false;
    Bool_t      individual = false;
    // Info("GridRailway::RegisterRuns", "Runs specified are %s", runs.Data());
    while ((part = static_cast<TObjString*>(next()))) {
      TString& s = part->String();
      if (s.Contains("-")) { // Run range 
	if (range) { 
	  Warning("GridRailway::RegisterRuns", "Run range already specified, "
		  "ignoring %s", s.Data());
	  continue;
	}
	if (individual) { 
	  Warning("GridRailway::RegisterRuns", 
		  "Run ranges and individual run specs do not mix, "
		  "ignoring %s", s.Data());
	  continue;
	}
	TObjArray* ranges = s.Tokenize("-");
	if (ranges->GetEntriesFast() > 2) { 
	  Warning("GridRailway::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;
	// Info("GridRailway::RegisterRuns", "Run range %d -> %d", first, last);
	fHandler->SetRunRange(first, last);
	ranges->Delete();
	range = true;
	for (Int_t r = first; r <= last; r++) StoreRun(r);
	continue;
      }
      if (s.IsDigit()) { // single run
	if (range) { 
	  Warning("GridRailway::RegisterRuns", 
		  "Run ranges and individual run specs do not mix, "
		  "ignoring %s", s.Data());
	  continue;
	}
	// Info("GridHandler::RegisterRuns", "Adding run %s", s.Data());
	fHandler->AddRunNumber(s.Atoi());
	StoreRun(s.Atoi());
	nRuns++;
	individual = true;
	continue;
      }
      if (range) { 
	Warning("GridRailway::RegisterRuns", "Run ranges and list file "
		"do not mix, ignoring %s", s.Data());
	continue;
      }

      // We assume this part is a file 
      // Info("GridRailway::RegisterRuns", "Reading runs from %s", s.Data());
      std::ifstream in(s.Data());
      if (!in) { 
	s.Prepend("../");
	in.open(s.Data());
	if (!in) {
	  Warning("GridRailway::RegisterRuns", "Failed to open %s", s.Data());
	  continue;
	}
      }
      while (!in.eof()) {
	TString lne;
	lne.ReadLine(in);

	TString bare = lne.Strip(TString::kBoth);
	if (bare[0] == '#') continue;

	TObjArray* ltokens = bare.Tokenize(" \t,");
	TIter lnext(ltokens);
	TObjString* str = 0;
	while ((str = static_cast<TObjString*>(lnext()))) {
	  const TString& token = str->String();
	  if (!token.IsDigit()) continue;
	  
	  int r = token.Atoi();
	  fHandler->AddRunNumber(r);
	  StoreRun(r);
	  nRuns++;
	}
	ltokens->Delete();
      }
#if 0
      while (!in.eof()) { 
	Int_t r;
	in >> r;
	// Info("GridRailway::RegisterRuns", "Read %d, adding", r);
	fHandler->AddRunNumber(r);
	StoreRun(r);
	nRuns++;
	Char_t c;
	in >> c;
	if (in.bad()) break;
      }
#endif
      individual = true;
      in.close();
    }
    return nRuns;
  }
  /** 
   * Executed before setting up tasks 
   * 
   * @return true on success 
   */
  virtual Bool_t PreSetup() 
  {
    if (!PluginRailway::PreSetup()) return false;
    
    // --- Add system library dir to load path -----------------------
    gSystem->AddDynamicPath("/usr/lib");

    // --- Open a connection to the grid -----------------------------
    if (!TGrid::Connect(Form("%s://", fUrl.GetProtocol()))) { 
      Error("GridRailway::PreSetup", "Failed to connect to AliEN");
      return false;
    }
    if (!gGrid || !gGrid->IsConnected()) { 
      Error("GridRailway::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() 
  {
    // Info("GridRailway::PostSetup", "Calling super.PostSetup");
    if (!PluginRailway::PostSetup()) return false;

    // --- API version -----------------------------------------------
    fHandler->SetAPIVersion(fOptions.Get("alien"));
    
    // --- Get the name ----------------------------------------------
    // Info("GridRailway", "Proceeding with plugin setup");
    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);

    // --- Add the run numbers ---------------------------------------
    fHandler->SetRunPrefix(fOptions.Has("mc") ? "%d" : "%09d");
    Int_t nRun = RegisterRuns();

    // --- 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 --------------------------------------
    if (fOptions.Has("ttl")) { 
      TString sttl = fOptions.Get("ttl");
      if (!sttl.EqualTo("max")) {
	Int_t   ttl  = 0;
	if (sttl.IsDigit()) ttl = sttl.Atoi();
	else { 
	  // Parse string of the form <DAYS>d<HOURS>h<MINUTES>m<SECONDS>s
	  Int_t id = sttl.Index("d", 0);
	  if (id == kNPOS) id = -1;
	  else { 
	    TString sdays(sttl(0,id));
	    ttl += 24 * 60 * 60 * sdays.Atoi();
	  }
	  Int_t ih = sttl.Index("h", id+1);
	  if (ih == kNPOS) ih = id;
	  else { 
	    TString shour(sttl(id+1,ih-id-1));
	    ttl += 60 * 60 * shour.Atoi();
	  }
	  Int_t im = sttl.Index("m", ih+1);
	  if (im == kNPOS) im = ih;
	  else { 
	    TString smin(sttl(ih+1, im-ih-1));
	    ttl += 60 * smin.Atoi();
	  }
	  Int_t is = sttl.Index("s", im+1);
	  if (is != kNPOS) { 
	    TString ssec(sttl(im+1, is-im-1));
	    ttl += ssec.Atoi();
	  }
	}
	if (ttl != 0) fHandler->SetTTL(ttl);
	else 
	  Warning("", "Option ttl given but no value found");
      }
    }
    
    // --- 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.AsInt("split"));
      }
    }
    // --- Merge parameters ------------------------------------------
    if (fOptions.Has("merge")) { 
      if (!fOptions.Get("merge").EqualTo("max")) { 
	fHandler->SetMaxMergeFiles(fOptions.AsInt("merge"));
      }
    }
    TString exclude="AliAOD.root *EventStat*.root *event_stat*.root";
    if (fOptions.Has("exclude")) { 
      TString exOpt = fOptions.Get("exclude");
      exOpt.ReplaceAll(",", " ");
      exclude.Append(" ");
      exclude.Append(exOpt);
    }
    fHandler->SetMergeExcludes(exclude);
    
    // --- Set number of runs per master - 1 or all ------------------
    fHandler->SetNrunsPerMaster(fOptions.Has("concat") ? nRun+1 : 1);


    // --- Enable default outputs ------------------------------------
    fHandler->SetDefaultOutputs(true);

    // --- 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("GridRailway::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);

    // --- Loop over defined containers in the analysis manager, and -
    // --- declare these as outputs
    TString listOfAODs  = "";
    TString listOfHists = "";
    TString listOfTerms = "";

    TObjArray*  outs[] = { mgr->GetOutputs(), mgr->GetParamOutputs(), 0 };
    TObjArray** out    = outs;
    while (*out) {
      AliAnalysisDataContainer* cont = 0;
      TIter nextCont(*out);
      while ((cont = static_cast<AliAnalysisDataContainer*>(nextCont()))) {
	TString outName(cont->GetFileName());
	Bool_t   term = (*out == outs[1]);
	TString& list = (outName == "default" ? listOfAODs : 
			 !term ? listOfHists : listOfTerms);
	if (outName == "default") { 
	  if (!mgr->GetOutputEventHandler()) continue; 
	  
	  outName = mgr->GetOutputEventHandler()->GetOutputFileName();
	}
	if (list.Contains(outName)) continue;
	if (!list.IsNull()) list.Append(",");
	list.Append(outName);
      }
      out++;
    }
    TString extra = mgr->GetExtraFiles();
    if (!extra.IsNull()) { 
      if (!listOfAODs.IsNull()) listOfAODs.Append("+");
      extra.ReplaceAll(" ", ",");
      listOfAODs.Append(extra);
   }

#if 0
    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));
    // Disabled for now 
    // plugin->SetOutputArchive(outArchive);
#endif 

    if (listOfAODs.IsNull() && listOfHists.IsNull()) 
      Fatal("PostSetup", "No outputs defined");
    if (!listOfTerms.IsNull()) 
      fHandler->SetTerminateFiles(listOfTerms);
    
    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) return 0;
    Long64_t ret = mgr->StartAnalysis("grid", nEvents);

#if 1
    std::ofstream outJobs(Form("%s.jobid", mgr->GetName()));
    outJobs << fHandler->GetGridJobIDs() << std::endl;
    outJobs.close();

    std::ofstream outStages(Form("%s.stage", mgr->GetName()));
    outStages << fHandler->GetGridStages() << std::endl;
    outStages.close();
#endif
    return ret;
  }
  /** 
   * Link an auxilary file to working directory 
   * 
   * @param name Name of the file
   * @param copy  Whether to copy or not 
   * 
   * @return true on success
   */
  virtual Bool_t AuxFile(const TString& name, bool copy=false)
  {
    if (!Railway::AuxFile(name, copy)) 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("GridRailway::OutputLocation", "No AliEn handler");
      return ret;
    }
    ret = fHandler->GetGridOutputDir();
    if (ret.BeginsWith("/")) return ret;

    AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
    if (!mgr) { 
      Warning("GridRailway::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"; }
  /** 
   * Write auxillary ROOT (and possible shell) script for more 
   * (post-)processing e.g., terminate
   * 
   * @param escaped        Escaped name  
   */
  void AuxSave(const TString& escaped, 
	       Bool_t /*asShellScript*/) 
  {
    // Write plug-in to file 
    TFile* plug = TFile::Open(Form("%s_plugin.root", escaped.Data()), 
			      "RECREATE");
    fHandler->Write("plugin");
    plug->Close();
    
    TIter       nextLib(&fExtraLibs);
    TObjString* lib = 0;
    TString     libs;
    while ((lib = static_cast<TObjString*>(nextLib()))) {
      if (!libs.IsNull()) libs.Append(" ");
      libs.Append(lib->String());
    }
    TIter       nextPar(&fExtraPars);
    TObjString* par = 0;
    TString     pars;
    while ((par = static_cast<TObjString*>(nextPar()))) {
      if (!pars.IsNull()) pars.Append(" ");
      pars.Append(par->String());
    }
    TIter       nextSrc(&fExtraSrcs);
    TObjString* src = 0;
    TString     srcs;
    while ((src = static_cast<TObjString*>(nextSrc()))) {
      if (!srcs.IsNull()) srcs.Append(" ");
      srcs.Append(src->String());
    }
    TString macDir("$ALICE_ROOT/PWGLF/FORWARD/trains");
    std::ofstream t("Terminate.C");
    if (!t) { 
      Error("GridRailway::AuxSave", "Failed to make terminate ROOT script");
      return;
    }

    t << "// Generated by GridRailway\n"
      << "Bool_t Terminate(Bool_t localMerge=false)\n"
      << "{\n"
      << "  TString name = \"" << escaped << "\";\n"
      << "  TString libs = \"" << libs << "\";\n"
      << "  TString pars = \"" << pars << "\";\n"
      << "  TString srcs = \"" << srcs << "\";\n\n"
      << "  gSystem->Load(\"libANALYSIS\");\n"
      << "  gSystem->Load(\"libANALYSISalice\");\n"
      << "  gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");\n\n"
      << "  gROOT->LoadMacro(\"" << macDir << "/GridTerminate.C+g\");\n\n"
      << "  return GridTerminate(name,libs,pars,srcs,localMerge);\n"
      << "}\n"
      << "// EOF\n"
      << std::endl;
    t.close();

    TString runs;
    TString format(fOptions.Has("mc") ? "%d" : "%09d");
    if (fOptions.Has("concat")) {
      Int_t first = fRuns.First()->GetUniqueID();
      Int_t last  = fRuns.Last()->GetUniqueID();
      TString fmt(format); 
      fmt.Append("_"); 
      fmt.Append(format);
      if (!runs.IsNull()) runs.Append(" ");
      runs.Append(TString::Format(fmt, first, last));
    }
    else {
      TIter next(&fRuns);
      TObject* o = 0;
      while ((o = next())) { 
	if (!runs.IsNull()) runs.Append(" ");
	runs.Append(Form(format, o->GetUniqueID()));
      }
    }

    std::ofstream d("Download.C");
    if (!d) { 
      Error("GridRailway::AuxSave", "Failed to make ROOT script Download.C");
      return;
    }
    d << "// Generated by GridRailway\n"
      << "void Download(Bool_t unpack=true)\n"
      << "{\n"
      << "  TString base = \"" << fUrl.GetProtocol() << "://" 
      << OutputPath() << "\";\n"
      << "  TString runs = \"" << runs << "\";\n\n"
      << "  gROOT->LoadMacro(\"" << macDir << "/GridDownload.C\");\n\n"
      << "  GridDownload(base, runs, unpack);\n"
      << "}\n"
      << "// EOF\n"
      << std::endl;
    d.close();

    std::ofstream w("Watch.C");
    if (!w) {
      Error("GridRailway::AuxSave", "Failed to make ROOT script Watch.C");
      return;
    }
    w << "// Generated by GridRailway\n"
      << "void Watch(Bool_t batch=false, Int_t delay=5*60)\n"
      << "{\n"
      << "  TString name = \"" << escaped << "\";\n"
      << "  gROOT->LoadMacro(\"" << macDir << "/GridWatch.C+g\");\n\n"
      << "  GridWatch(name,batch,delay);\n"
      << "}\n"
      << "// EOF\n"
      << std::endl;
    w.close();

  }
  TList fRuns;
};
#endif
//
// EOF
//
 GridRailway.C:1
 GridRailway.C:2
 GridRailway.C:3
 GridRailway.C:4
 GridRailway.C:5
 GridRailway.C:6
 GridRailway.C:7
 GridRailway.C:8
 GridRailway.C:9
 GridRailway.C:10
 GridRailway.C:11
 GridRailway.C:12
 GridRailway.C:13
 GridRailway.C:14
 GridRailway.C:15
 GridRailway.C:16
 GridRailway.C:17
 GridRailway.C:18
 GridRailway.C:19
 GridRailway.C:20
 GridRailway.C:21
 GridRailway.C:22
 GridRailway.C:23
 GridRailway.C:24
 GridRailway.C:25
 GridRailway.C:26
 GridRailway.C:27
 GridRailway.C:28
 GridRailway.C:29
 GridRailway.C:30
 GridRailway.C:31
 GridRailway.C:32
 GridRailway.C:33
 GridRailway.C:34
 GridRailway.C:35
 GridRailway.C:36
 GridRailway.C:37
 GridRailway.C:38
 GridRailway.C:39
 GridRailway.C:40
 GridRailway.C:41
 GridRailway.C:42
 GridRailway.C:43
 GridRailway.C:44
 GridRailway.C:45
 GridRailway.C:46
 GridRailway.C:47
 GridRailway.C:48
 GridRailway.C:49
 GridRailway.C:50
 GridRailway.C:51
 GridRailway.C:52
 GridRailway.C:53
 GridRailway.C:54
 GridRailway.C:55
 GridRailway.C:56
 GridRailway.C:57
 GridRailway.C:58
 GridRailway.C:59
 GridRailway.C:60
 GridRailway.C:61
 GridRailway.C:62
 GridRailway.C:63
 GridRailway.C:64
 GridRailway.C:65
 GridRailway.C:66
 GridRailway.C:67
 GridRailway.C:68
 GridRailway.C:69
 GridRailway.C:70
 GridRailway.C:71
 GridRailway.C:72
 GridRailway.C:73
 GridRailway.C:74
 GridRailway.C:75
 GridRailway.C:76
 GridRailway.C:77
 GridRailway.C:78
 GridRailway.C:79
 GridRailway.C:80
 GridRailway.C:81
 GridRailway.C:82
 GridRailway.C:83
 GridRailway.C:84
 GridRailway.C:85
 GridRailway.C:86
 GridRailway.C:87
 GridRailway.C:88
 GridRailway.C:89
 GridRailway.C:90
 GridRailway.C:91
 GridRailway.C:92
 GridRailway.C:93
 GridRailway.C:94
 GridRailway.C:95
 GridRailway.C:96
 GridRailway.C:97
 GridRailway.C:98
 GridRailway.C:99
 GridRailway.C:100
 GridRailway.C:101
 GridRailway.C:102
 GridRailway.C:103
 GridRailway.C:104
 GridRailway.C:105
 GridRailway.C:106
 GridRailway.C:107
 GridRailway.C:108
 GridRailway.C:109
 GridRailway.C:110
 GridRailway.C:111
 GridRailway.C:112
 GridRailway.C:113
 GridRailway.C:114
 GridRailway.C:115
 GridRailway.C:116
 GridRailway.C:117
 GridRailway.C:118
 GridRailway.C:119
 GridRailway.C:120
 GridRailway.C:121
 GridRailway.C:122
 GridRailway.C:123
 GridRailway.C:124
 GridRailway.C:125
 GridRailway.C:126
 GridRailway.C:127
 GridRailway.C:128
 GridRailway.C:129
 GridRailway.C:130
 GridRailway.C:131
 GridRailway.C:132
 GridRailway.C:133
 GridRailway.C:134
 GridRailway.C:135
 GridRailway.C:136
 GridRailway.C:137
 GridRailway.C:138
 GridRailway.C:139
 GridRailway.C:140
 GridRailway.C:141
 GridRailway.C:142
 GridRailway.C:143
 GridRailway.C:144
 GridRailway.C:145
 GridRailway.C:146
 GridRailway.C:147
 GridRailway.C:148
 GridRailway.C:149
 GridRailway.C:150
 GridRailway.C:151
 GridRailway.C:152
 GridRailway.C:153
 GridRailway.C:154
 GridRailway.C:155
 GridRailway.C:156
 GridRailway.C:157
 GridRailway.C:158
 GridRailway.C:159
 GridRailway.C:160
 GridRailway.C:161
 GridRailway.C:162
 GridRailway.C:163
 GridRailway.C:164
 GridRailway.C:165
 GridRailway.C:166
 GridRailway.C:167
 GridRailway.C:168
 GridRailway.C:169
 GridRailway.C:170
 GridRailway.C:171
 GridRailway.C:172
 GridRailway.C:173
 GridRailway.C:174
 GridRailway.C:175
 GridRailway.C:176
 GridRailway.C:177
 GridRailway.C:178
 GridRailway.C:179
 GridRailway.C:180
 GridRailway.C:181
 GridRailway.C:182
 GridRailway.C:183
 GridRailway.C:184
 GridRailway.C:185
 GridRailway.C:186
 GridRailway.C:187
 GridRailway.C:188
 GridRailway.C:189
 GridRailway.C:190
 GridRailway.C:191
 GridRailway.C:192
 GridRailway.C:193
 GridRailway.C:194
 GridRailway.C:195
 GridRailway.C:196
 GridRailway.C:197
 GridRailway.C:198
 GridRailway.C:199
 GridRailway.C:200
 GridRailway.C:201
 GridRailway.C:202
 GridRailway.C:203
 GridRailway.C:204
 GridRailway.C:205
 GridRailway.C:206
 GridRailway.C:207
 GridRailway.C:208
 GridRailway.C:209
 GridRailway.C:210
 GridRailway.C:211
 GridRailway.C:212
 GridRailway.C:213
 GridRailway.C:214
 GridRailway.C:215
 GridRailway.C:216
 GridRailway.C:217
 GridRailway.C:218
 GridRailway.C:219
 GridRailway.C:220
 GridRailway.C:221
 GridRailway.C:222
 GridRailway.C:223
 GridRailway.C:224
 GridRailway.C:225
 GridRailway.C:226
 GridRailway.C:227
 GridRailway.C:228
 GridRailway.C:229
 GridRailway.C:230
 GridRailway.C:231
 GridRailway.C:232
 GridRailway.C:233
 GridRailway.C:234
 GridRailway.C:235
 GridRailway.C:236
 GridRailway.C:237
 GridRailway.C:238
 GridRailway.C:239
 GridRailway.C:240
 GridRailway.C:241
 GridRailway.C:242
 GridRailway.C:243
 GridRailway.C:244
 GridRailway.C:245
 GridRailway.C:246
 GridRailway.C:247
 GridRailway.C:248
 GridRailway.C:249
 GridRailway.C:250
 GridRailway.C:251
 GridRailway.C:252
 GridRailway.C:253
 GridRailway.C:254
 GridRailway.C:255
 GridRailway.C:256
 GridRailway.C:257
 GridRailway.C:258
 GridRailway.C:259
 GridRailway.C:260
 GridRailway.C:261
 GridRailway.C:262
 GridRailway.C:263
 GridRailway.C:264
 GridRailway.C:265
 GridRailway.C:266
 GridRailway.C:267
 GridRailway.C:268
 GridRailway.C:269
 GridRailway.C:270
 GridRailway.C:271
 GridRailway.C:272
 GridRailway.C:273
 GridRailway.C:274
 GridRailway.C:275
 GridRailway.C:276
 GridRailway.C:277
 GridRailway.C:278
 GridRailway.C:279
 GridRailway.C:280
 GridRailway.C:281
 GridRailway.C:282
 GridRailway.C:283
 GridRailway.C:284
 GridRailway.C:285
 GridRailway.C:286
 GridRailway.C:287
 GridRailway.C:288
 GridRailway.C:289
 GridRailway.C:290
 GridRailway.C:291
 GridRailway.C:292
 GridRailway.C:293
 GridRailway.C:294
 GridRailway.C:295
 GridRailway.C:296
 GridRailway.C:297
 GridRailway.C:298
 GridRailway.C:299
 GridRailway.C:300
 GridRailway.C:301
 GridRailway.C:302
 GridRailway.C:303
 GridRailway.C:304
 GridRailway.C:305
 GridRailway.C:306
 GridRailway.C:307
 GridRailway.C:308
 GridRailway.C:309
 GridRailway.C:310
 GridRailway.C:311
 GridRailway.C:312
 GridRailway.C:313
 GridRailway.C:314
 GridRailway.C:315
 GridRailway.C:316
 GridRailway.C:317
 GridRailway.C:318
 GridRailway.C:319
 GridRailway.C:320
 GridRailway.C:321
 GridRailway.C:322
 GridRailway.C:323
 GridRailway.C:324
 GridRailway.C:325
 GridRailway.C:326
 GridRailway.C:327
 GridRailway.C:328
 GridRailway.C:329
 GridRailway.C:330
 GridRailway.C:331
 GridRailway.C:332
 GridRailway.C:333
 GridRailway.C:334
 GridRailway.C:335
 GridRailway.C:336
 GridRailway.C:337
 GridRailway.C:338
 GridRailway.C:339
 GridRailway.C:340
 GridRailway.C:341
 GridRailway.C:342
 GridRailway.C:343
 GridRailway.C:344
 GridRailway.C:345
 GridRailway.C:346
 GridRailway.C:347
 GridRailway.C:348
 GridRailway.C:349
 GridRailway.C:350
 GridRailway.C:351
 GridRailway.C:352
 GridRailway.C:353
 GridRailway.C:354
 GridRailway.C:355
 GridRailway.C:356
 GridRailway.C:357
 GridRailway.C:358
 GridRailway.C:359
 GridRailway.C:360
 GridRailway.C:361
 GridRailway.C:362
 GridRailway.C:363
 GridRailway.C:364
 GridRailway.C:365
 GridRailway.C:366
 GridRailway.C:367
 GridRailway.C:368
 GridRailway.C:369
 GridRailway.C:370
 GridRailway.C:371
 GridRailway.C:372
 GridRailway.C:373
 GridRailway.C:374
 GridRailway.C:375
 GridRailway.C:376
 GridRailway.C:377
 GridRailway.C:378
 GridRailway.C:379
 GridRailway.C:380
 GridRailway.C:381
 GridRailway.C:382
 GridRailway.C:383
 GridRailway.C:384
 GridRailway.C:385
 GridRailway.C:386
 GridRailway.C:387
 GridRailway.C:388
 GridRailway.C:389
 GridRailway.C:390
 GridRailway.C:391
 GridRailway.C:392
 GridRailway.C:393
 GridRailway.C:394
 GridRailway.C:395
 GridRailway.C:396
 GridRailway.C:397
 GridRailway.C:398
 GridRailway.C:399
 GridRailway.C:400
 GridRailway.C:401
 GridRailway.C:402
 GridRailway.C:403
 GridRailway.C:404
 GridRailway.C:405
 GridRailway.C:406
 GridRailway.C:407
 GridRailway.C:408
 GridRailway.C:409
 GridRailway.C:410
 GridRailway.C:411
 GridRailway.C:412
 GridRailway.C:413
 GridRailway.C:414
 GridRailway.C:415
 GridRailway.C:416
 GridRailway.C:417
 GridRailway.C:418
 GridRailway.C:419
 GridRailway.C:420
 GridRailway.C:421
 GridRailway.C:422
 GridRailway.C:423
 GridRailway.C:424
 GridRailway.C:425
 GridRailway.C:426
 GridRailway.C:427
 GridRailway.C:428
 GridRailway.C:429
 GridRailway.C:430
 GridRailway.C:431
 GridRailway.C:432
 GridRailway.C:433
 GridRailway.C:434
 GridRailway.C:435
 GridRailway.C:436
 GridRailway.C:437
 GridRailway.C:438
 GridRailway.C:439
 GridRailway.C:440
 GridRailway.C:441
 GridRailway.C:442
 GridRailway.C:443
 GridRailway.C:444
 GridRailway.C:445
 GridRailway.C:446
 GridRailway.C:447
 GridRailway.C:448
 GridRailway.C:449
 GridRailway.C:450
 GridRailway.C:451
 GridRailway.C:452
 GridRailway.C:453
 GridRailway.C:454
 GridRailway.C:455
 GridRailway.C:456
 GridRailway.C:457
 GridRailway.C:458
 GridRailway.C:459
 GridRailway.C:460
 GridRailway.C:461
 GridRailway.C:462
 GridRailway.C:463
 GridRailway.C:464
 GridRailway.C:465
 GridRailway.C:466
 GridRailway.C:467
 GridRailway.C:468
 GridRailway.C:469
 GridRailway.C:470
 GridRailway.C:471
 GridRailway.C:472
 GridRailway.C:473
 GridRailway.C:474
 GridRailway.C:475
 GridRailway.C:476
 GridRailway.C:477
 GridRailway.C:478
 GridRailway.C:479
 GridRailway.C:480
 GridRailway.C:481
 GridRailway.C:482
 GridRailway.C:483
 GridRailway.C:484
 GridRailway.C:485
 GridRailway.C:486
 GridRailway.C:487
 GridRailway.C:488
 GridRailway.C:489
 GridRailway.C:490
 GridRailway.C:491
 GridRailway.C:492
 GridRailway.C:493
 GridRailway.C:494
 GridRailway.C:495
 GridRailway.C:496
 GridRailway.C:497
 GridRailway.C:498
 GridRailway.C:499
 GridRailway.C:500
 GridRailway.C:501
 GridRailway.C:502
 GridRailway.C:503
 GridRailway.C:504
 GridRailway.C:505
 GridRailway.C:506
 GridRailway.C:507
 GridRailway.C:508
 GridRailway.C:509
 GridRailway.C:510
 GridRailway.C:511
 GridRailway.C:512
 GridRailway.C:513
 GridRailway.C:514
 GridRailway.C:515
 GridRailway.C:516
 GridRailway.C:517
 GridRailway.C:518
 GridRailway.C:519
 GridRailway.C:520
 GridRailway.C:521
 GridRailway.C:522
 GridRailway.C:523
 GridRailway.C:524
 GridRailway.C:525
 GridRailway.C:526
 GridRailway.C:527
 GridRailway.C:528
 GridRailway.C:529
 GridRailway.C:530
 GridRailway.C:531
 GridRailway.C:532
 GridRailway.C:533
 GridRailway.C:534
 GridRailway.C:535
 GridRailway.C:536
 GridRailway.C:537
 GridRailway.C:538
 GridRailway.C:539
 GridRailway.C:540
 GridRailway.C:541
 GridRailway.C:542
 GridRailway.C:543
 GridRailway.C:544
 GridRailway.C:545
 GridRailway.C:546
 GridRailway.C:547
 GridRailway.C:548
 GridRailway.C:549
 GridRailway.C:550
 GridRailway.C:551
 GridRailway.C:552
 GridRailway.C:553
 GridRailway.C:554
 GridRailway.C:555
 GridRailway.C:556
 GridRailway.C:557
 GridRailway.C:558
 GridRailway.C:559
 GridRailway.C:560
 GridRailway.C:561
 GridRailway.C:562
 GridRailway.C:563
 GridRailway.C:564
 GridRailway.C:565
 GridRailway.C:566
 GridRailway.C:567
 GridRailway.C:568
 GridRailway.C:569
 GridRailway.C:570
 GridRailway.C:571
 GridRailway.C:572
 GridRailway.C:573
 GridRailway.C:574
 GridRailway.C:575
 GridRailway.C:576
 GridRailway.C:577
 GridRailway.C:578
 GridRailway.C:579
 GridRailway.C:580
 GridRailway.C:581
 GridRailway.C:582
 GridRailway.C:583
 GridRailway.C:584
 GridRailway.C:585
 GridRailway.C:586
 GridRailway.C:587
 GridRailway.C:588
 GridRailway.C:589
 GridRailway.C:590
 GridRailway.C:591
 GridRailway.C:592
 GridRailway.C:593
 GridRailway.C:594
 GridRailway.C:595
 GridRailway.C:596
 GridRailway.C:597
 GridRailway.C:598
 GridRailway.C:599
 GridRailway.C:600
 GridRailway.C:601
 GridRailway.C:602
 GridRailway.C:603
 GridRailway.C:604
 GridRailway.C:605
 GridRailway.C:606
 GridRailway.C:607
 GridRailway.C:608
 GridRailway.C:609
 GridRailway.C:610
 GridRailway.C:611
 GridRailway.C:612
 GridRailway.C:613
 GridRailway.C:614
 GridRailway.C:615
 GridRailway.C:616
 GridRailway.C:617
 GridRailway.C:618
 GridRailway.C:619
 GridRailway.C:620
 GridRailway.C:621
 GridRailway.C:622
 GridRailway.C:623
 GridRailway.C:624
 GridRailway.C:625
 GridRailway.C:626
 GridRailway.C:627
 GridRailway.C:628
 GridRailway.C:629
 GridRailway.C:630
 GridRailway.C:631
 GridRailway.C:632
 GridRailway.C:633
 GridRailway.C:634
 GridRailway.C:635
 GridRailway.C:636
 GridRailway.C:637
 GridRailway.C:638
 GridRailway.C:639
 GridRailway.C:640
 GridRailway.C:641
 GridRailway.C:642
 GridRailway.C:643
 GridRailway.C:644
 GridRailway.C:645
 GridRailway.C:646
 GridRailway.C:647
 GridRailway.C:648
 GridRailway.C:649
 GridRailway.C:650
 GridRailway.C:651
 GridRailway.C:652
 GridRailway.C:653
 GridRailway.C:654
 GridRailway.C:655
 GridRailway.C:656
 GridRailway.C:657
 GridRailway.C:658
 GridRailway.C:659
 GridRailway.C:660
 GridRailway.C:661
 GridRailway.C:662
 GridRailway.C:663
 GridRailway.C:664
 GridRailway.C:665
 GridRailway.C:666
 GridRailway.C:667
 GridRailway.C:668
 GridRailway.C:669
 GridRailway.C:670
 GridRailway.C:671
 GridRailway.C:672
 GridRailway.C:673
 GridRailway.C:674
 GridRailway.C:675
 GridRailway.C:676
 GridRailway.C:677
 GridRailway.C:678
 GridRailway.C:679
 GridRailway.C:680
 GridRailway.C:681
 GridRailway.C:682
 GridRailway.C:683
 GridRailway.C:684
 GridRailway.C:685
 GridRailway.C:686
 GridRailway.C:687
 GridRailway.C:688
 GridRailway.C:689
 GridRailway.C:690
 GridRailway.C:691
 GridRailway.C:692
 GridRailway.C:693
 GridRailway.C:694
 GridRailway.C:695
 GridRailway.C:696
 GridRailway.C:697
 GridRailway.C:698
 GridRailway.C:699