TTreeFormula and TChain

Is is possibile to use TChain with TTreeFormula? I’m wondering if I need to manually update the address every time the TChain changes the file.

1 Like

Hi,

If you call:chain->SetNotify(myformula);The TChain will update the TTreeFormula automatically.

Cheers,
Philippe.

1 Like

Thank you. Can I call it multiple times on different objects (multiple TTreeFormulas)? Can you document it somewhere?

Hi,

No, it can only be called on one object. If you have multiple TTreeFormula, you would need to wrapped them in holder object deriving from TObject and overloading the Notify method to call UpdateFormulaLeaves on each of the TTreeFormula.

Cheers,
Philippe.

1 Like

This was very helpful. Thanks!

I’m including my implementation, in case people don’t want to go through the work of coding it themselves.
It has been tested. It requires adding the TreePlayer library to your build.

Header

/*
 * TTreeFormulaGroup.h
 *
 *  Created on: Dec 10, 2013
 *      Author: kaess
 */

#ifndef TTREEFORMULAGROUP_H_
#define TTREEFORMULAGROUP_H_

#include <TObject.h>
#include <TTreeFormula.h>
#include <TList.h>

class TTreeFormulaGroup: public TObject {

public:
	//Constructor: If setOwner==kTRUE, deletes member TTreeFormulas on delete.
	TTreeFormulaGroup(bool setOwner=kTRUE);

	//Destructor: Self-explanatory.
	virtual ~TTreeFormulaGroup();

	//Notify: Calls UpdateFormulaLeaves on all member TTreeFormulas
	//Also calls Notify for each member TTreeFormula
	//Returns true if every member Notify returns true
	bool Notify(void);

	//SetNotify: Adds passed TTreeFormula to group
	//Returns true if TTreeFormula successfully added.
	bool SetNotify(TTreeFormula *);

	//UnsetNotify: Removes passed TTreeFormula from group.
	//Returns true if TTreeFormula successfully removed.
	//Returns false if it was not a member.
	bool UnsetNotify(TTreeFormula *);

private:
	//Pay no attention to the TList behind the curtain.
	TList * tlist;

};

#endif /* TTREEFORMULAGROUP_H_ */

Source

/*
 * TTreeFormulaGroup.cpp
 *
 *  Created on: Dec 10, 2013
 *      Author: kaess
 */

#include "TTreeFormulaGroup.h"
#include <TIterator.h>

TTreeFormulaGroup::TTreeFormulaGroup(bool setOwner) {
	tlist = new TList();
	tlist->SetOwner(setOwner);
}

bool TTreeFormulaGroup::Notify(void) {

	bool success=true;

	TIter ti =TIter(tlist);
	TObject * temp;

	while((temp=ti.Next())) {
		((TTreeFormula *)temp)->UpdateFormulaLeaves();
		success=temp->Notify()&&success;
	}

	return success;
}

bool TTreeFormulaGroup::SetNotify(TTreeFormula * ttf) {

	Int_t n = tlist->GetEntries();
	tlist->Add(ttf);

	return (tlist->GetEntries()==n+1);
}

bool TTreeFormulaGroup::UnsetNotify(TTreeFormula *ttf) {

	Int_t n = tlist->GetEntries();
	while(tlist->Remove(ttf));//Removes all copies of ttf

	return (tlist->GetEntries()<n);
}

TTreeFormulaGroup::~TTreeFormulaGroup() {
	delete tlist;
}
1 Like

Hi,

Yes, I was having exactly this problem, first I did not know how to tell the computer how to change the tree when using a chain, I searched this in the TTreeFormula documentation but I could not find it. I think this piece of information is pretty relevant to anyone using a “TTreeFormula” object and should be documented there.

Then I found that my code was still crashing because I could not do:

    TTreeFormula f_wt   ("wt"   , "wt"         , chain); chain->SetNotify(&f_wt);
    TTreeFormula f_wtPRW("wtPRW", "wtPRW"      , chain); chain->SetNotify(&f_wtPRW);
    TTreeFormula f_wtSLC("wtSLC", "wtSLC"      , chain); chain->SetNotify(&f_wtSLC);
    TTreeFormula f_mjj  ("mjj"  , "jetJES12_m" , chain); chain->SetNotify(&f_mjj);

And in order to do that I need to create my own class (which fortunately kkaess seems to have written already) because its not implemented in ROOT (which should be the case).

Are you planning to document all this and implement the necessary classes so that we dont have to get our code to crash for the first 5 hours before we find this post?

Also:

Despite it works bool SetNotify(TTreeFormula *); could be replaced by bool AddFormula(TTreeFormula *), because the name SetNotify is a little misleading. You are adding a formula to a TTreeFormulaGroup object and then you are doing chain->SetNotify(&mygroup) on the group.

And I think you need to put ClassDef(TTreeFormulaGroup,1); at the end of the class declaration in the header file, because you are making your class derive from TObject.

For those who find this in the future I also proposed a slightly more compact solution in another thread. It would be nice for someone to include this functionality in TObjArray.

This is a good simple idea. I added the function to all ROOT collections. See http://root.cern.ch/gitweb?p=root.git;a=commitdiff;h=5a918e25f8c5df4e51ad837e66d8fd23133dec38 in time for v6.10.

Thanks,
Philippe.

1 Like

So, for root version higher than v6.10, if I want to use TTreeFormula for TChain, does it mean I just need to type
TTreeFormula* formula = new TTreeFormula(“test”, “random”, chain)
and no need to chain.SetNotify(formula) ?

And when looping all events, just use
chain->LoadTree(jentry)
float value = formula -> EvalInstance(0);
to get the value of the formula for a certain entry?

Can you please give a simple example how to use TChain with TTreeFormula?

My root version is binary version: ROOT 6.12/06 for mac, but I find I still need to use “chain.SetNotify(formula)” before the loop. Otherwise, " *** Break *** segmentation violation" error will occur.

Although I use “chain.SetNotify(formula)” , the value evaluated from the first tree of the chain stays to be 0, while the second tree is fine (I add two trees in the chain).

Would you please help me out with it? Thank you very much!

Chen

SetNotify is still required.