Effective C++ changes (Andrei)
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisTask.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 //   AliAnalysysTask - Class representing a basic analysis task. Any
21 // user-defined task should derive from it and implement the Exec() virtual
22 // method.
23 //==============================================================================
24 //
25 // A specific user analysis task have to derive from this class. The list of
26 // specific input and output slots have to be defined in the derived class ctor:
27 //
28 //   UserTask::UserTask(name, title)
29 //   {
30 //      DefineInput(0, TTree::Class());
31 //      DefineInput(1, TH1::Class());
32 //      ...
33 //      DefineOutput(0, TTree::Class());
34 //      DefineOutput(1, MyObject::Class());
35 //      ...
36 //   }
37 //
38 // An existing data contaner (AliAnalysisDataContainer) can be connected to the
39 // input/output slots of an analysis task. Containers should not be defined and
40 // connected by the derived analysis task, but from the level of AliAnalysisManager:
41 //
42 //   AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
43 //                                   AliAnalysisDataContainer *cont)
44 //   AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
45 //                                    AliAnalysisDataContainer *cont)
46 // To connect a slot to a data container, the data types declared by both must
47 // match.
48 //==============================================================================
49
50 #include "TClass.h"
51
52 #include "AliLog.h"
53 #include "AliAnalysisTask.h"
54 #include "AliAnalysisDataSlot.h"
55 #include "AliAnalysisDataContainer.h"
56
57 ClassImp(AliAnalysisTask)
58
59 //______________________________________________________________________________
60 AliAnalysisTask::AliAnalysisTask()
61                 :fReady(kFALSE),
62                  fNinputs(0),
63                  fNoutputs(0),
64                  fOutputReady(NULL),
65                  fPublishedData(NULL),
66                  fInputs(NULL),
67                  fOutputs(NULL)
68 {
69 // Default constructor.
70 }
71
72 //______________________________________________________________________________
73 AliAnalysisTask::AliAnalysisTask(const char *name, const char *title)
74                 :TTask(name,title),
75                  fReady(kFALSE),
76                  fNinputs(0),
77                  fNoutputs(0),
78                  fOutputReady(NULL),
79                  fPublishedData(NULL),
80                  fInputs(NULL),
81                  fOutputs(NULL)                 
82 {
83 // Constructor.
84    fInputs      = new TObjArray(2);
85    fOutputs     = new TObjArray(2);
86 }
87
88 //______________________________________________________________________________
89 AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task)
90                 :TTask(task),
91                  fReady(task.fReady),
92                  fNinputs(task.fNinputs),
93                  fNoutputs(task.fNoutputs),                 
94                  fOutputReady(NULL),
95                  fPublishedData(NULL),
96                  fInputs(NULL),
97                  fOutputs(NULL)                 
98 {
99 // Copy ctor.
100    fInputs      = new TObjArray((fNinputs)?fNinputs:2);
101    fOutputs     = new TObjArray((fNoutputs)?fNoutputs:2);
102    fPublishedData = 0;
103    Int_t i;
104    for (i=0; i<fNinputs; i++) fInputs->AddAt(task.GetInputSlot(i),i);
105    fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
106    for (i=0; i<fNoutputs; i++) {
107       fOutputReady[i] = IsOutputReady(i);
108       fOutputs->AddAt(task.GetOutputSlot(i),i);
109    }   
110 }
111
112 //______________________________________________________________________________
113 AliAnalysisTask::~AliAnalysisTask()
114 {
115 // Dtor.
116    if (fInputs)  {fInputs->Delete(); delete fInputs;}
117    if (fOutputs) {fOutputs->Delete(); delete fOutputs;}
118 }   
119   
120 //______________________________________________________________________________
121 AliAnalysisTask& AliAnalysisTask::operator=(const AliAnalysisTask& task)
122 {
123 // Assignment
124    if (&task == this) return *this;
125    TTask::operator=(task);
126    fReady       = task.IsReady();
127    fNinputs     = task.GetNinputs();
128    fNoutputs    = task.GetNoutputs();
129    fInputs      = new TObjArray((fNinputs)?fNinputs:2);
130    fOutputs     = new TObjArray((fNoutputs)?fNoutputs:2);
131    fPublishedData = 0;
132    Int_t i;
133    for (i=0; i<fNinputs; i++) fInputs->AddAt(new AliAnalysisDataSlot(*task.GetInputSlot(i)),i);
134    fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
135    for (i=0; i<fNoutputs; i++) {
136       fOutputReady[i] = IsOutputReady(i);
137       fOutputs->AddAt(new AliAnalysisDataSlot(*task.GetOutputSlot(i)),i);
138    }         
139    return *this;
140 }
141
142 //______________________________________________________________________________
143 Bool_t AliAnalysisTask::AreSlotsConnected()
144 {
145 // Check if all input/output slots are connected. If this is the case fReady=true
146    fReady = kFALSE;
147    if (!fNinputs || !fNoutputs) return kFALSE;
148    Int_t i;
149    AliAnalysisDataSlot *slot;
150    for (i=0; i<fNinputs; i++) {
151       slot = (AliAnalysisDataSlot*)fInputs->At(i);
152       if (!slot) {
153          AliError(Form("Input slot %i of task %s not defined !",i,GetName()));
154          return kFALSE;
155       }   
156       if (!slot->IsConnected()) return kFALSE;
157    }   
158    for (i=0; i<fNoutputs; i++) {
159       slot = (AliAnalysisDataSlot*)fOutputs->At(i);
160       if (!slot) {
161          AliError(Form("Output slot %i of task %s not defined !",i,GetName()));
162          return kFALSE;
163       }   
164       if (!slot->IsConnected()) return kFALSE;
165    } 
166    fReady = kTRUE;  
167    return kTRUE;
168 }
169
170 //______________________________________________________________________________
171 void AliAnalysisTask::CheckNotify()
172 {
173 // Check if data is available from all inputs. Change the status of the task
174 // accordingly. This method is called automatically for all tasks connected
175 // to a container where the data was published.
176    for (Int_t islot=0; islot<fNinputs; islot++) {
177       if (!GetInputData(islot)) {
178          SetActive(kFALSE);
179          return;
180       }   
181    }   
182    SetActive(kTRUE);
183 }
184
185 //______________________________________________________________________________
186 Bool_t AliAnalysisTask::ConnectInput(Int_t islot, AliAnalysisDataContainer *cont)
187 {
188 // Connect an input slot to a data container.
189    AliAnalysisDataSlot *input = GetInputSlot(islot);
190    if (!input) {
191       AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
192       return kFALSE;
193    }
194    // Check type matching          
195    if (!input->GetType()->InheritsFrom(cont->GetType())) {
196       AliError(Form("Data type %s for input %i of task %s not matching container %s of type %s",
197                input->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName()));
198       return kFALSE;
199    }  
200    // Connect the slot to the container as input          
201    if (!input->ConnectContainer(cont)) return kFALSE;
202    // Add this to the list of container consumers
203    cont->AddConsumer(this, islot);
204    AreSlotsConnected();
205    return kTRUE;
206 }   
207
208 //______________________________________________________________________________
209 Bool_t AliAnalysisTask::ConnectOutput(Int_t islot, AliAnalysisDataContainer *cont)
210 {
211 // Connect an output slot to a data container.
212    AliAnalysisDataSlot *output = GetOutputSlot(islot);
213    if (!output) {
214       AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
215       return kFALSE;
216    }
217    // Check type matching          
218    if (!output->GetType()->InheritsFrom(cont->GetType())) {
219       AliError(Form("Data type %s for output %i of task %s not matching container %s of type %s",
220                output->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName()));
221       return kFALSE;
222    }            
223    // Connect the slot to the container as output         
224    if (!output->ConnectContainer(cont)) return kFALSE;
225    // Declare this as the data producer
226    cont->SetProducer(this, islot);
227    AreSlotsConnected();
228    return kTRUE;
229 }   
230
231 //______________________________________________________________________________
232 void AliAnalysisTask::DefineInput(Int_t islot, TClass *type)
233 {
234 // Define an input slot and its type.
235    AliAnalysisDataSlot *input = new AliAnalysisDataSlot(type, this);
236    if (fNinputs<islot+1) fNinputs = islot+1;
237    fInputs->AddAt(input, islot);
238 }
239
240 //______________________________________________________________________________
241 void AliAnalysisTask::DefineOutput(Int_t islot, TClass *type)
242 {
243 // Define an output slot and its type.
244    if (islot<0) {
245       AliError(Form("Cannot define negative output slot number for task %s", GetName()));
246       return;
247    }   
248    AliAnalysisDataSlot *output = new AliAnalysisDataSlot(type, this);
249    if (fNoutputs<islot+1) {
250       fNoutputs = islot+1;
251       if (fOutputReady) delete [] fOutputReady;
252       fOutputReady = new Bool_t[fNoutputs];
253       memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
254    } 
255    fOutputs->AddAt(output, islot);
256 }
257
258 //______________________________________________________________________________
259 TClass *AliAnalysisTask::GetInputType(Int_t islot) const
260 {
261 // Retreive type of a given input slot.
262    AliAnalysisDataSlot *input = GetInputSlot(islot);
263    if (!input) {
264       AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
265       return NULL;
266    }
267    return (input->GetType());
268 }
269
270 //______________________________________________________________________________
271 TClass *AliAnalysisTask::GetOutputType(Int_t islot) const
272 {
273 // Retreive type of a given output slot.
274    AliAnalysisDataSlot *output = GetOutputSlot(islot);
275    if (!output) {
276       AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
277       return NULL;
278    }
279    return (output->GetType());
280 }
281
282 //______________________________________________________________________________
283 TObject *AliAnalysisTask::GetInputData(Int_t islot) const
284 {
285 // Retreive input data for a slot if ready. Normally called by Exec() and
286 // the object has to be statically cast to the appropriate type.
287    AliAnalysisDataSlot *input = GetInputSlot(islot);
288    if (!input) {
289       AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
290       return NULL;
291    }
292    return (input->GetData()); 
293 }
294
295 //______________________________________________________________________________
296 Bool_t AliAnalysisTask::PostData(Int_t iout, TObject *data, Option_t *option)
297 {
298 // Post output data for a given ouput slot in the corresponding data container.
299 // Published data becomes owned by the data container.
300 // If option is specified, the container connected to the output slot must have
301 // an associated file name defined. The option represents the method to open the file.
302    fPublishedData = 0;
303    AliAnalysisDataSlot *output = GetOutputSlot(iout);
304    if (!output) {
305       AliError(Form("Output slot %i not defined for analysis task %s", iout, GetName()));
306       return kFALSE;
307    }
308    if (!output->IsConnected()) {
309       AliError(Form("Output slot %i of analysis task %s not connected to any data container", iout, GetName()));
310       return kFALSE;
311    }
312    if (!fOutputReady) {
313       fOutputReady = new Bool_t[fNoutputs];
314       memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
315    }   
316    fOutputReady[iout] = kTRUE;
317    fPublishedData = data;
318    return (output->GetContainer()->SetData(data, option));
319 }
320
321 //______________________________________________________________________________
322 void AliAnalysisTask::SetUsed(Bool_t flag)
323 {
324 // Set 'used' flag recursively to task and all daughter tasks.
325    if (TestBit(kTaskUsed)==flag) return;
326    TObject::SetBit(kTaskUsed,flag);
327    Int_t nd = fTasks->GetSize();
328    AliAnalysisTask *task;
329    for (Int_t i=0; i<nd; i++) {
330       task = (AliAnalysisTask*)fTasks->At(i);
331       task->SetUsed(flag);
332    }
333 }   
334
335 //______________________________________________________________________________
336 Bool_t AliAnalysisTask::CheckCircularDeps()
337 {
338 // Check for illegal circular dependencies, e.g. a daughter task should not have
339 // a hierarchical parent as subtask.
340    if (IsChecked()) return kTRUE;
341    SetChecked();
342    TList *tasks = GetListOfTasks();
343    Int_t ntasks = tasks->GetSize();
344    AliAnalysisTask *task;
345    for (Int_t i=0; i<ntasks; i++) {
346       task = (AliAnalysisTask*)tasks->At(i);
347       if (task->CheckCircularDeps()) return kTRUE;
348    }
349    SetChecked(kFALSE);
350    return kFALSE;
351 }   
352    
353 //______________________________________________________________________________
354 void AliAnalysisTask::PrintTask(Option_t *option, Int_t indent) const
355 {
356 // Print task info.
357    AliAnalysisTask *thistask = (AliAnalysisTask*)this;
358    TString opt(option);
359    opt.ToLower();
360    Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
361    TString ind;
362    Int_t islot;
363    AliAnalysisDataContainer *cont;
364    for (Int_t i=0; i<indent; i++) ind += " ";
365    if (!dep || (dep && IsChecked())) {
366       printf("%s\n", Form("%stask: %s  ACTIVE=%i", ind.Data(), GetName(),IsActive()));
367       if (dep) thistask->SetChecked(kFALSE);
368       else {
369          for (islot=0; islot<fNinputs; islot++) {
370             printf("%s", Form("%s   INPUT #%i: %s <- ",ind.Data(),islot, GetInputType(islot)->GetName()));
371             cont = GetInputSlot(islot)->GetContainer();
372             if (cont) printf(" [%s]\n", cont->GetName());
373             else printf(" [NO CONTAINER]\n");
374          }
375          for (islot=0; islot<fNoutputs; islot++) {
376             printf("%s", Form("%s   OUTPUT #%i: %s -> ",ind.Data(),islot, GetOutputType(islot)->GetName()));
377             cont = GetOutputSlot(islot)->GetContainer();
378             if (cont) printf(" [%s]\n", cont->GetName());
379             else printf(" [NO CONTAINER]\n");
380          }            
381       }
382    }
383    PrintContainers(option, indent+3);
384 }      
385
386 //______________________________________________________________________________
387 void AliAnalysisTask::PrintContainers(Option_t *option, Int_t indent) const
388 {
389 // Print containers info.
390    AliAnalysisDataContainer *cont;
391    TString ind;
392    for (Int_t i=0; i<indent; i++) ind += " ";
393    Int_t islot;
394    for (islot=0; islot<fNoutputs; islot++) {
395       cont = GetOutputSlot(islot)->GetContainer();
396       cont->PrintContainer(option, indent);
397    }   
398 }