7e29eb7b95fd9f91f72bdb548aa163437edafee5
[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 <TClass.h>
31 #include <TFile.h>
32 #include <TMethodCall.h>
33 #include <TChain.h>
34 #include <TSystem.h>
35 #include <TROOT.h>
36
37 #include "AliAnalysisTask.h"
38 #include "AliAnalysisDataContainer.h"
39 #include "AliAnalysisDataSlot.h"
40 #include "AliAnalysisManager.h"
41
42 ClassImp(AliAnalysisManager)
43
44 AliAnalysisManager *AliAnalysisManager::fgAnalysisManager = NULL;
45
46 //______________________________________________________________________________
47 AliAnalysisManager::AliAnalysisManager() 
48                    :TNamed(),
49                     fTree(NULL),
50                     fCurrentEntry(-1),
51                     fMode(kLocalAnalysis),
52                     fInitOK(kFALSE),
53                     fTasks(NULL),
54                     fTopTasks(NULL),
55                     fZombies(NULL),
56                     fContainers(NULL),
57                     fInputs(NULL),
58                     fOutputs(NULL)
59 {
60 // Dummy constructor.
61    fgAnalysisManager = this;
62 }
63
64 //______________________________________________________________________________
65 AliAnalysisManager::AliAnalysisManager(const char *name, const char *title)
66                    :TNamed(name,title),
67                     fTree(NULL),
68                     fCurrentEntry(-1),
69                     fMode(kLocalAnalysis),
70                     fInitOK(kFALSE),
71                     fDebug(0),
72                     fTasks(NULL),
73                     fTopTasks(NULL),
74                     fZombies(NULL),
75                     fContainers(NULL),
76                     fInputs(NULL),
77                     fOutputs(NULL)
78 {
79 // Default constructor.
80    fgAnalysisManager = this;
81    fTasks      = new TObjArray();
82    fTopTasks   = new TObjArray();
83    fZombies    = new TObjArray();
84    fContainers = new TObjArray();
85    fInputs     = new TObjArray();
86    fOutputs    = new TObjArray();
87 }
88
89 //______________________________________________________________________________
90 AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other)
91                    :TNamed(other),
92                     fTree(NULL),
93                     fCurrentEntry(-1),
94                     fMode(other.fMode),
95                     fInitOK(other.fInitOK),
96                     fDebug(other.fDebug),
97                     fTasks(NULL),
98                     fTopTasks(NULL),
99                     fZombies(NULL),
100                     fContainers(NULL),
101                     fInputs(NULL),
102                     fOutputs(NULL)
103 {
104 // Copy constructor.
105    fTasks      = new TObjArray(*other.fTasks);
106    fTopTasks   = new TObjArray(*other.fTopTasks);
107    fZombies    = new TObjArray(*other.fZombies);
108    fContainers = new TObjArray(*other.fContainers);
109    fInputs     = new TObjArray(*other.fInputs);
110    fOutputs    = new TObjArray(*other.fOutputs);
111    fgAnalysisManager = this;
112 }
113    
114 //______________________________________________________________________________
115 AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other)
116 {
117 // Assignment
118    if (&other != this) {
119       TNamed::operator=(other);
120       fTree       = NULL;
121       fCurrentEntry = -1;
122       fMode       = other.fMode;
123       fInitOK     = other.fInitOK;
124       fDebug      = other.fDebug;
125       fTasks      = new TObjArray(*other.fTasks);
126       fTopTasks   = new TObjArray(*other.fTopTasks);
127       fZombies    = new TObjArray(*other.fZombies);
128       fContainers = new TObjArray(*other.fContainers);
129       fInputs     = new TObjArray(*other.fInputs);
130       fOutputs    = new TObjArray(*other.fOutputs);
131       fgAnalysisManager = this;
132    }
133    return *this;
134 }
135
136 //______________________________________________________________________________
137 AliAnalysisManager::~AliAnalysisManager()
138 {
139 // Destructor.
140    if (fTasks) {fTasks->Delete(); delete fTasks;}
141    if (fTopTasks) delete fTopTasks;
142    if (fZombies) delete fZombies;
143    if (fContainers) {fContainers->Delete(); delete fContainers;}
144    if (fInputs) delete fInputs;
145    if (fOutputs) delete fOutputs;
146    if (fgAnalysisManager==this) fgAnalysisManager = NULL;
147 }
148
149 //______________________________________________________________________________
150 Int_t AliAnalysisManager::GetEntry(Long64_t entry, Int_t getall)
151 {
152 // Read one entry of the tree or a whole branch.
153    if (fDebug > 1) {
154       cout << "== AliAnalysisManager::GetEntry()" << endl;
155    }   
156    fCurrentEntry = entry;
157    return fTree ? fTree->GetTree()->GetEntry(entry, getall) : 0;
158 }
159    
160 //______________________________________________________________________________
161 void AliAnalysisManager::Init(TTree *tree)
162 {
163   // The Init() function is called when the selector needs to initialize
164   // a new tree or chain. Typically here the branch addresses of the tree
165   // will be set. It is normaly not necessary to make changes to the
166   // generated code, but the routine can be extended by the user if needed.
167   // Init() will be called many times when running with PROOF.
168    if (!tree) return;
169    if (fDebug > 1) {
170       printf("->AliAnalysisManager::Init(%s)\n", tree->GetName());
171    }
172    if (!fInitOK) InitAnalysis();
173    if (!fInitOK) return;
174    fTree = tree;
175    AliAnalysisDataContainer *top = (AliAnalysisDataContainer*)fInputs->At(0);
176    if (!top) {
177       cout<<"Error: No top input container !" <<endl;
178       return;
179    }
180    top->SetData(tree);
181    if (fDebug > 1) {
182       printf("<-AliAnalysisManager::Init(%s)\n", tree->GetName());
183    }
184 }
185
186 //______________________________________________________________________________
187 void AliAnalysisManager::Begin(TTree *tree)
188 {
189   // The Begin() function is called at the start of the query.
190   // When running with PROOF Begin() is only called on the client.
191   // The tree argument is deprecated (on PROOF 0 is passed).
192    if (fDebug > 1) {
193       cout << "AliAnalysisManager::Begin()" << endl;
194    }   
195    Init(tree);
196 }
197
198 //______________________________________________________________________________
199 void AliAnalysisManager::SlaveBegin(TTree *tree)
200 {
201   // The SlaveBegin() function is called after the Begin() function.
202   // When running with PROOF SlaveBegin() is called on each slave server.
203   // The tree argument is deprecated (on PROOF 0 is passed).
204    if (fDebug > 1) {
205       cout << "->AliAnalysisManager::SlaveBegin()" << endl;
206    }
207
208    TIter next(fTasks);
209    AliAnalysisTask *task;
210    // Call CreateOutputObjects for all tasks
211    while ((task=(AliAnalysisTask*)next())) 
212       task->CreateOutputObjects();
213    if (fMode == kLocalAnalysis) Init(tree);   
214    if (fDebug > 1) {
215       cout << "<-AliAnalysisManager::SlaveBegin()" << endl;
216    }
217 }
218
219 //______________________________________________________________________________
220 Bool_t AliAnalysisManager::Notify()
221 {
222    // The Notify() function is called when a new file is opened. This
223    // can be either for a new TTree in a TChain or when when a new TTree
224    // is started when using PROOF. It is normaly not necessary to make changes
225    // to the generated code, but the routine can be extended by the
226    // user if needed. The return value is currently not used.
227    if (fTree) {
228       TFile *curfile = fTree->GetCurrentFile();
229       if (curfile && fDebug>1) printf("AliAnalysisManager::Notify() file: %s\n", curfile->GetName());
230       TIter next(fTasks);
231       AliAnalysisTask *task;
232       // Call Notify for all tasks
233       while ((task=(AliAnalysisTask*)next())) 
234          task->Notify();      
235    }
236    return kTRUE;
237 }    
238
239 //______________________________________________________________________________
240 Bool_t AliAnalysisManager::Process(Long64_t entry)
241 {
242   // The Process() function is called for each entry in the tree (or possibly
243   // keyed object in the case of PROOF) to be processed. The entry argument
244   // specifies which entry in the currently loaded tree is to be processed.
245   // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()
246   // to read either all or the required parts of the data. When processing
247   // keyed objects with PROOF, the object is already loaded and is available
248   // via the fObject pointer.
249   //
250   // This function should contain the "body" of the analysis. It can contain
251   // simple or elaborate selection criteria, run algorithms on the data
252   // of the event and typically fill histograms.
253
254   // WARNING when a selector is used with a TChain, you must use
255   //  the pointer to the current TTree to call GetEntry(entry).
256   //  The entry is always the local entry number in the current tree.
257   //  Assuming that fChain is the pointer to the TChain being processed,
258   //  use fChain->GetTree()->GetEntry(entry).
259    if (fDebug > 1) {
260       cout << "->AliAnalysisManager::Process()" << endl;
261    }
262    GetEntry(entry);
263    ExecAnalysis();
264    if (fDebug > 1) {
265       cout << "<-AliAnalysisManager::Process()" << endl;
266    }
267    return kTRUE;
268 }
269
270 //______________________________________________________________________________
271 void AliAnalysisManager::PackOutput(TList *target)
272 {
273   // Pack all output data containers in the output list. Called at SlaveTerminate
274   // stage in PROOF case for each slave.
275    if (fDebug > 1) {
276       cout << "->AliAnalysisManager::PackOutput()" << endl;
277    }   
278    if (!target) {
279       Error("PackOutput", "No target. Aborting.");
280       return;
281    }
282
283    if (fMode == kProofAnalysis) {
284       TIter next(fOutputs);
285       AliAnalysisDataContainer *output;
286       while ((output=(AliAnalysisDataContainer*)next())) {
287          if (fDebug > 1) printf("   Packing container %s...\n", output->GetName());
288          if (output->GetData()) target->Add(output->ExportData());
289       }
290    } 
291    if (fDebug > 1) {
292       printf("<-AliAnalysisManager::PackOutput: output list contains %d containers\n", target->GetSize());
293    }
294 }
295
296 //______________________________________________________________________________
297 void AliAnalysisManager::ImportWrappers(TList *source)
298 {
299 // Import data in output containers from wrappers coming in source.
300    if (fDebug > 1) {
301       cout << "->AliAnalysisManager::ImportWrappers()" << endl;
302    }   
303    TIter next(fOutputs);
304    AliAnalysisDataContainer *cont;
305    AliAnalysisDataWrapper   *wrap;
306    Int_t icont = 0;
307    while ((cont=(AliAnalysisDataContainer*)next())) {
308       wrap = (AliAnalysisDataWrapper*)source->FindObject(cont->GetName());
309       if (!wrap && fDebug>1) {
310          printf("(WW) ImportWrappers: container %s not found in analysis output !\n", cont->GetName());
311          continue;
312       }
313       icont++;
314       if (fDebug > 1) printf("   Importing data for container %s\n", wrap->GetName());
315       if (cont->GetFileName()) printf("    -> %s\n", cont->GetFileName());
316       cont->ImportData(wrap);
317    }         
318    if (fDebug > 1) {
319       cout << "<-AliAnalysisManager::ImportWrappers(): "<< icont << " containers imported" << endl;
320    }   
321 }
322
323 //______________________________________________________________________________
324 void AliAnalysisManager::UnpackOutput(TList *source)
325 {
326   // Called by AliAnalysisSelector::Terminate. Output containers should
327   // be in source in the same order as in fOutputs.
328    if (fDebug > 1) {
329       cout << "->AliAnalysisManager::UnpackOutput()" << endl;
330    }   
331    if (!source) {
332       Error("UnpackOutput", "No target. Aborting.");
333       return;
334    }
335    if (fDebug > 1) {
336       printf("   Source list contains %d containers\n", source->GetSize());
337    }   
338
339    if (fMode == kProofAnalysis) ImportWrappers(source);
340
341    TIter next(fOutputs);
342    AliAnalysisDataContainer *output;
343    while ((output=(AliAnalysisDataContainer*)next())) {
344       if (!output->GetData()) continue;
345       // Check if the output need to be written to a file.
346       const char *filename = output->GetFileName();
347       if (!filename || !strlen(filename)) continue;
348       TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
349       if (file) file->cd();
350       else      file = new TFile(filename, "RECREATE");
351       if (file->IsZombie()) continue;
352       // Reparent data to this file
353       TMethodCall callEnv;
354       if (output->GetData()->IsA())
355          callEnv.InitWithPrototype(output->GetData()->IsA(), "SetDirectory", "TDirectory*");
356       if (callEnv.IsValid()) {
357          callEnv.SetParam((Long_t) file);
358          callEnv.Execute(output->GetData());
359       }
360       output->GetData()->Write();      
361    }
362    if (fDebug > 1) {
363       cout << "<-AliAnalysisManager::UnpackOutput()" << endl;
364    }   
365 }
366
367 //______________________________________________________________________________
368 void AliAnalysisManager::Terminate()
369 {
370   // The Terminate() function is the last function to be called during
371   // a query. It always runs on the client, it can be used to present
372   // the results graphically.
373    if (fDebug > 1) {
374       cout << "->AliAnalysisManager::Terminate()" << endl;
375    }   
376    AliAnalysisTask *task;
377    TIter next(fTasks);
378    // Call Terminate() for tasks
379    while ((task=(AliAnalysisTask*)next())) task->Terminate();
380    if (fDebug > 1) {
381       cout << "<-AliAnalysisManager::Terminate()" << endl;
382    }   
383 }
384
385 //______________________________________________________________________________
386 void AliAnalysisManager::AddTask(AliAnalysisTask *task)
387 {
388 // Adds a user task to the global list of tasks.
389    task->SetActive(kFALSE);
390    fTasks->Add(task);
391 }  
392
393 //______________________________________________________________________________
394 AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const
395 {
396 // Retreive task by name.
397    if (!fTasks) return NULL;
398    return (AliAnalysisTask*)fTasks->FindObject(name);
399 }
400
401 //______________________________________________________________________________
402 AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name, 
403                                 TClass *datatype, EAliAnalysisContType type, const char *filename)
404 {
405 // Create a data container of a certain type. Types can be:
406 //   kExchangeContainer  = 0, used to exchange date between tasks
407 //   kInputContainer   = 1, used to store input data
408 //   kOutputContainer  = 2, used for posting results
409    AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
410    fContainers->Add(cont);
411    switch (type) {
412       case kInputContainer:
413          fInputs->Add(cont);
414          break;
415       case kOutputContainer:
416          if (fOutputs->FindObject(name)) printf("CreateContainer: warning: a container named %s existing !\n",name);
417          fOutputs->Add(cont);
418          if (filename && strlen(filename)) cont->SetFileName(filename);
419          break;
420       case kExchangeContainer:
421          break;   
422    }
423    return cont;
424 }
425          
426 //______________________________________________________________________________
427 Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
428                                         AliAnalysisDataContainer *cont)
429 {
430 // Connect input of an existing task to a data container.
431    if (!fTasks->FindObject(task)) {
432       AddTask(task);
433       Warning("ConnectInput", "Task %s not registered. Now owned by analysis manager", task->GetName());
434    } 
435    Bool_t connected = task->ConnectInput(islot, cont);
436    return connected;
437 }   
438
439 //______________________________________________________________________________
440 Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
441                                         AliAnalysisDataContainer *cont)
442 {
443 // Connect output of an existing task to a data container.
444    if (!fTasks->FindObject(task)) {
445       AddTask(task);
446       Warning("ConnectOutput", "Task %s not registered. Now owned by analysis manager", task->GetName());
447    } 
448    Bool_t connected = task->ConnectOutput(islot, cont);
449    return connected;
450 }   
451                                
452 //______________________________________________________________________________
453 void AliAnalysisManager::CleanContainers()
454 {
455 // Clean data from all containers that have already finished all client tasks.
456    TIter next(fContainers);
457    AliAnalysisDataContainer *cont;
458    while ((cont=(AliAnalysisDataContainer *)next())) {
459       if (cont->IsOwnedData() && 
460           cont->IsDataReady() && 
461           cont->ClientsExecuted()) cont->DeleteData();
462    }
463 }
464
465 //______________________________________________________________________________
466 Bool_t AliAnalysisManager::InitAnalysis()
467 {
468 // Initialization of analysis chain of tasks. Should be called after all tasks
469 // and data containers are properly connected
470    // Check for input/output containers
471    fInitOK = kFALSE;
472    // Check for top tasks (depending only on input data containers)
473    if (!fTasks->First()) {
474       Error("InitAnalysis", "Analysis has no tasks !");
475       return kFALSE;
476    }   
477    TIter next(fTasks);
478    AliAnalysisTask *task;
479    AliAnalysisDataContainer *cont;
480    Int_t ntop = 0;
481    Int_t nzombies = 0;
482    Bool_t iszombie = kFALSE;
483    Bool_t istop = kTRUE;
484    Int_t i;
485    while ((task=(AliAnalysisTask*)next())) {
486       istop = kTRUE;
487       iszombie = kFALSE;
488       Int_t ninputs = task->GetNinputs();
489       for (i=0; i<ninputs; i++) {
490          cont = task->GetInputSlot(i)->GetContainer();
491          if (!cont) {
492             if (!iszombie) {
493                task->SetZombie();
494                fZombies->Add(task);
495                nzombies++;
496                iszombie = kTRUE;
497             }   
498             Error("InitAnalysis", "Input slot %d of task %s has no container connected ! Declared zombie...", 
499                   i, task->GetName()); 
500          }
501          if (iszombie) continue;
502          // Check if cont is an input container
503          if (istop && !fInputs->FindObject(cont)) istop=kFALSE;
504          // Connect to parent task
505       }
506       if (istop) {
507          ntop++;
508          fTopTasks->Add(task);
509       }
510    }
511    if (!ntop) {
512       Error("InitAnalysis", "No top task defined. At least one task should be connected only to input containers");
513       return kFALSE;
514    }                        
515    // Check now if there are orphan tasks
516    for (i=0; i<ntop; i++) {
517       task = (AliAnalysisTask*)fTopTasks->At(i);
518       task->SetUsed();
519    }
520    Int_t norphans = 0;
521    next.Reset();
522    while ((task=(AliAnalysisTask*)next())) {
523       if (!task->IsUsed()) {
524          norphans++;
525          Warning("InitAnalysis", "Task %s is orphan", task->GetName());
526       }   
527    }          
528    // Check the task hierarchy (no parent task should depend on data provided
529    // by a daughter task)
530    for (i=0; i<ntop; i++) {
531       task = (AliAnalysisTask*)fTopTasks->At(i);
532       if (task->CheckCircularDeps()) {
533          Error("InitAnalysis", "Found illegal circular dependencies between following tasks:");
534          PrintStatus("dep");
535          return kFALSE;
536       }   
537    }
538    fInitOK = kTRUE;
539    return kTRUE;
540 }   
541
542 //______________________________________________________________________________
543 void AliAnalysisManager::PrintStatus(Option_t *option) const
544 {
545 // Print task hierarchy.
546    TIter next(fTopTasks);
547    AliAnalysisTask *task;
548    while ((task=(AliAnalysisTask*)next()))
549       task->PrintTask(option);
550 }
551
552 //______________________________________________________________________________
553 void AliAnalysisManager::ResetAnalysis()
554 {
555 // Reset all execution flags and clean containers.
556    CleanContainers();
557 }
558
559 //______________________________________________________________________________
560 void AliAnalysisManager::StartAnalysis(const char *type, TTree *tree)
561 {
562 // Start analysis for this manager. Analysis task can be: LOCAL, PROOF or GRID.
563    if (!fInitOK) {
564       Error("StartAnalysis","Analysis manager was not initialized !");
565       return;
566    }
567    if (fDebug>1) {
568       cout << "StartAnalysis: " << GetName() << endl;   
569    }   
570    TString anaType = type;
571    anaType.ToLower();
572    fMode = kLocalAnalysis;
573    if (tree) {
574       if (anaType.Contains("proof"))     fMode = kProofAnalysis;
575       else if (anaType.Contains("grid")) fMode = kGridAnalysis;
576    }
577    if (fMode == kGridAnalysis) {
578       Warning("StartAnalysis", "GRID analysis mode not implemented. Running local.");
579       fMode = kLocalAnalysis;
580    }
581    char line[128];   
582    // Disable by default all branches
583    if (tree) tree->SetBranchStatus("*",0);
584    TChain *chain = dynamic_cast<TChain*>(tree);
585    switch (fMode) {
586       case kLocalAnalysis:
587          if (!tree) {
588             TIter next(fTasks);
589             AliAnalysisTask *task;
590             // Call CreateOutputObjects for all tasks
591             while ((task=(AliAnalysisTask*)next())) task->CreateOutputObjects();
592             ExecAnalysis();
593             Terminate();
594             return;
595          } 
596          // Run tree-based analysis via AliAnalysisSelector  
597          gROOT->ProcessLine(".L AliAnalysisSelector.cxx+");
598          cout << "===== RUNNING LOCAL ANALYSIS " << GetName() << " ON TREE " << tree->GetName() << endl;
599          sprintf(line, "AliAnalysisSelector *selector = new AliAnalysisSelector((AliAnalysisManager*)0x%lx);",(ULong_t)this);
600          gROOT->ProcessLine(line);
601          sprintf(line, "((TTree*)0x%lx)->Process(selector);",(ULong_t)tree);
602          gROOT->ProcessLine(line);
603          break;
604       case kProofAnalysis:
605          if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
606             printf("StartAnalysis: no PROOF!!!\n");
607             return;
608          }   
609          sprintf(line, "gProof->AddInput((TObject*)0x%lx);", (ULong_t)this);
610          gROOT->ProcessLine(line);
611          if (chain) {
612             chain->SetProof();
613             cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON CHAIN " << chain->GetName() << endl;
614             chain->Process(gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/AliAnalysisSelector.cxx+"));
615          } else {
616             printf("StartAnalysis: no chain\n");
617             return;
618          }      
619          break;
620       case kGridAnalysis:
621          Warning("StartAnalysis", "GRID analysis mode not implemented. Running local.");
622    }   
623 }   
624
625 //______________________________________________________________________________
626 void AliAnalysisManager::ExecAnalysis(Option_t *option)
627 {
628 // Execute analysis.
629    if (!fInitOK) {
630      Error("ExecAnalysis", "Analysis manager was not initialized !");
631       return;
632    }   
633    AliAnalysisTask *task;
634    // Check if the top tree is active.
635    if (fTree) {
636       if (fDebug>1) {
637          printf("AliAnalysisManager::ExecAnalysis\n");
638       }   
639       TIter next(fTasks);
640    // De-activate all tasks
641       while ((task=(AliAnalysisTask*)next())) task->SetActive(kFALSE);
642       AliAnalysisDataContainer *cont = (AliAnalysisDataContainer*)fInputs->At(0);
643       if (!cont) {
644               Error("ExecAnalysis","Cannot execute analysis in TSelector mode without at least one top container");
645          return;
646       }   
647       cont->SetData(fTree); // This will notify all consumers
648       TIter next1(cont->GetConsumers());
649       while ((task=(AliAnalysisTask*)next1())) {
650 //         task->SetActive(kTRUE);
651          if (fDebug >1) {
652             cout << "    Executing task " << task->GetName() << endl;
653          }   
654          task->ExecuteTask(option);
655       }
656       return;
657    }   
658    // The event loop is not controlled by TSelector   
659    TIter next2(fTopTasks);
660    while ((task=(AliAnalysisTask*)next2())) {
661       task->SetActive(kTRUE);
662       if (fDebug > 1) {
663          cout << "    Executing task " << task->GetName() << endl;
664       }   
665       task->ExecuteTask(option);
666    }   
667 }
668
669 //______________________________________________________________________________
670 void AliAnalysisManager::FinishAnalysis()
671 {
672 // Finish analysis.
673 }