First prototype of the new analysis framework (A.Gheata)
authorhristov <hristov@f7af4fe6-9843-0410-8265-dc069ae4e863>
Sun, 16 Jul 2006 21:19:34 +0000 (21:19 +0000)
committerhristov <hristov@f7af4fe6-9843-0410-8265-dc069ae4e863>
Sun, 16 Jul 2006 21:19:34 +0000 (21:19 +0000)
13 files changed:
ANALYSIS/AliAnalysisDataContainer.cxx [new file with mode: 0644]
ANALYSIS/AliAnalysisDataContainer.h [new file with mode: 0644]
ANALYSIS/AliAnalysisDataSlot.cxx [new file with mode: 0644]
ANALYSIS/AliAnalysisDataSlot.h [new file with mode: 0644]
ANALYSIS/AliAnalysisManager.cxx [new file with mode: 0644]
ANALYSIS/AliAnalysisManager.h [new file with mode: 0644]
ANALYSIS/AliAnalysisRLContainer.cxx [new file with mode: 0644]
ANALYSIS/AliAnalysisRLContainer.h [new file with mode: 0644]
ANALYSIS/AliAnalysisTask.cxx [new file with mode: 0644]
ANALYSIS/AliAnalysisTask.h [new file with mode: 0644]
ANALYSIS/AnalysisTaskLinkDef.h [new file with mode: 0644]
ANALYSIS/libANALYSIS_NEW.pkg [new file with mode: 0644]
ANALYSIS/testAna.C [new file with mode: 0644]

diff --git a/ANALYSIS/AliAnalysisDataContainer.cxx b/ANALYSIS/AliAnalysisDataContainer.cxx
new file mode 100644 (file)
index 0000000..ed782a8
--- /dev/null
@@ -0,0 +1,274 @@
+/**************************************************************************
+ * 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);
+}   
diff --git a/ANALYSIS/AliAnalysisDataContainer.h b/ANALYSIS/AliAnalysisDataContainer.h
new file mode 100644 (file)
index 0000000..dc16665
--- /dev/null
@@ -0,0 +1,75 @@
+#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
diff --git a/ANALYSIS/AliAnalysisDataSlot.cxx b/ANALYSIS/AliAnalysisDataSlot.cxx
new file mode 100644 (file)
index 0000000..9804a95
--- /dev/null
@@ -0,0 +1,91 @@
+/**************************************************************************
+ * 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();
+}
+   
diff --git a/ANALYSIS/AliAnalysisDataSlot.h b/ANALYSIS/AliAnalysisDataSlot.h
new file mode 100644 (file)
index 0000000..2062bf3
--- /dev/null
@@ -0,0 +1,49 @@
+#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
diff --git a/ANALYSIS/AliAnalysisManager.cxx b/ANALYSIS/AliAnalysisManager.cxx
new file mode 100644 (file)
index 0000000..b5cbda9
--- /dev/null
@@ -0,0 +1,373 @@
+/**************************************************************************
+ * 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.
+}
diff --git a/ANALYSIS/AliAnalysisManager.h b/ANALYSIS/AliAnalysisManager.h
new file mode 100644 (file)
index 0000000..3828946
--- /dev/null
@@ -0,0 +1,91 @@
+#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
diff --git a/ANALYSIS/AliAnalysisRLContainer.cxx b/ANALYSIS/AliAnalysisRLContainer.cxx
new file mode 100644 (file)
index 0000000..7bfaf2e
--- /dev/null
@@ -0,0 +1,193 @@
+/**************************************************************************
+ * 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();
+}
diff --git a/ANALYSIS/AliAnalysisRLContainer.h b/ANALYSIS/AliAnalysisRLContainer.h
new file mode 100644 (file)
index 0000000..3eca65b
--- /dev/null
@@ -0,0 +1,54 @@
+#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
diff --git a/ANALYSIS/AliAnalysisTask.cxx b/ANALYSIS/AliAnalysisTask.cxx
new file mode 100644 (file)
index 0000000..68cd15b
--- /dev/null
@@ -0,0 +1,393 @@
+/**************************************************************************
+ * 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);
+   }   
+}
diff --git a/ANALYSIS/AliAnalysisTask.h b/ANALYSIS/AliAnalysisTask.h
new file mode 100644 (file)
index 0000000..bf99b20
--- /dev/null
@@ -0,0 +1,101 @@
+#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
diff --git a/ANALYSIS/AnalysisTaskLinkDef.h b/ANALYSIS/AnalysisTaskLinkDef.h
new file mode 100644 (file)
index 0000000..8ef9a4e
--- /dev/null
@@ -0,0 +1,13 @@
+#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
diff --git a/ANALYSIS/libANALYSIS_NEW.pkg b/ANALYSIS/libANALYSIS_NEW.pkg
new file mode 100644 (file)
index 0000000..4c9b0b3
--- /dev/null
@@ -0,0 +1,8 @@
+SRCS= AliAnalysisDataContainer.cxx AliAnalysisRLContainer.cxx \
+      AliAnalysisTask.cxx AliAnalysisDataSlot.cxx AliAnalysisManager.cxx
+
+HDRS= $(SRCS:.cxx=.h) 
+
+DHDR:=AnalysisTaskLinkDef.h
+
+EXPORT:=$(HDRS)
diff --git a/ANALYSIS/testAna.C b/ANALYSIS/testAna.C
new file mode 100644 (file)
index 0000000..4ebf070
--- /dev/null
@@ -0,0 +1,157 @@
+#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();
+   }   
+}                         
+