Suggestions for a TTree with kind of "heterogeneous" events

Dear ROOTers,

I want to convert the ASCII output of a simulation+reconstruction software (it basically runs a GEANT4 simulation and then applies some reconstruction algorithm) to a ROOT TTree, in order to have more freedom to make my own variable correlations (in particular with TTree::Draw) and probably (and as a second priority) to save disk space with respect to a text file.

Basically the reconstruction tags each event as a (sequence of) Compton scatterings of the impinging gamma, or a pair production event, etc.
Each type of event has, besides some common variables, some different “additional information” (not much, <10 doubles in any case), so my “Event” should have an heterogeneous list of Branches depending on the type. Somehow, it would be similar to the case when you use a “union” in C/C++ programming.

Some options that I have considered so far:

A)
Class hierarchy, i.e. having a “base-class Event” and “derived-class” specialized event. However I think that the serialization in a TTree does not support any “polymorphism”, please let me know if indeed it does.

B)
A set of pointers to the extra data class, something like:

class Event {
   // ... common variables ...
   ComptonExtraInfo* comptonextrainfo {nullptr};
   PairsExtraInfo* pairextrainfo {nullptr};
   // ... etc ...
};

and each event has only one of the pointers != nullptr.
However, the size of all the necessary pointers is comparable with the size of the extra information. It seems to me a waste of space.

C, the last resort)
I save my Event class without any splitting (the total size of information is not so large). I can provide methods to correctly access the information and have a big block of data that these methods know how to interpret. Basically the same approach with C/C++ unions.
BTW, can the automatically-generated streamer be produced also for C++ unions embedded in a class? If yes, at least the readability of the code would be much better.

Do you know any other approach? Any suggestion is very welcome.

Thanks,
Matteo

Hi Matteo,

[quote]A) … I think that the serialization in a TTree does not support any “polymorphism”, [/quote] This correctly only for the top level branch/type. And polymorphism is not supported for the split part of the object. Using regular polymorphism (via a pointer data member) is supported and will lead to that portion of the object to not be split. So you could do:

class Event { // ... common variables ... BaseClassExtraInfo* info {nullptr}; };where info might point to a ComptonExtraInfo in some entry and in other PairsExtraInfo.

We also have a split case for collection of pointers (requested with split level greater than 100) where the content of the collection is split even-though it contains polymorphic pointers. And thus you could do:

class Event { // ... common variables ... vector<BaseClassExtraInfo*> info; };if you some of your event have more than one extra info.

[quote]BTW, can the automatically-generated streamer be produced also for C++ unions embedded in a class? [/quote]As far as we know it is impossible to write a platform independent version of an union without ‘extra’ information. For example if the union isunion Inside { char fOne[4]; double fTwo; };The I/O layer has no way to know whether the user filled the ‘char[4]’ or the ‘double’, so the question is upon storing (or restoring) should we byte swap or not (assuming the file and the current machine have different endianess) … and whichever choice you make will be wrong for either fOne or fTwo … (So we might instead support the upcoming std::variant).

[quote]Each type of event has, besides some common variables, some different “additional information” (not much, <10 doubles in any case),[/quote]In case the information is indeed always doubles and you are looking for the most compact solution maybe you can use something

class Event { // ... common variables ... std::vector<pair<marker_t,double> > fExtraInfo; };
where marker_t might be an enum with a unique identifier for each possible value:

enum { kComptonExtraInfoSomething = 0, kComptonExtraInfoSomethingElse = 1, kPairsExtraInfoUsefullInfo = 2, etc... };

Cheers,
Philippe.