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 | // AliAnalysysManager - Manager analysis class. Allows creation of several |
21 | // analysis tasks and data containers storing their input/output. Allows |
22 | // connecting/chaining tasks via shared data containers. Serializes the current |
23 | // event for all tasks depending only on initial input data. |
24 | //============================================================================== |
25 | // |
26 | //============================================================================== |
27 | |
11026a80 |
28 | #include "Riostream.h" |
29 | |
d3106602 |
30 | #include "TClass.h" |
327eaf46 |
31 | #include "TFile.h" |
32 | #include "TTree.h" |
11026a80 |
33 | //#include "AliLog.h" |
d3106602 |
34 | |
35 | #include "AliAnalysisManager.h" |
36 | #include "AliAnalysisTask.h" |
37 | #include "AliAnalysisDataContainer.h" |
38 | #include "AliAnalysisDataSlot.h" |
39 | |
40 | ClassImp(AliAnalysisManager) |
41 | |
42 | //______________________________________________________________________________ |
37a26056 |
43 | AliAnalysisManager::AliAnalysisManager() : TSelector(), |
327eaf46 |
44 | fTree(NULL), |
37a26056 |
45 | fInitOK(kFALSE), |
46 | fContainers(NULL), |
47 | fInputs(NULL), |
48 | fOutputs(NULL), |
49 | fTasks(NULL), |
50 | fTopTasks(NULL), |
51 | fZombies(NULL) |
d3106602 |
52 | { |
53 | // Default constructor. |
37a26056 |
54 | if (TClass::IsCallingNew() != TClass::kDummyNew) { |
d3106602 |
55 | fContainers = new TObjArray(); |
56 | fInputs = new TObjArray(); |
57 | fOutputs = new TObjArray(); |
58 | fTasks = new TObjArray(); |
59 | fTopTasks = new TObjArray(); |
60 | fZombies = new TObjArray(); |
61 | // fStatus = new AliAnalysisInfo(this); |
62 | } |
63 | } |
64 | |
5daf9fd2 |
65 | #ifdef NEVER |
d3106602 |
66 | //______________________________________________________________________________ |
67 | AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other) |
37a26056 |
68 | :TSelector(other), |
327eaf46 |
69 | fTree(NULL), |
37a26056 |
70 | fInitOK(kFALSE), |
71 | fContainers(NULL), |
72 | fInputs(NULL), |
73 | fOutputs(NULL), |
74 | fTasks(NULL), |
75 | fTopTasks(NULL), |
76 | fZombies(NULL) |
d3106602 |
77 | { |
78 | // Copy constructor. |
37a26056 |
79 | fInitOK = other.fInitOK; |
80 | fContainers = new TObjArray(*other.fContainers); |
81 | fInputs = new TObjArray(*other.fInputs); |
82 | fOutputs = new TObjArray(*other.fOutputs); |
83 | fTasks = new TObjArray(*other.fTasks); |
84 | fTopTasks = new TObjArray(*other.fTopTasks); |
85 | fZombies = new TObjArray(*other.fZombies); |
d3106602 |
86 | // fStatus = new AliAnalysisInfo(this); |
87 | } |
88 | |
89 | //______________________________________________________________________________ |
90 | AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other) |
91 | { |
92 | // Assignment |
93 | if (&other != this) { |
94 | TSelector::operator=(other); |
327eaf46 |
95 | fTree = other.fTree; |
37a26056 |
96 | fInitOK = other.fInitOK; |
97 | fContainers = new TObjArray(*other.fContainers); |
98 | fInputs = new TObjArray(*other.fInputs); |
99 | fOutputs = new TObjArray(*other.fOutputs); |
100 | fTasks = new TObjArray(*other.fTasks); |
101 | fTopTasks = new TObjArray(*other.fTopTasks); |
102 | fZombies = new TObjArray(*other.fZombies); |
d3106602 |
103 | // fStatus = new AliAnalysisInfo(this); |
104 | } |
105 | return *this; |
106 | } |
5daf9fd2 |
107 | #endif |
d3106602 |
108 | |
109 | //______________________________________________________________________________ |
110 | AliAnalysisManager::~AliAnalysisManager() |
111 | { |
112 | // Destructor. |
113 | if (fContainers) {fContainers->Delete(); delete fContainers;} |
114 | if (fInputs) delete fInputs; |
115 | if (fOutputs) delete fOutputs; |
116 | if (fTasks) {fTasks->Delete(); delete fTasks;} |
117 | if (fTopTasks) delete fTopTasks; |
118 | if (fZombies) delete fZombies; |
119 | } |
d3106602 |
120 | //______________________________________________________________________________ |
327eaf46 |
121 | Int_t AliAnalysisManager::GetEntry(Long64_t entry, Int_t getall) |
122 | { |
123 | // Read one entry of the tree or a whole branch. |
124 | return fTree ? fTree->GetTree()->GetEntry(entry, getall) : 0; |
125 | } |
126 | |
127 | //______________________________________________________________________________ |
128 | void AliAnalysisManager::Init(TTree *tree) |
d3106602 |
129 | { |
130 | // The Init() function is called when the selector needs to initialize |
131 | // a new tree or chain. Typically here the branch addresses of the tree |
132 | // will be set. It is normaly not necessary to make changes to the |
133 | // generated code, but the routine can be extended by the user if needed. |
134 | // Init() will be called many times when running with PROOF. |
327eaf46 |
135 | printf("AliAnalysisManager::Init(%s)\n", tree->GetName()); |
136 | if (!fInitOK) { |
11026a80 |
137 | cout<<"You have to call InitAnalysis first"<<endl; |
138 | //AliError("You have to call InitAnalysis first"); |
327eaf46 |
139 | return; |
140 | } |
141 | if (!tree) return; |
142 | fTree = tree; |
143 | AliAnalysisDataContainer *top = (AliAnalysisDataContainer*)fInputs->At(0); |
144 | top->SetData(tree); |
d3106602 |
145 | } |
146 | |
147 | //______________________________________________________________________________ |
327eaf46 |
148 | void AliAnalysisManager::Begin(TTree *tree) |
d3106602 |
149 | { |
150 | // The Begin() function is called at the start of the query. |
151 | // When running with PROOF Begin() is only called on the client. |
152 | // The tree argument is deprecated (on PROOF 0 is passed). |
327eaf46 |
153 | printf("AliAnalysisManager::Begin(%s)\n", tree->GetName()); |
154 | Init(tree); |
d3106602 |
155 | } |
156 | |
157 | //______________________________________________________________________________ |
327eaf46 |
158 | void AliAnalysisManager::SlaveBegin(TTree *tree) |
d3106602 |
159 | { |
160 | // The SlaveBegin() function is called after the Begin() function. |
161 | // When running with PROOF SlaveBegin() is called on each slave server. |
162 | // The tree argument is deprecated (on PROOF 0 is passed). |
327eaf46 |
163 | printf("AliAnalysisManager::SlaveBegin(%s)\n", tree->GetName()); |
164 | Init(tree); |
d3106602 |
165 | } |
166 | |
167 | //______________________________________________________________________________ |
327eaf46 |
168 | Bool_t AliAnalysisManager::Notify() |
169 | { |
170 | // The Notify() function is called when a new file is opened. This |
171 | // can be either for a new TTree in a TChain or when when a new TTree |
172 | // is started when using PROOF. It is normaly not necessary to make changes |
173 | // to the generated code, but the routine can be extended by the |
174 | // user if needed. The return value is currently not used. |
175 | if (fTree) { |
176 | TFile *curfile = fTree->GetCurrentFile(); |
177 | if (curfile) printf("AliAnalysisManager::Notify() file: %s\n", curfile->GetName()); |
178 | } |
179 | return kTRUE; |
180 | } |
181 | |
182 | //______________________________________________________________________________ |
183 | Bool_t AliAnalysisManager::Process(Long64_t entry) |
d3106602 |
184 | { |
185 | // The Process() function is called for each entry in the tree (or possibly |
186 | // keyed object in the case of PROOF) to be processed. The entry argument |
187 | // specifies which entry in the currently loaded tree is to be processed. |
188 | // It can be passed to either TTree::GetEntry() or TBranch::GetEntry() |
189 | // to read either all or the required parts of the data. When processing |
190 | // keyed objects with PROOF, the object is already loaded and is available |
191 | // via the fObject pointer. |
192 | // |
193 | // This function should contain the "body" of the analysis. It can contain |
194 | // simple or elaborate selection criteria, run algorithms on the data |
195 | // of the event and typically fill histograms. |
196 | |
197 | // WARNING when a selector is used with a TChain, you must use |
198 | // the pointer to the current TTree to call GetEntry(entry). |
199 | // The entry is always the local entry number in the current tree. |
200 | // Assuming that fChain is the pointer to the TChain being processed, |
201 | // use fChain->GetTree()->GetEntry(entry). |
327eaf46 |
202 | |
203 | // printf("AliAnalysisManager::Process(%lld)\n", entry); |
204 | GetEntry(entry); |
205 | ExecAnalysis(); |
206 | return kTRUE; |
d3106602 |
207 | } |
208 | |
209 | //______________________________________________________________________________ |
210 | void AliAnalysisManager::SlaveTerminate() |
211 | { |
212 | // The SlaveTerminate() function is called after all entries or objects |
213 | // have been processed. When running with PROOF SlaveTerminate() is called |
214 | // on each slave server. |
327eaf46 |
215 | |
216 | printf("AliAnalysisManager::SlaveTerminate()\n"); |
217 | if (!fOutput) |
218 | { |
11026a80 |
219 | cout<<"ERROR: Output list not initialized."<<endl; |
220 | //AliError("ERROR: Output list not initialized."); |
327eaf46 |
221 | return; |
222 | } |
223 | TIter next(fOutputs); |
224 | AliAnalysisDataContainer *output; |
225 | while ((output=(AliAnalysisDataContainer *)next())) { |
226 | output->SetDataOwned(kFALSE); |
227 | fOutput->Add(output->GetData()); |
228 | } |
d3106602 |
229 | } |
230 | |
231 | //______________________________________________________________________________ |
232 | void AliAnalysisManager::Terminate() |
233 | { |
234 | // The Terminate() function is the last function to be called during |
235 | // a query. It always runs on the client, it can be used to present |
236 | // the results graphically or save the results to file. |
327eaf46 |
237 | printf("AliAnalysisManager::Terminate()\n"); |
238 | AliAnalysisDataContainer *output; |
239 | AliAnalysisTask *task; |
240 | TIter next(fOutputs); |
241 | while ((output=(AliAnalysisDataContainer *)next())) output->WriteData(); |
242 | TIter next1(fTasks); |
243 | // Call Terminate() for tasks |
244 | while ((task=(AliAnalysisTask*)next1())) task->Terminate(); |
d3106602 |
245 | } |
246 | |
247 | //______________________________________________________________________________ |
248 | void AliAnalysisManager::AddTask(AliAnalysisTask *task) |
249 | { |
250 | // Adds a user task to the global list of tasks. |
251 | task->SetActive(kFALSE); |
252 | fTasks->Add(task); |
253 | } |
254 | |
255 | //______________________________________________________________________________ |
256 | AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const |
257 | { |
258 | // Retreive task by name. |
259 | if (!fTasks) return NULL; |
260 | return (AliAnalysisTask*)fTasks->FindObject(name); |
261 | } |
262 | |
263 | //______________________________________________________________________________ |
264 | AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name, |
265 | TClass *datatype, EAliAnalysisContType type) |
266 | { |
267 | // Create a data container of a certain type. Types can be: |
268 | // kNormalContainer = 0, used to exchange date between tasks |
269 | // kInputContainer = 1, used to store input data |
270 | // kOutputContainer = 2, used for posting results |
271 | AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype); |
272 | fContainers->Add(cont); |
273 | switch (type) { |
274 | case kInputContainer: |
275 | fInputs->Add(cont); |
276 | break; |
277 | case kOutputContainer: |
278 | fOutputs->Add(cont); |
279 | break; |
280 | case kNormalContainer: |
281 | break; |
282 | } |
283 | return cont; |
284 | } |
285 | |
286 | //______________________________________________________________________________ |
287 | Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot, |
288 | AliAnalysisDataContainer *cont) |
289 | { |
290 | // Connect input of an existing task to a data container. |
291 | if (!fTasks->FindObject(task)) { |
292 | AddTask(task); |
11026a80 |
293 | cout<<"Task "<<task->GetName()<<" not registered. Now owned by analysis manager"<<endl; |
294 | //AliInfo(Form("Task %s not registered. Now owned by analysis manager", task->GetName())); |
d3106602 |
295 | } |
296 | Bool_t connected = task->ConnectInput(islot, cont); |
297 | return connected; |
298 | } |
299 | |
300 | //______________________________________________________________________________ |
301 | Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot, |
302 | AliAnalysisDataContainer *cont) |
303 | { |
304 | // Connect output of an existing task to a data container. |
305 | if (!fTasks->FindObject(task)) { |
306 | AddTask(task); |
11026a80 |
307 | cout<<"Task "<<task->GetName()<<"not registered. Now owned by analysis manager"<<endl; |
308 | //AliInfo(Form("Task %s not registered. Now owned by analysis manager", task->GetName())); |
d3106602 |
309 | } |
310 | Bool_t connected = task->ConnectOutput(islot, cont); |
311 | return connected; |
312 | } |
313 | |
314 | //______________________________________________________________________________ |
315 | void AliAnalysisManager::CleanContainers() |
316 | { |
317 | // Clean data from all containers that have already finished all client tasks. |
318 | TIter next(fContainers); |
319 | AliAnalysisDataContainer *cont; |
320 | while ((cont=(AliAnalysisDataContainer *)next())) { |
321 | if (cont->IsOwnedData() && |
322 | cont->IsDataReady() && |
323 | cont->ClientsExecuted()) cont->DeleteData(); |
324 | } |
325 | } |
326 | |
327 | //______________________________________________________________________________ |
328 | Bool_t AliAnalysisManager::InitAnalysis() |
329 | { |
330 | // Initialization of analysis chain of tasks. Should be called after all tasks |
331 | // and data containers are properly connected |
332 | // Check for input/output containers |
333 | fInitOK = kFALSE; |
327eaf46 |
334 | // if (!fInputs->GetEntriesFast()) { |
335 | // AliError("No input container defined. At least one container should store input data"); |
336 | // return kFALSE; |
337 | // } |
338 | // if (!fOutputs->GetEntriesFast()) { |
339 | // AliError("No output container defined. At least one container should store output data"); |
340 | // return kFALSE; |
341 | // } |
d3106602 |
342 | // Check for top tasks (depending only on input data containers) |
343 | if (!fTasks->First()) { |
11026a80 |
344 | cout<<"Analysis has no tasks !"<<endl; |
345 | //AliError("Analysis have no tasks !"); |
d3106602 |
346 | return kFALSE; |
347 | } |
348 | TIter next(fTasks); |
349 | AliAnalysisTask *task; |
350 | AliAnalysisDataContainer *cont; |
351 | Int_t ntop = 0; |
352 | Int_t nzombies = 0; |
327eaf46 |
353 | Bool_t iszombie = kFALSE; |
354 | Bool_t istop = kTRUE; |
d3106602 |
355 | Int_t i; |
356 | while ((task=(AliAnalysisTask*)next())) { |
327eaf46 |
357 | istop = kTRUE; |
358 | iszombie = kFALSE; |
d3106602 |
359 | Int_t ninputs = task->GetNinputs(); |
327eaf46 |
360 | // if (!ninputs) { |
361 | // task->SetZombie(); |
362 | // fZombies->Add(task); |
363 | // nzombies++; |
364 | // AliWarning(Form("Task %s has no input slots defined ! Declared zombie...",task->GetName())); |
365 | // continue; |
366 | // } |
d3106602 |
367 | for (i=0; i<ninputs; i++) { |
368 | cont = task->GetInputSlot(i)->GetContainer(); |
369 | if (!cont) { |
327eaf46 |
370 | if (!iszombie) { |
d3106602 |
371 | task->SetZombie(); |
372 | fZombies->Add(task); |
373 | nzombies++; |
327eaf46 |
374 | iszombie = kTRUE; |
d3106602 |
375 | } |
11026a80 |
376 | cout<<"Input slot "<<i<<" of task "<<task->GetName()<<" has no container connected ! Declared zombie..."<<endl; |
377 | //AliWarning(Form("Input slot %i of task %s has no container connected ! Declared zombie...",i,task->GetName())); |
d3106602 |
378 | } |
327eaf46 |
379 | if (iszombie) continue; |
d3106602 |
380 | // Check if cont is an input container |
327eaf46 |
381 | if (istop && !fInputs->FindObject(cont)) istop=kFALSE; |
d3106602 |
382 | // Connect to parent task |
383 | } |
327eaf46 |
384 | if (istop) { |
d3106602 |
385 | ntop++; |
386 | fTopTasks->Add(task); |
387 | } |
388 | } |
389 | if (!ntop) { |
11026a80 |
390 | cout<<"No top task defined. At least one task should be connected only to input containers"<<endl; |
391 | //AliError("No top task defined. At least one task should be connected only to input containers"); |
d3106602 |
392 | return kFALSE; |
393 | } |
394 | // Check now if there are orphan tasks |
395 | for (i=0; i<ntop; i++) { |
396 | task = (AliAnalysisTask*)fTopTasks->At(i); |
397 | task->SetUsed(); |
398 | } |
399 | Int_t norphans = 0; |
400 | next.Reset(); |
401 | while ((task=(AliAnalysisTask*)next())) { |
402 | if (!task->IsUsed()) { |
403 | norphans++; |
11026a80 |
404 | cout<<"Task "<<task->GetName()<<" is orphan"<<endl; |
405 | //AliWarning(Form("Task %s is orphan",task->GetName())); |
d3106602 |
406 | } |
407 | } |
408 | // Check the task hierarchy (no parent task should depend on data provided |
409 | // by a daughter task) |
410 | for (i=0; i<ntop; i++) { |
411 | task = (AliAnalysisTask*)fTopTasks->At(i); |
412 | if (task->CheckCircularDeps()) { |
11026a80 |
413 | cout<<"Found illegal circular dependencies between following tasks:"<<endl; |
414 | //AliError("Found illegal circular dependencies between following tasks:"); |
d3106602 |
415 | PrintStatus("dep"); |
416 | return kFALSE; |
417 | } |
418 | } |
327eaf46 |
419 | fInitOK = kTRUE; |
d3106602 |
420 | return kTRUE; |
421 | } |
422 | |
423 | //______________________________________________________________________________ |
424 | void AliAnalysisManager::PrintStatus(Option_t *option) const |
425 | { |
426 | // Print task hierarchy. |
427 | TIter next(fTopTasks); |
428 | AliAnalysisTask *task; |
429 | while ((task=(AliAnalysisTask*)next())) |
430 | task->PrintTask(option); |
431 | } |
432 | |
433 | //______________________________________________________________________________ |
434 | void AliAnalysisManager::ResetAnalysis() |
435 | { |
436 | // Reset all execution flags and clean containers. |
437 | CleanContainers(); |
438 | } |
439 | |
440 | //______________________________________________________________________________ |
441 | void AliAnalysisManager::ExecAnalysis(Option_t *option) |
442 | { |
443 | // Execute analysis. |
327eaf46 |
444 | if (!fInitOK) { |
11026a80 |
445 | cout<<"Analysis manager was not initialized !"<<endl; |
446 | //AliError("Analysis manager was not initialized !"); |
327eaf46 |
447 | return; |
448 | } |
d3106602 |
449 | AliAnalysisTask *task; |
327eaf46 |
450 | // Check if the top tree is active. |
451 | if (fTree) { |
452 | TIter next(fTasks); |
453 | // De-activate all tasks |
454 | while ((task=(AliAnalysisTask*)next())) task->SetActive(kFALSE); |
455 | AliAnalysisDataContainer *cont = (AliAnalysisDataContainer*)fInputs->At(0); |
456 | if (!cont) { |
11026a80 |
457 | cout<<"Cannot execute analysis in TSelector mode without at least one top container"<<endl; |
458 | //AliError("Cannot execute analysis in TSelector mode without at least one top container"); |
327eaf46 |
459 | return; |
460 | } |
461 | cont->SetData(fTree); // This will notify all consumers |
462 | TIter next1(cont->GetConsumers()); |
463 | while ((task=(AliAnalysisTask*)next1())) { |
464 | // task->SetActive(kTRUE); |
465 | task->ExecuteTask(option); |
466 | } |
467 | return; |
468 | } |
469 | // The event loop is not controlled by TSelector |
470 | TIter next2(fTopTasks); |
471 | while ((task=(AliAnalysisTask*)next2())) { |
472 | task->SetActive(kTRUE); |
473 | printf("executing %s\n", task->GetName()); |
d3106602 |
474 | task->ExecuteTask(option); |
327eaf46 |
475 | } |
d3106602 |
476 | } |
477 | |
478 | //______________________________________________________________________________ |
479 | void AliAnalysisManager::FinishAnalysis() |
480 | { |
481 | // Finish analysis. |
482 | } |