]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisManager.cxx
Manager ignores now all Notify calls coming from the selector level before the first...
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisManager.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17 // Author: Andrei Gheata, 31/05/2006
18
19 //==============================================================================
20 //   AliAnalysisManager - Manager analysis class. Allows creation of several
21 // analysis tasks and data containers storing their input/output. Allows
22 // connecting/chaining tasks via shared data containers. Serializes the current
23 // event for all tasks depending only on initial input data.
24 //==============================================================================
25 //
26 //==============================================================================
27
28 #include "AliAnalysisManager.h"
29
30 #include <cerrno>
31 #include <Riostream.h>
32 #include <TError.h>
33 #include <TClass.h>
34 #include <TFile.h>
35 #include <TMath.h>
36 #include <TH1.h>
37 #include <TMethodCall.h>
38 #include <TChain.h>
39 #include <TSystem.h>
40 #include <TROOT.h>
41 #include <TCanvas.h>
42 #include <TStopwatch.h>
43
44 #include "AliLog.h"
45 #include "AliAnalysisSelector.h"
46 #include "AliAnalysisGrid.h"
47 #include "AliAnalysisTask.h"
48 #include "AliAnalysisDataContainer.h"
49 #include "AliAnalysisDataSlot.h"
50 #include "AliVEventHandler.h"
51 #include "AliVEventPool.h"
52 #include "AliSysInfo.h"
53 #include "AliAnalysisStatistics.h"
54
55 ClassImp(AliAnalysisManager)
56
57 AliAnalysisManager *AliAnalysisManager::fgAnalysisManager = NULL;
58 TString AliAnalysisManager::fgCommonFileName = "";
59 Int_t AliAnalysisManager::fPBUpdateFreq = 1;
60
61 //______________________________________________________________________________
62 AliAnalysisManager::AliAnalysisManager(const char *name, const char *title)
63                    :TNamed(name,title),
64                     fTree(NULL),
65                     fInputEventHandler(NULL),
66                     fOutputEventHandler(NULL),
67                     fMCtruthEventHandler(NULL),
68                     fEventPool(NULL),
69                     fCurrentEntry(-1),
70                     fNSysInfo(0),
71                     fMode(kLocalAnalysis),
72                     fInitOK(kFALSE),
73                     fIsRemote(kFALSE),
74                     fDebug(0),
75                     fSpecialOutputLocation(""), 
76                     fTasks(NULL),
77                     fTopTasks(NULL),
78                     fZombies(NULL),
79                     fContainers(NULL),
80                     fInputs(NULL),
81                     fOutputs(NULL),
82                     fParamCont(NULL),
83                     fCommonInput(NULL),
84                     fCommonOutput(NULL),
85                     fSelector(NULL),
86                     fGridHandler(NULL),
87                     fExtraFiles(""),
88                     fAutoBranchHandling(kTRUE), 
89                     fTable(),
90                     fRunFromPath(0),
91                     fNcalls(0),
92                     fMaxEntries(0),
93                     fStatisticsMsg(),
94                     fRequestedBranches(),
95                     fStatistics(0)
96 {
97 // Default constructor.
98    fgAnalysisManager = this;
99    fgCommonFileName  = "AnalysisResults.root";
100    fTasks      = new TObjArray();
101    fTopTasks   = new TObjArray();
102    fZombies    = new TObjArray();
103    fContainers = new TObjArray();
104    fInputs     = new TObjArray();
105    fOutputs    = new TObjArray();
106    fParamCont  = new TObjArray();
107    SetEventLoop(kTRUE);
108    TObject::SetObjectStat(kFALSE);
109 }
110
111 //______________________________________________________________________________
112 AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other)
113                    :TNamed(other),
114                     fTree(NULL),
115                     fInputEventHandler(NULL),
116                     fOutputEventHandler(NULL),
117                     fMCtruthEventHandler(NULL),
118                     fEventPool(NULL),
119                     fCurrentEntry(-1),
120                     fNSysInfo(0),
121                     fMode(other.fMode),
122                     fInitOK(other.fInitOK),
123                     fIsRemote(other.fIsRemote),
124                     fDebug(other.fDebug),
125                     fSpecialOutputLocation(""), 
126                     fTasks(NULL),
127                     fTopTasks(NULL),
128                     fZombies(NULL),
129                     fContainers(NULL),
130                     fInputs(NULL),
131                     fOutputs(NULL),
132                     fParamCont(NULL),
133                     fCommonInput(NULL),
134                     fCommonOutput(NULL),
135                     fSelector(NULL),
136                     fGridHandler(NULL),
137                     fExtraFiles(),
138                     fAutoBranchHandling(other.fAutoBranchHandling), 
139                     fTable(),
140                     fRunFromPath(0),
141                     fNcalls(other.fNcalls),
142                     fMaxEntries(other.fMaxEntries),
143                     fStatisticsMsg(other.fStatisticsMsg),
144                     fRequestedBranches(other.fRequestedBranches),
145                     fStatistics(other.fStatistics)
146 {
147 // Copy constructor.
148    fTasks      = new TObjArray(*other.fTasks);
149    fTopTasks   = new TObjArray(*other.fTopTasks);
150    fZombies    = new TObjArray(*other.fZombies);
151    fContainers = new TObjArray(*other.fContainers);
152    fInputs     = new TObjArray(*other.fInputs);
153    fOutputs    = new TObjArray(*other.fOutputs);
154    fParamCont  = new TObjArray(*other.fParamCont);
155    fgCommonFileName  = "AnalysisResults.root";
156    fgAnalysisManager = this;
157    TObject::SetObjectStat(kFALSE);
158 }
159    
160 //______________________________________________________________________________
161 AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other)
162 {
163 // Assignment
164    if (&other != this) {
165       TNamed::operator=(other);
166       fInputEventHandler   = other.fInputEventHandler;
167       fOutputEventHandler  = other.fOutputEventHandler;
168       fMCtruthEventHandler = other.fMCtruthEventHandler;
169       fEventPool           = other.fEventPool;
170       fTree       = NULL;
171       fCurrentEntry = -1;
172       fNSysInfo   = other.fNSysInfo;
173       fMode       = other.fMode;
174       fInitOK     = other.fInitOK;
175       fIsRemote   = other.fIsRemote;
176       fDebug      = other.fDebug;
177       fTasks      = new TObjArray(*other.fTasks);
178       fTopTasks   = new TObjArray(*other.fTopTasks);
179       fZombies    = new TObjArray(*other.fZombies);
180       fContainers = new TObjArray(*other.fContainers);
181       fInputs     = new TObjArray(*other.fInputs);
182       fOutputs    = new TObjArray(*other.fOutputs);
183       fParamCont  = new TObjArray(*other.fParamCont);
184       fCommonInput = NULL;
185       fCommonOutput = NULL;
186       fSelector   = NULL;
187       fGridHandler = NULL;
188       fExtraFiles = other.fExtraFiles;
189       fgCommonFileName = "AnalysisResults.root";
190       fgAnalysisManager = this;
191       fAutoBranchHandling = other.fAutoBranchHandling;
192       fTable.Clear("nodelete");
193       fRunFromPath = other.fRunFromPath;
194       fNcalls     = other. fNcalls;
195       fMaxEntries = other.fMaxEntries;
196       fStatisticsMsg = other.fStatisticsMsg;
197       fRequestedBranches = other.fRequestedBranches;
198       fStatistics = other.fStatistics;
199    }
200    return *this;
201 }
202
203 //______________________________________________________________________________
204 AliAnalysisManager::~AliAnalysisManager()
205 {
206 // Destructor.
207    if (fTasks) {fTasks->Delete(); delete fTasks;}
208    if (fTopTasks) delete fTopTasks;
209    if (fZombies) delete fZombies;
210    if (fContainers) {fContainers->Delete(); delete fContainers;}
211    if (fInputs) delete fInputs;
212    if (fOutputs) delete fOutputs;
213    if (fParamCont) delete fParamCont;
214    if (fGridHandler) delete fGridHandler;
215    if (fInputEventHandler) delete fInputEventHandler;
216    if (fOutputEventHandler) delete fOutputEventHandler;
217    if (fMCtruthEventHandler) delete fMCtruthEventHandler;
218    if (fEventPool) delete fEventPool;
219    if (fgAnalysisManager==this) fgAnalysisManager = NULL;
220    TObject::SetObjectStat(kTRUE);
221 }
222
223 //______________________________________________________________________________
224 Int_t AliAnalysisManager::GetEntry(Long64_t entry, Int_t getall)
225 {
226 // Read one entry of the tree or a whole branch.
227    fCurrentEntry = entry;
228    if (!fAutoBranchHandling)
229      return 123456789;
230    return fTree ? fTree->GetTree()->GetEntry(entry, getall) : -1;
231 }
232
233 //______________________________________________________________________________
234 Int_t AliAnalysisManager::GetRunFromAlienPath(const char *path)
235 {
236 // Attempt to extract run number from input data path. Works only for paths to
237 // alice data in alien.
238 //    sim:  /alice/sim/<production>/run_no/...
239 //    data: /alice/data/year/period/000run_no/... (ESD or AOD)
240    TString s(path);
241    TString srun;
242    Int_t run = 0;
243    Int_t index = s.Index("/alice/sim");
244    if (index >= 0) {
245       for (Int_t i=0; i<3; i++) {
246          index = s.Index("/", index+1);
247          if (index<0) return 0;
248       }
249       srun = s(index+1,6);
250       run = atoi(srun);
251    }
252    index = s.Index("/alice/data");
253    if (index >= 0) {
254       for (Int_t i=0; i<4; i++) {
255          index = s.Index("/", index+1);
256          if (index<0) return 0;
257       }
258       srun = s(index+1,9);
259       run = atoi(srun);
260    }
261    return run;
262 }   
263
264 //______________________________________________________________________________
265 Bool_t AliAnalysisManager::Init(TTree *tree)
266 {
267   // The Init() function is called when the selector needs to initialize
268   // a new tree or chain. Typically here the branch addresses of the tree
269   // will be set. It is normaly not necessary to make changes to the
270   // generated code, but the routine can be extended by the user if needed.
271   // Init() will be called many times when running with PROOF.
272    Bool_t init = kFALSE;
273    if (!tree) return kFALSE; // Should not happen - protected in selector caller
274    if (fDebug > 1) {
275       printf("->AliAnalysisManager::Init(%s)\n", tree->GetName());
276    }
277    // Call InitTree of EventHandler
278    if (fOutputEventHandler) {
279       if (fMode == kProofAnalysis) {
280          init = fOutputEventHandler->Init(0x0, "proof");
281       } else {
282          init = fOutputEventHandler->Init(0x0, "local");
283       }
284       if (!init) {
285          Error("Init", "Output event handler failed to initialize");
286          return kFALSE;
287       }         
288    }
289    
290    if (fInputEventHandler) {
291       if (fMode == kProofAnalysis) {
292          init = fInputEventHandler->Init(tree, "proof");
293       } else {
294          init = fInputEventHandler->Init(tree, "local");
295       }
296       if (!init) {
297          Error("Init", "Input event handler failed to initialize tree"); 
298          return kFALSE;
299       }         
300    } else {
301       // If no input event handler we need to get the tree once
302       // for the chain
303       if(!tree->GetTree()) {
304          Long64_t readEntry = tree->LoadTree(0);
305          if (readEntry == -2) {
306             Error("Init", "Input tree has no entry. Exiting");
307             return kFALSE;
308          }
309       }   
310    }
311
312    if (fMCtruthEventHandler) {
313       if (fMode == kProofAnalysis) {
314          init = fMCtruthEventHandler->Init(0x0, "proof");
315       } else {
316          init = fMCtruthEventHandler->Init(0x0, "local");
317       }
318       if (!init) {
319          Error("Init", "MC event handler failed to initialize"); 
320          return kFALSE;
321       }         
322    }
323
324    if (!fInitOK) InitAnalysis();
325    if (!fInitOK) return kFALSE;
326    fTree = tree;
327    fTable.Rehash(100);
328    AliAnalysisDataContainer *top = fCommonInput;
329    if (!top) top = (AliAnalysisDataContainer*)fInputs->At(0);
330    if (!top) {
331       Error("Init","No top input container !");
332       return kFALSE;
333    }
334    top->SetData(tree);
335    CheckBranches(kFALSE);
336    if (fDebug > 1) {
337       printf("<-AliAnalysisManager::Init(%s)\n", tree->GetName());
338    }
339    return kTRUE;
340 }
341
342 //______________________________________________________________________________
343 void AliAnalysisManager::SlaveBegin(TTree *tree)
344 {
345   // The SlaveBegin() function is called after the Begin() function.
346   // When running with PROOF SlaveBegin() is called on each slave server.
347   // The tree argument is deprecated (on PROOF 0 is passed).
348    if (fDebug > 1) printf("->AliAnalysisManager::SlaveBegin()\n");
349    if (!CheckTasks()) Fatal("SlaveBegin", "Not all needed libraries were loaded");
350    static Bool_t isCalled = kFALSE;
351    Bool_t init = kFALSE;
352    Bool_t initOK = kTRUE;
353    TString msg;
354    TDirectory *curdir = gDirectory;
355    // Call SlaveBegin only once in case of mixing
356    if (isCalled && fMode==kMixingAnalysis) return;
357    gROOT->cd();
358    // Call Init of EventHandler
359    if (fOutputEventHandler) {
360       if (fMode == kProofAnalysis) {
361          // Merging AOD's in PROOF via TProofOutputFile
362          if (fDebug > 1) printf("   Initializing AOD output file %s...\n", fOutputEventHandler->GetOutputFileName());
363          init = fOutputEventHandler->Init("proof");
364          if (!init) msg = "Failed to initialize output handler on worker";
365       } else {
366          init = fOutputEventHandler->Init("local");
367          if (!init) msg = "Failed to initialize output handler";
368       }
369       initOK &= init;
370       if (!fSelector) Error("SlaveBegin", "Selector not set");
371       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
372    }
373    gROOT->cd();
374    if (fInputEventHandler) {
375       fInputEventHandler->SetInputTree(tree);
376       if (fMode == kProofAnalysis) {
377          init = fInputEventHandler->Init("proof");
378          if (!init) msg = "Failed to initialize input handler on worker";
379       } else {
380          init = fInputEventHandler->Init("local");
381          if (!init) msg = "Failed to initialize input handler";
382       }
383       initOK &= init;
384       if (!fSelector) Error("SlaveBegin", "Selector not set");      
385       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
386    }
387    gROOT->cd();
388    if (fMCtruthEventHandler) {
389       if (fMode == kProofAnalysis) {
390          init = fMCtruthEventHandler->Init("proof");
391          if (!init) msg = "Failed to initialize MC handler on worker";
392       } else {
393          init = fMCtruthEventHandler->Init("local");
394          if (!init) msg = "Failed to initialize MC handler";
395       }
396       initOK &= init;
397       if (!fSelector) Error("SlaveBegin", "Selector not set");      
398       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
399    }
400    if (curdir) curdir->cd();
401    isCalled = kTRUE;
402    if (!initOK) return;   
403    TIter next(fTasks);
404    AliAnalysisTask *task;
405    // Call CreateOutputObjects for all tasks
406    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
407    Bool_t dirStatus = TH1::AddDirectoryStatus();
408    Int_t itask = 0;
409    while ((task=(AliAnalysisTask*)next())) {
410       gROOT->cd();
411       // Start with memory as current dir and make sure by default histograms do not get attached to files.
412       TH1::AddDirectory(kFALSE);
413       task->CreateOutputObjects();
414       if (!task->CheckPostData()) {
415          Error("SlaveBegin","####### IMPORTANT! ####### \n\n\n\
416                 Task %s (%s) did not call PostData() for all its outputs in (User)CreateOutputObjects()\n\n\
417                 ####### FIX YOUR CODE, THIS WILL PRODUCE A FATAL ERROR IN FUTURE! ##########", task->GetName(), task->ClassName());
418       }
419       if (getsysInfo) AliSysInfo::AddStamp(Form("%s_CREATEOUTOBJ",task->ClassName()), 0, itask, 0);
420       itask++;
421    }
422    TH1::AddDirectory(dirStatus);
423    if (curdir) curdir->cd();
424    if (fDebug > 1) printf("<-AliAnalysisManager::SlaveBegin()\n");
425 }
426
427 //______________________________________________________________________________
428 Bool_t AliAnalysisManager::Notify()
429 {
430    // The Notify() function is called when a new file is opened. This
431    // can be either for a new TTree in a TChain or when when a new TTree
432    // is started when using PROOF. It is normaly not necessary to make changes
433    // to the generated code, but the routine can be extended by the
434    // user if needed. The return value is currently not used.
435    if (!fTree) return kFALSE;
436    if (!TObject::TestBit(AliAnalysisManager::kTrueNotify)) return kFALSE;
437
438    fTable.Clear("nodelete"); // clearing the hash table may not be needed -> C.L.
439    if (fMode == kProofAnalysis) fIsRemote = kTRUE;
440
441    TFile *curfile = fTree->GetCurrentFile();
442    if (!curfile) {
443       Error("Notify","No current file");
444       return kFALSE;
445    }   
446    
447    if (fDebug > 1) printf("->AliAnalysisManager::Notify() file: %s\n", curfile->GetName());
448    Int_t run = AliAnalysisManager::GetRunFromAlienPath(curfile->GetName());
449    if (run && (run != fRunFromPath)) {
450       fRunFromPath = run;
451       if (fDebug > 1) printf("   ### run found from path: %d\n", run);
452    }
453    TIter next(fTasks);
454    AliAnalysisTask *task;
455         
456    // Call Notify of the event handlers
457    if (fInputEventHandler) {
458        fInputEventHandler->Notify(curfile->GetName());
459    }
460
461    if (fOutputEventHandler) {
462        fOutputEventHandler->Notify(curfile->GetName());
463    }
464
465    if (fMCtruthEventHandler) {
466        fMCtruthEventHandler->Notify(curfile->GetName());
467    }
468
469    // Call Notify for all tasks
470    while ((task=(AliAnalysisTask*)next())) 
471       task->Notify();
472
473    if (fDebug > 1) printf("<-AliAnalysisManager::Notify()\n");
474    return kTRUE;
475 }    
476
477 //______________________________________________________________________________
478 Bool_t AliAnalysisManager::Process(Long64_t)
479 {
480   // The Process() function is called for each entry in the tree (or possibly
481   // keyed object in the case of PROOF) to be processed. The entry argument
482   // specifies which entry in the currently loaded tree is to be processed.
483   // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()
484   // to read either all or the required parts of the data. When processing
485   // keyed objects with PROOF, the object is already loaded and is available
486   // via the fObject pointer.
487   //
488   // This function should contain the "body" of the analysis. It can contain
489   // simple or elaborate selection criteria, run algorithms on the data
490   // of the event and typically fill histograms.
491
492   // WARNING when a selector is used with a TChain, you must use
493   //  the pointer to the current TTree to call GetEntry(entry).
494   //  The entry is always the local entry number in the current tree.
495   //  Assuming that fChain is the pointer to the TChain being processed,
496   //  use fChain->GetTree()->GetEntry(entry).
497
498    // This method is obsolete. ExecAnalysis is called instead.
499    return kTRUE;
500 }
501
502 //______________________________________________________________________________
503 void AliAnalysisManager::PackOutput(TList *target)
504 {
505   // Pack all output data containers in the output list. Called at SlaveTerminate
506   // stage in PROOF case for each slave.
507    if (fDebug > 1) printf("->AliAnalysisManager::PackOutput()\n");
508    if (!target) {
509       Error("PackOutput", "No target. Exiting.");
510       return;
511    }
512    TDirectory *cdir = gDirectory;
513    gROOT->cd();
514    if (fInputEventHandler)   fInputEventHandler  ->Terminate();
515    if (fOutputEventHandler)  fOutputEventHandler ->Terminate();
516    if (fMCtruthEventHandler) fMCtruthEventHandler->Terminate();
517    gROOT->cd();
518
519    // Call FinishTaskOutput() for each event loop task (not called for 
520    // post-event loop tasks - use Terminate() fo those)
521    TIter nexttask(fTasks);
522    AliAnalysisTask *task;
523    while ((task=(AliAnalysisTask*)nexttask())) {
524       if (!task->IsPostEventLoop()) {
525          if (fDebug > 1) printf("->FinishTaskOutput: task %s\n", task->GetName());
526          task->FinishTaskOutput();
527          gROOT->cd();
528          if (fDebug > 1) printf("<-FinishTaskOutput: task %s\n", task->GetName());
529       }
530    }
531    // Write statistics message on the workers.
532    if (fStatistics) WriteStatisticsMsg(fNcalls);
533    
534    if (fMode == kProofAnalysis) {
535       TIter next(fOutputs);
536       AliAnalysisDataContainer *output;
537       Bool_t isManagedByHandler = kFALSE;
538       TList filestmp;
539       filestmp.SetOwner();
540       while ((output=(AliAnalysisDataContainer*)next())) {
541          // Do not consider outputs of post event loop tasks
542          isManagedByHandler = kFALSE;
543          if (output->GetProducer() && output->GetProducer()->IsPostEventLoop()) continue;
544          const char *filename = output->GetFileName();
545          if (!(strcmp(filename, "default")) && fOutputEventHandler) {
546             isManagedByHandler = kTRUE;
547             printf("#### Handler output. Extra: %s\n", fExtraFiles.Data());
548             filename = fOutputEventHandler->GetOutputFileName();
549          }
550          // Check if data was posted to this container. If not, issue an error.
551          if (!output->GetData() && !isManagedByHandler) {
552             Error("PackOutput", "No data for output container %s. Forgot to PostData ?", output->GetName());
553             continue;
554          }   
555          if (!output->IsSpecialOutput()) {
556             // Normal outputs
557             if (strlen(filename) && !isManagedByHandler) {
558                // Backup current folder
559                TDirectory *opwd = gDirectory;
560                // File resident outputs. 
561                // Check first if the file exists.
562                TString openoption = "RECREATE";
563                Bool_t firsttime = kTRUE;
564                if (filestmp.FindObject(output->GetFileName())) {
565                   firsttime = kFALSE;
566                } else {   
567                   filestmp.Add(new TNamed(output->GetFileName(),""));
568                }   
569                if (!gSystem->AccessPathName(output->GetFileName()) && !firsttime) openoption = "UPDATE";
570 //               TFile *file = AliAnalysisManager::OpenFile(output, openoption, kTRUE);
571                // Save data to file, then close.
572                if (output->GetData()->InheritsFrom(TCollection::Class())) {
573                   // If data is a collection, we set the name of the collection 
574                   // as the one of the container and we save as a single key.
575                   TCollection *coll = (TCollection*)output->GetData();
576                   coll->SetName(output->GetName());
577 //                  coll->Write(output->GetName(), TObject::kSingleKey);
578                } else {
579                   if (output->GetData()->InheritsFrom(TTree::Class())) {
580                      TFile *file = AliAnalysisManager::OpenFile(output, openoption, kTRUE);
581                      // Save data to file, then close.
582                      TTree *tree = (TTree*)output->GetData();
583                      // Check if tree is in memory
584                      if (tree->GetDirectory()==gROOT) tree->SetDirectory(gDirectory);
585                      tree->AutoSave();
586                      file->Close();
587                   } else {
588 //                     output->GetData()->Write();
589                   }   
590                }      
591                if (fDebug > 1) printf("PackOutput %s: memory merge, file resident output\n", output->GetName());
592 //               if (fDebug > 2) {
593 //                  printf("   file %s listing content:\n", filename);
594 //                  file->ls();
595 //               }   
596                // Clear file list to release object ownership to user.
597 //               file->Clear();
598 //               file->Close();
599                output->SetFile(NULL);
600                // Restore current directory
601                if (opwd) opwd->cd();
602             } else {
603                // Memory-resident outputs   
604                if (fDebug > 1) printf("PackOutput %s: memory merge memory resident output\n", filename);
605             }   
606             AliAnalysisDataWrapper *wrap = 0;
607             if (isManagedByHandler) {
608                wrap = new AliAnalysisDataWrapper(fOutputEventHandler->GetTree());
609                wrap->SetName(output->GetName());
610             }   
611             else                    wrap =output->ExportData();
612             // Output wrappers must NOT delete data after merging - the user owns them
613             wrap->SetDeleteData(kFALSE);
614             target->Add(wrap);
615          } else {
616          // Special outputs. The file must be opened and connected to the container.
617             TDirectory *opwd = gDirectory;
618             TFile *file = output->GetFile();
619             if (!file) {
620                AliAnalysisTask *producer = output->GetProducer();
621                Fatal("PackOutput", 
622                      "File %s for special container %s was NOT opened in %s::CreateOutputObjects !!!",
623                      output->GetFileName(), output->GetName(), producer->ClassName());
624                continue;
625             }   
626             TString outFilename = file->GetName();
627             if (fDebug > 1) printf("PackOutput %s: special output\n", output->GetName());
628             if (isManagedByHandler) {
629                // Terminate IO for files managed by the output handler
630                // file->Write() moved to AOD handler (A.G. 11.01.10)
631 //               if (file) file->Write();
632                if (file && fDebug > 2) {
633                   printf("   handled file %s listing content:\n", file->GetName());
634                   file->ls();
635                }   
636                fOutputEventHandler->TerminateIO();
637             } else {               
638                file->cd();
639                // Release object ownership to users after writing data to file
640                if (output->GetData()->InheritsFrom(TCollection::Class())) {
641                   // If data is a collection, we set the name of the collection 
642                   // as the one of the container and we save as a single key.
643                   TCollection *coll = (TCollection*)output->GetData();
644                   coll->SetName(output->GetName());
645                   coll->Write(output->GetName(), TObject::kSingleKey);
646                } else {
647                   if (output->GetData()->InheritsFrom(TTree::Class())) {
648                      TTree *tree = (TTree*)output->GetData();
649                      tree->SetDirectory(file);
650                      tree->AutoSave();
651                   } else {
652                      output->GetData()->Write();
653                   }   
654                }      
655                if (fDebug > 2) {
656                   printf("   file %s listing content:\n", output->GetFileName());
657                   file->ls();
658                }
659                // Clear file list to release object ownership to user.
660 //               file->Clear();
661                file->Close();
662                output->SetFile(NULL);
663             }
664             // Restore current directory
665             if (opwd) opwd->cd();
666             // Check if a special output location was provided or the output files have to be merged
667             if (strlen(fSpecialOutputLocation.Data())) {
668                TString remote = fSpecialOutputLocation;
669                remote += "/";
670                Int_t gid = gROOT->ProcessLine("gProofServ->GetGroupId();");
671                if (remote.BeginsWith("alien:")) {
672                   gROOT->ProcessLine("TGrid::Connect(\"alien:\", gProofServ->GetUser());");
673                   remote += outFilename;
674                   remote.ReplaceAll(".root", Form("_%d.root", gid));
675                } else {   
676                   remote += Form("%s_%d_", gSystem->HostName(), gid);
677                   remote += outFilename;
678                }   
679                if (fDebug > 1) 
680                   Info("PackOutput", "Output file for container %s to be copied \n   at: %s. No merging.",
681                        output->GetName(), remote.Data());
682                TFile::Cp ( outFilename.Data(), remote.Data() );
683                // Copy extra outputs
684                if (fExtraFiles.Length() && isManagedByHandler) {
685                   TObjArray *arr = fExtraFiles.Tokenize(" ");
686                   TObjString *os;
687                   TIter nextfilename(arr);
688                   while ((os=(TObjString*)nextfilename())) {
689                      outFilename = os->GetString();
690                      remote = fSpecialOutputLocation;
691                      remote += "/";
692                      if (remote.BeginsWith("alien://")) {
693                         remote += outFilename;
694                         remote.ReplaceAll(".root", Form("_%d.root", gid));
695                      } else {   
696                         remote += Form("%s_%d_", gSystem->HostName(), gid);
697                         remote += outFilename;
698                      }   
699                      if (fDebug > 1) 
700                         Info("PackOutput", "Extra AOD file %s to be copied \n   at: %s. No merging.",
701                              outFilename.Data(), remote.Data());
702                      TFile::Cp ( outFilename.Data(), remote.Data() );
703                   }   
704                   delete arr;
705                }   
706             } else {
707             // No special location specified-> use TProofOutputFile as merging utility
708             // The file at this output slot must be opened in CreateOutputObjects
709                if (fDebug > 1) printf("   File for container %s to be merged via file merger...\n", output->GetName());
710             }
711          }      
712       }
713    } 
714    cdir->cd();
715    if (fDebug > 1) printf("<-AliAnalysisManager::PackOutput: output list contains %d containers\n", target->GetSize());
716 }
717
718 //______________________________________________________________________________
719 void AliAnalysisManager::ImportWrappers(TList *source)
720 {
721 // Import data in output containers from wrappers coming in source.
722    if (fDebug > 1) printf("->AliAnalysisManager::ImportWrappers()\n");
723    TIter next(fOutputs);
724    AliAnalysisDataContainer *cont;
725    AliAnalysisDataWrapper   *wrap;
726    Int_t icont = 0;
727    Bool_t inGrid = (fMode == kGridAnalysis)?kTRUE:kFALSE;
728    TDirectory *cdir = gDirectory;
729    while ((cont=(AliAnalysisDataContainer*)next())) {
730       wrap = 0;
731       if (cont->GetProducer() && cont->GetProducer()->IsPostEventLoop() && !inGrid) continue;
732       if (cont->IsRegisterDataset()) continue;
733       const char *filename = cont->GetFileName();
734       Bool_t isManagedByHandler = kFALSE;
735       if (!(strcmp(filename, "default")) && fOutputEventHandler) {
736          isManagedByHandler = kTRUE;
737          filename = fOutputEventHandler->GetOutputFileName();
738       }
739       if (cont->IsSpecialOutput() || inGrid) {
740          if (strlen(fSpecialOutputLocation.Data())) continue;
741          // Copy merged file from PROOF scratch space. 
742          // In case of grid the files are already in the current directory.
743          if (!inGrid) {
744             if (isManagedByHandler && fExtraFiles.Length()) {
745                // Copy extra registered dAOD files.
746                TObjArray *arr = fExtraFiles.Tokenize(" ");
747                TObjString *os;
748                TIter nextfilename(arr);
749                while ((os=(TObjString*)nextfilename())) GetFileFromWrapper(os->GetString(), source);
750                delete arr;
751             }
752             if (!GetFileFromWrapper(filename, source)) continue;
753          }   
754          // Normally we should connect data from the copied file to the
755          // corresponding output container, but it is not obvious how to do this
756          // automatically if several objects in file...
757          TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
758          if (!f) f = TFile::Open(filename, "READ");
759          if (!f) {
760             Error("ImportWrappers", "Cannot open file %s in read-only mode", filename);
761             continue;
762          }   
763          TObject *obj = 0;
764          // Cd to the directory pointed by the container
765          TString folder = cont->GetFolderName();
766          if (!folder.IsNull()) f->cd(folder);
767          // Try to fetch first an object having the container name.
768          obj = gDirectory->Get(cont->GetName());
769          if (!obj) {
770             Warning("ImportWrappers", "Could not import object of type:%s for container %s in file %s:%s.\n Object will not be available in Terminate(). Try if possible to name the output object as the container (%s) or to embed it in a TList", 
771                     cont->GetType()->GetName(), cont->GetName(), filename, cont->GetFolderName(), cont->GetName());
772             continue;
773          }  
774          wrap = new AliAnalysisDataWrapper(obj);
775          wrap->SetDeleteData(kFALSE);
776       }   
777       if (!wrap) wrap = (AliAnalysisDataWrapper*)source->FindObject(cont->GetName());
778       if (!wrap) {
779          Error("ImportWrappers","Container %s not found in analysis output !", cont->GetName());
780          continue;
781       }
782       icont++;
783       if (fDebug > 1) {
784          printf("   Importing data for container %s\n", cont->GetName());
785          if (strlen(filename)) printf("    -> file %s\n", filename);
786          else printf("\n");
787       }   
788       cont->ImportData(wrap);
789    }
790    if (cdir) cdir->cd();
791    if (fDebug > 1) printf("<-AliAnalysisManager::ImportWrappers(): %d containers imported\n", icont);
792 }
793
794 //______________________________________________________________________________
795 void AliAnalysisManager::UnpackOutput(TList *source)
796 {
797   // Called by AliAnalysisSelector::Terminate only on the client.
798    if (fDebug > 1) printf("->AliAnalysisManager::UnpackOutput()\n");
799    if (!source) {
800       Error("UnpackOutput", "No target. Exiting.");
801       return;
802    }
803    if (fDebug > 1) printf("   Source list contains %d containers\n", source->GetSize());
804
805    if (fMode == kProofAnalysis) ImportWrappers(source);
806
807    TIter next(fOutputs);
808    AliAnalysisDataContainer *output;
809    while ((output=(AliAnalysisDataContainer*)next())) {
810       if (!output->GetData()) continue;
811       // Check if there are client tasks that run post event loop
812       if (output->HasConsumers()) {
813          // Disable event loop semaphore
814          output->SetPostEventLoop(kTRUE);
815          TObjArray *list = output->GetConsumers();
816          Int_t ncons = list->GetEntriesFast();
817          for (Int_t i=0; i<ncons; i++) {
818             AliAnalysisTask *task = (AliAnalysisTask*)list->At(i);
819             task->CheckNotify(kTRUE);
820             // If task is active, execute it
821             if (task->IsPostEventLoop() && task->IsActive()) {
822                if (fDebug > 1) printf("== Executing post event loop task %s\n", task->GetName());
823                task->ExecuteTask();
824             }   
825          }
826       }   
827    }
828    if (fDebug > 1) printf("<-AliAnalysisManager::UnpackOutput()\n");
829 }
830
831 //______________________________________________________________________________
832 void AliAnalysisManager::Terminate()
833 {
834   // The Terminate() function is the last function to be called during
835   // a query. It always runs on the client, it can be used to present
836   // the results graphically.
837    if (fDebug > 1) printf("->AliAnalysisManager::Terminate()\n");
838    TDirectory *cdir = gDirectory;
839    gROOT->cd();
840    AliAnalysisTask *task;
841    AliAnalysisDataContainer *output;
842    TIter next(fTasks);
843    TStopwatch timer;
844    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
845    // Call Terminate() for tasks
846    Int_t itask = 0;
847    while (!IsSkipTerminate() && (task=(AliAnalysisTask*)next())) {
848       // Save all the canvases produced by the Terminate
849       TString pictname = Form("%s_%s", task->GetName(), task->ClassName());
850       task->Terminate();
851       gROOT->cd();
852       if (getsysInfo) 
853          AliSysInfo::AddStamp(Form("%s_TERMINATE",task->ClassName()),0, itask, 2);
854       itask++;   
855       if (TObject::TestBit(kSaveCanvases)) {
856          if (!gROOT->IsBatch()) {
857             if (fDebug>1) printf("Waiting 5 sec for %s::Terminate() to finish drawing ...\n", task->ClassName());
858             timer.Start();
859             while (timer.CpuTime()<5) {
860                timer.Continue();
861                gSystem->ProcessEvents();
862             }
863          }
864          Int_t iend = gROOT->GetListOfCanvases()->GetEntries();
865          if (iend==0) continue;
866          TCanvas *canvas;
867          for (Int_t ipict=0; ipict<iend; ipict++) {
868             canvas = (TCanvas*)gROOT->GetListOfCanvases()->At(ipict);
869             if (!canvas) continue;         
870             canvas->SaveAs(Form("%s_%02d.gif", pictname.Data(),ipict));
871          } 
872          gROOT->GetListOfCanvases()->Delete(); 
873       }
874    }   
875    //
876    if (fInputEventHandler)   fInputEventHandler  ->TerminateIO();
877    if (fOutputEventHandler)  fOutputEventHandler ->TerminateIO();
878    if (fMCtruthEventHandler) fMCtruthEventHandler->TerminateIO();
879    gROOT->cd();
880    TObjArray *allOutputs = new TObjArray();
881    Int_t icont;
882    for (icont=0; icont<fOutputs->GetEntriesFast(); icont++) allOutputs->Add(fOutputs->At(icont));
883    if (!IsSkipTerminate())
884       for (icont=0; icont<fParamCont->GetEntriesFast(); icont++) allOutputs->Add(fParamCont->At(icont));
885    TIter next1(allOutputs);
886    TString handlerFile = "";
887    TString extraOutputs = "";
888    if (fOutputEventHandler) {
889       handlerFile = fOutputEventHandler->GetOutputFileName();
890       extraOutputs = fOutputEventHandler->GetExtraOutputs();
891    }
892    icont = 0;
893    TList filestmp;
894    while ((output=(AliAnalysisDataContainer*)next1())) {
895       // Special outputs or grid files have the files already closed and written.
896       icont++;
897       if (fMode == kGridAnalysis && icont<=fOutputs->GetEntriesFast()) continue;
898       if (fMode == kProofAnalysis) {
899         if (output->IsSpecialOutput() || output->IsRegisterDataset()) continue;
900       }  
901       const char *filename = output->GetFileName();
902       TString openoption = "RECREATE";
903       if (!(strcmp(filename, "default"))) continue;
904       if (!strlen(filename)) continue;
905       if (!output->GetData()) continue;
906       TDirectory *opwd = gDirectory;
907       TFile *file = output->GetFile();
908       if (!file) file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
909       if (!file) {
910               //if (handlerFile == filename && !gSystem->AccessPathName(filename)) openoption = "UPDATE";
911          Bool_t firsttime = kTRUE;
912          if (filestmp.FindObject(filename) || extraOutputs.Contains(filename)) {
913             firsttime = kFALSE;
914          } else {   
915             filestmp.Add(new TNamed(filename,""));
916          }   
917          if (!gSystem->AccessPathName(filename) && !firsttime) openoption = "UPDATE";
918               if (fDebug>1) printf("Opening file: %s  option=%s\n",filename, openoption.Data());
919          file = new TFile(filename, openoption);
920       } else {
921          if (fDebug>1) printf("File <%s> already opened with option: <%s> \n", filename, file->GetOption());
922          openoption = file->GetOption();
923          if (openoption == "READ") {
924             if (fDebug>1) printf("...reopening in UPDATE mode\n");
925             file->ReOpen("UPDATE");            
926          }
927       }   
928       if (file->IsZombie()) {
929          Error("Terminate", "Cannot open output file %s", filename);
930          continue;
931       }   
932       output->SetFile(file);
933       file->cd();
934       // Check for a folder request
935       TString dir = output->GetFolderName();
936       if (!dir.IsNull()) {
937          if (!file->GetDirectory(dir)) file->mkdir(dir);
938          file->cd(dir);
939       }  
940       if (fDebug > 1) printf("...writing container %s to file %s:%s\n", output->GetName(), file->GetName(), output->GetFolderName());
941       if (output->GetData()->InheritsFrom(TCollection::Class())) {
942       // If data is a collection, we set the name of the collection 
943       // as the one of the container and we save as a single key.
944          TCollection *coll = (TCollection*)output->GetData();
945          coll->SetName(output->GetName());
946          coll->Write(output->GetName(), TObject::kSingleKey);
947       } else {
948          if (output->GetData()->InheritsFrom(TTree::Class())) {
949             TTree *tree = (TTree*)output->GetData();
950             tree->SetDirectory(gDirectory);
951             tree->AutoSave();
952          } else {
953             output->GetData()->Write();
954          }   
955       }      
956       if (opwd) opwd->cd();
957    }
958    gROOT->cd();
959    next1.Reset();
960    while ((output=(AliAnalysisDataContainer*)next1())) {
961       // Close all files at output
962       TDirectory *opwd = gDirectory;
963       if (output->GetFile()) {
964          // Clear file list to release object ownership to user.
965 //         output->GetFile()->Clear();
966          output->GetFile()->Close();
967          output->SetFile(NULL);
968          // Copy merged outputs in alien if requested
969          if (fSpecialOutputLocation.Length() && 
970              fSpecialOutputLocation.BeginsWith("alien://")) {
971             Info("Terminate", "Copy file %s to %s", output->GetFile()->GetName(),fSpecialOutputLocation.Data()); 
972             TFile::Cp(output->GetFile()->GetName(), 
973                       Form("%s/%s", fSpecialOutputLocation.Data(), output->GetFile()->GetName()));
974          }             
975       }   
976       if (opwd) opwd->cd();
977    }   
978    delete allOutputs;
979    //Write statistics information on the client
980    if (fStatistics) WriteStatisticsMsg(fNcalls);
981    if (getsysInfo) {
982       TDirectory *crtdir = gDirectory;
983       TFile f("syswatch.root", "RECREATE");
984       TH1 *hist;
985       TString cut;
986       if (!f.IsZombie()) {
987          TTree *tree = AliSysInfo::MakeTree("syswatch.log");
988          tree->SetName("syswatch");
989          tree->SetMarkerStyle(kCircle);
990          tree->SetMarkerColor(kBlue);
991          tree->SetMarkerSize(0.5);
992          if (!gROOT->IsBatch()) {
993             tree->SetAlias("event", "id0");
994             tree->SetAlias("task",  "id1");
995             tree->SetAlias("stage", "id2");
996             // Already defined aliases
997             // tree->SetAlias("deltaT","stampSec-stampOldSec");
998             // tree->SetAlias("T","stampSec-first");
999             // tree->SetAlias("deltaVM","(pI.fMemVirtual-pIOld.fMemVirtual)");
1000             // tree->SetAlias("VM","pI.fMemVirtual");
1001             TCanvas *canvas = new TCanvas("SysInfo","SysInfo",10,10,1200,800);
1002             Int_t npads = 1 /*COO plot for all tasks*/ +
1003                           fTopTasks->GetEntries() /*Exec plot per task*/ +
1004                           1 /*Terminate plot for all tasks*/ +
1005                           1; /*vm plot*/
1006                           
1007             Int_t iopt = (Int_t)TMath::Sqrt((Double_t)npads);
1008             if (npads<iopt*(iopt+1))
1009                canvas->Divide(iopt, iopt+1, 0.01, 0.01);
1010             else
1011                canvas->Divide(iopt+1, iopt+1, 0.01, 0.01);
1012             Int_t ipad = 1;
1013             // draw the plot of deltaVM for Exec for each task
1014             for (itask=0; itask<fTopTasks->GetEntriesFast(); itask++) {
1015                task = (AliAnalysisTask*)fTopTasks->At(itask);
1016                canvas->cd(ipad++);
1017                cut = Form("task==%d && stage==1", itask);
1018                tree->Draw("deltaVM:event",cut,"", 1234567890, 0);
1019                hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");            
1020                if (hist) {
1021                   hist->SetTitle(Form("%s: Exec dVM[MB]/event", task->GetName()));
1022                   hist->GetYaxis()->SetTitle("deltaVM [MB]");
1023                }   
1024             }
1025             // Draw the plot of deltaVM for CreateOutputObjects for all tasks
1026             canvas->cd(ipad++);
1027             tree->SetMarkerStyle(kFullTriangleUp);
1028             tree->SetMarkerColor(kRed);
1029             tree->SetMarkerSize(0.8);
1030             cut = "task>=0 && task<1000 && stage==0";
1031             tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
1032             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");            
1033             if (hist) {
1034                hist->SetTitle("Memory in CreateOutputObjects()");
1035                hist->GetYaxis()->SetTitle("deltaVM [MB]");
1036                hist->GetXaxis()->SetTitle("task");
1037             }   
1038             // draw the plot of deltaVM for Terminate for all tasks
1039             canvas->cd(ipad++);
1040             tree->SetMarkerStyle(kOpenSquare);
1041             tree->SetMarkerColor(kMagenta);
1042             cut = "task>=0 && task<1000 && stage==2";
1043             tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
1044             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1045             if (hist) {
1046                hist->SetTitle("Memory in Terminate()");
1047                hist->GetYaxis()->SetTitle("deltaVM [MB]");
1048                hist->GetXaxis()->SetTitle("task");
1049             }   
1050             // Full VM profile
1051             canvas->cd(ipad++);
1052             tree->SetMarkerStyle(kFullCircle);
1053             tree->SetMarkerColor(kGreen);
1054             cut = Form("task==%d && stage==1",fTopTasks->GetEntriesFast()-1);            
1055             tree->Draw("VM:event",cut,"", 1234567890, 0);
1056             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1057             if (hist) {
1058                hist->SetTitle("Virtual memory");
1059                hist->GetYaxis()->SetTitle("VM [MB]");
1060             }
1061             canvas->Modified();   
1062          }   
1063          tree->SetMarkerStyle(kCircle);
1064          tree->SetMarkerColor(kBlue);
1065          tree->SetMarkerSize(0.5);
1066          tree->Write();
1067          f.Close();
1068          delete tree;
1069       }
1070       if (crtdir) crtdir->cd();
1071    }
1072    // Validate the output files
1073    if (ValidateOutputFiles() && fIsRemote && fMode!=kProofAnalysis) {
1074       ofstream out;
1075       out.open("outputs_valid", ios::out);
1076       out.close();
1077    }
1078    cdir->cd();      
1079    if (fDebug > 1) printf("<-AliAnalysisManager::Terminate()\n");
1080 }
1081 //______________________________________________________________________________
1082 void AliAnalysisManager::ProfileTask(Int_t itop, const char *option) const
1083 {
1084 // Profiles the task having the itop index in the list of top (first level) tasks.
1085    AliAnalysisTask *task = (AliAnalysisTask*)fTopTasks->At(itop);
1086    if (!task) {
1087       Error("ProfileTask", "There are only %d top tasks in the manager", fTopTasks->GetEntries());
1088       return;
1089    }
1090    ProfileTask(task->GetName(), option);
1091 }      
1092
1093 //______________________________________________________________________________
1094 void AliAnalysisManager::ProfileTask(const char *name, const char */*option*/) const
1095 {
1096 // Profile a managed task after the execution of the analysis in case NSysInfo
1097 // was used.
1098    if (gSystem->AccessPathName("syswatch.root")) {
1099       Error("ProfileTask", "No file syswatch.root found in the current directory");
1100       return;
1101    }
1102    if (gROOT->IsBatch()) return;
1103    AliAnalysisTask *task = (AliAnalysisTask*)fTopTasks->FindObject(name);
1104    if (!task) {
1105       Error("ProfileTask", "No top task named %s known by the manager.", name);
1106       return;
1107    }
1108    Int_t itop = fTopTasks->IndexOf(task);
1109    Int_t itask = fTasks->IndexOf(task);
1110    // Create canvas with 2 pads: first draw COO + Terminate, second Exec
1111    TDirectory *cdir = gDirectory;
1112    TFile f("syswatch.root");
1113    TTree *tree = (TTree*)f.Get("syswatch");
1114    if (!tree) {
1115       Error("ProfileTask", "No tree named <syswatch> found in file syswatch.root");
1116       return;
1117    }   
1118    if (fDebug > 1) printf("=== Profiling task %s (class %s)\n", name, task->ClassName());
1119    TCanvas *canvas = new TCanvas(Form("profile_%d",itop),Form("Profile of task %s (class %s)",name,task->ClassName()),10,10,800,600);
1120    canvas->Divide(2, 2, 0.01, 0.01);
1121    Int_t ipad = 1;
1122    TString cut;
1123    TH1 *hist;
1124    // VM profile for COO and Terminate methods
1125    canvas->cd(ipad++);
1126    cut = Form("task==%d && (stage==0 || stage==2)",itask);
1127    tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
1128    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1129    if (hist) {
1130       hist->SetTitle("Alocated VM[MB] for COO and Terminate");
1131       hist->GetYaxis()->SetTitle("deltaVM [MB]");
1132       hist->GetXaxis()->SetTitle("method");
1133    }   
1134    // CPU profile per event
1135    canvas->cd(ipad++);
1136    cut = Form("task==%d && stage==1",itop);
1137    tree->Draw("deltaT:event",cut,"", 1234567890, 0);
1138    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1139    if (hist) {
1140       hist->SetTitle("Execution time per event");
1141       hist->GetYaxis()->SetTitle("CPU/event [s]");
1142    }   
1143    // VM profile for Exec
1144    canvas->cd(ipad++);
1145    cut = Form("task==%d && stage==1",itop);
1146    tree->Draw("deltaVM:event",cut,"", 1234567890, 0);
1147    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1148    if (hist) {
1149       hist->SetTitle("Alocated VM[MB] per event");
1150       hist->GetYaxis()->SetTitle("deltaVM [MB]");
1151    }   
1152    canvas->Modified();
1153    delete tree;
1154    f.Close();
1155    if (cdir) cdir->cd();
1156 }     
1157
1158 //______________________________________________________________________________
1159 void AliAnalysisManager::AddTask(AliAnalysisTask *task)
1160 {
1161 // Adds a user task to the global list of tasks.
1162    if (fInitOK) {
1163       Error("AddTask", "Cannot add task %s since InitAnalysis was already called", task->GetName());
1164       return;
1165    }   
1166       
1167    if (fTasks->FindObject(task)) {
1168       Warning("AddTask", "Task %s: the same object already added to the analysis manager. Not adding.", task->GetName());
1169       return;
1170    }   
1171    task->SetActive(kFALSE);
1172    fTasks->Add(task);
1173 }  
1174
1175 //______________________________________________________________________________
1176 AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const
1177 {
1178 // Retreive task by name.
1179    if (!fTasks) return NULL;
1180    return (AliAnalysisTask*)fTasks->FindObject(name);
1181 }
1182
1183 //______________________________________________________________________________
1184 AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name, 
1185                                 TClass *datatype, EAliAnalysisContType type, const char *filename)
1186 {
1187 // Create a data container of a certain type. Types can be:
1188 //   kExchangeContainer  = 0, used to exchange data between tasks
1189 //   kInputContainer   = 1, used to store input data
1190 //   kOutputContainer  = 2, used for writing result to a file
1191 // filename: composed by file#folder (e.g. results.root#INCLUSIVE) - will write
1192 // the output object to a folder inside the output file
1193    if (fContainers->FindObject(name)) {
1194       Error("CreateContainer","A container named %s already defined !",name);
1195       return NULL;
1196    }   
1197    AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
1198    fContainers->Add(cont);
1199    switch (type) {
1200       case kInputContainer:
1201          fInputs->Add(cont);
1202          break;
1203       case kOutputContainer:
1204          fOutputs->Add(cont);
1205          if (filename && strlen(filename)) {
1206             cont->SetFileName(filename);
1207             cont->SetDataOwned(kFALSE);  // data owned by the file
1208          }   
1209          break;
1210       case kParamContainer:
1211          fParamCont->Add(cont);
1212          if (filename && strlen(filename)) {
1213             cont->SetFileName(filename);
1214             cont->SetDataOwned(kFALSE);  // data owned by the file
1215          }   
1216          break;
1217       case kExchangeContainer:
1218          break;   
1219    }
1220    return cont;
1221 }
1222          
1223 //______________________________________________________________________________
1224 Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
1225                                         AliAnalysisDataContainer *cont)
1226 {
1227 // Connect input of an existing task to a data container.
1228    if (!task) {
1229       Error("ConnectInput", "Task pointer is NULL");
1230       return kFALSE;
1231    }   
1232    if (!fTasks->FindObject(task)) {
1233       AddTask(task);
1234       Info("ConnectInput", "Task %s was not registered. Now owned by analysis manager", task->GetName());
1235    } 
1236    Bool_t connected = task->ConnectInput(islot, cont);
1237    return connected;
1238 }   
1239
1240 //______________________________________________________________________________
1241 Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
1242                                         AliAnalysisDataContainer *cont)
1243 {
1244 // Connect output of an existing task to a data container.
1245    if (!task) {
1246       Error("ConnectOutput", "Task pointer is NULL");
1247       return kFALSE;
1248    }   
1249    if (!fTasks->FindObject(task)) {
1250       AddTask(task);
1251       Warning("ConnectOutput", "Task %s not registered. Now owned by analysis manager", task->GetName());
1252    } 
1253    Bool_t connected = task->ConnectOutput(islot, cont);
1254    return connected;
1255 }   
1256                                
1257 //______________________________________________________________________________
1258 void AliAnalysisManager::CleanContainers()
1259 {
1260 // Clean data from all containers that have already finished all client tasks.
1261    TIter next(fContainers);
1262    AliAnalysisDataContainer *cont;
1263    while ((cont=(AliAnalysisDataContainer *)next())) {
1264       if (cont->IsOwnedData() && 
1265           cont->IsDataReady() && 
1266           cont->ClientsExecuted()) cont->DeleteData();
1267    }
1268 }
1269
1270 //______________________________________________________________________________
1271 Bool_t AliAnalysisManager::InitAnalysis()
1272 {
1273 // Initialization of analysis chain of tasks. Should be called after all tasks
1274 // and data containers are properly connected
1275    // Reset flag and remove valid_outputs file if exists
1276    if (fInitOK) return kTRUE;
1277    if (!gSystem->AccessPathName("outputs_valid"))
1278       gSystem->Unlink("outputs_valid");
1279    // Check for top tasks (depending only on input data containers)
1280    if (!fTasks->First()) {
1281       Error("InitAnalysis", "Analysis has no tasks !");
1282       return kFALSE;
1283    }   
1284    TIter next(fTasks);
1285    AliAnalysisTask *task;
1286    AliAnalysisDataContainer *cont;
1287    Int_t ntop = 0;
1288    Int_t nzombies = 0;
1289    Bool_t iszombie = kFALSE;
1290    Bool_t istop = kTRUE;
1291    Int_t i;
1292    while ((task=(AliAnalysisTask*)next())) {
1293       istop = kTRUE;
1294       iszombie = kFALSE;
1295       Int_t ninputs = task->GetNinputs();
1296       for (i=0; i<ninputs; i++) {
1297          cont = task->GetInputSlot(i)->GetContainer();
1298          if (!cont) {
1299             if (!iszombie) {
1300                task->SetZombie();
1301                fZombies->Add(task);
1302                nzombies++;
1303                iszombie = kTRUE;
1304             }   
1305             Error("InitAnalysis", "Input slot %d of task %s has no container connected ! Declared zombie...", 
1306                   i, task->GetName()); 
1307          }
1308          if (iszombie) continue;
1309          // Check if cont is an input container
1310          if (istop && !fInputs->FindObject(cont)) istop=kFALSE;
1311          // Connect to parent task
1312       }
1313       if (istop) {
1314          ntop++;
1315          fTopTasks->Add(task);
1316       }
1317    }
1318    if (!ntop) {
1319       Error("InitAnalysis", "No top task defined. At least one task should be connected only to input containers");
1320       return kFALSE;
1321    }                        
1322    // Check now if there are orphan tasks
1323    for (i=0; i<ntop; i++) {
1324       task = (AliAnalysisTask*)fTopTasks->At(i);
1325       task->SetUsed();
1326    }
1327    Int_t norphans = 0;
1328    next.Reset();
1329    while ((task=(AliAnalysisTask*)next())) {
1330       if (!task->IsUsed()) {
1331          norphans++;
1332          Warning("InitAnalysis", "Task %s is orphan", task->GetName());
1333       }   
1334    }          
1335    // Check the task hierarchy (no parent task should depend on data provided
1336    // by a daughter task)
1337    for (i=0; i<ntop; i++) {
1338       task = (AliAnalysisTask*)fTopTasks->At(i);
1339       if (task->CheckCircularDeps()) {
1340          Error("InitAnalysis", "Found illegal circular dependencies between following tasks:");
1341          PrintStatus("dep");
1342          return kFALSE;
1343       }   
1344    }
1345    // Check that all containers feeding post-event loop tasks are in the outputs list
1346    TIter nextcont(fContainers); // loop over all containers
1347    while ((cont=(AliAnalysisDataContainer*)nextcont())) {
1348       if (!cont->IsPostEventLoop() && !fOutputs->FindObject(cont)) {
1349          if (cont->HasConsumers()) {
1350          // Check if one of the consumers is post event loop
1351             TIter nextconsumer(cont->GetConsumers());
1352             while ((task=(AliAnalysisTask*)nextconsumer())) {
1353                if (task->IsPostEventLoop()) {
1354                   fOutputs->Add(cont);
1355                   break;
1356                }
1357             }
1358          }
1359       }
1360    }   
1361    // Check if all special output containers have a file name provided
1362    TIter nextout(fOutputs);
1363    while ((cont=(AliAnalysisDataContainer*)nextout())) {
1364       if (cont->IsSpecialOutput() && !strlen(cont->GetFileName())) {
1365          Error("InitAnalysis", "Wrong container %s : a file name MUST be provided for special outputs", cont->GetName());
1366          return kFALSE;
1367       }
1368    }
1369    // Initialize requested branch list if needed
1370    if (!fAutoBranchHandling) {
1371       next.Reset();
1372       while ((task=(AliAnalysisTask*)next())) {
1373          if (!task->HasBranches()) {
1374             Error("InitAnalysis", "Manual branch loading requested but task %s of type %s does not define branches.\nUse: fBranchNames = \"ESD:br1,br2,...,brN AOD:bra1,bra2,...,braM\"",
1375                   task->GetName(), task->ClassName());
1376             return kFALSE;
1377          }
1378          if (!fInputEventHandler || !strlen(fInputEventHandler->GetDataType())) {
1379             Error("InitAnalysis", "Manual branch loading requested but no input handler defined or handler does not define data type.");
1380             return kFALSE;
1381          }
1382          TString taskbranches;
1383          task->GetBranches(fInputEventHandler->GetDataType(), taskbranches);
1384          if (taskbranches.IsNull()) {
1385             Error("InitAnalysis", "Manual branch loading requested but task %s of type %s does not define branches of type %s:",
1386                   task->GetName(), task->ClassName(), fInputEventHandler->GetDataType());
1387             return kFALSE;      
1388          }
1389          AddBranches(taskbranches);
1390       }         
1391    }
1392    fInitOK = kTRUE;
1393    return kTRUE;
1394 }   
1395
1396 //______________________________________________________________________________
1397 void AliAnalysisManager::AddBranches(const char *branches)
1398 {
1399 // Add branches to the existing fRequestedBranches.
1400    TString br(branches);
1401    TObjArray *arr = br.Tokenize(",");
1402    TIter next(arr);
1403    TObject *obj;
1404    while ((obj=next())) {
1405       if (!fRequestedBranches.Contains(obj->GetName())) {
1406          if (!fRequestedBranches.IsNull()) fRequestedBranches += ",";
1407          fRequestedBranches += obj->GetName();
1408       }
1409    }
1410   delete arr;
1411 }   
1412
1413 //______________________________________________________________________________
1414 void AliAnalysisManager::CheckBranches(Bool_t load)
1415 {
1416 // The method checks the input branches to be loaded during the analysis.
1417    if (fAutoBranchHandling || fRequestedBranches.IsNull() || !fTree) return;   
1418    TObjArray *arr = fRequestedBranches.Tokenize(",");
1419    TIter next(arr);
1420    TObject *obj;
1421    while ((obj=next())) {
1422       TBranch *br = dynamic_cast<TBranch*>(fTable.FindObject(obj->GetName()));
1423       if (!br) {
1424          br = fTree->GetBranch(obj->GetName());
1425          if (!br) {
1426             Error("CheckBranches", "Could not find branch %s",obj->GetName());
1427             continue;
1428          }
1429       }   
1430       fTable.Add(br);
1431       if (load && br->GetReadEntry()!=GetCurrentEntry()) br->GetEntry(GetCurrentEntry());
1432    }
1433   delete arr;
1434 }
1435
1436 //______________________________________________________________________________
1437 Bool_t AliAnalysisManager::CheckTasks() const
1438 {
1439 // Check consistency of tasks.
1440    Int_t ntasks = fTasks->GetEntries();
1441    if (!ntasks) {
1442       Error("CheckTasks", "No tasks connected to the manager. This may be due to forgetting to compile the task or to load their library.");
1443       return kFALSE;
1444    }
1445    // Get the pointer to AliAnalysisTaskSE::Class()
1446    TClass *badptr = (TClass*)gROOT->ProcessLine("AliAnalysisTaskSE::Class()");
1447    // Loop all tasks to check if their corresponding library was loaded
1448    TIter next(fTasks);
1449    TObject *obj;
1450    while ((obj=next())) {
1451       if (obj->IsA() == badptr) {
1452          Error("CheckTasks", "##################\n \
1453          Class for task %s NOT loaded. You probably forgot to load the library for this task (or compile it dynamically).\n###########################\n",obj->GetName());
1454          return kFALSE;
1455       }
1456    }
1457    return kTRUE;      
1458 }   
1459
1460 //______________________________________________________________________________
1461 void AliAnalysisManager::PrintStatus(Option_t *option) const
1462 {
1463 // Print task hierarchy.
1464    if (!fInitOK) {
1465       Info("PrintStatus", "Analysis manager %s not initialized : call InitAnalysis() first", GetName());
1466       return;
1467    }   
1468    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1469    if (getsysInfo)
1470       Info("PrintStatus", "System information will be collected each %lld events", fNSysInfo);
1471    TIter next(fTopTasks);
1472    AliAnalysisTask *task;
1473    while ((task=(AliAnalysisTask*)next()))
1474       task->PrintTask(option);
1475   
1476    if (!fAutoBranchHandling && !fRequestedBranches.IsNull()) 
1477       printf("Requested input branches:\n%s\n", fRequestedBranches.Data());
1478   
1479   TString sopt(option);
1480   sopt.ToUpper();
1481   
1482   if (sopt.Contains("ALL"))
1483   {
1484     if ( fOutputEventHandler )
1485     {
1486       cout << TString('_',78) << endl;
1487       cout << "OutputEventHandler:" << endl;
1488       fOutputEventHandler->Print("   ");
1489     }
1490   }
1491 }
1492
1493 //______________________________________________________________________________
1494 void AliAnalysisManager::ResetAnalysis()
1495 {
1496 // Reset all execution flags and clean containers.
1497    CleanContainers();
1498 }
1499
1500 //______________________________________________________________________________
1501 Long64_t AliAnalysisManager::StartAnalysis(const char *type, Long64_t nentries, Long64_t firstentry)
1502 {
1503 // Start analysis having a grid handler.
1504    if (!fGridHandler) {
1505       Error("StartAnalysis", "Cannot start analysis providing just the analysis type without a grid handler.");
1506       Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1507       return -1;
1508    }
1509    TTree *tree = NULL;
1510    return StartAnalysis(type, tree, nentries, firstentry);
1511 }
1512
1513 //______________________________________________________________________________
1514 Long64_t AliAnalysisManager::StartAnalysis(const char *type, TTree * const tree, Long64_t nentries, Long64_t firstentry)
1515 {
1516 // Start analysis for this manager. Analysis task can be: LOCAL, PROOF, GRID or
1517 // MIX. Process nentries starting from firstentry
1518    Long64_t retv = 0;
1519    // Backup current directory and make sure gDirectory points to gROOT
1520    TDirectory *cdir = gDirectory;
1521    gROOT->cd();
1522    if (!fInitOK) {
1523       Error("StartAnalysis","Analysis manager was not initialized !");
1524       cdir->cd();
1525       return -1;
1526    }
1527    if (!CheckTasks()) Fatal("StartAnalysis", "Not all needed libraries were loaded");
1528    if (fDebug > 1) {
1529       printf("StartAnalysis %s\n",GetName());
1530       AliLog::SetGlobalLogLevel(AliLog::kInfo);
1531    }   
1532    fMaxEntries = nentries;
1533    fIsRemote = kFALSE;
1534    TString anaType = type;
1535    anaType.ToLower();
1536    fMode = kLocalAnalysis;
1537    Bool_t runlocalinit = kTRUE;
1538    if (anaType.Contains("file")) {
1539       runlocalinit = kFALSE;
1540       fIsRemote = kTRUE;
1541    }   
1542    if (anaType.Contains("proof"))     fMode = kProofAnalysis;
1543    else if (anaType.Contains("grid")) fMode = kGridAnalysis;
1544    else if (anaType.Contains("mix"))  fMode = kMixingAnalysis;
1545
1546    if (fMode == kGridAnalysis) {
1547       fIsRemote = kTRUE;
1548       if (!anaType.Contains("terminate")) {
1549          if (!fGridHandler) {
1550             Error("StartAnalysis", "Cannot start grid analysis without a grid handler.");
1551             Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1552             cdir->cd();
1553             return -1;
1554          }
1555          // Write analysis manager in the analysis file
1556          cout << "===== RUNNING GRID ANALYSIS: " << GetName() << endl;
1557          // run local task configuration
1558          TIter nextTask(fTasks);
1559          AliAnalysisTask *task;
1560          while ((task=(AliAnalysisTask*)nextTask())) {
1561             task->LocalInit();
1562             gROOT->cd();
1563          }
1564          if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1565             Info("StartAnalysis", "Grid analysis was stopped and cannot be terminated");
1566             cdir->cd();
1567             return -1;
1568          }   
1569
1570          // Terminate grid analysis
1571          if (fSelector && fSelector->GetStatus() == -1) {cdir->cd(); return -1;}
1572          if (fGridHandler->GetRunMode() == AliAnalysisGrid::kOffline) {cdir->cd(); return 0;}
1573          cout << "===== MERGING OUTPUTS REGISTERED BY YOUR ANALYSIS JOB: " << GetName() << endl;
1574          if (!fGridHandler->MergeOutputs()) {
1575             // Return if outputs could not be merged or if it alien handler
1576             // was configured for offline mode or local testing.
1577             cdir->cd();
1578             return 0;
1579          }
1580       }   
1581       cout << "===== TERMINATING GRID ANALYSIS JOB: " << GetName() << endl;
1582       ImportWrappers(NULL);
1583       Terminate();
1584       cdir->cd();
1585       return 0;
1586    }
1587    TString line;
1588    SetEventLoop(kFALSE);
1589    // Enable event loop mode if a tree was provided
1590    if (tree || fGridHandler || fMode==kMixingAnalysis) SetEventLoop(kTRUE);
1591
1592    TChain *chain = 0;
1593    TString ttype = "TTree";
1594    if (tree && tree->IsA() == TChain::Class()) {
1595       chain = (TChain*)tree;
1596       if (!chain || !chain->GetListOfFiles()->First()) {
1597          Error("StartAnalysis", "Cannot process null or empty chain...");
1598          cdir->cd();
1599          return -1;
1600       }   
1601       ttype = "TChain";
1602    }   
1603
1604    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1605    if (getsysInfo) AliSysInfo::AddStamp("Start", 0);
1606    // Initialize locally all tasks (happens for all modes)
1607    TIter next(fTasks);
1608    AliAnalysisTask *task;
1609    if (runlocalinit) {
1610       while ((task=(AliAnalysisTask*)next())) {
1611          task->LocalInit();
1612          gROOT->cd();
1613       }
1614       if (getsysInfo) AliSysInfo::AddStamp("LocalInit_all", 0);
1615    }   
1616    
1617    switch (fMode) {
1618       case kLocalAnalysis:
1619          if (!tree && !fGridHandler) {
1620             TIter nextT(fTasks);
1621             // Call CreateOutputObjects for all tasks
1622             Int_t itask = 0;
1623             Bool_t dirStatus = TH1::AddDirectoryStatus();
1624             while ((task=(AliAnalysisTask*)nextT())) {
1625                TH1::AddDirectory(kFALSE);
1626                task->CreateOutputObjects();
1627                if (!task->CheckPostData()) {
1628                   Error("SlaveBegin","####### IMPORTANT! ####### \n\n\n\
1629                         Task %s (%s) did not call PostData() for all its outputs in (User)CreateOutputObjects()\n\n\
1630                         ########### FIX YOUR CODE, THIS WILL PRODUCE A FATAL ERROR IN FUTURE! ###########", task->GetName(), task->ClassName());
1631                }
1632                if (getsysInfo) AliSysInfo::AddStamp(Form("%s_CREATEOUTOBJ",task->ClassName()), 0, itask, 0);
1633                gROOT->cd();
1634                itask++;
1635             }   
1636             TH1::AddDirectory(dirStatus);
1637             if (IsExternalLoop()) {
1638                Info("StartAnalysis", "Initialization done. Event loop is controlled externally.\
1639                      \nSetData for top container, call ExecAnalysis in a loop and then Terminate manually");
1640                return 0;
1641             }
1642             ExecAnalysis();
1643             Terminate();
1644             return 0;
1645          } 
1646          fSelector = new AliAnalysisSelector(this);
1647          // Check if a plugin handler is used
1648          if (fGridHandler) {
1649             // Get the chain from the plugin
1650             TString dataType = "esdTree";
1651             if (fInputEventHandler) {
1652                dataType = fInputEventHandler->GetDataType();
1653                dataType.ToLower();
1654                dataType += "Tree";
1655             }   
1656             chain = fGridHandler->GetChainForTestMode(dataType);
1657             if (!chain) {
1658                Error("StartAnalysis", "No chain for test mode. Aborting.");
1659                return -1;
1660             }
1661             cout << "===== RUNNING LOCAL ANALYSIS" << GetName() << " ON CHAIN " << chain->GetName() << endl;
1662             retv = chain->Process(fSelector, "", nentries, firstentry);
1663             break;
1664          }
1665          // Run tree-based analysis via AliAnalysisSelector  
1666          cout << "===== RUNNING LOCAL ANALYSIS " << GetName() << " ON TREE " << tree->GetName() << endl;
1667          retv = tree->Process(fSelector, "", nentries, firstentry);
1668          break;
1669       case kProofAnalysis:
1670          fIsRemote = kTRUE;
1671          // Check if the plugin is used
1672          if (fGridHandler) {
1673             return StartAnalysis(type, fGridHandler->GetProofDataSet(), nentries, firstentry);
1674          }
1675          if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1676             Error("StartAnalysis", "No PROOF!!! Exiting.");
1677             cdir->cd();
1678             return -1;
1679          }   
1680          line = Form("gProof->AddInput((TObject*)%p);", this);
1681          gROOT->ProcessLine(line);
1682          if (chain) {
1683             chain->SetProof();
1684             cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON CHAIN " << chain->GetName() << endl;
1685             retv = chain->Process("AliAnalysisSelector", "", nentries, firstentry);
1686          } else {
1687             Error("StartAnalysis", "No chain!!! Exiting.");
1688             cdir->cd();
1689             return -1;
1690          }      
1691          break;
1692       case kGridAnalysis:
1693          fIsRemote = kTRUE;
1694          if (!anaType.Contains("terminate")) {
1695             if (!fGridHandler) {
1696                Error("StartAnalysis", "Cannot start grid analysis without a grid handler.");
1697                Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1698                cdir->cd();
1699                return -1;
1700             }
1701             // Write analysis manager in the analysis file
1702             cout << "===== RUNNING GRID ANALYSIS: " << GetName() << endl;
1703             // Start the analysis via the handler
1704             if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1705                Info("StartAnalysis", "Grid analysis was stopped and cannot be terminated");
1706                cdir->cd();
1707                return -1;
1708             }   
1709
1710             // Terminate grid analysis
1711             if (fSelector && fSelector->GetStatus() == -1) {cdir->cd(); return -1;}
1712             if (fGridHandler->GetRunMode() == AliAnalysisGrid::kOffline) {cdir->cd(); return 0;}
1713             cout << "===== MERGING OUTPUTS REGISTERED BY YOUR ANALYSIS JOB: " << GetName() << endl;
1714             if (!fGridHandler->MergeOutputs()) {
1715                // Return if outputs could not be merged or if it alien handler
1716                // was configured for offline mode or local testing.
1717                cdir->cd();
1718                return 0;
1719             }
1720          }   
1721          cout << "===== TERMINATING GRID ANALYSIS JOB: " << GetName() << endl;
1722          ImportWrappers(NULL);
1723          Terminate();
1724          cdir->cd();
1725          return 0;
1726       case kMixingAnalysis:   
1727          // Run event mixing analysis
1728          if (!fEventPool) {
1729             Error("StartAnalysis", "Cannot run event mixing without event pool");
1730             cdir->cd();
1731             return -1;
1732          }
1733          cout << "===== RUNNING EVENT MIXING ANALYSIS " << GetName() << endl;
1734          fSelector = new AliAnalysisSelector(this);
1735          while ((chain=fEventPool->GetNextChain())) {
1736             next.Reset();
1737             // Call NotifyBinChange for all tasks
1738             while ((task=(AliAnalysisTask*)next()))
1739                if (!task->IsPostEventLoop()) task->NotifyBinChange();
1740             retv = chain->Process(fSelector);
1741             if (retv < 0) {
1742                Error("StartAnalysis", "Mixing analysis failed");
1743                cdir->cd();
1744                return retv;
1745             }   
1746          }
1747          PackOutput(fSelector->GetOutputList());
1748          Terminate();
1749    }
1750    cdir->cd();
1751    return retv;
1752 }   
1753
1754 //______________________________________________________________________________
1755 Long64_t AliAnalysisManager::StartAnalysis(const char *type, const char *dataset, Long64_t nentries, Long64_t firstentry)
1756 {
1757 // Start analysis for this manager on a given dataset. Analysis task can be: 
1758 // LOCAL, PROOF or GRID. Process nentries starting from firstentry.
1759    if (!fInitOK) {
1760       Error("StartAnalysis","Analysis manager was not initialized !");
1761       return -1;
1762    }
1763    fIsRemote = kTRUE;
1764    if (fDebug > 1) printf("StartAnalysis %s\n",GetName());
1765    TString anaType = type;
1766    anaType.ToLower();
1767    if (!anaType.Contains("proof")) {
1768       Error("StartAnalysis", "Cannot process datasets in %s mode. Try PROOF.", type);
1769       return -1;
1770    }   
1771    fMode = kProofAnalysis;
1772    TString line;
1773    SetEventLoop(kTRUE);
1774    // Set the dataset flag
1775    TObject::SetBit(kUseDataSet);
1776    fTree = 0;
1777    if (fGridHandler) {
1778       // Start proof analysis using the grid handler
1779       if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1780          Error("StartAnalysis", "The grid plugin could not start PROOF analysis");
1781          return -1;
1782       }
1783       // Check if the plugin is in test mode
1784       if (fGridHandler->GetRunMode() == AliAnalysisGrid::kTest) {
1785          dataset = "test_collection";
1786       } else {
1787          dataset = fGridHandler->GetProofDataSet();
1788       }
1789    }   
1790
1791    if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1792       Error("StartAnalysis", "No PROOF!!! Exiting.");
1793       return -1;
1794    }   
1795
1796    // Initialize locally all tasks
1797    TIter next(fTasks);
1798    AliAnalysisTask *task;
1799    while ((task=(AliAnalysisTask*)next())) {
1800       task->LocalInit();
1801    }
1802    
1803    line = Form("gProof->AddInput((TObject*)%p);", this);
1804    gROOT->ProcessLine(line);
1805    Long_t retv;
1806    line = Form("gProof->Process(\"%s\", \"AliAnalysisSelector\", \"\", %lld, %lld);",
1807                dataset, nentries, firstentry);
1808    cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON DATASET " << dataset << endl;
1809    retv = (Long_t)gROOT->ProcessLine(line);
1810    return retv;
1811 }   
1812
1813 //______________________________________________________________________________
1814 TFile *AliAnalysisManager::OpenFile(AliAnalysisDataContainer *cont, const char *option, Bool_t ignoreProof)
1815 {
1816 // Opens according the option the file specified by cont->GetFileName() and changes
1817 // current directory to cont->GetFolderName(). If the file was already opened, it
1818 // checks if the option UPDATE was preserved. File open via TProofOutputFile can
1819 // be optionally ignored.
1820   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1821   TString filename = cont->GetFileName();
1822   TFile *f = NULL;
1823   if (filename.IsNull()) {
1824     ::Error("AliAnalysisManager::OpenFile", "No file name specified for container %s", cont->GetName());
1825     return NULL;
1826   }
1827   if (mgr->GetAnalysisType()==AliAnalysisManager::kProofAnalysis && cont->IsSpecialOutput()
1828       && !ignoreProof)
1829     f = mgr->OpenProofFile(cont,option);
1830   else {
1831     // Check first if the file is already opened
1832     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1833     if (f) {
1834       // Check if option "UPDATE" was preserved 
1835       TString opt(option);
1836       opt.ToUpper();
1837       if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1838         ::Info("AliAnalysisManager::OpenFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1839     } else {
1840       f = TFile::Open(filename, option);
1841     }    
1842   }   
1843   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1844     cont->SetFile(f);
1845     // Cd to file
1846     f->cd();
1847     // Check for a folder request
1848     TString dir = cont->GetFolderName(); 
1849     if (!dir.IsNull()) {
1850       if (!f->GetDirectory(dir)) f->mkdir(dir);
1851       f->cd(dir);
1852     }
1853     return f;
1854   }
1855   ::Fatal("AliAnalysisManager::OpenFile", "File %s could not be opened", filename.Data());
1856   cont->SetFile(NULL);
1857   return NULL;
1858 }    
1859  
1860 //______________________________________________________________________________
1861 TFile *AliAnalysisManager::OpenProofFile(AliAnalysisDataContainer *cont, const char *option, const char *extaod)
1862 {
1863 // Opens a special output file used in PROOF.
1864   TString line;
1865   TString filename = cont->GetFileName();
1866   if (cont == fCommonOutput) {
1867      if (fOutputEventHandler) {
1868         if (strlen(extaod)) filename = extaod;
1869         filename = fOutputEventHandler->GetOutputFileName();
1870      }   
1871      else Fatal("OpenProofFile","No output container. Exiting.");
1872   }   
1873   TFile *f = NULL;
1874   if (fMode!=kProofAnalysis || !fSelector) {
1875     Fatal("OpenProofFile","Cannot open PROOF file %s: no PROOF or selector",filename.Data());
1876     return NULL;
1877   } 
1878   if (fSpecialOutputLocation.Length()) {
1879     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1880     if (f) {
1881       // Check if option "UPDATE" was preserved 
1882       TString opt(option);
1883       opt.ToUpper();
1884       if ((opt=="UPDATE") && (opt!=f->GetOption()))
1885         ::Info("OpenProofFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1886     } else {
1887       f = new TFile(filename, option);
1888     }
1889     if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1890       cont->SetFile(f);
1891       // Cd to file
1892       f->cd();
1893       // Check for a folder request
1894       TString dir = cont->GetFolderName(); 
1895       if (dir.Length()) {
1896         if (!f->GetDirectory(dir)) f->mkdir(dir);
1897         f->cd(dir);
1898       }      
1899       return f;
1900     }
1901     Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1902     cont->SetFile(NULL);
1903     return NULL;       
1904   }
1905   // Check if there is already a proof output file in the output list
1906   TObject *pof = fSelector->GetOutputList()->FindObject(filename);
1907   if (pof) {
1908     // Get the actual file
1909     line = Form("((TProofOutputFile*)%p)->GetFileName();", pof);
1910     filename = (const char*)gROOT->ProcessLine(line);
1911     if (fDebug>1) {
1912       printf("File: %s already booked via TProofOutputFile\n", filename.Data());
1913     }  
1914     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1915     if (!f) {
1916        Fatal("OpenProofFile", "Proof output file found but no file opened for %s", filename.Data());
1917        return NULL;
1918     }   
1919     // Check if option "UPDATE" was preserved 
1920     TString opt(option);
1921     opt.ToUpper();
1922     if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1923       Fatal("OpenProofFile", "File %s already opened, but not in UPDATE mode!", cont->GetFileName());
1924   } else {
1925     if (cont->IsRegisterDataset()) {
1926       TString dsetName = filename;
1927       dsetName.ReplaceAll(".root", cont->GetTitle());
1928       dsetName.ReplaceAll(":","_");
1929       if (fDebug>1) printf("Booking dataset: %s\n", dsetName.Data());
1930       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\", \"DROV\", \"%s\");", filename.Data(), dsetName.Data());
1931     } else {
1932       if (fDebug>1) printf("Booking TProofOutputFile: %s to be merged\n", filename.Data());
1933       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\");", filename.Data());
1934     }
1935     if (fDebug > 1) printf("=== %s\n", line.Data());
1936     gROOT->ProcessLine(line);
1937     line = Form("pf->OpenFile(\"%s\");", option);
1938     gROOT->ProcessLine(line);
1939     f = gFile;
1940     if (fDebug > 1) {
1941       gROOT->ProcessLine("pf->Print()");
1942       printf(" == proof file name: %s", f->GetName());
1943     }   
1944     // Add to proof output list
1945     line = Form("((TList*)%p)->Add(pf);",fSelector->GetOutputList());
1946     if (fDebug > 1) printf("=== %s\n", line.Data());
1947     gROOT->ProcessLine(line);
1948   }
1949   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1950     cont->SetFile(f);
1951     // Cd to file
1952     f->cd();
1953     // Check for a folder request
1954     TString dir = cont->GetFolderName(); 
1955     if (!dir.IsNull()) {
1956       if (!f->GetDirectory(dir)) f->mkdir(dir);
1957       f->cd(dir);
1958     }
1959     return f;
1960   }
1961   Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1962   cont->SetFile(NULL);  
1963   return NULL;
1964 }   
1965
1966 //______________________________________________________________________________
1967 void AliAnalysisManager::ExecAnalysis(Option_t *option)
1968 {
1969 // Execute analysis.
1970    static Long64_t nentries = 0;
1971    static TTree *lastTree = 0;
1972    static TStopwatch *timer = new TStopwatch();
1973    // Only the first call to Process will trigger a true Notify. Other Notify
1974    // coming before is ignored.
1975    if (!TObject::TestBit(AliAnalysisManager::kTrueNotify)) {
1976       TObject::SetBit(AliAnalysisManager::kTrueNotify);
1977       Notify();
1978    }   
1979    if (fDebug > 0) printf("MGR: Processing event #%d\n", fNcalls);
1980    else {
1981       if (fTree && (fTree != lastTree)) {
1982          nentries += fTree->GetEntries();
1983          lastTree = fTree;
1984       }   
1985       if (!fNcalls) timer->Start();
1986       if (!fIsRemote && TObject::TestBit(kUseProgressBar)) ProgressBar("Processing event", fNcalls, TMath::Min(fMaxEntries,nentries), timer, kFALSE);
1987    }
1988    gROOT->cd();
1989    TDirectory *cdir = gDirectory;
1990    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1991    if (getsysInfo && ((fNcalls%fNSysInfo)==0)) AliSysInfo::AddStamp("Exec_start", (Int_t)fNcalls);
1992    if (!fInitOK) {
1993       Error("ExecAnalysis", "Analysis manager was not initialized !");
1994       cdir->cd();
1995       return;
1996    }
1997    fNcalls++;
1998    AliAnalysisTask *task;
1999    // Check if the top tree is active.
2000    if (fTree) {
2001       if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
2002          AliSysInfo::AddStamp("Handlers_BeginEventGroup",fNcalls, 1002, 0);
2003       TIter next(fTasks);
2004    // De-activate all tasks
2005       while ((task=(AliAnalysisTask*)next())) task->SetActive(kFALSE);
2006       AliAnalysisDataContainer *cont = fCommonInput;
2007       if (!cont) cont = (AliAnalysisDataContainer*)fInputs->At(0);
2008       if (!cont) {
2009               Error("ExecAnalysis","Cannot execute analysis in TSelector mode without at least one top container");
2010          cdir->cd();
2011          return;
2012       }   
2013       cont->SetData(fTree); // This will notify all consumers
2014       Long64_t entry = fTree->GetTree()->GetReadEntry();      
2015 //
2016 //    Call BeginEvent() for optional input/output and MC services 
2017       if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(entry);
2018       if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(entry);
2019       if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(entry);
2020       gROOT->cd();
2021       if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
2022          AliSysInfo::AddStamp("Handlers_BeginEvent",fNcalls, 1000, 0);
2023 //
2024 //    Execute the tasks
2025 //      TIter next1(cont->GetConsumers());
2026       TIter next1(fTopTasks);
2027       Int_t itask = 0;
2028       while ((task=(AliAnalysisTask*)next1())) {
2029          if (fDebug >1) {
2030             cout << "    Executing task " << task->GetName() << endl;
2031          }       
2032          task->ExecuteTask(option);
2033          gROOT->cd();
2034          if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
2035             AliSysInfo::AddStamp(task->ClassName(), fNcalls, itask, 1);
2036          itask++;   
2037       }
2038 //
2039 //    Call FinishEvent() for optional output and MC services 
2040       if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
2041       if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
2042       if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
2043       // Gather system information if requested
2044       if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
2045          AliSysInfo::AddStamp("Handlers_FinishEvent",fNcalls, 1001, 1);
2046       cdir->cd();   
2047       return;
2048    }   
2049    // The event loop is not controlled by TSelector   
2050 //
2051 //  Call BeginEvent() for optional input/output and MC services 
2052    if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(-1);
2053    if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(-1);
2054    if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(-1);
2055    gROOT->cd();
2056    if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
2057       AliSysInfo::AddStamp("Handlers_BeginEvent",fNcalls, 1000, 0);
2058    TIter next2(fTopTasks);
2059    while ((task=(AliAnalysisTask*)next2())) {
2060       task->SetActive(kTRUE);
2061       if (fDebug > 1) {
2062          cout << "    Executing task " << task->GetName() << endl;
2063       }   
2064       task->ExecuteTask(option);
2065       gROOT->cd();
2066    }   
2067 //
2068 // Call FinishEvent() for optional output and MC services 
2069    if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
2070    if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
2071    if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
2072    if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
2073       AliSysInfo::AddStamp("Handlers_FinishEvent",fNcalls, 1000, 1);
2074    cdir->cd();   
2075 }
2076
2077 //______________________________________________________________________________
2078 Bool_t AliAnalysisManager::IsPipe(std::ostream &out)
2079 {
2080 // Check if the stdout is connected to a pipe (C.Holm)
2081   Bool_t ispipe = kFALSE;
2082   out.seekp(0, std::ios_base::cur);
2083   if (out.fail()) {
2084     out.clear();
2085     if (errno == ESPIPE) ispipe = kTRUE;
2086   }
2087   return ispipe;
2088 }
2089    
2090 //______________________________________________________________________________
2091 void AliAnalysisManager::SetInputEventHandler(AliVEventHandler* const handler)
2092 {
2093 // Set the input event handler and create a container for it.
2094    fInputEventHandler   = handler;
2095    fCommonInput = CreateContainer("cAUTO_INPUT", TChain::Class(), AliAnalysisManager::kInputContainer);
2096 }
2097
2098 //______________________________________________________________________________
2099 void AliAnalysisManager::SetOutputEventHandler(AliVEventHandler* const handler)
2100 {
2101 // Set the input event handler and create a container for it.
2102    fOutputEventHandler   = handler;
2103    fCommonOutput = CreateContainer("cAUTO_OUTPUT", TTree::Class(), AliAnalysisManager::kOutputContainer, "default");
2104    fCommonOutput->SetSpecialOutput();
2105 }
2106
2107 //______________________________________________________________________________
2108 void AliAnalysisManager::SetDebugLevel(UInt_t level)
2109 {
2110 // Set verbosity of the analysis manager. If the progress bar is used, the call is ignored
2111    if (TObject::TestBit(kUseProgressBar)) {
2112       Info("SetDebugLevel","Ignored. Disable the progress bar first.");
2113       return;
2114    }
2115    fDebug = level;
2116 }
2117    
2118 //______________________________________________________________________________
2119 void AliAnalysisManager::SetUseProgressBar(Bool_t flag, Int_t freq)
2120 {
2121 // Enable a text mode progress bar. Resets debug level to 0.
2122    Info("SetUseProgressBar", "Progress bar enabled, updated every %d events.\n  ### NOTE: Debug level reset to 0 ###", freq);
2123    TObject::SetBit(kUseProgressBar,flag);
2124    fPBUpdateFreq = freq;
2125    fDebug = 0;
2126 }   
2127
2128 //______________________________________________________________________________
2129 void AliAnalysisManager::RegisterExtraFile(const char *fname)
2130 {
2131 // This method is used externally to register output files which are not
2132 // connected to any output container, so that the manager can properly register,
2133 // retrieve or merge them when running in distributed mode. The file names are
2134 // separated by blancs. The method has to be called in MyAnalysisTask::LocalInit().
2135    if (fExtraFiles.Contains(fname)) return;
2136    if (fExtraFiles.Length()) fExtraFiles += " ";
2137    fExtraFiles += fname;
2138 }
2139
2140 //______________________________________________________________________________
2141 Bool_t AliAnalysisManager::GetFileFromWrapper(const char *filename, const TList *source)
2142 {
2143 // Copy a file from the location specified ina the wrapper with the same name from the source list.
2144    char fullPath[512];
2145    char chUrl[512];
2146    char tmp[1024];
2147    TObject *pof =  source->FindObject(filename);
2148    if (!pof || !pof->InheritsFrom("TProofOutputFile")) {
2149       Error("GetFileFromWrapper", "TProofOutputFile object not found in output list for file %s", filename);
2150       return kFALSE;
2151    }
2152    gROOT->ProcessLine(Form("sprintf((char*)%p, \"%%s\", ((TProofOutputFile*)%p)->GetOutputFileName());", fullPath, pof));
2153    gROOT->ProcessLine(Form("sprintf((char*)%p, \"%%s\", gProof->GetUrl());",chUrl));
2154    TString clientUrl(chUrl);
2155    TString fullPath_str(fullPath);
2156    if (clientUrl.Contains("localhost")){
2157       TObjArray* array = fullPath_str.Tokenize ( "//" );
2158       TObjString *strobj = ( TObjString *)array->At(1);
2159       TObjArray* arrayPort = strobj->GetString().Tokenize ( ":" );
2160       TObjString *strobjPort = ( TObjString *) arrayPort->At(1);
2161       fullPath_str.ReplaceAll(strobj->GetString().Data(),"localhost:PORT");
2162       fullPath_str.ReplaceAll(":PORT",Form(":%s",strobjPort->GetString().Data()));
2163       if (fDebug > 1) Info("GetFileFromWrapper","Using tunnel from %s to %s",fullPath_str.Data(),filename);
2164       delete arrayPort;
2165       delete array;
2166    }
2167    else if (clientUrl.Contains("__lite__")) { 
2168      // Special case for ProofLite environement - get file info and copy. 
2169      gROOT->ProcessLine(Form("sprintf((char*)%p,\"%%s\",((TProofOutputFile*)%p)->GetDir());", tmp, pof));
2170      fullPath_str = Form("%s/%s", tmp, fullPath);
2171    }
2172    if (fDebug > 1) 
2173      Info("GetFileFromWrapper","Copying file %s from PROOF scratch space to %s", fullPath_str.Data(),filename);
2174    Bool_t gotit = TFile::Cp(fullPath_str.Data(), filename); 
2175    if (!gotit)
2176       Error("GetFileFromWrapper", "Could not get file %s from proof scratch space", filename);
2177    return gotit;
2178 }
2179
2180 //______________________________________________________________________________
2181 void AliAnalysisManager::GetAnalysisTypeString(TString &type) const
2182 {
2183 // Fill analysis type in the provided string.
2184    switch (fMode) {
2185       case kLocalAnalysis:
2186          type = "local";
2187          return;
2188       case kProofAnalysis:
2189          type = "proof";
2190          return;
2191       case kGridAnalysis:
2192          type = "grid";
2193          return;
2194       case kMixingAnalysis:
2195          type = "mix";
2196    }
2197 }
2198
2199 //______________________________________________________________________________
2200 Bool_t AliAnalysisManager::ValidateOutputFiles() const
2201 {
2202 // Validate all output files.
2203    TIter next(fOutputs);
2204    AliAnalysisDataContainer *output;
2205    TDirectory *cdir = gDirectory;
2206    TString openedFiles;
2207    while ((output=(AliAnalysisDataContainer*)next())) {
2208       if (output->IsRegisterDataset()) continue;
2209       TString filename = output->GetFileName();
2210       if (filename == "default") {
2211          if (!fOutputEventHandler) continue;
2212          filename = fOutputEventHandler->GetOutputFileName();
2213          // Main AOD may not be there
2214          if (gSystem->AccessPathName(filename)) continue;
2215       }
2216       // Check if the file is closed
2217       if (openedFiles.Contains(filename)) continue;;
2218       TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
2219       if (file) {
2220          Warning("ValidateOutputs", "File %s was not closed. Closing.", filename.Data());
2221          // Clear file list to release object ownership to user.
2222 //         file->Clear();
2223          file->Close();
2224       }
2225       file = TFile::Open(filename);
2226       if (!file || file->IsZombie() || file->TestBit(TFile::kRecovered)) {
2227          Error("ValidateOutputs", "Output file <%s> was not created or invalid", filename.Data());
2228          cdir->cd();
2229          return kFALSE;
2230       }
2231       file->Close();
2232       openedFiles += filename;
2233       openedFiles += " ";
2234    }
2235    cdir->cd();
2236    return kTRUE;
2237 }   
2238
2239 //______________________________________________________________________________
2240 void AliAnalysisManager::ProgressBar(const char *opname, Long64_t current, Long64_t size, TStopwatch * const watch, Bool_t last, Bool_t refresh)
2241 {
2242 // Implements a nice text mode progress bar.
2243    static Long64_t icount = 0;
2244    static TString oname;
2245    static TString nname;
2246    static Long64_t ocurrent = 0;
2247    static Long64_t osize = 0;
2248    static Int_t oseconds = 0;
2249    static TStopwatch *owatch = 0;
2250    static Bool_t oneoftwo = kFALSE;
2251    static Int_t nrefresh = 0;
2252    static Int_t nchecks = 0;
2253    static char lastChar = 0;
2254    const char symbol[4] = {'-','\\','|','/'}; 
2255    
2256    if (!lastChar) lastChar = (IsPipe(std::cerr))?'\r':'\n';
2257    if (!refresh) {
2258       nrefresh = 0;
2259       if (!size) return;
2260       owatch = watch;
2261       oname = opname;
2262       ocurrent = TMath::Abs(current);
2263       osize = TMath::Abs(size);
2264       if (ocurrent > osize) ocurrent=osize;
2265    } else {
2266       nrefresh++;
2267       if (!osize) return;
2268    }     
2269    if ((current % fPBUpdateFreq) != 0) return;
2270    icount++;
2271    char progress[11] = "          ";
2272    Int_t ichar = icount%4;
2273    Double_t time = 0.;
2274    Int_t hours = 0;
2275    Int_t minutes = 0;
2276    Int_t seconds = 0;
2277    if (owatch && !last) {
2278       owatch->Stop();
2279       time = owatch->RealTime();
2280       seconds   = int(time) % 60;
2281       minutes   = (int(time) / 60) % 60;
2282       hours     = (int(time) / 60 / 60);
2283       if (refresh)  {
2284          if (oseconds==seconds) {
2285             owatch->Continue();
2286             return;
2287          }
2288          oneoftwo = !oneoftwo;   
2289       }
2290       oseconds = seconds;   
2291    }
2292    if (refresh && oneoftwo) {
2293       nname = oname;
2294       if (nchecks <= 0) nchecks = nrefresh+1;
2295       Int_t pctdone = (Int_t)(100.*nrefresh/nchecks);
2296       oname = Form("     == %d%% ==", pctdone);
2297    }         
2298    Double_t percent = 100.0*ocurrent/osize;
2299    Int_t nchar = Int_t(percent/10);
2300    if (nchar>10) nchar=10;
2301    Int_t i;
2302    for (i=0; i<nchar; i++)  progress[i] = '=';
2303    progress[nchar] = symbol[ichar];
2304    for (i=nchar+1; i<10; i++) progress[i] = ' ';
2305    progress[10] = '\0';
2306    oname += "                    ";
2307    oname.Remove(20);
2308    if(size<10000) fprintf(stderr, "%s [%10s] %4lld ", oname.Data(), progress, ocurrent);
2309    else if(size<100000) fprintf(stderr, "%s [%10s] %5lld ",oname.Data(), progress, ocurrent);
2310    else fprintf(stderr, "%s [%10s] %7lld ",oname.Data(), progress, ocurrent);
2311    if (time>0.) {
2312      Int_t full   = Int_t(ocurrent > 0 ? 
2313                           time * (float(osize)/ocurrent) + .5 : 
2314                           99*3600+59*60+59); 
2315      Int_t remain = Int_t(full - time);
2316      Int_t rsec   = remain % 60;
2317      Int_t rmin   = (remain / 60) % 60;
2318      Int_t rhour  = (remain / 60 / 60);
2319      fprintf(stderr, "[%6.2f %%]   TIME %.2d:%.2d:%.2d  ETA %.2d:%.2d:%.2d%c",
2320              percent, hours, minutes, seconds, rhour, rmin, rsec, lastChar);
2321    }
2322    else fprintf(stderr, "[%6.2f %%]%c", percent, lastChar);
2323    if (refresh && oneoftwo) oname = nname;
2324    if (owatch) owatch->Continue();
2325    if (last) {
2326       icount = 0;
2327       owatch = 0;
2328       ocurrent = 0;
2329       osize = 0;
2330       oseconds = 0;
2331       oneoftwo = kFALSE;
2332       nrefresh = 0;
2333       fprintf(stderr, "\n");
2334    }   
2335 }
2336
2337 //______________________________________________________________________________
2338 void AliAnalysisManager::DoLoadBranch(const char *name) 
2339 {
2340   // Get tree and load branch if needed.
2341   static Long64_t crtEntry = -100;
2342
2343   if (fAutoBranchHandling || !fTree)
2344     return;
2345
2346   TBranch *br = dynamic_cast<TBranch*>(fTable.FindObject(name));
2347   if (!br) {
2348     br = fTree->GetBranch(name);
2349     if (!br) {
2350       Error("DoLoadBranch", "Could not find branch %s",name);
2351       return;
2352     }
2353     fTable.Add(br);
2354   }
2355   if (br->GetReadEntry()==fCurrentEntry) return;
2356   Int_t ret = br->GetEntry(GetCurrentEntry());
2357   if (ret<0) {
2358     Error("DoLoadBranch", "Could not load entry %lld from branch %s",GetCurrentEntry(), name);
2359     if (crtEntry != fCurrentEntry) {
2360       CountEvent(1,0,1,0);
2361       crtEntry = fCurrentEntry;
2362     }  
2363   } else {
2364     if (crtEntry != fCurrentEntry) {
2365       CountEvent(1,1,0,0);
2366       crtEntry = fCurrentEntry;
2367     }
2368   }
2369 }
2370
2371 //______________________________________________________________________________
2372 void AliAnalysisManager::AddStatisticsTask(UInt_t offlineMask)
2373 {
2374 // Add the statistics task to the manager.
2375   if (fStatistics) {
2376      Info("AddStatisticsTask", "Already added");
2377      return;
2378   }
2379   TString line = Form("AliAnalysisTaskStat::AddToManager(%u);", offlineMask);
2380   gROOT->ProcessLine(line);
2381 }  
2382
2383 //______________________________________________________________________________
2384 void AliAnalysisManager::CountEvent(Int_t ninput, Int_t nprocessed, Int_t nfailed, Int_t naccepted)
2385 {
2386 // Bookkeep current event;
2387    if (!fStatistics) return;
2388    fStatistics->AddInput(ninput);
2389    fStatistics->AddProcessed(nprocessed);
2390    fStatistics->AddFailed(nfailed);
2391    fStatistics->AddAccepted(naccepted);
2392 }   
2393
2394 //______________________________________________________________________________
2395 void AliAnalysisManager::AddStatisticsMsg(const char *line)
2396 {
2397 // Add a line in the statistics message. If available, the statistics message is written
2398 // at the end of the SlaveTerminate phase on workers AND at the end of Terminate
2399 // on the client.
2400    if (!strlen(line)) return;
2401    if (!fStatisticsMsg.IsNull()) fStatisticsMsg += "\n";
2402    fStatisticsMsg += line;
2403 }
2404
2405 //______________________________________________________________________________
2406 void AliAnalysisManager::WriteStatisticsMsg(Int_t)
2407 {
2408 // If fStatistics is present, write the file in the format ninput_nprocessed_nfailed_naccepted.stat
2409    static Bool_t done = kFALSE;
2410    if (done) return;
2411    done = kTRUE;
2412    if (!fStatistics) return;
2413    ofstream out;
2414    AddStatisticsMsg(Form("Number of input events:        %lld",fStatistics->GetNinput()));
2415    AddStatisticsMsg(Form("Number of processed events:    %lld",fStatistics->GetNprocessed()));      
2416    AddStatisticsMsg(Form("Number of failed events (I/O): %lld",fStatistics->GetNfailed()));
2417    AddStatisticsMsg(Form("Number of accepted events for mask %s: %lld", AliAnalysisStatistics::GetMaskAsString(fStatistics->GetOfflineMask()), fStatistics->GetNaccepted()));
2418    out.open(Form("%lld_%lld_%lld_%lld.stat",fStatistics->GetNinput(),
2419                  fStatistics->GetNprocessed(),fStatistics->GetNfailed(),
2420                  fStatistics->GetNaccepted()), ios::out);      
2421    out << fStatisticsMsg << endl;
2422    out.close();
2423 }
2424
2425 //______________________________________________________________________________
2426 const char* AliAnalysisManager::GetOADBPath()
2427 {
2428 // returns the path of the OADB
2429 // this static function just depends on environment variables
2430
2431    static TString oadbPath;
2432
2433    if (gSystem->Getenv("OADB_PATH"))
2434       oadbPath = gSystem->Getenv("OADB_PATH");
2435    else if (gSystem->Getenv("ALICE_ROOT"))
2436       oadbPath.Form("%s/OADB", gSystem->Getenv("ALICE_ROOT"));
2437    else
2438       ::Fatal("AliAnalysisManager::GetOADBPath", "Cannot figure out AODB path. Define ALICE_ROOT or OADB_PATH!");
2439       
2440    return oadbPath;
2441 }