How to enable TBufferFile::kStreamedMemberWise for specific branches in a TTree?

I have a piece of PyROOT code (mainly for usability, but should be easy to translate into C++) where I am creating two branches of std::vector<T> types (one 32b int, one double):

import ROOT

fp = ROOT.TFile.Open("stl_containers.root", "RECREATE")
tree = ROOT.TTree("tree", "")

ROOT.gROOT.ProcessLine("""
    std::vector<int32_t> vector_int32;
    std::vector<double_t> vector_double;
    std::vector<int32_t>* address_int32 = &vector_int32;
    std::vector<double_t>* address_double = &vector_double;
""")

tree.Branch('vector_int32', ROOT.address_int32)
tree.Branch('vector_double', ROOT.address_double)

data = [3, 6, 9]
for i in range(10):
    ROOT.vector_int32.clear()
    ROOT.vector_double.clear()
    for d in data:
        ROOT.vector_int32.push_back(int(d+i))
        ROOT.vector_double.push_back(float(d*i))

    tree.Fill()

tree.Print()
tree.Write()
fp.Close()

How do I get it so that vector_double is a branch written with kStreamedMemberWise enabled? I have tried, for example, adding these lines before the for loop

basket = tree.CreateBasket(tree.GetBranch('vector_double'))
tree.GetBranch('vector_double').AddBasket(basket, False, 0)
basket.SetBit(ROOT.TBufferFile.kStreamedMemberWise, 1)

to set this bit on the corresponding basket (doesn’t work, and the ROOT file written out is pretty badly mangled). The goal here is to have a std::vector<double> in a branch that’s been written out member-wise instead (and on some level, learn how to force this flag to be set, which does not seem to be obvious atm).

I have also tried the following at the top

fp.SetBit(ROOT.TBufferFile.kStreamedMemberWise, 1)

as well as the following at the bottom (before tree.Write()):

tree.GetBranch('vector_double').GetBasket(0).SetBit(ROOT.TBufferFile.kStreamedMemberWise, 1)

Hi @kratsg,

I think that the kStreamedMemberWise bit should not be set manually. I’m not an expert in TTree API, but I my suggestion would be to add a call to

TVirtualStreamerInfo::SetStreamMemberWise()

before creating the corresponding TFile and TTree instances. Nevertheless, I will invite @pcanal to this thread. I am sure he can give you a lot more information.

Cheers,
J.

Hi @jalopezg – thanks. It would be instructive to be able to create a ROOT file with “simple” std::vector collections in member-wise format. It seems like this is enabled by default, but does not force the bit. As far as I can tell, this only seems to be applied when the underlying type is a C-struct.

What do you intent to gain by setting this flag (i.e. in my understanding it would not change anything to the ondisk format of a simple vector<double>, it should only affect unsplit vector<struct/class>)?

Don’t try to manipulate TBasket object directly, they are transient per se and even if the code you had was correct and effective it would only affect a single basket.

basket.SetBit(ROOT.TBufferFile.kStreamedMemberWise, 1)

That bit is an internal detail, it is use to convoluted with the class layout version number when writing that version number as part of the byte stream. I.e. Don’t use unless you are (re)write part of the streaming implementation.

TVirtualStreamerInfo::SetStreamMemberWise()

This indicates whether ROOT I/O is globally allowed to stream eligible collection of struct/class in a member wise manner. The default is true. Nowadays, there is no known reason to disable it.

There is 2 main ways of designed whether a struct/class or a collection there is split (when stored as a branch) or streamed member wise (when stored as apart of an unsplit branch or in a key/outside of a TTree).

TClass::SetCanSplit (and ``TClass::CanSplit```): This indicate is the class or struct described by a given TClass object can or can not be split or streamer member wise (main reason not be able to split a class is if that class as a custom Streaming function).

The other mechanism is the last argument of the call to TTree::Branch (the overload that handles objects) which is called splitlevel. When set to 0, it request the object to be stored un-split, i.e. in a single branch (inside the collection can be stored memberwise). Then as the split level increase, this request to separate more and more level of nesting inside the class into its own branches. The default level is 99.

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