Howto best copy a vector from one tree (and file) to another

Dear All,

sorry for the longish post …

What I want to do:

I have a root input file with a TTree “physics”. I want to run a job which creates a new TTree (also with name “physics”). I want to be able to copy some variables (also vectors) from the old tree to the new tree (but on an event by event basis, i.e. not for all events). I also want to be able to add new variables to the new tree. Then, of course, I want to write out the new tree into a file.

Most of this works fine but with copying vectors from the old tree to the new tree I have some problems which I can solve but I don’t understand why it is works at the end (and if it it safe that way).

Here is what I do at the moment:

I create header/source with physics->MakeClass() from the TTree of the input file
I create a new class AnalysisLoop.h/.C which inherits from physics.h. This class implements the Loop() method and of course knows about all variables in the original TTree.
In the original TTree there is a vector origVector and I want to have that one in the new tree called TTree* outputTree.

There are several ways how I try this and all sort of depend on where this line goes (which tells the outpt tree the address of the vector which it should write out):
outputTree->Branch(“origVector”, “std::vector”, origVector);

The options I describe below are also indicated (with numbers) in the attached file which shows the essential parts of the Loop() method of my AnalysisLoop.C:

  1. if I put it before the actual event loop I get the message (since origVector == 0):
    Error in TTree::Branch: Reference interface requires a valid object (for branch: origVector)!
    then the vector is not written to the new TTree (even though the GetEntry() call should redirect the pointer)

1a) if I do 1) and in addition create a dummy vector
origVector = std::vector;
before
outputTree->Branch(“origVector”, “std::vector”, origVector);
Then everything works (which I find very weird because the dummy vector is never used, its address is replaced with the one of the object in the old tree after GetEntry()).

1b) If in addition to 1) and 1a) I delete the vector after the Branch() call (because it should not be used anyway) then the content of the variable in the histo is wrong.

  1. instead of 1) I can put the call
    outputTree->Branch(“origVector”, “std::vector”, origVector);
    into the event loop after the GetEntry() call. Then the address should always be correct. And indeed, in the TBrowser when looking at the TTree in the new file things look fine
    but when doing physics->Print() I see that the origVector entry was duplicated for every event in the event loop (and this blows up the file size).

If someone has an idea what is the correct way to do this please let me know. Keep in mind that I also want to add new stuff to the tree (which works fine) and not only copy variables from the old tree (which I guess I could more easily do with TTree::Clone).

cheers
Andi
AnalysisLoop.C (680 Bytes)

Try (see the “Case B” in the TTree class description): TFile outputntuple("out.root", "recreate"); TTree *m_outputTTree = new TTree("m_outputTTree", "m_outputTTree"); std::vector<float> *origVector = new std::vector<float>; m_outputTTree->Branch("origVector", &origVector); // ... the "for" loop which calls ... m_outputTTree->Fill(); ... then ... m_outputTTree->Write(); outputntuple.Close(); // automatically deletes "m_outputTTree" delete origVector;

Hi,

this is (almost) what I do when I use my option 1) + 1a) with the exception:

I use this line:
origVector = new std::vector
instead of
std::vector *origVector = new std::vector;
because origVector is a datamember of physics.h which is filled when GetEntry() of the old tree is called.

Then I cannot use just
m_outputTTree->Branch(“origVector”, &origVector);
which I did try before (case B as you mention) but it gives me:
Error in TTree::Branch: The pointer specified for origVector is not of a class or type known to ROOT

It does work for me if I use 1) and 1a) i.e.:

origVector = new std::vector<float>; // Why is this needed? The object is never used.
m_outputTTree->Branch("origVector", "std::vector<float>", origVector);
// ... the "for" loop which calls ... m_outputTTree->Fill(); ... then ...
m_outputTTree->Write();
outputntuple.Close();
delete origVector;

BUT I do not understand why in my case I have to new a vector which is NEVER used … the pointer is redirected to whatever GetEntry() of the old tree directs it to (in the event loop)

I thought this is a clever way because I do not need to really copy the vector of the old tree into a new vector to be written to the new tree. All I do is give the address of the vector in the old tree to the new tree.

Cheers
Andi

[quote=“wildauer”]Error in TTree::Branch: The pointer specified for origVector is not of a class or type known to ROOT[/quote] So, what EXACTLY the “origVector” is?

Hi,

it is
vector* origVector;

and is a datamember in physics.h because it is also read in from the input ntuple. I am also surprise that root says it does not know it but maybe I have to add/load some dictionary even though it is a “native type”.

Cheers
Andi

New ROOT versions should have “std::vector” built-in. You could try:
gInterpreter->GenerateDictionary(“vector”, “vector”);
And then, try:
m_outputTTree->Branch(“origVector”, “std::vector”, &origVector); // note the “&”

Hi,

I am on root ROOT 5.34/03 which I thought is not too old.

I am not using CINT. Which header do I need such that gInterpreter is known?

If I run it in CINT I get:
root[0] gInterpreter->GenerateDictionary(“vector”, “vector”);
Note: Link requested for already precompiled class vector<float,allocator > (ignore this message) :0:
Note: Link requested for already precompiled class vector<float,allocator >::iterator (ignore this message) :0:

In any case just to say again that it does work for me if I use lines 1 + 1a from my original post. I just wonder why I have to allocate memory for an empty vector which is thereafter never used anymore. Following the docu of TTree::Branch() I had the impression that using a 0 pointer should also work.

If I get the dictionary stuff to work I could try using:
m_outputTTree->Branch(“origVector”, origVector);
which I guess is what you wanted to suggest, rather than:
m_outputTTree->Branch(“origVector”, “std::vector”, &origVector);

Thanks for your help!
Andi

For the “gInterpreter”, you need:
#include “TInterpreter.h”

Note: “Link requested for already precompiled class” says that you do not need to “GenerateDictionary”.

In any case, for a “std::vector *origVector;”:
m_outputTTree->Branch(“origVector”, &origVector); // note the “&”

Hi,

sorry for the late reply. Just to add: it does not make a difference if I use
m_outputTTree->Branch(“origVector”, &origVector);
or
m_outputTTree->Branch(“origVector”, origVector);
I still get
Error in TTree::Branch: The pointer specified for origVector is not of a class or type known to ROOT

Btw. for the other way I should do

and not

(notice the &). But maybe it also does not make a diff here.

Cheers
Andi