]>
Commit | Line | Data |
---|---|---|
04a0c008 | 1 | //-*- Mode: C++ -*- |
2 | // $Id$ | |
3 | ||
4 | /// @file run-single-task.C | |
5 | /// @author Matthias.Richter@ift.uib.no | |
6 | /// @date 2012-04-06 | |
7 | /// @brief Run a single task | |
8 | /// | |
9 | /// Helper macro to run a single task either locally or on Grid | |
10 | /// Usage: | |
c98603ea | 11 | /// aliroot -b -q -l run-single-task.C'("mode", "input", "tasks", "name", "options", events, "path", "pattern", "friendPattern", "outputDir", "user")' |
04a0c008 | 12 | /// arguments |
13 | /// mode: local, full, test | |
c98603ea | 14 | /// input: In grid mode a list of run numbers. |
15 | /// In local mode: | |
16 | /// - ESD file AliESDs.root | |
17 | /// - a list of ESD files in a text file <choose-file-name>.txt | |
18 | /// - AOD file AliAOD.root | |
19 | /// - AODs with predefined list/AODs in same folder, specifiy as "AOD" | |
20 | /// | |
21 | /// tasks: list of class names/source or header files of task, or AddTask-Macro | |
04a0c008 | 22 | /// |
23 | /// optional arguments | |
24 | /// name: analysis name (default 'myanalysis') | |
c98603ea | 25 | /// options: optional arguments passed onto the task, e.g. 'mc', 'event-mixing' |
26 | /// options of run-single-task: | |
27 | /// 'mcData' -> the run numbers indicate MC Data, no '000' prepended | |
04a0c008 | 28 | /// events: number of events to be processed (default -1 -> all) |
29 | /// path: data search path for grid analysis (default from configuration file) | |
30 | /// pattern: data search pattern (default from configuration file) | |
39341c1f | 31 | /// friend pattern: friend file search pattern (default from configuration file) |
32 | /// output dir: output directory in Grid home (default gridwork/yyyy-mm-dd_hh-mm) | |
33 | /// user: default NULL, using user of active token | |
04a0c008 | 34 | /// |
35 | /// Examples: | |
36 | /// aliroot -b -q -l run-single-task.C'("full", "146860", "AliAnalysisTaskSample", "myanalysis_LHC11a")' | |
37 | /// | |
38 | /// aliroot -b -q -l run-single-task.C'("local", "$ALICE_ROOT/test/ppbench/AliESDs.root", "AliAnalysisTaskSample")' | |
39 | /// | |
39341c1f | 40 | /// aliroot -b -q -l run-single-task.C'("local", "AOD", "AddTaskSample.C")' |
9a3d923b | 41 | /// |
39341c1f | 42 | /// aliroot -b -q -l run-single-task.C'("full", "146860", "AliAnalysisTaskSample", "correlation3p_LHC11a", 0, -1, "/alice/data/2011/LHC11a", "*/pass2_without_SDD/AOD*/*/AliAOD.root")' |
04a0c008 | 43 | /// |
44 | /// Data input: | |
45 | /// depending on the format of the search pattern either the ESD or AOD input handler is used. | |
46 | /// | |
47 | /// Source files: | |
48 | /// If the task and classes used by the task are not in an AliRoot library available, e.g. | |
49 | /// for the purpose of development, all header and source files need to be in the local | |
50 | /// directory. The macro searches automatically for dependencies, compiles those and | |
51 | /// copies files to the Grid working directory. In order to make the files accessible in | |
52 | /// the local directory, the files can be just linked. | |
53 | /// <pre> | |
54 | /// for f in <search path>; do ln -s $f; done | |
55 | /// </pre> | |
c98603ea | 56 | /// If there are dependencies (include headers) which are not available in the working |
57 | /// directory, the macro searches for the aliroot libraries implementing them, and adds | |
58 | /// the libraries if found to the setup. | |
04a0c008 | 59 | /// |
60 | /// Local analysis: | |
61 | /// requires only the path to the input file and the task class name. If the specified file is | |
39341c1f | 62 | /// a text file (.txt) each line can contain an input ESD file path, all files are chained. |
63 | /// Analysis on local AOD files needs to be setup prior to this macro. gDirectory must contain | |
64 | /// a TChain object of name 'aodTree'. This is for example created by macros like | |
65 | /// $ALICE_ROOT/PWGHF/vertexingHF/MakeAODInputChain.C | |
66 | /// Set $ALICE_ROOT/PWGHF/correlationHF/macros/setupDxHFE.C for an example. | |
04a0c008 | 67 | /// |
68 | /// Grid analysis: | |
69 | /// All modes provided by the AliAnalysisAlien plugin can be used, e.g. full, test, offline | |
70 | /// A couple of settings need to be defined in a configuration file 'grid-config.C' which can be | |
39341c1f | 71 | /// either in the local directory or home directory. The file can look like |
04a0c008 | 72 | /// <pre> |
73 | /// const char* alienAPIVersion="V1.1x"; | |
39341c1f | 74 | /// const char* alienROOTVersion="v5-34-01"; |
75 | /// const char* alienAliROOTVersion="v5-03-61-AN"; | |
04a0c008 | 76 | /// const char* defaultGridDataDir="/alice/data/2011/LHC11a"; |
77 | /// const char* defaultDataPattern="*/pass2_without_SDD/*/AliESDs.root"; | |
39341c1f | 78 | /// const char* defaultFriendDataPattern=""; |
04a0c008 | 79 | /// {} // note this empty body |
80 | /// </pre> | |
81 | /// Data path and pattern can also be specified as command line arguments. | |
82 | /// The working directory in the grid home directory of the user is set to | |
39341c1f | 83 | /// gridwork/<date>_<time> (gridwork/yyyy-mm-dd_hh-mm), can be overridden by command line |
84 | /// parameter. | |
04a0c008 | 85 | /// |
a354ea1a | 86 | /// Options: |
87 | /// Options to the macro can be propagated via the parameter 'arguments', the known options | |
88 | /// are parsed and filtered out from the arguments, which are than further propagated to | |
89 | /// AdTask macros and task. | |
90 | /// --mcData switch indicates that the input data is mc data, the run numbers have | |
91 | /// a different format in real data | |
92 | /// --nTestFiles= number of test files to be used in test mode (default 10) | |
93 | /// --merge= merging mode 'local', 'grid', 'collect' (default Grid) | |
94 | /// | |
95 | /// Merging of output: | |
96 | /// The output files can be merged locally by using the argument '--merge=local'. In that | |
97 | /// case all files are downloaded to the local machine and merged. The merging on grid | |
98 | /// requires to launch the analysis with argument '--merge=grid'. After the jobs are done | |
99 | /// further steps are required, | |
100 | /// 1) run in mode "terminate" with argument '--merge=grid' and working directory on grid, | |
101 | /// 2) run in mode "terminate" with argument '--merge=collect' and working directory on grid. | |
102 | /// Step 1) can be repeated multiple times, the AnalysisManager will in each stage merge | |
103 | /// several files of the previous stage, it will notify you when the final result has | |
104 | /// already been merged. | |
04a0c008 | 105 | /// |
c98603ea | 106 | /// Suggestions: |
107 | /// Feedback appreciated: Matthias.Richter@cern.ch | |
108 | /// If you find this macro useful but not applicable without patching it, let me know | |
109 | /// your changes and use cases. | |
110 | ||
04a0c008 | 111 | |
f6f9bc4b | 112 | #if defined(__CINT__) && !defined(__MAKECINT__) |
04a0c008 | 113 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
114 | // | |
115 | // environment | |
116 | // | |
9a3d923b | 117 | int macroVerbosity=0; |
118 | const char* defaultAnalysisName="myanalysis"; | |
04a0c008 | 119 | const char* includePath="-I. -I$ROOTSYS/include -I$ALICE_ROOT/include"; |
120 | const char* libraryDependencies= | |
9a3d923b | 121 | "libSTEERBase.so " |
122 | "libESD.so " | |
123 | "libAOD.so " | |
124 | "libANALYSIS.so " | |
125 | "libANALYSISalice.so " | |
04a0c008 | 126 | ; |
127 | ||
128 | TString GetIncludeHeaders(const char* filename, TString& headers, TString& libs, bool loadClass=true); | |
a354ea1a | 129 | TObject* BuildCodeTree(const char* filename, TObject* pTree); |
f6f9bc4b | 130 | int ProcessCodeTree(TObject* tree, TString& sources, TString& headers, TString& libs); |
04a0c008 | 131 | void ErrorConfigurationFile(const char* fileName); |
132 | ||
133 | void run_single_task(const char* mode, | |
134 | const char* input, | |
685fea75 | 135 | const char* tasknames, |
9a3d923b | 136 | const char* analysisName=defaultAnalysisName, |
c98603ea | 137 | const char* arguments="", |
04a0c008 | 138 | int nevents=-1, |
139 | const char* gridDataDir=NULL, | |
140 | const char* dataPattern=NULL, | |
9a3d923b | 141 | const char* friendDataPattern=NULL, |
142 | TString odir="", | |
04a0c008 | 143 | const char* user=NULL |
144 | ) | |
145 | { | |
146 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
147 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
148 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
149 | // | |
150 | // defaults | |
151 | // | |
9a3d923b | 152 | if (analysisName==defaultAnalysisName && gDirectory!=NULL) { |
153 | // NOTE: the direct pointer comparison is on purpose | |
154 | // string comparison not necessary in this special case | |
155 | ||
156 | // fetch the analysis name from the setup file | |
157 | const char* confObjectName="analysis_name"; | |
158 | TObject* confObject=gDirectory->FindObject(confObjectName); | |
159 | if (confObject) { | |
160 | analysisName=confObject->GetTitle(); | |
161 | } | |
162 | } | |
163 | ||
04a0c008 | 164 | bool bRunLocal=strcmp(mode, "local")==0; |
165 | const char* gridConfigFile="grid-config.C"; | |
166 | TString strGridConfigFile=gridConfigFile; | |
167 | if (gSystem->AccessPathName(strGridConfigFile)!=0) { | |
168 | strGridConfigFile.Prepend("/"); | |
169 | strGridConfigFile.Prepend(gSystem->Getenv("HOME")); | |
170 | if (gSystem->AccessPathName(strGridConfigFile)!=0) { | |
171 | if (!bRunLocal) { | |
172 | ErrorConfigurationFile(gridConfigFile); | |
173 | return; | |
174 | } | |
175 | strGridConfigFile=""; | |
176 | } | |
177 | } | |
178 | ||
179 | if (strGridConfigFile.IsNull()==0 && !bRunLocal) { | |
180 | cout << "loading grid configuration from file '" << strGridConfigFile << "':" << endl; | |
181 | gROOT->LoadMacro(strGridConfigFile); | |
9a3d923b | 182 | cout << " alienAPIVersion =" << alienAPIVersion << endl; |
183 | cout << " alienROOTVersion =" << alienROOTVersion << endl; | |
184 | cout << " alienAliROOTVersion =" << alienAliROOTVersion << endl; | |
185 | cout << " defaultGridDataDir =" << defaultGridDataDir << endl; | |
186 | cout << " defaultDataPattern =" << defaultDataPattern << endl; | |
187 | cout << " defaultFriendDataPattern =" << defaultFriendDataPattern << endl; | |
04a0c008 | 188 | |
189 | if (gridDataDir==NULL) gridDataDir=defaultGridDataDir; | |
190 | if (dataPattern==NULL) dataPattern=defaultDataPattern; | |
9a3d923b | 191 | if (friendDataPattern==NULL) friendDataPattern=defaultFriendDataPattern; |
04a0c008 | 192 | } else if (bRunLocal) { |
193 | if (dataPattern==NULL) { | |
c98603ea | 194 | // thats a very crude logic, I guess it can fail in some special cases |
9a3d923b | 195 | TString strin=input; |
c98603ea | 196 | if (strin.Contains("AOD")) |
9a3d923b | 197 | dataPattern="AOD"; |
c98603ea | 198 | else if (strin.Contains("ESD")) |
9a3d923b | 199 | dataPattern="ESD"; |
04a0c008 | 200 | } |
201 | } | |
202 | ||
9a3d923b | 203 | if(!bRunLocal) { |
204 | // Connect to AliEn | |
205 | TGrid::Connect("alien://"); | |
206 | } | |
c98603ea | 207 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
208 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
209 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
210 | // | |
211 | // argument settings | |
212 | // | |
7162a4fd | 213 | bool bRunAnalysis=true; |
214 | bool bDefaultOutput=true; | |
a354ea1a | 215 | bool bMergeOnGrid=true; |
c98603ea | 216 | bool mcData=false; |
a354ea1a | 217 | int nTestFiles=10; |
c98603ea | 218 | TString strArguments(arguments); |
219 | TObjArray* tokens=strArguments.Tokenize(" "); | |
220 | if (tokens) { | |
221 | for (int iToken=0; iToken<tokens->GetEntriesFast(); iToken++) { | |
222 | TObject* token=tokens->At(iToken); | |
223 | if (!token) continue; | |
224 | TString arg=token->GetName(); | |
225 | const char* key=NULL; | |
226 | ||
a354ea1a | 227 | key="--mcData"; |
c98603ea | 228 | if (arg.CompareTo(key)==0) { |
a354ea1a | 229 | // this is an argument to the macro, don't propagate it further to tasks |
230 | // switch indicates that the input data is mc data, the run numbers have | |
231 | // a different format in real data | |
232 | // NOTE: not to be confused with option 'mc' which is propagated to tasks | |
233 | // and switches processing and output modes inside tasks | |
c98603ea | 234 | mcData=true; |
235 | } | |
a354ea1a | 236 | key="--merge="; |
237 | if (arg.BeginsWith(key)) { | |
238 | // this is an argument to the macro, don't propagate it further to tasks | |
239 | strArguments.ReplaceAll(arg, ""); | |
240 | arg.ReplaceAll(key, ""); | |
241 | if (arg.CompareTo("local")==0) { | |
242 | // download all files and merge locally | |
243 | bMergeOnGrid=false; | |
244 | } else if (arg.CompareTo("collect")==0) { | |
245 | // download the output of merging on Grid | |
246 | // macro must have been called in mode "terminate" with option | |
247 | // --merge=grid and the correct grid working directory | |
248 | bMergeOnGrid=false; | |
249 | } else if (arg.CompareTo("grid")==0) { | |
250 | // merge output on grid, the correct grid working directory | |
251 | // must be provided | |
252 | bMergeOnGrid=true; | |
253 | } | |
254 | } | |
255 | key="--nTestFiles="; | |
256 | if (arg.BeginsWith(key)) { | |
257 | // this is an argument to the macro, don't propagate it further to tasks | |
258 | strArguments.ReplaceAll(arg, ""); | |
259 | arg.ReplaceAll(key, ""); | |
260 | nTestFiles=arg.Atoi(); | |
261 | } | |
7162a4fd | 262 | key="--noDefaultOutput"; |
263 | if (arg.CompareTo(key)==0) { | |
264 | // this is an argument to the macro, don't propagate it further to tasks | |
265 | strArguments.ReplaceAll(arg, ""); | |
266 | bDefaultOutput=false; | |
267 | } | |
268 | key="--stopBeforeRunning"; | |
269 | if (arg.CompareTo(key)==0) { | |
270 | // this is an argument to the macro, don't propagate it further to tasks | |
271 | strArguments.ReplaceAll(arg, ""); | |
272 | bRunAnalysis=false; | |
273 | } | |
c98603ea | 274 | } |
275 | delete tokens; | |
276 | } | |
277 | ||
04a0c008 | 278 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
279 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
280 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
281 | // | |
282 | // make the analysis manager | |
283 | // | |
284 | AliAnalysisManager *pManager = new AliAnalysisManager("AnalysisManager"); | |
285 | if (!pManager) { | |
286 | cerr << "failed to created AnalysisManager" << endl; | |
287 | return; | |
288 | } | |
289 | AliInputEventHandler *pInputHandler = NULL; | |
290 | TString strDataPattern(dataPattern); | |
9a3d923b | 291 | if (strDataPattern.Contains("AOD")) pInputHandler=new AliAODInputHandler; |
292 | else if (strDataPattern.Contains("ESD")) pInputHandler=new AliESDInputHandler; | |
04a0c008 | 293 | else { |
294 | cerr << "can not determine input type from data pattern '" << dataPattern << "'" << endl; | |
295 | return; | |
296 | } | |
297 | if (!pInputHandler) { | |
298 | cerr << "failed to created input handler" << endl; | |
299 | return; | |
300 | } | |
301 | //pInputHandler->SetReadFriends(kFALSE); | |
302 | pManager->SetInputEventHandler(pInputHandler); | |
303 | pManager->SetNSysInfo(1000); | |
304 | ||
305 | TString ofile=Form("%s.root", analysisName); | |
306 | ||
307 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
308 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
309 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
310 | // | |
311 | // load task classes and find and load all dependencies | |
312 | // | |
313 | gSystem->AddIncludePath(includePath); | |
314 | TString libraries=libraryDependencies; | |
9a3d923b | 315 | if (gDirectory!=NULL) { |
316 | // fetch the analysis libraries from the setup file | |
317 | const char* confObjectName="analysis_libraries"; | |
318 | TObject* confObject=gDirectory->FindObject(confObjectName); | |
319 | if (confObject) { | |
320 | TString analysisLibraries(confObject->GetTitle()); | |
321 | TObjArray* pTokens=analysisLibraries.Tokenize(" "); | |
322 | if (pTokens) { | |
323 | for (int i=0; i<pTokens->GetEntriesFast(); i++) { | |
324 | if (libraries.Contains(pTokens->At(i)->GetName())==0) { | |
325 | libraries+=" "; | |
326 | libraries+=pTokens->At(i)->GetName(); | |
d8f45894 | 327 | TString library=pTokens->At(i)->GetName(); |
328 | if (!library.EndsWith(".so")) libraries+=".so"; | |
9a3d923b | 329 | } |
330 | } | |
331 | delete pTokens; | |
332 | } | |
333 | } | |
334 | } | |
04a0c008 | 335 | TObjArray* pTokens=libraries.Tokenize(" "); |
336 | if (pTokens) { | |
337 | for (int i=0; i<pTokens->GetEntriesFast(); i++) { | |
d8f45894 | 338 | TString library=pTokens->At(i)->GetName(); |
339 | if (!library.EndsWith(".so")) { | |
340 | cerr << "libraries need to have ending '.so' in order to be correctly processed by alien plugin, please correct library name '" << library << "'" << endl; | |
341 | } | |
9a3d923b | 342 | if (gSystem->Load(pTokens->At(i)->GetName())==0) { |
343 | cout << "loading " << pTokens->At(i)->GetName() << endl; | |
344 | } | |
04a0c008 | 345 | } |
346 | delete pTokens; | |
347 | } | |
04a0c008 | 348 | |
685fea75 | 349 | TString taskNames=tasknames; |
350 | TString taskClasses=""; | |
351 | TString taskSources=""; | |
352 | TString taskHeaders=""; | |
353 | TString addTaskMacros=""; | |
f6f9bc4b | 354 | TString dependencyHeader; |
355 | TString dependencySource; | |
685fea75 | 356 | TString parPackages=""; |
f6f9bc4b | 357 | TString delimiter(" "); |
358 | TStringToken taskNameTokens(taskNames, delimiter); | |
359 | TObject* pCodeTree=NULL; | |
360 | { | |
361 | while (taskNameTokens.NextToken()) { | |
362 | TString taskSource(taskNameTokens); | |
363 | TString taskHeader(taskNameTokens); | |
685fea75 | 364 | bool bIsAddTask=false; |
39341c1f | 365 | if (taskSource.EndsWith(".C")) { |
366 | // suppose that's an 'AddTask' macro | |
367 | taskHeader=""; | |
368 | bIsAddTask=true; | |
369 | } else if (taskSource.EndsWith(".par")) { | |
370 | // par file | |
371 | if (gSystem->AccessPathName(taskSource)!=0) { | |
372 | ::Error("run_single_task", Form("par file '%s' not found in current directory, you might want to set a symbolic link", taskSource.Data())); | |
373 | return; | |
374 | } | |
375 | parPackages+=" "; | |
376 | parPackages+=taskSource; | |
377 | continue; | |
378 | } else if (taskSource.EndsWith(".h")) { | |
379 | taskSource.ReplaceAll(".h", ""); | |
380 | taskClasses+=" "; | |
381 | taskClasses+=taskSource; | |
382 | taskSource+=".cxx"; | |
383 | } else if (taskSource.EndsWith(".cxx")) { | |
384 | taskHeader.ReplaceAll(".cxx", ""); | |
385 | taskClasses+=" "; | |
386 | taskClasses+=taskHeader; | |
387 | taskHeader+=".h"; | |
388 | } else { | |
389 | taskClasses+=" "; | |
390 | taskClasses+=taskSource; | |
391 | taskSource+=".cxx"; | |
392 | taskHeader+=".h"; | |
393 | } | |
39341c1f | 394 | if (gSystem->AccessPathName(taskSource)==0) { |
f6f9bc4b | 395 | pCodeTree=BuildCodeTree(taskSource, pCodeTree); |
39341c1f | 396 | if (!bIsAddTask) {taskSources+=" "; taskSources+=taskSource;} |
397 | else {addTaskMacros+=" "; addTaskMacros+=taskSource;} | |
398 | } | |
f6f9bc4b | 399 | if (gSystem->AccessPathName(taskHeader)==0) { |
400 | pCodeTree=BuildCodeTree(taskHeader, pCodeTree); | |
401 | taskHeaders+=" "; taskHeaders+=taskHeader; | |
39341c1f | 402 | } |
685fea75 | 403 | } |
685fea75 | 404 | } |
f6f9bc4b | 405 | ProcessCodeTree(pCodeTree, dependencySource, dependencyHeader, libraries); |
406 | ||
685fea75 | 407 | cout << "Tasks: " << taskClasses << endl; |
408 | cout << "Task files: " << taskSources << addTaskMacros << taskHeaders << endl; | |
04a0c008 | 409 | cout << "Dependency classes: " << dependencySource << endl; |
410 | cout << "Dependency headers: " << dependencyHeader << endl; | |
411 | cout << "Dependency libraries: " << libraries << endl; | |
685fea75 | 412 | cout << "Packages: " << parPackages << endl; |
04a0c008 | 413 | |
414 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
415 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
416 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
417 | // | |
418 | // init for local or GRID analysis | |
419 | // | |
9a3d923b | 420 | AliAnalysisAlien *alienHandler = NULL; // for grid analysis |
04a0c008 | 421 | TChain *chain=NULL; // for local analysis |
422 | TString strInput=input; | |
423 | if (bRunLocal) { | |
424 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
425 | // | |
426 | // local analysis | |
427 | // | |
c98603ea | 428 | if (strInput.BeginsWith("alien://")) { |
429 | // file on Grid -> connect to AliEn | |
430 | TGrid::Connect("alien://"); | |
431 | } | |
04a0c008 | 432 | if(strInput.EndsWith("AliESDs.root")){ |
433 | // suppose it's a single ESD file | |
434 | chain = new TChain("esdTree"); | |
435 | chain->Add(strInput); | |
436 | } else if(strInput.EndsWith(".txt")) { | |
437 | // Constructs chain from filenames in *.txt | |
438 | // in the form $DIR/AliESDs.root | |
439 | gROOT->LoadMacro("$ALICE_ROOT/PWG0/CreateESDChain.C"); | |
440 | // chain can contain up to 200 files, value can be modified to | |
441 | // include a subset of what the *txt file contains | |
c98603ea | 442 | chain = CreateESDChain(strInput.Data(),200); |
04a0c008 | 443 | |
444 | // check if the files are on grid | |
445 | TIter next(chain->GetListOfFiles()); | |
446 | TChainElement *chEl = 0; | |
447 | while(( chEl = (TChainElement*)next() )){ | |
448 | TString tmp = chEl->GetTitle(); | |
449 | if(tmp.BeginsWith("alien://")) { | |
450 | TGrid::Connect("alien://"); | |
451 | break; | |
452 | } | |
453 | } | |
c98603ea | 454 | } else if(strInput.EndsWith("ESD")){ |
455 | // fetch esd tree from the setup macro | |
a354ea1a | 456 | const char* esdTreeName="esdTree"; |
c98603ea | 457 | if (gDirectory!=NULL) { |
c98603ea | 458 | TObject* chainObject=gDirectory->FindObject(esdTreeName); |
459 | if (chainObject) { | |
460 | chain=dynamic_cast<TChain*>(chainObject); | |
461 | } | |
462 | } | |
463 | if (!chain) { | |
464 | ::Error("run_single_task", Form("failed to fetch esd tree object from setup; the chain with name '%s' has to be created before calling this macro", esdTreeName)); | |
465 | return; | |
466 | } | |
467 | } else if(strInput.EndsWith("AliAOD.root")){ | |
468 | // single local AOD file | |
469 | chain = new TChain("aodTree"); | |
470 | chain->Add(strInput); | |
9a3d923b | 471 | } else if(strInput.EndsWith("AOD")){ |
472 | // fetch aod tree from the setup macro | |
a354ea1a | 473 | const char* aodTreeName="aodTree"; |
9a3d923b | 474 | if (gDirectory!=NULL) { |
39341c1f | 475 | TObject* chainObject=gDirectory->FindObject(aodTreeName); |
9a3d923b | 476 | if (chainObject) { |
477 | chain=dynamic_cast<TChain*>(chainObject); | |
478 | } | |
479 | } | |
480 | if (!chain) { | |
39341c1f | 481 | ::Error("run_single_task", Form("failed to fetch aod tree object from setup; the chain with name '%s' has to be created before calling this macro", aodTreeName)); |
482 | return; | |
9a3d923b | 483 | } |
04a0c008 | 484 | } else { |
39341c1f | 485 | ::Error("run_single_task", Form("invalid input")); |
486 | return; | |
04a0c008 | 487 | } |
488 | } else { | |
489 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
490 | // | |
491 | // grid analysis | |
492 | // | |
39341c1f | 493 | bool bSetRun=true; |
39341c1f | 494 | if (!strInput.IsDigit()) { |
495 | // support for external macros specifying the the runs to be | |
496 | // analyzed | |
497 | // the input is expected to be an external plugin with name 'input' | |
498 | // and all run numbers being set | |
499 | TObject* pObj=gDirectory->FindObject(input); | |
500 | if (pObj) alienHandler=dynamic_cast<AliAnalysisAlien*>(pObj); | |
501 | if (!alienHandler) { | |
502 | ::Error("run_single_task", Form("can not find plugin of name '%s', please setup alien handler with name and run numbers before calling this macro", input)); | |
503 | return; | |
504 | } | |
505 | bSetRun=false; | |
506 | } else { | |
507 | alienHandler=new AliAnalysisAlien(); | |
508 | } | |
04a0c008 | 509 | if (!alienHandler) { |
39341c1f | 510 | ::Error("run_single_task", Form("failed to create alien handler")); |
04a0c008 | 511 | return; |
512 | } | |
513 | ||
514 | // do not check for copying to grid (CLOSE_SE) | |
515 | alienHandler->SetCheckCopy(kFALSE); | |
516 | ||
517 | // Set the run mode (can be "full", "test", "offline", "submit" or "terminate") | |
518 | alienHandler->SetRunMode(mode); | |
a354ea1a | 519 | |
520 | // number of files in test mode configurable via argument '--nTestFiles=' | |
521 | if(mode=="test") alienHandler->SetNtestFiles(nTestFiles); | |
04a0c008 | 522 | |
523 | // check the versions available on alien with the command 'packages' | |
524 | alienHandler->SetAPIVersion(alienAPIVersion); | |
525 | alienHandler->SetROOTVersion(alienROOTVersion); | |
526 | alienHandler->SetAliROOTVersion(alienAliROOTVersion); | |
527 | ||
7162a4fd | 528 | // using only default output |
529 | // the alien plugin automatically recognizes all output files associated to output | |
530 | // containers, all files are treated in the standard output and added to the | |
531 | // root-archieve.root, which also seems to be needed for merging on Grid | |
532 | // see further down for using non-default output | |
533 | alienHandler->SetDefaultOutputs(bDefaultOutput); | |
a354ea1a | 534 | |
04a0c008 | 535 | if (user && user[0]!=0) alienHandler->SetUser(user); |
536 | ||
537 | // data alien directory | |
538 | alienHandler->SetGridDataDir(gridDataDir); | |
539 | ||
540 | // Set data search pattern | |
541 | alienHandler->SetDataPattern(dataPattern); | |
9a3d923b | 542 | alienHandler->SetFriendChainName(friendDataPattern); |
04a0c008 | 543 | |
685fea75 | 544 | TObjArray* packageTokens=parPackages.Tokenize(" " ); |
545 | if (packageTokens) { | |
546 | for (int iPackageToken=0; iPackageToken<packageTokens->GetEntriesFast(); iPackageToken++) { | |
547 | alienHandler->EnablePackage(packageTokens->At(iPackageToken)->GetName()); | |
548 | } | |
549 | delete packageTokens; | |
550 | } | |
551 | ||
39341c1f | 552 | if (bSetRun) { |
553 | // only set if input is a run number | |
c98603ea | 554 | if (!mcData && !strInput.BeginsWith("000")) |
39341c1f | 555 | alienHandler->SetRunPrefix("000"); // real data |
04a0c008 | 556 | |
39341c1f | 557 | alienHandler->AddRunNumber(input); |
558 | } | |
04a0c008 | 559 | |
560 | // define working and output directories | |
561 | TDatime dt; | |
9a3d923b | 562 | if(odir.IsNull()) |
563 | odir=(Form("gridwork/%04d-%02d-%02d_%02d-%02d", dt.GetYear(), dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute())); | |
564 | cout << odir << endl; | |
04a0c008 | 565 | alienHandler->SetGridWorkingDir(odir); // relative to $HOME |
566 | alienHandler->SetGridOutputDir("output"); // relative to working dir | |
9a3d923b | 567 | //alienHandler->SetOverwriteMode(); // overwrites the contents of the working and output directory |
04a0c008 | 568 | |
9a3d923b | 569 | // workaround for a Root feature: GetIncludePath() appends always |
570 | // the current Root include path including escaped quotes. Those | |
571 | // quotes make it difficult to pass the output directly. Search for the | |
572 | // last appended include path and truncate | |
573 | TString strIncludePath(gSystem->GetIncludePath()); | |
574 | Int_t pos=strIncludePath.Index(includePath); | |
575 | if (pos>=0) { | |
576 | Int_t cut=0; | |
577 | do { | |
578 | cut=pos+strlen(includePath); | |
579 | } while ((pos=strIncludePath.Index(includePath, cut))>cut); | |
580 | strIncludePath.Resize(cut); | |
581 | } | |
582 | alienHandler->AddIncludePath(strIncludePath); | |
04a0c008 | 583 | |
584 | // Note: there is no extra source or header file to be transferred if 'AddTask' macros are used | |
685fea75 | 585 | alienHandler->SetAnalysisSource(Form("%s %s %s %s", dependencySource.Data(), dependencyHeader.Data(), taskSources.Data(), taskHeaders.Data())); |
a354ea1a | 586 | alienHandler->SetAdditionalLibs(Form("%s %s %s %s %s", libraries.Data(), dependencySource.Data(), dependencyHeader.Data(), taskSources.Data(), taskHeaders.Data())); |
04a0c008 | 587 | |
04a0c008 | 588 | // Optionally set a name for the generated analysis macro (default MyAnalysis.C) |
589 | TString macroName; macroName.Form("run_%s.C",analysisName); macroName.ReplaceAll("-","_"); | |
590 | alienHandler->SetAnalysisMacro(macroName); | |
591 | ||
592 | //alienHandler->SetExecutable("comparison.sh"); | |
593 | alienHandler->SetExecutable(Form("run_%s.sh",analysisName)); | |
594 | ||
595 | alienHandler->SetSplitMaxInputFileNumber(100); | |
596 | ||
597 | // Optionally set number of failed jobs that will trigger killing waiting sub-jobs. | |
598 | alienHandler->SetMaxInitFailed(10); | |
599 | ||
600 | // Optionally resubmit threshold. | |
601 | alienHandler->SetMasterResubmitThreshold(90); // in % | |
602 | ||
39341c1f | 603 | alienHandler->SetTTL(86400);// in sec |
04a0c008 | 604 | |
605 | // Optionally set input format (default xml-single) | |
606 | alienHandler->SetInputFormat("xml-single"); | |
607 | ||
608 | // Optionally modify the name of the generated JDL (default analysis.jdl) | |
609 | alienHandler->SetJDLName(Form("run_%s.jdl",analysisName)); | |
610 | ||
611 | // Optionally modify job price (default 1) | |
612 | alienHandler->SetPrice(1); | |
613 | ||
614 | // Optionally modify split mode (default 'se') | |
615 | alienHandler->SetSplitMode("se"); | |
616 | ||
a354ea1a | 617 | // configure merging on grid, |
618 | // argument '--merge=collect' sets 'false' for fetching the merged output | |
619 | alienHandler->SetMergeViaJDL(bMergeOnGrid); | |
04a0c008 | 620 | |
9a3d923b | 621 | alienHandler->SetOneStageMerging(kFALSE); |
622 | alienHandler->SetMaxMergeStages(2); | |
04a0c008 | 623 | } |
624 | ||
625 | // Connect plugin to the analysis manager | |
626 | if (alienHandler) { | |
627 | pManager->SetGridHandler(alienHandler); | |
628 | } | |
629 | ||
630 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
631 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
632 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
633 | // | |
634 | // create task from the name, create output container, connect slots | |
635 | // | |
685fea75 | 636 | TObjArray* taskClassTokens=taskClasses.Tokenize(" "); |
637 | if (taskClassTokens) { | |
638 | for (int iTaskClassToken=0; iTaskClassToken<taskClassTokens->GetEntriesFast(); iTaskClassToken++) { | |
39341c1f | 639 | AliAnalysisTaskSE *pTask=NULL; |
640 | TString taskName=taskClassTokens->At(iTaskClassToken)->GetName(); | |
641 | taskName.ReplaceAll(".cxx", ""); | |
642 | TClass* pCl=TClass::GetClass(taskName); | |
643 | if (!pCl) { | |
644 | cerr << "can not load class " << taskName << endl; | |
645 | return; | |
646 | } | |
a354ea1a | 647 | void* p=pCl->New(); |
39341c1f | 648 | if (!p) { |
649 | cerr << "failed to instantiate class " << taskName << endl; | |
650 | return; | |
651 | } | |
652 | pTask=reinterpret_cast<AliAnalysisTaskSE*>(p); | |
653 | pManager->AddTask(pTask); | |
654 | AliAnalysisDataContainer *pContainer=pManager->CreateContainer(analysisName ,TObject::Class(), AliAnalysisManager::kOutputContainer, ofile); | |
655 | pManager->ConnectInput(pTask,0,pManager->GetCommonInputContainer()); | |
656 | pManager->ConnectOutput(pTask,1,pContainer); | |
685fea75 | 657 | } |
658 | delete taskClassTokens; | |
659 | } | |
660 | TObjArray* taskMacroTokens=addTaskMacros.Tokenize(" "); | |
661 | if (taskMacroTokens) { | |
662 | for (int iTaskMacroToken=0; iTaskMacroToken<taskMacroTokens->GetEntriesFast(); iTaskMacroToken++) { | |
a354ea1a | 663 | TString taskSource= taskMacroTokens->At(iTaskMacroToken)->GetName(); |
664 | ||
39341c1f | 665 | taskSource+="+g"; |
666 | TString configuration; | |
a354ea1a | 667 | if(!strArguments.Contains("file=")) configuration+=Form(" file=%s",ofile.Data()); |
668 | if(!strArguments.Contains("name=")) configuration+=Form(" name=%s",analysisName); | |
669 | configuration+=" "; configuration+=strArguments.Data(); | |
39341c1f | 670 | if (gDirectory) gDirectory->Add(new TNamed("run_single_task_configuration", configuration.Data())); |
671 | gROOT->Macro(taskMacroTokens->At(iTaskMacroToken)->GetName()); | |
685fea75 | 672 | } |
673 | delete taskMacroTokens; | |
04a0c008 | 674 | } |
675 | ||
7162a4fd | 676 | if (!bDefaultOutput) { |
677 | // fetch all output files from the output containers | |
678 | TString ofiles; | |
679 | TIter nextcontainer(pManager->GetContainers()); | |
680 | TObject* objContainer=NULL; | |
681 | while ((objContainer=nextcontainer())!=NULL) { | |
682 | AliAnalysisDataContainer* container=dynamic_cast<AliAnalysisDataContainer*>(objContainer); | |
683 | if (!container) continue; | |
684 | ofiles+=container->GetFileName(); | |
685 | ofiles+=" "; | |
686 | } | |
687 | ||
688 | alienHandler->SetOutputFiles(ofiles); | |
689 | // Optionally define the files to be archived. | |
690 | alienHandler->SetOutputArchive("log_archive.zip:stdout,stderr"); | |
691 | } | |
692 | ||
04a0c008 | 693 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
694 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
695 | /////////////////////////////////////////////////////////////////////////////////////////////////// | |
696 | // | |
697 | // run | |
698 | // | |
a354ea1a | 699 | |
04a0c008 | 700 | if (!pManager->InitAnalysis()) { |
701 | cerr << "failed to initialize analysis" << endl; | |
702 | return; | |
703 | } | |
704 | if (nevents<0) nevents=1000000000; | |
705 | pManager->PrintStatus(); | |
7162a4fd | 706 | if (!bRunAnalysis) return; |
04a0c008 | 707 | if (bRunLocal) { |
708 | pManager->StartAnalysis("local", chain, nevents); | |
709 | } else { | |
710 | pManager->StartAnalysis("grid", nevents); | |
711 | } | |
712 | } | |
713 | ||
c98603ea | 714 | // method for backward compatibility |
715 | void run_single_task(const char* mode, | |
716 | const char* input, | |
717 | const char* tasknames, | |
718 | const char* analysisName, | |
719 | Bool_t useMC, | |
720 | int nevents=-1, | |
721 | const char* gridDataDir=NULL, | |
722 | const char* dataPattern=NULL, | |
723 | const char* friendDataPattern=NULL, | |
724 | TString odir="", | |
725 | const char* user=NULL | |
726 | ) | |
727 | { | |
728 | run_single_task(mode, | |
729 | input, | |
a354ea1a | 730 | tasknames, |
c98603ea | 731 | analysisName, |
a354ea1a | 732 | (useMC?"mc":""), |
c98603ea | 733 | nevents, |
734 | gridDataDir, | |
735 | dataPattern, | |
736 | friendDataPattern, | |
737 | odir, | |
738 | user | |
739 | ); | |
740 | } | |
741 | ||
a354ea1a | 742 | // method for calling with a fixed working directory, e.g. in mode terminate |
743 | void run_single_task(const char* mode, | |
744 | const char* input, | |
745 | const char* tasknames, | |
746 | const char* analysisName, | |
747 | const char* arguments, | |
748 | const char* workdir | |
749 | ) | |
750 | { | |
751 | TString odir(workdir); | |
752 | run_single_task(mode, | |
753 | input, | |
754 | tasknames, | |
755 | analysisName, | |
756 | arguments, | |
757 | -1, | |
758 | NULL, | |
759 | NULL, | |
760 | NULL, | |
761 | odir, | |
762 | NULL | |
763 | ); | |
764 | } | |
765 | ||
04a0c008 | 766 | TString GetIncludeHeaders(const char* filename, TString& headers, TString& libs, bool loadClass) |
767 | { | |
768 | // scan the file and add all include headers found by path | |
769 | // to the parameter headers | |
770 | ifstream input(filename); | |
04a0c008 | 771 | if (input.bad()) { |
772 | cerr << "failed to open file " << filename << endl; | |
773 | return headers; | |
774 | } | |
775 | TString line; | |
776 | while (!line.ReadLine(input).eof()) { | |
777 | if (!line.Contains("#include") || !line.Contains(".h")) continue; | |
778 | line=line(0, line.Index(".h"));line+=".h"; | |
779 | line.Replace(0, line.Index("#include"), ""); | |
780 | line.ReplaceAll("#include", ""); | |
781 | line.ReplaceAll(" ", ""); | |
782 | line.ReplaceAll("\"", ""); | |
783 | if (!line.BeginsWith("Ali") && !line.BeginsWith("T")) continue; | |
784 | if (gSystem->AccessPathName(line)!=0) { | |
785 | // not an include file in the current directory, check if class | |
786 | // is available or find library | |
787 | line.ReplaceAll(".h",""); | |
788 | //cout << "checking class " << line << endl; | |
789 | if (TClass::GetClass(line)==NULL) { | |
790 | TString command; | |
791 | TString resfilename(gSystem->TempDirectory()); resfilename+="/findlib.txt"; | |
792 | command.Form("for lib in $ALICE_ROOT/lib/*/lib*.so; do (nm $lib | grep %s | grep ' T ' | grep Class_Name > /dev/null) && echo $lib > %s; done", line.Data(), resfilename.Data()); | |
793 | gSystem->Exec(command); | |
794 | ifstream resfile(resfilename.Data()); | |
795 | if (resfile.good()) { | |
796 | TString result; | |
797 | if (!result.ReadLine(resfile).eof()) { | |
798 | Ssiz_t haveSlash=-1; | |
799 | while ((haveSlash=result.First('/'))>=0) result.Replace(0, haveSlash+1, ""); | |
800 | if (!libs.Contains(result)) { | |
801 | cout << "loading dependency library '" << result << "' for class '" << line << "'" << endl; | |
802 | gSystem->Load(result); | |
803 | if (!libs.IsNull()) libs+=" "; | |
804 | libs+=result; | |
805 | } | |
806 | } | |
807 | command="rm "; command+=resfilename; | |
808 | gSystem->Exec(command); | |
809 | } | |
810 | } | |
811 | } else { | |
812 | if (headers.Contains(line)) { | |
813 | if (!headers.BeginsWith(line)) { | |
814 | headers.ReplaceAll(line, ""); | |
815 | if (!headers.IsNull()) headers.Insert(0, " "); | |
9a3d923b | 816 | if (macroVerbosity>0) cout << "moving " << line << endl; |
04a0c008 | 817 | headers.Insert(0, line); |
818 | } | |
819 | continue; | |
820 | } | |
821 | if (!headers.IsNull()) headers.Insert(0, " "); | |
9a3d923b | 822 | if (macroVerbosity>0) cout << "inserting " << line << endl; |
04a0c008 | 823 | headers.Insert(0, line); |
824 | TString source=line; source.ReplaceAll(".h", ".cxx"); | |
825 | if (gSystem->AccessPathName(source)==0) { | |
826 | GetIncludeHeaders(source, headers, libs); | |
827 | } | |
828 | GetIncludeHeaders(line, headers, libs); | |
829 | if (loadClass && gSystem->AccessPathName(source)==0) { | |
830 | line.ReplaceAll(".h", ""); | |
831 | if (TClass::GetClass(line)==NULL) { | |
832 | source+="+g"; | |
833 | gROOT->LoadMacro(source); | |
834 | } | |
835 | } | |
836 | } | |
837 | } | |
9a3d923b | 838 | |
04a0c008 | 839 | return headers; |
840 | } | |
841 | ||
842 | void ErrorConfigurationFile(const char* fileName) { | |
843 | cout << endl; | |
844 | cout << "/// -------------------------------------------------------------------" << endl; | |
845 | cout << "/// Warning: can not find configuration file '" << fileName << "'" << endl; | |
846 | cout << "/// please create a configuration file in either local or HOME directory, or in" << endl; | |
847 | cout << "/// specified location. Below is an example, fill in your preferred defaults." << endl; | |
848 | cout << "/// -------------------------------------------------------------------" << endl; | |
849 | cout << endl; | |
850 | cout << "const char* alienAPIVersion=\"V1.1x\";" << endl; | |
851 | cout << "const char* alienROOTVersion=\"v5-33-02a\";" << endl; | |
852 | cout << "const char* alienAliROOTVersion=\"v5-01-Rev-29\";" << endl; | |
853 | cout << "const char* defaultGridDataDir=\"/alice/data/2011/LHC11f\";" << endl; | |
854 | cout << "const char* defaultDataPattern=\"*ESDs.root\";" << endl; | |
9a3d923b | 855 | cout << "const char* defaultFriendDataPattern=\"\";" << endl; |
04a0c008 | 856 | cout << "{} // note this empty body"; |
857 | cout << endl; | |
858 | } | |
f6f9bc4b | 859 | |
860 | class AliCodeNode : public TNamed | |
861 | { | |
862 | public: | |
863 | AliCodeNode(); | |
864 | AliCodeNode(const char* filename); | |
865 | ~AliCodeNode(); | |
866 | ||
867 | enum { | |
868 | kTypeInvalid = 0, | |
869 | kTypeSource = 1, | |
870 | kTypeHeader, | |
871 | kTypeMacro, | |
872 | kNofTypes | |
873 | }; | |
874 | ||
875 | const TList& GetParents() const {return fParents;} | |
876 | const TList& GetChilds() const {return fChilds;} | |
877 | int AddParent(AliCodeNode* pParent); | |
878 | int InsertChild(AliCodeNode* pChild); | |
879 | bool HasChilds() const {return (GetChilds().GetEntries()-fProcessedChilds.GetEntries())>0;} | |
880 | int MarkProcessed(); | |
881 | int MarkChildProcessed(AliCodeNode* pChild); | |
882 | bool HasSourceParent(); | |
883 | //int DisconnectParents(); | |
884 | ||
885 | bool IsHeader() const {return fType==kTypeHeader;} | |
886 | bool IsSource() const {return fType==kTypeSource;} | |
a354ea1a | 887 | void HaveFile(bool haveFile) {fHaveFile=haveFile;} |
888 | bool HaveFile() const {return fHaveFile;} | |
f6f9bc4b | 889 | void Print(Option_t *option="") const; |
890 | ||
891 | protected: | |
892 | //int DisconnectChild(const AliCodeNode& child); | |
893 | ||
894 | private: | |
895 | TList fParents; // list of parents | |
896 | TList fChilds; // list of childs | |
897 | TList fProcessedChilds; // list of processed childs | |
898 | int fType; // source of header | |
a354ea1a | 899 | bool fHaveFile;// file is existing in pwd |
f6f9bc4b | 900 | |
901 | ClassDef(AliCodeNode, 1) | |
902 | }; | |
903 | ||
904 | class AliCodeTree : public TObject | |
905 | { | |
906 | public: | |
907 | AliCodeTree(short verbosity=0) : fNodes(), fIndentCount(0), fVerbosity(verbosity) {fNodes.SetOwner(kTRUE);} | |
908 | ~AliCodeTree() {} | |
909 | ||
910 | AliCodeNode* Build(const char* topfile, AliCodeNode* parent=NULL); | |
911 | AliCodeNode* FindNode(const char* name); | |
912 | int Sort(); | |
913 | int LoadClasses(TString& libs); | |
914 | int LoadClasses() {TString dummy; return LoadClasses(dummy);} | |
915 | int GetHeaders(TString& headers); | |
916 | int GetSources(TString& sources); | |
917 | ||
918 | void Print(Option_t *option="") const; | |
919 | ||
920 | private: | |
921 | TObjArray fNodes; // list of nodes | |
922 | short fIndentCount; | |
923 | short fVerbosity; | |
924 | ||
925 | ClassDef(AliCodeTree, 1) | |
926 | }; | |
927 | ||
928 | ClassImp(AliCodeNode) | |
929 | ||
930 | AliCodeNode::AliCodeNode() | |
931 | : TNamed() | |
932 | , fParents() | |
933 | , fChilds() | |
934 | , fProcessedChilds() | |
935 | , fType(AliCodeNode::kTypeInvalid) | |
a354ea1a | 936 | , fHaveFile(false) |
f6f9bc4b | 937 | { |
938 | } | |
939 | ||
940 | AliCodeNode::AliCodeNode(const char* filename) | |
941 | : TNamed(filename, filename) | |
942 | , fParents() | |
943 | , fChilds() | |
944 | , fProcessedChilds() | |
945 | , fType(AliCodeNode::kTypeInvalid) | |
a354ea1a | 946 | , fHaveFile(false) |
f6f9bc4b | 947 | { |
948 | TString s(filename); | |
949 | if (s.EndsWith(".cxx")) fType=kTypeSource; | |
950 | else if (s.EndsWith(".h")) fType=kTypeHeader; | |
951 | else if (s.EndsWith(".C")) fType=kTypeMacro; | |
952 | } | |
953 | ||
954 | AliCodeNode::~AliCodeNode() | |
955 | { | |
956 | } | |
957 | ||
958 | int AliCodeNode::AddParent(AliCodeNode* pParent) | |
959 | { | |
960 | if (!pParent) return -1; | |
961 | if (fParents.FindObject(pParent)) return 0; | |
962 | if (GetChilds().FindObject(pParent)) { | |
963 | cerr << "error: circular dependency: can not add " << pParent->GetName() << " as parent to " << this->GetName() << endl; | |
964 | return -2; | |
965 | } | |
966 | fParents.Add(pParent); | |
967 | return 0; | |
968 | } | |
969 | ||
970 | int AliCodeNode::InsertChild(AliCodeNode* pChild) | |
971 | { | |
972 | if (!pChild) return -1; | |
973 | if (fChilds.FindObject(pChild)) return 0; | |
974 | if (pChild->GetChilds().FindObject(this)) { | |
975 | cerr << "error: circular dependency: can not add " << pChild->GetName() << " as child to " << this->GetName() << endl; | |
976 | return -2; | |
977 | } | |
978 | fChilds.Add(pChild); | |
979 | return 0; | |
980 | } | |
981 | ||
982 | int AliCodeNode::MarkProcessed() | |
983 | { | |
984 | TIter parents(&fParents); | |
985 | TObject* obj=NULL; | |
986 | while ((obj=parents())) { | |
987 | AliCodeNode* parent=dynamic_cast<AliCodeNode*>(obj); | |
988 | parent->MarkChildProcessed(this); | |
989 | } | |
990 | ||
991 | return 0; | |
992 | } | |
993 | ||
994 | bool AliCodeNode::HasSourceParent() | |
995 | { | |
996 | if (fType!=kTypeHeader) return false; | |
997 | TString name(GetName()); | |
998 | name.ReplaceAll(".h", ".cxx"); | |
999 | TIter parents(&fParents); | |
1000 | TObject* obj=NULL; | |
1001 | while ((obj=parents())) { | |
1002 | if (name.CompareTo(obj->GetName())==0) | |
1003 | return true; | |
1004 | } | |
1005 | return false; | |
1006 | } | |
1007 | ||
1008 | int AliCodeNode::MarkChildProcessed(AliCodeNode* pChild) | |
1009 | { | |
1010 | if (!pChild) return -1; | |
1011 | if (fChilds.FindObject(pChild)==NULL) { | |
1012 | cerr << "node " << GetName() << ": failed to find child node " << pChild->GetName() << endl; | |
1013 | return -1; | |
1014 | } | |
1015 | if (fProcessedChilds.FindObject(pChild)!=NULL) { | |
1016 | cerr << "node " << GetName() << ": child node " << pChild->GetName() << " already processed" << endl; | |
1017 | return 0; | |
1018 | } | |
1019 | fProcessedChilds.Add(pChild); | |
1020 | return 0; | |
1021 | } | |
1022 | ||
1023 | void AliCodeNode::Print(Option_t */*option*/) const | |
1024 | { | |
1025 | cout << "-- " << GetName() << endl; | |
1026 | TObject* obj=NULL; | |
1027 | cout << " - parents" << endl; | |
1028 | TIter parents(&fParents); | |
1029 | while ((obj=parents())) { | |
1030 | cout << " |- " << obj->GetName() << endl; | |
1031 | } | |
1032 | cout << " - childs" << endl; | |
1033 | TIter childs(&fChilds); | |
1034 | while ((obj=childs())) { | |
1035 | cout << " |- " << obj->GetName() << endl; | |
1036 | } | |
1037 | } | |
1038 | ||
1039 | ClassImp(AliCodeTree) | |
1040 | ||
1041 | AliCodeNode* AliCodeTree::Build(const char* topfile, AliCodeNode* parent) | |
1042 | { | |
1043 | // scan the file and recursively add all include headers found by path | |
1044 | int iResult=0; | |
f6f9bc4b | 1045 | AliCodeNode* node=FindNode(topfile); |
1046 | if (!node) { | |
1047 | if (fVerbosity>0) cout << setw(2*fIndentCount) << " " << "new node " << topfile << endl; | |
1048 | fIndentCount++; | |
1049 | node=new AliCodeNode(topfile); | |
1050 | fNodes.Add(node); | |
a354ea1a | 1051 | ifstream input(topfile); |
1052 | if (input.good()) { | |
1053 | node->HaveFile(true); | |
1054 | TString line; | |
1055 | while (!line.ReadLine(input).eof()) { | |
1056 | if (!line.Contains("#include") || !line.Contains(".h")) continue; | |
1057 | line=line(0, line.Index(".h"));line+=".h"; | |
1058 | line.Replace(0, line.Index("#include"), ""); | |
1059 | line.ReplaceAll("#include", ""); | |
1060 | line.ReplaceAll(" ", ""); | |
1061 | line.ReplaceAll("\"", ""); | |
1062 | if (!line.BeginsWith("Ali") && !line.BeginsWith("T")) continue; | |
1063 | AliCodeNode* child=NULL; | |
f6f9bc4b | 1064 | TString source=line; source.ReplaceAll(".h", ".cxx"); |
1065 | if (source.CompareTo(topfile)!=0 && gSystem->AccessPathName(source)==0) { | |
a354ea1a | 1066 | child=Build(source, node); |
f6f9bc4b | 1067 | node->InsertChild(child); |
1068 | } | |
a354ea1a | 1069 | child=Build(line, node); |
1070 | node->InsertChild(child); | |
f6f9bc4b | 1071 | } |
1072 | } | |
1073 | fIndentCount--; | |
1074 | } | |
1075 | if (parent) { | |
1076 | if ((iResult=node->AddParent(parent))<0) | |
1077 | return NULL; | |
1078 | } | |
1079 | if (fVerbosity>0) cout << setw(2*fIndentCount) << " " << "finished " << topfile << endl; | |
1080 | return node; | |
1081 | } | |
1082 | ||
1083 | int AliCodeTree::Sort() | |
1084 | { | |
1085 | TObjArray sortedNodes; | |
1086 | int nNodes=fNodes.GetEntriesFast(); | |
1087 | int nCount=0; | |
1088 | while (sortedNodes.GetEntriesFast()<nNodes && nCount<nNodes) { | |
1089 | for (int i=0; i<nNodes; i++) { | |
1090 | if (fNodes[i]==NULL) continue; | |
1091 | AliCodeNode* node=dynamic_cast<AliCodeNode*>(fNodes[i]); | |
1092 | if (node->HasChilds()) { | |
1093 | continue; | |
1094 | } | |
1095 | fNodes[i]=NULL; | |
1096 | sortedNodes.Add(node); | |
1097 | node->MarkProcessed(); | |
1098 | } | |
1099 | nCount++; | |
1100 | } | |
1101 | ||
1102 | for (int i=0; i<nNodes; i++) { | |
1103 | fNodes[i]=sortedNodes[i]; | |
1104 | } | |
1105 | ||
1106 | return 0; | |
1107 | } | |
1108 | ||
1109 | int AliCodeTree::LoadClasses(TString& libs) | |
1110 | { | |
1111 | TIter next(&fNodes); | |
1112 | TObject* obj=NULL; | |
1113 | while ((obj=next())!=NULL) { | |
1114 | AliCodeNode* node=dynamic_cast<AliCodeNode*>(obj); | |
1115 | TString name(node->GetName()); | |
1116 | if (node->IsHeader()) { | |
1117 | if (node->HasSourceParent()) { | |
1118 | // nothing to do, class going to be compiled from source | |
1119 | continue; | |
1120 | } | |
1121 | name.ReplaceAll(".h", ""); | |
1122 | if (TClass::GetClass(name)!=NULL) { | |
1123 | // class available in the system | |
1124 | continue; | |
1125 | } | |
1126 | ||
1127 | TString command; | |
1128 | TString resfilename(gSystem->TempDirectory()); resfilename+="/findlib.txt"; | |
1129 | command.Form("for lib in $ALICE_ROOT/lib/*/lib*.so; do (nm $lib | grep %s | grep ' T ' | grep Class_Name > /dev/null) && echo $lib > %s; done", name.Data(), resfilename.Data()); | |
1130 | gSystem->Exec(command); | |
1131 | ifstream resfile(resfilename.Data()); | |
1132 | if (resfile.good()) { | |
1133 | TString result; | |
1134 | if (!result.ReadLine(resfile).eof()) { | |
1135 | Ssiz_t haveSlash=-1; | |
1136 | while ((haveSlash=result.First('/'))>=0) result.Replace(0, haveSlash+1, ""); | |
1137 | if (!libs.Contains(result)) { | |
1138 | cout << "loading dependency library '" << result << "' for class '" << name << "'" << endl; | |
1139 | gSystem->Load(result); | |
1140 | if (!libs.IsNull()) libs+=" "; | |
1141 | libs+=result; | |
1142 | } | |
1143 | } | |
1144 | command="rm "; command+=resfilename; | |
1145 | gSystem->Exec(command); | |
1146 | } | |
1147 | continue; | |
1148 | } | |
1149 | if (node->IsSource()) { | |
1150 | TString classname(name); | |
1151 | classname.ReplaceAll(".cxx", ""); | |
1152 | if (TClass::GetClass(classname)!=NULL) { | |
1153 | // class available in the system | |
1154 | continue; | |
1155 | } | |
1156 | name+="+g"; | |
1157 | gROOT->LoadMacro(name); | |
1158 | } | |
1159 | } | |
1160 | return 0; | |
1161 | } | |
1162 | ||
1163 | int AliCodeTree::GetHeaders(TString& headers) | |
1164 | { | |
1165 | TIter next(&fNodes); | |
1166 | TObject* obj=NULL; | |
1167 | while ((obj=next())!=NULL) { | |
1168 | AliCodeNode* node=dynamic_cast<AliCodeNode*>(obj); | |
a354ea1a | 1169 | if (!node->IsHeader() || !node->HaveFile()) continue; |
f6f9bc4b | 1170 | if (!headers.IsNull()) headers+=" "; |
1171 | headers+=node->GetName(); | |
1172 | } | |
1173 | return 0; | |
1174 | } | |
1175 | ||
1176 | int AliCodeTree::GetSources(TString& sources) | |
1177 | { | |
1178 | TIter next(&fNodes); | |
1179 | TObject* obj=NULL; | |
1180 | while ((obj=next())!=NULL) { | |
1181 | AliCodeNode* node=dynamic_cast<AliCodeNode*>(obj); | |
a354ea1a | 1182 | if (!node->IsSource() || !node->HaveFile()) continue; |
f6f9bc4b | 1183 | if (!sources.IsNull()) sources+=" "; |
1184 | sources+=node->GetName(); | |
1185 | } | |
1186 | return 0; | |
1187 | } | |
1188 | ||
1189 | AliCodeNode* AliCodeTree::FindNode(const char* name) | |
1190 | { | |
1191 | TObject* node=fNodes.FindObject(name); | |
1192 | if (!node) return NULL; | |
1193 | return dynamic_cast<AliCodeNode*>(node); | |
1194 | } | |
1195 | ||
1196 | void AliCodeTree::Print(Option_t *option) const | |
1197 | { | |
1198 | const char* key=NULL; | |
1199 | int indent=0; | |
1200 | TString childOptions; | |
1201 | const TString delimiter(" "); | |
1202 | TStringToken options(option, delimiter); | |
1203 | while (options.NextToken()) { | |
1204 | key="indent="; | |
1205 | if (options.BeginsWith(key)) { | |
1206 | TString arg(options); | |
1207 | arg.ReplaceAll(key, ""); | |
1208 | indent=arg.Atoi(); | |
1209 | continue; | |
1210 | } | |
1211 | childOptions+=" "; | |
1212 | childOptions+=options; | |
1213 | } | |
1214 | childOptions+=Form("indent=%d", indent+1); | |
1215 | TIter next(&fNodes); | |
1216 | TObject* obj=NULL; | |
1217 | while ((obj=next())!=NULL) { | |
1218 | obj->Print(childOptions); | |
1219 | } | |
1220 | } | |
1221 | ||
1222 | TObject* BuildCodeTree(const char* filename, TObject* useObject) | |
1223 | { | |
1224 | AliCodeTree* pTree=NULL; | |
1225 | if (useObject) pTree=dynamic_cast<AliCodeTree*>(useObject); | |
1226 | if (!pTree) pTree=new AliCodeTree; | |
1227 | if (!pTree) return NULL; | |
1228 | ||
1229 | pTree->Build(filename); | |
1230 | return pTree; | |
1231 | } | |
1232 | ||
1233 | int ProcessCodeTree(TObject* tree, TString& sources, TString& headers, TString& libs) | |
1234 | { | |
1235 | if (!tree) return -1; | |
1236 | AliCodeTree* pTree=dynamic_cast<AliCodeTree*>(tree); | |
1237 | pTree->Sort(); | |
1238 | pTree->LoadClasses(libs); | |
1239 | pTree->GetHeaders(headers); | |
1240 | pTree->GetSources(sources); | |
1241 | return 0; | |
1242 | } | |
1243 | ||
1244 | #else | |
1245 | #include "TObject.h" | |
1246 | #include "TNamed.h" | |
1247 | #include "TList.h" | |
1248 | #include "TObjArray.h" | |
1249 | #include "TString.h" | |
1250 | #include "TPRegexp.h" | |
1251 | #include "TSystem.h" | |
1252 | #include "TROOT.h" | |
a354ea1a | 1253 | #include "TGrid.h" |
1254 | #include "TChain.h" | |
1255 | #include "TChainElement.h" | |
1256 | // #include "AliAnalysisManager.h" | |
1257 | // #include "AliAnalysisAlien.h" | |
1258 | // #include "AliAnalysisTaskSE.h" | |
1259 | // #include "AliInputEventHandler.h" | |
1260 | // #include "AliAODInputHandler.h" | |
1261 | // #include "AliESDInputHandler.h" | |
f6f9bc4b | 1262 | #include <iostream> |
1263 | #include <fstream> | |
1264 | #include <iomanip> | |
1265 | using namespace std; | |
1266 | ||
1267 | #endif |