]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/analysis2/trains/TrainSetup.C
Cleaned up error handling when missing corrections. Previously
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / analysis2 / trains / TrainSetup.C
1 /**
2  * @defgroup pwglf_forward_trains Trains
3  * 
4  * Train specifications 
5  *
6  * @ingroup pwglf_forward
7  */
8 /**
9  * @file   TrainSetup.C
10  * @author Christian Holm Christensen <cholm@dalsgaard.hehi.nbi.dk>
11  * @date   Wed Mar 23 12:12:00 2011
12  * 
13  * @brief  
14  * 
15  * @ingroup pwglf_forward_trains
16  * 
17  */
18
19 #ifndef __CINT__
20 #include <fstream>
21 #include <iostream>
22 #include <cstdlib>
23
24 #include <TAlienCollection.h>
25 #include <TArrayI.h>
26 #include <TChain.h>
27 #include <TDatime.h>
28 #include <TEnv.h>
29 #include <TFile.h>
30 #include <TGrid.h>
31 #include <TList.h>
32 #include <TObjString.h>
33 #include <TProof.h>
34 #include <TString.h>
35 #include <TSystem.h>
36 #include <TSystemDirectory.h>
37 #include <TSystemFile.h>
38 #include <TROOT.h>
39
40 #include <AliAODHandler.h>
41 #include <AliAODInputHandler.h>
42 #include <AliAnalysisDataContainer.h>
43 #include <AliAnalysisManager.h>
44 #include <AliAnalysisAlien.h>
45 #include <AliESDInputHandler.h>
46 #include <AliMCEventHandler.h>
47 #include <AliVEventHandler.h>
48 #include <AliPhysicsSelection.h>
49 #include <AliCentralitySelectionTask.h>
50 #else
51 class TArrayI;
52 class TChain;
53 class AliAnalysisManager;
54 class TDatime;
55 class TString;
56 class TSystemDirectory;
57 #endif
58
59
60
61 //====================================================================
62 /** 
63  * Generic set-up of an analysis train using the grid-handler (AliEn plugin). 
64  *
65  * See also @ref train_setup_doc
66  *
67  * @ingroup pwglf_forward_trains
68  * 
69  */
70 struct TrainSetup
71 {
72   // Forward declaration 
73   class Runner;
74   /** 
75    * Data type to process 
76    */
77   enum EType { 
78     /** Event Summary Data */
79     kESD, 
80     /** Analysis Object Data */
81     kAOD,
82     /** User defined */
83     kUser
84   };
85   /**
86    * How to run the analysis
87    * 
88    */
89   enum EMode {
90     /** Locally */ 
91     kLocal = 1, 
92     /** In PROOF(-Lite) cluster */
93     kProof, 
94     /** On the Grid */
95     kGrid 
96   };
97   /**
98    * What stage of the analysis to run 
99    * 
100    */
101   enum EOper { 
102     /** Testing.  Local processing, a single copied from Grid */
103     kTest, 
104     /** Off-line */
105     kOffline, 
106     /** Submit to queue */
107     kSubmit, 
108     /** Merge and terminate */
109     kTerminate, 
110     /** Full run */
111     kFull,
112     /** Only intialize */
113     kInitialize
114   };
115
116
117   //__________________________________________________________________
118   virtual ~TrainSetup() {}
119
120   //__________________________________________________________________
121   /** 
122    * Constructor 
123    * 
124    * @param name         Name of analysis (free-form)
125    */
126   TrainSetup(const char* name)
127     : fName(name),
128       fEscapedName(name),
129       fRootVersion("v5-28-00a"),
130       fAliRootVersion("v4-21-18-AN"),
131       fAliEnAPIVersion("V1.1x"),
132       fProofServer("alicecaf.cern.ch"),
133       fDataDir("/alice/data/2010/LHC10c"),
134       fDataPattern("*"),
135       fDataSet("/COMMON/COMMON/LHC09a4_run8100X#/esdTree"),
136       fXML(""), 
137       fNReplica(4),
138       fAllowOverwrite(kFALSE),
139       fUseGDB(kFALSE), 
140       fMaxSplit(50),
141       fRunNumbers(0),
142       fListOfPARs(),
143       fListOfSources(),
144       fListOfLibraries(),
145       fListOfExtras(),
146       fDatime(1995, 0, 0, 0, 0, 0), 
147       fExecType(kUser), 
148       fExecMode(kLocal), 
149       fExecOper(kFull),
150       fUsePar(false), 
151       fMC(false), 
152       fPerRunMerge(false),
153       fVerbose(0)
154   {
155     fEscapedName = EscapeName(fName, fDatime);
156   }
157   //__________________________________________________________________
158   /** 
159    * @{ 
160    * @name Software environment 
161    */
162   /** 
163    * Set ROOT version to use 
164    * 
165    * @param v Version string of ROOT 
166    */
167   void SetROOTVersion(const char* v)    { fRootVersion = v; }
168   /** 
169    * Set AliROOT version to use 
170    * 
171    * @param v Version string of AliROOT 
172    */
173   void SetAliROOTVersion(const char* v) { fAliRootVersion = v; }
174   /** 
175    * Set the AliEn API version to use 
176    * 
177    * @param v AliEn API version 
178    */
179   void SetAliEnAPIVersion(const char* v) { fAliEnAPIVersion = v; }
180   /** 
181    * Wether to use par files through-out. Mandetory and enforced in
182    * case of a PROOF job,
183    * 
184    * @param usePar If true, use PAR files - even for base libraries 
185    */
186   void SetUsePar(Bool_t usePar) { fUsePar = usePar; }
187   /* @} */
188
189   //__________________________________________________________________
190   /** 
191    * @{ 
192    * @name Input data  
193    */
194   /** 
195    * Set the GRID/Local data dir 
196    * 
197    * @param d Directory with data 
198    */
199   void SetDataDir(const char* d) { fDataDir = d; }
200   /** 
201    * Set the glob pattern to search input files in - Grid only
202    * 
203    * @param pattern Glob pattern
204    */
205   void SetDataPattern(const char* pattern) { fDataPattern = pattern; }
206   /** 
207    * Set the PROOF data set 
208    * 
209    * @param d PROOF registered data set 
210    */
211   void SetDataSet(const char* d) { fDataSet = d; }
212   /** 
213    * Set the XML file to use 
214    * 
215    * @param x XML file 
216    */
217   void SetXML(const char* x) { fXML = x; }
218   /** 
219    * Wether to assume the input comes from MC.  If this is set to
220    * true, and the CreateMCHandler member function isn't overloaded to
221    * return null, then the files @c galice.root, @c Kinematics.root,
222    * and @c TrackRefs.root must be present for each input file (@c
223    * AliESDs.root or @c AliAOD.root)
224    * 
225    * @param isMC If true, assume MC input 
226    */
227   void SetMC(Bool_t isMC) { fMC = isMC; } 
228   /* @} */
229
230   //__________________________________________________________________
231   /** 
232    * @{ 
233    * @name Grid storage and splitting 
234    */
235   /** 
236    * Set how many replicas of the output we want 
237    * 
238    * @param n Number of replicas requested 
239    */
240   void SetNReplica(Int_t n) { fNReplica = n; }
241   /** 
242    * Set the maximum number of files per sub-job.  
243    * 
244    * @param max Maximum number of files per sub-job
245    */  
246   void SetMaxSplit(UShort_t max=50) { fMaxSplit = max; }
247   /* @} */
248
249   //__________________________________________________________________
250   /** 
251    * @{ 
252    * @name Name and local working directory 
253    */
254   /** 
255    * Set whether to allow overwritting existing files/directories 
256    * 
257    * @param allow If true, allow overwritting files/directories
258    */
259   void SetAllowOverwrite(Bool_t allow) { fAllowOverwrite = allow; }
260   /** 
261    * Set the date and time 
262    * 
263    * @param year     Year (>1994) 
264    * @param month    Month
265    * @param day      Day
266    * @param hour     Hour
267    * @param minutes  Minute
268    */
269   void SetDateTime(UShort_t year, UShort_t month, UShort_t day, 
270                    UShort_t hour, UShort_t minutes)
271   {
272     fDatime.Set((year<1995?1995:year), month, day, hour, minutes, 0);
273     fEscapedName = EscapeName(fName, fDatime);
274   }
275   /** 
276    * Set the date and time from a string.
277    * 
278    * @param date Formatted like YYYY/MM/DD HH:MM:SS
279    */
280   void SetDateTime(const TString& date)
281   {
282     if (date.IsNull())
283       fDatime.Set(1985,0,0,0,0,0);
284     else if (date.EqualTo("now", TString::kIgnoreCase)) 
285       fDatime.Set();
286     else 
287       fDatime.Set(date);
288     fEscapedName = EscapeName(fName, fDatime);
289   }
290   /** 
291    * Return the escaped name 
292    * 
293    * @return Escaped name 
294    */
295   const TString& EscapedName() const 
296   {
297     return fEscapedName;
298   }
299   /* @} */
300   //__________________________________________________________________
301   /** 
302    * @{ 
303    * @name Execution parameters 
304    */
305   /** 
306    * Set the PROOF server URL
307    * 
308    * @param s PROOF server URL 
309    */
310   void SetProofServer(const char* s)    { fProofServer = s; }
311   /** 
312    * Set the type of analysis
313    * 
314    * @param type AOD or ESD
315    */
316   void SetType(EType type) { fExecType = type; }
317   /** 
318    * Set the type of analysis
319    * 
320    * @param type AOD or ESD
321    */
322   void SetType(const char* type) { SetType(ParseType(type)); }
323   /** 
324    * Set the execution mode of analysis
325    * 
326    * @param mode LOCAL, PROOF, GRID 
327    */
328   void SetMode(EMode mode) { fExecMode = mode; }
329   /** 
330    * Set the execution mode of analysis
331    * 
332    * @param mode LOCAL, PROOF, GRID 
333    */
334   void SetMode(const char* mode) { SetMode(ParseMode(mode)); }
335   /** 
336    * Set the execution operation of analysis
337    * 
338    * @param oper FULL, TERMINATE, INIT 
339    */
340   void SetOperation(EOper oper) { fExecOper = oper; }
341   /** 
342    * Set the execution operation of analysis
343    * 
344    * @param oper FULL, TERMINATE, INIT 
345    */
346   void SetOperation(const char* oper) { SetOperation(ParseOperation(oper)); }
347   /** 
348    * Use GDB to wrap PROOF slaves 
349    * 
350    * @param use Whether to use GDB or not 
351    */
352   void SetUseGDB(Bool_t use=kTRUE) { fUseGDB = use; }
353   /* @} */
354
355   //__________________________________________________________________
356   /** 
357    * @{ 
358    * @name Stuff to upload 
359    */
360   /** 
361    * Add a source file to be copied and byte compiled on slaves 
362    * 
363    * @param src          Sources 
364    * @param addToExtra   If false, do not copy 
365    */
366   void AddSource(const char* src, bool addToExtra=true) 
367   { 
368     fListOfSources.Add(new TObjString(src)); 
369     if (addToExtra) AddExtraFile(src); // Source code isn't copied!
370   }
371   /** 
372    * Add binary data to be uploaded to slaves 
373    * 
374    * @param lib Name of binary file 
375    */
376   void AddLibrary(const char* lib) { fListOfLibraries.Add(new TObjString(lib));}
377   /** 
378    * Add an extra file to be uploaded to slave 
379    * 
380    * @param file Extra file to be uploaded 
381    */
382   void AddExtraFile(const char* file)
383   {
384     if (!file || file[0] == '\0') return;
385     fListOfExtras.Add(new TObjString(file));
386   }
387   /* @} */
388
389   //__________________________________________________________________
390   /** 
391    * @{ 
392    * @name Run numbers 
393    */
394   /** 
395    * Add a run to be analysed
396    *  
397    * @param run Run number
398    */
399   void AddRun(Int_t run) 
400   {
401     Int_t i = fRunNumbers.fN; fRunNumbers.Set(i+1); fRunNumbers[i] = run;
402   }
403   /** 
404    * Read run numbers from a file 
405    * 
406    * @param filename File name 
407    */
408   void ReadRunNumbers(const char* filename)
409   {
410     std::ifstream file(filename);
411     if (!file) 
412       Fatal("ReadRunNumbers", "Cannot read from %s", filename);
413     
414     while (!file.eof()) { 
415       Int_t run;
416       file >> run;
417       AddRun(run);
418       Char_t c;
419       file >> c;
420       if (file.bad()) break;
421     }
422     file.close();
423   }
424   /** 
425    * Set the runs to read from a string.  The parts should be
426    * delimited by a character in the string @a delim.  If a non-number
427    * part is seen, it is assumed to be the name of a file containing
428    * run numbers.
429    * 
430    * @param runs   String of runs
431    * @param delim  Delimiters 
432    */
433   void SetRuns(const TString& runs, const char* delim=":, \t") 
434   {
435     TIter next(runs.Tokenize(delim));
436     TObjString* os = 0;
437     while ((os = static_cast<TObjString*>(next()))) {
438       TString s(os->String());
439       if (s.IsNull()) continue;
440       if (!s.IsDigit()) ReadRunNumbers(s);
441       else              AddRun(s.Atoi());
442     }
443   }
444   /** 
445    * Whether final merge should be done over all runs (argument true),
446    * or for each run individually. 
447    * 
448    * @param perRun If true, do final merge over all runs 
449    */
450   void SetPerRunMerge(Bool_t perRun) { fPerRunMerge = perRun; }
451   /* @} */
452   //__________________________________________________________________
453   /**
454    * @{ 
455    * @name Execution 
456    */
457   /** 
458    * Initialize the job 
459    * 
460    * @return true on success, false otherwise
461    */
462   Bool_t Init()
463   {
464     if (fExecMode == kProof) fUsePar    = true;
465
466     // Info("Init", "Connecting in mode=%d", mode);
467     if (!Connect()) return false;
468
469     // --- Get current directory and set-up sub-directory ------------
470     TString cwd = gSystem->WorkingDirectory();
471     if (!SetupWorkingDirectory()) return false;
472
473     // --- Load the common libraries ---------------------------------
474     if (!LoadCommonLibraries()) return false;
475     
476     // --- Create analysis manager -----------------------------------
477     AliAnalysisManager *mgr  = new AliAnalysisManager(fName,"Analysis Train");
478
479     // In test mode, collect system information on every event 
480     // if (oper == kTest)  mgr->SetNSysInfo(1); 
481     if (fVerbose  >  0)      mgr->SetDebugLevel(fVerbose);
482     if (fExecMode == kLocal) mgr->SetUseProgressBar(kTRUE, 100);
483    
484     // --- ESD input handler ------------------------------------------
485     AliVEventHandler*  inputHandler = CreateInputHandler(fExecType);
486     if (inputHandler) mgr->SetInputEventHandler(inputHandler);
487     
488     // --- Monte-Carlo ------------------------------------------------
489     AliVEventHandler*  mcHandler = CreateMCHandler(fExecType,fMC);
490     if (mcHandler) mgr->SetMCtruthEventHandler(mcHandler);
491     
492     // --- AOD output handler -----------------------------------------
493     AliVEventHandler*  outputHandler = CreateOutputHandler(fExecType);
494     if (outputHandler) mgr->SetOutputEventHandler(outputHandler);
495     
496     // --- Include analysis macro path in search path ----------------
497     gROOT->SetMacroPath(Form("%s:%s:$ALICE_ROOT/ANALYSIS/macros",
498                              cwd.Data(), gROOT->GetMacroPath()));
499
500     // --- Physics selction - only for ESD ---------------------------
501     if (fExecType == kESD) CreatePhysicsSelection(fMC, mgr);
502     
503     // --- Create centrality task ------------------------------------
504     CreateCentralitySelection(fMC, mgr);
505
506     // --- Create tasks ----------------------------------------------
507     CreateTasks(fExecMode, fUsePar, mgr);
508
509     // --- Create Grid handler ----------------------------------------
510     // _must_ be done after all tasks has been added
511     AliAnalysisAlien* gridHandler = CreateGridHandler();
512     if (gridHandler) mgr->SetGridHandler(gridHandler);
513
514     // --- Set debug level on defined tasks --------------------------
515     if (fVerbose > 0) {
516       TIter next(mgr->GetTasks());
517       AliAnalysisTask* sub = 0;
518       while ((sub = static_cast<AliAnalysisTask*>(next()))) { 
519         AliAnalysisTaskSE* se = dynamic_cast<AliAnalysisTaskSE*>(sub);
520         if (!se) continue;
521         se->SetDebugLevel(fVerbose);
522       }
523     }
524     
525     // --- Print setup -----------------------------------------------
526     Print();
527     // if (mode == kProof) {
528     // Info("Run", "Exported environment variables to PROOF slaves:");
529     // TProof::GetEnvVars()->ls();
530     // Info("Run", "Environment variables for this session:");
531     // gSystem->Exec("printenv");
532     // }
533
534     // --- Initialise the train --------------------------------------
535     if (!mgr->InitAnalysis())  {
536       gSystem->ChangeDirectory(cwd.Data());
537       Error("Run","Failed to initialise train");
538       return false;
539     }
540
541     // --- Show status -----------------------------------------------
542     mgr->PrintStatus();
543
544     return true;
545   }
546   //------------------------------------------------------------------
547   /** 
548    * Run the analysis. 
549    * 
550    * @param nEvents Number of events to analyse 
551    * @param r       Possible runner object 
552    * @param asShell Passed to SaveSetup
553    */
554   virtual void Run(Int_t nEvents, Runner* r=0, Bool_t asShell=false)
555   {
556     // Info("Exec", "Doing exec with type=%d, mode=%d, oper=%d, events=%d "
557     //      "mc=%d, usePar=%d", type, mode, oper, nEvents, mc, usePar);
558
559     TString cwd = gSystem->WorkingDirectory();
560     
561     if (!Init()) { 
562       Error("Run", "Failed to intialize the train");
563       return;
564     }
565     if (r) SaveSetup(*r, nEvents, asShell);
566     if (fExecOper == kInitialize) return;
567     
568     // --- Create the chain ------------------------------------------
569     TChain* chain = CreateChain();
570     if (fExecMode == kLocal) {
571       if (!chain) {
572         Error("Run", "No chain defined in local mode!");
573         return;
574       }
575       if (chain->GetListOfFiles()->GetEntries() < 1) { 
576         Error("Run", "Empty chain in local mode!");
577         return;
578       }
579     }
580
581     // --- Get manager and execute -----------------------------------
582     AliAnalysisManager *mgr  =AliAnalysisManager::GetAnalysisManager();
583     Long64_t ret = StartAnalysis(mgr, chain, nEvents);
584
585     // Make sure we go back 
586     gSystem->ChangeDirectory(cwd.Data());
587
588     // Return. 
589     if (ret < 0) Error("Exec", "Analysis failed");
590   }
591   //------------------------------------------------------------------
592   /** 
593    * Print the setup 
594    * 
595    */
596   virtual void Print() const 
597   {
598     bool mc=AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler();
599     std::cout << fName << " train setup\n"
600               << std::boolalpha;
601     PrintField(std::cout, "Escaped name",               fEscapedName);
602     PrintField(std::cout, "ROOT version",               fRootVersion);
603     PrintField(std::cout, "AliROOT version",            fAliRootVersion);
604     PrintField(std::cout, "AliEn API version",          fAliEnAPIVersion);
605     PrintField(std::cout, "Name of proof server",       fProofServer);
606     PrintField(std::cout, "Input directory",            fDataDir);
607     PrintField(std::cout, "Data pattern",               fDataPattern);
608     PrintField(std::cout, "Proof data set name",        fDataSet);
609     PrintField(std::cout, "XML collection",             fXML);
610     PrintField(std::cout, "Storage replication",        fNReplica);
611     PrintField(std::cout, "Allow overwrite",            fAllowOverwrite);
612     PrintField(std::cout, "Do GDB debugging",           fUseGDB);
613     PrintField(std::cout, "Max # files per split",      fMaxSplit);
614     PrintField(std::cout, "Monte-Carlo input",          fMC);
615     PrintField(std::cout, "Monte-Carlo handler",        mc);
616     PrintField(std::cout, "Per run merge",              fPerRunMerge);
617     PrintFieldName(std::cout, "Run numbers");
618     for (Int_t i = 0; i < fRunNumbers.GetSize(); i++) 
619       std::cout << (i == 0 ? "" : ", ") << fRunNumbers.At(i);
620     std::cout << std::endl;
621
622     PrintFieldList(std::cout, "PAR files",              fListOfPARs);
623     PrintFieldList(std::cout, "Script sources",         fListOfSources);
624     PrintFieldList(std::cout, "Libraries",              fListOfLibraries);
625     PrintFieldList(std::cout, "Extras",                 fListOfExtras, "\n  ");
626
627     std::cout << std::noboolalpha << std::endl;
628
629     AliAnalysisGrid* plugin = 
630       AliAnalysisManager::GetAnalysisManager()->GetGridHandler();
631     if (!plugin) return;
632     
633   }
634   /** 
635    * Whether to be verbosity level.  0 means no messages, while higher
636    * numbers increase the verbosity
637    * 
638    * @param verb Verbosity level 
639    */
640   void SetVerbose(Int_t verb) { fVerbose = verb; }
641   /* @} */
642 protected:
643   //__________________________________________________________________
644   /** 
645    * @{ 
646    * @name Copying 
647    */
648   /** 
649    * Copy constructor 
650    * 
651    * @param o Object to copy from
652    */
653   TrainSetup(const TrainSetup& o)
654   : fName(o.fName),
655     fEscapedName(o.fEscapedName),
656     fRootVersion(o.fRootVersion),
657     fAliRootVersion(o.fAliRootVersion),
658     fAliEnAPIVersion(o.fAliEnAPIVersion),
659     fProofServer(o.fProofServer),
660     fDataDir(o.fDataDir),       
661     fDataPattern(o.fDataPattern),
662     fDataSet(o.fDataSet),       
663     fXML(o.fXML),       
664     fNReplica(o.fNReplica),
665     fAllowOverwrite(o.fAllowOverwrite),
666     fUseGDB(o.fUseGDB),
667     fMaxSplit(o.fMaxSplit),
668     fRunNumbers(o.fRunNumbers),
669     fListOfPARs(),
670     fListOfSources(),
671     fListOfLibraries(),
672     fListOfExtras(),
673     fDatime(o.fDatime),
674     fExecType(o.fExecType), 
675     fExecMode(o.fExecMode), 
676     fExecOper(o.fExecOper),
677     fUsePar(o.fUsePar), 
678     fMC(o.fMC), 
679     fPerRunMerge(o.fPerRunMerge),
680     fVerbose(o.fVerbose)
681   {
682     if (isdigit(fName[0])) { 
683       Warning("TrainSetup", "Name starts with a digit, prepending 'a' to name");
684       fName = Form("a%s", fName.Data());
685     }
686     TObject* obj = 0;
687     TIter nextPar(&o.fListOfPARs);
688     while ((obj = nextPar())) fListOfPARs.Add(obj->Clone());
689     TIter nextSrc(&o.fListOfSources);
690     while ((obj = nextSrc())) fListOfSources.Add(obj->Clone());
691     TIter nextLib(&o.fListOfLibraries);
692     while ((obj = nextLib())) fListOfLibraries.Add(obj->Clone());
693     TIter nextExa(&o.fListOfExtras);
694     while ((obj = nextExa())) fListOfExtras.Add(obj->Clone());
695   }
696   //------------------------------------------------------------------
697   /** 
698    * Assignment operator 
699    * 
700    * @param o Object to assign from 
701    * 
702    * @return Reference to this object. 
703    */
704   TrainSetup& operator=(const TrainSetup& o)
705   {
706     fName               = o.fName;
707     fRootVersion        = o.fRootVersion;
708     fAliRootVersion     = o.fAliRootVersion;
709     fProofServer        = o.fProofServer;
710     fDataDir            = o.fDataDir;   
711     fDataPattern        = o.fDataPattern;
712     fDataSet            = o.fDataSet;   
713     fXML                = o.fXML;       
714     fNReplica           = o.fNReplica;  
715     fRunNumbers         = o.fRunNumbers;
716     TObject* obj = 0;
717     TIter nextPar(&o.fListOfPARs);
718     while ((obj = nextPar())) fListOfPARs.Add(obj->Clone());
719     TIter nextSrc(&o.fListOfSources);
720     while ((obj = nextSrc())) fListOfSources.Add(obj->Clone());
721     TIter nextLib(&o.fListOfLibraries);
722     while ((obj = nextLib())) fListOfLibraries.Add(obj->Clone());
723     TIter nextExa(&o.fListOfExtras);
724     while ((obj = nextExa())) fListOfExtras.Add(obj->Clone());
725
726     return *this;
727   }
728   /* @} */
729
730   //__________________________________________________________________
731   /** 
732    * @{ 
733    * @name Utility functions 
734    */
735   /** 
736    * Escape bad elements of the name 
737    * 
738    * @param name   Name to escape 
739    * @param datime Date and Time 
740    * 
741    * @return escaped name 
742    */  
743   static TString EscapeName(const char* name, const TDatime& datime)
744   {
745     TString escaped = name;
746     char  c[] = { ' ', '/', '@', 0 };
747     char* p   = c;
748     while (*p) { 
749       escaped.ReplaceAll(Form("%c", *p), "_");
750       p++;
751     }
752     if (datime.GetYear() <= 1995 ||
753         datime.GetMonth() == 0 || 
754         datime.GetDay() == 0) return escaped;
755     escaped.Append(Form("_%04d%02d%02d_%02d%02d", 
756                         datime.GetYear(), 
757                         datime.GetMonth(), 
758                         datime.GetDay(), 
759                         datime.GetHour(), 
760                         datime.GetMinute()));
761     return escaped;
762   }    
763   //------------------------------------------------------------------
764   static void PrintFieldName(std::ostream& o, const char* name)
765   {
766     o << "  " << std::left << std::setw(25) << name << ": " << std::flush;
767   }
768   //------------------------------------------------------------------
769   static void PrintFieldList(std::ostream& o, const char* name, 
770                              const TCollection& c, const char* sep=", ")
771   {
772     PrintFieldName(o, name);
773     Bool_t   first = true;
774     TObject* obj = 0;
775     TIter    next(&c);
776     while ((obj = next())) {
777       o << (first ? "" : sep) << obj->GetName();
778       first = false;
779     }
780     std::cout << std::endl;
781   }
782   //------------------------------------------------------------------
783   template <typename T>
784   static void PrintField(std::ostream& o, const char* name, T& value) 
785   {
786     PrintFieldName(o, name);
787     o << value << std::endl;
788   }
789   //------------------------------------------------------------------
790   /** 
791    * Return a string that reflects the passed operation
792    * 
793    * @param eOper Operation
794    * 
795    * @return String representation of operation 
796    */
797   static const char* OperString(EOper eOper) 
798   {
799     switch (eOper) {
800     case kTest:         return "TEST";
801     case kOffline:      return "OFFLINE";
802     case kSubmit:       return "SUBMIT";
803     case kTerminate:    return "TERMINATE";
804     case kFull:         return "FULL";
805     case kInitialize:   return "INIT";
806     }
807     return 0;
808   }
809   //------------------------------------------------------------------
810   /** 
811    * Parse an operation string 
812    * 
813    * @param oper Operation 
814    * 
815    * @return An EOper value
816    */
817   static EOper ParseOperation(const char* oper)
818   {
819     TString sOper(oper);
820     sOper.ToUpper();
821     EOper eOper = kFull;
822     if      (sOper.Contains("TEST"))      eOper = kTest;
823     else if (sOper.Contains("OFFLINE"))   eOper = kOffline;
824     else if (sOper.Contains("SUBMIT"))    eOper = kSubmit;
825     else if (sOper.Contains("TERMINATE")) eOper = kTerminate;
826     else if (sOper.Contains("FULL"))      eOper = kFull;
827     else if (sOper.Contains("INIT"))      eOper = kInitialize;
828     else 
829       Fatal("Run", "unknown operation '%s'", oper);
830     return eOper;
831   }
832   //------------------------------------------------------------------
833   /** 
834    * Return a string that reflects the passed mode
835    * 
836    * @param eType Type of analysis 
837    * 
838    * @return String representation of execution type
839    */
840   static const char* TypeString(EType eType) 
841   {
842     switch (eType) {
843     case kESD:  return "ESD";
844     case kAOD:  return "AOD";
845     case kUser: return "USER";
846     }
847     return 0;
848   }
849   //------------------------------------------------------------------
850   /** 
851    * Parse a string into a type enum
852    * 
853    * @param type String to pass
854    * 
855    * @return Enumaration value 
856    */
857   static EType ParseType(const char* type)
858   {
859     // mc = false;
860     TString sType(type);
861     sType.ToUpper();
862     EType eType = kESD;
863     // if      (sType.Contains("MC"))    mc    = true;
864     if      (sType.Contains("ESD"))   eType = kESD; 
865     else if (sType.Contains("AOD"))   eType = kAOD;
866     else 
867       Fatal("Run", "Unknown type '%s'", type);
868     
869     return eType;
870   }
871   //------------------------------------------------------------------
872   /** 
873    * Return a string that reflects the passed mode
874    * 
875    * @param eMode Mode 
876    * 
877    * @return String representation of mode 
878    */
879   static const char* ModeString(EMode eMode) 
880   {
881     switch (eMode) {
882     case kLocal:        return "LOCAL";
883     case kProof:        return "PROOF";
884     case kGrid:         return "GRID";
885     }
886     return 0;
887   }
888   //------------------------------------------------------------------
889   /** 
890    * Parse a string for mode specifier 
891    * 
892    * @param mode Mode string
893    * 
894    * @return EMode value
895    */
896   static EMode ParseMode(const char* mode)
897   {
898     TString sMode(mode);
899     sMode.ToUpper();
900     EMode eMode = kLocal;
901     if      (sMode.Contains("LOCAL")) eMode = kLocal;
902     else if (sMode.Contains("PROOF")) eMode = kProof;
903     else if (sMode.Contains("GRID"))  eMode = kGrid;
904     else 
905       Fatal("Run", "Unknown mode '%s'", mode);
906     return eMode;
907   }
908   /* @} */
909
910
911   //__________________________________________________________________
912   /** 
913    * @{ 
914    * @name Overloadable creators 
915    */
916   /** 
917    * Create a grid handler 
918    * 
919    * @return Grid handler 
920    */
921   virtual AliAnalysisAlien* 
922   CreateGridHandler()
923   {
924     if (fExecMode != kGrid) return 0;
925
926     TString name = EscapedName();
927
928     // Create the plug-in object, and set run mode 
929     AliAnalysisAlien* plugin = new AliAnalysisAlien();
930     plugin->SetRunMode(OperString(fExecOper == kInitialize ? 
931                                   kFull : fExecOper));
932     
933     // Production mode - not used here 
934     // plugin->SetProductionMode();
935     
936     // Set output to be per run 
937     plugin->SetOutputToRunNo(true); 
938
939     // Set the job tag 
940     plugin->SetJobTag(fName);
941
942     // Set number of test files - used in test mode only 
943     plugin->SetNtestFiles(1);
944
945     // Set name of generated analysis macro 
946     plugin->SetAnalysisMacro(Form("%s.C", name.Data()));
947     
948     // Maximum number of sub-jobs 
949     // plugin->SetSplitMaxInputFileNumber(25);
950     
951     // Set the Time-To-Live 
952     plugin->SetTTL(70000);
953     
954     // Re-submit failed jobs as long as the ratio of failed jobs is
955     // below this percentage. 
956     plugin->SetMasterResubmitThreshold(95);
957
958     // Set the input format
959     plugin->SetInputFormat("xml-single");
960
961     // Set the name of the generated jdl 
962     plugin->SetJDLName(Form("%s.jdl", name.Data()));
963
964     // Set the name of the generated executable 
965     plugin->SetExecutable(Form("%s.sh", name.Data()));
966     
967     // Set the job price !?
968     plugin->SetPrice(1);
969
970     // Set whether to merge via JDL 
971     plugin->SetMergeViaJDL(true);
972     
973     // Fast read otion 
974     plugin->SetFastReadOption(false);
975
976     // Whether to overwrite existing output 
977     plugin->SetOverwriteMode(true);
978
979     // Set the executable binary name and options 
980     plugin->SetExecutableCommand("aliroot -b -q -x");
981     
982     // Split by storage element - must be lower case!
983     plugin->SetSplitMode("se");
984     plugin->SetSplitMaxInputFileNumber(fMaxSplit);
985
986     // Disable default outputs 
987     plugin->SetDefaultOutputs(true);
988
989     // Merge parameters 
990     plugin->SetMaxMergeFiles(20);
991     plugin->SetMergeExcludes("AliAOD.root "
992                             "*EventStat*.root "
993                             "*event_stat*.root");
994     
995     // Keep log files 
996     plugin->SetKeepLogs();
997
998     // Set the working directory to be the trains name (with special
999     // characters replaced by '_' and the date appended), and also set
1000     // the output directory (relative to working directory)
1001     plugin->SetGridWorkingDir(name.Data());
1002     plugin->SetGridOutputDir("output");
1003
1004     // Set required version of software 
1005     if (!fAliEnAPIVersion.IsNull()) plugin->SetAPIVersion(fAliEnAPIVersion);
1006     if (!fRootVersion.IsNull())     plugin->SetROOTVersion(fRootVersion);
1007     if (!fAliRootVersion.IsNull())  plugin->SetAliROOTVersion(fAliRootVersion);
1008
1009     // Declare root of input data directory 
1010     TString dataDir(fDataDir);
1011     if (dataDir.BeginsWith("alien://")) 
1012       dataDir.ReplaceAll("alien://", "");
1013     plugin->SetGridDataDir(dataDir);
1014
1015     // Data search patterns 
1016     TString pat;
1017     if (AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler())
1018       plugin->SetRunPrefix("");
1019     else {
1020       plugin->SetRunPrefix("000");
1021     }
1022     pat = fDataPattern;
1023     if (!pat.EndsWith("/")) pat.Append("/");
1024     pat.Append(Form("*%s.root", fExecType == kESD ? "ESDs" : "AOD"));
1025     plugin->SetDataPattern(pat);
1026
1027     // Add the run numbers 
1028     Int_t nRun = 0;
1029     for (Int_t i = 0; i < fRunNumbers.fN; i++) {
1030       if (fRunNumbers[i] < 0) continue; 
1031       plugin->AddRunNumber(fRunNumbers[i]);
1032       nRun++;
1033     }
1034     // Set number of runs per master - set to one to per run
1035     if (fPerRunMerge) plugin->SetNrunsPerMaster(1);
1036     else              plugin->SetNrunsPerMaster(nRun+1);
1037     
1038     // Enable configured PARs 
1039     TIter nextPar(&fListOfPARs);
1040     TObject* parName;
1041     while ((parName = nextPar()))
1042       plugin->EnablePackage(parName->GetName());
1043     
1044     // Add sources that need to be compiled on the workers using
1045     // AcLIC. 
1046     TString addSources = SetupSources();
1047     if (!addSources.IsNull()) plugin->SetAnalysisSource(addSources.Data());
1048
1049     // Add binary libraries that should be uploaded to the workers 
1050     TString addLibs = SetupLibraries();
1051     if (!addLibs.IsNull()) plugin->SetAdditionalLibs(addLibs.Data());
1052     
1053     // Loop over defined containers in the analysis manager, 
1054     // and declare these as outputs 
1055     TString listOfAODs  = "";
1056     TString listOfHists = "";
1057     AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
1058     AliAnalysisDataContainer* cont = 0;
1059     TIter nextCont(mgr->GetOutputs());
1060     while ((cont = static_cast<AliAnalysisDataContainer*>(nextCont()))) {
1061       TString outName(cont->GetFileName());
1062       TString& list = (outName == "default" ? listOfAODs : listOfHists);
1063       if (outName == "default") { 
1064         if (!mgr->GetOutputEventHandler()) continue; 
1065
1066         outName = mgr->GetOutputEventHandler()->GetOutputFileName();
1067       }
1068       if (list.Contains(outName)) continue;
1069       if (!list.IsNull()) list.Append(",");
1070       list.Append(outName);
1071     }
1072     if (!mgr->GetExtraFiles().IsNull()) { 
1073       if (!listOfAODs.IsNull()) listOfAODs.Append("+");
1074       TString extra = mgr->GetExtraFiles();
1075       extra.ReplaceAll(" ", ",");
1076       listOfAODs.Append(extra);
1077    }
1078     TString outArchive = Form("stderr, stdout@disk=%d", fNReplica);
1079     if (!listOfHists.IsNull()) 
1080       outArchive.Append(Form(" hist_archive.zip:%s@disk=%d", 
1081                              listOfHists.Data(), fNReplica));
1082     if (!listOfAODs.IsNull()) 
1083       outArchive.Append(Form(" aod_archive.zip:%s@disk=%d", 
1084                              listOfAODs.Data(), fNReplica));
1085     if (listOfAODs.IsNull() && listOfHists.IsNull()) 
1086       Fatal("CreateGridHandler", "No outputs defined");
1087     // Disabled for now 
1088     // plugin->SetOutputArchive(outArchive);
1089     
1090
1091     return plugin;
1092   }
1093   //------------------------------------------------------------------
1094   /** 
1095    * Create input handler 
1096    * 
1097    * @param type 
1098    * 
1099    * @return 
1100    */
1101   virtual AliVEventHandler* CreateInputHandler(EType type)
1102   {
1103     switch (type) {
1104     case kESD: return new AliESDInputHandler(); 
1105     case kAOD: return new AliAODInputHandler(); 
1106     case kUser: return 0;
1107     }
1108     return 0;
1109   }
1110   //------------------------------------------------------------------
1111   /** 
1112    * Create input handler 
1113    * 
1114    * @param type  Run type (ESD or AOD)
1115    * @param mc    Assume monte-carlo input 
1116    * 
1117    * @return 
1118    */
1119   virtual AliVEventHandler* CreateMCHandler(EType /*type*/, bool mc)
1120   {
1121     if (!mc)          return 0;
1122     // if (type != kESD) return 0;
1123     Info("CreateMCHandler", "Making MC handler");
1124     AliMCEventHandler* mcHandler = new AliMCEventHandler();
1125     mcHandler->SetReadTR(true); 
1126     return mcHandler;
1127   }
1128   //------------------------------------------------------------------
1129   /** 
1130    * Create output event handler 
1131    * 
1132    * @param type 
1133    * 
1134    * @return 
1135    */
1136   virtual AliVEventHandler* CreateOutputHandler(EType type)
1137   {
1138     AliAODHandler* ret = new AliAODHandler();
1139     switch (type) { 
1140     case kESD: 
1141       ret->SetOutputFileName("AliAOD.root");
1142       break;
1143     case kAOD: 
1144       ret->SetOutputFileName("AliAOD.pass2.root");
1145       break;
1146     case kUser: 
1147       break;
1148     }
1149     
1150     return ret;
1151   }
1152   //------------------------------------------------------------------
1153   /** 
1154    * Create physics selection, and add to manager
1155    * 
1156    * @param mc Whether this is for MC 
1157    * @param mgr Manager
1158    */
1159   virtual void CreatePhysicsSelection(Bool_t mc,
1160                                       AliAnalysisManager* mgr)
1161   {
1162     gROOT->Macro(Form("AddTaskPhysicsSelection.C(%d)", mc));
1163     mgr->RegisterExtraFile("event_stat.root");
1164   }
1165   //------------------------------------------------------------------
1166   /** 
1167    * Create centrality selection, and add to manager
1168    * 
1169    * @param mc Whether this is for MC 
1170    * @param mgr Manager
1171    */
1172   virtual void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
1173   {
1174     gROOT->Macro("AddTaskCentrality.C");
1175     const char* name = "CentralitySelection";
1176     AliCentralitySelectionTask* ctask = 
1177       dynamic_cast<AliCentralitySelectionTask*>(mgr->GetTask(name));
1178     if (!ctask) return;
1179     if (mc) ctask->SetMCInput();
1180   }
1181   //------------------------------------------------------------------
1182   /** 
1183    * Create analysis tasks.  Must be overloaded by sub-class
1184    * 
1185    * @param mode Run mode
1186    * @param mgr  Manager
1187    * @param par  Whether to use pars 
1188    */
1189   virtual void CreateTasks(EMode mode, Bool_t par, AliAnalysisManager* mgr)=0;
1190   /* @} */
1191
1192   //__________________________________________________________________
1193   /** 
1194    * @{ 
1195    * @name Library loading 
1196    */
1197   //------------------------------------------------------------------
1198   /** 
1199    * Load common libraries 
1200    * 
1201    * @return true on success 
1202    */
1203   Bool_t LoadCommonLibraries() 
1204   {
1205     if (!gSystem->Getenv("ALICE_ROOT")) { 
1206       Error("LoadCommonLibraries", "Local AliROOT not available");
1207       return false;
1208     }
1209     gSystem->Load("libTree.so");
1210     gSystem->Load("libGeom.so");
1211     gSystem->Load("libVMC.so");
1212     gSystem->Load("libPhysics.so");
1213     gSystem->Load("libMinuit.so");
1214     if (fExecMode == kProof) { 
1215       gProof->Exec("gSystem->Load(\"libTree.so\");");
1216       gProof->Exec("gSystem->Load(\"libGeom.so\");");
1217       gProof->Exec("gSystem->Load(\"libMinuit.so\");");
1218       gProof->Exec("gSystem->Load(\"libVMC.so\");");
1219
1220       
1221     }
1222
1223     Bool_t ret   = true;
1224     Bool_t basic = fExecMode == kGrid ? false : fUsePar;
1225     
1226     ret &= LoadLibrary("STEERBase",     basic, false);
1227     ret &= LoadLibrary("ESD",           basic, false);
1228     ret &= LoadLibrary("AOD",           basic, false);
1229     ret &= LoadLibrary("ANALYSIS",      basic, true);
1230     ret &= LoadLibrary("OADB",          basic, true);
1231     ret &= LoadLibrary("ANALYSISalice", basic, true);
1232
1233     return ret;
1234   }
1235   //------------------------------------------------------------------
1236   /** 
1237    * Load a library 
1238    * 
1239    * @param what What library to load
1240    * @param par  If true, load as PAR
1241    * @param rec  If true, also load on slaves
1242    * 
1243    * @return true on success 
1244    */
1245   Bool_t LoadLibrary(const char* what, Bool_t par, Bool_t rec=false)
1246   {
1247     if (!what || what[0] == '\0') return true;
1248     
1249     TString module(what);
1250     TString libName(what);
1251     if (!libName.BeginsWith("lib")) { 
1252       // Check if the library corresponds to a compiled macro 
1253       if (!gSystem->AccessPathName(Form("%s_C.so", libName.Data()))) {
1254         libName.Append("_C");
1255       }
1256       else if (!gSystem->AccessPathName(Form("../%s_C.so", libName.Data()))) {
1257         libName = Form("../%s_C", what);
1258       }
1259       else 
1260         libName = Form("lib%s", libName.Data());
1261     }
1262     if (!libName.EndsWith(".so"))   libName.Append(".so");
1263
1264     Int_t ret = 0;
1265
1266     switch (fExecMode) { 
1267     case kLocal: // Just load and exit 
1268       if (gSystem->Load(libName.Data()) < 0) {
1269         Error("LoadLibrary", "Failed to load library %s", libName.Data());
1270         return false;
1271       }
1272       break;
1273     case kGrid: 
1274       if (par) { 
1275         ret = SetupPAR(what) ? 0 : -1;
1276         if (rec) fListOfPARs.Add(new TObjString(what));
1277       } else  {
1278         ret = gSystem->Load(libName.Data());
1279         if (rec) fListOfLibraries.Add(new TObjString(libName));
1280       }
1281       break;
1282     case kProof: 
1283       Info("LoadLibrary", "Uploading %s", what);
1284       ret = gProof->UploadPackage(what, TProof::kRemoveOld);
1285       if (ret < 0)  {   
1286           ret = gProof->UploadPackage(gSystem->ExpandPathName(Form("../%s.par",
1287                                                                    what)));
1288         if (ret < 0) {  
1289           ret = 
1290             gProof->UploadPackage(gSystem
1291                                   ->ExpandPathName(Form("$ALICE_ROOT/%s.par", 
1292                                                         what)));
1293           if (ret < 0) {
1294             Error("LoadLibrary", 
1295                   "Could not find module %s.par in current directory nor "
1296                   "in $ALICE_ROOT", module.Data());
1297             return false;
1298           }
1299         }
1300       }
1301       Info("LoadLibrary", "Enabling package %s", what);
1302       ret = gProof->EnablePackage(what);
1303       break;
1304     }
1305     if (ret < 0) { 
1306       Error("LoadLibrary", "Couldn't load %s", what);
1307       return false;
1308     }
1309     return true;
1310   }
1311   /* @} */
1312
1313   //__________________________________________________________________
1314   /** 
1315    * @{ 
1316    * @name PAR generation from script 
1317    */
1318   /** 
1319    * Service function to make a PAR out of a script.  
1320    * 
1321    * The script should contain can contain a sub-class of AliAnalysisTask. 
1322    * The script will be compiled on the slaves before loading the 
1323    * AliAnalysisManager.  Parts to (not) be compiled can be protected like 
1324    * 
1325    * @code 
1326    * #ifdef BUILD_PAR
1327    * // This will _only_ be compiled in the servers 
1328    * #endif
1329    * #ifndef BUILD_PAR
1330    * // This will not be compiled in the servers 
1331    * #endif
1332    * @endcode
1333    * 
1334    * @param mode   Execution mode (Grid, PROOF, Local)
1335    * @param script Script to upload and compile in the PAR
1336    * @param deps   Dependency pars 
1337    * 
1338    * @return true on success. 
1339    */
1340   static Bool_t MakeScriptPAR(EMode mode, const char* script, const char* deps)
1341   {
1342     // Get the base name 
1343     Info("MakeScriptPAR", "Making par file for %s", script);
1344     TString base(gSystem->BaseName(script));
1345     Int_t   idx = base.Last('.');
1346     if (idx != kNPOS) base.Remove(idx);
1347     Bool_t retval = true;
1348     // Info("MakeScriptPAR", "script=%s, base=%s", script, base.Data());
1349
1350     if (mode == kLocal) { 
1351       if (gROOT->LoadMacro(Form("%s.C++g", base.Data())) < 0)
1352         return false;
1353       return true;
1354     }
1355
1356     TString tmpdir(gSystem->TempDirectory());
1357     int   ltempl = tmpdir.Length() + 1 + 5 + 6 + 1;
1358     char* templ  = new char[ltempl];
1359     snprintf(templ, ltempl, "%s/trainXXXXXX", tmpdir.Data());
1360     if (!mkdtemp(templ)) {
1361       Error("MakeScriptPAR", 
1362             "Failed to generate temporary directory from template %s", 
1363             templ);
1364       return false;
1365     }
1366
1367     try {
1368       // Check name of script file 
1369       TString scr(script);
1370       TString ext;
1371       if      (scr.EndsWith(".C"))   ext = "C"; 
1372       else if (scr.EndsWith(".cxx")) ext = "cxx";
1373       else                           { ext = "C"; scr.Append(".C"); }
1374       
1375       // Check if we can access the file 
1376       TString path = TString::Format(".:%s", TROOT::GetMacroPath());
1377       char* loc = gSystem->Which(path, scr);
1378       if (!loc) throw TString::Format("Script %s not found in %s", 
1379                                       scr.Data(), path.Data());
1380       TString full(loc);
1381       
1382       TString dir = TString::Format("%s/%s", templ, base.Data());
1383       // Set-up directories 
1384       if (gSystem->MakeDirectory(dir) < 0) 
1385         throw TString::Format("Could not make directory '%s'", base.Data());
1386       
1387       if (gSystem->MakeDirectory(Form("%s/PROOF-INF", dir.Data()))) 
1388         throw TString::Format("Could not make directory %s/PROOF-INF", 
1389                               base.Data());
1390       
1391       // Copy the script to the setup directory 
1392       TString dest = TString::Format("%s/%s.%s", dir.Data(),
1393                                      base.Data(), ext.Data());
1394       Int_t ret = gSystem->CopyFile(full, dest, true);
1395       switch (ret) { 
1396       case -1: throw TString::Format("Couldn't open %s for copy", scr.Data());
1397       case -2: throw TString::Format("File %s exists", dest.Data());
1398       case -3: throw TString::Format("Error while copying %s", scr.Data());
1399       }
1400       
1401       // Make our build file 
1402       // Info("MakeScriptPAR", "Making build script %s/PROOF-INF/BUILD.sh", dir.Data());
1403       std::ofstream b(Form("%s/PROOF-INF/BUILD.sh", dir.Data()));
1404       if (!b) 
1405         throw TString::Format("Failed to open b shell script");
1406       b << "#!/bin/sh\n"
1407         << "echo BUILD.sh@`hostname`: Building " << base << "\n"
1408         << "root.exe -l -b -q PROOF-INF/BUILD.C 2>&1 | tee " << base << ".log\n"
1409         << "echo BUILD.sh@`hostname`: done: $?\n"
1410         << std::endl;
1411       b.close();
1412       if (gSystem->Chmod(Form("%s/PROOF-INF/BUILD.sh", dir.Data()), 0755) != 0)
1413         throw TString::Format("Failed to set exectuable flags on "
1414                               "%s/PROOF-INF/BUILD.sh", dir.Data());
1415       
1416       // Info("MakeScriptPAR", "Making utility script %s/PROOF-INF/UTIL.C", dir.Data());
1417       std::ofstream u(Form("%s/PROOF-INF/UTIL.C", dir.Data()));
1418       if (!u) 
1419         throw TString::Format("Failed to open utility script");
1420       u << "void LoadROOTLibs() {\n"
1421         << "  gSystem->Load(\"libVMC\");\n"
1422         << "  gSystem->Load(\"libNet\");\n"
1423         << "  gSystem->Load(\"libTree\");\n"
1424         << "  gSystem->Load(\"libPhysics\");\n"
1425         << "  gSystem->Load(\"libMinuit\");\n"
1426         << "}\n\n"
1427         << "void AddAliROOT() {\n"
1428         << "  TString val(gSystem->Getenv(\"ALICE_ROOT\"));\n"
1429         << "  if (val.IsNull())\n"
1430         << "    Warning(\"Add\",\"ALICE_ROOT not defined\");\n"
1431         << "  else\n"
1432         << "    gSystem->AddIncludePath(Form(\"-I%s/include\",val.Data()));\n"
1433         << "}\n\n"
1434         << "void AddDep(const char* env) {\n"
1435         << "  TString val(gSystem->Getenv(Form(\"%s_INCLUDE\",env)));\n"
1436         << "  if (val.IsNull())\n"
1437         << "    Warning(\"Add\",\"%s_INCLUDE not defined\", env);\n"
1438         << "  else {\n"
1439         << "    gSystem->AddIncludePath(Form(\"-I../%s\",val.Data()));\n"
1440         << "  }\n"
1441         << "}\n\n"
1442         << "void LoadDep(const char* name) {\n"
1443         << "  gSystem->AddDynamicPath(Form(\"../%s\",name));\n"
1444         << "  char* full = gSystem->DynamicPathName(name,true);\n"
1445         << "  if (!full) \n"
1446         << "   full = gSystem->DynamicPathName(Form(\"lib%s\",name),true);\n"
1447         << "  if (!full) \n"
1448         << "   full = gSystem->DynamicPathName(Form(\"lib%s.so\",name),true);\n"
1449         << "  if (!full) {\n"
1450         << "    Warning(\"LoadDep\",\"Module %s not found\", name);\n"
1451         << "    return;\n"
1452         << "  }\n"
1453         << "  gSystem->Load(full);\n"
1454         << "}\n"
1455         << std::endl;
1456       u.close();
1457
1458       // Info("MakeScriptPAR", "Making utility script %s/PROOF-INF/BUILD.C", dir.Data());
1459       std::ofstream cbuild(Form("%s/PROOF-INF/BUILD.C", dir.Data()));
1460       if (!cbuild) 
1461         throw TString::Format("Failed to open build script");
1462       cbuild << "void BUILD() {\n"
1463              << "  gSystem->AddIncludePath(\"-DBUILD_PAR=1\");\n"
1464              << "  gROOT->LoadMacro(\"PROOF-INF/UTIL.C\");\n"
1465              << "  LoadROOTLibs();\n"
1466              << "  AddAliROOT();\n";
1467       TObjArray*  depList = TString(deps).Tokenize(",");
1468       TIter       next(depList);
1469       TObject*    dep = 0;
1470       while ((dep = next())) {
1471         cbuild << "  AddDep(\"" << dep->GetName() << "\");\t"
1472                << "  LoadDep(\"" << dep->GetName() << "\");\n";
1473       }
1474       cbuild << "  // gDebug = 5;\n"
1475              << "  int ret = gROOT->LoadMacro(\"" 
1476              << base << "." << ext << "++g\");\n"
1477              << "  if (ret != 0) Fatal(\"BUILD\",\"Failed to build\");\n"
1478              << "  // else Info(\"BUILD\", \"Made " << base << "\");\n"
1479              << "}\n"
1480              << std::endl;
1481       cbuild.close();
1482       
1483       // Make our set-up script 
1484       // Info("MakeScriptPAR", "Making setup script %s/PROOF-INF/SETUP.C", dir.Data());
1485       std::ofstream setup(Form("%s/PROOF-INF/SETUP.C", dir.Data()));
1486       if (!setup) 
1487         throw TString::Format("Failed to open setup script");
1488       setup << "void SETUP() {\n"
1489             << "  gROOT->LoadMacro(\"PROOF-INF/UTIL.C\");\n"
1490             << "  LoadROOTLibs();\n"
1491             << "  // Info(\"SETUP\",\"Loading libraries\");\n";
1492       next.Reset();
1493       dep = 0;
1494       while ((dep = next())) 
1495         setup << "  LoadDep(\"" << dep->GetName() << "\");\n";
1496       setup << "  // gDebug = 5;\n"
1497             << "  // Info(\"SETUP\",\"Loading " << base << "_" << ext << ".so\");\n"
1498             << "  gSystem->Load(\"" << base << "_" << ext << ".so\");\n"
1499             << "  // gDebug = 0;\n"
1500             << "  gROOT->ProcessLine(\".include " << base << "\");\n"
1501             << "  gSystem->Setenv(\"" << base << "_INCLUDE\",\"" 
1502             << base << "\");\n"
1503             << "  // Info(\"SETUP\", \"Done\");\n"
1504             << "}\n"
1505             << std::endl;
1506       setup.close();
1507
1508       // Info("MakeScriptPAR", "Packing up tar-archive");
1509       ret = gSystem->Exec(Form("(cd %s && tar -czf %s.par %s)", 
1510                                templ, base.Data(),base.Data()));
1511       if (ret != 0) 
1512         throw TString::Format("Failed to create PAR file %s.PAR from %s", 
1513                               base.Data(), dir.Data());
1514
1515       // Info("MakeScriptPAR", "Moving PAR archive");
1516       ret = gSystem->Exec(Form("mv -f %s/%s.par %s.par", templ, base.Data(), 
1517                                base.Data()));
1518       if (ret != 0) 
1519         throw TString::Format("Failed to rename %s/%s.par to %s.par: %s", 
1520                               templ, base.Data(), base.Data(), 
1521                               gSystem->GetError());
1522     }
1523     catch (TString& e) { 
1524       Error("MakeScriptPAR", "%s", e.Data()); 
1525       retval = false;
1526     }
1527     // Info("MakeScriptPAR", "Removing temperary directory %s", templ);
1528     gSystem->Exec(Form("rm -rf %s", templ));
1529     return retval;
1530   }
1531   /* @} */
1532
1533   //__________________________________________________________________
1534   /** 
1535    * @{ 
1536    * @name Execution implementation
1537    */
1538   /** 
1539    * Start the analysis 
1540    * 
1541    * @param mgr       Analysis manager
1542    * @param chain     Input data (local and proof only)
1543    * @param nEvents   Number of events to analyse 
1544    */
1545   Long64_t StartAnalysis(AliAnalysisManager* mgr, 
1546                          TChain*             chain,
1547                          Int_t               nEvents)
1548   {
1549     // --- Run the analysis ------------------------------------------
1550     TString mode = ModeString(fExecMode);
1551     switch (fExecMode) { 
1552     case kLocal: 
1553       if (!chain) {
1554         Error("StartAnalysis", "No chain defined");
1555         return -1;
1556       }
1557       if (nEvents < 0) nEvents = chain->GetEntries();
1558       return mgr->StartAnalysis(mode, chain, nEvents);
1559     case kProof: 
1560       if (fDataSet.IsNull()) {
1561         if (!chain) { 
1562           Error("StartAnalysis", "No chain defined");
1563           return -1;
1564         }
1565         if (nEvents < 0) nEvents = chain->GetEntries();
1566         return mgr->StartAnalysis(mode, chain, nEvents);
1567       }
1568       return mgr->StartAnalysis(mode, fDataSet);
1569     case kGrid: 
1570       if (nEvents < 0)
1571         return mgr->StartAnalysis(mode);
1572       return mgr->StartAnalysis(mode, nEvents);
1573     }
1574     // We should never get  here 
1575     return -1;
1576   }
1577   //------------------------------------------------------------------
1578   /** 
1579    * Connect to external services (Proof and/or grid)
1580    * 
1581    * @return true on success 
1582    */
1583   virtual Bool_t Connect()
1584   {
1585     if (fExecMode == kLocal) return true;
1586                           
1587     // --- Set-up connections to Proof cluster and alien -------------
1588     if (fExecMode == kProof) { 
1589       Info("Connect", "Opening connection to proof server");
1590       // --- Find user name ------------------------------------------
1591       TString userName(gSystem->Getenv("alien_API_USER"));
1592       if (userName.IsNull()) {
1593         userName = gSystem->GetUserInfo()->fUser;
1594         Warning("Connect", 
1595                 "environment variable 'alien_API_USER' not set, using %s", 
1596                 userName.Data());
1597       }
1598
1599       // --- Set prefered GSI method ---------------------------------
1600       gEnv->SetValue("XSec.GSI.DelegProxy", "2");
1601
1602       // --- Figure out some server settings -------------------------
1603       TString serv = "";
1604       Bool_t  lite = false;
1605       if (fProofServer.BeginsWith("workers=") || fProofServer.IsNull()) {
1606         lite = true;
1607         serv = fProofServer;
1608       }
1609       else 
1610         serv = Form("%s@%s", userName.Data(), fProofServer.Data());
1611
1612       // --- Possibly debug slave sessions with GDB ------------------
1613       if (fUseGDB) { 
1614         TString gdbCmd("/usr/bin/gdb --batch -ex run -ex bt --args");
1615         // TString gdbCmd("\"gdb --batch -ex run -ex bt --args\"");
1616         Info("Connect", "Using GDB to wrap slaves: %s", gdbCmd.Data());
1617         TProof::AddEnvVar("PROOF_WRAPPERCMD", gdbCmd);
1618       }
1619       
1620       // --- Add ALICE_ROOT directory to search path for packages ----
1621       Info("Connect", "Set location of packages");
1622       gEnv->SetValue("Proof.GlobalPackageDirs", 
1623                      Form("%s:%s", 
1624                           gEnv->GetValue("Proof.GlobalPackageDirs", "."), 
1625                           gSystem->Getenv("ALICE_ROOT")));
1626                                                      
1627       // --- Set OADB path on workers --------------------------------
1628       const char* oadbPath = AliAnalysisManager::GetOADBPath();
1629       TProof::AddEnvVar("OADB_PATH", oadbPath);
1630       // if (lite) gSystem->Setenv("OADB_PATH", oadbPath);
1631       // Info("Connect", "OADB_PATH=%s", gSystem->Getenv("OADB_PATH"));
1632
1633       // --- Now open connection to PROOF cluster --------------------
1634       TProof::Open(serv);
1635       if (!gProof) { 
1636         Error("Connect", "Failed to connect to Proof cluster %s as %s",
1637               fProofServer.Data(), userName.Data());
1638         return false;
1639       }
1640       Info("Connect", "Now connected to Proof");
1641       // gProof->SetParameter("PROOF_LookupOpt", "all");
1642       if (lite) return true;
1643     }
1644
1645     // --- Open a connection to the grid -----------------------------
1646
1647     TGrid::Connect("alien://");
1648     if (!gGrid || !gGrid->IsConnected()) { 
1649       // This is only fatal in grid mode 
1650       Error("Connect", "Failed to connect to AliEN");
1651       if (fExecMode == kGrid) return false; 
1652       return true;
1653     }
1654     if (fExecMode == kGrid) return true;
1655
1656     // --- Set and make output directory -----------------------------
1657     TString name = EscapedName();
1658     TString homeDir(gGrid->GetHomeDirectory());
1659     TString workDir(homeDir);
1660     workDir.Append("/");
1661     workDir.Append(name);
1662     
1663     // Make working directory 
1664     if (!gGrid->Cd(workDir)) { 
1665       gGrid->Cd(homeDir);
1666       if (gGrid->Mkdir(workDir)) {
1667         gGrid->Cd(name);
1668         Info("Connect", "Directory %s created", workDir.Data());
1669       }
1670     }
1671     // Make output directory 
1672     gGrid->Mkdir("proof_output");
1673     gGrid->Cd("proof_output");
1674
1675     return true;
1676   }       
1677   //------------------------------------------------------------------
1678   /** 
1679    * Get the output directory (local or Grid)
1680    * 
1681    * @param mode Mode of execution 
1682    * 
1683    * @return Path to output directory 
1684    */
1685   TString GetOutputDirectory(EMode mode) const 
1686   {
1687     TString ret(fEscapedName);
1688     if (mode != kGrid) return ret;
1689     
1690     AliAnalysisManager* am = AliAnalysisManager::GetAnalysisManager();
1691     if (!am) { 
1692       Warning("GetOutputDirectory", "No analysis manager defined yet");
1693       return ret;
1694     }
1695     AliAnalysisGrid* ag = am->GetGridHandler();
1696     if (!ag) { 
1697       Warning("GetOutputDirectory", "No grid handler defined yet");
1698       return ret;
1699     }
1700     AliAnalysisAlien* aa = dynamic_cast<AliAnalysisAlien*>(ag);
1701     if (!aa) { 
1702       Warning("GetOutputDirectory", "Grid handler isn't for AliEn");
1703       return ret;
1704     }
1705     ret = aa->GetGridOutputDir();
1706     if (!ret.BeginsWith("/")) {
1707       if (gGrid)
1708         ret = Form("%s/%s/%s", gGrid->GetHomeDirectory(), 
1709                    fEscapedName.Data(), aa->GetGridOutputDir());
1710       else 
1711         ret = Form("%s/%s", fEscapedName.Data(), aa->GetGridOutputDir());
1712     }
1713     return ret;
1714   }
1715   /* @} */
1716
1717   //__________________________________________________________________
1718   /** 
1719    * @{ 
1720    * @name Setup 
1721    */
1722   /** 
1723    * Make our working directory if so requested 
1724    * 
1725    * @return true on success
1726    */
1727   Bool_t SetupWorkingDirectory()
1728   {
1729     TString nam = EscapedName();
1730     //Info("Init","Current dir=%s, escaped name=%s",cwd.Data(),nam.Data());
1731     Bool_t exists = gSystem->AccessPathName(nam.Data()) == 0;
1732     if (fExecOper == kTerminate && !exists) {
1733       Error("SetupWorkingDirectory", "File/directory %s does not exists", 
1734             nam.Data());
1735       return false;
1736     }
1737
1738         
1739     if (!fAllowOverwrite && exists) {
1740       Error("SetupWorkingDirectory", "File/directory %s already exists", 
1741             nam.Data());
1742       return false;
1743     }
1744
1745     if (!exists) {
1746       if (gSystem->MakeDirectory(nam.Data())) {
1747         Error("SetupWorkingDirectory", "Failed to make directory '%s'", 
1748               nam.Data());
1749         return false;
1750       }
1751     }
1752       
1753     if (!gSystem->ChangeDirectory(nam.Data())) { 
1754       Error("SetupWorkingDirectory", "Failed to change directory to %s", 
1755             nam.Data());
1756       return false;
1757     }
1758     Info("SetupWorkingDirectory", "Made subdirectory %s, and cd'ed there", 
1759          nam.Data());
1760     return true;
1761   }
1762   //------------------------------------------------------------------
1763   /** 
1764    * Set-up a PAR file 
1765    * 
1766    * @param what PAR file 
1767    * 
1768    * @return true on success
1769    */
1770   Bool_t SetupPAR(const char* what)
1771   {
1772     if (!what || what[0] == '\0') return -1;
1773     
1774     TString parFile(Form("%s.par", what));
1775     if (gSystem->AccessPathName(parFile.Data())) { 
1776       if (gSystem->AccessPathName(Form("../%s.par", what))) { 
1777         // If not found 
1778         TString aliParFile = 
1779           gSystem->ExpandPathName(Form("$(ALICE_ROOT)/%s.par", what));
1780         if (gSystem->AccessPathName(aliParFile.Data())) { 
1781           Error("SetupPAR", "PAR file %s not found in current directory or "
1782                 "$(ALICE_ROOT)", what);
1783           return false;
1784         }
1785         // Copy to current directory 
1786         TFile::Cp(aliParFile, parFile);
1787       }
1788       else 
1789         gSystem->Exec(Form("ln -s ../%s.par .", what));
1790     }
1791     
1792     // Extract archive 
1793     gSystem->Exec(Form("tar xzf %s", parFile.Data()));
1794     
1795     // Change directory into par archive
1796     TString cwd = gSystem->WorkingDirectory();
1797     
1798     if (!gSystem->ChangeDirectory(what)) { 
1799       Error("SetupPAR", "Failed to change directory to %s", what);
1800       return false;
1801     }
1802     
1803     // Test the build 
1804     if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
1805       Info("SetupPar", "Building in PAR archive %s", what);
1806       if (gSystem->Exec("PROOF-INF/BUILD.sh")) { 
1807         Error("SetupPar", "Failed to build in PAR directory %s", what);
1808         gSystem->ChangeDirectory(cwd.Data());
1809         return false;
1810       }
1811     }
1812     
1813     // Check for setup script
1814     if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
1815       // Info("SetupPAR", "Setting up for PAR %s", what);
1816       gROOT->Macro("PROOF-INF/SETUP.C");
1817     }
1818     if (!gSystem->ChangeDirectory(cwd.Data())) return false;
1819
1820     return true;
1821   }
1822   //------------------------------------------------------------------
1823   /** 
1824    * Set-up extra sources. 
1825    * 
1826    * @return true on success
1827    */
1828   TString SetupExtras()
1829   {
1830     TString ret;
1831     TIter next(&fListOfExtras);
1832     TObjString* obj = 0;
1833     while ((obj = static_cast<TObjString*>(next()))) {
1834       TString path = gSystem->ExpandPathName(obj->GetName());
1835       if (!path.BeginsWith("/")) 
1836         // If not an absolute path, prepend to up-one
1837         path = Form("../%s", path.Data());
1838       if (gSystem->AccessPathName(path.Data())) { 
1839         // File not accessible 
1840         Warning("SetupExtras", "File %s not accessible", path.Data());
1841         continue;
1842       }
1843       ret.Append(Form("%s ", gSystem->BaseName(obj->GetName())));
1844       gSystem->Exec(Form("ln -s %s .", path.Data()));
1845     }
1846     ret = ret.Strip();
1847     return ret;
1848   }
1849   //------------------------------------------------------------------
1850   /** 
1851    * Set-up sources for upload 
1852    * 
1853    * 
1854    * @return String of sources 
1855    */
1856   TString SetupSources()
1857   {
1858     TString nam = EscapedName();
1859     TString ret;
1860     TIter next(&fListOfSources); 
1861     TObject* src;
1862     while ((src = next())) {
1863       TString path = gSystem->ExpandPathName(src->GetName());
1864       if (!path.BeginsWith("/")) 
1865         // If not an absolute path, prepend to up-one
1866         path = Form("../%s", path.Data());
1867       if (gSystem->AccessPathName(path.Data())) { 
1868         // File not accessible 
1869         Warning("SetupSources", "File %s not accessible", path.Data());
1870         continue;
1871       }
1872       ret.Append(Form("%s ", gSystem->BaseName(src->GetName())));
1873       gSystem->Exec(Form("ln -s %s .", path.Data()));
1874     }
1875     ret = ret.Strip();
1876     return ret;
1877   }
1878   //------------------------------------------------------------------
1879   /** 
1880    * Set-up extra libraries to upload 
1881    * 
1882    * @return String of libraries 
1883    */
1884   TString SetupLibraries()
1885   {
1886     TString ret;
1887     TIter next(&fListOfLibraries); 
1888     TObject* lib;
1889     while ((lib = next())) {
1890       ret.Append(lib->GetName());
1891       ret.Append(" ");
1892     }
1893     // Also add extra files to this variable 
1894     ret.Append(SetupExtras());
1895     ret = ret.Strip();
1896     return ret;
1897   }
1898   /* @} */
1899
1900   //__________________________________________________________________
1901   /** 
1902    * @{ 
1903    * @name Chain building 
1904    */
1905   /** 
1906    * Check if we can add a file to the chain 
1907    * 
1908    * @param path   Full path to file 
1909    * @param chain  Chain 
1910    * 
1911    * @return true on success, false otherwise
1912    */
1913   Bool_t CheckFile(const TString& path, TChain* chain)
1914   {
1915     TFile* test = TFile::Open(path, "READ");
1916     if (!test) { 
1917       Warning("CheckFile", "Failed to open %s", path.Data());
1918       return false;
1919     }
1920
1921     Bool_t ok = false; // Assume failure
1922     TObject* o = test->Get(chain->GetName());
1923     if (!o) 
1924       Warning("CheckFile", "The file %s does not contain the object %s", 
1925               path.Data(), chain->GetName());
1926     else if (!dynamic_cast<TTree*>(o)) 
1927       Warning("CheckFile", "Object %s found in %s is not a TTree", 
1928               o->GetName(), path.Data());
1929     else 
1930       ok = true;
1931     test->Close();
1932     if (ok) chain->AddFile(path);
1933
1934     return ok;
1935   }
1936   /** 
1937    * Scan directory @a dir (possibly recursive) for tree files to add
1938    * to the chain.    This does not follow sym-links
1939    * 
1940    * @param dir        Directory to scan
1941    * @param chain      Chain to add to
1942    * @param recursive  Whether to scan recursively 
1943    *
1944    * @return true if any files where added 
1945    */
1946   Bool_t ScanDirectory(TSystemDirectory* dir, TChain* chain, 
1947                        bool recursive)
1948   {
1949     TString fnPattern;
1950     switch (fExecType) { 
1951     case kESD:  fnPattern = "AliESD"; break;
1952     case kAOD:  fnPattern = "AliAOD"; break;
1953     case kUser: fnPattern = "";       break;
1954     }
1955
1956     // Assume failure 
1957     Bool_t ret = false;
1958
1959     // Get list of files, and go back to old working directory
1960     TString oldDir(gSystem->WorkingDirectory());
1961     TList*  files = dir->GetListOfFiles();
1962     if (!gSystem->ChangeDirectory(oldDir)) { 
1963       Error("ScanDirectory", "Failed to go back to %s", oldDir.Data());
1964       return false;
1965     }
1966     if (!files) return false;
1967
1968     TList toAdd;
1969     toAdd.SetOwner();
1970     Bool_t hasGAlice = (!fMC ? true : false);
1971     Bool_t hasKine   = (!fMC ? true : false);
1972     Bool_t hasTrRef  = (!fMC ? true : false);
1973     
1974     // Sort list of files and check if we should add it 
1975     files->Sort();
1976     TIter next(files);
1977     TSystemFile* file = 0;
1978     while ((file = static_cast<TSystemFile*>(next()))) {
1979       TString name(file->GetName());
1980       TString title(file->GetTitle());
1981       TString full(gSystem->ConcatFileName(file->GetTitle(), name.Data()));
1982       if (dynamic_cast<TSystemDirectory*>(file)) full = title;
1983       // Ignore special links 
1984       if (name == "." || name == "..") { 
1985         // Info("ScanDirectory", "Ignoring %s", name.Data());
1986         continue;
1987       }
1988
1989       FileStat_t fs;
1990       if (gSystem->GetPathInfo(full.Data(), fs)) {
1991         Warning("ScanDirectory", "Cannot stat %s (%s)", full.Data(),
1992                 gSystem->WorkingDirectory());
1993         continue;
1994       }
1995       // Check if this is a directory 
1996       if (file->IsDirectory(full)) { 
1997         if (recursive) {
1998           // if (title[0] == '/') 
1999           TSystemDirectory* d = new TSystemDirectory(file->GetName(),
2000                                                      full.Data());
2001           if (ScanDirectory(d,chain,recursive))
2002             ret = true;
2003           delete d;
2004         }
2005         continue;
2006       }
2007     
2008       // If this is not a root file, ignore 
2009       if (!name.EndsWith(".root")) continue;
2010
2011       // If this file does not contain AliESDs, ignore 
2012       if (!name.Contains(fnPattern)) { 
2013         // Info("ScanDirectory", "%s does not match pattern %s", 
2014         //      name.Data(), fnPattern.Data());
2015         if (fMC) { 
2016           if (name.CompareTo("galice.root") == 0)     hasGAlice = true;
2017           if (name.CompareTo("Kinematics.root") == 0) hasKine   = true;
2018           if (name.CompareTo("TrackRefs.root")  == 0) hasTrRef = true;
2019         }
2020         continue;
2021       }
2022     
2023       // Add 
2024       // Info("ScanDirectory", "Adding %s", full.Data());
2025       toAdd.Add(new TObjString(full));
2026     }
2027
2028     if (fMC && toAdd.GetEntries() > 0 && 
2029         (!hasGAlice || !hasKine || !hasTrRef)) { 
2030       Warning("ScanDirectory", 
2031               "one or more of {galice,Kinematics,TrackRefs}.root missing from "
2032               "%s, not adding anything from this directory", 
2033               dir->GetTitle());
2034       toAdd.Delete();
2035     }
2036
2037     TIter nextAdd(&toAdd);
2038     TObjString* s = 0;
2039     Int_t added = 0;
2040     while ((s = static_cast<TObjString*>(nextAdd()))) {
2041       // Info("ScanDirectory", "Adding %s", s->GetString().Data());
2042       TString fn = s->GetString();
2043       if (!CheckFile(fn, chain)) continue;
2044
2045       added++;
2046     }
2047     if (added > 0) ret = true;
2048
2049     gSystem->ChangeDirectory(oldDir);
2050     return ret;
2051   }
2052   //------------------------------------------------------------------
2053   /** 
2054    * Create a chain from an XML containing an collection
2055    * 
2056    * @param treeName Name of tree's 
2057    * @param xmlFile  XML collection
2058    * 
2059    * @return Newly allocated chain or null
2060    */
2061   TChain* CreateChainFromXML(const char* treeName, 
2062                              const char* xmlFile) 
2063   {
2064     TGridCollection* collection = TAlienCollection::Open(xmlFile);
2065     if (!collection) { 
2066       Error("CreateChainFromXML", "Cannot create AliEn collection from "
2067             "XML file %s", xmlFile);
2068       return 0;
2069     }
2070
2071     TChain* chain = new TChain(treeName);
2072     collection->Reset();
2073     while (collection->Next()) chain->Add(collection->GetTURL(""));
2074     
2075     return chain;
2076   }
2077   //------------------------------------------------------------------
2078   /** 
2079    * Create a chain of data 
2080    *
2081    * @return TChain of data 
2082    */    
2083   TChain* CreateChain()
2084   {
2085     TString treeName;
2086     switch (fExecType) { 
2087     case kESD:  treeName = "esdTree"; break;
2088     case kAOD:  treeName = "aodTree"; break;
2089     case kUser: treeName = "";        break;
2090     }
2091
2092     TChain* chain = 0;
2093     switch (fExecMode) { 
2094     case kProof: 
2095       if (!fDataSet.IsNull()) break; 
2096       // Otherwise fall through
2097     case kLocal:
2098       if (fXML.IsNull()) {
2099         chain = new TChain(treeName.Data());
2100         TString dir(fDataDir);
2101         if (dir == ".") dir = "";
2102         if (!dir.BeginsWith("/")) dir = Form("../%s", dir.Data());
2103         FileStat_t stat; 
2104         gSystem->GetPathInfo(dir, stat);
2105         if (!R_ISDIR(stat.fMode)) { // A file, check it 
2106           if (!CheckFile(dir, chain)) { 
2107             delete chain;
2108             chain = 0;
2109           }
2110           break;
2111         }
2112         TString savdir(gSystem->WorkingDirectory());
2113         TSystemDirectory d(gSystem->BaseName(dir.Data()), dir.Data());
2114         if (!ScanDirectory(&d, chain, true)) { 
2115           delete chain;
2116           chain = 0;
2117         }
2118         gSystem->ChangeDirectory(savdir);
2119       }
2120       else 
2121         chain = CreateChainFromXML(treeName.Data(), fXML.Data());
2122       break;
2123     case kGrid:  break; // Do nothing - we use plugin
2124     }
2125     
2126     if (chain && chain->GetNtrees() <= 0) { 
2127       delete chain;
2128       return 0;
2129     }
2130     return chain;
2131   }
2132   /* @} */
2133
2134 public:
2135   //====================================================================
2136   /**
2137    * Option class 
2138    * 
2139    */
2140   struct Option
2141   {
2142     /** 
2143      * Constructor 
2144      * 
2145      * @param name Option name
2146      * @param desc Option description 
2147      * @param arg  Option argument, if any
2148      */
2149     Option(const char* name, const char* desc, const char* arg="")
2150       : fName(name),
2151         fDesc(desc),
2152         fArg(arg),
2153         fIsSet(false),
2154         fValue("")
2155     {}
2156     /** 
2157      * Process an option string. 
2158      * 
2159      * @param opt String to process
2160      * 
2161      * @return true, if this handled the option, false otherwise
2162      */
2163     Bool_t Process(const TString& opt)
2164     {
2165       // Info("Option::Process", "Option %s processing %s",
2166       //      fName.Data(), opt.Data());
2167       if (!opt.BeginsWith(fName, TString::kIgnoreCase)) return false;
2168
2169       // We've got a value 
2170       fIsSet = true;
2171     
2172       // No argument options shouldn't set a value 
2173       if (fArg.IsNull()) return true;
2174
2175       // Parse out value 
2176       Int_t eq = opt.Index("=");
2177
2178       // Empty string is an OK value 
2179       if (eq == kNPOS) return true;
2180
2181       TString tmp = opt(eq+1,opt.Length()-eq-1);
2182       fValue = tmp.Strip();
2183     
2184       return true;
2185     }
2186     /** 
2187      * Get option value as a string 
2188      * 
2189      * @return Option value
2190      */
2191     const TString& AsString() const { return fValue; } 
2192     /** 
2193      * Get option value as a double
2194      * 
2195      * @return Option value
2196      */
2197     Double_t AsDouble() const { return fValue.Atof(); }
2198     /** 
2199      * Get option value as an integer 
2200      * 
2201      * @return Option value
2202      */
2203     Int_t AsInt() const { return fValue.Atoi(); } 
2204     /** 
2205      * Get option value as a boolean
2206      * 
2207      * @return Option value
2208      */
2209     Bool_t   AsBool() const { return fIsSet; }
2210     /** 
2211      * Test if the option has been set.
2212      * 
2213      * @return True if the option was given
2214      */
2215     Bool_t   IsSet() const { return fIsSet; }
2216     /** 
2217      * Print help. 
2218      * 
2219      * @param o Stream to write on
2220      * @param prefix Prefix
2221      */
2222     void PrintHelp(std::ostream& o, const char* prefix) const 
2223     {
2224       TString arg(fName);
2225       if (!fArg.IsNull()) arg.Append(Form("=%s", fArg.Data()));
2226       o << "  " << (prefix ? prefix : "") 
2227         << std::left << std::setw(30) << arg 
2228         << " " << fDesc << std::endl;
2229     }
2230     /** 
2231      * Print the setting 
2232      * 
2233      * @param o Stream to write on
2234      */
2235     void PrintSettings(std::ostream& o) const 
2236     {
2237       o << "  " << std::left << std::setw(30) << fName << ": ";
2238       if (fArg.IsNull()) o << (IsSet() ? "true" : "false");
2239       else               o << fValue;
2240       o << std::endl;
2241     }
2242     /** 
2243      * Save the setting 
2244      * 
2245      * @param str  object nmae 
2246      * @param val  Value
2247      * @param o Stream to write on
2248      */
2249     void Save(std::ostream& o, const char* str, bool val)
2250     {
2251       if (!val) return;
2252       if (str[0] == '-') {
2253         o << "  " << str << fName << " \\" << std::endl;
2254         return;
2255       }
2256       o << "  " << str << ".Append(\"" << fName <<  ",\");" << std::endl;
2257     }
2258     /** 
2259      * Save the setting 
2260      * 
2261      * @param str  object nmae 
2262      * @param val  Value
2263      * @param o Stream to write on
2264      */
2265     void Save(std::ostream& o, const char* str, Int_t val)
2266     {
2267       if (str[0] == '-') { 
2268         o << "  " << str << fName << "=" << val << " \\" << std::endl;
2269         return;
2270       }
2271       o << "  " << str << ".Append(\"" << fName <<  "=" << val 
2272         << ",\");" << std::endl;
2273     }
2274     /** 
2275      * Save the setting 
2276      * 
2277      * @param str  object nmae 
2278      * @param val  Value
2279      * @param o Stream to write on
2280      */
2281     void Save(std::ostream& o, const char* str, Double_t val)
2282     {
2283       if (str[0] == '-') { 
2284         o << "  " << str << fName << "=" << val << "  \\" << std::endl;
2285         return;
2286       }
2287       o << "  " << str << ".Append(\"" << fName <<  "=" << val 
2288         << ",\");" << std::endl;
2289     }
2290     /** 
2291      * Save the setting 
2292      * 
2293      * @param str  object nmae 
2294      * @param val  Value
2295      * @param o Stream to write on
2296      */
2297     void Save(std::ostream& o, const char* str, const char* val)
2298     {
2299       if (str[0] == '-') { 
2300         TString sval(val);
2301         sval.ReplaceAll(" ", "\\ ");
2302         o << "  " << str << fName << "=" << sval << " \\" << std::endl;
2303         return;
2304       }
2305       o << "  " << str << ".Append(\"" << fName <<  "=" << val 
2306         << ",\");" << std::endl;
2307     }
2308
2309     TString fName;  // Name of the option 
2310     TString fDesc;  // Decription 
2311     TString fArg;   // Argument, if any
2312     Bool_t  fIsSet; // Whether the option has been set.
2313     TString fValue; // Value of the option. 
2314   };
2315   //====================================================================
2316   /**
2317    * Run a train setup
2318    * 
2319    */
2320   struct Runner 
2321   {
2322     /** 
2323      * Constructor 
2324      * 
2325      * @param train Train to run 
2326      * @param max   Maximum number of options
2327      */
2328     Runner(TrainSetup& train, UShort_t max=30)
2329       : fTrain(&train), fOptions(0), fN(0), fMax(max)
2330     {
2331       fOptions = new Option*[fMax];
2332       for (Int_t i = 0; i < fMax; i++) fOptions[i] = 0;
2333     }
2334     /** 
2335      * Add an option 
2336      * 
2337      * @param opt Option to add 
2338      */
2339     void Add(Option* opt)
2340     {
2341       if (fN >= fMax) {
2342         Warning("AddOption", "No room for option %s", opt->fName.Data());
2343         return;
2344       }
2345       fOptions[fN++] = opt;
2346     }
2347     /** 
2348      * Remove an option
2349      * 
2350      * @param name 
2351      */
2352     void Remove(const TString& name)
2353     {
2354       Option** ptr = fOptions;
2355       Option** tmp = 0;
2356       while (*ptr) { 
2357         if (name.EqualTo((*ptr)->fName)) {
2358           tmp = ptr;
2359           break;
2360         }
2361         ptr++;
2362       }
2363       if (!tmp) // nothing found, returning 
2364         return;
2365       
2366       ptr = tmp;
2367       delete *tmp;
2368       tmp++;
2369       fN--;
2370       while (*tmp) { 
2371         *ptr = *tmp;
2372         ptr++;
2373         tmp++;
2374       }
2375       *ptr = 0;
2376     }
2377
2378     /** 
2379      * Parse option string 
2380      * 
2381      * @param options Option string. 
2382      * @param delim   Delimiters 
2383      * 
2384      * @return true on success. 
2385      */
2386     Bool_t Parse(const TString& options, const char* delim=",;")
2387     {
2388       TObjArray* a = options.Tokenize(delim);
2389       return Parse(*a);
2390     }
2391     /** 
2392      * Parse options 
2393      * 
2394      * @param options 
2395      * 
2396      * @return true on success
2397      */
2398     Bool_t Parse(TObjArray& options) 
2399     {
2400       TIter next(&options);
2401       TObjString* os = 0;
2402       while ((os = static_cast<TObjString*>(next()))) {
2403         TString s(os->String());
2404         // Info("Runner::Parse", "Processing option %s", s.Data());
2405         if (s.IsNull()) continue;
2406
2407         Bool_t   ok  = false;
2408         Option** ptr = fOptions;
2409         while (*ptr && !ok) { 
2410           Option* o = *ptr;
2411           if (o->Process(s)) ok = true;
2412           ptr++;
2413         }
2414         
2415         if (!ok) 
2416           Warning("Parse", "Unknown option %s", s.Data());
2417       }
2418       return true;
2419     }
2420     /** 
2421      * Check if we asked for help 
2422      * 
2423      * 
2424      * @return 
2425      */
2426     Bool_t IsHelpAsked() const 
2427     {
2428       Option* help = FindOption("help");
2429       return (help && help->IsSet());
2430     }
2431     /** 
2432      * Print help
2433      * 
2434      * @param out Stream to write on  
2435      * @param prefix Prefix
2436      */
2437     void PrintHelp(std::ostream& out, const char* prefix="") const
2438     {
2439       Option** ptr = fOptions;
2440       while (*ptr) { 
2441         (*ptr)->PrintHelp(out, prefix);
2442         ptr++;
2443       }
2444     }
2445     /** 
2446      * Print the settings 
2447      * 
2448      * @param out Stream to write on. 
2449      */
2450     void PrintSettings(std::ostream& out) const
2451     {
2452       Option** ptr = fOptions;
2453       while (*ptr) { 
2454         (*ptr)->PrintSettings(out);
2455         ptr++;
2456       }
2457     }
2458     /** 
2459      * Find an option by name 
2460      * 
2461      * @param name Name of option to find
2462      * 
2463      * @return Pointer to option, or null
2464      */
2465     Option* FindOption(const TString& name) const
2466     {
2467       Option** ptr = fOptions;
2468       while (*ptr) { 
2469         if (name.EqualTo((*ptr)->fName)) return *ptr;
2470         ptr++;
2471       }
2472       return 0;
2473     }
2474     /** 
2475      * Initialize the train
2476      * 
2477      * @param options  Execution options 
2478      * 
2479      * @return true on success
2480      */
2481     Bool_t Init(const TString& options)
2482     {
2483       fTrain->MakeOptions(*this);
2484       if (!Parse(options)) return false;
2485       return true;
2486     }
2487     /** 
2488      * Run the train
2489      * 
2490      * @param runs     Run numbers 
2491      * @param nEvents  Number of events
2492      * @param asShell  Save set-up as shell script 
2493      * 
2494      * @return 
2495      */
2496     Bool_t Run(const TString& runs, Int_t nEvents, Bool_t asShell=false)
2497     {
2498       PrintSettings(std::cout);
2499
2500       fTrain->SetOptions(*this);
2501       fTrain->SetRuns(runs);
2502       // fTrain->SaveSetup(*this, nEvents, asShell);
2503       
2504       fTrain->Run(nEvents, this, asShell);
2505       return true;
2506     }
2507       
2508     TrainSetup* fTrain;
2509     Option** fOptions;  // Our options 
2510     UShort_t fN;        // Current number of options 
2511     UShort_t fMax;      // Maximum number of options
2512   };
2513 protected:
2514   //__________________________________________________________________
2515   /** 
2516    * @{ 
2517    * @name Options 
2518    */
2519   /** 
2520    * Class name of this train setup.  Sub-classes must define this. 
2521    * 
2522    * @return Class name of this setup 
2523    */
2524   virtual const char* ClassName() const = 0;
2525   //------------------------------------------------------------------
2526   /** 
2527    * Make the options for this train.  Sub-classes can overload this
2528    * to define new options, or append to the set of default option.
2529    */    
2530   virtual void MakeOptions(Runner& r)
2531   {
2532     r.Add(new Option("help",   "Show this help"));
2533     r.Add(new Option("par",    "Use PAR files (PROOF and Grid)"));
2534     r.Add(new Option("mc",     "Assume simulation input"));
2535     r.Add(new Option("debug",  "Execute in debugger"));
2536     r.Add(new Option("type",   "Type of train",    "AOD|ESD"));
2537     r.Add(new Option("mode",   "Execution mode",   "LOCAL|PROOF|GRID"));
2538     r.Add(new Option("oper",   "Operation mode",   "TEST|TERMINATE|FULL|INIT"));
2539     r.Add(new Option("date",   "Set date string",  "YYYY-MM-DD HH:MM:SS"));
2540     r.Add(new Option("cluster","PROOF cluster",         "HOST"));
2541     r.Add(new Option("dataSet","Data set (PROOF only)", "NAME"));
2542     r.Add(new Option("dataDir","Data directory",        "DIRECTORY"));
2543     r.Add(new Option("pattern","Data pattern (grid only)", "GLOB")); 
2544     r.Add(new Option("verb",   "Verbosity",             "NUMBER")); 
2545     r.Add(new Option("root",   "ROOT version (Grid)",   "TAG")); 
2546     r.Add(new Option("aliroot","AliROOT version (Grid)","TAG")); 
2547     r.Add(new Option("alien",  "AliEn API version (Grid)","TAG")); 
2548     r.Add(new Option("overwrite", "Allow overwrite"));
2549     r.Add(new Option("per-run", "Per run merge"));
2550   } 
2551   //------------------------------------------------------------------
2552   /** 
2553    * Set the option values on the train.  Sub-classes can overload 
2554    * this to set custom options on the train. 
2555    */
2556   virtual void SetOptions(Runner& r)
2557   {
2558     Option* debug       = r.FindOption("debug");
2559     Option* date        = r.FindOption("date");
2560     Option* cluster     = r.FindOption("cluster");
2561     Option* dataSet     = r.FindOption("dataSet");
2562     Option* dataDir     = r.FindOption("dataDir");
2563     Option* pattern     = r.FindOption("pattern");
2564     Option* par         = r.FindOption("par");
2565     Option* type        = r.FindOption("type");
2566     Option* mode        = r.FindOption("mode");
2567     Option* oper        = r.FindOption("oper");
2568     Option* mc          = r.FindOption("mc");
2569     Option* verb        = r.FindOption("verb");
2570     Option* root        = r.FindOption("root");
2571     Option* aliroot     = r.FindOption("aliroot");
2572     Option* alien       = r.FindOption("alien");
2573     Option* overwrite   = r.FindOption("overwrite");
2574     Option* run_merge   = r.FindOption("per-run");
2575     
2576     if (date && date->IsSet()) SetDateTime(date->AsString());
2577     if (cluster)               SetProofServer(cluster->AsString());
2578     if (dataSet)               SetDataSet(dataSet->AsString());
2579     if (dataDir)               SetDataDir(dataDir->AsString());
2580     if (pattern)               SetDataPattern(pattern->AsString());
2581     if (debug)                 SetUseGDB(debug->AsBool());
2582     if (type && type->IsSet()) SetType(type->AsString());
2583     if (mode && mode->IsSet()) SetMode(mode->AsString());
2584     if (oper && oper->IsSet()) SetOperation(oper->AsString());
2585     if (par)                   SetUsePar(par->AsBool());
2586     if (mc)                    SetMC(mc->AsBool());
2587     if (verb)                  SetVerbose(verb->AsInt());
2588     if (root)                  SetROOTVersion(root->AsString());
2589     if (aliroot)               SetAliROOTVersion(aliroot->AsString());
2590     if (alien)                 SetAliEnAPIVersion(alien->AsString());
2591     if (overwrite)             SetAllowOverwrite(overwrite->AsBool());
2592     if (run_merge)             SetPerRunMerge(run_merge->AsBool());
2593   }
2594   //------------------------------------------------------------------
2595   /** 
2596    * Set the option values on the train.  Sub-classes can overload 
2597    * this to set custom options on the train. 
2598    */
2599   virtual void SaveOptions(std::ostream& o, const char* str, Runner& r)
2600   {
2601     Option* debug       = r.FindOption("debug");
2602     Option* date        = r.FindOption("date");
2603     Option* cluster     = r.FindOption("cluster");
2604     Option* dataSet     = r.FindOption("dataSet");
2605     Option* dataDir     = r.FindOption("dataDir");
2606     Option* pattern     = r.FindOption("pattern");
2607     Option* par         = r.FindOption("par");
2608     Option* type        = r.FindOption("type");
2609     Option* mode        = r.FindOption("mode");
2610     Option* oper        = r.FindOption("oper");
2611     Option* mc          = r.FindOption("mc");
2612     Option* verb        = r.FindOption("verb");
2613     Option* root        = r.FindOption("root");
2614     Option* aliroot     = r.FindOption("aliroot");
2615     Option* alien       = r.FindOption("alien");
2616     Option* overwrite   = r.FindOption("overwrite");
2617     Option* run_merge   = r.FindOption("per-run");
2618     
2619     if (date) date->Save(o, str, 
2620                          Form("%04d-%02d-%02d %02d:%02d:00",
2621                               fDatime.GetYear(), 
2622                               fDatime.GetMonth(), 
2623                               fDatime.GetDay(), 
2624                               fDatime.GetHour(),
2625                               fDatime.GetMinute()));
2626     if (cluster)  cluster->Save(o, str, fProofServer);
2627     if (dataSet)  dataSet->Save(o, str, fDataSet);
2628     if (dataDir)  dataDir->Save(o, str, fDataDir);
2629     if (pattern)  pattern->Save(o, str, fDataPattern);
2630     if (debug)    debug->Save(o, str, fUseGDB);
2631     if (type)     type->Save(o, str, TypeString(fExecType));
2632     if (mode)     mode->Save(o, str, ModeString(fExecMode));
2633     if (oper)     oper->Save(o, str, OperString(fExecOper));
2634     if (par)      par->Save(o, str, fUsePar);
2635     if (mc)       mc->Save(o, str, fMC);
2636     if (verb)     verb->Save(o, str, fVerbose);
2637     if (root)     root->Save(o, str, fRootVersion);
2638     if (aliroot)  aliroot->Save(o, str, fAliRootVersion);
2639     if (alien)    alien->Save(o, str, fAliEnAPIVersion);
2640     if (overwrite)overwrite->Save(o, str, fAllowOverwrite);
2641     if (run_merge)run_merge->Save(o, str, fPerRunMerge);
2642   }
2643   /** 
2644    * Save the setup to file for later re-execution 
2645    * 
2646    * @param r         Runner object 
2647    * @param nEvents   Number of events 
2648    * @param asShell   If true, save as shell script - otherwise ROOT script
2649    */
2650   virtual void SaveSetup(Runner& r, Int_t nEvents, Bool_t asShell=false)
2651   {
2652     if (asShell) SaveSetupShell(r, nEvents); 
2653     /* else */   SaveSetupROOT(r, nEvents);
2654   }
2655   /** 
2656    * Save the setup to shell script for later re-execution 
2657    * 
2658    * @param r         Runner object 
2659    * @param nEvents   Number of events 
2660    */
2661   virtual void SaveSetupShell(Runner& r, Int_t nEvents)
2662   {
2663     std::ofstream o("rerun.sh");
2664     o << "#!/bin/bash\n\n"
2665       << "oper=$1\n"
2666       << "if test x$oper = x ; then oper=full ; fi \n\n"
2667       << "class=\"" << ClassName() << "\"\n"
2668       << "name=\"" << fName << "\"\n"
2669       << "nev=" << nEvents << "\n\n"
2670       << "opts=(--class=$class \\\n"
2671       << "  --name=$name \\\n"
2672       << "  --events=$nev \\" << std::endl;
2673     for (Int_t i = 0; i < fRunNumbers.GetSize(); i++) 
2674       o << "  --run=" << fRunNumbers.At(i) << " \\\n";
2675     SaveOptions(o, "--", r);
2676     o << "  --oper=$oper)\n\n"
2677       << "echo \"Running runTrain ${opts[@]}\"\n"
2678       << "runTrain \"${opts[@]}\"\n\n"
2679       << "# EOF" << std::endl;
2680     o.close();
2681     gSystem->Exec("chmod a+x rerun.sh");
2682   }
2683   /** 
2684    * Save the setup to shell script for later re-execution 
2685    * 
2686    * @param r         Runner object 
2687    * @param nEvents   Number of events 
2688    */
2689   virtual void SaveSetupROOT(Runner& r, Int_t nEvents) 
2690   {
2691     std::ofstream o("rerun.C");
2692     o << "void rerun(bool terminate=false)\n"
2693       << "{\n" 
2694       << "  TString opts;" << std::endl;
2695     SaveOptions(o, "opts", r);
2696       
2697     o << "  if (terminate) opts.Append(\"mode=terminate;\");\n\n"
2698       << "  TString runs(\"";
2699     for (Int_t i = 0; i < fRunNumbers.GetSize(); i++) 
2700       o << (i == 0 ? "" : ", ") << fRunNumbers.At(i);
2701     o << "\");\n\n"
2702       << "  Int_t   nEvents = " << nEvents << ";\n\n"
2703       << "  gROOT->LoadMacro(\"$ALICE_ROOT/PWGLF/FORWARD/analysis2/trains/RunTrain.C\");\n"
2704       << "  RunTrain(\"" << ClassName() << "\",\"" 
2705       << fName << "\",opts,runs,nEvents);\n"
2706       << "}\n"
2707       << "// EOF" << std::endl;
2708     o.close();
2709   }
2710   /* @} */
2711
2712   //__________________________________________________________________
2713   TString fName;             // Name of analysis
2714   TString fEscapedName;      // Name escaped for special chars
2715   TString fRootVersion;      // ROOT version to use 
2716   TString fAliRootVersion;   // AliROOT version to use 
2717   TString fAliEnAPIVersion;  // AliEn API version to use 
2718   TString fProofServer;      // Name of proof server
2719   TString fDataDir;          // Grid Input directory 
2720   TString fDataPattern;      // Data directory pattern
2721   TString fDataSet;          // Proof data set name 
2722   TString fXML;              // XML collection for local/proof mode
2723   Int_t   fNReplica;         // Storage replication
2724   Bool_t  fAllowOverwrite;   // Allow overwriting output dir
2725   Bool_t  fUseGDB;           // Wrap PROOF slaves in GDB 
2726   Int_t   fMaxSplit;         // Maximum number of files per split
2727   TArrayI fRunNumbers;       // List of run number 
2728   TList   fListOfPARs;       // List of PAR files to use 
2729   TList   fListOfSources;    // List of sources to upload and AcLIC
2730   TList   fListOfLibraries;  // List of libraries to load
2731   TList   fListOfExtras;     // List of extra files to upload
2732   TDatime fDatime;           // Date and time 
2733   EType   fExecType;         // Execution type (ESD, AOD)
2734   EMode   fExecMode;         // Execution mode (PROOF, local, Grid)
2735   EOper   fExecOper;         // Execution operation (full, terminate, ...)
2736   Bool_t  fUsePar;           // Wether to use PAR files 
2737   Bool_t  fMC;               // Whether to assume MC input 
2738   Bool_t  fPerRunMerge;      // Whether to merge per run or over-all
2739   Int_t   fVerbose;          // Verbosity level 
2740 };
2741   
2742 //____________________________________________________________________
2743 //
2744 // EOF
2745 //