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