This method has to be called INSIDE the user redefined CreateOutputObjects
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisDataContainer.cxx
CommitLineData
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// AliAnalysysDataContainer - Container of data of arbitrary type deriving
21// from TObject used for analysis. A container must be connected to the
22// output data slot of a single analysis task (producer) , but also as
23// input slot for possibly several other tasks (consumers). The connected
24// slots must enforce the same data type as the container (or a derived type).
25// A container becomes the owner of the contained data once this was produced.
26//
27// Containers should be defined by the analysis module using:
28//
29// AliAnalysisModule::AddContainer(const char *name, TClass *type);
30//
31// A container should be connected to a producer:
32
33// AliAnalysisModule::ConnectOutput(AliAnalysisTask *task,
34// AliAnalysisDataContainer *cont)
35// and to its consumers:
36//
37// AliAnalysisModule::ConnectInput(AliAnalysisTask *task, Int_t islot,
38// AliAnalysisDataContainer *cont)
39//
40// The container will create an implicit connection between the producer task
41// and all consumers, which will become sub-tasks of the producer.
42//
43//==============================================================================
44
c52c2132 45#include <Riostream.h>
46#include <TMethodCall.h>
11026a80 47
c52c2132 48#include <TClass.h>
49#include <TTree.h>
50#include <TROOT.h>
d3106602 51
52#include "AliAnalysisDataContainer.h"
53#include "AliAnalysisDataSlot.h"
54#include "AliAnalysisTask.h"
55
56ClassImp(AliAnalysisDataContainer)
57
58//______________________________________________________________________________
37a26056 59AliAnalysisDataContainer::AliAnalysisDataContainer() : TNamed(),
60 fDataReady(kFALSE),
61 fOwnedData(kFALSE),
c52c2132 62 fFileName(),
37a26056 63 fData(NULL),
64 fType(NULL),
65 fProducer(NULL),
66 fConsumers(NULL)
d3106602 67{
c52c2132 68// Dummy ctor.
c5a87c56 69 TObject::SetBit(kContEvtByEvt, kTRUE);
d3106602 70}
37a26056 71
d3106602 72//______________________________________________________________________________
73AliAnalysisDataContainer::AliAnalysisDataContainer(const char *name, TClass *type)
37a26056 74 :TNamed(name,""),
75 fDataReady(kFALSE),
76 fOwnedData(kTRUE),
c52c2132 77 fFileName(),
37a26056 78 fData(NULL),
79 fType(type),
80 fProducer(NULL),
81 fConsumers(NULL)
d3106602 82{
c52c2132 83// Default constructor.
84 SetTitle(fType->GetName());
c5a87c56 85 TObject::SetBit(kContEvtByEvt, kTRUE);
37a26056 86}
87
88//______________________________________________________________________________
89AliAnalysisDataContainer::AliAnalysisDataContainer(const AliAnalysisDataContainer &cont)
90 :TNamed(cont),
91 fDataReady(cont.fDataReady),
92 fOwnedData(kFALSE),
c52c2132 93 fFileName(cont.fFileName),
37a26056 94 fData(cont.fData),
c52c2132 95 fType(NULL),
37a26056 96 fProducer(cont.fProducer),
97 fConsumers(NULL)
98{
99// Copy ctor.
c52c2132 100 GetType();
37a26056 101 if (cont.fConsumers) {
102 fConsumers = new TObjArray(2);
103 Int_t ncons = cont.fConsumers->GetEntriesFast();
104 for (Int_t i=0; i<ncons; i++) fConsumers->Add(cont.fConsumers->At(i));
105 }
d3106602 106}
107
108//______________________________________________________________________________
109AliAnalysisDataContainer::~AliAnalysisDataContainer()
110{
111// Destructor. Deletes data ! (What happens if data is a container ???)
112 if (fData && fOwnedData) delete fData;
113 if (fConsumers) delete fConsumers;
114}
115
37a26056 116//______________________________________________________________________________
117AliAnalysisDataContainer &AliAnalysisDataContainer::operator=(const AliAnalysisDataContainer &cont)
118{
119// Assignment.
120 if (&cont != this) {
121 TNamed::operator=(cont);
122 fDataReady = cont.fDataReady;
123 fOwnedData = kFALSE; // !!! Data owned by cont.
c52c2132 124 fFileName = cont.fFileName;
37a26056 125 fData = cont.fData;
c52c2132 126 GetType();
37a26056 127 fProducer = cont.fProducer;
128 if (cont.fConsumers) {
129 fConsumers = new TObjArray(2);
130 Int_t ncons = cont.fConsumers->GetEntriesFast();
131 for (Int_t i=0; i<ncons; i++) fConsumers->Add(cont.fConsumers->At(i));
132 }
133 }
134 return *this;
135}
136
c52c2132 137//______________________________________________________________________________
138void AliAnalysisDataContainer::AddConsumer(AliAnalysisTask *consumer, Int_t islot)
139{
140// Add a consumer for contained data;
141 AliAnalysisDataSlot *slot = consumer->GetInputSlot(islot);
142 if (!slot || !slot->GetType()) {
143 cout<<"Consumer task "<< consumer->GetName()<<" does not have an input/type #"<<islot<<endl;
144 //AliError(Form("Consumer task %s does not have an input #%i", consumer->GetName(),islot));
145 return;
146 }
147 if (!slot->GetType()->InheritsFrom(GetType())) {
148 cout<<"Data type "<<slot->GetTitle()<<" for input slot "<<islot<<" of task "<<consumer->GetName()<<" does not match container type "<<GetTitle()<<endl;
149 //AliError(Form("Data type %s for input slot %i of task %s does not match container type %s", slot->GetType()->GetName(),islot,consumer->GetName(),fType->GetName()));
150 return;
151 }
152
153 if (!fConsumers) fConsumers = new TObjArray(2);
154 fConsumers->Add(consumer);
155 // Add the consumer task to the list of task of the producer
156 if (fProducer && !fProducer->GetListOfTasks()->FindObject(consumer))
157 fProducer->Add(consumer);
158}
159
160//______________________________________________________________________________
161Bool_t AliAnalysisDataContainer::ClientsExecuted() const
162{
163// Check if all client tasks have executed.
164 TIter next(fConsumers);
165 AliAnalysisTask *task;
166 while ((task=(AliAnalysisTask*)next())) {
167 if (!task->HasExecuted()) return kFALSE;
168 }
169 return kTRUE;
170}
171
172//______________________________________________________________________________
173void AliAnalysisDataContainer::DeleteData()
174{
175// Delete data if not needed anymore.
176 if (!fDataReady || !ClientsExecuted()) {
177 cout<<"Data not ready or not all clients of container "<<GetName()<<" executed. Data not deleted."<<endl;
178 //AliWarning(Form("Data not ready or not all clients of container %s executed. Data not deleted.", GetName()));
179 return;
180 }
181 if (!fOwnedData) {
182 cout<<"Data not owned by container "<<GetName()<<". Not deleted."<<endl;
183 //AliWarning(Form("Data not owned by container %s. Not deleted.", GetName()));
184 return;
185 }
186 delete fData;
187 fData = 0;
188 fDataReady = kFALSE;
189}
190
191//______________________________________________________________________________
192TClass *AliAnalysisDataContainer::GetType() const
193{
194// Get class type for this slot.
195 AliAnalysisDataContainer *cont = (AliAnalysisDataContainer*)this;
196 if (!fType) cont->SetType(gROOT->GetClass(fTitle.Data()));
197 if (!fType) printf("AliAnalysisDataContainer: Unknown class: %s\n", GetTitle());
198 return fType;
199}
200
201//______________________________________________________________________________
202void AliAnalysisDataContainer::GetEntry(Long64_t ientry)
203{
204// If data is ready and derives from TTree or from TBranch, this will get the
205// requested entry in memory if not already loaded.
206 if (!fDataReady || !GetType()) return;
207 Bool_t istree = fType->InheritsFrom(TTree::Class());
208 if (istree) {
209 TTree *tree = (TTree*)fData;
210 if (tree->GetReadEntry() != ientry) tree->GetEntry(ientry);
211 return;
212 }
213 Bool_t isbranch = fType->InheritsFrom(TBranch::Class());
214 if (isbranch) {
215 TBranch *branch = (TBranch*)fData;
216 if (branch->GetReadEntry() != ientry) branch->GetEntry(ientry);
217 return;
218 }
219}
220
221//______________________________________________________________________________
222Long64_t AliAnalysisDataContainer::Merge(TCollection *list)
223{
224// Merge a list of containers with this one. Containers in the list must have
225// data of the same type.
226 if (!list || !fData) return 0;
227 printf("Merging %d containers %s\n", list->GetSize()+1, GetName());
228 TMethodCall callEnv;
229 if (fData->IsA())
230 callEnv.InitWithPrototype(fData->IsA(), "Merge", "TCollection*");
231 if (!callEnv.IsValid() && !list->IsEmpty()) {
232 cout << "No merge interface for data stored by " << GetName() << ". Merging not possible !" << endl;
233 return 1;
37153431 234 }
235
c52c2132 236 if (list->IsEmpty()) return 1;
237
238 TIter next(list);
37153431 239 AliAnalysisDataContainer *cont;
c52c2132 240 // Make a list where to temporary store the data to be merged.
241 TList *collectionData = new TList();
242 Int_t count = 0; // object counter
243 while ((cont=(AliAnalysisDataContainer*)next())) {
244 TObject *data = cont->GetData();
245 if (!data) continue;
246 if (strcmp(cont->GetName(), GetName())) {
247 cout << "Not merging containers with different names !" << endl;
248 continue;
249 }
250 printf(" ... merging object %s\n", data->GetName());
251 collectionData->Add(data);
252 count++;
37153431 253 }
c52c2132 254 callEnv.SetParam((Long_t) collectionData);
255 callEnv.Execute(fData);
256 delete collectionData;
37153431 257
258 return count+1;
c52c2132 259}
260
261//______________________________________________________________________________
262void AliAnalysisDataContainer::PrintContainer(Option_t *option, Int_t indent) const
263{
264// Print info about this container.
265 TString ind;
266 for (Int_t i=0; i<indent; i++) ind += " ";
267 TString opt(option);
268 opt.ToLower();
269 Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
270 if (!dep) {
12856ea6 271 printf("%sContainer: %s type: %s", ind.Data(), GetName(), GetTitle());
c52c2132 272 if (fProducer)
12856ea6 273 printf("%s = Data producer: task %s",ind.Data(),fProducer->GetName());
c52c2132 274 else
12856ea6 275 printf("%s= No data producer",ind.Data());
276 printf("%s = Consumer tasks: ", ind.Data());
c52c2132 277 if (!fConsumers || !fConsumers->GetEntriesFast()) printf("-none-\n");
278 else printf("\n");
37153431 279 }
280 printf("Filename: %s\n", fFileName.Data());
c52c2132 281 TIter next(fConsumers);
282 AliAnalysisTask *task;
283 while ((task=(AliAnalysisTask*)next())) task->PrintTask(option, indent+3);
284}
285
d3106602 286//______________________________________________________________________________
327eaf46 287Bool_t AliAnalysisDataContainer::SetData(TObject *data, Option_t *)
d3106602 288{
289// Set the data as READY only if it was published by the producer.
d3106602 290 // If there is no producer declared, this is a top level container.
291 AliAnalysisTask *task;
327eaf46 292 Bool_t init = kFALSE;
d3106602 293 Int_t i, nc;
294 if (!fProducer) {
327eaf46 295 if (data != fData) init = kTRUE;
d3106602 296 fData = data;
297 fDataReady = kTRUE;
298 if (fConsumers) {
299 nc = fConsumers->GetEntriesFast();
300 for (i=0; i<nc; i++) {
301 task = (AliAnalysisTask*)fConsumers->At(i);
327eaf46 302 task->CheckNotify(init);
d3106602 303 }
304 }
305 return kTRUE;
37153431 306 }
d3106602 307 // Check if it is the producer who published the data
308 if (fProducer->GetPublishedData()==data) {
309 fData = data;
310 fDataReady = kTRUE;
d3106602 311 if (fConsumers) {
312 nc = fConsumers->GetEntriesFast();
313 for (i=0; i<nc; i++) {
314 task = (AliAnalysisTask*)fConsumers->At(i);
315 task->CheckNotify();
316 }
317 }
318 return kTRUE;
319 } else {
11026a80 320 cout<<"Data for container "<<GetName()<<" can be published only by producer task "<<fProducer->GetName()<<endl;
321 //AliWarning(Form("Data for container %s can be published only by producer task %s", GetName(), fProducer->GetName()));
322 return kFALSE;
d3106602 323 }
324}
325
d3106602 326//______________________________________________________________________________
327void AliAnalysisDataContainer::SetProducer(AliAnalysisTask *prod, Int_t islot)
328{
329// Set the producer of data. The slot number is required for data type checking.
330 if (fProducer) {
11026a80 331 cout<<"Data container "<<GetName()<<" already has a producer: "<<fProducer->GetName()<<endl;
332 //AliWarning(Form("Data container %s already has a producer: %s",GetName(),fProducer->GetName()));
d3106602 333 }
334 if (fDataReady) {
11026a80 335 cout<<GetName()<<" container contains data - cannot change producer!"<<endl;
336 //AliError(Form("%s container contains data - cannot change producer!", GetName()));
d3106602 337 return;
338 }
339 AliAnalysisDataSlot *slot = prod->GetOutputSlot(islot);
340 if (!slot) {
11026a80 341 cout<<"Producer task "<<prod->GetName()<<" does not have an output #"<<islot<<endl;
342 //AliError(Form("Producer task %s does not have an output #%i", prod->GetName(),islot));
d3106602 343 return;
344 }
c52c2132 345 if (!slot->GetType()->InheritsFrom(GetType())) {
346 cout<<"Data type "<<slot->GetTitle()<<"for output slot "<<islot<<" of task "<<prod->GetName()<<" does not match container type "<<GetTitle()<<endl;
11026a80 347 //AliError(Form("Data type %s for output slot %i of task %s does not match container type %s", slot->GetType()->GetName(),islot,prod->GetName(),fType->GetName()));
d3106602 348 return;
349 }
350
351 fProducer = prod;
352 // Add all consumers as daughter tasks
353 TIter next(fConsumers);
354 AliAnalysisTask *cons;
355 while ((cons=(AliAnalysisTask*)next())) {
356 if (!prod->GetListOfTasks()->FindObject(cons)) prod->Add(cons);
357 }
358}
981f2614 359
360//______________________________________________________________________________
361AliAnalysisDataWrapper *AliAnalysisDataContainer::ExportData() const
362{
363// Wraps data for sending it through the net.
364 AliAnalysisDataWrapper *pack = 0;
365 if (!fData) return pack;
366 pack = new AliAnalysisDataWrapper(fData);
367 pack->SetName(fName.Data());
368 return pack;
369}
370
371//______________________________________________________________________________
372void AliAnalysisDataContainer::ImportData(AliAnalysisDataWrapper *pack)
373{
374// Unwraps data from a data wrapper.
375 if (pack) {
376 fData = pack->Data();
377 fDataReady = kTRUE;
378 }
379}
d3106602 380
981f2614 381ClassImp (AliAnalysisDataWrapper)
382
383//______________________________________________________________________________
384AliAnalysisDataWrapper &AliAnalysisDataWrapper::operator=(const AliAnalysisDataWrapper &other)
385{
386// Assignment.
387 if (&other != this) {
388 TNamed::operator=(other);
389 fData = other.fData;
390 }
391 return *this;
392}
393
394//______________________________________________________________________________
395Long64_t AliAnalysisDataWrapper::Merge(TCollection *list)
396{
397// Merge a list of containers with this one. Containers in the list must have
398// data of the same type.
399 if (!fData) return 0;
400 if (!list || list->IsEmpty()) return 1;
401
402 printf("Merging %d data wrappers %s\n", list->GetSize()+1, GetName());
403 TMethodCall callEnv;
404 if (fData->InheritsFrom(TSeqCollection::Class())) {
405 TSeqCollection *coll = (TSeqCollection*)fData;
406 if (coll->IsEmpty()) return 0;
407 Int_t nentries = coll->GetEntries();
408 AliAnalysisDataWrapper *top;
409 TIter next(list);
410 TSeqCollection *collcrt = 0;
411 TList *list1 = 0;
412 for (Int_t i=0; i<nentries; i++) {
413 list1 = new TList();
414 top = new AliAnalysisDataWrapper(coll->At(i));
415 next.Reset();
416 while ((collcrt=(TSeqCollection*)next()))
417 list1->Add(new AliAnalysisDataWrapper(collcrt->At(i)));
418 if (!top->Merge(list1)) {
419 list1->Delete();
420 delete list1;
421 return 0;
422 }
423 list1->Delete();
424 delete list1;
425 }
426 return nentries;
427 }
428
429 if (fData->IsA())
430 callEnv.InitWithPrototype(fData->IsA(), "Merge", "TCollection*");
431 if (!callEnv.IsValid()) {
432 cout << "No merge interface for data stored by " << GetName() << ". Merging not possible !" << endl;
433 return 1;
434 }
435
436 TIter next(list);
437 AliAnalysisDataWrapper *cont;
438 // Make a list where to temporary store the data to be merged.
439 TList *collectionData = new TList();
440 Int_t count = 0; // object counter
441 while ((cont=(AliAnalysisDataWrapper*)next())) {
442 TObject *data = cont->Data();
443 if (!data) continue;
444 if (strcmp(cont->GetName(), GetName())) continue;
445 collectionData->Add(data);
446 count++;
447 }
448 callEnv.SetParam((Long_t) collectionData);
449 callEnv.Execute(fData);
450 delete collectionData;
451
452 return count+1;
453}