]>
Commit | Line | Data |
---|---|---|
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 | } |