Creating TTree with vector branches

Hello all, lowly grad student here trying to make an analysis script in PyROOT.

By browsing the forums here I have pieced together something that seems to almost work.

Essentially I am just trying to read the contents of a D3PD, do some manipulation and write it back into another TTree that I create. I’ll post a stripped down version of the code below where I just try to make a branch called truthTrks which is a vector of integers. I just try to assign it some random values and then print them out to make sure it actually works, then write it into my Tree.

It runs until the line where I try to write it back to the TTree, so I think the problem is how I am declaring the branch. From these threads:
[url]TTree in python root session
[url]Filling branches with STLcollection

I have found two suggestions by Wim of how to do this, but both give me a ‘Break Seg Violation’.

ROOT.gROOT.ProcessLine('gSystem->Load( "libCintex.so")')
ROOT.gROOT.ProcessLine('Cintex::Cintex::Enable()')

import numpy

ROOT.gROOT.ProcessLine('.L Loader.C+') 

outj = ROOT.TTree('JTree','Julians test tree')
ROOT.gROOT.ProcessLine("struct JStruct{vector<int> truthTrks;};")
from ROOT import JStruct
y=JStruct()
y.truthTrks = ROOT.std.vector('int')()  

#Here is where I think trouble is, neither of these seem to work.
#outj.Branch("truthTrks",y.truthTrks.__class__.__name__,y.truthTrks)
outj.Branch('truthTrks',y.truthTrks)

def fillTreeJ(index):
    for k in range(t.mcTrk_n):
        if k<3:
            y.truthTrks.push_back(k)
            print y.truthTrks[k]
    outj.Fill()

I have attached the full error output as errors.txt

Any help is greatly appreciated!

-Julian
errors.txt (16 KB)

Julian,

compile your JStruct, e.g. by adding it to the Loader.C script that you already have. The interpreted version does not work (the ctor of the vector is not called).

Another thing that is going to hurt, is that by enabling Cintex in an ATLAS environment (my assumption based on the mentioning of D3PDs), is that a Reflex edition of std::vector will be available. With Loader.C+ or with the interpretation, you’ll create a CINT version. The two don’t mix, last time I checked.

For just this snippet of code, you don’t need the JStruct anyway, as it could be a python object with a data member ROOT.std.vector(int)().

Cheers,
Wim

Hm, if I add the struct into the Loader.C file, I start getting the

“Error: A dictionary has been requested for vector but there is no declaration!” errors again.

[quote=“wlav”]
Another thing that is going to hurt, is that by enabling Cintex in an ATLAS environment (my assumption based on the mentioning of D3PDs), is that a Reflex edition of std::vector will be available. With Loader.C+ or with the interpretation, you’ll create a CINT version. The two don’t mix, last time I checked. [/quote]
You are correct, it is in an ATLAS environment. So I should either get rid of Cintex or the Loader?

Well, I of course have more variables in the real code, I was just simplifying it for posting purposes. Is this what you were referring to?

Thanks for your time!

Julian,

is that “no declaration” header being caused due to a missing #include ? Or perhaps b/c the vector is not properly scoped with ‘std::’?

As for Cintex or Loader: yes, use either one not both, or run genreflex.py on Loader.C to be all Reflex (and use the resultant dictionary through Cintex).

Cheers,
Wim

Hm, I don’t think so. The contents of my Loader.C are:

[code]#include

#pragma link C++ class vector +;
#pragma link C++ class vector +;
#pragma link C++ class vector +; Loader

struct JStruct{\
  std::vector<int> truthTrks;	\
  std::vector<int> truthPt;	\
  std::vector<int> recoTrks;	\
  std::vector<int> recoPt;	\
Int_t EvNum;\
Int_t recoTrk_n;\
Int_t truthTrk_n;\
};

[/code]

I read somewhere that the #pragmalink business does not work within an ATLAS framework, which is why I put in the Cintex Enable as a workaround.

Hi,

but you are missing the “std::” there in every #pragma of vector? Also, there appears to be a spurious word “Loader” in the file. As for the last, no the #pragma’s for rootcint and Reflex/Cintex are unrelated.

Cheers,
Wim

You are right, of course. I have fixed those but unfortunately the seg violation continues.

If I simply comment out the tree.Fill() line in my function, it runs fine and uses the vectors as it should.

I am not sure if you have given up on this thread, but if not, I have started my code from scratch using a slightly different approach that I found on these boards. In doing so I have found two things:

When I am adding branches to my tree, I must add the vector branches last. Otherwise the code seg faults when I try to tree.Fill(). This seems odd, but perhaps is normal?

Secondly, (and this is where I am currently stuck), once I add an input file to a TChain to read from, it seg faults when I try to fill my tree with tree.Fill(). Any idea why this might be?

Lines 17-18 is where I define my input file. If they are commented out the code passes the test loop on lines 41-48 and complains that t is not defined. If Lines 17-18 are left in, the test loop fails at the tree.Fill()

-Julian
julian.py (1.99 KB)
JStruct.h (253 Bytes)

Julian,

not given up, just that it was 4th of July weekend here in the US. Also, the code as posted didn’t run and needed many changes (nothing to do with the original problem, just naming, imports. etc.). After that, it simply ran on my machine.

I noticed that Sebastien responded to your mail on hn-atlas-offline that the particular version of ROOT you’re using has a bug in std::vector. I hope that moving the version one patch up solves this for you.

Cheers,
Wim

Hi Wim, no worries about the 4th of July weekend :slight_smile: A few more questions for you!

  1. Out of curiosity, what includes did you have to put into the code that I posted a few days ago to get it to run? You could simply post the working code if you still have it.

  2. I did see sebastian’s response. However I never actually tried running in 5.30 because the other response worked as well. Loek Hooft van Huysduynen replied and simply removed the vectors from the struct entirely and declared them as

truthTrks = std.vector('Int_t')() recoPt = std.vector('Int_t')() recoTrks = std.vector('Int_t')() truthPt = std.vector('Int_t')()

And this actually seems to work fine. Now I know there was some reason for having them in the struct in the first place, is this fix OK to do? Or will I run into problems later?

  1. And one final question, if I declare my vectors as Loek suggests, how would I expand to create a vector of vectors with that notation? in C it is just std::vector<vector>, but it seems not so trivial with these quotes and parenthesis.

Thanks again!

Julian,

ad 1: just basic stuff, such as adding import ROOT, removing numpy, adding a #pragma for the JStruct, protecting the #pragma’s with #ifdef CINT, etc. None of which should really matter. (Your second .py is actually worse in that regards: it’ll give plenty NameErrors.)

ad 2: I haven’t seen Loek’s response, but by declaring the vectors on the python side, the code will use whatever dictionary for std::vector<> is already loaded. This has a higher chance of begin consistent. Also, since no new dictionary is being generated, there can be no problems in the generation. :slight_smile:

ad 3: Presuming that the vector of vectors is available (probably is in ATLAS in Reflex form, not so in standalone ROOT), the syntax can be any form of:std.vector('std::vector<int>') std.vector(std.vector('int')) std.vector(std.vector(int))
Internally, when given a type, the name is extracted. When given a string, it is used “as is.” The types simply cascade.

Cheers,
Wim