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