TDataFrame: how to pass a C-style array of floats from a branch to a function?

Hi,
I am trying to use TDataFrame to create a reduced TTree.
In the original TTree, I have a branch of C-style array of floats “fe_temp[25]/F” (I cannot change that).
I’d like to define a new column with the mean of the 25 values and snapshot it.
For that purpose, I define a function to compute the mean. But how do I pass the fe_temp array to the function ?

I tried the following code:

TDF = ROOT.ROOT.Experimental.TDataFrame
d = TDF("mytree","temperatures.root")

# Compute mean temperature
get_temp_code ='''
float get_fe_temp (const float (&fe_temp)[25])
{
   #include <numeric>
   float sum = std::accumulate(fe_temp, fe_temp+25, 0.0);
   return sum/25;
}
'''
ROOT.gInterpreter.Declare(get_temp_code)

# Define new branches
d2 = d.Define("temperature", "get_fe_temp( fe_temp )") 

But get the following error:

input_line_62:2:8: error: no matching function for call to 'get_fe_temp'
return get_fe_temp( fe_temp )
       ^~~~~~~~~~~
input_line_27:2:7: note: candidate function not viable: no known conversion from 'ROOT::Experimental::TDF::TArrayBranch<Float_t>'
      (aka 'TArrayBranch<float>') to 'const float [25]' for 1st argument
float get_fe_temp (const float (&fe_temp)[25])
      ^

Should I try to pass it as a ROOT::Experimental::TDF::TArrayBranch<Float_t>& ?

Thanks,
Neal


ROOT Version (6.12.06):
Platform, compiler (Fedora 27, gcc 7.3.1):


not an expert of TDataFrame but 2 things:

  • #include <numeric> inside a function implementation? yikes :stuck_out_tongue: (just move it above float get_fe_temp(...)
  • you may want to modify the signature of your function to take advantage of the automatic decay of C-arrays:
#include <numeric>

float get_fe_temp(const float* fe_temp) {
    float sum = std::accumulate(fe_temp, fe_temp+25, 0.0);
    return sum/25.0;
}

Hi @ngauvin,
this is how you would do it in v6.12 (tested on v6.12/07):

import ROOT

TDF = ROOT.ROOT.Experimental.TDataFrame
d = TDF("t","f.root")

# Compute mean temperature
get_temp_code ='''
#include <numeric>
float get_fe_temp (const ROOT::Experimental::TDF::TArrayBranch<float> &arr)
{
   float sum = std::accumulate(arr.begin(), arr.end(), .0f);
   return sum/arr.size();
}
'''
ROOT.gInterpreter.Declare(get_temp_code)

# Define new branches
d2 = d.Define("temperature", "get_fe_temp(arr)") 

# Check that the computation is run correctly
d2.Filter("std::cout << temperature << std::endl; return true;").Count().GetValue()

But we have given some love to TDataFrame and python since v6.12, and things improved quite a bit.
In the upcoming v6.14 ROOT::Experimental::TDataFrame was renamed to ROOT::RDataFrame (it’s the convention for new ROOT interfaces, and note that there’s no Experimental anymore) and we added a new class RVec to easily deal with arrays: all array branches are automatically read as RVecs.

import ROOT

DF = ROOT.ROOT.RDataFrame
d = DF("mytree","temperatures.root")

d2 = d.Define("temperature", "Mean(fe_temp)") 

Hope this helps!
Enrico

1 Like

Hi,
works great for ROOT version 6.12.04 and greater. Thanks.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.