]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/trains/GridHelper.C
Remove code to dump Job IDs and stages until merged into trunk of AliAnalysisAlien
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / trains / GridHelper.C
1 /**
2  * @file   GridHelper.C
3  * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4  * @date   Tue Oct 16 19:01:27 2012
5  * 
6  * @brief  Grid Analysis Helper
7  * 
8  * @ingroup pwglf_forward_trains_helper
9  * 
10  */
11 #ifndef GRIDHELPER_C
12 #define GRIDHELPER_C
13 #include "PluginHelper.C"
14 #ifndef __CINT__
15 # include <TUrl.h>
16 # include <TString.h>
17 # include <TGrid.h>
18 # include <AliAnalysisManager.h>
19 # include <AliAnalysisAlien.h>
20 #else
21 class TUrl;
22 class AliAnalysisAlien;
23 #endif
24
25 // ===================================================================
26 /**
27  * Handle analysis on an the Grid
28  * 
29  * This helper is triggered by a URL of the form 
30  *
31  * @code
32  * alien:///<directory>[?<options>][#<pattern>]
33  * @endcode 
34  * where 
35  * <dl>
36  *   <dt>&lt;directory@gt;</dt>
37  *   <dd>Grid directory that holds the data</dd>
38  *   <dt>&lt;treeName@gt;</dt>
39  *   <dd>Tree to loop over</dd>
40  *   <dt>&lt;options@gt;</dt>
41  *   <dd>List of options separated by an &amp;
42  *     <dl>
43  *       <dt><tt>storage=&lt;url&gt;</tt></dt>
44  *       <dd>Specify a non-default storage location for special output
45  *         (e.g., AOD trees).  &lt;url&gt; should be a valid XRootd 
46  *         server URI accessible to the slaves - e.g., 
47  *         <tt>root://lxplus.cern.ch:10930//tmp</tt>.</dd>
48  *       <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
49  *       <dd>Set the AliROOT mode.  If not specified <tt>default</tt> 
50  *         is assumed</tt>.  See also CreateAliROOTPar</dd>
51  *       <dt><tt>par</tt></dt>
52  *       <dd> Use PAR files</dd>
53  *       <dt><tt>runs=[list or file]</tt></dt>
54  *       <dd>Comma separated list of run numbers, or file(s) containing 
55  *         run numbers</dd> 
56  *       <dt><tt>oper=[FULL,TERMINATE,SUBMIT,OFFLINE,TEST]</tt></dt>
57  *       <dd>How to run the analysis</dd>
58  *       <dt><tt>split=&lt;N&gt;</tt></dt>
59  *       <dd>Maximum number of files per split</dd>
60  *       <dt><tt>merge=&lt;N&gt;</tt></dt>
61  *       <dd>Maximum number of files per merger</dd>
62  *       <dt><tt>mc</tt></dt>
63  *       <dd>Scan also for MC files (<tt>galice.root</tt>, 
64  *          <tt>Kinematics.root</tt>, and <tt>TrackRefs.root</tt>) when 
65  *          scanning &lt;datadir&gt;</dd>
66  *       <dt><tt>pattern=&lt;GLOB&gt;</tt></dt>
67  *       <dd>Shell glob pattern that files must check when scanning 
68  *         &lt;datadir&gt;</dd>
69  *     </dl>
70  *   </dd>
71  * </dl>  
72  *
73  * @ingroup pwglf_forward_trains_helper
74  */
75 struct GridHelper : public PluginHelper
76 {
77   /** 
78    * Constructor 
79    * 
80    * @param url  Url 
81    * @param opts Options 
82    */
83   GridHelper(const TUrl& url, Int_t verbose)
84     : PluginHelper(url, verbose), fRuns()
85   {
86     fOptions.Add("oper", "FULL|TERMINATE|SUBMIT", "Analysis operation", "FULL");
87     fOptions.Add("split",  "N|max",  "Max number of files before split","max");
88     fOptions.Add("merge",  "N|max",  "Max number of files for merge",   "max");
89     fOptions.Add("run",    "RUNS",   "Range, list, and/or file of runs");
90     fOptions.Add("pattern","GLOB",   "File/directory name pattern");
91     fOptions.Add("alien",  "VERSION","Alien API version",              "V1.1x");
92     fOptions.Add("concat", "Concatenate all runs");
93     fOptions.Add("ttl",    "N|max",  "Time to live",                    "max");
94   }
95   GridHelper(const GridHelper& o)
96     : PluginHelper(o), fRuns()
97   {}
98   GridHelper& operator=(const GridHelper& o)
99   {
100     if (&o == this) return *this;
101     PluginHelper::operator=(o);
102     return *this;
103   }
104   virtual ~GridHelper() {}
105   /** 
106    * Get the mode identifier 
107    * 
108    * @return Always kProof
109    */
110   virtual UShort_t Mode() const { return kGrid; }
111   /**
112    * Get the mode string used for AliAnalysisManager::StartAnalysis
113    */
114   virtual const char* ModeString() const { return "grid"; }
115   /** 
116    * Set-up done before task set-ups 
117    * 
118    * @return true on success 
119    */
120   virtual UShort_t Operation() const 
121   {
122     if (!fOptions.Has("oper")) return kFull;
123     const TString& oper = fOptions.Get("oper");
124     if      (oper.EqualTo("FULL",      TString::kIgnoreCase)) return kFull;
125     else if (oper.EqualTo("OFFLINE",   TString::kIgnoreCase)) return kOffline;
126     else if (oper.EqualTo("SUBMIT",    TString::kIgnoreCase)) return kSubmit;
127     else if (oper.EqualTo("TERMINATE", TString::kIgnoreCase)) return kTerminate;
128     else if (oper.EqualTo("TEST",      TString::kIgnoreCase)) return kTest;
129     return kFull;
130   }
131   void StoreRun(Int_t r)
132   {
133     TObject* o = new TObject;
134     o->SetUniqueID(r);
135     fRuns.Add(o);
136   }
137   /**
138    * Read run numbers 
139    *
140    * @return Number of registered runs 
141    */
142   virtual Int_t RegisterRuns()
143   {
144     if (!fOptions.Find("run")) {
145       Error("GridHelper::RegisterRuns", "No runs specified");
146       return -1;
147     }
148     Int_t       nRuns  = 0;
149     TString     runs   = fOptions.Get("run");
150     TObjArray*  tokens = runs.Tokenize(",+.");
151     TObjString* part   = 0;
152     TIter       next(tokens);
153     Bool_t      range  = false;
154     Bool_t      individual = false;
155     // Info("GridHelper::RegisterRuns", "Runs specified are %s", runs.Data());
156     while ((part = static_cast<TObjString*>(next()))) {
157       TString& s = part->String();
158       if (s.Contains("-")) { // Run range 
159         if (range) { 
160           Warning("GridHelper::RegisterRuns", "Run range already specified, "
161                   "ignoring %s", s.Data());
162           continue;
163         }
164         if (individual) { 
165           Warning("GridHelper::RegisterRuns", 
166                   "Run ranges and individual run specs do not mix, "
167                   "ignoring %s", s.Data());
168           continue;
169         }
170         TObjArray* ranges = s.Tokenize("-");
171         if (ranges->GetEntriesFast() > 2) { 
172           Warning("GridHelper::RegisterRuns", "Invalid run range: %s", 
173                   s.Data());
174           ranges->Delete();
175           continue;
176         }
177         Int_t first = static_cast<TObjString*>(ranges->At(0))->String().Atoi();
178         Int_t last  = static_cast<TObjString*>(ranges->At(1))->String().Atoi();
179         nRuns       = last-first+1;
180         // Info("GridHelper::RegisterRuns", "Run range %d -> %d", first, last);
181         fHandler->SetRunRange(first, last);
182         ranges->Delete();
183         range = true;
184         for (Int_t r = first; r <= last; r++) StoreRun(r);
185         continue;
186       }
187       if (s.IsDigit()) { // single run
188         if (range) { 
189           Warning("GridHelper::RegisterRuns", 
190                   "Run ranges and individual run specs do not mix, "
191                   "ignoring %s", s.Data());
192           continue;
193         }
194         // Info("GridHandler::RegisterRuns", "Adding run %s", s.Data());
195         fHandler->AddRunNumber(s.Atoi());
196         StoreRun(s.Atoi());
197         nRuns++;
198         individual = true;
199         continue;
200       }
201       if (range) { 
202         Warning("GridHelper::RegisterRuns", "Run ranges and list file "
203                 "do not mix, ignoring %s", s.Data());
204         continue;
205       }
206
207       // We assume this part is a file 
208       // Info("GridHelper::RegisterRuns", "Reading runs from %s", s.Data());
209       std::ifstream in(s.Data());
210       if (!in) { 
211         s.Prepend("../");
212         in.open(s.Data());
213         if (!in) {
214           Warning("GridHelper::RegisterRuns", "Failed to open %s", s.Data());
215           continue;
216         }
217       }
218       while (!in.eof()) { 
219         Int_t r;
220         in >> r;
221         // Info("GridHelper::RegisterRuns", "Read %d, adding", r);
222         fHandler->AddRunNumber(r);
223         StoreRun(r);
224         nRuns++;
225         Char_t c;
226         in >> c;
227         if (in.bad()) break;
228       }
229       individual = true;
230       in.close();
231     }
232     return nRuns;
233   }
234   /** 
235    * Executed before setting up tasks 
236    * 
237    * @return true on success 
238    */
239   virtual Bool_t PreSetup() 
240   {
241     if (!PluginHelper::PreSetup()) return false;
242     
243     // --- Add system library dir to load path -----------------------
244     gSystem->AddDynamicPath("/usr/lib");
245
246     // --- Open a connection to the grid -----------------------------
247     if (!TGrid::Connect(Form("%s://", fUrl.GetProtocol()))) { 
248       Error("GridHelper::PreSetup", "Failed to connect to AliEN");
249       return false;
250     }
251     if (!gGrid || !gGrid->IsConnected()) { 
252       Error("GridHelper::PreSetup", "Failed to connect to AliEN");
253       return false;
254     }
255
256     return true;
257   }
258   /** 
259    * Set-up done after the task set-ups 
260    *
261    * @return true on success 
262    */
263   virtual Bool_t PostSetup() 
264   {
265     // Info("GridHelper::PostSetup", "Calling super.PostSetup");
266     if (!PluginHelper::PostSetup()) return false;
267
268     // --- API version -----------------------------------------------
269     fHandler->SetAPIVersion(fOptions.Get("alien"));
270     
271     // --- Get the name ----------------------------------------------
272     // Info("GridHelper", "Proceeding with plugin setup");
273     AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
274     TString name(mgr->GetName());
275
276     // --- Set the operation to do (TEST, SUBMIT, TERMINATE, FULL) ---
277     TString operation("FULL");
278     if (fOptions.Has("oper")) operation = fOptions.Get("oper");
279     fHandler->SetRunMode(operation);
280
281     // --- Add the run numbers ---------------------------------------
282     fHandler->SetRunPrefix(fOptions.Has("mc") ? "%d" : "%09d");
283     Int_t nRun = RegisterRuns();
284
285     // --- Do not test copying ---------------------------------------
286     fHandler->SetCheckCopy(false);
287     
288     // --- Set output to be per run ----------------------------------
289     fHandler->SetOutputToRunNo(true); 
290
291     // --- Set the job tag -------------------------------------------
292     fHandler->SetJobTag(name);
293
294     // --- Set number of test files - used in test mode only ---------
295     fHandler->SetNtestFiles(1);
296
297     // --- Set the Time-To-Live --------------------------------------
298     if (fOptions.Has("ttl")) { 
299       if (!fOptions.Get("ttl").EqualTo("max")) {
300         fHandler->SetTTL(fOptions.AsInt("ttl"));
301       }
302     }
303     
304     // --- Re-submit failed jobs as long as the ratio of failed jobs -
305     // --- is this percentage.
306     fHandler->SetMasterResubmitThreshold(95);
307
308     // --- Set the input format --------------------------------------
309     fHandler->SetInputFormat("xml-single");
310
311     // --- Set names of generated files ------------------------------
312     fHandler->SetAnalysisMacro(Form("%s.C", name.Data()));
313     fHandler->SetJDLName(Form("%s.jdl", name.Data()));
314     fHandler->SetExecutable(Form("%s.sh", name.Data()));
315     
316     // ---- Set the job price !? -------------------------------------
317     fHandler->SetPrice(1);
318
319     // --- Set whether to merge via JDL ------------------------------
320     fHandler->SetMergeViaJDL(true);
321     
322     // --- Fast read otion -------------------------------------------
323     fHandler->SetFastReadOption(false);
324
325     // --- Whether to overwrite existing output ----------------------
326     fHandler->SetOverwriteMode(true);
327
328     // --- Set the executable binary name and options ----------------
329     fHandler->SetExecutableCommand("aliroot -b -q -x");
330
331     // --- Split by storage element - must be lower case! ------------
332     fHandler->SetSplitMode("se");
333
334     // --- How much to split -----------------------------------------
335     if (fOptions.Has("split")) { 
336       if (!fOptions.Get("split").EqualTo("max")) {
337         fHandler->SetSplitMaxInputFileNumber(fOptions.AsInt("split"));
338       }
339     }
340     // --- Merge parameters ------------------------------------------
341     if (fOptions.Has("merge")) { 
342       if (!fOptions.Get("merge").EqualTo("max")) { 
343         fHandler->SetMaxMergeFiles(fOptions.AsInt("merge"));
344       }
345     }
346     fHandler->SetMergeExcludes("AliAOD.root *EventStat*.root "
347                                "*event_stat*.root");
348     
349     // --- Set number of runs per master - 1 or all ------------------
350     fHandler->SetNrunsPerMaster(fOptions.Has("concat") ? nRun+1 : 1);
351
352
353     // --- Enable default outputs ------------------------------------
354     fHandler->SetDefaultOutputs(true);
355
356     // --- Keep log files ------------------------------------------
357     fHandler->SetKeepLogs();
358
359     // --- Set the working directory to be the trains name (with -----
360     // --- special characters replaced by '_' and the date appended),
361     // --- and also set the output directory (relative to working
362     // --- directory)
363     fHandler->SetGridWorkingDir(name.Data());
364     fHandler->SetGridOutputDir("output");
365     fHandler->SetGridDataDir(fUrl.GetFile());
366
367     // --- Get the tree name and set the file pattern ----------------
368     TString pattern;
369     if (fOptions.Has("pattern")) pattern = fOptions.Get("pattern");
370     else {
371       TString treeName(fUrl.GetAnchor());
372       if (treeName.IsNull()) { 
373         Warning("GridHelper::PreSetup", "No tree name specified, assuming T");
374         treeName = "T";
375       }
376       if      (treeName.EqualTo("esdTree")) pattern = "AliESD";
377       else if (treeName.EqualTo("aodTree")) pattern = "AliAOD";
378     }
379     fHandler->SetDataPattern(pattern);
380
381     // --- Loop over defined containers in the analysis manager, and -
382     // --- declare these as outputs
383     TString listOfAODs  = "";
384     TString listOfHists = "";
385     TString listOfTerms = "";
386
387     TObjArray*  outs[] = { mgr->GetOutputs(), mgr->GetParamOutputs(), 0 };
388     TObjArray** out    = outs;
389     while (*out) {
390       AliAnalysisDataContainer* cont = 0;
391       TIter nextCont(*out);
392       while ((cont = static_cast<AliAnalysisDataContainer*>(nextCont()))) {
393         TString outName(cont->GetFileName());
394         Bool_t   term = (*out == outs[1]);
395         TString& list = (outName == "default" ? listOfAODs : 
396                          !term ? listOfHists : listOfTerms);
397         if (outName == "default") { 
398           if (!mgr->GetOutputEventHandler()) continue; 
399           
400           outName = mgr->GetOutputEventHandler()->GetOutputFileName();
401         }
402         if (list.Contains(outName)) continue;
403         if (!list.IsNull()) list.Append(",");
404         list.Append(outName);
405       }
406       out++;
407     }
408     TString extra = mgr->GetExtraFiles();
409     if (!extra.IsNull()) { 
410       if (!listOfAODs.IsNull()) listOfAODs.Append("+");
411       extra.ReplaceAll(" ", ",");
412       listOfAODs.Append(extra);
413    }
414
415 #if 0
416     Int_t nReplica = 2;
417     TString outArchive = Form("stderr, stdout@disk=%d", nReplica);
418     if (!listOfHists.IsNull()) 
419       outArchive.Append(Form(" hist_archive.zip:%s@disk=%d", 
420                              listOfHists.Data(), nReplica));
421     if (!listOfAODs.IsNull()) 
422       outArchive.Append(Form(" aod_archive.zip:%s@disk=%d", 
423                              listOfAODs.Data(), nReplica));
424     // Disabled for now 
425     // plugin->SetOutputArchive(outArchive);
426 #endif 
427
428     if (listOfAODs.IsNull() && listOfHists.IsNull()) 
429       Fatal("PostSetup", "No outputs defined");
430     if (!listOfTerms.IsNull()) 
431       fHandler->SetTerminateFiles(listOfTerms);
432     
433     return true;
434   };
435   /** 
436    * Start the analysis 
437    * 
438    * @param nEvents Number of events to analyse 
439    * 
440    * @return The return value of AliAnalysisManager::StartAnalysis
441    */
442   virtual Long64_t Run(Long64_t nEvents=-1) 
443   {
444     AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
445     if (nEvents == 0) return 0;
446     Long64_t ret = mgr->StartAnalysis("grid", nEvents);
447
448 #if 0
449     std::ofstream outJobs(Form("%s.jobid", mgr->GetName()));
450     //outJobs << fHandler->GetGridJobIDs() << std::endl;
451     outJobs.close();
452
453     std::ofstream outStages(Form("%s.stage", mgr->GetName()));
454    // outStages << fHandler->GetGridStages() << std::endl;
455     outStages.close();
456 #endif
457     return ret;
458   }
459   /** 
460    * Link an auxilary file to working directory 
461    * 
462    * @param name Name of the file
463    * 
464    * @return true on success
465    */
466   virtual Bool_t AuxFile(const TString& name, bool copy=false)
467   {
468     if (!Helper::AuxFile(name, copy)) return false;
469     // We need to add this file as an additional 'library', so that the 
470     // file is uploaded to the users Grid working directory. 
471     fHandler->AddAdditionalLibrary(gSystem->BaseName(name.Data()));
472     return true;
473   }
474   /** 
475    * Get the output (directory)
476    *
477    */
478   virtual TString OutputPath() const
479   {
480     TString ret;
481     if (!fHandler) {
482       Warning("GridHelper::OutputLocation", "No AliEn handler");
483       return ret;
484     }
485     ret = fHandler->GetGridOutputDir();
486     if (ret.BeginsWith("/")) return ret;
487
488     AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
489     if (!mgr) { 
490       Warning("GridHelper::OutputLocation", "No analysis manager");
491       return ret;
492     }
493     ret.Prepend(Form("%s/",  mgr->GetName()));
494     if (gGrid) 
495       ret.Prepend(Form("%s/", gGrid->GetHomeDirectory())); 
496     
497     return ret;
498   }
499   /** 
500    * @return URL help string
501    */
502   virtual const Char_t* UrlHelp() const 
503   {
504     return "alien:///<datadir>[?<options>][#<treeName>]";
505   }
506   /** 
507    * @return Short description
508    */
509   virtual const char* Desc() const { return "AliEn"; }
510   /** 
511    * Write auxillary ROOT (and possible shell) script for more 
512    * (post-)processing e.g., terminate
513    * 
514    * @param escaped        Escaped name  
515    * @param asShellScript  also save as shell script
516    */
517   void AuxSave(const TString& escaped, 
518                Bool_t /*asShellScript*/) 
519   {
520     // Write plug-in to file 
521     TFile* plug = TFile::Open(Form("%s_plugin.root", escaped.Data()), 
522                               "RECREATE");
523     fHandler->Write("plugin");
524     plug->Close();
525     
526     TIter       nextLib(&fExtraLibs);
527     TObjString* lib = 0;
528     TString     libs;
529     while ((lib = static_cast<TObjString*>(nextLib()))) {
530       if (!libs.IsNull()) libs.Append(" ");
531       libs.Append(lib->String());
532     }
533     TIter       nextPar(&fExtraPars);
534     TObjString* par = 0;
535     TString     pars;
536     while ((par = static_cast<TObjString*>(nextPar()))) {
537       if (!pars.IsNull()) pars.Append(" ");
538       pars.Append(par->String());
539     }
540     TIter       nextSrc(&fExtraSrcs);
541     TObjString* src = 0;
542     TString     srcs;
543     while ((src = static_cast<TObjString*>(nextSrc()))) {
544       if (!srcs.IsNull()) srcs.Append(" ");
545       srcs.Append(src->String());
546     }
547     TString macDir("$ALICE_ROOT/PWGLF/FORWARD/trains");
548     std::ofstream t("Terminate.C");
549     if (!t) { 
550       Error("GridHelper::AuxSave", "Failed to make terminate ROOT script");
551       return;
552     }
553
554     t << "// Generated by GridHelper\n"
555       << "Bool_t Terminate()\n"
556       << "{\n"
557       << "  TString name = \"" << escaped << "\";\n"
558       << "  TString libs = \"" << libs << "\";\n"
559       << "  TString pars = \"" << pars << "\";\n"
560       << "  TString srcs = \"" << srcs << "\";\n\n"
561       << "  gROOT->LoadMacro(\"" << macDir << "/GridTerminate.C\");\n\n"
562       << "  return GridTerminate(name,libs,pars,srcs);\n"
563       << "}\n"
564       << "// EOF\n"
565       << std::endl;
566     t.close();
567
568     TString runs;
569     TString format(fOptions.Has("mc") ? "%d" : "%09d");
570     if (fOptions.Has("concat")) {
571       Int_t first = fRuns.First()->GetUniqueID();
572       Int_t last  = fRuns.Last()->GetUniqueID();
573       TString fmt(format); 
574       fmt.Append("_"); 
575       fmt.Append(format);
576       if (!runs.IsNull()) runs.Append(" ");
577       runs.Append(TString::Format(fmt, first, last));
578     }
579     else {
580       TIter next(&fRuns);
581       TObject* o = 0;
582       while ((o = next())) { 
583         if (!runs.IsNull()) runs.Append(" ");
584         runs.Append(Form(format, o->GetUniqueID()));
585       }
586     }
587
588     std::ofstream d("Download.C");
589     if (!d) { 
590       Error("GridHelper::AuxSave", "Failed to make ROOT script Download.C");
591       return;
592     }
593     d << "// Generated by GridHelper\n"
594       << "void Download()\n"
595       << "{\n"
596       << "  TString base = \"" << fUrl.GetProtocol() << "://" 
597       << OutputPath() << "\";\n"
598       << "  TString runs = \"" << runs << "\";\n\n"
599       << "  gROOT->LoadMacro(\"" << macDir << "/GridDownload.C\");\n\n"
600       << "  GridDownload(base, runs);\n"
601       << "}\n"
602       << "// EOF\n"
603       << std::endl;
604     d.close();
605
606     std::ofstream w("Watch.C");
607     if (!w) {
608       Error("GridHelper::AuxSave", "Failed to make ROOT script Watch.C");
609       return;
610     }
611     w << "// Generated by GridHelper\n"
612       << "void Watch(Int_t delay=5*60)\n"
613       << "{\n"
614       << "  TString name = \"" << escaped << "\";\n"
615       << "  gROOT->LoadMacro(\"" << macDir << "/GridWatch.C+g\");\n\n"
616       << "  GridWatch(name,delay);\n"
617       << "}\n"
618       << "// EOF\n"
619       << std::endl;
620     w.close();
621
622   }
623   TList fRuns;
624 };
625 #endif
626 //
627 // EOF
628 //