b35021ceeb7b56b441bcbd00d52c9d99986a0855
[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 // The method ConnectInputData() has to be overloaded by the derived class in order to
50 // set the branch address or connect to a branch address in case the input
51 // slots are connected to trees.
52 // Example:
53 // MyAnalysisTask::ConnectInputData(Option_t *)
54 // {
55 //  // One should first check if the branch address was taken by some other task
56 //    char ** address = (char **)GetBranchAddress(0, "ESD");
57 //    if (address) {
58 //      fESD = (AliESD*)(*address);
59 //    } else {
60 //      fESD = new AliESD();
61 //      SetBranchAddress(0, "ESD", &fESD);
62 //    }
63 // }
64 // 
65 // The method CreateOutputObjects() has to be overloaded an will contain the
66 // objects that should be created only once per session (e.g. output
67 // histograms)
68 //
69 // void MyAnalysisTask::CreateOutputObjects()
70 //{
71   // create histograms 
72 //  fhPt = new TH1F("fhPt","This is the Pt distribution",15,0.1,3.1);
73 //  fhPt->SetStats(kTRUE);
74 //  fhPt->GetXaxis()->SetTitle("P_{T} [GeV]");
75 //  fhPt->GetYaxis()->SetTitle("#frac{dN}{dP_{T}}");
76 //  fhPt->GetXaxis()->SetTitleColor(1);
77 //  fhPt->SetMarkerStyle(kFullCircle);
78 // }
79 //
80 // The method Terminate() will be called by the framework once at the end of
81 // data processing. Overload this if needed. DO NOT ASSUME that the pointers
82 // to histograms defined in  CreateOutputObjects() are valid, since this is
83 // not true in case of PROOF. Restore the pointer values like:
84 //
85 //void MyAnalysisTask::Terminate(Option_t *) 
86 //{
87 //  fhPt = (TH1F*)GetOutputData(0);
88 // ...
89 //}
90
91 //
92 //==============================================================================
93
94 #include <Riostream.h>
95 #include <TDirectory.h>
96 #include <TClass.h>
97
98 #include "AliAnalysisTask.h"
99 #include "AliAnalysisDataSlot.h"
100 #include "AliAnalysisDataContainer.h"
101
102 ClassImp(AliAnalysisTask)
103
104 //______________________________________________________________________________
105 AliAnalysisTask::AliAnalysisTask()
106                 :fReady(kFALSE),
107                  fInitialized(kFALSE),
108                  fNinputs(0),
109                  fNoutputs(0),
110                  fOutputReady(NULL),
111                  fPublishedData(NULL),
112                  fInputs(NULL),
113                  fOutputs(NULL)
114 {
115 // Default constructor.
116 }
117
118 //______________________________________________________________________________
119 AliAnalysisTask::AliAnalysisTask(const char *name, const char *title)
120                 :TTask(name,title),
121                  fReady(kFALSE),
122                  fInitialized(kFALSE),
123                  fNinputs(0),
124                  fNoutputs(0),
125                  fOutputReady(NULL),
126                  fPublishedData(NULL),
127                  fInputs(NULL),
128                  fOutputs(NULL)                 
129 {
130 // Constructor.
131    fInputs      = new TObjArray(2);
132    fOutputs     = new TObjArray(2);
133 }
134
135 //______________________________________________________________________________
136 AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task)
137                 :TTask(task),
138                  fReady(task.fReady),
139                  fInitialized(task.fInitialized),
140                  fNinputs(task.fNinputs),
141                  fNoutputs(task.fNoutputs),                 
142                  fOutputReady(NULL),
143                  fPublishedData(NULL),
144                  fInputs(NULL),
145                  fOutputs(NULL)                 
146 {
147 // Copy ctor.
148    fInputs      = new TObjArray((fNinputs)?fNinputs:2);
149    fOutputs     = new TObjArray((fNoutputs)?fNoutputs:2);
150    fPublishedData = 0;
151    Int_t i;
152    for (i=0; i<fNinputs; i++) fInputs->AddAt(task.GetInputSlot(i),i);
153    fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
154    for (i=0; i<fNoutputs; i++) {
155       fOutputReady[i] = IsOutputReady(i);
156       fOutputs->AddAt(task.GetOutputSlot(i),i);
157    }   
158 }
159
160 //______________________________________________________________________________
161 AliAnalysisTask::~AliAnalysisTask()
162 {
163 // Dtor.
164    if (fTasks) fTasks->Clear();
165    if (fInputs)  {fInputs->Delete(); delete fInputs;}
166    if (fOutputs) {fOutputs->Delete(); delete fOutputs;}
167 }   
168   
169 //______________________________________________________________________________
170 AliAnalysisTask& AliAnalysisTask::operator=(const AliAnalysisTask& task)
171 {
172 // Assignment
173    if (&task == this) return *this;
174    TTask::operator=(task);
175    fReady       = task.IsReady();
176    fInitialized = task.IsInitialized();
177    fNinputs     = task.GetNinputs();
178    fNoutputs    = task.GetNoutputs();
179    fInputs      = new TObjArray((fNinputs)?fNinputs:2);
180    fOutputs     = new TObjArray((fNoutputs)?fNoutputs:2);
181    fPublishedData = 0;
182    Int_t i;
183    for (i=0; i<fNinputs; i++) fInputs->AddAt(new AliAnalysisDataSlot(*task.GetInputSlot(i)),i);
184    fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
185    for (i=0; i<fNoutputs; i++) {
186       fOutputReady[i] = IsOutputReady(i);
187       fOutputs->AddAt(new AliAnalysisDataSlot(*task.GetOutputSlot(i)),i);
188    }         
189    return *this;
190 }
191
192 //______________________________________________________________________________
193 Bool_t AliAnalysisTask::AreSlotsConnected()
194 {
195 // Check if all input/output slots are connected. If this is the case fReady=true
196    fReady = kFALSE;
197    if (!fNinputs || !fNoutputs) return kFALSE;
198    Int_t i;
199    AliAnalysisDataSlot *slot;
200    for (i=0; i<fNinputs; i++) {
201       slot = (AliAnalysisDataSlot*)fInputs->At(i);
202       if (!slot) {
203               Error("AreSlotsConnected", "Input slot %d of task %s not defined !",i,GetName());
204          return kFALSE;
205       }   
206       if (!slot->IsConnected()) return kFALSE;
207    }   
208    for (i=0; i<fNoutputs; i++) {
209       slot = (AliAnalysisDataSlot*)fOutputs->At(i);
210       if (!slot) {
211          Error("AreSlotsConnected", "Output slot %d of task %s not defined !",i,GetName());
212          return kFALSE;
213       }   
214       if (!slot->IsConnected()) return kFALSE;
215    } 
216    fReady = kTRUE;  
217    return kTRUE;
218 }
219
220 //______________________________________________________________________________
221 void AliAnalysisTask::CheckNotify(Bool_t init)
222 {
223 // Check if data is available from all inputs. Change the status of the task
224 // accordingly. This method is called automatically for all tasks connected
225 // to a container where the data was published.
226    if (init) fInitialized = kFALSE;
227    for (Int_t islot=0; islot<fNinputs; islot++) {
228       if (!GetInputData(islot)) {
229          SetActive(kFALSE);
230          return;
231       }   
232    }   
233    SetActive(kTRUE);
234    if (fInitialized) return;
235    TDirectory *cursav = gDirectory;
236    ConnectInputData();
237    if (cursav) cursav->cd();
238    fInitialized = kTRUE;
239 }
240
241 //______________________________________________________________________________
242 Bool_t AliAnalysisTask::ConnectInput(Int_t islot, AliAnalysisDataContainer *cont)
243 {
244 // Connect an input slot to a data container.
245    AliAnalysisDataSlot *input = GetInputSlot(islot);
246    if (!input) {
247       Error("ConnectInput","Input slot %i not defined for analysis task %s", islot, GetName());
248       return kFALSE;
249    }
250    // Check type matching          
251    if (!input->GetType()->InheritsFrom(cont->GetType())) {
252       Error("ConnectInput","Data type %s for input %i of task %s not matching container %s of type %s",input->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName());
253       return kFALSE;
254    }  
255    // Connect the slot to the container as input          
256    if (!input->ConnectContainer(cont)) return kFALSE;
257    // Add this to the list of container consumers
258    cont->AddConsumer(this, islot);
259    AreSlotsConnected();
260    return kTRUE;
261 }   
262
263 //______________________________________________________________________________
264 Bool_t AliAnalysisTask::ConnectOutput(Int_t islot, AliAnalysisDataContainer *cont)
265 {
266 // Connect an output slot to a data container.
267    AliAnalysisDataSlot *output = GetOutputSlot(islot);
268    if (!output) {
269       Error("ConnectOutput","Output slot %i not defined for analysis task %s", islot, GetName());
270       return kFALSE;
271    }
272    // Check type matching          
273    if (!output->GetType()->InheritsFrom(cont->GetType())) {
274       Error("ConnectOutput","Data type %s for output %i of task %s not matching container %s of type %s",output->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName());
275       return kFALSE;
276    }            
277    // Connect the slot to the container as output         
278    if (!output->ConnectContainer(cont)) return kFALSE;
279    // Declare this as the data producer
280    cont->SetProducer(this, islot);
281    AreSlotsConnected();
282    return kTRUE;
283 }   
284
285 //______________________________________________________________________________
286 void AliAnalysisTask::DefineInput(Int_t islot, TClass *type)
287 {
288 // Define an input slot and its type.
289    AliAnalysisDataSlot *input = new AliAnalysisDataSlot(type, this);
290    if (fNinputs<islot+1) fNinputs = islot+1;
291    fInputs->AddAtAndExpand(input, islot);
292 }
293
294 //______________________________________________________________________________
295 void AliAnalysisTask::DefineOutput(Int_t islot, TClass *type)
296 {
297 // Define an output slot and its type.
298    AliAnalysisDataSlot *output = new AliAnalysisDataSlot(type, this);
299    if (fNoutputs<islot+1) {
300       fNoutputs = islot+1;
301       if (fOutputReady) delete [] fOutputReady;
302       fOutputReady = new Bool_t[fNoutputs];
303       memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
304    } 
305    fOutputs->AddAtAndExpand(output, islot);
306 }
307
308 //______________________________________________________________________________
309 TClass *AliAnalysisTask::GetInputType(Int_t islot) const
310 {
311 // Retreive type of a given input slot.
312    AliAnalysisDataSlot *input = GetInputSlot(islot);
313    if (!input) {
314       Error("GetInputType","Input slot %d not defined for analysis task %s", islot, GetName());
315       return NULL;
316    }
317    return (input->GetType());
318 }
319
320 //______________________________________________________________________________
321 TClass *AliAnalysisTask::GetOutputType(Int_t islot) const
322 {
323 // Retreive type of a given output slot.
324    AliAnalysisDataSlot *output = GetOutputSlot(islot);
325    if (!output) {
326       Error("GetOutputType","Output slot %d not defined for analysis task %s", islot, GetName());
327       return NULL;
328    }
329    return (output->GetType());
330 }
331
332 //______________________________________________________________________________
333 TObject *AliAnalysisTask::GetInputData(Int_t islot) const
334 {
335 // Retreive input data for a slot if ready. Normally called by Exec() and
336 // the object has to be statically cast to the appropriate type.
337    AliAnalysisDataSlot *input = GetInputSlot(islot);
338    if (!input) {
339       Error("GetInputData","Input slot %d not defined for analysis task %s", islot, GetName());
340       return NULL;
341    }
342    return (input->GetData()); 
343 }
344
345 //______________________________________________________________________________
346 TObject *AliAnalysisTask::GetOutputData(Int_t islot) const
347 {
348 // Retreive output data for a slot. Normally called in UserTask::Terminate to
349 // get a valid pointer to data even in case of Proof.
350    AliAnalysisDataSlot *output = GetOutputSlot(islot);
351    if (!output) {
352       Error("GetOutputData","Input slot %d not defined for analysis task %s", islot, GetName());
353       return NULL;
354    }
355    return (output->GetData()); 
356 }
357
358 //______________________________________________________________________________
359 char *AliAnalysisTask::GetBranchAddress(Int_t islot, const char *branch) const
360 {
361 // Check if a branch with a given name from the specified input is connected
362 // to some address. Call this in Init() before trying to call SetBranchAddress()
363 // since the adress may be set by other task.
364    return (char *)GetInputSlot(islot)->GetBranchAddress(branch);
365 }
366
367 //______________________________________________________________________________
368 Bool_t AliAnalysisTask::SetBranchAddress(Int_t islot, const char *branch, void *address) const
369 {
370 // Connect an object address to a branch of the specified input.
371    return GetInputSlot(islot)->SetBranchAddress(branch, address);
372 }   
373
374 //______________________________________________________________________________
375 void AliAnalysisTask::ConnectInputData(Option_t *)
376 {
377 // Overload and connect your branches here.
378 }
379
380 //______________________________________________________________________________
381 void AliAnalysisTask::CreateOutputObjects()
382 {
383 // Called once per task either in PROOF or local mode. Overload to put some 
384 // task initialization and/or create your output objects here.
385 }
386
387 //______________________________________________________________________________
388 Bool_t AliAnalysisTask::Notify()
389 {
390 // Overload this IF you need to treat input file change.
391    return kTRUE;
392 }
393
394 //______________________________________________________________________________
395 void AliAnalysisTask::Terminate(Option_t *)
396 {
397 // Method called by the framework at the end of data processing.
398 }
399
400 //______________________________________________________________________________
401 Bool_t AliAnalysisTask::PostData(Int_t iout, TObject *data, Option_t *option)
402 {
403 // Post output data for a given ouput slot in the corresponding data container.
404 // Published data becomes owned by the data container.
405 // If option is specified, the container connected to the output slot must have
406 // an associated file name defined. The option represents the method to open the file.
407    fPublishedData = 0;
408    AliAnalysisDataSlot *output = GetOutputSlot(iout);
409    if (!output) {
410       Error("PostData","Output slot %i not defined for analysis task %s", iout, GetName());
411       return kFALSE;
412    }
413    if (!output->IsConnected()) {
414       Error("PostData","Output slot %i of analysis task %s not connected to any data container", iout, GetName());
415       return kFALSE;
416    }
417    if (!fOutputReady) {
418       fOutputReady = new Bool_t[fNoutputs];
419       memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
420    }   
421    fOutputReady[iout] = kTRUE;
422    fPublishedData = data;
423    return (output->GetContainer()->SetData(data, option));
424 }
425
426 //______________________________________________________________________________
427 void AliAnalysisTask::SetUsed(Bool_t flag)
428 {
429 // Set 'used' flag recursively to task and all daughter tasks.
430    if (TestBit(kTaskUsed)==flag) return;
431    TObject::SetBit(kTaskUsed,flag);
432    Int_t nd = fTasks->GetSize();
433    AliAnalysisTask *task;
434    for (Int_t i=0; i<nd; i++) {
435       task = (AliAnalysisTask*)fTasks->At(i);
436       task->SetUsed(flag);
437    }
438 }   
439
440 //______________________________________________________________________________
441 Bool_t AliAnalysisTask::CheckCircularDeps()
442 {
443 // Check for illegal circular dependencies, e.g. a daughter task should not have
444 // a hierarchical parent as subtask.
445    if (IsChecked()) return kTRUE;
446    SetChecked();
447    TList *tasks = GetListOfTasks();
448    Int_t ntasks = tasks->GetSize();
449    AliAnalysisTask *task;
450    for (Int_t i=0; i<ntasks; i++) {
451       task = (AliAnalysisTask*)tasks->At(i);
452       if (task->CheckCircularDeps()) return kTRUE;
453    }
454    SetChecked(kFALSE);
455    return kFALSE;
456 }   
457    
458 //______________________________________________________________________________
459 void AliAnalysisTask::PrintTask(Option_t *option, Int_t indent) const
460 {
461 // Print task info.
462    AliAnalysisTask *thistask = (AliAnalysisTask*)this;
463    TString opt(option);
464    opt.ToLower();
465    Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
466    TString ind;
467    Int_t islot;
468    AliAnalysisDataContainer *cont;
469    for (Int_t i=0; i<indent; i++) ind += " ";
470    if (!dep || (dep && IsChecked())) {
471       printf("%s\n", Form("%stask: %s  ACTIVE=%i", ind.Data(), GetName(),IsActive()));
472       if (dep) thistask->SetChecked(kFALSE);
473       else {
474          for (islot=0; islot<fNinputs; islot++) {
475             printf("%s", Form("%s   INPUT #%i: %s <- ",ind.Data(),islot, GetInputType(islot)->GetName()));
476             cont = GetInputSlot(islot)->GetContainer();
477             if (cont) printf(" [%s]\n", cont->GetName());
478             else printf(" [NO CONTAINER]\n");
479          }
480          for (islot=0; islot<fNoutputs; islot++) {
481             printf("%s", Form("%s   OUTPUT #%i: %s -> ",ind.Data(),islot, GetOutputType(islot)->GetName()));
482             cont = GetOutputSlot(islot)->GetContainer();
483             if (cont) printf(" [%s]\n", cont->GetName());
484             else printf(" [NO CONTAINER]\n");
485          }            
486       }
487    }
488    PrintContainers(option, indent+3);
489 }      
490
491 //______________________________________________________________________________
492 void AliAnalysisTask::PrintContainers(Option_t *option, Int_t indent) const
493 {
494 // Print containers info.
495    AliAnalysisDataContainer *cont;
496    TString ind;
497    for (Int_t i=0; i<indent; i++) ind += " ";
498    Int_t islot;
499    for (islot=0; islot<fNoutputs; islot++) {
500       cont = GetOutputSlot(islot)->GetContainer();
501       cont->PrintContainer(option, indent);
502    }   
503 }