Is std::vector<TLorentzVector> OK?

Hi,

I have a question, which may seem a bit random. It’s more of a shot in the dark, one possible explanation of a memory problem I’m having (see a little more explanation at the end of the post).

I have a class, Particle_Electron, which inherits from class Particle, which inherits from TLorentzVector. Is there anything inherhently wrong with this (compiled code using gcc 3.4.6, ROOT version 5.16, on either of SLC3 or SLC4):

struct sort_by_Pt :
  public std::binary_function<const Particle&, const Particle&, bool>
{
  bool operator()(const Particle& x, const Particle& y)
  {
    return x.Pt() > y.Pt();
  }
};

std::vector<Particle_Electron> Electrons;
...
// Code which fills the vector Electrons
...
std::sort(Electrons.begin(), Electrons.end(), sort_by_Pt());

I suppose what I’m really asking here is whether there is any internal ROOT bookkeeping of TLorentzVectors that will not like the std::sort function? If there is, how can I turn it off please?

Cheers,
Mike Flowerdew

Some explanation: I have some code which gives this run-time error:

Three factors make this error annoying: (a) the error disappears when I run in valgrind (How?? I don’t know) (b) Try as I might, I can’t boil this down to a simple example I can post, (c) The error behaves in an erratic way suggestive of a memory leak, but I have checked already that the CPU is not running out of memory - I believe it is an allocation/deallocation error, hence my question. When I remove all the std::sort functions, the problem appears to go away, although this is far from conclusive in itself. The error is actually thrown in quasi-random bits of code (parts of the ROOT library) that I believe are actually unrelated to the real problem here.

Hi,

Is this executed in interpreted or compiled code?
If it is interpreted, you must generate the dictionary for std::vector<Particle_Electron> (the interpreted version does not work properly with objects).
If it is compiled, you should try to run the program in gdb and see what the stack trace at the crash is.

Cheers,
Philippe.

Hi,

As I said, this is compiled code, it contains several features I would not expect to work without compilation.

I have run it in gdb, and valgrind. The errors are not all that useful, except in suggesting that memory assignment has gone wrong somewhere, which causes a crash at some point further down the line. I am just trying to think of things which may go wrong, and this question about sorting a vector of what are essentially augmented TLorentzVectors occurred to me.

If it helps, I’ve attached the gdb backtrace below. Note that the program does not always crash in the same place. It always seems to be in a TBranch method, but I believe that is luck as much as anything as most of the program memory is probably associated with branches.

Cheers,
Mike

Line 55 of SignalAnalysis.C is where I call TChain::Process(TSelector*), in main(). AnalysisBase inherits from TSelector, and line 861 is a call to TBranch::GetEntry(). The actual line is just

b_BunchNum->GetEntry(entry);

The relevant declarations and branch-assignments in AnalysisBase.h are

// in AnalysisBase class declaration
   std::vector<long>    *BunchNum;
   TBranch        *b_BunchNum;   //!
// in AnalysisBase::Init(Tree*)
   BunchNum = 0;
   fChain->SetBranchAddress("BunchNum", &BunchNum, &b_BunchNum);

Hi,

Humm … Since you are storing vector objects (and I assume that you are also storing the std::vector<Particle_Electron>), you need to load a directory for them (Technically, you only need to load a compiled collection proxy).

The required information would be loaded for each std::vector instance if, for that std::vector instance:

  • you generated the dictionary for a class whose has at least one data member of this type
    or
  • for simple type (vector, vector), you loaded the pre-compiled dictionary (for example via gROOT->ProcessLine("#include ");
    or
  • explicitly generate the dictionary (for example #pragma link C++ class vector<Particle_Electron>;

Cheers,
Philippe.

PS. The absence of this compile collection proxy leads to the use of an Emulated Collection proxy which has a different memory layout than the compile version.

Hi Philippe,

Thanks for the reply. It’s not clear to me how much of this I need to implement. I myself don’t store any vectors of anything. I have a root file that contains vector and vector. I only read these. I make several vector<Particle_Electron>, map<TString, TH1F> and the like, but these are all transient. At the end, I only actually write histograms.

Given this, for the simple types, you suggest

I naturally already head the relevant files with #include , #include and so on. Is gROOT->ProcessLine() necessary on top of this? ie what does it add to a plain #include statement?

For the custom classes, I assume that to get your suggestion to work, I’d have to add a ClassDef() line to each class to declare its existence to ROOT? Is this necessary for something I don’t intend to write to a TFile? I’ve never managed to compile successfully with a ClassDef() in, but if this is important I can of course give it another go.

Cheers,
Mike

Hi,

OK, so I’ve managed to get a simple example working, even including a vector of my own objects and all appears to work fine. Thanks for the suggestion. It will take some time to update my actual analysis code to fit this, and I can’t know until then whether the problem is actually fixed.

I have one quite big niggle remaining however. I apologise in advance for the potentially stupid and naive question here. Any clarification is much appreciated :slight_smile:

The thing is, what does making a library of my custom classes really add to what I had before? As far as I can tell, it gives me access to (a) file I/O, (b) HTML documentation, or © access to classes in CINT. None of which are particularly essential to me.

So, unless I’ve really missed something, I can’t see anything in this that will actually solve the original problem. That is, I already had compiled code, compiled using g++. To the absolute best of my knowledge it’s clear of bugs, and it ran under most circumstances. But not in ROOT 5.16, when either reading std::vector<long/float> or sorting std::vector<Particle_Electron> seems to cause a problem. Am I completely missing the point about these libraries?

Thanks,
Mike

[quote]Is gROOT->ProcessLine() necessary on top of this? ie what does it add to a plain #include statement? [/quote]It depends where you put those plain #include statements. The point of the gROOT->ProcessLine is to make sure that these statements are seen by CINT (as opposed to the compiler). When CINT sees those include statements it knows to load the shared library that contains the dictionary and I/O helper for the (default) STL containers instances.

[quote]I’d have to add a ClassDef() line to each class to declare its existence to ROOT? [/quote]No, you do not. Totally uninstrumented classes are supported by the ROOT I/O.

[quote] I’ve never managed to compile successfully with a ClassDef()[/quote]Most likely you were missing the dictionary file (which is required when you use ClassDef) You need to run rootcint on your header files and compile and link the resulting dictionary files. For example for a class MyClass declared in a header file MyHeader.h, you would write a file myLinkDef.h file containing:#pragma link C++ class MyClass+; // .. same for other classes in the library
and run rootcint:rootcint -f mydict.cxx -c MyHeader.h myLinkDef.hYou would do the same to generate the I/O (and CINT dictionary) for the class whether it has a ClassDef or not.

Cheers,
Philippe

[quote]The thing is, what does making a library of my custom classes really add to what I had before? As far as I can tell, it gives me access to (a) file I/O, (b) HTML documentation, or © access to classes in CINT. None of which are particularly essential to me. [/quote]In addition, it also properly setup the I/O for any STL container used for one of the class data member (this is likely the part that solved this problem).

You do not need to generate the dictionary for the containing classes for this. You can request the dictionary for the STL container directly. For example put in your linkdef file:#pragma link C++ class std::vector<Particle_Electron>+; #pragma link C++ class std::vector<float>+;
(as mention earlier the later is already generated as part of one of the shared library loaded when CINT sees #include ).

Cheers,
Philippe.