Correct way to fill TTree using a variable class

Hi ROOTers,

So, I hve always had problems filling a TTree with variables from a c-struct like class and have been able to fix it by trial and error. But now this time I want to know the exact way of dooing this:

Firstly I want to know, is this not a good way to do things? I want to avoid SetBranchAddress for each variable by hand, which I think is cumbersome, hence I use this class method.

Secondly, here is what I do. So I have a variable class and class that fills in the tree and writes it to a file. I compile these with a Makefile, which compiles without errors. Then I run this program to fill trees, and it runs without complaint, but ofcourse the tree does not have the leaves I assign to it - the tree shows up, just the leaves (the variables from my class) aren’t there. What am I doing wrong?

Here is my code:

#include <newclassvar.hxx>
#include <TTree.h>
#include <TFile.h>


class classA: public classB::functionC {
public:
  classA() {}
  virtual ~classA() {}

  TFile *sfile;
  TTree* fOutputTree;
  Newclassvar *snewclassvar;

  virtual void Initialize(void) {
    sfile = new TFile ("SFiles.root","RECREATE");
    
    fOutputTree = new TTree("userLoopTree","A simple summary tree");
    fOutputTree->SetDirectory(sfile);

    snewclassvar = new Newclassvar;

    fOutputTree->Branch("SBranch",&snewclassvar, 16000,0);
    
  }

  bool operator () (classB::D& event) {
    //do some stuff to get variables; for now I'll use dummies
    snewclassvar->var1 = 10.;
    snewclassvar->var2 = 11.;
    fOutputTree->Fill();
    return true; 
  }
 
  void Finalize(classB::E& output) {
    
    sfile->cd();
    fOutputTree->SetDirectory(sfile);
    fOutputTree->Write();    
    sfile->Write();
    sfile->Close();
    fOutputTree->Print();

  }

};

int main(int argc, char **argv) {
  classA usercode;
}

and my variables class looks like this:

#include <TTree.h>

class Newclassvar : public TObject
{
public:

int var1; 
double var2; 

Newclassvar():
var1(0),
var2(0.){}

ClassDef (Newclassvar,0);
};

Thanks in advance!

  • Sujeewa

[quote]Firstly I want to know, is this not a good way to do things? [/quote]Yes, it is, except for a few minor details.

[quote]Then I run this program to fill trees, and it runs without complaint, but ofcourse the tree does not have the leaves I assign to it[/quote]How do you assert this? I assume that you do not see them in tree->Print(); but you should see you variable in the TBrowser.

[quote]the tree shows up, just the leaves (the variables from my class) aren’t there. [/quote]Technically, you explicitly requested for them not to be there. In fOutputTree->Branch("SBranch",&snewclassvar, 16000,0);the ‘0’ at the end is the split level you request. So here you explicitly request only one branch for your class. If you want the class to be split more (and thus leaves to appear in tree->Print() and also getting better compression and better performance), you ought to leave this value to the default (i.e. 99).

Also in Finalize, the part fOutputTree->SetDirectory(sfile);is unnecessary, as you already did it at the beginning.

The part sfile->Close(); fOutputTree->Print();because the TTree is owned by the TFile and thus the area pointed to by fOutputTree is deleted when you call sfile->Close().

Cheers,
Philippe

Hi Philippe,

Thanks! but…

So I have made the changes you suggested :

fOutputTree->Branch(“SBranch”,&snewclassvar, 16000,99);

removed the SetDirectory in Finalize

fOutputTree->Print();
sfile->Close();

And it still isn’t working. Like before no errors thrown, but the TTree::Print() statement returns nothing and if I do a TRootBrowser, it has nothing either.

  • Sujeewa

[quote]And it still isn’t working. Like before no errors thrown, but the TTree::Print() statement returns nothing[/quote]I do not know how TTree::Print could return nothing after a ‘quiet’ call to Branch, the code snippet you shown look perfectly fine. So I am guessing there is something in their interaction or in the not-shown part that is affecting the result. I would need a complete running example to understand the problem.

For example, I filling a few blanks in your code and adapted to compile and run via ACLiC and with the attached file I get:[code]$ root.exe -b -l -q working.C+
root [0]
Processing working.C+…
Info in TUnixSystem::ACLiC: creating shared library /var/tmp/./working_C.so


*Tree :userLoopTree: A simple summary tree *
*Entries : 2 : Total = 2276 bytes File Size = 0 *

  •    :          : Tree compression factor =   1.00                       *
    

*Branch :SBranch *
*Entries : 2 : BranchElement (see below) *

*Br 0 :var1 : Int_t *
*Entries : 2 : Total Size= 656 bytes One basket in memory *
*Baskets : 0 : Basket Size= 16000 bytes Compression= 1.00 *

*Br 1 :var2 : Int_t *
*Entries : 2 : Total Size= 656 bytes One basket in memory *
*Baskets : 0 : Basket Size= 16000 bytes Compression= 1.00 *

(int)0[/code]

Cheers,
Philippe.
working.C (1.09 KB)

Hi Philippe,

So after much prodding around, I found out why it fails, but still have no way of fixing it. It is the ClassDef that makes it not work.

In your example code, if you insert a ClassDef, then it gives the same result, the branch is in the root file, but without the leaves. Do you know how I can get this to work - I think ClassDef is important for schema evolution, right?

This is the non-working code (with just line 12 inserted):

#include <TTree.h>
#include <TFile.h>

class Newclassvar
{
public:
   Newclassvar(): var1(0),var2(0) {}

   int var1;
   int var2;

  ClassDef (Newclassvar,0);
};

#ifdef __MAKECINT__
#pragma link C++ class Newclassvar+;
#endif

class tclassA {
public:
   tclassA() : sfile(0),fOutputTree(0),snewclassvar(0) {}
  virtual ~tclassA() {}

  TFile *sfile;
  TTree* fOutputTree;
  Newclassvar *snewclassvar;

  virtual void Initialize(void) {
    sfile = new TFile ("SFiles.root","RECREATE");
    
    fOutputTree = new TTree("userLoopTree","A simple summary tree");
    fOutputTree->SetDirectory(sfile);

    snewclassvar = new Newclassvar;

    fOutputTree->Branch("SBranch",&snewclassvar, 16000, 99);
    
  }

   bool operator () (int /* event */) {
    //do some stuff to get variables; for now I'll use dummies
    snewclassvar->var1 = 10.;
    snewclassvar->var2 = 11.;
    fOutputTree->Fill();
    return true; 
  }

  void Finalize() {    
    fOutputTree->Print();
    sfile->Write();
    sfile->Close();
  }

};

int working() {
  tclassA usercode;
  usercode.Initialize();
  usercode(0);
  usercode(0);
  usercode.Finalize();
  return 0;
}

Thanks a lot!

  • Sujeewa

Hi,

[quote]ClassDef (Newclassvar,0);[/quote]Setting the class version to 0 is an explicit request to not stream the content of this class. Set the class version to 2 or more (1 works for too but has some minor technical draw backs).

Cheers,
Philippe.

Hi Philippe,

Thanks a lot… It did solve my problem… So I didn’t know I can not put 0 - I thought I always had to start from 0 and increment it every time I changed the variables?

  • Sujeewa

[quote]I thought I always had to start from 0[/quote]Where in the documentation did you find this? If you point it out, we will make sure to clarify the text and avoid any future confusion.

Thanks,
Philippe.

Hi Philippe,

I don’t remember where I saw this; I am now reading through the documentation and not finding such - I could have very well made some self-extrapolation… :blush:

Thanks anyway!

  • Sujeewa