--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysDataContainer - Container of data of arbitrary type deriving
+// from TObject used for analysis. A container must be connected to the
+// output data slot of a single analysis task (producer) , but also as
+// input slot for possibly several other tasks (consumers). The connected
+// slots must enforce the same data type as the container (or a derived type).
+// A container becomes the owner of the contained data once this was produced.
+//
+// Containers should be defined by the analysis module using:
+//
+// AliAnalysisModule::AddContainer(const char *name, TClass *type);
+//
+// A container should be connected to a producer:
+
+// AliAnalysisModule::ConnectOutput(AliAnalysisTask *task,
+// AliAnalysisDataContainer *cont)
+// and to its consumers:
+//
+// AliAnalysisModule::ConnectInput(AliAnalysisTask *task, Int_t islot,
+// AliAnalysisDataContainer *cont)
+//
+// The container will create an implicit connection between the producer task
+// and all consumers, which will become sub-tasks of the producer.
+//
+//==============================================================================
+
+#include "TClass.h"
+#include "TTree.h"
+#include "TFile.h"
+#include "AliLog.h"
+
+#include "AliAnalysisDataContainer.h"
+#include "AliAnalysisDataSlot.h"
+#include "AliAnalysisTask.h"
+
+ClassImp(AliAnalysisDataContainer)
+
+//______________________________________________________________________________
+AliAnalysisDataContainer::AliAnalysisDataContainer()
+{
+// Default ctor.
+ fDataReady = kFALSE;
+ fOwnedData = kFALSE;
+ fFileName = "";
+ fData = 0;
+ fType = 0;
+ fProducer = 0;
+ fConsumers = 0;
+}
+//______________________________________________________________________________
+AliAnalysisDataContainer::AliAnalysisDataContainer(const char *name, TClass *type)
+ :TNamed(name,"")
+{
+// Normal constructor.
+ fDataReady = kFALSE;
+ fOwnedData = kTRUE;
+ fFileName = "";
+ fData = 0;
+ fType = type;
+ fProducer = 0;
+ fConsumers = 0;
+}
+
+//______________________________________________________________________________
+AliAnalysisDataContainer::~AliAnalysisDataContainer()
+{
+// Destructor. Deletes data ! (What happens if data is a container ???)
+ if (fData && fOwnedData) delete fData;
+ if (fConsumers) delete fConsumers;
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisDataContainer::SetData(TObject *data, Option_t *option)
+{
+// Set the data as READY only if it was published by the producer.
+// If option is not empty the data will be saved in the file fFileName and option
+// describes the method to opent the file: NEW/CREATE, RECREATE, UPDATE
+ // If there is no producer declared, this is a top level container.
+ AliAnalysisTask *task;
+ Int_t i, nc;
+ if (!fProducer) {
+ fData = data;
+ fDataReady = kTRUE;
+ if (fConsumers) {
+ nc = fConsumers->GetEntriesFast();
+ for (i=0; i<nc; i++) {
+ task = (AliAnalysisTask*)fConsumers->At(i);
+ task->CheckNotify();
+ }
+ }
+ return kTRUE;
+ }
+ // Check if it is the producer who published the data
+ if (fProducer->GetPublishedData()==data) {
+ fData = data;
+ fDataReady = kTRUE;
+ if (strlen(option)) {
+ if (!fFileName.Length()) {
+ AliWarning(Form("Cannot write data since file name for container %s was not set", GetName()));
+ return kFALSE;
+ }
+ TFile *f = new TFile(fFileName.Data(), option);
+ if (!f->IsZombie()) {
+ fData->Write();
+ f->Write();
+ }
+ }
+ if (fConsumers) {
+ nc = fConsumers->GetEntriesFast();
+ for (i=0; i<nc; i++) {
+ task = (AliAnalysisTask*)fConsumers->At(i);
+ task->CheckNotify();
+ }
+ }
+ return kTRUE;
+ } else {
+ AliWarning(Form("Data for container %s can be published only by producer task %s",
+ GetName(), fProducer->GetName()));
+ return kFALSE;
+ }
+}
+
+//______________________________________________________________________________
+void AliAnalysisDataContainer::SetFileName(const char *name)
+{
+// Data will be written to this file if it is set using SetData(data, option)
+// Option represent the way the file is accessed: NEW, APPEND, ...
+ fFileName = name;
+}
+
+//______________________________________________________________________________
+void AliAnalysisDataContainer::GetEntry(Long64_t ientry)
+{
+// If data is ready and derives from TTree or from TBranch, this will get the
+// requested entry in memory if not already loaded.
+ if (!fDataReady) return;
+ Bool_t is_tree = fType->InheritsFrom(TTree::Class());
+ if (is_tree) {
+ TTree *tree = (TTree*)fData;
+ if (tree->GetReadEntry() != ientry) tree->GetEntry(ientry);
+ return;
+ }
+ Bool_t is_branch = fType->InheritsFrom(TBranch::Class());
+ if (is_branch) {
+ TBranch *branch = (TBranch*)fData;
+ if (branch->GetReadEntry() != ientry) branch->GetEntry(ientry);
+ return;
+ }
+}
+
+//______________________________________________________________________________
+void AliAnalysisDataContainer::SetProducer(AliAnalysisTask *prod, Int_t islot)
+{
+// Set the producer of data. The slot number is required for data type checking.
+ if (fProducer) {
+ AliWarning(Form("Data container %s already has a producer: %s",
+ GetName(),fProducer->GetName()));
+ }
+ if (fDataReady) {
+ AliError(Form("%s container contains data - cannot change producer!", GetName()));
+ return;
+ }
+ AliAnalysisDataSlot *slot = prod->GetOutputSlot(islot);
+ if (!slot) {
+ AliError(Form("Producer task %s does not have an output #%i", prod->GetName(),islot));
+ return;
+ }
+ if (!slot->GetType()->InheritsFrom(fType)) {
+ 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()));
+ return;
+ }
+
+ fProducer = prod;
+ // Add all consumers as daughter tasks
+ TIter next(fConsumers);
+ AliAnalysisTask *cons;
+ while ((cons=(AliAnalysisTask*)next())) {
+ if (!prod->GetListOfTasks()->FindObject(cons)) prod->Add(cons);
+ }
+}
+
+//______________________________________________________________________________
+void AliAnalysisDataContainer::AddConsumer(AliAnalysisTask *consumer, Int_t islot)
+{
+// Add a consumer for contained data;
+ AliAnalysisDataSlot *slot = consumer->GetInputSlot(islot);
+ if (!slot) {
+ AliError(Form("Consumer task %s does not have an input #%i", consumer->GetName(),islot));
+ return;
+ }
+ if (!slot->GetType()->InheritsFrom(fType)) {
+ 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()));
+ return;
+ }
+
+ if (!fConsumers) fConsumers = new TObjArray(2);
+ fConsumers->Add(consumer);
+ // Add the consumer task to the list of task of the producer
+ if (fProducer && !fProducer->GetListOfTasks()->FindObject(consumer))
+ fProducer->Add(consumer);
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisDataContainer::ClientsExecuted() const
+{
+// Check if all client tasks have executed.
+ TIter next(fConsumers);
+ AliAnalysisTask *task;
+ while ((task=(AliAnalysisTask*)next())) {
+ if (!task->HasExecuted()) return kFALSE;
+ }
+ return kTRUE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisDataContainer::DeleteData()
+{
+// Delete data if not needed anymore.
+ if (!fDataReady || !ClientsExecuted()) {
+ AliWarning(Form("Data not ready or not all clients of container %s executed. Data not deleted.", GetName()));
+ return;
+ }
+ if (!fOwnedData) {
+ AliWarning(Form("Data not owned by container %s. Not deleted.", GetName()));
+ return;
+ }
+ delete fData;
+ fData = 0;
+ fDataReady = kFALSE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisDataContainer::PrintContainer(Option_t *option, Int_t indent) const
+{
+// Print info about this container.
+ TString ind;
+ for (Int_t i=0; i<indent; i++) ind += " ";
+ TString opt(option);
+ opt.ToLower();
+ Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
+ if (!dep) {
+ printf("%s\n", Form("%sContainer: %s type: %s", ind.Data(), GetName(), fType->GetName()));
+ if (fProducer)
+ printf("%s\n", Form("%s = Data producer: task %s",ind.Data(),fProducer->GetName()));
+ else
+ printf("%s\n", Form("%s= No data producer"));
+ printf("%s", Form("%s = Consumer tasks: "));
+ if (!fConsumers || !fConsumers->GetEntriesFast()) printf("-none-\n");
+ else printf("\n");
+ }
+ TIter next(fConsumers);
+ AliAnalysisTask *task;
+ while ((task=(AliAnalysisTask*)next())) task->PrintTask(option, indent+3);
+}
--- /dev/null
+#ifndef ALIANALYSISDATACONTAINER_H
+#define ALIANALYSISDATACONTAINER_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysDataContainer - Container of data of arbitrary type deriving
+// from TObject used for analysis. A container must be connected to the
+// output data slot of a single analysis task (producer) , but also as
+// input slot for possibly several other tasks (consumers). The connected
+// slots must enforce the same data type as the container (or a derived type).
+// A container becomes the owner of the contained data once this was produced.
+//==============================================================================
+
+#ifndef ROOT_TNamed
+#include "TNamed.h"
+#endif
+
+class TClass;
+class TString;
+class TObjArray;
+class AliAnalysisTask;
+class AliESD;
+
+class AliAnalysisDataContainer : public TNamed {
+
+public:
+enum ENotifyMessage {
+ kDeleteData,
+ kSaveData,
+ kFileChange
+};
+ AliAnalysisDataContainer();
+ AliAnalysisDataContainer(const char *name, TClass *type);
+ virtual ~AliAnalysisDataContainer();
+
+ // Getters
+ TObject *GetData() const {return fData;}
+ TClass *GetType() const {return fType;}
+ AliAnalysisTask *GetProducer() const {return fProducer;}
+ TObjArray *GetConsumers() const {return fConsumers;}
+ virtual void GetEntry(Long64_t ientry);
+ // Setters
+ virtual Bool_t SetData(TObject *data, Option_t *option="");
+ void SetDataOwned(Bool_t flag) {fOwnedData = flag;}
+ void SetFileName(const char *name);
+ void SetProducer(AliAnalysisTask *prod, Int_t islot);
+ void AddConsumer(AliAnalysisTask *cons, Int_t islot);
+ void DeleteData();
+ // Container status checking
+ Bool_t IsDataReady() const {return fDataReady;}
+ Bool_t IsOwnedData() const {return fOwnedData;}
+ Bool_t ClientsExecuted() const;
+ Bool_t HasConsumers() const {return (fConsumers != 0);}
+ Bool_t HasProducer() const {return (fProducer != 0);}
+ // Send a notify signal to the container
+ virtual void NotifyChange(ENotifyMessage /*type*/) {;}
+ // Print connected tasks/status
+ void PrintContainer(Option_t *option="all", Int_t indent=0) const;
+
+protected:
+ Bool_t fDataReady; // Flag that data is ready
+ Bool_t fOwnedData; // Flag data ownership
+ TString fFileName; // Name of the file that will store the data if requested
+ TObject *fData; // Contained data
+ TClass *fType; // Type of contained data
+ AliAnalysisTask *fProducer; // Analysis task to which the slot belongs
+ TObjArray *fConsumers; // List of consumers of the data
+
+ ClassDef(AliAnalysisDataContainer,1) // Class describing a data container for analysis
+};
+#endif
--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysDataSlot - Class representing a data slot of an analysis task.
+// An analysis slot enforces a certain data type required by the Exec()
+// method of the analysis task. The slot must be connected to a data
+// container with data of the same type.
+//
+// The class should not be directly created by users - it is created by
+// each AliAnalysisTask when defining its input/output slots using:
+//
+// AliAnalysisTask::SetInput(Int_t index, TClass *type);
+// AliAnalysisTask::SetOutput(TClass *type);
+//
+// An existing data contaner (AliAnalysisDataContainer) can be connected to the
+// input/output slots of an analysis task using:
+//
+// AliAnalysisModule::ConnectInput(AliAnalysisTask *task, Int_t islot,
+// AliAnalysisDataContainer *cont)
+// AliAnalysisModule::ConnectOutput(AliAnalysisTask *task,
+// AliAnalysisDataContainer *cont)
+// To connect a slot to a data container, the data types declared by both must
+// match.
+//==============================================================================
+
+#include "TClass.h"
+#include "AliLog.h"
+
+#include "AliAnalysisDataSlot.h"
+#include "AliAnalysisTask.h"
+#include "AliAnalysisDataContainer.h"
+
+ClassImp(AliAnalysisDataSlot)
+
+//______________________________________________________________________________
+Bool_t AliAnalysisDataSlot::ConnectContainer(AliAnalysisDataContainer *cont)
+{
+// Connect the data slot with a given container. The operation will succeed only
+// if the type defined by the slot inherits from the type enforced by the container.
+// The error message in case of failure is posted by the caller.
+ if (!cont || !fType) return kFALSE;
+ if (!fType->InheritsFrom(cont->GetType())) {
+ AliError(Form("Data slot of type %s of task %s cannot be connected to data container %s of type %s",
+ fType->GetName(), fParent->GetName(), cont->GetName(), cont->GetType()->GetName()));
+ return kFALSE;
+ }
+ fContainer = cont;
+ return kTRUE;
+}
+
+//______________________________________________________________________________
+TObject *AliAnalysisDataSlot::GetData() const
+{
+// Retreives the data from the container if it is ready.
+ if (!fContainer) {
+ AliError(Form("Data slot of type %s of task %s has no connected data container",
+ fType->GetName(), fParent->GetName()));
+ return NULL;
+ }
+ if (!fContainer->IsDataReady()) return NULL;
+ return fContainer->GetData();
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisDataSlot::IsDataReady() const
+{
+// Check if data for this slot is ready in its container.
+ if (!fContainer) {
+ AliError(Form("Data slot of type %s of task %s has no connected data container",
+ fType->GetName(), fParent->GetName()));
+ return kFALSE;
+ }
+ return fContainer->IsDataReady();
+}
+
--- /dev/null
+#ifndef ALIANALYSISDATASLOT_H
+#define ALIANALYSISDATASLOT_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysDataSlot - Class representing a data slot of an analysis task.
+// An analysis slot enforces a certain data type required by the Exec()
+// method of the analysis task. The slot must be connected to a data
+// container with data of the same type.
+//==============================================================================
+
+#ifndef ROOT_TObject
+#include "TObject.h"
+#endif
+
+class TClass;
+class AliAnalysisDataContainer;
+class AliAnalysisTask;
+
+class AliAnalysisDataSlot : public TObject {
+
+public:
+ AliAnalysisDataSlot() : fType(NULL), fParent(NULL), fContainer(NULL) { }
+ AliAnalysisDataSlot(TClass *type, AliAnalysisTask *task) : fType(type), fParent(task), fContainer(NULL) { }
+ virtual ~AliAnalysisDataSlot() { }
+
+ // Connect some container to the slot
+ Bool_t ConnectContainer(AliAnalysisDataContainer *cont);
+ // Getters
+ TClass *GetType() const {return fType;}
+ AliAnalysisTask *GetParent() const {return fParent;}
+ AliAnalysisDataContainer *GetContainer() const {return fContainer;}
+ TObject *GetData() const;
+ // Slot status checking
+ Bool_t IsConnected() const {return ((fContainer)?kTRUE:kFALSE);}
+ Bool_t IsDataReady() const;
+
+protected:
+ TClass *fType; // Data type required by the slot
+ AliAnalysisTask *fParent; // Analysis task to which the slot belongs
+ AliAnalysisDataContainer *fContainer; // Container connected to the slot
+
+ ClassDef(AliAnalysisDataSlot,1) // Class describing an analysis data slot
+};
+#endif
--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysManager - Manager analysis class. Allows creation of several
+// analysis tasks and data containers storing their input/output. Allows
+// connecting/chaining tasks via shared data containers. Serializes the current
+// event for all tasks depending only on initial input data.
+//==============================================================================
+//
+//==============================================================================
+
+#include "TClass.h"
+#include "AliLog.h"
+
+#include "AliAnalysisManager.h"
+#include "AliAnalysisTask.h"
+#include "AliAnalysisDataContainer.h"
+#include "AliAnalysisDataSlot.h"
+
+ClassImp(AliAnalysisManager)
+
+//______________________________________________________________________________
+AliAnalysisManager::AliAnalysisManager() : TSelector()
+{
+// Default constructor.
+ if (TClass::IsCallingNew() == TClass::kDummyNew) {
+ fInitOK = kFALSE;
+ fContainers = 0;
+ fInputs = 0;
+ fOutputs = 0;
+ fTasks = 0;
+ fTopTasks = 0;
+ fZombies = 0;
+ fStatus = 0;
+ } else {
+ fInitOK = kFALSE;
+ fContainers = new TObjArray();
+ fInputs = new TObjArray();
+ fOutputs = new TObjArray();
+ fTasks = new TObjArray();
+ fTopTasks = new TObjArray();
+ fZombies = new TObjArray();
+// fStatus = new AliAnalysisInfo(this);
+ }
+}
+
+//______________________________________________________________________________
+AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other)
+ :TSelector(other)
+{
+// Copy constructor.
+ fInitOK = other.IsInitialized();
+ fContainers = new TObjArray(*other.GetContainers());
+ fInputs = new TObjArray(*other.GetInputs());
+ fOutputs = new TObjArray(*other.GetOutputs());
+ fTasks = new TObjArray(*other.GetTasks());
+ fTopTasks = new TObjArray(*other.GetTopTasks());
+ fZombies = new TObjArray(*other.GetZombieTasks());
+// fStatus = new AliAnalysisInfo(this);
+}
+
+//______________________________________________________________________________
+AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other)
+{
+// Assignment
+ if (&other != this) {
+ TSelector::operator=(other);
+ fInitOK = other.IsInitialized();
+ fContainers = new TObjArray(*other.GetContainers());
+ fInputs = new TObjArray(*other.GetInputs());
+ fOutputs = new TObjArray(*other.GetOutputs());
+ fTasks = new TObjArray(*other.GetTasks());
+ fTopTasks = new TObjArray(*other.GetTopTasks());
+ fZombies = new TObjArray(*other.GetZombieTasks());
+// fStatus = new AliAnalysisInfo(this);
+ }
+ return *this;
+}
+
+//______________________________________________________________________________
+AliAnalysisManager::~AliAnalysisManager()
+{
+// Destructor.
+ if (fContainers) {fContainers->Delete(); delete fContainers;}
+ if (fInputs) delete fInputs;
+ if (fOutputs) delete fOutputs;
+ if (fTasks) {fTasks->Delete(); delete fTasks;}
+ if (fTopTasks) delete fTopTasks;
+ if (fZombies) delete fZombies;
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::Init(TTree */*tree*/)
+{
+ // The Init() function is called when the selector needs to initialize
+ // a new tree or chain. Typically here the branch addresses of the tree
+ // will be set. It is normaly not necessary to make changes to the
+ // generated code, but the routine can be extended by the user if needed.
+ // Init() will be called many times when running with PROOF.
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::Begin(TTree */*tree*/)
+{
+ // The Begin() function is called at the start of the query.
+ // When running with PROOF Begin() is only called on the client.
+ // The tree argument is deprecated (on PROOF 0 is passed).
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::SlaveBegin(TTree */*tree*/)
+{
+ // The SlaveBegin() function is called after the Begin() function.
+ // When running with PROOF SlaveBegin() is called on each slave server.
+ // The tree argument is deprecated (on PROOF 0 is passed).
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisManager::Process(Long64_t /*entry*/)
+{
+ // The Process() function is called for each entry in the tree (or possibly
+ // keyed object in the case of PROOF) to be processed. The entry argument
+ // specifies which entry in the currently loaded tree is to be processed.
+ // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()
+ // to read either all or the required parts of the data. When processing
+ // keyed objects with PROOF, the object is already loaded and is available
+ // via the fObject pointer.
+ //
+ // This function should contain the "body" of the analysis. It can contain
+ // simple or elaborate selection criteria, run algorithms on the data
+ // of the event and typically fill histograms.
+
+ // WARNING when a selector is used with a TChain, you must use
+ // the pointer to the current TTree to call GetEntry(entry).
+ // The entry is always the local entry number in the current tree.
+ // Assuming that fChain is the pointer to the TChain being processed,
+ // use fChain->GetTree()->GetEntry(entry).
+ return kFALSE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::SlaveTerminate()
+{
+ // The SlaveTerminate() function is called after all entries or objects
+ // have been processed. When running with PROOF SlaveTerminate() is called
+ // on each slave server.
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::Terminate()
+{
+ // The Terminate() function is the last function to be called during
+ // a query. It always runs on the client, it can be used to present
+ // the results graphically or save the results to file.
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::AddTask(AliAnalysisTask *task)
+{
+// Adds a user task to the global list of tasks.
+ task->SetActive(kFALSE);
+ fTasks->Add(task);
+}
+
+//______________________________________________________________________________
+AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const
+{
+// Retreive task by name.
+ if (!fTasks) return NULL;
+ return (AliAnalysisTask*)fTasks->FindObject(name);
+}
+
+//______________________________________________________________________________
+AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name,
+ TClass *datatype, EAliAnalysisContType type)
+{
+// Create a data container of a certain type. Types can be:
+// kNormalContainer = 0, used to exchange date between tasks
+// kInputContainer = 1, used to store input data
+// kOutputContainer = 2, used for posting results
+ AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
+ fContainers->Add(cont);
+ switch (type) {
+ case kInputContainer:
+ fInputs->Add(cont);
+ break;
+ case kOutputContainer:
+ fOutputs->Add(cont);
+ break;
+ case kNormalContainer:
+ break;
+ }
+ return cont;
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
+ AliAnalysisDataContainer *cont)
+{
+// Connect input of an existing task to a data container.
+ if (!fTasks->FindObject(task)) {
+ AddTask(task);
+ AliInfo(Form("Task %s not registered. Now owned by analysis manager", task->GetName()));
+ }
+ Bool_t connected = task->ConnectInput(islot, cont);
+ return connected;
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
+ AliAnalysisDataContainer *cont)
+{
+// Connect output of an existing task to a data container.
+ if (!fTasks->FindObject(task)) {
+ AddTask(task);
+ AliInfo(Form("Task %s not registered. Now owned by analysis manager", task->GetName()));
+ }
+ Bool_t connected = task->ConnectOutput(islot, cont);
+ return connected;
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::CleanContainers()
+{
+// Clean data from all containers that have already finished all client tasks.
+ TIter next(fContainers);
+ AliAnalysisDataContainer *cont;
+ while ((cont=(AliAnalysisDataContainer *)next())) {
+ if (cont->IsOwnedData() &&
+ cont->IsDataReady() &&
+ cont->ClientsExecuted()) cont->DeleteData();
+ }
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisManager::InitAnalysis()
+{
+// Initialization of analysis chain of tasks. Should be called after all tasks
+// and data containers are properly connected
+ // Check for input/output containers
+ fInitOK = kFALSE;
+ if (!fInputs->GetEntriesFast()) {
+ AliError("No input container defined. At least one container should store input data");
+ return kFALSE;
+ }
+ if (!fOutputs->GetEntriesFast()) {
+ AliError("No output container defined. At least one container should store output data");
+ return kFALSE;
+ }
+ // Check for top tasks (depending only on input data containers)
+ if (!fTasks->First()) {
+ AliError("Analysis have no tasks !");
+ return kFALSE;
+ }
+ TIter next(fTasks);
+ AliAnalysisTask *task;
+ AliAnalysisDataContainer *cont;
+ Int_t ntop = 0;
+ Int_t nzombies = 0;
+ Bool_t is_zombie = kFALSE;
+ Bool_t is_top = kTRUE;
+ Int_t i;
+ while ((task=(AliAnalysisTask*)next())) {
+ is_top = kTRUE;
+ is_zombie = kFALSE;
+ Int_t ninputs = task->GetNinputs();
+ if (!ninputs) {
+ task->SetZombie();
+ fZombies->Add(task);
+ nzombies++;
+ AliWarning(Form("Task %s has no input slots defined ! Declared zombie...",task->GetName()));
+ continue;
+ }
+ for (i=0; i<ninputs; i++) {
+ cont = task->GetInputSlot(i)->GetContainer();
+ if (!cont) {
+ if (!is_zombie) {
+ task->SetZombie();
+ fZombies->Add(task);
+ nzombies++;
+ is_zombie = kTRUE;
+ }
+ AliWarning(Form("Input slot %i of task %s has no container connected ! Declared zombie...",
+ i,task->GetName()));
+ }
+ if (is_zombie) continue;
+ // Check if cont is an input container
+ if (is_top && !fInputs->FindObject(cont)) is_top=kFALSE;
+ // Connect to parent task
+ }
+ if (is_top) {
+ ntop++;
+ fTopTasks->Add(task);
+ }
+ }
+ if (!ntop) {
+ AliError("No top task defined. At least one task should be connected only to input containers");
+ return kFALSE;
+ }
+ // Check now if there are orphan tasks
+ for (i=0; i<ntop; i++) {
+ task = (AliAnalysisTask*)fTopTasks->At(i);
+ task->SetUsed();
+ }
+ Int_t norphans = 0;
+ next.Reset();
+ while ((task=(AliAnalysisTask*)next())) {
+ if (!task->IsUsed()) {
+ norphans++;
+ AliWarning(Form("Task %s is orphan",task->GetName()));
+ }
+ }
+ // Check the task hierarchy (no parent task should depend on data provided
+ // by a daughter task)
+ for (i=0; i<ntop; i++) {
+ task = (AliAnalysisTask*)fTopTasks->At(i);
+ if (task->CheckCircularDeps()) {
+ AliError("Found illegal circular dependencies between following tasks:");
+ PrintStatus("dep");
+ return kFALSE;
+ }
+ }
+ return kTRUE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::PrintStatus(Option_t *option) const
+{
+// Print task hierarchy.
+ TIter next(fTopTasks);
+ AliAnalysisTask *task;
+ while ((task=(AliAnalysisTask*)next()))
+ task->PrintTask(option);
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::ResetAnalysis()
+{
+// Reset all execution flags and clean containers.
+ CleanContainers();
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::ExecAnalysis(Option_t *option)
+{
+// Execute analysis.
+ TIter next(fTopTasks);
+ AliAnalysisTask *task;
+ while ((task=(AliAnalysisTask*)next()))
+ task->ExecuteTask(option);
+}
+
+//______________________________________________________________________________
+void AliAnalysisManager::FinishAnalysis()
+{
+// Finish analysis.
+}
--- /dev/null
+#ifndef ALIANALYSISMANAGER_H
+#define ALIANALYSISMANAGER_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysManager - Manager analysis class. Allows creation of several
+// analysis tasks and data containers storing their input/output. Allows
+// connecting/chaining tasks via shared data containers. Serializes the current
+// event for all tasks depending only on initial input data.
+//==============================================================================
+
+#ifndef ROOT_TSelector
+#include "TSelector.h"
+#endif
+
+class TClass;
+class AliAnalysisDataContainer;
+class AliAnalysisTask;
+
+class AliAnalysisManager : public TSelector {
+
+public:
+
+enum EAliAnalysisContType {
+ kNormalContainer = 0,
+ kInputContainer = 1,
+ kOutputContainer = 2
+};
+ AliAnalysisManager();
+ AliAnalysisManager(const AliAnalysisManager& other);
+ AliAnalysisManager& operator=(const AliAnalysisManager& other);
+ virtual ~AliAnalysisManager();
+
+ // Selector-specific methods
+ virtual void Init(TTree *tree);
+ virtual void Begin(TTree *tree);
+ virtual void SlaveBegin(TTree *tree);
+ virtual Bool_t Process(Long64_t entry);
+ virtual void SlaveTerminate();
+ virtual void Terminate();
+
+ // Getters
+ TObjArray *GetContainers() const {return fContainers;}
+ TObjArray *GetInputs() const {return fInputs;}
+ TObjArray *GetOutputs() const {return fOutputs;}
+ TObjArray *GetTasks() const {return fTasks;}
+ TObjArray *GetTopTasks() const {return fTopTasks;}
+ TObjArray *GetZombieTasks() const {return fZombies;}
+// AliAnalysisInfo *GetStatus() const {return fStatus;}
+
+ // Container handling
+ AliAnalysisDataContainer *CreateContainer(const char *name, TClass *datatype,
+ EAliAnalysisContType type=kNormalContainer);
+
+ // Including tasks and getting them
+ void AddTask(AliAnalysisTask *task);
+ AliAnalysisTask *GetTask(const char *name) const;
+
+ // Connecting data containers to task inputs/outputs
+ Bool_t ConnectInput(AliAnalysisTask *task, Int_t islot,
+ AliAnalysisDataContainer *cont);
+ Bool_t ConnectOutput(AliAnalysisTask *task, Int_t islot,
+ AliAnalysisDataContainer *cont);
+ // Garbage collection
+ void CleanContainers();
+
+ // Analysis initialization and execution, status
+ Bool_t InitAnalysis();
+ Bool_t IsInitialized() const {return fInitOK;}
+ void ResetAnalysis();
+ void ExecAnalysis(Option_t *option="");
+ void FinishAnalysis();
+ void PrintStatus(Option_t *option="all") const;
+
+protected:
+ Bool_t fInitOK; // Initialisation done
+ TObjArray *fContainers; //-> List of all containers
+ TObjArray *fInputs; //-> List of containers with input data
+ TObjArray *fOutputs; //-> List of containers with results
+ TObjArray *fTasks; //-> List of analysis tasks
+ TObjArray *fTopTasks; //-> List of top tasks
+ TObjArray *fZombies; //-> List of zombie tasks
+// AliAnalysisInfo *fStatus; // Analysis info object
+
+ ClassDef(AliAnalysisManager,1) // Analysis manager class
+};
+#endif
--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysRLContainer -
+//==============================================================================
+
+#include "AliAnalysisRLContainer.h"
+#include "TTree.h"
+#include "TFile.h"
+
+#include "AliLog.h"
+#include "AliRunLoader.h"
+#include "AliESD.h"
+#include "AliHeader.h"
+#include "AliStack.h"
+#include "AliAnalysisDataContainer.h"
+#include "AliAnalysisDataSlot.h"
+#include "AliAnalysisTask.h"
+
+ClassImp(AliAnalysisRLContainer)
+
+//______________________________________________________________________________
+AliAnalysisRLContainer::AliAnalysisRLContainer()
+{
+// Dummy ctor.
+ fRunLoader = 0;
+ fESD = 0;
+ fKineFile = 0;
+ fKinematicsLoaded = kFALSE;
+ fHeaderLoaded = kFALSE;
+}
+
+//______________________________________________________________________________
+AliAnalysisRLContainer::AliAnalysisRLContainer(const char *name)
+ :AliAnalysisDataContainer(name, TTree::Class())
+{
+// Normal constructor.
+ fRunLoader = 0;
+ fESD = 0;
+ fKineFile = 0;
+ fKinematicsLoaded = kFALSE;
+ fHeaderLoaded = kFALSE;
+}
+
+//______________________________________________________________________________
+AliAnalysisRLContainer::~AliAnalysisRLContainer()
+{
+// Destructor. Deletes data ! (What happens if data is a container ???)
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisRLContainer::SetData(TObject *data, Option_t */*option*/)
+{
+// Data must be a tree here.
+ fData = data;
+ TTree *tree = (TTree *)data;
+ // Set branch address
+ tree->SetBranchAddress("ESD", &fESD);
+ fDataReady = kTRUE;
+ return kTRUE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisRLContainer::GetEntry(Long64_t ientry)
+{
+// If data is ready and derives from TTree or from TBranch, this will get the
+// requested entry in memory if not already loaded.
+ if (!fDataReady) return;
+ TTree *tree = (TTree*)fData;
+ tree->GetTree()->GetEntry(ientry);
+ if (fRunLoader) fRunLoader->GetEvent(ientry);
+}
+
+//______________________________________________________________________________
+void AliAnalysisRLContainer::NotifyChange(ENotifyMessage type)
+{
+// Notify container that file has changed.
+ AliAnalysisDataContainer::NotifyChange(type);
+ if (!type==kFileChange) return;
+ DeleteKinematicsFile();
+ DeleteRunLoader();
+}
+
+//______________________________________________________________________________
+void AliAnalysisRLContainer::DeleteRunLoader()
+{
+// Deletes the runloader.
+ if (fRunLoader) {
+ fRunLoader->Delete();
+ fRunLoader = 0;
+ }
+ fKinematicsLoaded = kFALSE;
+ fHeaderLoaded = kFALSE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisRLContainer::DeleteKinematicsFile()
+{
+// Closes the kinematics file and deletes the pointer.
+ if (fKineFile) {
+ fKineFile->Close();
+ delete fKineFile;
+ fKineFile = 0;
+ }
+}
+
+//______________________________________________________________________________
+AliRunLoader* AliAnalysisRLContainer::GetRunLoader()
+{
+// Returns AliRun instance corresponding to current ESD active in fTree
+// Loads galice.root, the file is identified by replacing "AliESDs" to
+// "galice" in the file path of the ESD file. This is a hack, to be changed!
+
+ if (!fDataReady) return 0;
+ TTree *tree = (TTree*)fData;
+ if (!fRunLoader) {
+ if (!tree->GetCurrentFile()) return 0;
+ TString fileName(tree->GetCurrentFile()->GetName());
+ fileName.ReplaceAll("AliESDs", "galice");
+ fRunLoader = AliRunLoader::Open(fileName);
+ if (!fRunLoader) return 0;
+ if (fRunLoader->LoadgAlice() != 0) {
+ delete fRunLoader;
+ fRunLoader = 0;
+ return 0;
+ }
+ fRunLoader->GetEvent(tree->GetTree()->GetReadEntry());
+ }
+ return fRunLoader;
+}
+
+//______________________________________________________________________________
+AliHeader* AliAnalysisRLContainer::GetHeader()
+{
+// Returns header retrieved from RunLoader
+ AliRunLoader* runLoader = GetRunLoader();
+ if (!runLoader) return 0;
+ if (!fHeaderLoaded)
+ if (runLoader->LoadHeader() != 0) return 0;
+ fHeaderLoaded = kTRUE;
+ return runLoader->GetHeader();
+}
+
+//______________________________________________________________________________
+TTree* AliAnalysisRLContainer::GetKinematics()
+{
+// Returns kinematics tree corresponding to current ESD active in fTree
+// Loads the kinematics from the kinematics file, the file is identified by replacing "AliESDs" to
+// "Kinematics" in the file path of the ESD file. This is a hack, to be changed!
+
+ if (!fDataReady) return 0;
+ TTree *tree = (TTree*)fData;
+ if (!fKineFile) {
+ if (!tree->GetCurrentFile()) return 0;
+ TString fileName(tree->GetCurrentFile()->GetName());
+ fileName.ReplaceAll("AliESDs", "Kinematics");
+
+ AliDebug(AliLog::kInfo, Form("Opening %s", fileName.Data()));
+
+ fKineFile = TFile::Open(fileName);
+ if (!fKineFile) return 0;
+ }
+ return dynamic_cast<TTree*> (fKineFile->Get(Form("Event%d/TreeK", tree->GetTree()->GetReadEntry())));
+}
+
+//______________________________________________________________________________
+AliStack* AliAnalysisRLContainer::GetStack()
+{
+// Returns stack retrieved from RunLoader
+
+ AliRunLoader* runLoader = GetRunLoader();
+ if (!runLoader) return 0;
+ if (!fKinematicsLoaded)
+ if (runLoader->LoadKinematics() != 0) return 0;
+ fKinematicsLoaded = kTRUE;
+ return runLoader->Stack();
+}
--- /dev/null
+#ifndef ALIANALYSISRLCONTAINER_H
+#define ALIANALYSISRLCONTAINER_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysRLContainer - Special container working with AliRunLoader
+// with trees
+//==============================================================================
+
+#ifndef ALIANALYSISDATQCONTAINER_H
+#include "AliAnalysisDataContainer.h"
+#endif
+
+class TFile;
+class TTree;
+class AliRunLoader;
+class AliHeader;
+class AliStack;
+
+class AliAnalysisRLContainer : public AliAnalysisDataContainer {
+
+public:
+ AliAnalysisRLContainer();
+ AliAnalysisRLContainer(const char *name);
+ virtual ~AliAnalysisRLContainer();
+
+//protected:
+ AliRunLoader *GetRunLoader();
+ AliHeader *GetHeader();
+ AliStack *GetStack();
+ TTree *GetKinematics();
+ AliESD *GetESD() const {return fESD;}
+ virtual void GetEntry(Long64_t ientry);
+ virtual Bool_t SetData(TObject *data, Option_t *option="");
+ // Send a notify signal to the container
+ virtual void NotifyChange(ENotifyMessage type);
+
+private:
+ void DeleteKinematicsFile();
+ void DeleteRunLoader();
+
+ AliRunLoader* fRunLoader; //! pointer to the RunLoader if galice.root was opened
+ AliESD* fESD; //! "ESD" branch in fChain
+ TFile* fKineFile; //! pointer to Kinematics.root if the file was opened
+ Bool_t fKinematicsLoaded; // determines if the stack is properly loaded (AliRunLoader::LoadKinematics() succeeded), this is needed because the GetStack returnes a invalid stack object when the function failed
+ Bool_t fHeaderLoaded; // determines if the header is properly loaded
+
+ ClassDef(AliAnalysisRLContainer,1) // Class describing a data container using AliRunLoader
+};
+#endif
--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysTask - Class representing a basic analysis task. Any
+// user-defined task should derive from it and implement the Exec() virtual
+// method.
+//==============================================================================
+//
+// A specific user analysis task have to derive from this class. The list of
+// specific input and output slots have to be defined in the derived class ctor:
+//
+// UserTask::UserTask(name, title)
+// {
+// DefineInput(0, TTree::Class());
+// DefineInput(1, TH1::Class());
+// ...
+// DefineOutput(0, TTree::Class());
+// DefineOutput(1, MyObject::Class());
+// ...
+// }
+//
+// An existing data contaner (AliAnalysisDataContainer) can be connected to the
+// input/output slots of an analysis task. Containers should not be defined and
+// connected by the derived analysis task, but from the level of AliAnalysisManager:
+//
+// AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
+// AliAnalysisDataContainer *cont)
+// AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
+// AliAnalysisDataContainer *cont)
+// To connect a slot to a data container, the data types declared by both must
+// match.
+//==============================================================================
+
+#include "TClass.h"
+
+#include "AliLog.h"
+#include "AliAnalysisTask.h"
+#include "AliAnalysisDataSlot.h"
+#include "AliAnalysisDataContainer.h"
+
+ClassImp(AliAnalysisTask)
+
+//______________________________________________________________________________
+AliAnalysisTask::AliAnalysisTask()
+{
+// Default constructor.
+ fReady = kFALSE;
+ fNinputs = 0;
+ fNoutputs = 0;
+ fOutputReady = 0;
+ fPublishedData = 0;
+ fInputs = 0;
+ fOutputs = 0;
+}
+
+//______________________________________________________________________________
+AliAnalysisTask::AliAnalysisTask(const char *name, const char *title)
+ :TTask(name,title)
+{
+// Named constructor.
+ fReady = kFALSE;
+ fNinputs = 0;
+ fNoutputs = 0;
+ fOutputReady = 0;
+ fPublishedData = 0;
+ fInputs = new TObjArray(2);
+ fOutputs = new TObjArray(2);
+}
+
+//______________________________________________________________________________
+AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task)
+ :TTask(task)
+{
+// Copy ctor.
+ fReady = task.IsReady();
+ fNinputs = task.GetNinputs();
+ fNoutputs = task.GetNoutputs();
+ fInputs = new TObjArray((fNinputs)?fNinputs:2);
+ fOutputs = new TObjArray((fNoutputs)?fNoutputs:2);
+ fPublishedData = 0;
+ Int_t i;
+ for (i=0; i<fNinputs; i++) fInputs->AddAt(task.GetInputSlot(i),i);
+ fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
+ for (i=0; i<fNoutputs; i++) {
+ fOutputReady[i] = IsOutputReady(i);
+ fOutputs->AddAt(task.GetOutputSlot(i),i);
+ }
+}
+
+//______________________________________________________________________________
+AliAnalysisTask::~AliAnalysisTask()
+{
+// Dtor.
+ if (fInputs) {fInputs->Delete(); delete fInputs;}
+ if (fOutputs) {fOutputs->Delete(); delete fOutputs;}
+}
+
+//______________________________________________________________________________
+AliAnalysisTask& AliAnalysisTask::operator=(const AliAnalysisTask& task)
+{
+// Assignment
+ if (&task != this) {
+ TTask::operator=(task);
+ fReady = task.IsReady();
+ fNinputs = task.GetNinputs();
+ fNoutputs = task.GetNoutputs();
+ fInputs = new TObjArray((fNinputs)?fNinputs:2);
+ fOutputs = new TObjArray((fNoutputs)?fNoutputs:2);
+ fPublishedData = 0;
+ Int_t i;
+ for (i=0; i<fNinputs; i++) fInputs->AddAt(task.GetInputSlot(i),i);
+ fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
+ for (i=0; i<fNoutputs; i++) {
+ fOutputReady[i] = IsOutputReady(i);
+ fOutputs->AddAt(task.GetOutputSlot(i),i);
+ }
+ }
+ return *this;
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisTask::AreSlotsConnected()
+{
+// Check if all input/output slots are connected. If this is the case fReady=true
+ fReady = kFALSE;
+ if (!fNinputs || !fNoutputs) return kFALSE;
+ Int_t i;
+ AliAnalysisDataSlot *slot;
+ for (i=0; i<fNinputs; i++) {
+ slot = (AliAnalysisDataSlot*)fInputs->At(i);
+ if (!slot) {
+ AliError(Form("Input slot %i of task %s not defined !",i,GetName()));
+ return kFALSE;
+ }
+ if (!slot->IsConnected()) return kFALSE;
+ }
+ for (i=0; i<fNoutputs; i++) {
+ slot = (AliAnalysisDataSlot*)fOutputs->At(i);
+ if (!slot) {
+ AliError(Form("Output slot %i of task %s not defined !",i,GetName()));
+ return kFALSE;
+ }
+ if (!slot->IsConnected()) return kFALSE;
+ }
+ fReady = kTRUE;
+ return kTRUE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisTask::CheckNotify()
+{
+// Check if data is available from all inputs. Change the status of the task
+// accordingly. This method is called automatically for all tasks connected
+// to a container where the data was published.
+ for (Int_t islot=0; islot<fNinputs; islot++) {
+ if (!GetInputData(islot)) {
+ SetActive(kFALSE);
+ return;
+ }
+ }
+ SetActive(kTRUE);
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisTask::ConnectInput(Int_t islot, AliAnalysisDataContainer *cont)
+{
+// Connect an input slot to a data container.
+ AliAnalysisDataSlot *input = GetInputSlot(islot);
+ if (!input) {
+ AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
+ return kFALSE;
+ }
+ // Check type matching
+ if (!input->GetType()->InheritsFrom(cont->GetType())) {
+ 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()));
+ return kFALSE;
+ }
+ // Connect the slot to the container as input
+ if (!input->ConnectContainer(cont)) return kFALSE;
+ // Add this to the list of container consumers
+ cont->AddConsumer(this, islot);
+ AreSlotsConnected();
+ return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisTask::ConnectOutput(Int_t islot, AliAnalysisDataContainer *cont)
+{
+// Connect an output slot to a data container.
+ AliAnalysisDataSlot *output = GetOutputSlot(islot);
+ if (!output) {
+ AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
+ return kFALSE;
+ }
+ // Check type matching
+ if (!output->GetType()->InheritsFrom(cont->GetType())) {
+ 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()));
+ return kFALSE;
+ }
+ // Connect the slot to the container as output
+ if (!output->ConnectContainer(cont)) return kFALSE;
+ // Declare this as the data producer
+ cont->SetProducer(this, islot);
+ AreSlotsConnected();
+ return kTRUE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisTask::DefineInput(Int_t islot, TClass *type)
+{
+// Define an input slot and its type.
+ AliAnalysisDataSlot *input = new AliAnalysisDataSlot(type, this);
+ if (fNinputs<islot+1) fNinputs = islot+1;
+ fInputs->AddAt(input, islot);
+}
+
+//______________________________________________________________________________
+void AliAnalysisTask::DefineOutput(Int_t islot, TClass *type)
+{
+// Define an output slot and its type.
+ if (islot<0) {
+ AliError(Form("Cannot define negative output slot number for task %s", GetName()));
+ return;
+ }
+ AliAnalysisDataSlot *output = new AliAnalysisDataSlot(type, this);
+ if (fNoutputs<islot+1) {
+ fNoutputs = islot+1;
+ if (fOutputReady) delete [] fOutputReady;
+ fOutputReady = new Bool_t[fNoutputs];
+ memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
+ }
+ fOutputs->AddAt(output, islot);
+}
+
+//______________________________________________________________________________
+TClass *AliAnalysisTask::GetInputType(Int_t islot) const
+{
+// Retreive type of a given input slot.
+ AliAnalysisDataSlot *input = GetInputSlot(islot);
+ if (!input) {
+ AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
+ return NULL;
+ }
+ return (input->GetType());
+}
+
+//______________________________________________________________________________
+TClass *AliAnalysisTask::GetOutputType(Int_t islot) const
+{
+// Retreive type of a given output slot.
+ AliAnalysisDataSlot *output = GetOutputSlot(islot);
+ if (!output) {
+ AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
+ return NULL;
+ }
+ return (output->GetType());
+}
+
+//______________________________________________________________________________
+TObject *AliAnalysisTask::GetInputData(Int_t islot) const
+{
+// Retreive input data for a slot if ready. Normally called by Exec() and
+// the object has to be statically cast to the appropriate type.
+ AliAnalysisDataSlot *input = GetInputSlot(islot);
+ if (!input) {
+ AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
+ return NULL;
+ }
+ return (input->GetData());
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisTask::PostData(Int_t iout, TObject *data, Option_t *option)
+{
+// Post output data for a given ouput slot in the corresponding data container.
+// Published data becomes owned by the data container.
+// If option is specified, the container connected to the output slot must have
+// an associated file name defined. The option represents the method to open the file.
+ fPublishedData = 0;
+ AliAnalysisDataSlot *output = GetOutputSlot(iout);
+ if (!output) {
+ AliError(Form("Output slot %i not defined for analysis task %s", iout, GetName()));
+ return kFALSE;
+ }
+ if (!output->IsConnected()) {
+ AliError(Form("Output slot %i of analysis task %s not connected to any data container", iout, GetName()));
+ return kFALSE;
+ }
+ if (!fOutputReady) {
+ fOutputReady = new Bool_t[fNoutputs];
+ memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
+ }
+ fOutputReady[iout] = kTRUE;
+ fPublishedData = data;
+ return (output->GetContainer()->SetData(data, option));
+}
+
+//______________________________________________________________________________
+void AliAnalysisTask::SetUsed(Bool_t flag)
+{
+// Set 'used' flag recursively to task and all daughter tasks.
+ if (TestBit(kTaskUsed)==flag) return;
+ TObject::SetBit(kTaskUsed,flag);
+ Int_t nd = fTasks->GetSize();
+ AliAnalysisTask *task;
+ for (Int_t i=0; i<nd; i++) {
+ task = (AliAnalysisTask*)fTasks->At(i);
+ task->SetUsed(flag);
+ }
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisTask::CheckCircularDeps()
+{
+// Check for illegal circular dependencies, e.g. a daughter task should not have
+// a hierarchical parent as subtask.
+ if (IsChecked()) return kTRUE;
+ SetChecked();
+ TList *tasks = GetListOfTasks();
+ Int_t ntasks = tasks->GetSize();
+ AliAnalysisTask *task;
+ for (Int_t i=0; i<ntasks; i++) {
+ task = (AliAnalysisTask*)tasks->At(i);
+ if (task->CheckCircularDeps()) return kTRUE;
+ }
+ SetChecked(kFALSE);
+ return kFALSE;
+}
+
+//______________________________________________________________________________
+void AliAnalysisTask::PrintTask(Option_t *option, Int_t indent) const
+{
+// Print task info.
+ AliAnalysisTask *thistask = (AliAnalysisTask*)this;
+ TString opt(option);
+ opt.ToLower();
+ Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
+ TString ind;
+ Int_t islot;
+ AliAnalysisDataContainer *cont;
+ for (Int_t i=0; i<indent; i++) ind += " ";
+ if (!dep || (dep && IsChecked())) {
+ printf("%s\n", Form("%stask: %s ACTIVE=%i", ind.Data(), GetName(),IsActive()));
+ if (dep) thistask->SetChecked(kFALSE);
+ else {
+ for (islot=0; islot<fNinputs; islot++) {
+ printf("%s", Form("%s INPUT #%i: %s <- ",ind.Data(),islot, GetInputType(islot)->GetName()));
+ cont = GetInputSlot(islot)->GetContainer();
+ if (cont) printf(" [%s]\n", cont->GetName());
+ else printf(" [NO CONTAINER]\n");
+ }
+ for (islot=0; islot<fNoutputs; islot++) {
+ printf("%s", Form("%s OUTPUT #%i: %s -> ",ind.Data(),islot, GetOutputType(islot)->GetName()));
+ cont = GetOutputSlot(islot)->GetContainer();
+ if (cont) printf(" [%s]\n", cont->GetName());
+ else printf(" [NO CONTAINER]\n");
+ }
+ }
+ }
+ PrintContainers(option, indent+3);
+}
+
+//______________________________________________________________________________
+void AliAnalysisTask::PrintContainers(Option_t *option, Int_t indent) const
+{
+// Print containers info.
+ AliAnalysisDataContainer *cont;
+ TString ind;
+ for (Int_t i=0; i<indent; i++) ind += " ";
+ Int_t islot;
+ for (islot=0; islot<fNoutputs; islot++) {
+ cont = GetOutputSlot(islot)->GetContainer();
+ cont->PrintContainer(option, indent);
+ }
+}
--- /dev/null
+#ifndef ALIANALYSISTASK_H
+#define ALIANALYSISTASK_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/* $Id$ */
+// Author: Andrei Gheata, 31/05/2006
+
+//==============================================================================
+// AliAnalysysTask - Class representing a basic analysis task. Any
+// user-defined task should derive from it and implement the Exec() virtual
+// method.
+//==============================================================================
+
+#ifndef ROOT_TTask
+#include "TTask.h"
+#endif
+
+#ifndef ROOT_TObjArray
+#include "TObjArray.h"
+#endif
+
+class TClass;
+class AliAnalysisDataSlot;
+class AliAnalysisDataContainer;
+
+class AliAnalysisTask : public TTask {
+public:
+enum EAnalysisTaskFlags {
+ kTaskUsed = BIT(14),
+ kTaskZombie = BIT(15),
+ kTaskChecked = BIT(16)
+};
+protected:
+ AliAnalysisTask& operator=(const AliAnalysisTask &task);
+
+ // Define the input/output slots (called by user in the ctor of the derived class)
+ //=== CALL IN THE CONSTRUCTOR OF DERIVED CLASS TO DEFINE INPUTS/OUTPUTS ===
+ void DefineInput(Int_t islot, TClass *type);
+ void DefineOutput(Int_t islot, TClass *type);
+ //=====================================================================
+
+ // Post output data (called by Exec() when data is ready)
+ //=== CALL IN EXEC() FOR EACH OUTPUT WHEN READY ===
+ Bool_t PostData(Int_t iout, TObject *data, Option_t *option="");
+ //=====================================================================
+
+public:
+ AliAnalysisTask();
+ AliAnalysisTask(const char *name, const char *title);
+ AliAnalysisTask(const AliAnalysisTask &task);
+ virtual ~AliAnalysisTask();
+
+ // Conect inputs/outputs to data containers (by AliAnalysisModule)
+ Bool_t ConnectInput(Int_t islot, AliAnalysisDataContainer *cont);
+ Bool_t ConnectOutput(Int_t islot, AliAnalysisDataContainer *cont);
+ // Check connectivity
+ Bool_t AreSlotsConnected();
+ // Check if data for all inputs is ready
+ void CheckNotify();
+ // Check if there are illegal circular dependencies
+ Bool_t CheckCircularDeps();
+ // Getters
+ Int_t GetNinputs() const {return fNinputs;}
+ Int_t GetNoutputs() const {return fNoutputs;}
+ TObject *GetPublishedData() const {return fPublishedData;}
+ AliAnalysisDataSlot *GetInputSlot(Int_t islot) const {return (AliAnalysisDataSlot*)fInputs->At(islot);}
+ AliAnalysisDataSlot *GetOutputSlot(Int_t islot) const {return (AliAnalysisDataSlot*)fOutputs->At(islot);}
+ TClass *GetInputType(Int_t islot) const;
+ TClass *GetOutputType(Int_t islot) const;
+ // === USE THIS TO RETREIVE INPUT DATA AND STATICALLY CAST IT TO THE DECLARED TYPE
+ TObject *GetInputData(Int_t islot) const;
+ //=====================================================================
+ Bool_t IsOutputReady(Int_t islot) const {return fOutputReady[islot];}
+ Bool_t IsChecked() const {return TObject::TestBit(kTaskChecked);}
+ Bool_t IsReady() const {return fReady;}
+ Bool_t IsUsed() const {return TObject::TestBit(kTaskUsed);}
+ Bool_t IsZombie() const {return TObject::TestBit(kTaskZombie);}
+ void PrintTask(Option_t *option="all", Int_t indent=0) const;
+ void PrintContainers(Option_t *option="all", Int_t indent=0) const;
+ void SetChecked(Bool_t flag=kTRUE) {TObject::SetBit(kTaskChecked,flag);}
+ void SetUsed(Bool_t flag=kTRUE);
+ void SetZombie(Bool_t flag=kTRUE) {TObject::SetBit(kTaskZombie,flag);}
+ // Main task execution
+ //=== IMPLEMENT THIS !!! ==============================================
+ virtual void Exec(Option_t *option) = 0;
+ //=====================================================================
+ Bool_t HasExecuted() const {return fHasExecuted;}
+
+protected:
+ Bool_t fReady; // Flag if the task is ready
+ Int_t fNinputs; // Number of inputs
+ Int_t fNoutputs; // Number of outputs
+ Bool_t *fOutputReady; //[fNoutputs] Flags for output readyness
+ TObject *fPublishedData; // !published data
+ TObjArray *fInputs; // Array of input slots
+ TObjArray *fOutputs; // Array of output slots
+
+ ClassDef(AliAnalysisTask,1) // Class describing an analysis task
+};
+#endif
--- /dev/null
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class AliAnalysisDataContainer+;
+#pragma link C++ class AliAnalysisRLContainer+;
+#pragma link C++ class AliAnalysisTask+;
+#pragma link C++ class AliAnalysisDataSlot+;
+#pragma link C++ class AliAnalysisManager+;
+
+#endif
--- /dev/null
+SRCS= AliAnalysisDataContainer.cxx AliAnalysisRLContainer.cxx \
+ AliAnalysisTask.cxx AliAnalysisDataSlot.cxx AliAnalysisManager.cxx
+
+HDRS= $(SRCS:.cxx=.h)
+
+DHDR:=AnalysisTaskLinkDef.h
+
+EXPORT:=$(HDRS)
--- /dev/null
+#include "TNtuple.h"
+#include "TH1.h"
+#include "TFile.h"
+#include "TCanvas.h"
+#include "TSystem.h"
+#include "AliAnalysisTask.h"
+#include "AliAnalysisManager.h"
+#include "AliAnalysisDataContainer.h"
+
+//______________________________________________________________________________
+class TaskPt : public AliAnalysisTask {
+
+public:
+ TaskPt(const char *name);
+ virtual ~TaskPt() {;}
+
+ virtual void Exec(Option_t *option);
+
+ ClassDef(TaskPt, 0); // example of analysis
+};
+
+//______________________________________________________________________________
+class TaskCombine : public AliAnalysisTask {
+
+public:
+ TaskCombine(const char *name);
+ virtual ~TaskCombine() {;}
+
+ virtual void Exec(Option_t *option);
+
+ ClassDef(TaskCombine, 0); // example of combination
+};
+
+ClassImp(TaskPt)
+
+//______________________________________________________________________________
+TaskPt::TaskPt(const char *name)
+ :AliAnalysisTask(name,"")
+{
+// Constructor.
+ // Input slot #0 works with an Ntuple
+ DefineInput(0, TNtuple::Class());
+ // Output slot #0 writes into a TH1 container
+ DefineOutput(0, TH1F::Class());
+}
+
+//______________________________________________________________________________
+void TaskPt::Exec(Option_t *)
+{
+// Task making a pt distribution.
+ static Int_t icalls=0;
+ icalls++;
+ TCanvas *c1 = new TCanvas(Form("c%i",icalls),"Dynamic Filling Example",200,10,700,500);
+ TH1F *h1 = new TH1F(Form("hpt%i",icalls),"This is the pt distribution",100,0,5);
+ // Get input data
+ TNtuple *ntuple = (TNtuple*)GetInputData(0);
+ if (!ntuple) {
+ printf("WOOPS ! Where is input 0 for %s ?\n", GetName());
+ return;
+ }
+ Float_t px, py, pt;
+ const Int_t kUPDATE = 1000;
+ ntuple->SetBranchAddress("px", &px);
+ ntuple->SetBranchAddress("py", &py);
+ Long64_t nentries = ntuple->GetEntries();
+ for (Long64_t i=0; i<nentries; i++) {
+ ntuple->GetEntry(i);
+ pt = TMath::Sqrt(px*px+py*py);
+ h1->Fill(pt);
+ if (i && (i%kUPDATE) == 0) {
+ if (i == kUPDATE) h1->Draw();
+ c1->Modified();
+ c1->Update();
+ if (gSystem->ProcessEvents())
+ break;
+ }
+ }
+ // Post final data. It will be written to a file with option "RECREATE"
+// h1->Draw();
+ PostData(0, h1, "RECREATE");
+}
+
+ClassImp(TaskCombine)
+
+//______________________________________________________________________________
+TaskCombine::TaskCombine(const char *name)
+ :AliAnalysisTask(name,"")
+{
+// Constructor.
+ // Input slot #0 works with a TH1
+ DefineInput(0, TH1F::Class());
+ // Input slot #1 works with a TH1
+ DefineInput(1, TH1F::Class());
+ // Output slot #0 writes into a TH1 container
+ DefineOutput(0, TH1F::Class());
+}
+
+//______________________________________________________________________________
+void TaskCombine::Exec(Option_t *)
+{
+// Task combining 2 histograms.
+ new TCanvas("c2","h1+h2",200,10,700,500);
+ TH1F *h1 = (TH1F*)GetInputData(0);
+ TH1F *h2 = (TH1F*)GetInputData(1);
+ TH1F *hsum = new TH1F("hsum","h1+h2",100,0,5);
+ hsum->Add(h1);
+ hsum->Add(h2);
+ hsum->Draw();
+ PostData(0,hsum);
+}
+
+
+//______________________________________________________________________________
+void testAna()
+{
+ // Make the analysis manager
+ TFile *f = 0;
+ AliAnalysisManager *mgr = new AliAnalysisManager();
+ // Make a task
+ AliAnalysisTask *task1 = new TaskPt("PtTask1");
+ mgr->AddTask(task1);
+ AliAnalysisTask *task2 = new TaskPt("PtTask2");
+ mgr->AddTask(task2);
+ AliAnalysisTask *task = new TaskCombine("TaskCombine");
+ mgr->AddTask(task);
+ // Create containers for input/output
+ AliAnalysisDataContainer *cinput = mgr->CreateContainer("cntuple",
+ TNtuple::Class(),AliAnalysisManager::kInputContainer);
+ AliAnalysisDataContainer *coutput1 = mgr->CreateContainer("chist1", TH1::Class());
+ AliAnalysisDataContainer *coutput2 = mgr->CreateContainer("chist2", TH1::Class());
+ AliAnalysisDataContainer *coutput = mgr->CreateContainer("chistsum",
+ TH1::Class(),AliAnalysisManager::kOutputContainer);
+ coutput1->SetFileName("output1.root");
+ coutput2->SetFileName("output2.root");
+ mgr->ConnectInput(task1,0,cinput);
+ mgr->ConnectInput(task2,0,cinput);
+ mgr->ConnectOutput(task1,0,coutput1);
+ mgr->ConnectOutput(task2,0,coutput2);
+ mgr->ConnectInput(task,0,coutput1);
+ mgr->ConnectInput(task,1,coutput2);
+ mgr->ConnectOutput(task,0,coutput);
+ // Open data
+ if (!gSystem->AccessPathName("hsimple.root")) {
+ f = new TFile("hsimple.root");
+ TNtuple *ntpl = (TNtuple*)f->Get("ntuple");
+ cinput->SetData(ntpl);
+ } else {
+ printf("FIRST run $ROOTSYS/tutorials/hsimple.C\n");
+ return;
+ }
+
+ if (mgr->InitAnalysis()) {
+ mgr->PrintStatus();
+ mgr->ExecAnalysis();
+ }
+}
+