Effective C++ changes (Andrei)
[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 "TClass.h"
29 #include "AliLog.h"
30
31 #include "AliAnalysisManager.h"
32 #include "AliAnalysisTask.h"
33 #include "AliAnalysisDataContainer.h"
34 #include "AliAnalysisDataSlot.h"
35
36 ClassImp(AliAnalysisManager)
37
38 //______________________________________________________________________________
39 AliAnalysisManager::AliAnalysisManager() : TSelector(),
40                     fInitOK(kFALSE),
41                     fContainers(NULL),
42                     fInputs(NULL),
43                     fOutputs(NULL),
44                     fTasks(NULL),
45                     fTopTasks(NULL),
46                     fZombies(NULL)
47 {
48 // Default constructor.
49    if (TClass::IsCallingNew() != TClass::kDummyNew) {
50       fContainers = new TObjArray();
51       fInputs     = new TObjArray();
52       fOutputs    = new TObjArray();  
53       fTasks      = new TObjArray();
54       fTopTasks   = new TObjArray();
55       fZombies    = new TObjArray();
56 //      fStatus     = new AliAnalysisInfo(this);
57    }
58 }
59
60 //______________________________________________________________________________
61 AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other)
62                    :TSelector(other),
63                     fInitOK(kFALSE),
64                     fContainers(NULL),
65                     fInputs(NULL),
66                     fOutputs(NULL),
67                     fTasks(NULL),
68                     fTopTasks(NULL),
69                     fZombies(NULL)
70 {
71 // Copy constructor.
72    fInitOK     = other.fInitOK;
73    fContainers = new TObjArray(*other.fContainers);
74    fInputs     = new TObjArray(*other.fInputs);
75    fOutputs    = new TObjArray(*other.fOutputs);
76    fTasks      = new TObjArray(*other.fTasks);
77    fTopTasks   = new TObjArray(*other.fTopTasks);
78    fZombies    = new TObjArray(*other.fZombies);
79 //   fStatus     = new AliAnalysisInfo(this);
80 }
81    
82 //______________________________________________________________________________
83 AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other)
84 {
85 // Assignment
86    if (&other != this) {
87       TSelector::operator=(other);
88       fInitOK     = other.fInitOK;
89       fContainers = new TObjArray(*other.fContainers);
90       fInputs     = new TObjArray(*other.fInputs);
91       fOutputs    = new TObjArray(*other.fOutputs);
92       fTasks      = new TObjArray(*other.fTasks);
93       fTopTasks   = new TObjArray(*other.fTopTasks);
94       fZombies    = new TObjArray(*other.fZombies);
95 //      fStatus     = new AliAnalysisInfo(this);
96    }
97    return *this;
98 }
99
100 //______________________________________________________________________________
101 AliAnalysisManager::~AliAnalysisManager()
102 {
103 // Destructor.
104    if (fContainers) {fContainers->Delete(); delete fContainers;}
105    if (fInputs) delete fInputs;
106    if (fOutputs) delete fOutputs;
107    if (fTasks) {fTasks->Delete(); delete fTasks;}
108    if (fTopTasks) delete fTopTasks;
109    if (fZombies) delete fZombies;
110 }
111
112 //______________________________________________________________________________
113 void AliAnalysisManager::Init(TTree */*tree*/)
114 {
115   // The Init() function is called when the selector needs to initialize
116   // a new tree or chain. Typically here the branch addresses of the tree
117   // will be set. It is normaly not necessary to make changes to the
118   // generated code, but the routine can be extended by the user if needed.
119   // Init() will be called many times when running with PROOF.
120 }
121
122 //______________________________________________________________________________
123 void AliAnalysisManager::Begin(TTree */*tree*/)
124 {
125   // The Begin() function is called at the start of the query.
126   // When running with PROOF Begin() is only called on the client.
127   // The tree argument is deprecated (on PROOF 0 is passed).
128 }
129
130 //______________________________________________________________________________
131 void AliAnalysisManager::SlaveBegin(TTree */*tree*/)
132 {
133   // The SlaveBegin() function is called after the Begin() function.
134   // When running with PROOF SlaveBegin() is called on each slave server.
135   // The tree argument is deprecated (on PROOF 0 is passed).
136 }
137
138 //______________________________________________________________________________
139 Bool_t AliAnalysisManager::Process(Long64_t /*entry*/)
140 {
141   // The Process() function is called for each entry in the tree (or possibly
142   // keyed object in the case of PROOF) to be processed. The entry argument
143   // specifies which entry in the currently loaded tree is to be processed.
144   // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()
145   // to read either all or the required parts of the data. When processing
146   // keyed objects with PROOF, the object is already loaded and is available
147   // via the fObject pointer.
148   //
149   // This function should contain the "body" of the analysis. It can contain
150   // simple or elaborate selection criteria, run algorithms on the data
151   // of the event and typically fill histograms.
152
153   // WARNING when a selector is used with a TChain, you must use
154   //  the pointer to the current TTree to call GetEntry(entry).
155   //  The entry is always the local entry number in the current tree.
156   //  Assuming that fChain is the pointer to the TChain being processed,
157   //  use fChain->GetTree()->GetEntry(entry).
158   return kFALSE;
159 }
160
161 //______________________________________________________________________________
162 void AliAnalysisManager::SlaveTerminate()
163 {
164   // The SlaveTerminate() function is called after all entries or objects
165   // have been processed. When running with PROOF SlaveTerminate() is called
166   // on each slave server.
167 }
168
169 //______________________________________________________________________________
170 void AliAnalysisManager::Terminate()
171 {
172   // The Terminate() function is the last function to be called during
173   // a query. It always runs on the client, it can be used to present
174   // the results graphically or save the results to file.
175 }
176
177 //______________________________________________________________________________
178 void AliAnalysisManager::AddTask(AliAnalysisTask *task)
179 {
180 // Adds a user task to the global list of tasks.
181    task->SetActive(kFALSE);
182    fTasks->Add(task);
183 }  
184
185 //______________________________________________________________________________
186 AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const
187 {
188 // Retreive task by name.
189    if (!fTasks) return NULL;
190    return (AliAnalysisTask*)fTasks->FindObject(name);
191 }
192
193 //______________________________________________________________________________
194 AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name, 
195                                 TClass *datatype, EAliAnalysisContType type)
196 {
197 // Create a data container of a certain type. Types can be:
198 //   kNormalContainer  = 0, used to exchange date between tasks
199 //   kInputContainer   = 1, used to store input data
200 //   kOutputContainer  = 2, used for posting results
201    AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
202    fContainers->Add(cont);
203    switch (type) {
204       case kInputContainer:
205          fInputs->Add(cont);
206          break;
207       case kOutputContainer:
208          fOutputs->Add(cont);
209          break;
210       case kNormalContainer:
211          break;   
212    }
213    return cont;
214 }
215          
216 //______________________________________________________________________________
217 Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
218                                         AliAnalysisDataContainer *cont)
219 {
220 // Connect input of an existing task to a data container.
221    if (!fTasks->FindObject(task)) {
222       AddTask(task);
223       AliInfo(Form("Task %s not registered. Now owned by analysis manager", task->GetName()));
224    } 
225    Bool_t connected = task->ConnectInput(islot, cont);
226    return connected;
227 }   
228
229 //______________________________________________________________________________
230 Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
231                                         AliAnalysisDataContainer *cont)
232 {
233 // Connect output of an existing task to a data container.
234    if (!fTasks->FindObject(task)) {
235       AddTask(task);
236       AliInfo(Form("Task %s not registered. Now owned by analysis manager", task->GetName()));
237    } 
238    Bool_t connected = task->ConnectOutput(islot, cont);
239    return connected;
240 }   
241                                
242 //______________________________________________________________________________
243 void AliAnalysisManager::CleanContainers()
244 {
245 // Clean data from all containers that have already finished all client tasks.
246    TIter next(fContainers);
247    AliAnalysisDataContainer *cont;
248    while ((cont=(AliAnalysisDataContainer *)next())) {
249       if (cont->IsOwnedData() && 
250           cont->IsDataReady() && 
251           cont->ClientsExecuted()) cont->DeleteData();
252    }
253 }
254
255 //______________________________________________________________________________
256 Bool_t AliAnalysisManager::InitAnalysis()
257 {
258 // Initialization of analysis chain of tasks. Should be called after all tasks
259 // and data containers are properly connected
260    // Check for input/output containers
261    fInitOK = kFALSE;
262    if (!fInputs->GetEntriesFast()) {
263       AliError("No input container defined. At least one container should store input data");
264       return kFALSE;
265    }   
266    if (!fOutputs->GetEntriesFast()) {
267       AliError("No output container defined. At least one container should store output data");
268       return kFALSE;
269    }   
270    // Check for top tasks (depending only on input data containers)
271    if (!fTasks->First()) {
272       AliError("Analysis have no tasks !");
273       return kFALSE;
274    }   
275    TIter next(fTasks);
276    AliAnalysisTask *task;
277    AliAnalysisDataContainer *cont;
278    Int_t ntop = 0;
279    Int_t nzombies = 0;
280    Bool_t is_zombie = kFALSE;
281    Bool_t is_top = kTRUE;
282    Int_t i;
283    while ((task=(AliAnalysisTask*)next())) {
284       is_top = kTRUE;
285       is_zombie = kFALSE;
286       Int_t ninputs = task->GetNinputs();
287       if (!ninputs) {
288          task->SetZombie();
289          fZombies->Add(task);
290          nzombies++;
291          AliWarning(Form("Task %s has no input slots defined ! Declared zombie...",task->GetName()));
292          continue;
293       }
294       for (i=0; i<ninputs; i++) {
295          cont = task->GetInputSlot(i)->GetContainer();
296          if (!cont) {
297             if (!is_zombie) {
298                task->SetZombie();
299                fZombies->Add(task);
300                nzombies++;
301                is_zombie = kTRUE;
302             }   
303             AliWarning(Form("Input slot %i of task %s has no container connected ! Declared zombie...",
304                        i,task->GetName()));
305          }
306          if (is_zombie) continue;
307          // Check if cont is an input container
308          if (is_top && !fInputs->FindObject(cont)) is_top=kFALSE;
309          // Connect to parent task
310       }
311       if (is_top) {
312          ntop++;
313          fTopTasks->Add(task);
314       }
315    }
316    if (!ntop) {
317       AliError("No top task defined. At least one task should be connected only to input containers");
318       return kFALSE;
319    }                        
320    // Check now if there are orphan tasks
321    for (i=0; i<ntop; i++) {
322       task = (AliAnalysisTask*)fTopTasks->At(i);
323       task->SetUsed();
324    }
325    Int_t norphans = 0;
326    next.Reset();
327    while ((task=(AliAnalysisTask*)next())) {
328       if (!task->IsUsed()) {
329          norphans++;
330          AliWarning(Form("Task %s is orphan",task->GetName()));
331       }   
332    }          
333    // Check the task hierarchy (no parent task should depend on data provided
334    // by a daughter task)
335    for (i=0; i<ntop; i++) {
336       task = (AliAnalysisTask*)fTopTasks->At(i);
337       if (task->CheckCircularDeps()) {
338          AliError("Found illegal circular dependencies between following tasks:");
339          PrintStatus("dep");
340          return kFALSE;
341       }   
342    }
343    return kTRUE;
344 }   
345
346 //______________________________________________________________________________
347 void AliAnalysisManager::PrintStatus(Option_t *option) const
348 {
349 // Print task hierarchy.
350    TIter next(fTopTasks);
351    AliAnalysisTask *task;
352    while ((task=(AliAnalysisTask*)next()))
353       task->PrintTask(option);
354 }
355
356 //______________________________________________________________________________
357 void AliAnalysisManager::ResetAnalysis()
358 {
359 // Reset all execution flags and clean containers.
360    CleanContainers();
361 }
362
363 //______________________________________________________________________________
364 void AliAnalysisManager::ExecAnalysis(Option_t *option)
365 {
366 // Execute analysis.
367    TIter next(fTopTasks);
368    AliAnalysisTask *task;
369    while ((task=(AliAnalysisTask*)next()))
370       task->ExecuteTask(option);
371 }
372
373 //______________________________________________________________________________
374 void AliAnalysisManager::FinishAnalysis()
375 {
376 // Finish analysis.
377 }