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