]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/trains/TrainSetup.C
This commit has two major parts:
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / trains / TrainSetup.C
1 /**
2  * @defgroup pwglf_forward_trains Trains
3  * 
4  * Train specifications 
5  *
6  */
7 /**
8  * @file   TrainSetup.C
9  * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
10  * @date   Tue Oct 16 17:56:57 2012
11  * 
12  * @brief  Base classs for train specifications 
13  * 
14  * @ingroup pwglf_forward_trains
15  */
16 #ifndef TRAINSETUP_C
17 #define TRAINSETUP_C
18 #ifndef __CINT__
19 # include "Helper.C"
20 # include "Option.C"
21 # include <TDatime.h>
22 # include <TUrl.h>
23 # include <TString.h>
24 # include <TApplication.h>
25 # include <TStopwatch.h>
26 # include <AliAnalysisManager.h>
27 # include <AliVEventHandler.h>
28 # include <AliPhysicsSelection.h>
29 # include <AliPhysicsSelectionTask.h>
30 # include <AliCentralitySelectionTask.h>
31 # include <AliESDInputHandler.h>
32 # include <AliAODInputHandler.h>
33 # include <AliAODHandler.h>
34 # include <AliMCEventHandler.h>
35 # include <ctime>
36 #else 
37 struct Helper;
38 struct OptionList;
39 class TDatime;
40 class TUrl;
41 class TString;
42 class TStopwatch;
43 class AliVEventHandler;
44 class AliAnalysisManager;
45 class AliInputEventHandler;
46 #endif
47
48 //====================================================================
49 /** 
50  * Generic set-up of an analysis train 
51  *
52  * See also @ref train_setup_doc
53  *
54  * @ingroup pwglf_forward_trains
55  * 
56  */
57 struct TrainSetup
58 {
59   /** 
60    * Constructor 
61    * 
62    * @param name Name of the train
63    */
64   TrainSetup(const TString& name)
65     : fName(name), 
66       fEscapedName(name),
67       fDatimeString(""),
68       fOptions(),
69       fHelper(0)
70   {
71     fOptions.Add("help", "Show help", false);
72     fOptions.Add("date", "YYYY-MM-DD HH:MM", "Set date", "now");
73     fOptions.Add("bare-ps", "Use bare physics selection w/o task", false);
74     fOptions.Add("verbose", "LEVEL", "Set verbosity level", 0);
75     fOptions.Add("url", "URL", "Job location & input URL", "");
76     fOptions.Add("overwrite", "Allow overwrite", false);
77     fOptions.Add("events", "N", "Number of events to analyse", -1);
78     fOptions.Add("type", "ESD|AOD|USER", "Input data stype", "");
79     fOptions.Add("setup", "Only do the setup", false);
80     fOptions.Add("branches", "Load only requested branches", false);
81     fDatimeString = "";
82     fEscapedName  = EscapeName(fName, fDatimeString);
83   }
84   /** 
85    * Copy constructor 
86    * 
87    * @param o Object to copy from 
88    */
89   TrainSetup(const TrainSetup& o) 
90     : fName(o.fName), 
91       fEscapedName(o.fEscapedName), 
92       fDatimeString(o.fDatimeString),
93       fOptions(o.fOptions), 
94       fHelper(o.fHelper)
95   {}
96   /** 
97    * Assignment operator
98    * 
99    * @param o Object to assign from 
100    * 
101    * @return Reference to this object
102    */
103   TrainSetup& operator=(const TrainSetup& o) 
104   {
105     if (&o == this) return *this;
106     fName         = o.fName;
107     fEscapedName  = o.fEscapedName;
108     fDatimeString = o.fDatimeString;
109     fOptions      = o.fOptions;
110     fHelper       = o.fHelper;
111     return *this;
112   }
113   
114   /** 
115    * Destructor
116    */
117   virtual ~TrainSetup() {}
118   /* @} */
119   //__________________________________________________________________
120   /** 
121    * @{ 
122    * @name Execution 
123    */
124   /** 
125    * Initialize 
126    * 
127    * @return true on success 
128    */
129   Bool_t Init()
130   {
131     // --- Create the helper -----------------------------------------
132     TString  url     = fOptions.Get("url");
133     Int_t    verbose = fOptions.AsInt("verbose");
134
135     fHelper = Helper::Create(url.Data(), verbose);
136     if (!fHelper) { 
137       Error("Init", "Failed to make the worker for URL %s", url.Data());
138       return false;
139     }
140
141     // --- Check the type, if possible -------------------------------
142     UShort_t type    = fHelper->InputType();
143     Bool_t   mc      = fHelper->IsMC();
144     if (fOptions.Has("type")) { 
145       const TString& it = fOptions.Get("type");
146       if      (it.EqualTo("ESD",TString::kIgnoreCase)) type = Helper::kESD;
147       else if (it.EqualTo("AOD",TString::kIgnoreCase)) type = Helper::kAOD;
148       else if (it.EqualTo("user",TString::kIgnoreCase)) 
149         type = Helper::kUser;
150     }
151
152     // --- Rewrite the escpaed name ----------------------------------
153     if (fOptions.Has("date")) { 
154       fDatimeString = fOptions.Get("date");
155       fEscapedName  = EscapeName(fName, fDatimeString);
156     }
157     
158     // --- Get current directory and set-up sub-directory ------------
159     TString cwd = gSystem->WorkingDirectory();
160     if (!SetupWorkingDirectory()) return false;
161
162     // --- Do initial helper setup -----------------------------------
163     if (!fHelper->PreSetup()) return false;
164
165     // --- Load ROOT libraries ---------------------------------------
166     if (!fHelper->LoadROOT()) return false;
167     
168     // --- Load AliROOT libraries ------------------------------------
169     if (!fHelper->LoadAliROOT()) return false;
170
171     // --- Create analysis manager -----------------------------------
172     AliAnalysisManager *mgr  = CreateAnalysisManager(fEscapedName);
173
174     // In test mode, collect system information on every event 
175     // if (oper == kTest)  mgr->SetNSysInfo(1); 
176     if (verbose  >  0)      mgr->SetDebugLevel(verbose);
177     mgr->SetAutoBranchLoading(!fOptions.Has("branches"));
178     if (fHelper->Mode() == Helper::kLocal) 
179       mgr->SetUseProgressBar(kTRUE, 100);
180    
181     // --- ESD input handler ------------------------------------------
182     AliVEventHandler*  inputHandler = CreateInputHandler(type);
183     if (inputHandler) mgr->SetInputEventHandler(inputHandler);
184     
185     // --- Monte-Carlo ------------------------------------------------
186     AliVEventHandler*  mcHandler = CreateMCHandler(type,mc);
187     if (mcHandler) mgr->SetMCtruthEventHandler(mcHandler);
188     
189     // --- AOD output handler -----------------------------------------
190     AliVEventHandler*  outputHandler = CreateOutputHandler(type);
191     if (outputHandler) mgr->SetOutputEventHandler(outputHandler);
192
193     // --- Include analysis macro path in search path ----------------
194     gROOT->SetMacroPath(Form("%s:%s:$ALICE_ROOT/ANALYSIS/macros",
195                              cwd.Data(), gROOT->GetMacroPath()));
196
197     // --- Physics selction - only for ESD ---------------------------
198     if (type == Helper::kESD) CreatePhysicsSelection(mc, mgr);
199     
200     // --- Create centrality task ------------------------------------
201     CreateCentralitySelection(mc, mgr);
202
203     // --- Create tasks ----------------------------------------------
204     CreateTasks(mgr);
205
206     // --- Post set-up initialization of helper ----------------------
207     if (!fHelper->PostSetup()) return false;
208
209     // --- Set debug level on defined tasks --------------------------
210     if (verbose > 0) {
211       TIter next(mgr->GetTasks());
212       AliAnalysisTask* sub = 0;
213       while ((sub = static_cast<AliAnalysisTask*>(next()))) { 
214         AliAnalysisTaskSE* se = dynamic_cast<AliAnalysisTaskSE*>(sub);
215         if (!se) continue;
216         se->SetDebugLevel(verbose);
217       }
218     }
219
220     // --- Print this setup ------------------------------------------
221     Print();
222
223     // --- Initialise the train --------------------------------------
224     if (!mgr->InitAnalysis())  {
225       gSystem->ChangeDirectory(cwd.Data());
226       Error("Init","Failed to initialise train");
227       return false;
228     }
229
230     // --- Enable progress bar ---------------------------------------
231     if (fHelper->Mode() != Helper::kGrid) 
232       mgr->SetUseProgressBar(true, 100);
233
234     // --- Save setup to disk ----------------------------------------
235     SaveSetup(true);
236
237     // --- Some information ------------------------------------------
238     mgr->PrintStatus();
239     if (fHelper->Mode() != Helper::kLocal) {
240       TIter next(mgr->GetTasks());
241       AliAnalysisTask* sub = 0;
242       while ((sub = static_cast<AliAnalysisTask*>(next()))) { 
243         sub->Print();
244       }
245     }
246     return true;
247   }
248   /** 
249    * Print timer information
250    * 
251    * @param timer The timer
252    * @param where Where this was called from 
253    */
254   void PrintTimer(TStopwatch& timer, const char* where)
255   {
256     timer.Stop();
257     Double_t t = timer.RealTime();
258     Int_t    h = Int_t(t / 3600); t -= h * 3600;
259     Int_t    m = Int_t(t /   60); t -= m *   60;
260     if (t < 0) t = 0;
261     Info(where, "took %4d:%02d:%06.3f", h, m, t);
262   }
263   /** 
264    * Run this train 
265    * 
266    * @return true on success 
267    */    
268   Bool_t Run()
269   {
270     TString cwd = gSystem->WorkingDirectory();
271     Bool_t status = false;
272     TStopwatch timer;
273     timer.Start();
274     try {
275       if (!Init()) throw TString("Failed to intialize the train");
276       PrintTimer(timer, "Initialization");
277       timer.Continue();
278       
279       // Check if we're asked to only do the setup 
280       if (fOptions.Has("setup")) {
281         status = true;
282         throw TString("Only did setup, no running");
283       }
284
285       // if (r) SaveSetup(*r, nEvents, asShell);
286       
287       Long64_t nEvents = fOptions.AsLong("events", -1);
288       Long64_t ret     = fHelper->Run(nEvents);
289       PrintTimer(timer, "Processing");
290       timer.Continue();
291       
292       // Make sure we go back 
293       gSystem->ChangeDirectory(cwd.Data());
294       
295       // Return. 
296       if (ret < 0) throw TString("Analysis failed");
297
298       status = true;
299     }
300     catch (TString& e) {
301       if (status) Warning("Run", "%s", e.Data());
302       else        Error("Run", "%s", e.Data());
303     }
304     if (fOptions.Has("date")) {
305       TString tmp     = "";
306       TString escaped = EscapeName(fName, tmp);
307       gSystem->Exec(Form("rm -f last_%s", escaped.Data()));
308       gSystem->Exec(Form("ln -sf %s last_%s", 
309                          fEscapedName.Data(), escaped.Data()));
310     }
311     PrintTimer(timer, "Finish");
312     timer.Continue();
313     return status;
314   }
315   /** 
316    * Get the options 
317    * 
318    * 
319    * @return Reference ot the options 
320    */
321   OptionList& Options() { return fOptions; }
322   /** 
323    * Print information to standard output 
324    * 
325    */
326   void Print(Option_t* ="") const
327   {
328     std::cout << "Train: " << fName << " (" << fEscapedName << ")" 
329               << std::endl;
330     fOptions.Show(std::cout);
331     if (fHelper) fHelper->Print();
332   }
333   /** 
334    * Show the help 
335    * 
336    * @param o      Output stream
337    * @param asProg If true, output as program options 
338    * 
339    * @return 
340    */
341   Bool_t Help(std::ostream& o=std::cout, bool asProg=false)
342   {
343     if (!fOptions.Has("help")) return true;
344
345     if (!asProg) 
346       o << "Usage: RunTrain(NAME, CLASS, OPTIONS)";
347     
348     o << "\n\nTrain Options:\n";
349     fOptions.Help(o, asProg ? "  --" : "  ");
350     o << "\n";
351
352     if (!fHelper && fOptions.Has("url")) {
353       TString url = fOptions.Get("url");
354       fHelper = Helper::Create(url.Data());
355     }
356     if (fHelper) { 
357       o << fHelper->Desc() << " URL form:\n\n"
358         << "    " << fHelper->UrlHelp() << "\n\n"
359         << "Options:\n";
360       fHelper->Options().Help(o, "    ");
361       o << "\n";
362     }
363     else { 
364       o << "Possible URL forms:\n\n";
365       Helper::ShowUrlHelp("LocalHelper");
366       Helper::ShowUrlHelp("ProofHelper");
367       Helper::ShowUrlHelp("LiteHelper");
368       Helper::ShowUrlHelp("AAFHelper");
369       Helper::ShowUrlHelp("AAFPluginHelper");
370       Helper::ShowUrlHelp("GridHelper");
371       o << "\n";
372     }
373     return false;
374   }
375   /** 
376    * Run train.  This will AcLic compile the setup script, create
377    * an object of that type with the given name, and then pass the 
378    * options to it.  Then, it will run the setup.
379    * 
380    * @param name   Train name 
381    * @param cls    Class name 
382    * @param opts   Comma seperated list of options
383    * @param asProg Run as program 
384    * @param spawn  Spawn ROOT shell after execution 
385    * 
386    * @return true on success
387    */
388   static Bool_t Main(const TString& name, const TString& cls, 
389                      const TCollection* opts, 
390                      Bool_t asProg=true,
391                      Bool_t spawn=false)
392   {
393     Bool_t ret = false;
394     try {
395       if (cls.IsNull()) 
396         throw TString("No class name specified");
397       if (name.IsNull()) 
398         throw TString("No train name specified");
399
400       gROOT->ProcessLine("gSystem->RedirectOutput(\"build.log\",\"w\");");
401       Int_t error = 0;
402       Int_t r1 = gROOT->LoadMacro(Form("%s.C+g", cls.Data()), &error);
403       gROOT->ProcessLine("gSystem->RedirectOutput(0);");
404       if (r1 < 0 || error) 
405         throw TString::Format("Failed to load setup %s: %d - see build.log", 
406                               cls.Data(), error);
407
408       // Make our object using the interpreter 
409       TString create = TString::Format("new %s(\"%s\")", 
410                                        cls.Data(), name.Data());
411       gROOT->ProcessLine("gSystem->RedirectOutput(\"build.log\",\"a\");");
412       Long_t retP = gROOT->ProcessLine(create, &error);
413       gROOT->ProcessLine("gSystem->RedirectOutput(0);");
414       if (!retP || error) 
415         throw TString::Format("Failed to make object of class %s "
416                               "(see build.log): 0x%08lx/%d\n\t%s", 
417                               cls.Data(), retP, error, create.Data());
418
419       TrainSetup* train = reinterpret_cast<TrainSetup*>(retP);
420     
421       // Now parse the options 
422       if (!train->Options().Parse(opts)) 
423         throw TString("Failed to parse options");
424
425       // Info("", "URL=%s", train->Options().Get("url").Data());
426
427       // Check if we got a help request
428       if (train->Options().Has("help")) { 
429         train->Help(std::cout, asProg);
430         ret = true;
431         throw TString("");
432       }
433
434       // return train->Init();
435       ret = train->Run();
436     }
437     catch (TString& e) { 
438       if (!e.IsNull()) Error("Main", "%s", e.Data());
439     }
440     // Info("Main", "End of main loop (app=%p, asProg=%s, spawn=%s)",
441     //   gApplication, asProg ? "true" : "false", spawn ? "true" : "false");
442     if (gApplication && asProg) {
443       if (!spawn) {
444         gSystem->Sleep(3);
445         gApplication->Terminate(ret ? 0 : 1);
446       }
447     }
448     return ret;
449   }
450 protected:
451   //__________________________________________________________________
452   /** 
453    * @{ 
454    * @name Overloadable behaviour 
455    */
456   //------------------------------------------------------------------
457   /** 
458    * Create the analysis manager 
459    * 
460    * @param name Name of the analysis 
461    * 
462    * @return Created analysis manager 
463    */
464   virtual AliAnalysisManager* CreateAnalysisManager(const char* name)
465   {
466     return new AliAnalysisManager(name,"Analysis Train");
467   }
468   //------------------------------------------------------------------
469   /** 
470    * Create input handler 
471    * 
472    * @param type 
473    * 
474    * @return 
475    */
476   virtual AliVEventHandler* CreateInputHandler(UShort_t type)
477   {
478     switch (type) {
479     case Helper::kESD:  return new AliESDInputHandler(); 
480     case Helper::kAOD:  return new AliAODInputHandler(); 
481     case Helper::kUser: return 0;
482     }
483     return 0;
484   }
485   //------------------------------------------------------------------
486   /** 
487    * Create MC input handler 
488    * 
489    * @param mc    Assume monte-carlo input 
490    * 
491    * @return 
492    */
493   virtual AliVEventHandler* CreateMCHandler(UShort_t /*type*/, bool mc)
494   {
495     if (!mc) return 0;
496     AliMCEventHandler* mcHandler = new AliMCEventHandler();
497     mcHandler->SetReadTR(true); 
498     return mcHandler;
499   }
500   //------------------------------------------------------------------
501   /** 
502    * Create output event handler 
503    * 
504    * @param type 
505    * 
506    * @return 
507    */
508   virtual AliVEventHandler* CreateOutputHandler(UShort_t type)
509   {
510     AliAODHandler* ret = new AliAODHandler();
511     switch (type) { 
512     case Helper::kESD: 
513       ret->SetOutputFileName("AliAOD.root");
514       break;
515     case Helper::kAOD: 
516       ret->SetOutputFileName("AliAOD.pass2.root");
517       break;
518     case Helper::kUser: 
519       break;
520     }
521     
522     return ret;
523   }
524   //------------------------------------------------------------------
525   /** 
526    * Create physics selection, and add to manager
527    * 
528    * @param mc Whether this is for MC 
529    * @param mgr Manager
530    */
531   virtual void CreatePhysicsSelection(Bool_t mc, AliAnalysisManager* mgr)
532   {
533     if (fOptions.Has("bare-ps")) {
534       AliInputEventHandler* input = 
535         dynamic_cast<AliInputEventHandler*> (mgr->GetInputEventHandler());
536       if (!input) return;
537
538       AliPhysicsSelection* ps = new AliPhysicsSelection();
539       if (mc) ps->SetAnalyzeMC();
540
541       input->SetEventSelection(ps);
542
543       return;
544     }
545     gROOT->Macro(Form("AddTaskPhysicsSelection.C(%d)", mc));
546     mgr->RegisterExtraFile("event_stat.root");
547     mgr->AddStatisticsTask(AliVEvent::kAny);
548   }
549   //------------------------------------------------------------------
550   /** 
551    * Create centrality selection, and add to manager
552    * 
553    * @param mc Whether this is for MC 
554    * @param mgr Manager
555    */
556   virtual void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
557   {
558     gROOT->Macro("AddTaskCentrality.C(true)");
559     const char* name = "CentralitySelection";
560     AliCentralitySelectionTask* ctask = 
561       dynamic_cast<AliCentralitySelectionTask*>(mgr->GetTask(name));
562     if (!ctask) return;
563     if (mc) ctask->SetMCInput();
564   }
565   //------------------------------------------------------------------
566   /** 
567    * Create analysis tasks.  Must be overloaded by sub-class
568    * 
569    * @param mgr  Manager
570    */
571   virtual void CreateTasks(AliAnalysisManager* mgr)=0;
572   /** 
573    * Add a task using a script and possibly some arguments 
574    * 
575    * @param macro Script to execute 
576    * @param args  Optional arguments to the script 
577    * 
578    * @return Created task or null
579    */
580   virtual AliAnalysisTask* AddTask(const TString& macro, 
581                                    const TString& args)
582   {
583     TString p = gSystem->Which(gROOT->GetMacroPath(), macro.Data());
584     if (p.IsNull()) { 
585       Error("AddTask", "Macro %s not found", macro.Data());
586       return 0;
587     }
588     TString cmd(p);
589     if (!args.IsNull()) 
590       cmd.Append(TString::Format("(%s)", args.Data()));
591     
592     Int_t err;
593     Long_t ret = gROOT->Macro(cmd.Data(), &err, false);
594     if (!ret) { 
595       Error("AddTask", "Failed to execute %s", cmd.Data());
596       return 0;
597     }
598     return reinterpret_cast<AliAnalysisTask*>(ret);
599   }
600   /** 
601    * Add a task to the train with no arguments passed to the script 
602    * 
603    * @param macro The <b>AddTask</b> macro. 
604    * 
605    * @return The added task, if any
606    */
607   virtual AliAnalysisTask* AddTask(const TString& macro)
608   {
609     TString args;
610     return AddTask(macro, args);
611   }
612   /** 
613    * Add a single event analysis task to the train, passing the
614    * specified arguments to the macro.
615    * 
616    * @param macro The <b>AddTask</b> macro 
617    * @param args  Arguments to pass the macro 
618    * 
619    * @return The added task, if any 
620    */
621   virtual AliAnalysisTaskSE* AddSETask(const TString& macro, 
622                                        const TString& args)
623   {
624     return dynamic_cast<AliAnalysisTaskSE*>(AddTask(macro, args));
625   }
626   /** 
627    * Add a single event task to the train with no arguments passed to
628    * the script
629    * 
630    * @param macro The <b>AddTask</b> macro. 
631    * 
632    * @return The added task, if any
633    */
634   virtual AliAnalysisTaskSE* AddSETask(const TString& macro)
635   {
636     TString args;
637     return AddSETask(macro, args);
638   }
639
640   /** 
641    * Set the name of the train - should be name of the class.  Must be
642    * overloaded.
643    * 
644    * @return Class name as a constant C string 
645    */
646   virtual const Char_t* ClassName() const = 0;
647   /* @} */
648   //__________________________________________________________________
649   /** 
650    * @{ 
651    * @name Utility functions 
652    */
653   /** 
654    * Escape bad elements of the name 
655    * 
656    * @param name      Name to escape 
657    * @param datimeStr Date and Time string 
658    * 
659    * @return escaped name 
660    */  
661   static TString EscapeName(const char* name, TString& datimeStr)
662   {
663     TString escaped = name;
664     char  c[] = { ' ', '/', '@', 0 };
665     char* p   = c;
666     while (*p) { 
667       char tmp[] = { *p, '\0' };
668       escaped.ReplaceAll(tmp, "_");
669       p++;
670     }
671     if (!datimeStr.IsNull()) {
672       TDatime datime;
673       if (datimeStr.EqualTo("now", TString::kIgnoreCase)) 
674         datime.Set();
675       else {
676         // Try various formats 
677         struct tm t;
678         const char* formats[] = { "%Ec", // Locale 
679                                   "%c", // Locale 
680                                   "%Ex EX", // Locale 
681                                   "%x %X", // Locale 
682                                   "%Y%m%d_%H%M", // YYYYMMDD_HHMM
683                                   "%F %R", // ISO standard, no seconds 
684                                   0 };
685         const char** f = formats;
686         Bool_t found = false;
687         while (*f && !found) { 
688           // Reset needed fields 
689           t.tm_year  = 0;
690           t.tm_mon   = 0;
691           t.tm_mday  = 0;
692           t.tm_hour  = 0;
693           t.tm_min   = 0;
694           // Stop processing on first match 
695           if (strptime(datimeStr.Data(), *f, &t) != 0) found = true;
696           f++;
697         }
698         if (found) {
699           t.tm_mon += 1; // Return 0-based month
700           datime.Set(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, 0); 
701         }
702       }
703       if (datime.GetYear() <= 1995 ||
704           datime.GetMonth() == 0 || 
705           datime.GetDay() == 0) return escaped;
706       datimeStr = Form("%04d%02d%02d_%02d%02d", 
707                        datime.GetYear(), 
708                        datime.GetMonth(), 
709                        datime.GetDay(), 
710                        datime.GetHour(), 
711                        datime.GetMinute());
712       escaped.Append(Form("_%s", datimeStr.Data()));
713     }
714     return escaped;
715   }    
716   /** 
717    * Make our working directory if so requested 
718    * 
719    * @return true on success
720    */
721   Bool_t SetupWorkingDirectory()
722   {
723     // Get the name of the target directory 
724     TString& nam = fEscapedName;
725
726     // Check if the directory exists already 
727     Bool_t exists = gSystem->AccessPathName(nam.Data()) == 0;
728     if (fHelper->Operation() == Helper::kTerminate && !exists) {
729       Error("SetupWorkingDirectory", "File/directory %s does not exists", 
730             nam.Data());
731       return false;
732     }
733
734     Bool_t overwrite = fOptions.Has("overwrite");
735     // If we're not allowed to overwrite, then complain
736     if (!overwrite && exists) {
737       Error("SetupWorkingDirectory", "File/directory %s already exists", 
738             nam.Data());
739       return false;
740     }
741
742     // Make the target directory if it doesn't exists 
743     if (!exists) {
744       if (gSystem->MakeDirectory(nam.Data())) {
745         Error("SetupWorkingDirectory", "Failed to make directory '%s'", 
746               nam.Data());
747         return false;
748       }
749     }
750       
751     // Change directory to target directory 
752     if (!gSystem->ChangeDirectory(nam.Data())) { 
753       Error("SetupWorkingDirectory", "Failed to change directory to %s", 
754             nam.Data());
755       return false;
756     }
757     // Info("SetupWorkingDirectory", "Made subdirectory %s, and cd'ed there", 
758     //      nam.Data());
759     return true;
760   }
761   /** 
762    * Save the setup as a ROOT script and possibly also a shell script
763    * 
764    * @param asShellScript If true, also save as shell script
765    */
766   virtual void SaveSetup(Bool_t asShellScript)
767   {
768     OptionList tmp(fOptions);
769     const OptionList* uopts = (fHelper ? &fHelper->Options() : 0);
770     if (tmp.Find("overwrite")) tmp.Set("overwrite");
771     if (tmp.Find("date") && fEscapedName.Length() > fName.Length()+1) {
772       Int_t n = fName.Length()+1;
773       tmp.Set("date", fEscapedName(n, fEscapedName.Length()-n));
774     }
775     if (asShellScript) 
776       SaveSetupShell("rerun", ClassName(), fName, tmp, uopts);
777     SaveSetupROOT("ReRun", ClassName(), fName, tmp, uopts);
778     if (fHelper) fHelper->AuxSave(fEscapedName, asShellScript);
779   }
780   /** 
781    * Save a setup as a shell script 
782    * 
783    * @param out   Output name of shell script 
784    * @param cls   Class of the train 
785    * @param name  Name of the train
786    * @param opts  Option list
787    * @param uopts Url options 
788    */
789   static void SaveSetupShell(const TString& out, const TString& cls,
790                              const TString& name, const OptionList& opts,
791                              const OptionList* uopts)
792   {
793     std::ofstream o(Form("%s.sh", out.Data()));
794     o << "#!/bin/bash\n\n"
795       << "class=\"" << cls << "\"\n"
796       << "name=\"" << name << "\"\n\n"
797       << "# Available options\n"
798       << "# \n";
799     opts.Help(o, "#    --");
800     if (uopts) {
801       o << "#\n"
802         << "# Available URI options\n"
803         << "# \n";
804       uopts->Help(o, "#      ");
805     }
806     o << "#\n"
807       << "opts=(--class=$class \\\n"
808       << "  --name=$name";
809     opts.Store(o, " \\\n  --", "", true);
810     o << ")\n\n"
811       << "echo \"Running runTrain ${opts[@]} $@\"\n"
812       << "runTrain \"${opts[@]}\" $@\n\n"
813       << "# EOF" << std::endl;
814     o.close();
815     gSystem->Exec(Form("chmod a+x %s.sh", out.Data()));
816   }
817   /** 
818    * Save a setup as a ROOT script 
819    * 
820    * @param out   Output name of shell script 
821    * @param cls   Class of the train 
822    * @param name  Name of the train
823    * @param opts  Option list
824    * @param uopts Url options 
825    */
826   static void SaveSetupROOT(const TString& out, const TString& cls,
827                             const TString& name, const OptionList& opts,
828                             const OptionList* uopts)
829   {
830     OptionList tmp(opts);
831     tmp.Remove("url");
832
833     std::ofstream o(Form("%s.C", out.Data()));
834     o << "// Available options:\n"
835       << "// \n";
836     tmp.Help(o, "//     ");
837     if (uopts) {
838       o << "// \n"
839         << "// Available URI options\n";
840       uopts->Help(o, "//      ");
841     }
842     o << "//\n"
843       << "Bool_t " << out << "()\n" 
844       << "{\n"
845       << "  TString name(\"" << name << "\");\n"
846       << "  TString cls(\"" << cls << "\");\n"
847       << "  TUrl    uri(\"" << opts.Get("url") << "\");\n"
848       << "  \n"
849       << "  TString opts(";
850     tmp.Store(o, "\"", ",\"\n               ", false);
851     o << ");\n\n"
852       << "  TString path(";
853     TString     path(gROOT->GetMacroPath());
854     TObjArray*  elements = path.Tokenize(":");
855     TObjString* element = 0;
856     TIter       next(elements);
857     while ((element = static_cast<TObjString*>(next()))) {
858       if (element->String().IsNull()) continue;
859       o << "\n               \"" << element->GetName() << ":\"";
860     }
861     elements->Delete();
862     o << ");\n"
863       << "  path.Append(\"$ALICE_ROOT/PWGLF/FORWARD/trains\");\n"
864       << "  gROOT->SetMacroPath(path);\n\n"
865       << "  gROOT->LoadMacro(\"RunTrain.C\");\n\n"
866       << "  return RunTrain(name, cls, uri, opts);\n"
867       << "}\n" 
868       << "//\n"
869       << "// EOF\n" 
870       << "//" << std::endl;
871     o.close();
872   }    
873   /* @} */
874   TString      fName;
875   TString      fEscapedName;
876   TString      fDatimeString;
877   OptionList   fOptions;
878   Helper*      fHelper;
879 };
880 #endif