Post-event loop tasks are tasks for which the Exec() method is not called in the
main event loop, but afterwards. An example is fitting a histogram produced by
other task in the event loop. To use a task in this mode one has to:
1. Connect the task input(s) at container used as output(s) by normal event loop
task(s)
2. Use the method AliAnalysisTask::SetPostEventLoop(kTRUE), e.g.
myFitTask->SetPostEventLoop(kTRUE);
When containing post event loop tasks, the analysis will run in 2 stages: the
event loop triggered by AliAnalysisSelector first, then all remaining post event
loop tasks.
fConsumers(NULL)
{
// Dummy ctor.
- TObject::SetBit(kContEvtByEvt, kTRUE);
}
//______________________________________________________________________________
{
// Default constructor.
SetTitle(fType->GetName());
- TObject::SetBit(kContEvtByEvt, kTRUE);
}
//______________________________________________________________________________
opt.ToLower();
Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
if (!dep) {
- printf("%sContainer: %s type: %s", ind.Data(), GetName(), GetTitle());
+ printf("%sContainer: %s type: %s POST_LOOP=%i", ind.Data(), GetName(), GetTitle(), IsPostEventLoop());
if (fProducer)
printf("%s = Data producer: task %s",ind.Data(),fProducer->GetName());
else
kFileChange
};
enum EAnalysisContainerFlags {
- kContEvtByEvt
+ kPostEventLoop = BIT(14)
};
AliAnalysisDataContainer();
AliAnalysisDataContainer(const AliAnalysisDataContainer &cont);
void ResetDataReady() {fDataReady = kFALSE;}
virtual Bool_t SetData(TObject *data, Option_t *option="");
void SetDataOwned(Bool_t flag) {fOwnedData = flag;}
- void SetEventByEvent(Bool_t flag=kTRUE) {TObject::SetBit(kContEvtByEvt,flag);}
+ void SetPostEventLoop(Bool_t flag=kTRUE) {TObject::SetBit(kPostEventLoop,flag);}
void SetFileName(const char *filename) {fFileName = filename;}
void SetProducer(AliAnalysisTask *prod, Int_t islot);
void AddConsumer(AliAnalysisTask *cons, Int_t islot);
void ImportData(AliAnalysisDataWrapper *pack);
// Container status checking
Bool_t IsDataReady() const {return fDataReady;}
- Bool_t IsEventByEvent() const {return TObject::TestBit(kContEvtByEvt);}
+ Bool_t IsPostEventLoop() const {return TObject::TestBit(kPostEventLoop);}
Bool_t IsOwnedData() const {return fOwnedData;}
Bool_t ClientsExecuted() const;
Bool_t HasConsumers() const {return (fConsumers != 0);}
return br->GetAddress();
}
+//______________________________________________________________________________
+Int_t AliAnalysisDataSlot::EnableBranch(const char *bname, TTree *tree)
+{
+// Static method to enable recursively a branch in a tree (why this in not in ROOT?)
+ TBranch *branch = tree->GetBranch(bname);
+ Int_t count = 0;
+// static Int_t indent = 0;
+ if (!branch) return count;
+// TString s;
+// for (Int_t i=0; i<indent; i++) s += " ";
+ count++;
+// printf("%sbranch %s: kDoNotProcess=%d\n",s.Data(), branch->GetName(), branch->TestBit(kDoNotProcess));
+ branch->SetBit(kDoNotProcess, kFALSE);
+ TIter next(branch->GetListOfBranches());
+ TBranch *branch_sub;
+ // Activate all sub-branches
+// indent++;
+ while ((branch_sub=(TBranch*)next())) {
+ count += AliAnalysisDataSlot::EnableBranch(branch_sub->GetName(), tree);
+ }
+// indent--;
+ return count;
+}
+
//______________________________________________________________________________
Bool_t AliAnalysisDataSlot::SetBranchAddress(const char *branchname, void *address)
{
return kFALSE;
}
TTree *tree = (TTree*)GetData();
- // Activate the branch itself
- tree->SetBranchStatus(branchname,1);
- TBranch *branch = tree->GetBranch(branchname);
- if (!branch) return kFALSE;
- TIter next(branch->GetListOfLeaves());
- TLeaf *leaf;
- // Activate all sub-branches
- while ((leaf=(TLeaf*)next())) {
- branch = (TBranch*)leaf->GetBranch();
- tree->SetBranchStatus(branch->GetName(),1);
- }
tree->SetBranchAddress(branchname, address);
return kTRUE;
}
#endif
class TClass;
+class TTree;
class AliAnalysisDataContainer;
class AliAnalysisTask;
AliAnalysisDataSlot &operator=(const AliAnalysisDataSlot &slot);
// Connect some container to the slot
Bool_t ConnectContainer(AliAnalysisDataContainer *cont);
+ static Int_t EnableBranch(const char *bname, TTree *tree);
// Getters
void *GetBranchAddress(const char *branch) const;
Bool_t SetBranchAddress(const char *branch, void *address);
{
// Dummy constructor.
fgAnalysisManager = this;
+ SetEventLoop(kTRUE);
}
//______________________________________________________________________________
fContainers = new TObjArray();
fInputs = new TObjArray();
fOutputs = new TObjArray();
+ SetEventLoop(kTRUE);
}
//______________________________________________________________________________
AliAnalysisDataContainer *output;
while ((output=(AliAnalysisDataContainer*)next())) {
if (!output->GetData()) continue;
+ // Check if there are client tasks that run post event loop
+ if (output->HasConsumers()) {
+ // Disable event loop semaphore
+ output->SetPostEventLoop(kTRUE);
+ TObjArray *list = output->GetConsumers();
+ Int_t ncons = list->GetEntriesFast();
+ for (Int_t i=0; i<ncons; i++) {
+ AliAnalysisTask *task = (AliAnalysisTask*)list->At(i);
+ task->CheckNotify(kTRUE);
+ // If task is active, execute it
+ if (task->IsPostEventLoop() && task->IsActive()) {
+ if (fDebug > 1) {
+ cout << "== Executing post event loop task " << task->GetName() << endl;
+ }
+ task->ExecuteTask();
+ }
+ }
+ }
// Check if the output need to be written to a file.
const char *filename = output->GetFileName();
if (!filename || !strlen(filename)) continue;
callEnv.Execute(output->GetData());
}
output->GetData()->Write();
- // Check if there are client tasks that run in single-shot mode.
- if (!output->HasConsumers()) continue;
- output->SetEventByEvent(kFALSE);
- TObjArray *list = output->GetConsumers();
- Int_t ncons = list->GetEntriesFast();
- for (Int_t i=0; i<ncons; i++) {
- AliAnalysisTask *task = (AliAnalysisTask*)list->At(i);
- task->CheckNotify(kTRUE);
- // If task is active, execute it
- if (task->IsActive()) task->ExecuteTask();
- }
}
if (fDebug > 1) {
cout << "<-AliAnalysisManager::UnpackOutput()" << endl;
// kExchangeContainer = 0, used to exchange date between tasks
// kInputContainer = 1, used to store input data
// kOutputContainer = 2, used for posting results
+ if (fContainers->FindObject(name)) {
+ Error("CreateContainer","A container named %s already defined !\n",name);
+ return NULL;
+ }
AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
fContainers->Add(cont);
switch (type) {
fInputs->Add(cont);
break;
case kOutputContainer:
- if (fOutputs->FindObject(name)) printf("CreateContainer: warning: a container named %s existing !\n",name);
fOutputs->Add(cont);
if (filename && strlen(filename)) cont->SetFileName(filename);
break;
return kFALSE;
}
}
+ // Check that all containers feeding post-event loop tasks are in the outputs list
+ TIter nextcont(fContainers); // loop over all containers
+ while ((cont=(AliAnalysisDataContainer*)nextcont())) {
+ if (!cont->IsPostEventLoop() && !fOutputs->FindObject(cont)) {
+ if (cont->HasConsumers()) {
+ // Check if one of the consumers is post event loop
+ TIter nextconsumer(cont->GetConsumers());
+ while ((task=(AliAnalysisTask*)nextconsumer())) {
+ if (task->IsPostEventLoop()) {
+ fOutputs->Add(cont);
+ break;
+ }
+ }
+ }
+ }
+ }
fInitOK = kTRUE;
return kTRUE;
}
}
char line[128];
SetEventLoop(kFALSE);
- // Disable by default all branches and set event loop mode
+ // Disable all branches if requested and set event loop mode
if (tree) {
-// tree->SetBranchStatus("*",0);
+ if (TestBit(kDisableBranches)) {
+ printf("Disabling all branches...\n");
+// tree->SetBranchStatus("*",0); // not yet working
+ }
SetEventLoop(kTRUE);
}
- AliAnalysisDataContainer *cont = 0;
- TIter nextc(fInputs);
- // Force top containers have the same event loop type as the analysis
- while ((cont=(AliAnalysisDataContainer*)nextc())) cont->SetEventByEvent(IsEventLoop());
- AliAnalysisDataContainer *cont_top = (AliAnalysisDataContainer*)fInputs->First();
TChain *chain = dynamic_cast<TChain*>(tree);
TIter next(fTasks);
AliAnalysisTask *task;
while ((task=(AliAnalysisTask*)next())) {
- for (Int_t islot=0; islot<task->GetNinputs(); islot++) {
- cont = task->GetInputSlot(islot)->GetContainer();
- if (cont==cont_top) break;
- cont = 0;
- }
- // All tasks feeding from the top containers must have the same event loop type
-// if (cont) task->SetExecPerEvent(IsEventLoop());
-// else task->SetExecPerEvent(task->IsExecPerEvent());
task->LocalInit();
}
};
enum EAliAnalysisFlags {
- kEventLoop = BIT(14)
+ kEventLoop = BIT(14),
+ kDisableBranches = BIT(15)
};
AliAnalysisManager();
void SetAnalysisType(EAliAnalysisExecMode mode) {fMode = mode;}
void SetCurrentEntry(Long64_t entry) {fCurrentEntry = entry;}
void SetDebugLevel(UInt_t level) {fDebug = level;}
+ void SetDisableBranches(Bool_t disable=kTRUE) {TObject::SetBit(kDisableBranches,disable);}
// Container handling
AliAnalysisDataContainer *CreateContainer(const char *name, TClass *datatype,
#include <Riostream.h>
#include <TFile.h>
#include <TClass.h>
+#include <TTree.h>
#include "AliAnalysisTask.h"
#include "AliAnalysisDataSlot.h"
fOutputs(NULL)
{
// Default constructor.
- TObject::SetBit(kTaskEvtByEvt, kTRUE);
}
//______________________________________________________________________________
fOutputs(NULL)
{
// Constructor.
- TObject::SetBit(kTaskEvtByEvt, kTRUE);
fInputs = new TObjArray(2);
fOutputs = new TObjArray(2);
}
// accordingly. This method is called automatically for all tasks connected
// to a container where the data was published.
if (init) fInitialized = kFALSE;
-// Bool_t execperevent = IsExecPerEvent();
+ Bool_t single_shot = IsPostEventLoop();
AliAnalysisDataContainer *cinput;
for (Int_t islot=0; islot<fNinputs; islot++) {
cinput = GetInputSlot(islot)->GetContainer();
- if (!cinput) return;
- if (!cinput->GetData()) {
-// if (!cinput->GetData() || execperevent!=cinput->IsEventByEvent()) {
+ if (!cinput->GetData() || (single_shot && !cinput->IsPostEventLoop())) {
SetActive(kFALSE);
return;
}
}
// 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();
return GetInputSlot(islot)->SetBranchAddress(branch, address);
}
+//______________________________________________________________________________
+void AliAnalysisTask::EnableBranch(Int_t islot, const char *bname) const
+{
+// 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::ConnectInputData(Option_t *)
{
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()));
+ printf("%s\n", Form("%stask: %s ACTIVE=%i POST_LOOP=%i", ind.Data(), GetName(),IsActive(),IsPostEventLoop()));
if (dep) thistask->SetChecked(kFALSE);
else {
for (islot=0; islot<fNinputs; islot++) {
}
//______________________________________________________________________________
-void AliAnalysisTask::SetExecPerEvent(Bool_t flag)
+void AliAnalysisTask::SetPostEventLoop(Bool_t flag)
{
-// Set the task execution mode - run in a event loop or single shot. All output
+// Set the task execution mode - run after event loop or not. All output
// containers of this task will get the same type.
- TObject::SetBit(kTaskEvtByEvt,flag);
+ TObject::SetBit(kTaskPostEventLoop,flag);
AliAnalysisDataContainer *cont;
Int_t islot;
for (islot=0; islot<fNoutputs; islot++) {
cont = GetOutputSlot(islot)->GetContainer();
- if (cont) cont->SetEventByEvent(flag);
+ if (cont) cont->SetPostEventLoop(flag);
}
}
kTaskUsed = BIT(14),
kTaskZombie = BIT(15),
kTaskChecked = BIT(16),
- kTaskEvtByEvt = BIT(17)
+ kTaskPostEventLoop = BIT(17)
};
protected:
Bool_t PostData(Int_t iout, TObject *data, Option_t *option="");
//=====================================================================
- // === USE THIS FIRST IN YOUR Init() TO CHECH IF A BRANCH IS ALREADY CONNECTED
+ // === USE THIS FIRST IN YOUR ConnectInputData() TO CHECH IF A BRANCH IS ALREADY CONNECTED
// TO SOME ADDRESS.
char *GetBranchAddress(Int_t islot, const char *branch) const;
- // === CALL THIS AFTERWARDS IN Init() IF THE BRANCH ADDRESS IS NOT YET SET
+ // === CALL THIS AFTERWARDS IN ConnectInputData() IF THE BRANCH ADDRESS IS NOT YET SET
Bool_t SetBranchAddress(Int_t islot, const char *branch, void *address) const;
//=====================================================================
+ //=== CALL IN ConnectInputData() TO ENABLE ONLY EXPLICIT BRANCHES NEEDED FOR THIS TASK EXECUTION
+ void EnableBranch(Int_t islot, const char *bname) const;
+ //=====================================================================
// === CALL THIS IN CreateOutputObjects BEFORE CREATING THE OBJECT FOR EACH
// OUTPUT IOUT THAT HAS TO BE WRITTEN TO A FILE
void OpenFile(Int_t iout, Option_t *option="RECREATE") const;
TObject *GetOutputData(Int_t islot) const;
Bool_t IsOutputReady(Int_t islot) const {return fOutputReady[islot];}
Bool_t IsChecked() const {return TObject::TestBit(kTaskChecked);}
- Bool_t IsExecPerEvent() const {return TObject::TestBit(kTaskEvtByEvt);}
+ Bool_t IsPostEventLoop() const {return TObject::TestBit(kTaskPostEventLoop);}
Bool_t IsInitialized() const {return fInitialized;}
Bool_t IsReady() const {return fReady;}
Bool_t IsUsed() const {return TObject::TestBit(kTaskUsed);}
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 SetExecPerEvent(Bool_t flag=kTRUE);
+ void SetPostEventLoop(Bool_t flag=kTRUE);
void SetUsed(Bool_t flag=kTRUE);
void SetZombie(Bool_t flag=kTRUE) {TObject::SetBit(kTaskZombie,flag);}
// Main task execution