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