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.
[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: