3 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4 * @date Tue Oct 16 19:01:27 2012
6 * @brief Grid Analysis Helper
8 * @ingroup pwglf_forward_trains_helper
13 #include "PluginHelper.C"
18 # include <AliAnalysisManager.h>
19 # include <AliAnalysisAlien.h>
22 class AliAnalysisAlien;
25 // ===================================================================
27 * Handle analysis on an the Grid
29 * This helper is triggered by a URL of the form
32 * alien:///<directory>[?<options>][#<pattern>]
36 * <dt><directory@gt;</dt>
37 * <dd>Grid directory that holds the data</dd>
38 * <dt><treeName@gt;</dt>
39 * <dd>Tree to loop over</dd>
40 * <dt><options@gt;</dt>
41 * <dd>List of options separated by an &
43 * <dt><tt>storage=<url></tt></dt>
44 * <dd>Specify a non-default storage location for special output
45 * (e.g., AOD trees). <url> 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
56 * <dt><tt>oper=[FULL,TERMINATE,SUBMIT,OFFLINE,TEST]</tt></dt>
57 * <dd>How to run the analysis</dd>
58 * <dt><tt>split=<N></tt></dt>
59 * <dd>Maximum number of files per split</dd>
60 * <dt><tt>merge=<N></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 <datadir></dd>
66 * <dt><tt>pattern=<GLOB></tt></dt>
67 * <dd>Shell glob pattern that files must check when scanning
68 * <datadir></dd>
73 * @ingroup pwglf_forward_trains_helper
75 struct GridHelper : public PluginHelper
83 GridHelper(const TUrl& url, Int_t verbose)
84 : PluginHelper(url, verbose), fRuns()
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");
95 GridHelper(const GridHelper& o)
96 : PluginHelper(o), fRuns()
98 GridHelper& operator=(const GridHelper& o)
100 if (&o == this) return *this;
101 PluginHelper::operator=(o);
104 virtual ~GridHelper() {}
106 * Get the mode identifier
108 * @return Always kProof
110 virtual UShort_t Mode() const { return kGrid; }
112 * Get the mode string used for AliAnalysisManager::StartAnalysis
114 virtual const char* ModeString() const { return "grid"; }
116 * Set-up done before task set-ups
118 * @return true on success
120 virtual UShort_t Operation() const
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;
131 void StoreRun(Int_t r)
133 TObject* o = new TObject;
140 * @return Number of registered runs
142 virtual Int_t RegisterRuns()
144 if (!fOptions.Find("run")) {
145 Error("GridHelper::RegisterRuns", "No runs specified");
149 TString runs = fOptions.Get("run");
150 TObjArray* tokens = runs.Tokenize(",+.");
151 TObjString* part = 0;
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
160 Warning("GridHelper::RegisterRuns", "Run range already specified, "
161 "ignoring %s", s.Data());
165 Warning("GridHelper::RegisterRuns",
166 "Run ranges and individual run specs do not mix, "
167 "ignoring %s", s.Data());
170 TObjArray* ranges = s.Tokenize("-");
171 if (ranges->GetEntriesFast() > 2) {
172 Warning("GridHelper::RegisterRuns", "Invalid run range: %s",
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);
184 for (Int_t r = first; r <= last; r++) StoreRun(r);
187 if (s.IsDigit()) { // single run
189 Warning("GridHelper::RegisterRuns",
190 "Run ranges and individual run specs do not mix, "
191 "ignoring %s", s.Data());
194 // Info("GridHandler::RegisterRuns", "Adding run %s", s.Data());
195 fHandler->AddRunNumber(s.Atoi());
202 Warning("GridHelper::RegisterRuns", "Run ranges and list file "
203 "do not mix, ignoring %s", s.Data());
207 // We assume this part is a file
208 // Info("GridHelper::RegisterRuns", "Reading runs from %s", s.Data());
209 std::ifstream in(s.Data());
214 Warning("GridHelper::RegisterRuns", "Failed to open %s", s.Data());
221 // Info("GridHelper::RegisterRuns", "Read %d, adding", r);
222 fHandler->AddRunNumber(r);
235 * Executed before setting up tasks
237 * @return true on success
239 virtual Bool_t PreSetup()
241 if (!PluginHelper::PreSetup()) return false;
243 // --- Add system library dir to load path -----------------------
244 gSystem->AddDynamicPath("/usr/lib");
246 // --- Open a connection to the grid -----------------------------
247 if (!TGrid::Connect(Form("%s://", fUrl.GetProtocol()))) {
248 Error("GridHelper::PreSetup", "Failed to connect to AliEN");
251 if (!gGrid || !gGrid->IsConnected()) {
252 Error("GridHelper::PreSetup", "Failed to connect to AliEN");
259 * Set-up done after the task set-ups
261 * @return true on success
263 virtual Bool_t PostSetup()
265 // Info("GridHelper::PostSetup", "Calling super.PostSetup");
266 if (!PluginHelper::PostSetup()) return false;
268 // --- API version -----------------------------------------------
269 fHandler->SetAPIVersion(fOptions.Get("alien"));
271 // --- Get the name ----------------------------------------------
272 // Info("GridHelper", "Proceeding with plugin setup");
273 AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
274 TString name(mgr->GetName());
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);
281 // --- Add the run numbers ---------------------------------------
282 fHandler->SetRunPrefix(fOptions.Has("mc") ? "%d" : "%09d");
283 Int_t nRun = RegisterRuns();
285 // --- Do not test copying ---------------------------------------
286 fHandler->SetCheckCopy(false);
288 // --- Set output to be per run ----------------------------------
289 fHandler->SetOutputToRunNo(true);
291 // --- Set the job tag -------------------------------------------
292 fHandler->SetJobTag(name);
294 // --- Set number of test files - used in test mode only ---------
295 fHandler->SetNtestFiles(1);
297 // --- Set the Time-To-Live --------------------------------------
298 if (fOptions.Has("ttl")) {
299 if (!fOptions.Get("ttl").EqualTo("max")) {
300 fHandler->SetTTL(fOptions.AsInt("ttl"));
304 // --- Re-submit failed jobs as long as the ratio of failed jobs -
305 // --- is this percentage.
306 fHandler->SetMasterResubmitThreshold(95);
308 // --- Set the input format --------------------------------------
309 fHandler->SetInputFormat("xml-single");
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()));
316 // ---- Set the job price !? -------------------------------------
317 fHandler->SetPrice(1);
319 // --- Set whether to merge via JDL ------------------------------
320 fHandler->SetMergeViaJDL(true);
322 // --- Fast read otion -------------------------------------------
323 fHandler->SetFastReadOption(false);
325 // --- Whether to overwrite existing output ----------------------
326 fHandler->SetOverwriteMode(true);
328 // --- Set the executable binary name and options ----------------
329 fHandler->SetExecutableCommand("aliroot -b -q -x");
331 // --- Split by storage element - must be lower case! ------------
332 fHandler->SetSplitMode("se");
334 // --- How much to split -----------------------------------------
335 if (fOptions.Has("split")) {
336 if (!fOptions.Get("split").EqualTo("max")) {
337 fHandler->SetSplitMaxInputFileNumber(fOptions.AsInt("split"));
340 // --- Merge parameters ------------------------------------------
341 if (fOptions.Has("merge")) {
342 if (!fOptions.Get("merge").EqualTo("max")) {
343 fHandler->SetMaxMergeFiles(fOptions.AsInt("merge"));
346 fHandler->SetMergeExcludes("AliAOD.root *EventStat*.root "
347 "*event_stat*.root");
349 // --- Set number of runs per master - 1 or all ------------------
350 fHandler->SetNrunsPerMaster(fOptions.Has("concat") ? nRun+1 : 1);
353 // --- Enable default outputs ------------------------------------
354 fHandler->SetDefaultOutputs(true);
356 // --- Keep log files ------------------------------------------
357 fHandler->SetKeepLogs();
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
363 fHandler->SetGridWorkingDir(name.Data());
364 fHandler->SetGridOutputDir("output");
365 fHandler->SetGridDataDir(fUrl.GetFile());
367 // --- Get the tree name and set the file pattern ----------------
369 if (fOptions.Has("pattern")) pattern = fOptions.Get("pattern");
371 TString treeName(fUrl.GetAnchor());
372 if (treeName.IsNull()) {
373 Warning("GridHelper::PreSetup", "No tree name specified, assuming T");
376 if (treeName.EqualTo("esdTree")) pattern = "AliESD";
377 else if (treeName.EqualTo("aodTree")) pattern = "AliAOD";
379 fHandler->SetDataPattern(pattern);
381 // --- Loop over defined containers in the analysis manager, and -
382 // --- declare these as outputs
383 TString listOfAODs = "";
384 TString listOfHists = "";
385 TString listOfTerms = "";
387 TObjArray* outs[] = { mgr->GetOutputs(), mgr->GetParamOutputs(), 0 };
388 TObjArray** out = outs;
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;
400 outName = mgr->GetOutputEventHandler()->GetOutputFileName();
402 if (list.Contains(outName)) continue;
403 if (!list.IsNull()) list.Append(",");
404 list.Append(outName);
408 TString extra = mgr->GetExtraFiles();
409 if (!extra.IsNull()) {
410 if (!listOfAODs.IsNull()) listOfAODs.Append("+");
411 extra.ReplaceAll(" ", ",");
412 listOfAODs.Append(extra);
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));
425 // plugin->SetOutputArchive(outArchive);
428 if (listOfAODs.IsNull() && listOfHists.IsNull())
429 Fatal("PostSetup", "No outputs defined");
430 if (!listOfTerms.IsNull())
431 fHandler->SetTerminateFiles(listOfTerms);
438 * @param nEvents Number of events to analyse
440 * @return The return value of AliAnalysisManager::StartAnalysis
442 virtual Long64_t Run(Long64_t nEvents=-1)
444 AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
445 if (nEvents == 0) return 0;
446 Long64_t ret = mgr->StartAnalysis("grid", nEvents);
449 std::ofstream outJobs(Form("%s.jobid", mgr->GetName()));
450 //outJobs << fHandler->GetGridJobIDs() << std::endl;
453 std::ofstream outStages(Form("%s.stage", mgr->GetName()));
454 // outStages << fHandler->GetGridStages() << std::endl;
460 * Link an auxilary file to working directory
462 * @param name Name of the file
464 * @return true on success
466 virtual Bool_t AuxFile(const TString& name, bool copy=false)
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()));
475 * Get the output (directory)
478 virtual TString OutputPath() const
482 Warning("GridHelper::OutputLocation", "No AliEn handler");
485 ret = fHandler->GetGridOutputDir();
486 if (ret.BeginsWith("/")) return ret;
488 AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
490 Warning("GridHelper::OutputLocation", "No analysis manager");
493 ret.Prepend(Form("%s/", mgr->GetName()));
495 ret.Prepend(Form("%s/", gGrid->GetHomeDirectory()));
500 * @return URL help string
502 virtual const Char_t* UrlHelp() const
504 return "alien:///<datadir>[?<options>][#<treeName>]";
507 * @return Short description
509 virtual const char* Desc() const { return "AliEn"; }
511 * Write auxillary ROOT (and possible shell) script for more
512 * (post-)processing e.g., terminate
514 * @param escaped Escaped name
515 * @param asShellScript also save as shell script
517 void AuxSave(const TString& escaped,
518 Bool_t /*asShellScript*/)
520 // Write plug-in to file
521 TFile* plug = TFile::Open(Form("%s_plugin.root", escaped.Data()),
523 fHandler->Write("plugin");
526 TIter nextLib(&fExtraLibs);
529 while ((lib = static_cast<TObjString*>(nextLib()))) {
530 if (!libs.IsNull()) libs.Append(" ");
531 libs.Append(lib->String());
533 TIter nextPar(&fExtraPars);
536 while ((par = static_cast<TObjString*>(nextPar()))) {
537 if (!pars.IsNull()) pars.Append(" ");
538 pars.Append(par->String());
540 TIter nextSrc(&fExtraSrcs);
543 while ((src = static_cast<TObjString*>(nextSrc()))) {
544 if (!srcs.IsNull()) srcs.Append(" ");
545 srcs.Append(src->String());
547 TString macDir("$ALICE_ROOT/PWGLF/FORWARD/trains");
548 std::ofstream t("Terminate.C");
550 Error("GridHelper::AuxSave", "Failed to make terminate ROOT script");
554 t << "// Generated by GridHelper\n"
555 << "Bool_t Terminate()\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"
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();
576 if (!runs.IsNull()) runs.Append(" ");
577 runs.Append(TString::Format(fmt, first, last));
582 while ((o = next())) {
583 if (!runs.IsNull()) runs.Append(" ");
584 runs.Append(Form(format, o->GetUniqueID()));
588 std::ofstream d("Download.C");
590 Error("GridHelper::AuxSave", "Failed to make ROOT script Download.C");
593 d << "// Generated by GridHelper\n"
594 << "void Download()\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"
606 std::ofstream w("Watch.C");
608 Error("GridHelper::AuxSave", "Failed to make ROOT script Watch.C");
611 w << "// Generated by GridHelper\n"
612 << "void Watch(Int_t delay=5*60)\n"
614 << " TString name = \"" << escaped << "\";\n"
615 << " gROOT->LoadMacro(\"" << macDir << "/GridWatch.C+g\");\n\n"
616 << " GridWatch(name,delay);\n"