Access members of a ROOT file

Not sure why this is so difficult. I have a .root file in the following format:

file.root
|—> a2MC (tree)
|—>|—> PanelHits (branch)
|—>|—>|—> fHit (leaf)
|—>|—>|—> fRun (leaf)
|—>|—>|—> fPanelID (leaf)

etc etc.

I just want the number of entries with given panel ID. I have tried using a dataframe:

 ROOT::RDataFrame* d = new ROOT::RDataFrame("a2MC",sfile.c_str());
auto entries = d->Filter("PanelHits.fPanelID == 0").Count()
(ROOT::RDF::RResultPtr<ULong64_t>) @0x560314c83b20

Then:
entries.GetValue()
gives

/home/lgolino/packages/root/install/include/ROOT/RDF/InterfaceUtils.hxx:300:4: error: static_assert failed due to requirement 'std::is_convertible<ROOT::VecOps::RVec<int>, bool>::value' "filter expression returns a type that is not convertible to bool"
   static_assert(std::is_convertible<FilterRet_t, bool>::value,
   ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/lgolino/packages/root/install/include/ROOT/RDF/InterfaceUtils.hxx:428:4: note: in instantiation of function template specialization 'ROOT::Internal::RDF::CheckFilter<R_rdf::(lambda at input_line_56:2:16)>' requested here
   CheckFilter(f);
   ^
input_line_63:2:23: note: in instantiation of function template specialization 'ROOT::Internal::RDF::JitFilterHelper<R_rdf::(lambda at input_line_56:2:16) &, ROOT::Detail::RDF::RNodeBase>' requested here
 ROOT::Internal::RDF::JitFilterHelper(R_rdf::lambda0, new const char*[1]{"PanelHits.fPanelID"}, 1, "", reinterpret_cast<std::weak_ptr<ROOT::Detail::RDF::RJittedFilter>*>(0x5603134c58d0), reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>(0x560312905260),reinterpret_cast<ROOT::Internal::RDF::RColumnRegister*>(0x56031348fec0));
                      ^
In module 'ROOTDataFrame':
/home/lgolino/packages/root/install/include/ROOT/RDF/RFilter.hxx:114:14: error: no viable conversion from returned value of type 'ROOT::VecOps::RVec<int>' to function return type 'bool'
      return fFilter(fValues[slot][S]->template Get<ColTypes>(entry)...);
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/lgolino/packages/root/install/include/ROOT/RDF/RFilter.hxx:98:27: note: in instantiation of function template specialization 'ROOT::Detail::RDF::RFilter<R_rdf::(lambda at input_line_56:2:16), ROOT::Detail::RDF::RNodeBase>::CheckFilterHelper<ROOT::VecOps::RVec<int> , 0>' requested here
            auto passed = CheckFilterHelper(slot, entry, ColumnTypes_t{}, TypeInd_t{});
                          ^
/home/lgolino/packages/root/install/include/ROOT/RDF/RFilter.hxx:71:4: note: in instantiation of member function 'ROOT::Detail::RDF::RFilter<R_rdf::(lambda at input_line_56:2:16), ROOT::Detail::RDF::RNodeBase>::CheckFilters' requested here
   RFilter(FilterF f, const ROOT::RDF::ColumnNames_t &columns, std::shared_ptr<PrevNode_t> pd,
   ^
/home/lgolino/packages/root/install/include/ROOT/RDF/InterfaceUtils.hxx:437:40: note: in instantiation of member function 'ROOT::Detail::RDF::RFilter<R_rdf::(lambda at input_line_56:2:16), ROOT::Detail::RDF::RNodeBase>::RFilter' requested here
      std::unique_ptr<RFilterBase>(new F_t(std::forward<F>(f), cols, *prevNodeOnHeap, *colRegister, name)));
                                       ^
input_line_63:2:23: note: in instantiation of function template specialization 'ROOT::Internal::RDF::JitFilterHelper<R_rdf::(lambda at input_line_56:2:16) &, ROOT::Detail::RDF::RNodeBase>' requested here
 ROOT::Internal::RDF::JitFilterHelper(R_rdf::lambda0, new const char*[1]{"PanelHits.fPanelID"}, 1, "", reinterpret_cast<std::weak_ptr<ROOT::Detail::RDF::RJittedFilter>*>(0x5603134c58d0), reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>(0x560312905260),reinterpret_cast<ROOT::Internal::RDF::RColumnRegister*>(0x56031348fec0));
                      ^
/home/lgolino/packages/root/install/include/ROOT/RVec.hxx:1246:4: note: candidate template ignored: could not match 'RVecN<type-parameter-0-0, N>' against 'bool'
   operator RVecN<U, M>() const
   ^
/home/lgolino/packages/root/install/include/ROOT/RVec.hxx:1507:4: note: candidate template ignored: could not match 'RVec<type-parameter-0-0>' against 'bool'
   operator RVec<U>() const
   ^
Error in <TRint::HandleTermInput()>: std::runtime_error caught:
An error occurred during just-in-time compilation in RLoopManager::Run. The lines above might indicate the cause of the crash
All RDF objects that have not run their event loop yet should be considered in an invalid state.

And it seems anything else I do with the dataframe gives the same issue, the only thing I can really do is DrawClone on the histogram.

I have also tried:

int main() 
{

  // Here's the input file
  // Without the 'recreate' argument, ROOT will assume this file exists to be read in.
  TFile f("../root/a2MC-2022-08-05-13-28-33_0.root");

  // We will now "Get" the tree from the file and assign it to
  // a new local variable.
  TTree *input_tree = (TTree*)f.Get("a2MC");
  TBranch *input_branch = (TBranch*)f.Get("PanelHits");

  int panelID;
  // Assign these variables to specific branch addresses
  input_tree->SetBranchAddress("fPanelID",&panelID);
  //Also tried this: input_tree->SetBranchAddress("PanelHits.fPanelID",&panelID);


  // Get the number of events in the file
  Int_t nevents = input_tree->GetEntries();

  for (Int_t i=0;i<nevents;i++) {

      // Get the values for the i`th event and fill all our local variables
      // that were assigned to TBranches
      input_tree->GetEntry(i);

      // Print the number of jets in this event
      printf("%d\n",panelID);
  }

  return 0;
}

Which just seg faults.

It cannot be this difficult to access members of a root file? What am I missing. I can’t find a single thing online to access members of a root file that actually works. Please help. Cheers.


Please read tips for efficient and successful posting and posting code

ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided


Hi,

about the RDataFrame version, as per the (beginning of the very verbose) error message the problem is that your Filter expression does not return a bool. That’s likely because PanelHits.fPanelID is an array, so PanelHits.fPanelID == 0 returns an array of booleans and Filter does not know what to do with it. Maybe you want this instead (I haven’t tested the code but it should give you the idea):

ROOT::RDataFrame d("a2MC",sfile);
auto allHits = d.Define("nHitsPerEvent", "Sum(PanelHits.fPanelID == 0)").Sum("nHitsPerEvent");

(note that you can just use ROOT::RDataFrame d("a2MC", sfile); instead of new ROOT::RDataFrame("a2MC", sfile.c_str())).

The second version probably segfaults for a similar type mismatch problem, you are reading fPanelID into a single int but it’s actually an array of integers.

You can check the type of the branch with either d.GetColumnType("PanelHits.fPanelID") or tree->Print().

Cheers,
Enrico

Ah I see, printing the tree gives:

*............................................................................*
*Br   45 :PanelHits.fPanelID : Int_t fPanelID[PanelHits_]                    *
*Entries :     1000 : Total  Size=       5350 bytes  File Size  =        541 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   8.73     *
*............................................................................*

and via dataframe:

root [3] d->GetColumnType("PanelHits.fPanelID")
(std::string) "ROOT::VecOps::RVec<Int_t>"

I assume this means then its a single vector thats been stored in the tree at the end instead of the individual variable throughout the process? Is there anyway to just return this vector?

The above method of

just gave more errors…

root [5] auto allHits = d->Define("nHitsPerEvent", "Sum(PanelHits.fPanelID == 0)").Sum("nHitsPerEvent");
IncrementalExecutor::executeFunction: symbol '_ZN4ROOT8Internal3RDF16MakeSharedOnHeapIdEEPSt10shared_ptrIT_ERKS5_' unresolved while linking function '_GLOBAL__sub_I_cling_module_100'!
You are probably missing the definition of std::shared_ptr<double>* ROOT::Internal::RDF::MakeSharedOnHeap<double>(std::shared_ptr<double> const&)
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZN4ROOT8Internal3RDF30WarnOnLazySnapshotNotTriggeredIdEEvRKNS_3RDF10RResultPtrIT_EE' unresolved while linking function '_GLOBAL__sub_I_cling_module_100'!
You are probably missing the definition of void ROOT::Internal::RDF::WarnOnLazySnapshotNotTriggered<double>(ROOT::RDF::RResultPtr<double> const&)
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZN4ROOT6Detail3RDF13MakeResultPtrIdEENS_3RDF10RResultPtrIT_EERKSt10shared_ptrIS5_ERNS1_12RLoopManagerES7_INS_8Internal3RDF11RActionBaseEE' unresolved while linking function '_GLOBAL__sub_I_cling_module_100'!
You are probably missing the definition of ROOT::RDF::RResultPtr<double> ROOT::Detail::RDF::MakeResultPtr<double>(std::shared_ptr<double> const&, ROOT::Detail::RDF::RLoopManager&, std::shared_ptr<ROOT::Internal::RDF::RActionBase>)
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZSt11make_sharedIdJRKdEESt10shared_ptrIT_EDpOT0_' unresolved while linking function '_GLOBAL__sub_I_cling_module_100'!
You are probably missing the definition of std::shared_ptr<double> std::make_shared<double, double const&>(double const&)
Maybe you need to load the corresponding shared library?

Thanks already for your response.

That looks like a broken interpreter session (try again after quitting and restarting the interpreter) or a broken ROOT installation. The error says that ROOT’s C++ interpreter cannot find a certain function, but that’s a function that is should absolutely be able to find.

More probably each PanelHit object has a single fPanelID value, but for every event an array of PanelHits is being stored (so PanelHits.fPanelID gets expanded to the array of IDs of every element of the PanelHits collection).

There are several. If you are ok with a vector<RVec<int>> you can use d.Take<ROOT::RVec<int>>(“PanelHits.fPanelID”).GetValue()`.

Cheers,
Enrico

I’m not sure what exactly a vector<RVec<int>> is but maybe it would work but unfortunately I get the following error

EDIT: Please disregard, I missed the strings.

This is my output. What a strange way to store the data. Maybe I need to go see if this can be rearanged instead…

root [3] d->Take<ROOT::RVec<int>>("PanelHits.fPanelID").GetValue()
(const std::vector<ROOT::VecOps::RVec<int>, std::allocator<ROOT::VecOps::RVec<int> > > &) { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2, 2 }, {}, {}, {}, { 2, 0, 0 }, {}, {}, { 4 }, {}, {}, {}, {}, {}, {}, {}, {}, { 2 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 3, 3, 3, 3, 3 }, {}, {}, {}, {}, {}, {}, {}, {}, { 2, 0 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2, 2, 2, 2, 2, 2, 2, 3 }, {}, {}, {}, {}, {}, {}, {}, { 7 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 3, 3, 3, 3, 3, 3, 3, 3 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 1, 1 }, {}, {}, {}, {}, {}, {}, { 5 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 0 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3 }, {}, {}, { 2, 2 }, {}, {}, {}, {}, {}, {}, {}, { 2 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3 }, {}, {}, {}, { 2, 2, 2, 2, 2, 2, 2, 2 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 1, 1, 1, 3 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2 }, {}, {}, { 3 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 1 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 4 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2, 2 }, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 3 }, {}, {}, {}, {}, {}, {}, { 5 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2 }, { 6 }, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 1 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 1, 1, 1 }, {}, {}, { 1, 1 }, {}, {}, {}, {}, {}, {}, { 2, 2 }, { 3 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 0 }, {}, {}, {}, {}, { 1, 1, 1 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 6 }, {}, {}, {}, {}, {}, {}, { 0 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 1, 1, 1 }, { 2, 2, 0, 2 }, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 1 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2, 2 }, {}, {}, {}, { 2 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 0 }, {}, {}, {}, {}, {}, {}, {}, {}, { 0, 0 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 5, 4 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3 }, {}, {}, {}, { 2, 0, 0, 0 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 1 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 6, 7 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 2 }, {}, {}, {}, {}, {}, {}, { 3, 1 }, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, { 7 }, {}, {} }

Regardless I was able to get the data I required from this by doing:

    ROOT::RDataFrame* d = open_root(runNumber);
    auto thing = d->Histo1D("PanelHits.fPanelID");
    auto hist = thing.GetValue();

And extract the information from the histogram.

I am worried that in future I may need to do something similar but with a different variable where binned data wont be good enough. But for now I guess my issue is solved. Thanks

Hi @lgolino ,

That’s a standard vector of a vector (RVec is RDataFrame’s custom vector implementation with some features useful for HEP analysis, e.g. you can calculate InvariantMass or DeltaR of RVecs easily). For each event (in the outer vector) you get a vector of values (in the inner RVec).

For example:

auto ids = df.Take<ROOT::RVecI>("PanelHits.fPanelID").GetValue(); // the alias ROOT::RVecI is available since ROOT v6.26

ids.size(); // returns the number of events
ids[0].size(); // returns the number of entries in "PanelHits.fPanelID" for the first event
ids[2][3]; // returns the 4th entry in "PanelHits.fPanelID" for the 3rd event (if it exists)

I hope this clarifies things a bit.
Cheers,
Enrico