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