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