]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisTaskCfg.cxx
Coverity warning corrected.
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisTaskCfg.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 #include "AliAnalysisTaskCfg.h"
17 #include "AliAnalysisManager.h"
18
19 #include "Riostream.h"
20 #include "TError.h"
21 #include "TMacro.h"
22 #include "TInterpreter.h"
23 #include "TSystem.h"
24 #include "TObjArray.h"
25 #include "TObjString.h"
26 #include "TList.h"
27
28 // Author: Andrei Gheata, 12/08/2011
29
30 //==============================================================================
31 //   AliAnalysysTaskCfg - Class embedding the configuration needed to run
32 // a given analysis task: libraries to be loaded, location and name of the macro
33 // used to add the task to the analysis manager, dependencies.
34 //==============================================================================
35
36 // This class is used to fully describe how to run a given analysis task. It
37 // requires that the user creates an AddTask macro for his task and defines:
38 //  - The needed libs separated by commas,
39 //  - The full path to the AddTask macro (starting with $ALICE_ROOT if needed)
40 //  - The list of arguments to be provided to the AddTask macro. One can use
41 //    here only constants that can be interpreted.
42 //  - The list of dependencies (other modules required to run this task). These
43 //    must be names of other AliAnalysisTaskCfg objects, separated by commas.
44 //  - Data types supported by the task (e.g. ESD, AOD, MC)
45 // The class has normal ROOT IO, but it can also read from and write to text files.
46 // An example:
47 // Content of file: QAsym.cfg
48 /*
49 # Lines that do not start with #Module are ignored, except those in embedded
50   macro blocks
51 #Module.Begin        QAsym
52 #Module.Libs         PWG1
53 #Module.Deps         PhysicsSelection
54 #Module.DataTypes    ESD, AOD, MC
55 #Module.MacroName    $ALICE_ROOT/PWG1/PilotTrain/AddTaskQAsym.C
56 #Module.MacroArgs    0, AliVEvent::kAnyINT, AliVEvent::kHighMult, AliVEvent::kEMC7, AliVEvent::kMUU7
57 #Module.StartConfig  
58 __R_ADDTASK__->SelectCollisionCandidates();
59 #Module.EndConfig
60 */
61 // The following special variable names can be used:
62 // __R_ADDTASK__ = the return value of the AddTask macro included
63 // __R_ESDH__    = pointer to ESD handler
64 // __R_AODH__    = pointer to AOD handler
65 // __R_MCH__     = pointer to MC handler
66 // The static method ExtractModulesFrom(const char *filename) allows reading
67 // several task configuration modules from the same text file and returning
68 // them in a TObjArray.
69 //
70 // A list of configuration modules representing a train should be injected in
71 // the right order in the grid handler to generate train macros.
72
73
74 ClassImp(AliAnalysisTaskCfg)
75
76 //______________________________________________________________________________
77 AliAnalysisTaskCfg::AliAnalysisTaskCfg()
78                    :TNamed(),
79                     fMacroName(),
80                     fMacroArgs(),
81                     fLibs(),
82                     fDeps(),
83                     fDataTypes(),
84                     fMacro(0),
85                     fConfigDeps(0),
86                     fRAddTask(0)
87 {
88 // I/O constructor.
89 }
90
91 //______________________________________________________________________________
92 AliAnalysisTaskCfg::AliAnalysisTaskCfg(const char *name)
93                    :TNamed(name,""),
94                     fMacroName(),
95                     fMacroArgs(),
96                     fLibs(),
97                     fDeps(),
98                     fDataTypes(),
99                     fMacro(0),
100                     fConfigDeps(0),
101                     fRAddTask(0)
102 {
103 // Constructor. All configuration objects need to be named since they are looked
104 // for by name.
105 }
106
107 //______________________________________________________________________________
108 AliAnalysisTaskCfg::AliAnalysisTaskCfg(const AliAnalysisTaskCfg &other)
109                    :TNamed(other),
110                     fMacroName(other.fMacroName),
111                     fMacroArgs(other.fMacroArgs),
112                     fLibs(other.fLibs),
113                     fDeps(other.fDeps),
114                     fDataTypes(other.fDataTypes),
115                     fMacro(0),
116                     fConfigDeps(0),
117                     fRAddTask(0)
118 {
119 // Copy constructor.
120    if (other.fMacro) fMacro = new TMacro(*other.fMacro);
121    if (other.fConfigDeps) fConfigDeps = new TMacro(*other.fConfigDeps);
122 }   
123
124 //______________________________________________________________________________
125 AliAnalysisTaskCfg::~AliAnalysisTaskCfg()
126 {
127 // Destructor.
128    delete fMacro;
129    delete fConfigDeps;
130 }
131
132 //______________________________________________________________________________
133 AliAnalysisTaskCfg& AliAnalysisTaskCfg::operator=(const AliAnalysisTaskCfg &other)
134 {
135 // Assignment operator.
136    if (&other == this) return *this;
137    TNamed::operator=(other);
138    fMacroName = other.fMacroName;
139    fMacroArgs = other.fMacroArgs;
140    fLibs      = other.fLibs;
141    fDeps      = other.fDeps;
142    fDataTypes = other.fDataTypes;
143    if (other.fMacro) fMacro = new TMacro(*other.fMacro);
144    if (other.fConfigDeps) fConfigDeps = new TMacro(*other.fConfigDeps);
145    fRAddTask  = other.fRAddTask;
146    return *this;
147 }
148    
149 //______________________________________________________________________________
150 TMacro *AliAnalysisTaskCfg::OpenMacro(const char *name)
151 {
152 // Opens the specified macro if name is not empty. In case of success updates
153 // fMacroName, creates the maco object and returns its pointer.
154    // Clean-up previous macro if any
155    if (fMacro) {
156       delete fMacro;
157       fMacro = 0;
158    }   
159    TString expname;
160    if (strlen(name)) expname = gSystem->ExpandPathName(name);
161    else              expname = gSystem->ExpandPathName(fMacroName.Data());
162    if (expname.IsNull()) {
163       Error("OpenMacro", "Macro name not provided and not previously set");
164       return 0;
165    }   
166    if (gSystem->AccessPathName(expname)) {
167       Error("OpenMacro", "Macro: %s cannot be opened.", expname.Data());
168       return 0;
169    }
170    if (strlen(name)) fMacroName = name;
171    fMacro = new TMacro(expname);
172    return fMacro;
173 }   
174
175 //______________________________________________________________________________
176 void AliAnalysisTaskCfg::SetMacro(TMacro *macro)
177 {
178 // Set the AddTask macro from outside. This will discard the existing macro if
179 // any. The provided macro will be owned by this object.
180    if (fMacro) delete fMacro;
181    fMacro = macro;
182 }   
183
184 //______________________________________________________________________________
185 Long64_t AliAnalysisTaskCfg::ExecuteMacro(const char *newargs)
186 {
187 // Execute AddTask macro. Opens first the macro pointed by fMacroName if not yet
188 // done. Checks if the requested libraries are loaded, else loads them. Executes 
189 // with stored fMacroArgs unless new arguments are provided. The flag IsLoaded
190 // is set once the macro was successfully executed.
191    if (IsLoaded()) return kTRUE;
192    if (!fMacro && !OpenMacro()) {
193       Error("ExecuteMacro", "Cannot execute this macro");
194       return -1;
195    }
196    if (!CheckLoadLibraries()) {
197       Error("ExecuteMacro", "Cannot load requested libraries: %s", fLibs.Data());
198       return -1;
199    }
200    
201    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
202    if (!mgr) {
203       Error("ExecuteMacro", "Analysis manager not defined yet");
204       return -1;
205    }
206    Int_t ntasks0 = mgr->GetTasks()->GetEntriesFast();
207    TString args = newargs;
208    if (args.IsNull()) args = fMacroArgs;
209    Int_t error = 0;
210    Long64_t retval = fMacro->Exec(args, &error);
211    if (error != TInterpreter::kNoError)
212    {
213       Error("ExecuteMacro", "Macro interpretation failed");
214       return -1;
215    }
216    Int_t ntasks = mgr->GetTasks()->GetEntriesFast();
217    if (ntasks<=ntasks0)
218    {
219       Error("ExecuteMacro", "The macro did not add any tasks to the manager");
220       return -1;
221    }
222    Long64_t ptrTask = (Long64_t)mgr->GetTasks()->At(ntasks0);
223    if (retval >= ptrTask) {
224       TObject::SetBit(AliAnalysisTaskCfg::kLoaded, kTRUE);
225       fRAddTask = reinterpret_cast<TObject*>(retval);
226       if (fConfigDeps && dynamic_cast<TObject*>(fRAddTask)) {
227          TString classname = fRAddTask->ClassName();
228          classname += Form("* __R_ADDTASK__ = (%s*)0x%lx;", classname.Data(),(ULong_t)retval);
229          classname.Prepend("  ");
230          TObjString *line = fConfigDeps->GetLineWith("__R_ADDTASK__");
231          if (line) {
232             TList *lines = fConfigDeps->GetListOfLines();
233             lines->AddBefore(line, new TObjString(classname));
234          }
235       }   
236    }
237    Info("ExecuteMacro", "Macro %s added %d tasks to the manager", fMacro->GetName(), ntasks-ntasks0);
238    return retval;
239 }
240
241 //______________________________________________________________________________
242 Int_t AliAnalysisTaskCfg::GetNlibs() const
243 {
244 // Returns number of requested libraries.
245    if (fLibs.IsNull()) return 0;
246    TObjArray *list  = fLibs.Tokenize(",");
247    Int_t nlibs = list->GetEntriesFast();
248    delete list;
249    return nlibs;
250 }
251
252 //______________________________________________________________________________
253 const char *AliAnalysisTaskCfg::GetLibrary(Int_t i) const
254 {
255 // Returns library name for the i-th library.
256    Int_t nlibs = GetNlibs();
257    if (i>=nlibs) return 0;
258    static TString libname;
259    TObjArray *list  = fLibs.Tokenize(",");
260    libname = list->At(i)->GetName();
261    libname.ReplaceAll(".so","");
262    libname.ReplaceAll(" ","");
263    if (libname.BeginsWith("lib")) libname.Remove(0, 3);
264    delete list;
265    return libname.Data();
266 }
267
268 //______________________________________________________________________________
269 Bool_t AliAnalysisTaskCfg::CheckLoadLibraries() const
270 {
271 // Check if all requested libraries were loaded, otherwise load them. If some
272 // library cannot be loaded return false.
273    TString library;
274    Int_t nlibs = GetNlibs();
275    for (Int_t i=0; i<nlibs; i++) {
276       library = GetLibrary(i);
277       library.Prepend("lib");
278       Int_t loaded = strlen(gSystem->GetLibraries(library,"",kFALSE));
279       if (!loaded) loaded = gSystem->Load(library);
280       if (loaded < 0) {
281          Error("CheckLoadLibraries", "Cannot load library %s", library.Data());
282          return kFALSE;
283       }
284    }
285    return kTRUE;
286 }
287
288 //______________________________________________________________________________
289 Bool_t AliAnalysisTaskCfg::NeedsLibrary(const char *lib) const
290 {
291 // Check if a given library is needed by the module.
292    TString libname = lib;
293    libname.ReplaceAll(".so","");
294    if (libname.BeginsWith("lib")) libname.Remove(0, 3);
295    return fLibs.Contains(libname);
296 }
297
298 //______________________________________________________________________________
299 Int_t AliAnalysisTaskCfg::GetNdeps() const
300 {
301 // Returns number of requested libraries.
302    if (fDeps.IsNull()) return 0;
303    Int_t ndeps = fDeps.CountChar(',')+1;
304    return ndeps;
305 }
306
307 //______________________________________________________________________________
308 const char *AliAnalysisTaskCfg::GetDependency(Int_t i) const
309 {
310 // Returns library name for the i-th library.
311    Int_t ndeps = GetNdeps();
312    if (i>=ndeps) return 0;
313    static TString depname;
314    TObjArray *list  = fDeps.Tokenize(",");
315    depname = list->At(i)->GetName();
316    depname.ReplaceAll(" ","");
317    delete list;
318    return depname.Data();
319 }
320
321 //______________________________________________________________________________
322 Bool_t AliAnalysisTaskCfg::NeedsDependency(const char *dep) const
323 {
324 // Check if a given library is needed by the module.
325    return fDeps.Contains(dep);
326 }
327
328 //______________________________________________________________________________
329 TMacro *AliAnalysisTaskCfg::OpenConfigMacro(const char *name)
330 {
331 // Opens the specified macro if name is not empty.
332    if (fConfigDeps) {
333       delete fConfigDeps;
334       fConfigDeps = 0;
335    }
336    
337    TString expname = gSystem->ExpandPathName(name);
338    if (expname.IsNull()) {
339       Error("OpenConfigMacro", "Macro name not provided");
340       return 0;
341    }   
342    if (gSystem->AccessPathName(expname)) {
343       Error("OpenMacro", "Macro: %s cannot be opened.", expname.Data());
344       return 0;
345    }
346    fConfigDeps = new TMacro(expname);
347    return fConfigDeps;
348 }   
349
350 //______________________________________________________________________________
351 void AliAnalysisTaskCfg::SetConfigMacro(TMacro *macro)
352 {
353 // Set the macro for configuring deps from outside. This will discard the 
354 // existing macro if any. The provided macro will be owned by this object.
355    if (fConfigDeps) delete fConfigDeps;
356    fConfigDeps = macro;
357 }   
358   
359 //______________________________________________________________________________
360 Long64_t AliAnalysisTaskCfg::ExecuteConfigMacro()
361 {
362 // Execute macro to configure dependencies. No arguments are supported.
363    if (!fConfigDeps) {
364       Error("ExecuteConfigMacro", "Call OpenConfigMacro() first");
365       return -1;
366    }
367    if (!CheckLoadLibraries()) {
368       Error("ExecuteConfigMacro", "Cannot load requested libraries: %s", fLibs.Data());
369       return -1;
370    }
371    return fConfigDeps->Exec();
372 }
373
374 //______________________________________________________________________________
375 void AliAnalysisTaskCfg::SetDataTypes(const char *types)
376 {
377 // Sets the data types supported by the module. Stored in upper case.
378    fDataTypes = types;
379    fDataTypes.ToUpper();
380 }
381
382 //______________________________________________________________________________
383 Bool_t AliAnalysisTaskCfg::SupportsData(const char *type) const
384 {
385 // Checks if the given data type is supported.
386    TString stype = type;
387    stype.ToUpper();
388    return fDataTypes.Contains(stype);
389 }
390
391 //______________________________________________________________________________
392 void AliAnalysisTaskCfg::Print(Option_t * option) const
393 {
394 // Print content of the module.
395    TString opt(option);
396    Bool_t full = (opt.Length())?kTRUE:kFALSE;
397    printf("====================================================================\n");
398    printf("# Analysis task:                %s\n", GetName());
399    printf("# Supported data types:         %s\n", fDataTypes.Data());
400    printf("# Extra libraries:              %s\n", fLibs.Data());
401    printf("# Extra dependencies:           %s\n", fDeps.Data());
402    if (fConfigDeps) {
403       printf("# Macro to configure deps:      %s\n", fConfigDeps->GetTitle());
404       if (full) fConfigDeps->Print();
405    }   
406    printf("# Macro connecting this task:   %s\n", fMacroName.Data());
407    printf("# Arguments to run the macro:   %s\n", fMacroArgs.Data());
408    if (full) {
409       if (fMacro) fMacro->Print();
410       else {
411          TMacro macro(gSystem->ExpandPathName(fMacroName.Data()));
412          macro.Print();
413       }   
414    }   
415 }
416    
417 //______________________________________________________________________________
418 void AliAnalysisTaskCfg::SaveAs(const char *filename, Option_t *option) const
419 {
420 // Save the configuration module as text file in the form key:value. The
421 // option can be APPEND, otherwise the file gets overwritten.
422    TString opt(option);
423    opt.ToUpper();
424    ios::openmode mode = ios::out;
425    if (opt == "APPEND") mode = ios::app;
426    ofstream out;
427    out.open(filename, mode);
428    if (out.bad()) {
429       Error("SaveAs", "Bad file name: %s", filename);
430       return;
431    }
432    out << "#Module.Begin " << GetName() << endl;
433    out << "#Module.Libs " << fLibs << endl;
434    out << "#Module.Deps " << fDeps << endl;
435    out << "#Module.DataTypes " << fDataTypes << endl;
436    out << "#Module.MacroName " << fMacroName << endl;
437    out << "#Module.MacroArgs " << fMacroArgs << endl;
438    if (fConfigDeps) {
439       out << "#Config.Deps " << fConfigDeps->GetTitle() << endl;
440    }      
441 }
442
443
444 //______________________________________________________________________________
445 const char *AliAnalysisTaskCfg::DecodeValue(TString &line)
446 {
447 // Decode the value string from the line
448    static TString value;
449    value = line(line.Index(' '),line.Length());
450    value = value.Strip(TString::kLeading,' ');
451    value = value.Strip(TString::kTrailing,' ');
452    return value.Data();
453 }
454    
455 //______________________________________________________________________________
456 TObjArray *AliAnalysisTaskCfg::ExtractModulesFrom(const char *filename)
457 {
458 // Read all modules from a text file and add them to an object array. The
459 // caller must delete the array at the end. Any module must start with a line
460 // containing: #Module.Begin
461    TString expname = gSystem->ExpandPathName(filename);
462    if (gSystem->AccessPathName(expname)) {
463       ::Error("ExtractModulesFrom", "Cannot open file %s", filename);
464       return 0;
465    }   
466    AliAnalysisTaskCfg *cfg = 0;
467    TObjArray *array = 0;
468    ifstream in;
469    in.open(expname);
470    char cline[1024];
471    TString line;
472    TString decode;
473    TMacro *addMacro = 0;
474    TMacro *addConfig = 0;
475    while (in.good()) {
476       in.getline(cline,1024);
477       line = cline;
478       if (line.BeginsWith("#Module.Begin")) {
479       // New module found, save previous if any
480          if (cfg) {
481             if (addMacro) cfg->SetMacro(addMacro);
482             if (addConfig) cfg->SetConfigMacro(addConfig);
483             if (!array) array = new TObjArray();
484             array->Add(cfg);
485          }
486          // Decode module name from the line
487          decode = AliAnalysisTaskCfg::DecodeValue(line);
488          cfg = new AliAnalysisTaskCfg(decode);
489          addMacro = 0;
490          addConfig = 0;
491       } else if (cfg && line.BeginsWith("#Module.Libs")) {
492          // Libraries section
493          decode = AliAnalysisTaskCfg::DecodeValue(line);
494          cfg->SetLibraries(decode);
495       } else if (cfg && line.BeginsWith("#Module.Deps")) {
496          // Dependencies section
497          decode = AliAnalysisTaskCfg::DecodeValue(line);
498          cfg->SetDependencies(decode);
499       } else if (cfg && line.BeginsWith("#Module.DataTypes")) {
500          // Data types
501          decode = AliAnalysisTaskCfg::DecodeValue(line);
502          cfg->SetDataTypes(decode);
503       } else if (cfg && line.BeginsWith("#Module.MacroName")) {
504          // Name of the add task macro (including path)
505          decode = AliAnalysisTaskCfg::DecodeValue(line);
506          cfg->SetMacroName(decode);
507       } else if (cfg && line.BeginsWith("#Module.MacroArgs")) {
508          // Arguments for the AddTask macro
509          decode = AliAnalysisTaskCfg::DecodeValue(line);
510          cfg->SetMacroArgs(decode);
511       } else if (cfg && line.BeginsWith("#Module.StartMacro")) {
512          // Marker for start of the AddTask macro
513          addMacro = new TMacro();
514          TString shortName = gSystem->BaseName(cfg->GetMacroName());
515          shortName = shortName(0,shortName.Index("."));
516          addMacro->SetName(shortName);
517          addMacro->SetTitle(cfg->GetMacroName());
518       } else if (cfg && line.BeginsWith("#Module.StartConfig")) {
519          // Marker for start of the configuration macro
520          addConfig = new TMacro();
521          TString shortName = gSystem->BaseName(cfg->GetMacroName());
522          shortName = shortName(0,shortName.Index("."));
523          shortName += "Config";
524          addConfig->SetName(shortName);
525          shortName.Prepend("/");
526          shortName.Prepend(gSystem->DirName(cfg->GetMacroName()));
527          shortName += ".C";
528          addConfig->SetTitle(shortName);
529       } else if (cfg && line.BeginsWith("#Module.EndMacro")) {
530          // Marker for the end of the embedded macro. EndMacro block mandatory.
531          if (cfg && addMacro) {
532             cfg->SetMacro(addMacro);
533             addMacro = 0;
534          } else {
535             ::Error("ExtractModulesFrom", "Canot end un-started macro block");
536          }
537       } else if (cfg && line.BeginsWith("#Module.EndConfig")) {
538          // Marker for the end of the config macro. EndConfig block is mandatory
539          if (cfg && addConfig) {
540             addConfig->GetListOfLines()->AddFirst(new TObjString(Form("%s() {",gSystem->BaseName(addConfig->GetName()))));
541             addConfig->GetListOfLines()->AddLast(new TObjString("}"));
542             cfg->SetConfigMacro(addConfig);
543             addConfig = 0;
544          } else {
545             ::Error("ExtractModulesFrom", "Canot end un-started config macro block");
546          }
547       } else {   
548          // Reading a block line
549          if (addMacro) addMacro->AddLine(line);
550          else if (addConfig) addConfig->AddLine(line);
551       }   
552    }
553    // Add last found object to the list
554    if (cfg) {
555       if (addMacro) ::Error("ExtractModulesFrom", "#Module.EndMacro block not found");         
556       if (addConfig) ::Error("ExtractModulesFrom", "#Module.EndConfig block not found");
557       if (!array) array = new TObjArray();
558       array->Add(cfg);
559    }
560    return array;  
561 }