TLorentzVector: variable-length array vs vector

Hi.

The following piece of code appears to run fine and produces an output ROOT file without any complaints. When I try to browse the contents, I observe the following:

  • variables px, py (variable-length arrays of type Float_t) can be accessed without problems.
  • variable q (vector) can also be accessed without problems.
  • variable p (variable-length array of type TLorentzVector) cannot be read back: I am getting errors that the # of bytes read is not what was expected.

(I have a small bias against vector since I would like to avoid making an extra copy of a temporary object.)

Any ideas what I am doing wrong?

Many thanks.

–Christos

PS. Running ROOT 5.22/00 on Windows Vista SP1 (compiled with win32gdk, Visual Studio 2008).

[code]// root stuff
#include <TROOT.h>
#include <TChain.h>
#include <TFile.h>
#include <TLeaf.h>
#include <TBranch.h>
#include <TRandom.h>
#include <TLorentzVector.h>

#include

// maximum # of tracks in event
const int N_MAX = 50;

/// class containing output root-tuple structure
class Event : public TObject {
public:
/// number of tracks
Int_t N;
/// event #
Int_t evt_no;
// px, py
Float_t * px; // [N]
Float_t * py; // [N]
TLorentzVector * p; // [N]
std::vector q;
// constructor
Event(void){
px = new Float_t[N_MAX];
py = new Float_t[N_MAX];
p = new TLorentzVector[N_MAX];
}

// destructor
~Event(void){
delete [] px; delete [] py; delete [] p;
}

ClassDef(Event, 1)
};

int variableLengthArray(void)
{

TFile * output_file = new TFile(“temp.root”, “recreate”);
TTree * root_tree = new TTree(“tree”, “root-tuple description”);
root_tree->SetDirectory(output_file);

Event * evt = new Event();
TBranch * branch = root_tree->Branch(“myTuple”, “Event”, &evt, 8000, 1);

for(int i = 0; i != 10000; ++i)
{ // loop over events

  evt->q.clear();
  // get # of tracks for event
  evt->N = int(gRandom->Gaus(10, 2) ); // gauss with mean = 10, sigma = 2

  // do not go beyond maximum length!
  if(evt->N > N_MAX)evt->N = N_MAX;

  evt->evt_no = i;

  for(int j = 0; j < evt->N; ++j)
{ // loop over tracks in event
  
  float px = gRandom->Gaus(0, 5); // gauss with mean = 0, sigma = 5;
  float py = gRandom->Gaus(3, 2); // gauss with mean = 3, sigma = 2
  evt->px[j] = px;
  evt->py[j] = py;
  evt->p[j].SetXYZM(px, py, 0, 0);
  TLorentzVector tmp; tmp.SetXYZM(px, py, 0, 0); evt->q.push_back(tmp);
} // loop over tracks in event

  root_tree->Fill();
} // loop over events

output_file->cd();
root_tree->Write();
output_file->Close();

return 0;

}
[/code]

I assume this link answers my question. Didn’t spot it earlier…

Hi,

Actually, TLorentzVector * p; // [N] is currently not supported when splitting the class.

By the way, the most efficient container you can use (better than both std::vector and C-style array (for different reasons :slight_smile:) ) is a TClonesArray.

Cheers,
Philippe.

Dear Philippe.

Thanks for the answer. I followed your advice and implemented this by using a TClonesArray and this seems to do the trick.

I do have one last question though. Would a call to TClonesArray::Clear at the beginning of the event loop take care of the necessary cleanup? I would like to ensure there are no memory leaks.

Please see the code below.

Many thanks.

–Christos

[code]// root stuff
#include <TROOT.h>
#include <TChain.h>
#include <TFile.h>
#include <TLeaf.h>
#include <TBranch.h>
#include <TRandom.h>
#include <TLorentzVector.h>
#include <TClonesArray.h>

#include

// maximum # of tracks in event
const int N_MAX = 50;

/// class containing output root-tuple structure
class Event : public TObject {
public:
/// number of tracks
Int_t N;
/// event #
Int_t evt_no;
// px, py
Float_t * px; // [N]
Float_t * py; // [N]
TClonesArray * p;
std::vector q;
// constructor
Event(void){
px = new Float_t[N_MAX];
py = new Float_t[N_MAX];
p = new TClonesArray(“TLorentzVector”);
}

// destructor
~Event(void){
delete [] px; delete [] py; delete p;
}

ClassDef(Event, 1)
};

int variableLengthArray(void)
{

TFile * output_file = new TFile(“temp.root”, “recreate”);
TTree * root_tree = new TTree(“tree”, “root-tuple description”);
root_tree->SetDirectory(output_file);

Event * evt = new Event();
TBranch * branch = root_tree->Branch(“myTuple”, “Event”, &evt, 8000, 2);

TClonesArray & p_ = *(evt->p);

for(int i = 0; i != 10000; ++i)
{ // loop over events

  evt->p->Clear();
  evt->q.clear();
  // get # of tracks for event
  evt->N = int(gRandom->Gaus(10, 2) ); // gauss with mean = 10, sigma = 2

  // do not go beyond maximum length!
  if(evt->N > N_MAX)evt->N = N_MAX;

  evt->evt_no = i;

  for(int j = 0; j < evt->N; ++j)
{ // loop over tracks in event
  
  float px = gRandom->Gaus(0, 5); // gauss with mean = 0, sigma = 5;
  float py = gRandom->Gaus(3, 2); // gauss with mean = 3, sigma = 2
  evt->px[j] = px;
  evt->py[j] = py;
  new(p_[j]) TLorentzVector(px, py, 0, 0);
  TLorentzVector tmp; tmp.SetXYZM(px, py, 0, 0); evt->q.push_back(tmp);
} // loop over tracks in event

  root_tree->Fill();
} // loop over events

output_file->cd();
root_tree->Write();
output_file->Close();

return 0;

}
[/code]

[quote]Would a call to TClonesArray::Clear at the beginning of the event loop take care of the necessary cleanup?[/quote]Yes. (However see TClonesArray::Clear documentation for more complex cases)

Cheers,
Philippe