Filling RNTuple with derived classes


ROOT Version: master build
Platform: ubuntu 22.04


I’m trying to figure out how to add derived classes to an RNTuple if we don’t know the exact type of the derived class. The way we used to do this using TTrees was to check if a branch using the same derived class as the object we try to write already existed (using a mapping between TClass* and the pointer-pointer of the base class), and if not we would create a new branch using the class name as name and type, and a pointer-pointer of the base class.

I tried doing something similar with the RNTuple using a model updater to add new fields as needed. But it seems that the only way to get a pointer to set the values of the field is to use something like

ntuple->GetModel()->Get<classtype>("fieldname")

where classtype is the type of the derived class (which we don’t know)?

Is there another way of doing this without having the type of the derived class?

In order to fill an RNTuple, you let the model create an REntry for you (RNTupleModel::CreateEntry()). From the entry, you can get the memory location of the object connected to a field with REntry::Get<TypeName>("FieldName").

If you already have the object pointers (e.g., in a framework), you can use CreateBareEntry() and bind the memory locations to field names with REntry()::CaptureValueUnsafe().

The entry object is then used to fill an entry in RNTupleWriter::Fill(entry). If you use RNTupleModel::MakeField to create the fields of your writer, the objects returned by MakeField will get automatically connected to the model’s default field, in which case you can directly use them and fill with RNTupleWriter::Fill() (without argument). I.e., this is a shortcut so that you don’t explicitly need to deal with an REntry.

All of the above is standard writing, without model extension. For the specifics of model extension, you can take a look into the corresponding unit test. For filling in general, the multi-threaded fill tutorial could be useful.

Please keep in mind that the interfaces are still changing a little, and that it’s probably best to experiment with the RNTuple from the latest sources.

One more important type: in contrast to TTree, in RNTuple you cannot store a derived class in a field of type base class. You’d need to edit your data model such that the class types are exact. If you know the possible derived classes for a field upfront, you can use a field of type std::variant<T1, T2, ...>.

I did try using RNTupleModel::CreateEntry() at first, but that did not work at all, all entries would stay at zero (default value). I will try and post an example of that soon.

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