Vector branch and TTreeFormula

Hi!

I would like to fill for a TTree one or more branches with the results of TTreeFormula based on the rest of the branches. This could be used e.g. for persisting an alias formula to a branch. The example code below shows what I mean, and how I currently solved it:

void ttf2br(int n=0, TString fml="x+y") 
{
  if (n==0) return;
  double x, y, v;
  vector<double> vx;
  
  TTree *t = new TTree("t","t");
  t->Branch("x",  &x, "x/D");
  t->Branch("y",  &y, "y/D");
  t->Branch("vx", &vx);
  TBranch *bv = t->Branch("v", &v, "v/D");
  TTreeFormula tf("tf", fml, t);
  
  for (int i=1; i<=n; ++i) {
    x = i;
    y = i*i;
    vx = {x, y};
    
    // switch of branch bv and fill the rest of the tree
    bv->SetStatus(0);
    t->Fill();
    
    // switch on branch bv and fill it with TTreeFormula::EvalInstance()
    bv->SetStatus(1);
    v = tf.EvalInstance();
    bv->Fill();
  }
    
  t->Scan();
  t->Scan(fml);
}

There, the result of a TTreeFormula is stored to the branch "v". A call root -l 'ttf2br.C(3, "x+y")' gives, which if fine:

***********************************************************************
*    Row   * Instance *       x.x *       y.y *        vx *       v.v *
***********************************************************************
*        0 *        0 *         1 *         1 *         1 *         2 *
*        0 *        1 *         1 *         1 *         1 *         2 *
*        1 *        0 *         2 *         4 *         2 *         6 *
*        1 *        1 *         2 *         4 *         4 *         6 *
*        2 *        0 *         3 *         9 *         3 *        12 *
*        2 *        1 *         3 *         9 *         9 *        12 *
***********************************************************************
************************
*    Row   *       x+y *
************************
*        0 *         2 *
*        1 *         6 *
*        2 *        12 *
************************

But when I want to use a formula based on the vector components (that usually works in TTree::Scan/Draw), it fails:

Processing ttf2br.C(3,"vx[0]+vx[1]")...
***********************************************************************
*    Row   * Instance *       x.x *       y.y *        vx *       v.v *
***********************************************************************
*        0 *        0 *         1 *         1 *         1 *         0 *
*        0 *        1 *         1 *         1 *         1 *         0 *
*        1 *        0 *         2 *         4 *         2 *         0 *
*        1 *        1 *         2 *         4 *         4 *         0 *
*        2 *        0 *         3 *         9 *         3 *         0 *
*        2 *        1 *         3 *         9 *         9 *         0 *
***********************************************************************
************************
*    Row   * vx[0]+vx[ *
************************
*        0 *         2 *
*        1 *         6 *
*        2 *        12 *
************************

The column v.v shows only zeros, while a scan with the same expression shows the expected numbers.

I have two questions:

  1. How can I fix this vector issue, if possible?
  2. Is there a smarter way to fill branches with the results of TTreeFormula based on the other branches?

Thanks a lot,
Klaus


ROOT Version: 6.36.000
Platform: Debia Linux

Try like this:

GetEntry and GetNdata must be called before EvalInstance

void ttf2br(int n=0, TString fml="x+y") 
{
  if (n==0) return;
  double x, y, v;
  vector<double> vx;
  
  TTree *t = new TTree("t","t");
  t->Branch("x",  &x, "x/D");
  t->Branch("y",  &y, "y/D");
  t->Branch("vx", &vx);
  TBranch *bv = t->Branch("v", &v, "v/D");
  TTreeFormula tf("tf", fml, t);
  
  for (int i=1; i<=n; ++i) {
    x = i;
    y = i*i;
    vx = {x, y};
    
    // switch of branch bv and fill the rest of the tree
    bv->SetStatus(0);
    t->Fill();
    
    // switch on branch bv and fill it with TTreeFormula::EvalInstance()
    bv->SetStatus(1);
    t->GetEntry(i-1);
    if (tf.GetNdata())
       v = tf.EvalInstance();
    bv->Fill();
  }
    
  t->Scan();
  t->Scan(fml);
}
1 Like

Cool, thanks a lot, that does it!

You’re welcome. More details are here: