Copy std::vector from one TTree to another

Hello PyROOT experts. I have an input TFile with a TTree in it that has a few branches containing std::vector<Int_t>. In analyzing the input, I produce an output TFile which has a new TTree, and I wish to have this TTree contain copies of the std::vectors from the input file. I don’t think I can just use the “Friendship” feature, because I am reducing the size of the trees, i.e. for one entry in the output TTree, I want copies of the std::vector branches from 40 (fixed) entries of the input TTree.

I know of a dumb way to do this, by creating 40 explicit branches in the output TTree using ROOT.std.vector(“Int_t”)(), then for each input entry, loop over the elements of the std::vector and push_back into the std::vector branch of the output tree. Doing it element-wise this way seems like a bad idea. The ROOT.std.vector doesn’t have a Copy or Clone method, so I don’t know how to copy the whole vector without using a python loop. There must be a way, or a way to link the 40 entries of the input tree into separate branches of the output tree. I also know I can make a vector<vector<Int_t>> on the python side, so I could make a 40-element vector with copies of the original vectors as the elements, but again I don’t know how to do this without resorting to an element-by-element copy in python.

I guess in the end I don’t really care if the output branches are std::vectors or some other kind of container like python array.arrays.

Thanks for any help,
Jean-François

How about std::vector::insert (should allow you to easily add the whole contents of one vector into another one).

One of the reasons I think I can’t copy the entire input vectors is that the TTree.Branch method needs the address of the vector, and if I use newvect = ROOT.std.vector(“Int_t”)(oldvect), then the address of newvect changes every time, so the Branch is no longer valid. Is that the right way of understanding?

You suggestion of std::vector::insert might work, if I do something like

[code]
newvect = ROOT.std.vector(“Int_t”)()
newvect.reserve(hugenum)

set branches and such

getentry from oldtree

newvect.clear()

insert oldvect into newvect

fill newtree[/code]

Is that what you are suggesting?

Well, I think that the address of the vector itself will NOT change, unless you delete it and create another one. What may be changing is the address of the vector’s “internal allocated storage for data”.
If you create a TBranch using the address of the vector itself, there should be no problem at all. Of course, you need to create this vector just once, before you create the TBranch, and you have to make sure that this vector will exist as long as it is used by this TBranch.
However, you do not need to care about what happens to the vector’s “internal allocated storage for data”. You do not need to “reserve(hugenum)” in the beginning at all -> it will automatically “grow”, when needed.
Note: you can std::vector::clear the vector at any moment, e.g. in order to “prepare” it for the next TTree entry -> just do not delete it.
For “std::vector<std::vector >” see [url]Storing 2D vector [--> vector<vector<...> >] into a TTree
For “std::vector<std::vectorstd::string >” see [url]Problem in getting the vector < vector <string> > branch

I finally got back to this part of my work. It seems that in ROOT (at least in PyROOT/CINT), std::vectors do not have the member functions assign or copy.

Is there a reason why these are missing? I can do v.clear() and then use v.insert, as you suggest, but it seems std::vector::copy/assign is what I really want.

Jean-François

Both, the std::copy and the std::vector::assign, are “function templates”.
I think you need to “instantiate” them and create appropriate (ROOT)CINT dictionary entries for them.
(You probably do not need to do this if you use them in compiled code -> e.g. via ACLiC.)

I found many posts relating to vectors of special C++ objects, but I had trouble finding anything about function templates.

I tried the following:

ROOT.gInterpreter.GenerateDictionary("vector<Int_t>","vector")
ROOT.gInterpreter.GenerateDictionary("vector<Int_t>::assign","vector")
ROOT.gInterpreter.GenerateDictionary("vector::assign","vector")
ROOT.gInterpreter.GenerateDictionary("copy","algorithm")

and other variations with std:: prefixing. The first generates something, but when I then make a ROOT.std.vector(“Int_t”)(), it does not have the assign method. The other trials give error messages.

I have never fully understood the concepts or proper instructions for generating dictionaries in this way. The instructions seem to be mostly clear when referring to vectors and custom classes:
root.cern.ch/drupal/content/how- … dictionary
But I’m not able to “translate” to algorithms, or missing methods for already-known classes.

Jean-François

Hi,

We have never automated the generation of the dictionary for function template instances, however the point is moot in ROOT 6 as the interpreter will fully support templates and will instantiate them as needed.

In the meantime, you can simply compile your code (you may have to add missing #include, etc) with ACLiC by adding a trailing + at the end of the file name when loading your script: .L Script.C+).

Cheers,
Philippe.

My code for this is entirely in PyROOT, so I don’t know what part I am supposed to compile. I have seen other posts where people talk about a Loader.C file with some preprocessor directives, for using vector<vector> for example. Is such a file necessary for std::copy or vector::assign? I’m still not sure what I need to write in that file…my attempts at guessing are not working.

Example of a post with a Loader.C file:

Jean-François

Hi,

Indeed, for PyROOT you still need to generate the dictionary. For a function you can add the line

#pragma link C++ function std::copy(vector<int>&,vector<int>&);to your loader.C file.

Cheers,
Philippe.