]>
Commit | Line | Data |
---|---|---|
fdfd93b4 | 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><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 & | |
42 | * <dl> | |
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 | |
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=<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> | |
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) | |
85 | { | |
86 | fOptions.Add("oper", "FULL|TERMINATE|SUBMIT", "Analysis operation", "FULL"); | |
87 | fOptions.Add("split", "N", "Maximum number of files before split", "max"); | |
88 | fOptions.Add("merge", "N", "Maximum 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("mc", "Assume MC input"); | |
92 | } | |
93 | virtual ~GridHelper() {} | |
94 | /** | |
95 | * Get the mode identifier | |
96 | * | |
97 | * @return Always kProof | |
98 | */ | |
99 | virtual UShort_t Mode() const { return kGrid; } | |
100 | /** | |
101 | * Get the mode string used for AliAnalysisManager::StartAnalysis | |
102 | */ | |
103 | virtual const char* ModeString() const { return "grid"; } | |
104 | /** | |
105 | * Set-up done before task set-ups | |
106 | * | |
107 | * @return true on success | |
108 | */ | |
109 | virtual UShort_t Operation() const | |
110 | { | |
111 | if (!fOptions.Has("oper")) return kFull; | |
112 | const TString& oper = fOptions.Get("oper"); | |
113 | if (oper.EqualTo("FULL", TString::kIgnoreCase)) return kFull; | |
114 | else if (oper.EqualTo("OFFLINE", TString::kIgnoreCase)) return kOffline; | |
115 | else if (oper.EqualTo("SUBMIT", TString::kIgnoreCase)) return kSubmit; | |
116 | else if (oper.EqualTo("TERMINATE", TString::kIgnoreCase)) return kTerminate; | |
117 | else if (oper.EqualTo("TEST", TString::kIgnoreCase)) return kTest; | |
118 | return kFull; | |
119 | } | |
120 | /** | |
121 | * Read run numbers | |
122 | * | |
123 | * @return Number of registered runs | |
124 | */ | |
125 | virtual Int_t RegisterRuns() | |
126 | { | |
127 | if (!fOptions.Find("run")) { | |
128 | Error("GridHelper::RegisterRuns", "No runs specified"); | |
129 | return -1; | |
130 | } | |
131 | Int_t nRuns = 0; | |
132 | TString runs = fOptions.Get("runs"); | |
133 | TObjArray* tokens = runs.Tokenize(","); | |
134 | TObjString* part = 0; | |
135 | TIter next(tokens); | |
136 | Bool_t range = false; | |
137 | Bool_t individual = false; | |
138 | while ((part = static_cast<TObjString*>(next()))) { | |
139 | TString& s = part->String(); | |
140 | if (s.Contains("-")) { // Run range | |
141 | if (range) { | |
142 | Warning("GridHelper::RegisterRuns", "Run range already specified, " | |
143 | "ignoring %s", s.Data()); | |
144 | continue; | |
145 | } | |
146 | if (individual) { | |
147 | Warning("GridHelper::RegisterRuns", | |
148 | "Run ranges and individual run specs do not mix, " | |
149 | "ignoring %s", s.Data()); | |
150 | continue; | |
151 | } | |
152 | TObjArray* ranges = s.Tokenize("-"); | |
153 | if (ranges->GetEntriesFast() > 2) { | |
154 | Warning("GridHelper::RegisterRuns", "Invalid run range: %s", | |
155 | s.Data()); | |
156 | ranges->Delete(); | |
157 | continue; | |
158 | } | |
159 | Int_t first = static_cast<TObjString*>(ranges->At(0))->String().Atoi(); | |
160 | Int_t last = static_cast<TObjString*>(ranges->At(1))->String().Atoi(); | |
161 | nRuns = last-first+1; | |
162 | fHandler->SetRunRange(first, last); | |
163 | ranges->Delete(); | |
164 | range = true; | |
165 | continue; | |
166 | } | |
167 | if (s.IsDigit()) { // single run | |
168 | if (range) { | |
169 | Warning("GridHelper::RegisterRuns", | |
170 | "Run ranges and individual run specs do not mix, " | |
171 | "ignoring %s", s.Data()); | |
172 | continue; | |
173 | } | |
174 | fHandler->AddRunNumber(s.Data()); | |
175 | nRuns++; | |
176 | individual = true; | |
177 | continue; | |
178 | } | |
179 | if (range) { | |
180 | Warning("GridHelper::RegisterRuns", "Run ranges and list file " | |
181 | "do not mix, ignoring %s", s.Data()); | |
182 | continue; | |
183 | } | |
184 | ||
185 | // We assume this part is a file | |
186 | std::ifstream in(s.Data()); | |
187 | if (!in) { | |
188 | Warning("GridHelper::RegisterRuns", "Failed to open %s", s.Data()); | |
189 | continue; | |
190 | } | |
191 | while (!in.eof()) { | |
192 | Int_t r; | |
193 | in >> r; | |
194 | fHandler->AddRunNumber(r); | |
195 | nRuns++; | |
196 | Char_t c; | |
197 | in >> c; | |
198 | if (in.bad()) break; | |
199 | } | |
200 | individual = true; | |
201 | in.close(); | |
202 | } | |
203 | return nRuns; | |
204 | } | |
205 | /** | |
206 | * Executed before setting up tasks | |
207 | * | |
208 | * @return true on success | |
209 | */ | |
210 | virtual Bool_t PreSetup() | |
211 | { | |
212 | if (!PluginHelper::PreSetup()) return false; | |
213 | ||
214 | // --- Open a connection to the grid ----------------------------- | |
215 | TGrid::Connect(Form("%s://", fUrl.GetProtocol())); | |
216 | if (!gGrid || !gGrid->IsConnected()) { | |
217 | Error("GridHelper::PreSetup", "Failed to connect to AliEN"); | |
218 | return false; | |
219 | } | |
220 | ||
221 | return true; | |
222 | } | |
223 | /** | |
224 | * Set-up done after the task set-ups | |
225 | * | |
226 | * @return true on success | |
227 | */ | |
228 | virtual Bool_t PostSetup() | |
229 | { | |
230 | if (!PluginHelper::PostSetup()) return false; | |
231 | ||
232 | AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager(); | |
233 | TString name(mgr->GetName()); | |
234 | ||
235 | // --- Set the operation to do (TEST, SUBMIT, TERMINATE, FULL) --- | |
236 | TString operation("FULL"); | |
237 | if (fOptions.Has("oper")) operation = fOptions.Get("oper"); | |
238 | fHandler->SetRunMode(operation); | |
239 | ||
240 | // --- Do not test copying --------------------------------------- | |
241 | fHandler->SetCheckCopy(false); | |
242 | ||
243 | // --- Set output to be per run ---------------------------------- | |
244 | fHandler->SetOutputToRunNo(true); | |
245 | ||
246 | // --- Set the job tag ------------------------------------------- | |
247 | fHandler->SetJobTag(name); | |
248 | ||
249 | // --- Set number of test files - used in test mode only --------- | |
250 | fHandler->SetNtestFiles(1); | |
251 | ||
252 | // --- Set the Time-To-Live -------------------------------------- | |
253 | fHandler->SetTTL(70000); | |
254 | ||
255 | // --- Re-submit failed jobs as long as the ratio of failed jobs - | |
256 | // --- is this percentage. | |
257 | fHandler->SetMasterResubmitThreshold(95); | |
258 | ||
259 | // --- Set the input format -------------------------------------- | |
260 | fHandler->SetInputFormat("xml-single"); | |
261 | ||
262 | // --- Set names of generated files ------------------------------ | |
263 | fHandler->SetAnalysisMacro(Form("%s.C", name.Data())); | |
264 | fHandler->SetJDLName(Form("%s.jdl", name.Data())); | |
265 | fHandler->SetExecutable(Form("%s.sh", name.Data())); | |
266 | ||
267 | // ---- Set the job price !? ------------------------------------- | |
268 | fHandler->SetPrice(1); | |
269 | ||
270 | // --- Set whether to merge via JDL ------------------------------ | |
271 | fHandler->SetMergeViaJDL(true); | |
272 | ||
273 | // --- Fast read otion ------------------------------------------- | |
274 | fHandler->SetFastReadOption(false); | |
275 | ||
276 | // --- Whether to overwrite existing output ---------------------- | |
277 | fHandler->SetOverwriteMode(true); | |
278 | ||
279 | // --- Set the executable binary name and options ---------------- | |
280 | fHandler->SetExecutableCommand("aliroot -b -q -x"); | |
281 | ||
282 | // --- Split by storage element - must be lower case! ------------ | |
283 | fHandler->SetSplitMode("se"); | |
284 | ||
285 | // --- How much to split ----------------------------------------- | |
286 | if (fOptions.Has("split")) { | |
287 | if (!fOptions.Get("split").EqualTo("max")) { | |
288 | fHandler->SetSplitMaxInputFileNumber(fOptions.Get("split").Atoi()); | |
289 | } | |
290 | } | |
291 | ||
292 | // --- Enable default outputs ------------------------------------ | |
293 | fHandler->SetDefaultOutputs(true); | |
294 | ||
295 | // --- Merge parameters ------------------------------------------ | |
296 | if (fOptions.Has("merge")) { | |
297 | if (!fOptions.Get("merge").EqualTo("max")) { | |
298 | fHandler->SetMaxMergeFiles(fOptions.Get("merge").Atoi()); | |
299 | } | |
300 | } | |
301 | fHandler->SetMergeExcludes("AliAOD.root *EventStat*.root " | |
302 | "*event_stat*.root"); | |
303 | ||
304 | // --- Keep log files ------------------------------------------ | |
305 | fHandler->SetKeepLogs(); | |
306 | ||
307 | // --- Set the working directory to be the trains name (with ----- | |
308 | // --- special characters replaced by '_' and the date appended), | |
309 | // --- and also set the output directory (relative to working | |
310 | // --- directory) | |
311 | fHandler->SetGridWorkingDir(name.Data()); | |
312 | fHandler->SetGridOutputDir("output"); | |
313 | fHandler->SetGridDataDir(fUrl.GetFile()); | |
314 | ||
315 | // --- Get the tree name and set the file pattern ---------------- | |
316 | TString pattern; | |
317 | if (fOptions.Has("pattern")) pattern = fOptions.Get("pattern"); | |
318 | else { | |
319 | TString treeName(fUrl.GetAnchor()); | |
320 | if (treeName.IsNull()) { | |
321 | Warning("GridHelper::PreSetup", "No tree name specified, assuming T"); | |
322 | treeName = "T"; | |
323 | } | |
324 | if (treeName.EqualTo("esdTree")) pattern = "AliESD"; | |
325 | else if (treeName.EqualTo("aodTree")) pattern = "AliAOD"; | |
326 | } | |
327 | fHandler->SetDataPattern(pattern); | |
328 | fHandler->SetRunPrefix(mgr->GetMCtruthEventHandler() ? "" : "000"); | |
329 | ||
330 | // --- Add the run numbers --------------------------------------- | |
331 | Int_t nRun = RegisterRuns(); | |
332 | ||
333 | // --- Set number of runs per master - set to one to per run ----- | |
334 | fHandler->SetNrunsPerMaster(fOptions.Has("run-merge") ? 1 : nRun+1); | |
335 | ||
336 | // --- Loop over defined containers in the analysis manager, and - | |
337 | // --- declare these as outputs | |
338 | TString listOfAODs = ""; | |
339 | TString listOfHists = ""; | |
340 | ||
341 | AliAnalysisDataContainer* cont = 0; | |
342 | TIter nextCont(mgr->GetOutputs()); | |
343 | while ((cont = static_cast<AliAnalysisDataContainer*>(nextCont()))) { | |
344 | TString outName(cont->GetFileName()); | |
345 | TString& list = (outName == "default" ? listOfAODs : listOfHists); | |
346 | if (outName == "default") { | |
347 | if (!mgr->GetOutputEventHandler()) continue; | |
348 | ||
349 | outName = mgr->GetOutputEventHandler()->GetOutputFileName(); | |
350 | } | |
351 | if (list.Contains(outName)) continue; | |
352 | if (!list.IsNull()) list.Append(","); | |
353 | list.Append(outName); | |
354 | } | |
355 | if (!mgr->GetExtraFiles().IsNull()) { | |
356 | if (!listOfAODs.IsNull()) listOfAODs.Append("+"); | |
357 | TString extra = mgr->GetExtraFiles(); | |
358 | extra.ReplaceAll(" ", ","); | |
359 | listOfAODs.Append(extra); | |
360 | } | |
361 | ||
362 | Int_t nReplica = 2; | |
363 | TString outArchive = Form("stderr, stdout@disk=%d", nReplica); | |
364 | if (!listOfHists.IsNull()) | |
365 | outArchive.Append(Form(" hist_archive.zip:%s@disk=%d", | |
366 | listOfHists.Data(), nReplica)); | |
367 | if (!listOfAODs.IsNull()) | |
368 | outArchive.Append(Form(" aod_archive.zip:%s@disk=%d", | |
369 | listOfAODs.Data(), nReplica)); | |
370 | if (listOfAODs.IsNull() && listOfHists.IsNull()) | |
371 | Fatal("PostSetup", "No outputs defined"); | |
372 | ||
373 | return true; | |
374 | }; | |
375 | /** | |
376 | * Start the analysis | |
377 | * | |
378 | * @param nEvents Number of events to analyse | |
379 | * | |
380 | * @return The return value of AliAnalysisManager::StartAnalysis | |
381 | */ | |
382 | virtual Long64_t Run(Long64_t nEvents=-1) | |
383 | { | |
384 | AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager(); | |
385 | ||
386 | return mgr->StartAnalysis("grid", nEvents); | |
387 | } | |
388 | /** | |
389 | * Link an auxilary file to working directory | |
390 | * | |
391 | * @param name Name of the file | |
392 | * | |
393 | * @return true on success | |
394 | */ | |
395 | virtual Bool_t AuxFile(const TString& name) | |
396 | { | |
397 | if (!Helper::AuxFile(name)) return false; | |
398 | // We need to add this file as an additional 'library', so that the | |
399 | // file is uploaded to the users Grid working directory. | |
400 | fHandler->AddAdditionalLibrary(gSystem->BaseName(name.Data())); | |
401 | return true; | |
402 | } | |
403 | /** | |
404 | * Get the output (directory) | |
405 | * | |
406 | */ | |
407 | virtual TString OutputPath() const | |
408 | { | |
409 | TString ret; | |
410 | if (!fHandler) { | |
411 | Warning("GridHelper::OutputLocation", "No AliEn handler"); | |
412 | return ret; | |
413 | } | |
414 | ret = fHandler->GetGridOutputDir(); | |
415 | if (ret.BeginsWith("/")) return ret; | |
416 | ||
417 | AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager(); | |
418 | if (!mgr) { | |
419 | Warning("GridHelper::OutputLocation", "No analysis manager"); | |
420 | return ret; | |
421 | } | |
422 | ret.Prepend(Form("%s/", mgr->GetName())); | |
423 | if (gGrid) | |
424 | ret.Prepend(Form("%s/", gGrid->GetHomeDirectory())); | |
425 | ||
426 | return ret; | |
427 | } | |
428 | /** | |
429 | * @return URL help string | |
430 | */ | |
431 | virtual const Char_t* UrlHelp() const | |
432 | { | |
433 | return "alien:///<datadir>[?<options>][#<treeName>]"; | |
434 | } | |
435 | /** | |
436 | * @return Short description | |
437 | */ | |
438 | virtual const char* Desc() const { return "AliEn"; } | |
439 | }; | |
440 | #endif | |
441 | // | |
442 | // EOF | |
443 | // |