X-Git-Url: http://git.uio.no/git/?a=blobdiff_plain;f=ANALYSIS%2FAliAnalysisTask.cxx;h=0d608b294ced93a4b73fd4c3665acc8c7540bc83;hb=041e39a01cecf9c7759d1b0347635210d1d0b32d;hp=223845c4976cff99d828da411484d49bfddb1a9b;hpb=0b28fd572e7c99af7c7f6d12acd7044923da6cdf;p=u%2Fmrichter%2FAliRoot.git diff --git a/ANALYSIS/AliAnalysisTask.cxx b/ANALYSIS/AliAnalysisTask.cxx index 223845c4976..0d608b294ce 100644 --- a/ANALYSIS/AliAnalysisTask.cxx +++ b/ANALYSIS/AliAnalysisTask.cxx @@ -46,36 +46,68 @@ // To connect a slot to a data container, the data types declared by both must // match. // -// The method Init will be called once per session at the moment when the data is -// available at all input slots. -// The method Init() has to be overloaded by the derived class in order to: -// 1. Define objects that should be created only once per session (e.g. output -// histograms) -// 2. Set the branch address or connect to a branch address in case the input -// slots are connected to trees. -// +// The method ConnectInputData() has to be overloaded by the derived class in order to +// set the branch address or connect to a branch address in case the input +// slots are connected to trees. // Example: -// MyAnalysisTask::Init(Option_t *) +// MyAnalysisTask::ConnectInputData(Option_t *) // { -// if (!fHist1) fHist1 = new TH1F("h1", ....); -// if (!fHist2) fHist2 = new TH1F("h2", ....); -// fESD = GetBranchAddress(islot=0, "ESD"); -// if (!fESD) SetBranchAddress(islot=0, "ESD", &fESD); +// // One should first check if the branch address was taken by some other task +// char ** address = (char **)GetBranchAddress(0, "ESD"); +// if (address) { +// fESD = (AliESD*)(*address); +// } else { +// fESD = new AliESD(); +// SetBranchAddress(0, "ESD", &fESD); +// } +// } +// +// The method LocalInit() may be implemented to call locally (on the client) +// all initialization methods of the class. It is not mandatory and was created +// in order to minimize the complexity and readability of the analysis macro. +// DO NOT create in this method the histigrams or task output objects that will +// go in the task output containers. Use CreateOutputObjects for that. +// +// The method CreateOutputObjects() has to be implemented an will contain the +// objects that should be created only once per session (e.g. output +// histograms) +// +// void MyAnalysisTask::CreateOutputObjects() +//{ + // create histograms +// fhPt = new TH1F("fhPt","This is the Pt distribution",15,0.1,3.1); +// fhPt->SetStats(kTRUE); +// fhPt->GetXaxis()->SetTitle("P_{T} [GeV]"); +// fhPt->GetYaxis()->SetTitle("#frac{dN}{dP_{T}}"); +// fhPt->GetXaxis()->SetTitleColor(1); +// fhPt->SetMarkerStyle(kFullCircle); // } // // The method Terminate() will be called by the framework once at the end of -// data processing. Overload this if needed. +// data processing. Overload this if needed. DO NOT ASSUME that the pointers +// to histograms defined in CreateOutputObjects() are valid, since this is +// not true in case of PROOF. Restore the pointer values like: +// +//void MyAnalysisTask::Terminate(Option_t *) +//{ +// fhPt = (TH1F*)GetOutputData(0); +// ... +//} + // //============================================================================== #include +#include #include -#include +#include +#include +#include -//#include "AliLog.h" #include "AliAnalysisTask.h" #include "AliAnalysisDataSlot.h" #include "AliAnalysisDataContainer.h" +#include "AliAnalysisManager.h" ClassImp(AliAnalysisTask) @@ -88,7 +120,8 @@ AliAnalysisTask::AliAnalysisTask() fOutputReady(NULL), fPublishedData(NULL), fInputs(NULL), - fOutputs(NULL) + fOutputs(NULL), + fBranchNames() { // Default constructor. } @@ -103,7 +136,8 @@ AliAnalysisTask::AliAnalysisTask(const char *name, const char *title) fOutputReady(NULL), fPublishedData(NULL), fInputs(NULL), - fOutputs(NULL) + fOutputs(NULL), + fBranchNames() { // Constructor. fInputs = new TObjArray(2); @@ -120,7 +154,8 @@ AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task) fOutputReady(NULL), fPublishedData(NULL), fInputs(NULL), - fOutputs(NULL) + fOutputs(NULL), + fBranchNames(task.fBranchNames) { // Copy ctor. fInputs = new TObjArray((fNinputs)?fNinputs:2); @@ -139,6 +174,7 @@ AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task) AliAnalysisTask::~AliAnalysisTask() { // Dtor. + if (fTasks) fTasks->Clear(); if (fInputs) {fInputs->Delete(); delete fInputs;} if (fOutputs) {fOutputs->Delete(); delete fOutputs;} } @@ -163,6 +199,7 @@ AliAnalysisTask& AliAnalysisTask::operator=(const AliAnalysisTask& task) fOutputReady[i] = IsOutputReady(i); fOutputs->AddAt(new AliAnalysisDataSlot(*task.GetOutputSlot(i)),i); } + fBranchNames = task.fBranchNames; return *this; } @@ -177,8 +214,7 @@ Bool_t AliAnalysisTask::AreSlotsConnected() for (i=0; iAt(i); if (!slot) { - cout<<"Input slot "<IsConnected()) return kFALSE; @@ -186,8 +222,7 @@ Bool_t AliAnalysisTask::AreSlotsConnected() for (i=0; iAt(i); if (!slot) { - cout<<"Output slot "<IsConnected()) return kFALSE; @@ -203,8 +238,11 @@ void AliAnalysisTask::CheckNotify(Bool_t init) // accordingly. This method is called automatically for all tasks connected // to a container where the data was published. if (init) fInitialized = kFALSE; + Bool_t single_shot = IsPostEventLoop(); + AliAnalysisDataContainer *cinput; for (Int_t islot=0; islotGetContainer(); + if (!cinput->GetData() || (single_shot && !cinput->IsPostEventLoop())) { SetActive(kFALSE); return; } @@ -212,25 +250,64 @@ void AliAnalysisTask::CheckNotify(Bool_t init) SetActive(kTRUE); if (fInitialized) return; TDirectory *cursav = gDirectory; - Init(); + ConnectInputData(); if (cursav) cursav->cd(); fInitialized = kTRUE; } +//______________________________________________________________________________ +Bool_t AliAnalysisTask::CheckPostData() const +{ +// Checks if data was posted to all outputs defined by the task. If task does +// not have output slots this returns always kTRUE. + Bool_t dataPosted = kTRUE; + AliAnalysisDataContainer *coutput; + AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager(); + for (Int_t islot=0; islotGetContainer(); + if (!mgr->GetOutputs()->FindObject(coutput)) continue; + if (!coutput->GetData()) { + Error("CheckPostData", "Data not posted for slot #%d of task %s (%s)", + islot, GetName(), ClassName()); + dataPosted = kFALSE; + } + } + CheckOwnership(); + return dataPosted; +} + +//______________________________________________________________________________ +Bool_t AliAnalysisTask::CheckOwnership() const +{ +// Check ownership of containers posted on output slots (1 level only) + TObject *outdata; + for (Int_t islot=0; islotInheritsFrom(TCollection::Class())) { + TCollection *coll = (TCollection*)outdata; + if (!coll->IsOwner()) { + Error("CheckOwnership","####### IMPORTANT! ####### \n\n\n\ + Task %s (%s) posts a container that is not owner at output #%d. This may apply for other embedded containers. \n\n\ + ####### FIX YOUR CODE, THIS WILL PRODUCE A FATAL ERROR IN FUTURE! ##########", GetName(), ClassName(), islot); + return kFALSE; + } + } + } + return kTRUE; +} + //______________________________________________________________________________ Bool_t AliAnalysisTask::ConnectInput(Int_t islot, AliAnalysisDataContainer *cont) { // Connect an input slot to a data container. AliAnalysisDataSlot *input = GetInputSlot(islot); if (!input) { - cout<<"Input slot "<GetType()->InheritsFrom(cont->GetType())) { - cout<<"Data type "<GetType()->GetName()<<" for input "<GetName()<<" of type "<GetType()->GetName()<GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName())); + Error("ConnectInput","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 @@ -247,18 +324,18 @@ Bool_t AliAnalysisTask::ConnectOutput(Int_t islot, AliAnalysisDataContainer *con // Connect an output slot to a data container. AliAnalysisDataSlot *output = GetOutputSlot(islot); if (!output) { - cout<<"Output slot "<GetType()->InheritsFrom(cont->GetType())) { - cout<<"Data type "<GetType()->GetName()<<" for output "<GetName()<<" of type "<GetType()->GetName()<GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName())); + Error("ConnectOutput","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; + // Set event loop type the same as for the task + cont->SetPostEventLoop(IsPostEventLoop()); // Declare this as the data producer cont->SetProducer(this, islot); AreSlotsConnected(); @@ -278,11 +355,6 @@ void AliAnalysisTask::DefineInput(Int_t islot, TClass *type) void AliAnalysisTask::DefineOutput(Int_t islot, TClass *type) { // Define an output slot and its type. - if (islot<0) { - cout<<"Cannot define negative output slot number for task "<GetType()); @@ -312,8 +383,7 @@ TClass *AliAnalysisTask::GetOutputType(Int_t islot) const // Retreive type of a given output slot. AliAnalysisDataSlot *output = GetOutputSlot(islot); if (!output) { - cout<<"Output slot "<GetType()); @@ -326,13 +396,25 @@ TObject *AliAnalysisTask::GetInputData(Int_t islot) const // the object has to be statically cast to the appropriate type. AliAnalysisDataSlot *input = GetInputSlot(islot); if (!input) { - cout<<"Input slot "<GetData()); } +//______________________________________________________________________________ +TObject *AliAnalysisTask::GetOutputData(Int_t islot) const +{ +// Retreive output data for a slot. Normally called in UserTask::Terminate to +// get a valid pointer to data even in case of Proof. + AliAnalysisDataSlot *output = GetOutputSlot(islot); + if (!output) { + Error("GetOutputData","Input slot %d not defined for analysis task %s", islot, GetName()); + return NULL; + } + return (output->GetData()); +} + //______________________________________________________________________________ char *AliAnalysisTask::GetBranchAddress(Int_t islot, const char *branch) const { @@ -350,23 +432,107 @@ Bool_t AliAnalysisTask::SetBranchAddress(Int_t islot, const char *branch, void * } //______________________________________________________________________________ -void AliAnalysisTask::Init(Option_t *) +void AliAnalysisTask::EnableBranch(Int_t islot, const char *bname) const { -// Branch address initialization. +// Call this in ConnectInputData() to enable only the branches needed by this +// task. "*" will enable everything. + AliAnalysisDataSlot *input = GetInputSlot(islot); + if (!input || !input->GetType()->InheritsFrom(TTree::Class())) { + Error("EnableBranch", "Wrong slot type #%d for task %s: not TTree-derived type", islot, GetName()); + return; + } + TTree *tree = (TTree*)input->GetData(); + if (!strcmp(bname, "*")) { + tree->SetBranchStatus("*",1); + return; + } + AliAnalysisDataSlot::EnableBranch(bname, tree); } //______________________________________________________________________________ -void AliAnalysisTask::Terminate(Option_t *) +void AliAnalysisTask::FinishTaskOutput() { -// Method called by the framework at the end of data processing. +// Optional method that is called in SlaveTerminate phase. +// Used for calling aditional methods just after the last event was processed ON +// THE WORKING NODE. The call is made also in local case. +// Do NOT delete output objects here since they will have to be sent for +// merging in PROOF mode - use class destructor for cleanup. +} + +//______________________________________________________________________________ +void AliAnalysisTask::ConnectInputData(Option_t *) +{ +// Overload and connect your branches here. } //______________________________________________________________________________ -void AliAnalysisTask::OpenFile(Int_t iout, const char *name, Option_t *option) const +void AliAnalysisTask::LocalInit() { -// Set data at output iout to be written in the specified file. - GetOutputSlot(iout)->GetContainer()->OpenFile(name, option); -} +// The method LocalInit() may be implemented to call locally (on the client) +// all initialization methods of the class. It is not mandatory and was created +// in order to minimize the complexity and readability of the analysis macro. +// DO NOT create in this method the histigrams or task output objects that will +// go in the task output containers. Use CreateOutputObjects for that. +} + +//______________________________________________________________________________ +void AliAnalysisTask::CreateOutputObjects() +{ +// Called once per task either in PROOF or local mode. Overload to put some +// task initialization and/or create your output objects here. +} + +//______________________________________________________________________________ +TFile *AliAnalysisTask::OpenFile(Int_t iout, Option_t *option) const +{ +// This method has to be called INSIDE the user redefined CreateOutputObjects +// method, before creating each object corresponding to the output containers +// that are to be written to a file. This need to be done in general for the big output +// objects that may not fit memory during processing. +// - 'option' is the file opening option. +//========================================================================= +// NOTE !: The method call will be ignored in PROOF mode, in which case the +// results have to be streamed back to the client and written just before Terminate() +//========================================================================= +// +// Example: +// void MyAnaTask::CreateOutputObjects() { +// OpenFile(0); // Will open the file for the object to be written at output #0 +// fAOD = new TTree("AOD for D0toKPi"); +// OpenFile(1); +// now some histos that should go in the file of the second output container +// fHist1 = new TH1F("my quality check hist1",...); +// fHist2 = new TH2F("my quality check hist2",...); +// } + + if (iout<0 || iout>=fNoutputs) { + Error("OpenFile", "No output slot for task %s with index %d", GetName(), iout); + return NULL; + } + // Method delegated to the analysis manager (A.G. 02/11/09) + AliAnalysisDataContainer *cont = GetOutputSlot(iout)->GetContainer(); + return AliAnalysisManager::OpenFile(cont, option); +} + +//______________________________________________________________________________ +Bool_t AliAnalysisTask::Notify() +{ +// Overload this IF you need to treat input file change. + return kTRUE; +} + +//______________________________________________________________________________ +Bool_t AliAnalysisTask::NotifyBinChange() +{ +// Overload this IF you need to treat bin change in event mixing. + return kTRUE; +} + +//______________________________________________________________________________ +void AliAnalysisTask::Terminate(Option_t *) +{ +// Method called by the framework at the end of data processing. +} //______________________________________________________________________________ Bool_t AliAnalysisTask::PostData(Int_t iout, TObject *data, Option_t *option) @@ -378,13 +544,11 @@ Bool_t AliAnalysisTask::PostData(Int_t iout, TObject *data, Option_t *option) fPublishedData = 0; AliAnalysisDataSlot *output = GetOutputSlot(iout); if (!output) { - cout<<"Output slot "<IsConnected()) { - cout<<"Output slot "<SetChecked(kFALSE); + printf("______________________________________________________________________________\n"); + printf("%s\n", Form("%stask: %s ACTIVE=%i POST_LOOP=%i", ind.Data(), GetName(),IsActive(),IsPostEventLoop())); + if (dep) const_cast(this)->SetChecked(kFALSE); else { for (islot=0; islotGetName())); @@ -459,6 +623,7 @@ void AliAnalysisTask::PrintTask(Option_t *option, Int_t indent) const } } PrintContainers(option, indent+3); + if (!fBranchNames.IsNull()) printf("Requested branches: %s\n", fBranchNames.Data()); } //______________________________________________________________________________ @@ -471,6 +636,36 @@ void AliAnalysisTask::PrintContainers(Option_t *option, Int_t indent) const Int_t islot; for (islot=0; islotGetContainer(); - cont->PrintContainer(option, indent); + if (cont) cont->PrintContainer(option, indent); } } + +//______________________________________________________________________________ +void AliAnalysisTask::SetPostEventLoop(Bool_t flag) +{ +// Set the task execution mode - run after event loop or not. All output +// containers of this task will get the same type. + TObject::SetBit(kTaskPostEventLoop,flag); + AliAnalysisDataContainer *cont; + Int_t islot; + for (islot=0; islotGetContainer(); + if (cont) cont->SetPostEventLoop(flag); + } +} + +//______________________________________________________________________________ +void AliAnalysisTask::GetBranches(const char *type, TString &result) const +{ +// Get the list of branches for a given type (ESD, AOD). The list of branches +// requested by a task has to ve declared in the form: +// SetBranches("ESD:branch1,branch2,...,branchN AOD:branch1,branch2,...,branchM") + result = ""; + if (fBranchNames.IsNull()) return; + Int_t index1 = fBranchNames.Index(type); + if (index1<0) return; + index1 += 1+strlen(type); + Int_t index2 = fBranchNames.Index(" ", index1); + if (index2<0) index2 = fBranchNames.Length(); + result = fBranchNames(index1, index2-index1); +}