Various fixes
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / trains / Helper.C
1 /**
2  * @defgroup pwglf_forward_trains_helper Analysis helpers
3  *
4  * @ingroup pwglf_forward_trains
5  * 
6  * 
7  */
8 /**
9  * @file   Helper.C
10  * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
11  * @date   Tue Oct 16 19:00:17 2012
12  * 
13  * @brief  Base class for analysis helpers
14  * 
15  * @ingroup pwglf_forward_trains_helper
16  * 
17  */
18 #ifndef TRAIN_HELPER_C
19 #define TRAIN_HELPER_C
20 #ifndef __CINT__
21 # include "Option.C"
22 # include <TUrl.h>
23 # include <TString.h>
24 # include <TMap.h>
25 # include <TObjString.h>
26 # include <TSystem.h>
27 # include <TROOT.h>
28 # include <TError.h>
29 # include <TObjArray.h>
30 # include <AliAnalysisManager.h>
31 # include <iostream>
32 #else 
33 class TString;
34 class TUrl;
35 class TMap;
36 class Option;
37 class OptionList;
38 #endif
39
40 /**
41  * Helper class to set-up an analysis using a train 
42  *
43  * @ingroup pwglf_forward_trains_helper
44  */
45 struct Helper 
46 {
47   enum EMode { 
48     kLocal, 
49     kProof, 
50     kGrid
51   };
52   enum EOperation { 
53     kTest,
54     kOffline,
55     kSubmit,
56     kTerminate, 
57     kFull
58   };
59   enum EInput { 
60     kESD, 
61     kAOD, 
62     kUser
63   };
64   Helper(const Helper& o) 
65     : fUrl(o.fUrl), fOptions(o.fOptions), fVerbose(o.fVerbose)
66   {}
67   Helper& operator=(const Helper&) { return *this; }
68   /** 
69    * Create a helper object. 
70    * 
71    * @param url Url describing the job. 
72    *
73    * - Local mode: 
74    *
75    * @code
76    * local://<path>[#<treeName>][?[recursive[&]]]
77    * @endcode 
78    *
79    * &lt;path&gt; can be a single ROOT file, a text file with one
80    * entry per file to add to the chain, or a directory containing the
81    * files. If &lt;path&gt; does not start with a '/' then it is
82    * interpreted as a relative path.
83    *
84    * - Grid mode: 
85    *
86    * @code 
87    * alien:///<path>#<pattern>
88    * @endcode
89    *
90    * - PROOF mode: 
91    * 
92    * Several options 
93    *
94    * @code 
95    * lite:///<path>[?[recursive[&]][workers=<n>]][#treeName]
96    * proof:///<path>[?[recursive[&]][workers=<n>]][#treeName]
97    * @endcode 
98    *
99    * @code 
100    * proof://<host>/<dsname>[?[workers=<n>[&]][dsname[=<outname>]]][#treeName]
101    * @endcode 
102    *
103    * Note, if &lt;host&gt; is recognised as an Alice Analysis
104    * Facility, then the Grid handler (AliAnalysisAlien) is used unless
105    * the option <tt>plain</tt> was given. 
106    * 
107    * @return Newly allocated helper or null 
108    */
109   static Helper* Create(const TUrl& url, Int_t verbose=0);
110   /** 
111    * Load a library 
112    * 
113    * @param name   Name of library 
114    * @param slave  If true also load on slaves
115    * 
116    * @return true on success, false otherwise 
117    */
118   virtual Bool_t LoadLibrary(const TString& name, 
119                              Bool_t slave=true) = 0;
120   /** 
121    * Load a source file, and compile it 
122    * 
123    * @param name Name of the source file 
124    * 
125    * @return true on success
126    */
127   virtual Bool_t LoadSource(const TString& name)
128   {
129     if (!AuxFile(name)) return false;
130     TString base(gSystem->BaseName(name));
131     gROOT->LoadMacro(Form("%s++g", base.Data()));
132     return true;
133   }
134   /** 
135    * Load auxillary file - not compiled or sourced.  Just copied to
136    * working directory
137    * 
138    * @param name Extra file name 
139    *
140    * @return true on success 
141    */
142   virtual Bool_t LoadAux(const TString& name)
143   {
144     if (!AuxFile(name)) return false;
145     return true;
146   }
147
148   /** 
149    * Load needed ROOT libaries 
150    */
151   virtual Bool_t LoadROOT()
152   {
153     if (gSystem->Load("libTree.so")    < 0) return false;
154     if (gSystem->Load("libGeom.so")    < 0) return false;
155     if (gSystem->Load("libVMC.so")     < 0) return false;
156     if (gSystem->Load("libPhysics.so") < 0) return false;
157     if (gSystem->Load("libMinuit.so")  < 0) return false;
158     return true;
159   }
160   /** 
161    * Set-up to load the AliROOT libraries 
162    * 
163    * @param par Whether to use PAR files 
164    * 
165    * @return true on success
166    */
167   virtual Bool_t LoadAliROOT()
168   {
169     if (!gSystem->Getenv("ALICE_ROOT")) { 
170       Error("Helper::LoadAliROOT", "Local AliROOT not available");
171       return false;
172     }
173     if (!LoadLibrary("STEERBase"))     return false;
174     if (!LoadLibrary("ESD"))           return false;
175     if (!LoadLibrary("AOD"))           return false;
176     if (!LoadLibrary("ANALYSIS"))      return false;
177     if (!LoadLibrary("OADB"))          return false;
178     if (!LoadLibrary("ANALYSISalice")) return false;
179     return true;
180   }
181   /** 
182    * Get the execution mode 
183    * 
184    * @return Execution mode set in set-up URL
185    */
186   virtual UShort_t Mode() const = 0;
187   /** 
188    * Get the operation - this only makes sense for Grid jobs
189    * 
190    * @return Operation type
191    */
192   virtual UShort_t Operation() const { return kFull; }
193   /** 
194    * Get the input data type 
195    *
196    * @return Input data type 
197    */
198   virtual Short_t InputType() const
199   {
200     UShort_t ret = DeduceType(fUrl.GetAnchor());
201     if (ret != kUser) return ret;
202
203     if (fOptions.Has("pattern")) ret = DeduceType(fOptions.Get("pattern"));
204     if (ret != kUser) return ret;
205     
206     ret = DeduceType(fUrl.GetFile());
207     return ret;
208   }
209   /** 
210    * The file part of tehe output URL - overwritten by derived classes. 
211    * 
212    * 
213    * @return File part of output URL
214    */
215   virtual TString OutputPath() const { return ""; }
216   /** 
217    * Get the location of the output data.  Use ful to define second pass 
218    * scripts, etc. 
219    * 
220    * 
221    * @return Url string 
222    */
223   virtual TString OutputLocation() const 
224   {
225     AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
226     if (!mgr || !mgr->GetOutputEventHandler()) return "";
227
228     TString path(OutputPath());
229     if (path.IsNull()) {
230       path = gSystem->WorkingDirectory(); 
231       // mgr->GetName();
232     }
233
234     TUrl u(fUrl);
235     u.SetFile(path);
236     u.SetAnchor("aodTree");
237     TString opt(u.GetOptions());
238     opt.ReplaceAll("AliESDs", "AliAOD");
239     u.SetOptions(opt);
240
241     return u.GetUrl();
242   }
243   /** 
244    * Set-up done before task setup 
245    * 
246    * @return true on success
247    */
248   virtual Bool_t PreSetup() = 0;
249   /** 
250    * Set-up done after task setup 
251    * 
252    * @return true on success
253    */
254   virtual Bool_t PostSetup() = 0;
255   /** 
256    * Run the analysis
257    * 
258    * @param nEvents Number of events to analyse 
259    * 
260    * @return The return value of AliAnalysisManager::StartAnalysis
261    */
262   virtual Long64_t Run(Long64_t nEvents=-1) = 0;
263   /** 
264    * Print information to standard output 
265    * 
266    * @param option 
267    * 
268    * @return 
269    */
270   virtual void Print(Option_t* ="") const
271   {
272     std::cout << "Url: " << fUrl.GetUrl() << std::endl;
273     fOptions.Show(std::cout);
274   }
275   /** 
276    * @return URL help string 
277    */
278   virtual const Char_t* UrlHelp() const  = 0;
279   /** 
280    * @return Short description string 
281    */
282   virtual const char* Desc() const = 0;
283   /** 
284    * Get the input URL 
285    * 
286    * @return Input URL 
287    */
288   const TUrl& Url() const { return fUrl; }
289   /** 
290    * Get the list of options 
291    * 
292    * @return Reference to list of options 
293    */
294   const OptionList& Options() const { return fOptions; }
295   /** 
296    * Create an instance of a helper class 
297    */
298   static Helper* CreateObject(const TString& cl, 
299                               const TUrl&    url, 
300                               Int_t verbose=0)
301   {
302     if (verbose > 3) gSystem->RedirectOutput("/dev/null","w");
303     if (cl.Contains("proof", TString::kIgnoreCase) || 
304         cl.Contains("lite",  TString::kIgnoreCase) || 
305         cl.Contains("aaf",   TString::kIgnoreCase)) {
306       gSystem->Load("libProof");
307       gSystem->Load("libProofPlayer");
308     }
309     // Always recompile and with debug symbols 
310     gROOT->LoadMacro(Form("%s.C++g",cl.Data()));
311     Long_t ptr = gROOT->ProcessLine(Form("new %s(\"%s\", %d);", 
312                                          cl.Data(), url.GetUrl(), verbose));
313     if (verbose > 3) gSystem->RedirectOutput(0);
314     if (!ptr) { 
315       Warning("Helper::CreateObject", "Failed to instantize a %s", cl.Data());
316       return 0;
317     }
318     Helper* h = reinterpret_cast<Helper*>(ptr);
319     return h;
320   }
321   /** 
322    * Show help on URL using the interpreter 
323    * 
324    * @param cl Helper class 
325    */
326   static void ShowUrlHelp(const TString& cl)
327   {
328     Helper* h = CreateObject(cl, "", true);
329     if (!h) return;
330
331     std::cout << "   " << h->UrlHelp() << std::endl;
332   }
333   /** 
334    * Show help on URL and options using the interpreter 
335    * 
336    * @param cl Helper class 
337    */
338   static void ShowFullHelp(const TString& cl) 
339   {
340     Helper* h = CreateObject(cl, "", true);
341     if (!h) return;
342     
343     std::cout << h->Desc() << ":\n" 
344               << "==============\n"
345               << "  " << h->UrlHelp() << "\n\n"
346               << "Options: " << std::endl;
347     h->Options().Help(std::cout);
348     std::cout << std::endl;
349   }
350 protected:
351   /** 
352    * Constructor 
353    * 
354    * @param url Set-up URL
355    * @param opts Pre-parsed options 
356    */
357   Helper(const TUrl& url, Int_t verbose) 
358     : fUrl(url), fOptions(), fVerbose(verbose)
359   {
360   }
361
362   virtual Bool_t ParseOptions()
363   {
364     return fOptions.Parse(fUrl.GetOptions(), "&");
365   }
366   /** 
367    * Destructor 
368    */
369   virtual ~Helper()
370   {
371   }
372   /** 
373    * Normalize a library name
374    * 
375    * @param name 
376    * 
377    * @return 
378    */
379   const TString& MakeLibraryName(const TString& name)
380   {
381     static TString libName;
382
383     libName = name;
384
385     if (!libName.BeginsWith("lib")) { 
386       // Check if the library corresponds to a compiled macro 
387       if (!gSystem->AccessPathName(Form("%s_C.so", libName.Data()))) 
388         libName.Append("_C");
389       else if (!gSystem->AccessPathName(Form("../%s_C.so", libName.Data()))) 
390         libName = Form("../%s_C", libName.Data());
391       else 
392         libName = Form("lib%s", libName.Data());
393     }
394     if (!libName.EndsWith(".so"))   libName.Append(".so");
395
396     return libName;
397   }
398   /** 
399    * Link an auxilary file to working directory 
400    * 
401    * @param name Name of the file
402    * 
403    * @return true on success
404    */
405   virtual Bool_t AuxFile(const TString& name)
406   {
407     TString path(gSystem->ExpandPathName(name.Data()));
408     // If not absolute, prepend up-one
409     if (!path.BeginsWith("/")) path.Prepend("../");
410     if (gSystem->AccessPathName(path.Data())) { 
411       // File not accessible
412       Warning("Helper::AuxFile", "File %s not accessible", path.Data());
413       return false;
414     }
415     TString base(gSystem->BaseName(path.Data()));
416     if (gSystem->AccessPathName(base.Data()) == 0) { 
417       // File or link exists - remove it 
418       if (gSystem->Unlink(base) != 0) { 
419         Error("Helper::AuxFile", "Failed to remove old %s", base.Data());
420         return false;
421       }
422     }
423     gSystem->Exec(Form("ln -s %s .", path.Data()));
424     return true;
425   }
426   /** 
427    * Deduce the top of job from a string 
428    * 
429    * @param str String 
430    * 
431    * @return Job type
432    */
433   static UShort_t DeduceType(const TString& str)
434   {
435     if (str.IsNull()) return kUser;
436     if (str.Contains("aod", TString::kIgnoreCase)) return kAOD;
437     if (str.Contains("esd", TString::kIgnoreCase)) return kESD;
438     return kUser;
439   }
440   // --- Data members ------------------------------------------------
441   TUrl        fUrl;     // The URI
442   OptionList  fOptions; 
443   Int_t       fVerbose;
444 };
445
446
447
448
449 // ===================================================================
450 Helper* 
451 Helper::Create(const TUrl& url, Int_t verbose)
452 {
453   if (!url.IsValid()) { 
454     Warning("Helper::Create", "URL is invalid");
455     return 0;
456   }
457
458   TString prot(url.GetProtocol());
459   prot.ToLower();
460
461   TUrl tmp(url);
462   TString opts(tmp.GetOptions());
463   TString host(url.GetHost());
464   TString cl = "";
465   if (prot.EqualTo("alien")) { 
466     // Create an AliEn helper 
467     cl = "GridHelper";
468   }
469   else if (prot.EqualTo("local")) { 
470     // Create Lite helper 
471     cl = "LocalHelper";
472   }
473   else if (prot.EqualTo("proof")) { 
474     // Create a Proof helper 
475     if (host.IsNull()) 
476       cl = "LiteHelper";
477     else if (host.BeginsWith("alice-caf")) { 
478       // AAF 
479       cl = opts.Contains("plugin") ? "AAFPluginHelper" : "AAFHelper";
480     }
481     else 
482       cl = "ProofHelper";
483   }
484   else if (prot.EqualTo("lite")) { 
485     // Create a Proof helper 
486     cl = "LiteHelper";
487   }
488   else if (prot.EqualTo("help")) {
489     // Special HELP protocol
490     if (host.Contains("options")) {
491       std::cout << "Possible URL types and options are:" << std::endl;
492       ShowFullHelp("LocalHelper");
493       ShowFullHelp("ProofHelper");
494       ShowFullHelp("LiteHelper");
495       ShowFullHelp("AAFHelper");
496       ShowFullHelp("AAFPluginHelper");
497       ShowFullHelp("GridHelper");
498       return 0;
499     }
500     std::cout << "Possible URL types are:" << std::endl;
501     ShowUrlHelp("LocalHelper");
502     ShowUrlHelp("ProofHelper");
503     ShowUrlHelp("LiteHelper");
504     ShowUrlHelp("AAFHelper");
505     ShowUrlHelp("AAFPluginHelper");
506     ShowUrlHelp("GridHelper");
507     return 0;
508   }
509   // --- Check if we got a scheme ------------------------------------
510   if (cl.IsNull()) {
511     Error("Helper::Create", "Unknown scheme: %s", prot.Data());
512     return 0;
513   }
514
515   // --- Use interpreter to make our object --------------------------
516   Helper* helper = CreateObject(cl, url, verbose);
517   if (!helper) {
518     Error("Helper::Create", "Failed to make object of class %s", cl.Data());
519     return 0;
520   }
521
522   // --- Parse options -----------------------------------------------
523   if (!helper->ParseOptions()) {
524     delete helper;
525     helper = 0;
526   }
527
528   return helper;
529 }
530
531 #endif