Proper way to store an event into a Tree

Dear ROOT experts,

I am currently working on a Geant4 simulation program which links to ROOT, and I would like to store event information into a ROOT Tree using a custom Class as the data model. I think it is possible to do it without creating libraries / dictionaries such as it is shown here: Chapter: Trees, since I don’t need to implement any method in this class, it is only used as storage.

The tutorials (such this one I have linked) seem to be a bit outdated, providing many dead references. The best example I could find was ROOT: tutorials/tree/tree0.C File Reference. I have managed to run this successfuly on the ROOT console:

#include <TTree.h>

class Event : public TObject
{
public:
    Int_t fEventID;
    
    ClassDef(Event, 1)
};

ClassImp(Event);

void event()
{

    TTree *tree = new TTree("tree", "My Tree");
    Event *e = new Event;

    tree->Branch("Event", &e);

    Int_t nevent = 10000;
    for (Int_t iev = 0; iev < nevent; iev++)
    {
        e->fEventID = iev;
        tree->Fill();
    }

    tree->Show(0);
}
root [3] tree->Show(2)
======> EVENT:2
 fEventID        = (Event*)0x7ffe429cfa70
 fUniqueID       = 0
 fBits           = 50331648
 fEventID        = 2

However I am failing to achieve the same results in my standalone c++ program that links to ROOT. I would like to know the “canonical” way to achieve this, hopefully without having to create a library.

In my project I have:

// ... all dependencies ... 
// DataModel.h

class UserGeant4Event : public TObject {
   public:
    Int_t fEventID;

   public:
    UserGeant4Event();
    ~UserGeant4Event();

    ClassDef(UserGeant4Event, 1);
};

// DataModel.cpp

#include "DataModel.h"

ClassImp(UserGeant4Event);

UserGeant4Event::UserGeant4Event() {}
UserGeant4Event::~UserGeant4Event() {}

Currently its not compiling giving errors such as (sorry they are not in english):

/usr/bin/ld: CMakeFiles/restGeant4.dir/src/DataModel.cpp.o: en la función `__static_initialization_and_destruction_0(int, int)':
/tmp/tmp.HxEn9kcj7v/src/DataModel.cpp:4: referencia a `ROOT::GenerateInitInstance(UserGeant4Event const*)' sin definir
/usr/bin/ld: CMakeFiles/restGeant4.dir/src/DataModel.cpp.o: en la función `UserGeant4Event::IsA() const':
/tmp/tmp.HxEn9kcj7v/include/DataModel.h:73: referencia a `UserGeant4Event::Class()' sin definir
/usr/bin/ld: CMakeFiles/restGeant4.dir/src/DataModel.cpp.o: en la función `UserGeant4Event::ShowMembers(TMemberInspector&) const':
/tmp/tmp.HxEn9kcj7v/include/DataModel.h:73: referencia a `UserGeant4Event::Class()' sin definir
/usr/bin/ld: CMakeFiles/restGeant4.dir/src/DataModel.cpp.o:(.data.rel.ro._ZTV15UserGeant4Event[_ZTV15UserGeant4Event]+0x1e0): referencia a `UserGeant4Event::Streamer(TBuffer&)' sin definir
collect2: error: ld returned 1 exit status

Looks like its a linker issue, but no idea how to fix it.

Thanks in advance!

Edit:

If I remove ClassDef and ClassImp macro calls, the program will compile but the object stored in the TTree will be a plain TObject* without the fields I defined.

All the remotely useful information I can find online is related to ROOT dictionaries (such as ROOT macros and shared libraries - ROOT), can’t I do what I intend without dictionaries? The ROOT macro doesn’t seem to use them, I can open the tree without loading any dictionaries

A “workaround” (maybe its the only way?) is to define a dictionary and link to the library, but it looks too involved for what I want to achieve (following GitHub - eguiraud/root_dictionaries_tutorial: A tutorial on creating ROOT dictionaries to perform I/O of custom C++ classes).

I have created a repository: GitHub - lobis/root_event_tree_cmake: A simple template to save a ROOT Class into a TTree to show my progress, hopefuly it can serve as a reference when (if) I manage to get it working.

If you don’t want to generate the dictionary, try with:

// DataModel.h

class UserGeant4Event : public TObject
{
public:
   Int_t fEventID;

public:
   UserGeant4Event() {}
   ~UserGeant4Event() {}

   ClassDefInline(UserGeant4Event, 1);
};

main.cxx:

#include <TInterpreter.h>
#include <TTree.h>
#include "DataModel.h"

int main(int argc, char* argv[])
{
   // make the UserGeant4Event class known by the interpreter
   gInterpreter->Declare("#include \"DataModel.h\"");
   TTree *tree = new TTree("tree", "My Tree");
   UserGeant4Event *e = new UserGeant4Event;
   tree->Branch("UserGeant4Event", &e);
   Int_t nevent = 10000;
   for (Int_t iev = 0; iev < nevent; iev++) {
      e->fEventID = iev;
      tree->Fill();
   }
   tree->Show(0);
}

No need of ClassImp, and no DataModel.cxx

Thanks! It works.

I have compiled a working small project here: GitHub - lobis/root_event_tree_cmake at 9972c0be325237b9b8e1155278be57074542e03b for anyone interested which implements this solution.

1 Like

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