The merging jobs run also the Terminate method of the tasks after merging.
[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 //   AliAnalysysManager - 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 <Riostream.h>
29
30 #include <TError.h>
31 #include <TClass.h>
32 #include <TFile.h>
33 //#include <TKey.h>
34 #include <TMath.h>
35 #include <TH1.h>
36 #include <TMethodCall.h>
37 #include <TChain.h>
38 #include <TSystem.h>
39 #include <TROOT.h>
40 #include <TCanvas.h>
41 #include <TStopwatch.h>
42
43 #include "AliAnalysisSelector.h"
44 #include "AliAnalysisGrid.h"
45 #include "AliAnalysisTask.h"
46 #include "AliAnalysisDataContainer.h"
47 #include "AliAnalysisDataSlot.h"
48 #include "AliVEventHandler.h"
49 #include "AliVEventPool.h"
50 #include "AliSysInfo.h"
51 #include "AliAnalysisManager.h"
52
53 ClassImp(AliAnalysisManager)
54
55 AliAnalysisManager *AliAnalysisManager::fgAnalysisManager = NULL;
56 TString AliAnalysisManager::fgCommonFileName = "";
57
58 //______________________________________________________________________________
59 AliAnalysisManager::AliAnalysisManager(const char *name, const char *title)
60                    :TNamed(name,title),
61                     fTree(NULL),
62                     fInputEventHandler(NULL),
63                     fOutputEventHandler(NULL),
64                     fMCtruthEventHandler(NULL),
65                     fEventPool(NULL),
66                     fCurrentEntry(-1),
67                     fNSysInfo(0),
68                     fMode(kLocalAnalysis),
69                     fInitOK(kFALSE),
70                     fDebug(0),
71                     fSpecialOutputLocation(""), 
72                     fTasks(NULL),
73                     fTopTasks(NULL),
74                     fZombies(NULL),
75                     fContainers(NULL),
76                     fInputs(NULL),
77                     fOutputs(NULL),
78                     fParamCont(NULL),
79                     fCommonInput(NULL),
80                     fCommonOutput(NULL),
81                     fSelector(NULL),
82                     fGridHandler(NULL),
83                     fExtraFiles("")
84 {
85 // Default constructor.
86    fgAnalysisManager = this;
87    fgCommonFileName  = "AnalysisResults.root";
88    fTasks      = new TObjArray();
89    fTopTasks   = new TObjArray();
90    fZombies    = new TObjArray();
91    fContainers = new TObjArray();
92    fInputs     = new TObjArray();
93    fOutputs    = new TObjArray();
94    fParamCont  = new TObjArray();
95    SetEventLoop(kTRUE);
96    TObject::SetObjectStat(kFALSE);
97 }
98
99 //______________________________________________________________________________
100 AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other)
101                    :TNamed(other),
102                     fTree(NULL),
103                     fInputEventHandler(NULL),
104                     fOutputEventHandler(NULL),
105                     fMCtruthEventHandler(NULL),
106                     fEventPool(NULL),
107                     fCurrentEntry(-1),
108                     fNSysInfo(0),
109                     fMode(other.fMode),
110                     fInitOK(other.fInitOK),
111                     fDebug(other.fDebug),
112                     fSpecialOutputLocation(""), 
113                     fTasks(NULL),
114                     fTopTasks(NULL),
115                     fZombies(NULL),
116                     fContainers(NULL),
117                     fInputs(NULL),
118                     fOutputs(NULL),
119                     fParamCont(NULL),
120                     fCommonInput(NULL),
121                     fCommonOutput(NULL),
122                     fSelector(NULL),
123                     fGridHandler(NULL),
124                     fExtraFiles()
125 {
126 // Copy constructor.
127    fTasks      = new TObjArray(*other.fTasks);
128    fTopTasks   = new TObjArray(*other.fTopTasks);
129    fZombies    = new TObjArray(*other.fZombies);
130    fContainers = new TObjArray(*other.fContainers);
131    fInputs     = new TObjArray(*other.fInputs);
132    fOutputs    = new TObjArray(*other.fOutputs);
133    fParamCont  = new TObjArray(*other.fParamCont);
134    fgCommonFileName  = "AnalysisResults.root";
135    fgAnalysisManager = this;
136    TObject::SetObjectStat(kFALSE);
137 }
138    
139 //______________________________________________________________________________
140 AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other)
141 {
142 // Assignment
143    if (&other != this) {
144       TNamed::operator=(other);
145       fInputEventHandler   = other.fInputEventHandler;
146       fOutputEventHandler  = other.fOutputEventHandler;
147       fMCtruthEventHandler = other.fMCtruthEventHandler;
148       fEventPool           = other.fEventPool;
149       fTree       = NULL;
150       fCurrentEntry = -1;
151       fNSysInfo   = other.fNSysInfo;
152       fMode       = other.fMode;
153       fInitOK     = other.fInitOK;
154       fDebug      = other.fDebug;
155       fTasks      = new TObjArray(*other.fTasks);
156       fTopTasks   = new TObjArray(*other.fTopTasks);
157       fZombies    = new TObjArray(*other.fZombies);
158       fContainers = new TObjArray(*other.fContainers);
159       fInputs     = new TObjArray(*other.fInputs);
160       fOutputs    = new TObjArray(*other.fOutputs);
161       fParamCont  = new TObjArray(*other.fParamCont);
162       fCommonInput = NULL;
163       fCommonOutput = NULL;
164       fSelector   = NULL;
165       fGridHandler = NULL;
166       fExtraFiles = other.fExtraFiles;
167       fgCommonFileName = "AnalysisResults.root";
168       fgAnalysisManager = this;
169    }
170    return *this;
171 }
172
173 //______________________________________________________________________________
174 AliAnalysisManager::~AliAnalysisManager()
175 {
176 // Destructor.
177    if (fTasks) {fTasks->Delete(); delete fTasks;}
178    if (fTopTasks) delete fTopTasks;
179    if (fZombies) delete fZombies;
180    if (fContainers) {fContainers->Delete(); delete fContainers;}
181    if (fInputs) delete fInputs;
182    if (fOutputs) delete fOutputs;
183    if (fParamCont) delete fParamCont;
184    if (fGridHandler) delete fGridHandler;
185    if (fgAnalysisManager==this) fgAnalysisManager = NULL;
186    TObject::SetObjectStat(kTRUE);
187 }
188
189 //______________________________________________________________________________
190 Int_t AliAnalysisManager::GetEntry(Long64_t entry, Int_t getall)
191 {
192 // Read one entry of the tree or a whole branch.
193    fCurrentEntry = entry;
194    return fTree ? fTree->GetTree()->GetEntry(entry, getall) : 0;
195 }
196    
197 //______________________________________________________________________________
198 Bool_t AliAnalysisManager::Init(TTree *tree)
199 {
200   // The Init() function is called when the selector needs to initialize
201   // a new tree or chain. Typically here the branch addresses of the tree
202   // will be set. It is normaly not necessary to make changes to the
203   // generated code, but the routine can be extended by the user if needed.
204   // Init() will be called many times when running with PROOF.
205    Bool_t init = kFALSE;
206    if (!tree) return kFALSE; // Should not happen - protected in selector caller
207    if (fDebug > 0) {
208       printf("->AliAnalysisManager::Init(%s)\n", tree->GetName());
209    }
210    // Call InitTree of EventHandler
211    if (fOutputEventHandler) {
212       if (fMode == kProofAnalysis) {
213          init = fOutputEventHandler->Init(0x0, "proof");
214       } else {
215          init = fOutputEventHandler->Init(0x0, "local");
216       }
217       if (!init) {
218          Error("Init", "Output event handler failed to initialize");
219          return kFALSE;
220       }         
221    }
222    
223    if (fInputEventHandler) {
224       if (fMode == kProofAnalysis) {
225          init = fInputEventHandler->Init(tree, "proof");
226       } else {
227          init = fInputEventHandler->Init(tree, "local");
228       }
229       if (!init) {
230          Error("Init", "Input event handler failed to initialize tree"); 
231          return kFALSE;
232       }         
233    } else {
234       // If no input event handler we need to get the tree once
235       // for the chain
236       if(!tree->GetTree()) {
237          Long64_t readEntry = tree->LoadTree(0);
238          if (readEntry == -2) {
239             Error("Init", "Input tree has no entry. Exiting");
240             return kFALSE;
241          }
242       }   
243    }
244
245    if (fMCtruthEventHandler) {
246       if (fMode == kProofAnalysis) {
247          init = fMCtruthEventHandler->Init(0x0, "proof");
248       } else {
249          init = fMCtruthEventHandler->Init(0x0, "local");
250       }
251       if (!init) {
252          Error("Init", "MC event handler failed to initialize"); 
253          return kFALSE;
254       }         
255    }
256
257    if (!fInitOK) InitAnalysis();
258    if (!fInitOK) return kFALSE;
259    fTree = tree;
260    AliAnalysisDataContainer *top = fCommonInput;
261    if (!top) top = (AliAnalysisDataContainer*)fInputs->At(0);
262    if (!top) {
263       Error("Init","No top input container !");
264       return kFALSE;
265    }
266    top->SetData(tree);
267    if (fDebug > 0) {
268       printf("<-AliAnalysisManager::Init(%s)\n", tree->GetName());
269    }
270    return kTRUE;
271 }
272
273 //______________________________________________________________________________
274 void AliAnalysisManager::SlaveBegin(TTree *tree)
275 {
276   // The SlaveBegin() function is called after the Begin() function.
277   // When running with PROOF SlaveBegin() is called on each slave server.
278   // The tree argument is deprecated (on PROOF 0 is passed).
279    if (fDebug > 0) printf("->AliAnalysisManager::SlaveBegin()\n");
280    static Bool_t isCalled = kFALSE;
281    Bool_t init = kFALSE;
282    Bool_t initOK = kTRUE;
283    TString msg;
284    TDirectory *curdir = gDirectory;
285    // Call SlaveBegin only once in case of mixing
286    if (isCalled && fMode==kMixingAnalysis) return;
287    // Call Init of EventHandler
288    if (fOutputEventHandler) {
289       if (fMode == kProofAnalysis) {
290          // Merging AOD's in PROOF via TProofOutputFile
291          if (fDebug > 1) printf("   Initializing AOD output file %s...\n", fOutputEventHandler->GetOutputFileName());
292          init = fOutputEventHandler->Init("proof");
293          if (!init) msg = "Failed to initialize output handler on worker";
294       } else {
295          init = fOutputEventHandler->Init("local");
296          if (!init) msg = "Failed to initialize output handler";
297       }
298       initOK &= init;
299       if (!fSelector) Error("SlaveBegin", "Selector not set");
300       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
301    }
302
303    if (fInputEventHandler) {
304       fInputEventHandler->SetInputTree(tree);
305       if (fMode == kProofAnalysis) {
306          init = fInputEventHandler->Init("proof");
307          if (!init) msg = "Failed to initialize input handler on worker";
308       } else {
309          init = fInputEventHandler->Init("local");
310          if (!init) msg = "Failed to initialize input handler";
311       }
312       initOK &= init;
313       if (!fSelector) Error("SlaveBegin", "Selector not set");      
314       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
315    }
316
317    if (fMCtruthEventHandler) {
318       if (fMode == kProofAnalysis) {
319          init = fMCtruthEventHandler->Init("proof");
320          if (!init) msg = "Failed to initialize MC handler on worker";
321       } else {
322          init = fMCtruthEventHandler->Init("local");
323          if (!init) msg = "Failed to initialize MC handler";
324       }
325       initOK &= init;
326       if (!fSelector) Error("SlaveBegin", "Selector not set");      
327       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
328    }
329    if (curdir) curdir->cd();
330    isCalled = kTRUE;
331    if (!initOK) return;   
332    TIter next(fTasks);
333    AliAnalysisTask *task;
334    // Call CreateOutputObjects for all tasks
335    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
336    Int_t itask = 0;
337    while ((task=(AliAnalysisTask*)next())) {
338       curdir = gDirectory;
339       task->CreateOutputObjects();
340       if (getsysInfo) AliSysInfo::AddStamp(Form("%s_CREATEOUTOBJ",task->ClassName()), 0, itask, 0);
341       itask++;
342       if (curdir) curdir->cd();
343    }
344    if (fDebug > 0) printf("<-AliAnalysisManager::SlaveBegin()\n");
345 }
346
347 //______________________________________________________________________________
348 Bool_t AliAnalysisManager::Notify()
349 {
350    // The Notify() function is called when a new file is opened. This
351    // can be either for a new TTree in a TChain or when when a new TTree
352    // is started when using PROOF. It is normaly not necessary to make changes
353    // to the generated code, but the routine can be extended by the
354    // user if needed. The return value is currently not used.
355    if (!fTree) return kFALSE;
356
357    TFile *curfile = fTree->GetCurrentFile();
358    if (!curfile) {
359       Error("Notify","No current file");
360       return kFALSE;
361    }   
362    
363    if (fDebug > 0) printf("->AliAnalysisManager::Notify() file: %s\n", curfile->GetName());
364    TIter next(fTasks);
365    AliAnalysisTask *task;
366    // Call Notify for all tasks
367    while ((task=(AliAnalysisTask*)next())) 
368       task->Notify();
369         
370    // Call Notify of the event handlers
371    if (fInputEventHandler) {
372        fInputEventHandler->Notify(curfile->GetName());
373    }
374
375    if (fOutputEventHandler) {
376        fOutputEventHandler->Notify(curfile->GetName());
377    }
378
379    if (fMCtruthEventHandler) {
380        fMCtruthEventHandler->Notify(curfile->GetName());
381    }
382    if (fDebug > 0) printf("<-AliAnalysisManager::Notify()\n");
383    return kTRUE;
384 }    
385
386 //______________________________________________________________________________
387 Bool_t AliAnalysisManager::Process(Long64_t entry)
388 {
389   // The Process() function is called for each entry in the tree (or possibly
390   // keyed object in the case of PROOF) to be processed. The entry argument
391   // specifies which entry in the currently loaded tree is to be processed.
392   // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()
393   // to read either all or the required parts of the data. When processing
394   // keyed objects with PROOF, the object is already loaded and is available
395   // via the fObject pointer.
396   //
397   // This function should contain the "body" of the analysis. It can contain
398   // simple or elaborate selection criteria, run algorithms on the data
399   // of the event and typically fill histograms.
400
401   // WARNING when a selector is used with a TChain, you must use
402   //  the pointer to the current TTree to call GetEntry(entry).
403   //  The entry is always the local entry number in the current tree.
404   //  Assuming that fChain is the pointer to the TChain being processed,
405   //  use fChain->GetTree()->GetEntry(entry).
406    if (fDebug > 0) printf("->AliAnalysisManager::Process(%lld)\n", entry);
407
408    if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(entry);
409    if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(entry);
410    if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(entry);
411    
412    GetEntry(entry);
413    ExecAnalysis();
414    if (fDebug > 0) printf("<-AliAnalysisManager::Process()\n");
415    return kTRUE;
416 }
417
418 //______________________________________________________________________________
419 void AliAnalysisManager::PackOutput(TList *target)
420 {
421   // Pack all output data containers in the output list. Called at SlaveTerminate
422   // stage in PROOF case for each slave.
423    if (fDebug > 0) printf("->AliAnalysisManager::PackOutput()\n");
424    if (!target) {
425       Error("PackOutput", "No target. Exiting.");
426       return;
427    }
428    if (fInputEventHandler)   fInputEventHandler  ->Terminate();
429    if (fOutputEventHandler)  fOutputEventHandler ->Terminate();
430    if (fMCtruthEventHandler) fMCtruthEventHandler->Terminate();
431
432    // Call FinishTaskOutput() for each event loop task (not called for 
433    // post-event loop tasks - use Terminate() fo those)
434    TIter nexttask(fTasks);
435    AliAnalysisTask *task;
436    while ((task=(AliAnalysisTask*)nexttask())) {
437       if (!task->IsPostEventLoop()) {
438          if (fDebug > 0) printf("->FinishTaskOutput: task %s\n", task->GetName());
439          task->FinishTaskOutput();
440          if (fDebug > 0) printf("<-FinishTaskOutput: task %s\n", task->GetName());
441       }
442    }      
443    
444    if (fMode == kProofAnalysis) {
445       TIter next(fOutputs);
446       AliAnalysisDataContainer *output;
447       Bool_t isManagedByHandler = kFALSE;
448       while ((output=(AliAnalysisDataContainer*)next())) {
449          // Do not consider outputs of post event loop tasks
450          isManagedByHandler = kFALSE;
451          if (output->GetProducer()->IsPostEventLoop()) continue;
452          const char *filename = output->GetFileName();
453          if (!(strcmp(filename, "default")) && fOutputEventHandler) {
454             isManagedByHandler = kTRUE;
455             printf("#### Handler output. Extra: %s\n", fExtraFiles.Data());
456             filename = fOutputEventHandler->GetOutputFileName();
457          }
458          // Check if data was posted to this container. If not, issue an error.
459          if (!output->GetData() && !isManagedByHandler) {
460             Error("PackOutput", "No data for output container %s. Forgot to PostData ?", output->GetName());
461             continue;
462          }   
463          if (!output->IsSpecialOutput()) {
464             // Normal outputs
465             if (strlen(filename) && !isManagedByHandler) {
466                // Backup current folder
467                TDirectory *opwd = gDirectory;
468                // File resident outputs. 
469                // Check first if the file exists.
470                TString openoption = "RECREATE";
471                if (!gSystem->AccessPathName(output->GetFileName())) openoption = "UPDATE";
472                TFile *file = AliAnalysisManager::OpenFile(output, openoption, kTRUE);
473                // Clear file list to release object ownership to user.
474                file->Clear();
475                // Save data to file, then close.
476                if (output->GetData()->InheritsFrom(TCollection::Class())) {
477                   // If data is a collection, we set the name of the collection 
478                   // as the one of the container and we save as a single key.
479                   TCollection *coll = (TCollection*)output->GetData();
480                   coll->SetName(output->GetName());
481                   coll->Write(output->GetName(), TObject::kSingleKey);
482                } else {
483                   if (output->GetData()->InheritsFrom(TTree::Class())) {
484                      TTree *tree = (TTree*)output->GetData();
485                      // tree->SetDirectory(file);
486                      tree->AutoSave();
487                   } else {
488                      output->GetData()->Write();
489                   }   
490                }      
491                if (fDebug > 1) printf("PackOutput %s: memory merge, file resident output\n", output->GetName());
492                if (fDebug > 2) {
493                   printf("   file %s listing content:\n", filename);
494                   file->ls();
495                }   
496                file->Close();
497                output->SetFile(NULL);
498                // Restore current directory
499                if (opwd) opwd->cd();
500             } else {
501                // Memory-resident outputs   
502                if (fDebug > 1) printf("PackOutput %s: memory merge memory resident output\n", filename);
503             }   
504             AliAnalysisDataWrapper *wrap = 0;
505             if (isManagedByHandler) {
506                wrap = new AliAnalysisDataWrapper(fOutputEventHandler->GetTree());
507                wrap->SetName(output->GetName());
508             }   
509             else                    wrap =output->ExportData();
510             // Output wrappers must NOT delete data after merging - the user owns them
511             wrap->SetDeleteData(kFALSE);
512             target->Add(wrap);
513          } else {
514          // Special outputs. The file must be opened and connected to the container.
515             TDirectory *opwd = gDirectory;
516             TFile *file = output->GetFile();
517             if (!file) {
518                AliAnalysisTask *producer = output->GetProducer();
519                Fatal("PackOutput", 
520                      "File %s for special container %s was NOT opened in %s::CreateOutputObjects !!!",
521                      output->GetFileName(), output->GetName(), producer->ClassName());
522                continue;
523             }   
524             TString outFilename = file->GetName();
525             if (fDebug > 1) printf("PackOutput %s: special output\n", output->GetName());
526             if (isManagedByHandler) {
527                // Terminate IO for files managed by the output handler
528                // file->Write() moved to AOD handler (A.G. 11.01.10)
529 //               if (file) file->Write();
530                if (file && fDebug > 2) {
531                   printf("   handled file %s listing content:\n", file->GetName());
532                   file->ls();
533                }   
534                fOutputEventHandler->TerminateIO();
535             } else {               
536                file->cd();
537                // Release object ownership to users after writing data to file
538                if (output->GetData()->InheritsFrom(TCollection::Class())) {
539                   // If data is a collection, we set the name of the collection 
540                   // as the one of the container and we save as a single key.
541                   TCollection *coll = (TCollection*)output->GetData();
542                   coll->SetName(output->GetName());
543                   coll->Write(output->GetName(), TObject::kSingleKey);
544                } else {
545                   if (output->GetData()->InheritsFrom(TTree::Class())) {
546                      TTree *tree = (TTree*)output->GetData();
547                      tree->SetDirectory(file);
548                      tree->AutoSave();
549                   } else {
550                      output->GetData()->Write();
551                   }   
552                }      
553                file->Clear();
554                if (fDebug > 2) {
555                   printf("   file %s listing content:\n", output->GetFileName());
556                   file->ls();
557                }
558                file->Close();
559                output->SetFile(NULL);
560             }
561             // Restore current directory
562             if (opwd) opwd->cd();
563             // Check if a special output location was provided or the output files have to be merged
564             if (strlen(fSpecialOutputLocation.Data())) {
565                TString remote = fSpecialOutputLocation;
566                remote += "/";
567                Int_t gid = gROOT->ProcessLine("gProofServ->GetGroupId();");
568                if (remote.BeginsWith("alien://")) {
569                   gROOT->ProcessLine("TGrid::Connect(\"alien://pcapiserv01.cern.ch:10000\", gProofServ->GetUser());");
570                   remote += outFilename;
571                   remote.ReplaceAll(".root", Form("_%d.root", gid));
572                } else {   
573                   remote += Form("%s_%d_", gSystem->HostName(), gid);
574                   remote += outFilename;
575                }   
576                if (fDebug > 1) 
577                   Info("PackOutput", "Output file for container %s to be copied \n   at: %s. No merging.",
578                        output->GetName(), remote.Data());
579                TFile::Cp ( outFilename.Data(), remote.Data() );
580                // Copy extra outputs
581                if (fExtraFiles.Length() && isManagedByHandler) {
582                   TObjArray *arr = fExtraFiles.Tokenize(" ");
583                   TObjString *os;
584                   TIter nextfilename(arr);
585                   while ((os=(TObjString*)nextfilename())) {
586                      outFilename = os->GetString();
587                      remote = fSpecialOutputLocation;
588                      remote += "/";
589                      if (remote.BeginsWith("alien://")) {
590                         remote += outFilename;
591                         remote.ReplaceAll(".root", Form("_%d.root", gid));
592                      } else {   
593                         remote += Form("%s_%d_", gSystem->HostName(), gid);
594                         remote += outFilename;
595                      }   
596                      if (fDebug > 1) 
597                         Info("PackOutput", "Extra AOD file %s to be copied \n   at: %s. No merging.",
598                              outFilename.Data(), remote.Data());
599                      TFile::Cp ( outFilename.Data(), remote.Data() );
600                   }   
601                   delete arr;
602                }   
603             } else {
604             // No special location specified-> use TProofOutputFile as merging utility
605             // The file at this output slot must be opened in CreateOutputObjects
606                if (fDebug > 1) printf("   File for container %s to be merged via file merger...\n", output->GetName());
607             }
608          }      
609       }
610    } 
611    if (fDebug > 0) printf("<-AliAnalysisManager::PackOutput: output list contains %d containers\n", target->GetSize());
612 }
613
614 //______________________________________________________________________________
615 void AliAnalysisManager::ImportWrappers(TList *source)
616 {
617 // Import data in output containers from wrappers coming in source.
618    if (fDebug > 0) printf("->AliAnalysisManager::ImportWrappers()\n");
619    TIter next(fOutputs);
620    AliAnalysisDataContainer *cont;
621    AliAnalysisDataWrapper   *wrap;
622    Int_t icont = 0;
623    Bool_t inGrid = (fMode == kGridAnalysis)?kTRUE:kFALSE;
624    TDirectory *cdir = gDirectory;
625    while ((cont=(AliAnalysisDataContainer*)next())) {
626       wrap = 0;
627       if (cont->GetProducer()->IsPostEventLoop() && !inGrid) continue;
628       if (cont->IsRegisterDataset()) continue;
629       const char *filename = cont->GetFileName();
630       Bool_t isManagedByHandler = kFALSE;
631       if (!(strcmp(filename, "default")) && fOutputEventHandler) {
632          isManagedByHandler = kTRUE;
633          filename = fOutputEventHandler->GetOutputFileName();
634       }
635       if (cont->IsSpecialOutput() || inGrid) {
636          if (strlen(fSpecialOutputLocation.Data())) continue;
637          // Copy merged file from PROOF scratch space. 
638          // In case of grid the files are already in the current directory.
639          if (!inGrid) {
640             if (isManagedByHandler && fExtraFiles.Length()) {
641                // Copy extra registered dAOD files.
642                TObjArray *arr = fExtraFiles.Tokenize(" ");
643                TObjString *os;
644                TIter nextfilename(arr);
645                while ((os=(TObjString*)nextfilename())) GetFileFromWrapper(os->GetString(), source);
646                delete arr;
647             }
648             if (!GetFileFromWrapper(filename, source)) continue;
649          }   
650          // Normally we should connect data from the copied file to the
651          // corresponding output container, but it is not obvious how to do this
652          // automatically if several objects in file...
653          TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
654          if (!f) f = TFile::Open(filename, "READ");
655          if (!f) {
656             Error("ImportWrappers", "Cannot open file %s in read-only mode", filename);
657             continue;
658          }   
659          TObject *obj = 0;
660          // Cd to the directory pointed by the container
661          TString folder = cont->GetFolderName();
662          if (!folder.IsNull()) f->cd(folder);
663          // Try to fetch first an object having the container name.
664          obj = gDirectory->Get(cont->GetName());
665          if (!obj) {
666             Warning("ImportWrappers", "Could not import object for container %s in file %s:%s.\n Object will not be available in Terminate()", 
667                     cont->GetName(), filename, cont->GetFolderName());
668             continue;
669          }  
670          wrap = new AliAnalysisDataWrapper(obj);
671          wrap->SetDeleteData(kFALSE);
672       }   
673       if (!wrap) wrap = (AliAnalysisDataWrapper*)source->FindObject(cont->GetName());
674       if (!wrap) {
675          Error("ImportWrappers","Container %s not found in analysis output !", cont->GetName());
676          continue;
677       }
678       icont++;
679       if (fDebug > 1) {
680          printf("   Importing data for container %s\n", cont->GetName());
681          if (strlen(filename)) printf("    -> file %s\n", filename);
682          else printf("\n");
683       }   
684       cont->ImportData(wrap);
685    }
686    if (cdir) cdir->cd();
687    if (fDebug > 0) printf("<-AliAnalysisManager::ImportWrappers(): %d containers imported\n", icont);
688 }
689
690 //______________________________________________________________________________
691 void AliAnalysisManager::UnpackOutput(TList *source)
692 {
693   // Called by AliAnalysisSelector::Terminate only on the client.
694    if (fDebug > 0) printf("->AliAnalysisManager::UnpackOutput()\n");
695    if (!source) {
696       Error("UnpackOutput", "No target. Exiting.");
697       return;
698    }
699    if (fDebug > 1) printf("   Source list contains %d containers\n", source->GetSize());
700
701    if (fMode == kProofAnalysis) ImportWrappers(source);
702
703    TIter next(fOutputs);
704    AliAnalysisDataContainer *output;
705    while ((output=(AliAnalysisDataContainer*)next())) {
706       if (!output->GetData()) continue;
707       // Check if there are client tasks that run post event loop
708       if (output->HasConsumers()) {
709          // Disable event loop semaphore
710          output->SetPostEventLoop(kTRUE);
711          TObjArray *list = output->GetConsumers();
712          Int_t ncons = list->GetEntriesFast();
713          for (Int_t i=0; i<ncons; i++) {
714             AliAnalysisTask *task = (AliAnalysisTask*)list->At(i);
715             task->CheckNotify(kTRUE);
716             // If task is active, execute it
717             if (task->IsPostEventLoop() && task->IsActive()) {
718                if (fDebug > 0) printf("== Executing post event loop task %s\n", task->GetName());
719                task->ExecuteTask();
720             }   
721          }
722       }   
723    }
724    if (fDebug > 0) printf("<-AliAnalysisManager::UnpackOutput()\n");
725 }
726
727 //______________________________________________________________________________
728 void AliAnalysisManager::Terminate()
729 {
730   // The Terminate() function is the last function to be called during
731   // a query. It always runs on the client, it can be used to present
732   // the results graphically.
733    if (fDebug > 0) printf("->AliAnalysisManager::Terminate()\n");
734    AliAnalysisTask *task;
735    AliAnalysisDataContainer *output;
736    TIter next(fTasks);
737    TStopwatch timer;
738    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
739    // Call Terminate() for tasks
740    Int_t itask = 0;
741    while (!IsSkipTerminate() && (task=(AliAnalysisTask*)next())) {
742       // Save all the canvases produced by the Terminate
743       TString pictname = Form("%s_%s", task->GetName(), task->ClassName());
744       task->Terminate();
745       if (getsysInfo) 
746          AliSysInfo::AddStamp(Form("%s_TERMINATE",task->ClassName()),0, itask, 2);
747       itask++;   
748       if (TObject::TestBit(kSaveCanvases)) {
749          if (!gROOT->IsBatch()) {
750             if (fDebug>0) printf("Waiting 5 sec for %s::Terminate() to finish drawing ...", task->ClassName());
751             timer.Start();
752             while (timer.CpuTime()<5) {
753                timer.Continue();
754                gSystem->ProcessEvents();
755             }
756          }
757          Int_t iend = gROOT->GetListOfCanvases()->GetEntries();
758          if (iend==0) continue;
759          TCanvas *canvas;
760          for (Int_t ipict=0; ipict<iend; ipict++) {
761             canvas = (TCanvas*)gROOT->GetListOfCanvases()->At(ipict);
762             if (!canvas) continue;         
763             canvas->SaveAs(Form("%s_%02d.gif", pictname.Data(),ipict));
764          } 
765          gROOT->GetListOfCanvases()->Delete(); 
766       }
767    }   
768    //
769    if (fInputEventHandler)   fInputEventHandler  ->TerminateIO();
770    if (fOutputEventHandler)  fOutputEventHandler ->TerminateIO();
771    if (fMCtruthEventHandler) fMCtruthEventHandler->TerminateIO();
772    TObjArray *allOutputs = new TObjArray();
773    Int_t icont;
774    for (icont=0; icont<fOutputs->GetEntriesFast(); icont++) allOutputs->Add(fOutputs->At(icont));
775    if (!IsSkipTerminate())
776       for (icont=0; icont<fParamCont->GetEntriesFast(); icont++) allOutputs->Add(fParamCont->At(icont));
777    TIter next1(allOutputs);
778    TString handlerFile = "";
779    if (fOutputEventHandler) {
780       handlerFile = fOutputEventHandler->GetOutputFileName();
781    }
782    while ((output=(AliAnalysisDataContainer*)next1())) {
783       // Special outputs or grid files have the files already closed and written.
784       if (fMode == kGridAnalysis) continue;
785       if (fMode == kProofAnalysis) {
786         if (output->IsSpecialOutput() || output->IsRegisterDataset()) continue;
787       }  
788       const char *filename = output->GetFileName();
789       TString openoption = "RECREATE";
790       if (!(strcmp(filename, "default"))) continue;
791       if (!strlen(filename)) continue;
792       if (!output->GetData()) continue;
793       TDirectory *opwd = gDirectory;
794       TFile *file = output->GetFile();
795       if (!file) file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
796       if (!file) {
797               //if (handlerFile == filename && !gSystem->AccessPathName(filename)) openoption = "UPDATE";
798          if (!gSystem->AccessPathName(filename)) openoption = "UPDATE";
799               if (fDebug>0) printf("Opening file: %s  option=%s\n",filename, openoption.Data());
800          file = new TFile(filename, openoption);
801       } else {
802          if (fDebug>0) printf("File already opened: %s\n", filename);
803       }   
804       if (file->IsZombie()) {
805          Error("Terminate", "Cannot open output file %s", filename);
806          continue;
807       }   
808       output->SetFile(file);
809       file->cd();
810       // Check for a folder request
811       TString dir = output->GetFolderName();
812       if (!dir.IsNull()) {
813          if (!file->GetDirectory(dir)) file->mkdir(dir);
814          file->cd(dir);
815       }  
816       if (fDebug > 0) printf("...writing container %s to file %s:%s\n", output->GetName(), file->GetName(), output->GetFolderName());
817       if (output->GetData()->InheritsFrom(TCollection::Class())) {
818       // If data is a collection, we set the name of the collection 
819       // as the one of the container and we save as a single key.
820          TCollection *coll = (TCollection*)output->GetData();
821          coll->SetName(output->GetName());
822          coll->Write(output->GetName(), TObject::kSingleKey);
823       } else {
824          if (output->GetData()->InheritsFrom(TTree::Class())) {
825             TTree *tree = (TTree*)output->GetData();
826             tree->SetDirectory(file);
827             tree->AutoSave();
828          } else {
829             output->GetData()->Write();
830          }   
831       }      
832       if (opwd) opwd->cd();
833    }   
834    next1.Reset();
835    while ((output=(AliAnalysisDataContainer*)next1())) {
836       // Close all files at output
837       TDirectory *opwd = gDirectory;
838       if (output->GetFile()) {
839          output->GetFile()->Close();
840          output->SetFile(NULL);
841          // Copy merged outputs in alien if requested
842          if (fSpecialOutputLocation.Length() && 
843              fSpecialOutputLocation.BeginsWith("alien://")) {
844             Info("Terminate", "Copy file %s to %s", output->GetFile()->GetName(),fSpecialOutputLocation.Data()); 
845             TFile::Cp(output->GetFile()->GetName(), 
846                       Form("%s/%s", fSpecialOutputLocation.Data(), output->GetFile()->GetName()));
847          }             
848       }   
849       if (opwd) opwd->cd();
850    }   
851    delete allOutputs;
852
853    if (getsysInfo) {
854       TDirectory *cdir = gDirectory;
855       TFile f("syswatch.root", "RECREATE");
856       TH1 *hist;
857       TString cut;
858       if (!f.IsZombie()) {
859          TTree *tree = AliSysInfo::MakeTree("syswatch.log");
860          tree->SetName("syswatch");
861          tree->SetMarkerStyle(kCircle);
862          tree->SetMarkerColor(kBlue);
863          tree->SetMarkerSize(0.5);
864          if (!gROOT->IsBatch()) {
865             tree->SetAlias("event", "id0");
866             tree->SetAlias("task",  "id1");
867             tree->SetAlias("stage", "id2");
868             // Already defined aliases
869             // tree->SetAlias("deltaT","stampSec-stampOldSec");
870             // tree->SetAlias("T","stampSec-first");
871             // tree->SetAlias("deltaVM","(pI.fMemVirtual-pIOld.fMemVirtual)");
872             // tree->SetAlias("VM","pI.fMemVirtual");
873             TCanvas *canvas = new TCanvas("SysInfo","SysInfo",10,10,1200,800);
874             Int_t npads = 1 /*COO plot for all tasks*/ +
875                           fTopTasks->GetEntries() /*Exec plot per task*/ +
876                           1 /*Terminate plot for all tasks*/ +
877                           1; /*vm plot*/
878                           
879             Int_t iopt = (Int_t)TMath::Sqrt((Double_t)npads);
880             if (npads<iopt*(iopt+1))
881                canvas->Divide(iopt, iopt+1, 0.01, 0.01);
882             else
883                canvas->Divide(iopt+1, iopt+1, 0.01, 0.01);
884             Int_t ipad = 1;
885             // draw the plot of deltaVM for Exec for each task
886             for (itask=0; itask<fTopTasks->GetEntriesFast(); itask++) {
887                task = (AliAnalysisTask*)fTopTasks->At(itask);
888                canvas->cd(ipad++);
889                cut = Form("task==%d && stage==1", itask);
890                tree->Draw("deltaVM:event",cut,"", 1234567890, 0);
891                hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");            
892                if (hist) {
893                   hist->SetTitle(Form("%s: Exec dVM[kB]/event", task->GetName()));
894                   hist->GetYaxis()->SetTitle("deltaVM [kB]");
895                }   
896             }
897             // Draw the plot of deltaVM for CreateOutputObjects for all tasks
898             canvas->cd(ipad++);
899             tree->SetMarkerStyle(kFullTriangleUp);
900             tree->SetMarkerColor(kRed);
901             tree->SetMarkerSize(0.8);
902             cut = "task>=0 && task<1000 && stage==0";
903             tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
904             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");            
905             if (hist) {
906                hist->SetTitle("Memory in CreateOutputObjects()");
907                hist->GetYaxis()->SetTitle("deltaVM [kB]");
908                hist->GetXaxis()->SetTitle("task");
909             }   
910             // draw the plot of deltaVM for Terminate for all tasks
911             canvas->cd(ipad++);
912             tree->SetMarkerStyle(kOpenSquare);
913             tree->SetMarkerColor(kMagenta);
914             cut = "task>=0 && task<1000 && stage==2";
915             tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
916             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
917             if (hist) {
918                hist->SetTitle("Memory in Terminate()");
919                hist->GetYaxis()->SetTitle("deltaVM [kB]");
920                hist->GetXaxis()->SetTitle("task");
921             }   
922             // Full VM profile
923             canvas->cd(ipad++);
924             tree->SetMarkerStyle(kFullCircle);
925             tree->SetMarkerColor(kGreen);
926             cut = Form("task==%d && stage==1",fTopTasks->GetEntriesFast()-1);            
927             tree->Draw("VM:event",cut,"", 1234567890, 0);
928             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
929             if (hist) {
930                hist->SetTitle("Virtual memory");
931                hist->GetYaxis()->SetTitle("VM [kB]");
932             }
933             canvas->Modified();   
934          }   
935          tree->SetMarkerStyle(kCircle);
936          tree->SetMarkerColor(kBlue);
937          tree->SetMarkerSize(0.5);
938          tree->Write();
939          f.Close();
940          delete tree;
941       }
942       if (cdir) cdir->cd();
943    }
944    // Validate the output files
945    if (ValidateOutputFiles()) {
946       ofstream out;
947       out.open("outputs_valid", ios::out);
948       out.close();
949    }      
950    if (fDebug > 0) printf("<-AliAnalysisManager::Terminate()\n");
951 }
952 //______________________________________________________________________________
953 void AliAnalysisManager::ProfileTask(Int_t itop, const char *option) const
954 {
955 // Profiles the task having the itop index in the list of top (first level) tasks.
956    AliAnalysisTask *task = (AliAnalysisTask*)fTopTasks->At(itop);
957    if (!task) {
958       Error("ProfileTask", "There are only %d top tasks in the manager", fTopTasks->GetEntries());
959       return;
960    }
961    ProfileTask(task->GetName(), option);
962 }      
963
964 //______________________________________________________________________________
965 void AliAnalysisManager::ProfileTask(const char *name, const char */*option*/) const
966 {
967 // Profile a managed task after the execution of the analysis in case NSysInfo
968 // was used.
969    if (gSystem->AccessPathName("syswatch.root")) {
970       Error("ProfileTask", "No file syswatch.root found in the current directory");
971       return;
972    }
973    if (gROOT->IsBatch()) return;
974    AliAnalysisTask *task = (AliAnalysisTask*)fTopTasks->FindObject(name);
975    if (!task) {
976       Error("ProfileTask", "No top task named %s known by the manager.", name);
977       return;
978    }
979    Int_t itop = fTopTasks->IndexOf(task);
980    Int_t itask = fTasks->IndexOf(task);
981    // Create canvas with 2 pads: first draw COO + Terminate, second Exec
982    TDirectory *cdir = gDirectory;
983    TFile f("syswatch.root");
984    TTree *tree = (TTree*)f.Get("syswatch");
985    if (!tree) {
986       Error("ProfileTask", "No tree named <syswatch> found in file syswatch.root");
987       return;
988    }   
989    if (fDebug > 0) printf("=== Profiling task %s (class %s)\n", name, task->ClassName());
990    TCanvas *canvas = new TCanvas(Form("profile_%d",itop),Form("Profile of task %s (class %s)",name,task->ClassName()),10,10,800,600);
991    canvas->Divide(2, 2, 0.01, 0.01);
992    Int_t ipad = 1;
993    TString cut;
994    TH1 *hist;
995    // VM profile for COO and Terminate methods
996    canvas->cd(ipad++);
997    cut = Form("task==%d && (stage==0 || stage==2)",itask);
998    tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
999    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1000    if (hist) {
1001       hist->SetTitle("Alocated VM[kB] for COO and Terminate");
1002       hist->GetYaxis()->SetTitle("deltaVM [kB]");
1003       hist->GetXaxis()->SetTitle("method");
1004    }   
1005    // CPU profile per event
1006    canvas->cd(ipad++);
1007    cut = Form("task==%d && stage==1",itop);
1008    tree->Draw("deltaT:event",cut,"", 1234567890, 0);
1009    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1010    if (hist) {
1011       hist->SetTitle("Execution time per event");
1012       hist->GetYaxis()->SetTitle("CPU/event [s]");
1013    }   
1014    // VM profile for Exec
1015    canvas->cd(ipad++);
1016    cut = Form("task==%d && stage==1",itop);
1017    tree->Draw("deltaVM:event",cut,"", 1234567890, 0);
1018    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1019    if (hist) {
1020       hist->SetTitle("Alocated VM[kB] per event");
1021       hist->GetYaxis()->SetTitle("deltaVM [kB]");
1022    }   
1023    canvas->Modified();
1024    delete tree;
1025    f.Close();
1026    if (cdir) cdir->cd();
1027 }     
1028
1029 //______________________________________________________________________________
1030 void AliAnalysisManager::AddTask(AliAnalysisTask *task)
1031 {
1032 // Adds a user task to the global list of tasks.
1033    if (fTasks->FindObject(task)) {
1034       Warning("AddTask", "Task %s: the same object already added to the analysis manager. Not adding.", task->GetName());
1035       return;
1036    }   
1037    task->SetActive(kFALSE);
1038    fTasks->Add(task);
1039 }  
1040
1041 //______________________________________________________________________________
1042 AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const
1043 {
1044 // Retreive task by name.
1045    if (!fTasks) return NULL;
1046    return (AliAnalysisTask*)fTasks->FindObject(name);
1047 }
1048
1049 //______________________________________________________________________________
1050 AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name, 
1051                                 TClass *datatype, EAliAnalysisContType type, const char *filename)
1052 {
1053 // Create a data container of a certain type. Types can be:
1054 //   kExchangeContainer  = 0, used to exchange data between tasks
1055 //   kInputContainer   = 1, used to store input data
1056 //   kOutputContainer  = 2, used for writing result to a file
1057 // filename: composed by file#folder (e.g. results.root#INCLUSIVE) - will write
1058 // the output object to a folder inside the output file
1059    if (fContainers->FindObject(name)) {
1060       Error("CreateContainer","A container named %s already defined !",name);
1061       return NULL;
1062    }   
1063    AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
1064    fContainers->Add(cont);
1065    switch (type) {
1066       case kInputContainer:
1067          fInputs->Add(cont);
1068          break;
1069       case kOutputContainer:
1070          fOutputs->Add(cont);
1071          if (filename && strlen(filename)) {
1072             cont->SetFileName(filename);
1073             cont->SetDataOwned(kFALSE);  // data owned by the file
1074          }   
1075          break;
1076       case kParamContainer:
1077          fParamCont->Add(cont);
1078          if (filename && strlen(filename)) {
1079             cont->SetFileName(filename);
1080             cont->SetDataOwned(kFALSE);  // data owned by the file
1081          }   
1082          break;
1083       case kExchangeContainer:
1084          break;   
1085    }
1086    return cont;
1087 }
1088          
1089 //______________________________________________________________________________
1090 Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
1091                                         AliAnalysisDataContainer *cont)
1092 {
1093 // Connect input of an existing task to a data container.
1094    if (!task) {
1095       Error("ConnectInput", "Task pointer is NULL");
1096       return kFALSE;
1097    }   
1098    if (!fTasks->FindObject(task)) {
1099       AddTask(task);
1100       Info("ConnectInput", "Task %s was not registered. Now owned by analysis manager", task->GetName());
1101    } 
1102    Bool_t connected = task->ConnectInput(islot, cont);
1103    return connected;
1104 }   
1105
1106 //______________________________________________________________________________
1107 Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
1108                                         AliAnalysisDataContainer *cont)
1109 {
1110 // Connect output of an existing task to a data container.
1111    if (!task) {
1112       Error("ConnectOutput", "Task pointer is NULL");
1113       return kFALSE;
1114    }   
1115    if (!fTasks->FindObject(task)) {
1116       AddTask(task);
1117       Warning("ConnectOutput", "Task %s not registered. Now owned by analysis manager", task->GetName());
1118    } 
1119    Bool_t connected = task->ConnectOutput(islot, cont);
1120    return connected;
1121 }   
1122                                
1123 //______________________________________________________________________________
1124 void AliAnalysisManager::CleanContainers()
1125 {
1126 // Clean data from all containers that have already finished all client tasks.
1127    TIter next(fContainers);
1128    AliAnalysisDataContainer *cont;
1129    while ((cont=(AliAnalysisDataContainer *)next())) {
1130       if (cont->IsOwnedData() && 
1131           cont->IsDataReady() && 
1132           cont->ClientsExecuted()) cont->DeleteData();
1133    }
1134 }
1135
1136 //______________________________________________________________________________
1137 Bool_t AliAnalysisManager::InitAnalysis()
1138 {
1139 // Initialization of analysis chain of tasks. Should be called after all tasks
1140 // and data containers are properly connected
1141    // Reset flag and remove valid_outputs file if exists
1142    fInitOK = kFALSE;
1143    if (!gSystem->AccessPathName("outputs_valid"))
1144       gSystem->Unlink("outputs_valid");
1145    // Check for top tasks (depending only on input data containers)
1146    if (!fTasks->First()) {
1147       Error("InitAnalysis", "Analysis has no tasks !");
1148       return kFALSE;
1149    }   
1150    TIter next(fTasks);
1151    AliAnalysisTask *task;
1152    AliAnalysisDataContainer *cont;
1153    Int_t ntop = 0;
1154    Int_t nzombies = 0;
1155    Bool_t iszombie = kFALSE;
1156    Bool_t istop = kTRUE;
1157    Int_t i;
1158    while ((task=(AliAnalysisTask*)next())) {
1159       istop = kTRUE;
1160       iszombie = kFALSE;
1161       Int_t ninputs = task->GetNinputs();
1162       for (i=0; i<ninputs; i++) {
1163          cont = task->GetInputSlot(i)->GetContainer();
1164          if (!cont) {
1165             if (!iszombie) {
1166                task->SetZombie();
1167                fZombies->Add(task);
1168                nzombies++;
1169                iszombie = kTRUE;
1170             }   
1171             Error("InitAnalysis", "Input slot %d of task %s has no container connected ! Declared zombie...", 
1172                   i, task->GetName()); 
1173          }
1174          if (iszombie) continue;
1175          // Check if cont is an input container
1176          if (istop && !fInputs->FindObject(cont)) istop=kFALSE;
1177          // Connect to parent task
1178       }
1179       if (istop) {
1180          ntop++;
1181          fTopTasks->Add(task);
1182       }
1183    }
1184    if (!ntop) {
1185       Error("InitAnalysis", "No top task defined. At least one task should be connected only to input containers");
1186       return kFALSE;
1187    }                        
1188    // Check now if there are orphan tasks
1189    for (i=0; i<ntop; i++) {
1190       task = (AliAnalysisTask*)fTopTasks->At(i);
1191       task->SetUsed();
1192    }
1193    Int_t norphans = 0;
1194    next.Reset();
1195    while ((task=(AliAnalysisTask*)next())) {
1196       if (!task->IsUsed()) {
1197          norphans++;
1198          Warning("InitAnalysis", "Task %s is orphan", task->GetName());
1199       }   
1200    }          
1201    // Check the task hierarchy (no parent task should depend on data provided
1202    // by a daughter task)
1203    for (i=0; i<ntop; i++) {
1204       task = (AliAnalysisTask*)fTopTasks->At(i);
1205       if (task->CheckCircularDeps()) {
1206          Error("InitAnalysis", "Found illegal circular dependencies between following tasks:");
1207          PrintStatus("dep");
1208          return kFALSE;
1209       }   
1210    }
1211    // Check that all containers feeding post-event loop tasks are in the outputs list
1212    TIter nextcont(fContainers); // loop over all containers
1213    while ((cont=(AliAnalysisDataContainer*)nextcont())) {
1214       if (!cont->IsPostEventLoop() && !fOutputs->FindObject(cont)) {
1215          if (cont->HasConsumers()) {
1216          // Check if one of the consumers is post event loop
1217             TIter nextconsumer(cont->GetConsumers());
1218             while ((task=(AliAnalysisTask*)nextconsumer())) {
1219                if (task->IsPostEventLoop()) {
1220                   fOutputs->Add(cont);
1221                   break;
1222                }
1223             }
1224          }
1225       }
1226    }   
1227    // Check if all special output containers have a file name provided
1228    TIter nextout(fOutputs);
1229    while ((cont=(AliAnalysisDataContainer*)nextout())) {
1230       if (cont->IsSpecialOutput() && !strlen(cont->GetFileName())) {
1231          Error("InitAnalysis", "Wrong container %s : a file name MUST be provided for special outputs", cont->GetName());
1232          return kFALSE;
1233       }
1234    }      
1235    fInitOK = kTRUE;
1236    return kTRUE;
1237 }   
1238
1239 //______________________________________________________________________________
1240 void AliAnalysisManager::PrintStatus(Option_t *option) const
1241 {
1242 // Print task hierarchy.
1243    if (!fInitOK) {
1244       Info("PrintStatus", "Analysis manager %s not initialized : call InitAnalysis() first", GetName());
1245       return;
1246    }   
1247    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1248    if (getsysInfo)
1249       Info("PrintStatus", "System information will be collected each %lld events", fNSysInfo);
1250    TIter next(fTopTasks);
1251    AliAnalysisTask *task;
1252    while ((task=(AliAnalysisTask*)next()))
1253       task->PrintTask(option);
1254 }
1255
1256 //______________________________________________________________________________
1257 void AliAnalysisManager::ResetAnalysis()
1258 {
1259 // Reset all execution flags and clean containers.
1260    CleanContainers();
1261 }
1262
1263 //______________________________________________________________________________
1264 Long64_t AliAnalysisManager::StartAnalysis(const char *type, TTree * const tree, Long64_t nentries, Long64_t firstentry)
1265 {
1266 // Start analysis for this manager. Analysis task can be: LOCAL, PROOF, GRID or
1267 // MIX. Process nentries starting from firstentry
1268    Long64_t retv = 0;
1269    if (!fInitOK) {
1270       Error("StartAnalysis","Analysis manager was not initialized !");
1271       return -1;
1272    }
1273    if (fDebug > 0) printf("StartAnalysis %s\n",GetName());
1274    TString anaType = type;
1275    anaType.ToLower();
1276    fMode = kLocalAnalysis;
1277    Bool_t runlocalinit = kTRUE;
1278    if (anaType.Contains("file")) {
1279       runlocalinit = kFALSE;
1280    }   
1281    if (anaType.Contains("proof"))     fMode = kProofAnalysis;
1282    else if (anaType.Contains("grid")) fMode = kGridAnalysis;
1283    else if (anaType.Contains("mix"))  fMode = kMixingAnalysis;
1284
1285    if (fMode == kGridAnalysis) {
1286       if (!anaType.Contains("terminate")) {
1287          if (!fGridHandler) {
1288             Error("StartAnalysis", "Cannot start grid analysis without a grid handler.");
1289             Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1290             return -1;
1291          }
1292          // Write analysis manager in the analysis file
1293          cout << "===== RUNNING GRID ANALYSIS: " << GetName() << endl;
1294          // run local task configuration
1295          TIter nextTask(fTasks);
1296          AliAnalysisTask *task;
1297          while ((task=(AliAnalysisTask*)nextTask())) {
1298             task->LocalInit();
1299          }
1300          if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1301             Info("StartAnalysis", "Grid analysis was stopped and cannot be terminated");
1302             return -1;
1303          }   
1304
1305          // Terminate grid analysis
1306          if (fSelector && fSelector->GetStatus() == -1) return -1;
1307          if (fGridHandler->GetRunMode() == AliAnalysisGrid::kOffline) return 0;
1308          cout << "===== MERGING OUTPUTS REGISTERED BY YOUR ANALYSIS JOB: " << GetName() << endl;
1309          if (!fGridHandler->MergeOutputs()) {
1310             // Return if outputs could not be merged or if it alien handler
1311             // was configured for offline mode or local testing.
1312             return 0;
1313          }
1314       }   
1315       cout << "===== TERMINATING GRID ANALYSIS JOB: " << GetName() << endl;
1316       ImportWrappers(NULL);
1317       Terminate();
1318       return 0;
1319    }
1320    char line[256];
1321    SetEventLoop(kFALSE);
1322    // Enable event loop mode if a tree was provided
1323    if (tree || fMode==kMixingAnalysis) SetEventLoop(kTRUE);
1324
1325    TChain *chain = 0;
1326    TString ttype = "TTree";
1327    if (tree && tree->IsA() == TChain::Class()) {
1328       chain = (TChain*)tree;
1329       if (!chain || !chain->GetListOfFiles()->First()) {
1330          Error("StartAnalysis", "Cannot process null or empty chain...");
1331          return -1;
1332       }   
1333       ttype = "TChain";
1334    }   
1335
1336    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1337    if (getsysInfo) AliSysInfo::AddStamp("Start", 0);
1338    // Initialize locally all tasks (happens for all modes)
1339    TIter next(fTasks);
1340    AliAnalysisTask *task;
1341    if (runlocalinit) {
1342       while ((task=(AliAnalysisTask*)next())) {
1343          task->LocalInit();
1344       }
1345       if (getsysInfo) AliSysInfo::AddStamp("LocalInit_all", 0);
1346    }   
1347    
1348    switch (fMode) {
1349       case kLocalAnalysis:
1350          if (!tree) {
1351             TIter nextT(fTasks);
1352             // Call CreateOutputObjects for all tasks
1353             Int_t itask = 0;
1354             while ((task=(AliAnalysisTask*)nextT())) {
1355                TDirectory *curdir = gDirectory;
1356                task->CreateOutputObjects();
1357                if (getsysInfo) AliSysInfo::AddStamp(Form("%s_CREATEOUTOBJ",task->ClassName()), 0, itask, 0);
1358                if (curdir) curdir->cd();
1359                itask++;
1360             }   
1361             if (IsExternalLoop()) {
1362                Info("StartAnalysis", "Initialization done. Event loop is controlled externally.\
1363                      \nSetData for top container, call ExecAnalysis in a loop and then Terminate manually");
1364                return 0;
1365             }         
1366             ExecAnalysis();
1367             Terminate();
1368             return 0;
1369          } 
1370          // Run tree-based analysis via AliAnalysisSelector  
1371          cout << "===== RUNNING LOCAL ANALYSIS " << GetName() << " ON TREE " << tree->GetName() << endl;
1372          fSelector = new AliAnalysisSelector(this);
1373          retv = tree->Process(fSelector, "", nentries, firstentry);
1374          break;
1375       case kProofAnalysis:
1376          if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1377             Error("StartAnalysis", "No PROOF!!! Exiting.");
1378             return -1;
1379          }   
1380          sprintf(line, "gProof->AddInput((TObject*)0x%lx);", (ULong_t)this);
1381          gROOT->ProcessLine(line);
1382          if (chain) {
1383             chain->SetProof();
1384             cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON CHAIN " << chain->GetName() << endl;
1385             retv = chain->Process("AliAnalysisSelector", "", nentries, firstentry);
1386          } else {
1387             Error("StartAnalysis", "No chain!!! Exiting.");
1388             return -1;
1389          }      
1390          break;
1391       case kGridAnalysis:
1392          Warning("StartAnalysis", "GRID analysis mode not implemented. Running local.");
1393          break;
1394       case kMixingAnalysis:   
1395          // Run event mixing analysis
1396          if (!fEventPool) {
1397             Error("StartAnalysis", "Cannot run event mixing without event pool");
1398             return -1;
1399          }
1400          cout << "===== RUNNING EVENT MIXING ANALYSIS " << GetName() << endl;
1401          fSelector = new AliAnalysisSelector(this);
1402          while ((chain=fEventPool->GetNextChain())) {
1403             next.Reset();
1404             // Call NotifyBinChange for all tasks
1405             while ((task=(AliAnalysisTask*)next()))
1406                if (!task->IsPostEventLoop()) task->NotifyBinChange();
1407             retv = chain->Process(fSelector);
1408             if (retv < 0) {
1409                Error("StartAnalysis", "Mixing analysis failed");
1410                return retv;
1411             }   
1412          }
1413          PackOutput(fSelector->GetOutputList());
1414          Terminate();
1415    }
1416    return retv;
1417 }   
1418
1419 //______________________________________________________________________________
1420 Long64_t AliAnalysisManager::StartAnalysis(const char *type, const char *dataset, Long64_t nentries, Long64_t firstentry)
1421 {
1422 // Start analysis for this manager on a given dataset. Analysis task can be: 
1423 // LOCAL, PROOF or GRID. Process nentries starting from firstentry.
1424    if (!fInitOK) {
1425       Error("StartAnalysis","Analysis manager was not initialized !");
1426       return -1;
1427    }
1428    if (fDebug > 0) printf("StartAnalysis %s\n",GetName());
1429    TString anaType = type;
1430    anaType.ToLower();
1431    if (!anaType.Contains("proof")) {
1432       Error("StartAnalysis", "Cannot process datasets in %s mode. Try PROOF.", type);
1433       return -1;
1434    }   
1435    fMode = kProofAnalysis;
1436    char line[256];
1437    SetEventLoop(kTRUE);
1438    // Set the dataset flag
1439    TObject::SetBit(kUseDataSet);
1440    fTree = 0;
1441
1442    // Initialize locally all tasks
1443    TIter next(fTasks);
1444    AliAnalysisTask *task;
1445    while ((task=(AliAnalysisTask*)next())) {
1446       task->LocalInit();
1447    }
1448    
1449    if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1450       Error("StartAnalysis", "No PROOF!!! Exiting.");
1451       return -1;
1452    }   
1453    sprintf(line, "gProof->AddInput((TObject*)0x%lx);", (ULong_t)this);
1454    gROOT->ProcessLine(line);
1455    sprintf(line, "gProof->GetDataSet(\"%s\");", dataset);
1456    if (!gROOT->ProcessLine(line)) {
1457       Error("StartAnalysis", "Dataset %s not found", dataset);
1458       return -1;
1459    }   
1460    sprintf(line, "gProof->Process(\"%s\", \"AliAnalysisSelector\", \"\", %lld, %lld);",
1461            dataset, nentries, firstentry);
1462    cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON DATASET " << dataset << endl;
1463    Long_t retv = (Long_t)gROOT->ProcessLine(line);
1464    return retv;
1465 }   
1466
1467 //______________________________________________________________________________
1468 TFile *AliAnalysisManager::OpenFile(AliAnalysisDataContainer *cont, const char *option, Bool_t ignoreProof)
1469 {
1470 // Opens according the option the file specified by cont->GetFileName() and changes
1471 // current directory to cont->GetFolderName(). If the file was already opened, it
1472 // checks if the option UPDATE was preserved. File open via TProofOutputFile can
1473 // be optionally ignored.
1474   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1475   TString filename = cont->GetFileName();
1476   TFile *f = NULL;
1477   if (filename.IsNull()) {
1478     ::Error("AliAnalysisManager::OpenFile", "No file name specified for container %s", cont->GetName());
1479     return NULL;
1480   }
1481   if (mgr->GetAnalysisType()==AliAnalysisManager::kProofAnalysis && cont->IsSpecialOutput()
1482       && !ignoreProof)
1483     f = mgr->OpenProofFile(cont,option);
1484   else {
1485     // Check first if the file is already opened
1486     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1487     if (f) {
1488       // Check if option "UPDATE" was preserved 
1489       TString opt(option);
1490       opt.ToUpper();
1491       if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1492         ::Info("AliAnalysisManager::OpenFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1493     } else {
1494       f = TFile::Open(filename, option);
1495     }    
1496   }   
1497   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1498     cont->SetFile(f);
1499     // Cd to file
1500     f->cd();
1501     // Check for a folder request
1502     TString dir = cont->GetFolderName(); 
1503     if (!dir.IsNull()) {
1504       if (!f->GetDirectory(dir)) f->mkdir(dir);
1505       f->cd(dir);
1506     }
1507     return f;
1508   }
1509   ::Fatal("AliAnalysisManager::OpenFile", "File %s could not be opened", filename.Data());
1510   cont->SetFile(NULL);
1511   return NULL;
1512 }    
1513  
1514 //______________________________________________________________________________
1515 TFile *AliAnalysisManager::OpenProofFile(AliAnalysisDataContainer *cont, const char *option)
1516 {
1517 // Opens a special output file used in PROOF.
1518   TString line;
1519   TString filename = cont->GetFileName();
1520   if (cont == fCommonOutput) {
1521      if (fOutputEventHandler) filename = fOutputEventHandler->GetOutputFileName();
1522      else Fatal("OpenProofFile","No output container. Exiting.");
1523   }   
1524   TFile *f = NULL;
1525   if (fMode!=kProofAnalysis || !fSelector) {
1526     Fatal("OpenProofFile","Cannot open PROOF file %s: no PROOF or selector",filename.Data());
1527     return NULL;
1528   } 
1529   if (fSpecialOutputLocation.Length()) {
1530     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1531     if (f) {
1532       // Check if option "UPDATE" was preserved 
1533       TString opt(option);
1534       opt.ToUpper();
1535       if ((opt=="UPDATE") && (opt!=f->GetOption()))
1536         ::Info("OpenProofFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1537     } else {
1538       f = new TFile(filename, option);
1539     }
1540     if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1541       cont->SetFile(f);
1542       // Cd to file
1543       f->cd();
1544       // Check for a folder request
1545       TString dir = cont->GetFolderName(); 
1546       if (dir.Length()) {
1547         if (!f->GetDirectory(dir)) f->mkdir(dir);
1548         f->cd(dir);
1549       }      
1550       return f;
1551     }
1552     Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1553     cont->SetFile(NULL);
1554     return NULL;       
1555   }
1556   // Check if there is already a proof output file in the output list
1557   TObject *pof = fSelector->GetOutputList()->FindObject(filename);
1558   if (pof) {
1559     // Get the actual file
1560     line = Form("((TProofOutputFile*)0x%lx)->GetFileName();", (ULong_t)pof);
1561     filename = (const char*)gROOT->ProcessLine(line);
1562     if (fDebug>1) {
1563       printf("File: %s already booked via TProofOutputFile\n", filename.Data());
1564     }  
1565     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1566     if (!f) Fatal("OpenProofFile", "Proof output file found but no file opened for %s", filename.Data());
1567     // Check if option "UPDATE" was preserved 
1568     TString opt(option);
1569     opt.ToUpper();
1570     if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1571       Fatal("OpenProofFile", "File %s already opened, but not in UPDATE mode!", cont->GetFileName());
1572   } else {
1573     if (cont->IsRegisterDataset()) {
1574       TString dsetName = filename;
1575       dsetName.ReplaceAll(".root", cont->GetTitle());
1576       dsetName.ReplaceAll(":","_");
1577       if (fDebug>1) printf("Booking dataset: %s\n", dsetName.Data());
1578       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\", \"DROV\", \"%s\");", filename.Data(), dsetName.Data());
1579     } else {
1580       if (fDebug>1) printf("Booking TProofOutputFile: %s to be merged\n", filename.Data());
1581       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\");", filename.Data());
1582     }
1583     if (fDebug > 1) printf("=== %s\n", line.Data());
1584     gROOT->ProcessLine(line);
1585     line = Form("pf->OpenFile(\"%s\");", option);
1586     gROOT->ProcessLine(line);
1587     f = gFile;
1588     if (fDebug > 1) {
1589       gROOT->ProcessLine("pf->Print()");
1590       printf(" == proof file name: %s", f->GetName());
1591     }   
1592     // Add to proof output list
1593     line = Form("((TList*)0x%lx)->Add(pf);",(ULong_t)fSelector->GetOutputList());
1594     if (fDebug > 1) printf("=== %s\n", line.Data());
1595     gROOT->ProcessLine(line);
1596   }
1597   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1598     cont->SetFile(f);
1599     // Cd to file
1600     f->cd();
1601     // Check for a folder request
1602     TString dir = cont->GetFolderName(); 
1603     if (!dir.IsNull()) {
1604       if (!f->GetDirectory(dir)) f->mkdir(dir);
1605       f->cd(dir);
1606     }
1607     return f;
1608   }
1609   Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1610   cont->SetFile(NULL);  
1611   return NULL;
1612 }   
1613
1614 //______________________________________________________________________________
1615 void AliAnalysisManager::ExecAnalysis(Option_t *option)
1616 {
1617 // Execute analysis.
1618    static Long64_t ncalls = 0;
1619    if (fDebug > 0) printf("MGR: Processing event #%lld\n", ncalls);
1620    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1621    if (getsysInfo && ((ncalls%fNSysInfo)==0)) AliSysInfo::AddStamp("Exec_start", (Int_t)ncalls);
1622    ncalls++;
1623    if (!fInitOK) {
1624      Error("ExecAnalysis", "Analysis manager was not initialized !");
1625       return;
1626    }   
1627    AliAnalysisTask *task;
1628    // Check if the top tree is active.
1629    if (fTree) {
1630       TIter next(fTasks);
1631    // De-activate all tasks
1632       while ((task=(AliAnalysisTask*)next())) task->SetActive(kFALSE);
1633       AliAnalysisDataContainer *cont = fCommonInput;
1634       if (!cont) cont = (AliAnalysisDataContainer*)fInputs->At(0);
1635       if (!cont) {
1636               Error("ExecAnalysis","Cannot execute analysis in TSelector mode without at least one top container");
1637          return;
1638       }   
1639       cont->SetData(fTree); // This will notify all consumers
1640       Long64_t entry = fTree->GetTree()->GetReadEntry();
1641       
1642 //
1643 //    Call BeginEvent() for optional input/output and MC services 
1644       if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(entry);
1645       if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(entry);
1646       if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(entry);
1647       if (getsysInfo && ((ncalls%fNSysInfo)==0)) 
1648          AliSysInfo::AddStamp("Handlers_BeginEvent",(Int_t)ncalls, 1000, 0);
1649 //
1650 //    Execute the tasks
1651 //      TIter next1(cont->GetConsumers());
1652       TIter next1(fTopTasks);
1653       Int_t itask = 0;
1654       while ((task=(AliAnalysisTask*)next1())) {
1655          if (fDebug >1) {
1656             cout << "    Executing task " << task->GetName() << endl;
1657          }       
1658          task->ExecuteTask(option);
1659          if (getsysInfo && ((ncalls%fNSysInfo)==0)) 
1660             AliSysInfo::AddStamp(task->ClassName(),(Int_t)ncalls, itask, 1);
1661          itask++;   
1662       }
1663 //
1664 //    Call FinishEvent() for optional output and MC services 
1665       if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
1666       if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
1667       if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
1668       // Gather system information if requested
1669       if (getsysInfo && ((ncalls%fNSysInfo)==0)) 
1670          AliSysInfo::AddStamp("Handlers_FinishEvent",(Int_t)ncalls, 1000, 1);
1671       return;
1672    }   
1673    // The event loop is not controlled by TSelector   
1674 //
1675 //  Call BeginEvent() for optional input/output and MC services 
1676    if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(-1);
1677    if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(-1);
1678    if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(-1);
1679    if (getsysInfo && ((ncalls%fNSysInfo)==0)) 
1680       AliSysInfo::AddStamp("Handlers_BeginEvent",(Int_t)ncalls, 1000, 0);
1681    TIter next2(fTopTasks);
1682    while ((task=(AliAnalysisTask*)next2())) {
1683       task->SetActive(kTRUE);
1684       if (fDebug > 1) {
1685          cout << "    Executing task " << task->GetName() << endl;
1686       }   
1687       task->ExecuteTask(option);
1688    }   
1689 //
1690 // Call FinishEvent() for optional output and MC services 
1691    if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
1692    if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
1693    if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
1694    if (getsysInfo && ((ncalls%fNSysInfo)==0)) 
1695       AliSysInfo::AddStamp("Handlers_FinishEvent",(Int_t)ncalls, 1000, 1);
1696 }
1697
1698 //______________________________________________________________________________
1699 void AliAnalysisManager::SetInputEventHandler(AliVEventHandler* const handler)
1700 {
1701 // Set the input event handler and create a container for it.
1702    fInputEventHandler   = handler;
1703    fCommonInput = CreateContainer("cAUTO_INPUT", TChain::Class(), AliAnalysisManager::kInputContainer);
1704 //   Warning("SetInputEventHandler", " An automatic input container for the input chain was created.\nPlease use: mgr->GetCommonInputContainer() to access it.");
1705 }
1706
1707 //______________________________________________________________________________
1708 void AliAnalysisManager::SetOutputEventHandler(AliVEventHandler* const handler)
1709 {
1710 // Set the input event handler and create a container for it.
1711    fOutputEventHandler   = handler;
1712    fCommonOutput = CreateContainer("cAUTO_OUTPUT", TTree::Class(), AliAnalysisManager::kOutputContainer, "default");
1713    fCommonOutput->SetSpecialOutput();
1714 //   Warning("SetOutputEventHandler", " An automatic output container for the output tree was created.\nPlease use: mgr->GetCommonOutputContainer() to access it.");
1715 }
1716
1717 //______________________________________________________________________________
1718 void AliAnalysisManager::RegisterExtraFile(const char *fname)
1719 {
1720 // This method is used externally to register output files which are not
1721 // connected to any output container, so that the manager can properly register,
1722 // retrieve or merge them when running in distributed mode. The file names are
1723 // separated by blancs. The method has to be called in MyAnalysisTask::LocalInit().
1724    if (fExtraFiles.Length()) fExtraFiles += " ";
1725    fExtraFiles += fname;
1726 }
1727
1728 //______________________________________________________________________________
1729 Bool_t AliAnalysisManager::GetFileFromWrapper(const char *filename, const TList *source)
1730 {
1731 // Copy a file from the location specified ina the wrapper with the same name from the source list.
1732    char fullPath[512];
1733    char chUrl[512];
1734    TObject *pof =  source->FindObject(filename);
1735    if (!pof || !pof->InheritsFrom("TProofOutputFile")) {
1736       Error("GetFileFromWrapper", "TProofOutputFile object not found in output list for file %s", filename);
1737       return kFALSE;
1738    }
1739    gROOT->ProcessLine(Form("sprintf((char*)0x%lx, \"%%s\", ((TProofOutputFile*)0x%lx)->GetOutputFileName();)", fullPath, pof));
1740    gROOT->ProcessLine(Form("sprintf((char*)0x%lx, \"%%s\", gProof->GetUrl();)", chUrl));
1741    TString clientUrl(chUrl);
1742    TString fullPath_str(fullPath);
1743    if (clientUrl.Contains("localhost")){
1744       TObjArray* array = fullPath_str.Tokenize ( "//" );
1745       TObjString *strobj = ( TObjString *)array->At(1);
1746       TObjArray* arrayPort = strobj->GetString().Tokenize ( ":" );
1747       TObjString *strobjPort = ( TObjString *) arrayPort->At(1);
1748       fullPath_str.ReplaceAll(strobj->GetString().Data(),"localhost:PORT");
1749       fullPath_str.ReplaceAll(":PORT",Form(":%s",strobjPort->GetString().Data()));
1750       if (fDebug > 1) Info("GetFileFromWrapper","Using tunnel from %s to %s",fullPath_str.Data(),filename);
1751       delete arrayPort;
1752       delete array;
1753    }
1754    if (fDebug > 1) 
1755       Info("GetFileFromWrapper","Copying file %s from PROOF scratch space", fullPath_str.Data());
1756    Bool_t gotit = TFile::Cp(fullPath_str.Data(), filename); 
1757    if (!gotit)
1758       Error("GetFileFromWrapper", "Could not get file %s from proof scratch space", filename);
1759    return gotit;
1760 }
1761
1762 //______________________________________________________________________________
1763 void AliAnalysisManager::GetAnalysisTypeString(TString &type) const
1764 {
1765 // Fill analysis type in the provided string.
1766    switch (fMode) {
1767       case kLocalAnalysis:
1768          type = "local";
1769          return;
1770       case kProofAnalysis:
1771          type = "proof";
1772          return;
1773       case kGridAnalysis:
1774          type = "grid";
1775          return;
1776       case kMixingAnalysis:
1777          type = "mix";
1778    }
1779 }
1780
1781 //______________________________________________________________________________
1782 Bool_t AliAnalysisManager::ValidateOutputFiles() const
1783 {
1784 // Validate all output files.
1785    TIter next(fOutputs);
1786    AliAnalysisDataContainer *output;
1787    TDirectory *cdir = gDirectory;
1788    TString openedFiles;
1789    while ((output=(AliAnalysisDataContainer*)next())) {
1790       if (output->IsRegisterDataset()) continue;
1791       TString filename = output->GetFileName();
1792       if (filename == "default") {
1793          if (!fOutputEventHandler) continue;
1794          filename = fOutputEventHandler->GetOutputFileName();
1795          // Main AOD may not be there
1796          if (gSystem->AccessPathName(filename)) continue;
1797       }
1798       // Check if the file is closed
1799       if (openedFiles.Contains(filename)) continue;;
1800       TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1801       if (file) {
1802          Warning("ValidateOutputs", "File %s was not closed. Closing.", filename.Data());
1803          file->Close();
1804       }
1805       file = TFile::Open(filename);
1806       if (!file || file->IsZombie() || file->TestBit(TFile::kRecovered)) {
1807          Error("ValidateOutputs", "Output file <%s> was not created or invalid", filename.Data());
1808          cdir->cd();
1809          return kFALSE;
1810       }
1811       file->Close();
1812       openedFiles += filename;
1813       openedFiles += " ";
1814    }
1815    cdir->cd();
1816    return kTRUE;
1817 }   
1818
1819 //______________________________________________________________________________
1820 void AliAnalysisManager::ProgressBar(const char *opname, Long64_t current, Long64_t size, TStopwatch * const watch, Bool_t last, Bool_t refresh)
1821 {
1822 // Implements a nice text mode progress bar.
1823    static Long64_t icount = 0;
1824    static TString oname;
1825    static TString nname;
1826    static Long64_t ocurrent = 0;
1827    static Long64_t osize = 0;
1828    static Int_t oseconds = 0;
1829    static TStopwatch *owatch = 0;
1830    static Bool_t oneoftwo = kFALSE;
1831    static Int_t nrefresh = 0;
1832    static Int_t nchecks = 0;
1833    const char symbol[4] = {'=','\\','|','/'}; 
1834    char progress[11] = "          ";
1835    Int_t ichar = icount%4;
1836    
1837    if (!refresh) {
1838       nrefresh = 0;
1839       if (!size) return;
1840       owatch = watch;
1841       oname = opname;
1842       ocurrent = TMath::Abs(current);
1843       osize = TMath::Abs(size);
1844       if (ocurrent > osize) ocurrent=osize;
1845    } else {
1846       nrefresh++;
1847       if (!osize) return;
1848    }     
1849    icount++;
1850    Double_t time = 0.;
1851    Int_t hours = 0;
1852    Int_t minutes = 0;
1853    Int_t seconds = 0;
1854    if (owatch && !last) {
1855       owatch->Stop();
1856       time = owatch->RealTime();
1857       hours = (Int_t)(time/3600.);
1858       time -= 3600*hours;
1859       minutes = (Int_t)(time/60.);
1860       time -= 60*minutes;
1861       seconds = (Int_t)time;
1862       if (refresh)  {
1863          if (oseconds==seconds) {
1864             owatch->Continue();
1865             return;
1866          }
1867          oneoftwo = !oneoftwo;   
1868       }
1869       oseconds = seconds;   
1870    }
1871    if (refresh && oneoftwo) {
1872       nname = oname;
1873       if (nchecks <= 0) nchecks = nrefresh+1;
1874       Int_t pctdone = (Int_t)(100.*nrefresh/nchecks);
1875       oname = Form("     == %d%% ==", pctdone);
1876    }         
1877    Double_t percent = 100.0*ocurrent/osize;
1878    Int_t nchar = Int_t(percent/10);
1879    if (nchar>10) nchar=10;
1880    Int_t i;
1881    for (i=0; i<nchar; i++)  progress[i] = '=';
1882    progress[nchar] = symbol[ichar];
1883    for (i=nchar+1; i<10; i++) progress[i] = ' ';
1884    progress[10] = '\0';
1885    oname += "                    ";
1886    oname.Remove(20);
1887    if(size<10000) fprintf(stderr, "%s [%10s] %4lld ", oname.Data(), progress, ocurrent);
1888    else if(size<100000) fprintf(stderr, "%s [%10s] %5lld ",oname.Data(), progress, ocurrent);
1889    else fprintf(stderr, "%s [%10s] %7lld ",oname.Data(), progress, ocurrent);
1890    if (time>0.) fprintf(stderr, "[%6.2f %%]   TIME %.2d:%.2d:%.2d             \r", percent, hours, minutes, seconds);
1891    else fprintf(stderr, "[%6.2f %%]\r", percent);
1892    if (refresh && oneoftwo) oname = nname;
1893    if (owatch) owatch->Continue();
1894    if (last) {
1895       icount = 0;
1896       owatch = 0;
1897       ocurrent = 0;
1898       osize = 0;
1899       oseconds = 0;
1900       oneoftwo = kFALSE;
1901       nrefresh = 0;
1902       fprintf(stderr, "\n");
1903    }   
1904 }