Hello All,
I have been struggling to get a TTree with custom objects working correctly.
I need to generate some custom Objects which I can then read in a Geant4 application.
I followed this advice, http://root.cern.ch/phpBB3//viewtopic.php?t=6172, and changed the JetEvent example from Root into the following file TMyRootEvent.hpp. Otherwise I was getting vtable and typeinfo errors when compiling my Geant4 application.
#ifndef TMyRootEvent_hpp
#define TMyRootEvent_hpp
#include "TObject.h"
#include "TString.h"
#include "TMath.h"
#include "TRandom.h"
#include "TClonesArray.h"
#include "TRefArray.h"
#include "TVector3.h"
class Hit : public TObject {
public:
Float_t fX; //X of hit
Float_t fY; //Y of hit
Float_t fZ; //Z of hit
public:
Hit(){ };
~Hit() { };
ClassDef(Hit,1) //A track hit
};
class Track : public TObject {
public:
Float_t fPx; //X component of the momentum
Float_t fPy; //Y component of the momentum
Float_t fPz; //Z component of the momentum
Int_t fNhit; //Number of hits for this track
TRefArray fHits; //List of Hits for this track
public:
Track() { };
~Track() { };
Int_t GetNhit() const { return fNhit; }
TRefArray &GetHits() {return fHits; }
ClassDef(Track,1) //A track segment
};
class Jet : public TObject {
public:
Double_t fPt; //Pt of jet
Double_t fPhi; //Phi of jet
TRefArray fTracks; //List of tracks in the jet
public:
Jet() { };
~Jet() { };
TRefArray &GetTracks() {return fTracks; }
ClassDef(Jet,1) //Jet class
};
class Particle : public TObject {
private:
Int_t fPdgCode;
Double_t fPx; //Px of jet
Double_t fPy; //Py of jet
Double_t fPz; //Pz of jet
Double_t fE; //E of jet
public:
Particle() { fPx = fPy = fPz = fE = 0;};
~Particle() { };
public:
Int_t GetPdgCode() const {return fPdgCode;};
Double_t Px() const {return fPx;};
Double_t Py() const {return fPy;};
Double_t Pz() const {return fPz;};
Double_t E() const {return fE;};
void SetPdgCode(Int_t pdg) {fPdgCode = pdg;};
void SetPx(Double_t px) {fPx = px;};
void SetPy(Double_t py) {fPy = py;};
void SetPz(Double_t pz) {fPz = pz;};
void SetE(Double_t e) {fE = e;};
ClassDef(Particle,1) //Particle class
};
class TMyRootEvent : public TObject
{
private:
TVector3 fVertex; //vertex coordinates
Int_t fNparticle; //Number of particles
Int_t fNjet; //Number of jets
Int_t fNtrack; //Number of tracks
Int_t fNhitA; //Number of hist in detector A
Int_t fNhitB; //Number of hist in detector B
TClonesArray *fParticles; //->array with all Particles
TClonesArray *fJets; //->array with all jets
TClonesArray *fTracks; //->array with all tracks
TClonesArray *fHitsA; //->array of hits in detector A
TClonesArray *fHitsB; //->array of hits in detector B
public :
TMyRootEvent()
{
// Create a TMyRootEvent object.
// When the constructor is invoked for the first time, the class static
// variables fgxxx are 0 and the TClonesArray fgxxx are created.
fParticles = new TClonesArray("Particle", 100);
fTracks = new TClonesArray("Track", 100);
fJets = new TClonesArray("Jet", 10);
fHitsA = new TClonesArray("Hit", 10000);
fHitsB = new TClonesArray("Hit", 1000);
fNparticle = fNjet = fNtrack = fNhitA = fNhitB = 0;
}
~TMyRootEvent ()
{
Reset(0);
}
void Build(Int_t jetm = 3, Int_t trackm = 10, Int_t hitam = 100, Int_t hitbm = 10) {
//Build one event
//Save current Object count
Int_t ObjectNumber = TProcessID::GetObjectCount();
Clear(0);
Hit *hit;
Track *track;
Jet *jet;
Particle *particle;
fNparticle = fNjet = fNtrack = fNhitA = fNhitB = 0;
fVertex.SetXYZ(gRandom->Gaus(0,0.1),
gRandom->Gaus(0,0.2),
gRandom->Gaus(0,10));
Int_t njets = (Int_t)gRandom->Gaus(jetm,1); if (njets < 1) njets = 1;
for (Int_t j=0;j<njets;j++) {
particle = AddParticle();
jet = AddJet();
jet->fPt = gRandom->Gaus(0,10);
jet->fPhi = 2*TMath::Pi()*gRandom->Rndm();
Int_t ntracks = (Int_t)gRandom->Gaus(trackm,3); if (ntracks < 1) ntracks = 1;
for (Int_t t=0;t<ntracks;t++) {
track = AddTrack();
track->fPx = gRandom->Gaus(0,1);
track->fPy = gRandom->Gaus(0,1);
track->fPz = gRandom->Gaus(0,5);
jet->fTracks.Add(track);
Int_t nhitsA = (Int_t)gRandom->Gaus(hitam,5);
for (Int_t ha=0;ha<nhitsA;ha++) {
hit = AddHitA();
hit->fX = 10000*j + 100*t +ha;
hit->fY = 10000*j + 100*t +ha+0.1;
hit->fZ = 10000*j + 100*t +ha+0.2;
track->fHits.Add(hit);
}
Int_t nhitsB = (Int_t)gRandom->Gaus(hitbm,2);
for (Int_t hb=0;hb<nhitsB;hb++) {
hit = AddHitB();
hit->fX = 20000*j + 100*t +hb+0.3;
hit->fY = 20000*j + 100*t +hb+0.4;
hit->fZ = 20000*j + 100*t +hb+0.5;
track->fHits.Add(hit);
}
track->fNhit = nhitsA + nhitsB;
}
}
//Restore Object count
//To save space in the table keeping track of all referenced objects
//we assume that our events do not address each other. We reset the
//object count to what it was at the beginning of the event.
TProcessID::SetObjectCount(ObjectNumber);
}
void Clear(Option_t *option)
{
fNparticle = fNjet = fNtrack = fNhitA = fNhitB = 0;
fParticles->Clear(option);
fJets->Clear(option);
fTracks->Clear(option);
fHitsA->Clear(option);
fHitsB->Clear(option);
}
//______________________________________________________________________________
void Reset(Option_t *)
{
// Static function to reset all static objects for this event
delete fParticles; fParticles = 0;
delete fJets; fJets = 0;
delete fTracks; fTracks = 0;
delete fHitsA; fHitsA = 0;
delete fHitsB; fHitsB = 0;
}
Int_t GetNparticle() const { return fNparticle; }
Int_t GetNjet() const { return fNjet; }
Int_t GetNtrack() const { return fNtrack; }
Int_t GetNhitA() const { return fNhitA; }
Int_t GetNhitB() const { return fNhitB; }
Particle *AddParticle()
{
// Add a new Jet to the list of tracks for this event.
TClonesArray &particles = *fParticles;
Particle *particle = new(particles[fNparticle++]) Particle();
return particle;
}
Jet *AddJet()
{
// Add a new Jet to the list of tracks for this event.
TClonesArray &jets = *fJets;
Jet *jet = new(jets[fNjet++]) Jet();
return jet;
}
Track *AddTrack()
{
// Add a new track to the list of tracks for this event.
TClonesArray &tracks = *fTracks;
Track *track = new(tracks[fNtrack++]) Track();
return track;
}
Hit *AddHitA()
{
// Add a new hit to the list of hits in detector A
TClonesArray &hitsA = *fHitsA;
Hit *hit = new(hitsA[fNhitA++]) Hit();
return hit;
}
Hit *AddHitB()
{
// Add a new hit to the list of hits in detector B
TClonesArray &hitsB = *fHitsB;
Hit *hit = new(hitsB[fNhitB++]) Hit();
return hit;
}
TClonesArray *GetJets() const { return fJets; }
ClassDef (TMyRootEvent,1) ;
} ;
#endif
I was able to write from of my Geant4 classes as follows (just fine!)
f = new TFile("JetEvent.root","recreate");
T = new TTree("T","Event example with Jets");
event = new TMyRootEvent;
T->Branch("event","TMyRootEvent",&event,8000,2);
for (Int_t ev=0;ev<250;ev++) {
event->Build();
T->Fill();
}
T->Print();
T->Write();
In a simple root macro, I could only write the file as follows.
root>.L TMyRootEvent.hpp+
root>.x test.C
#include <stdio.h>
#include <vector>
#include "TMyRootEvent.hpp"
#include "TFile.h"
#include "TTree.h"
#include "TRandom.h"
#include "TROOT.h"
#include "TSystem.h"
#include "Riostream.h"
using namespace std;
void test(){
//gROOT->ProcessLine(".L TMyRootEvent.hpp+");
gSystem->Load("TMyRootEvent_hpp.so");
TFile *f = TFile::Open("events.root","RECREATE");
TTree *t1 = new TTree("t1","Tree With Particles");
TMyRootEvent *event = new TMyRootEvent();
t1->Branch("event",&event,8000,2);
for(Int_t iev = 0; iev < 10; iev++){
event->Build();
t1->Fill();
}
t1->Write();
t1->Print();
}
Uncommenting gROOT->ProcessLine(".L TMyRootEvent.hpp+") did not work!
If I would generate the library, leave my root session, and just load said library agian,
I would get something along these lines
Error in TTree::Branch: The actual class (TVector3) of the object provided for the definition of the branch “event” does not inherit from TMyRootEvent
*** glibc detected *** /home/yakov/FC/root/bin/root.exe: corrupted double-linked list: 0x0000000001ff7c20 ***
Memory Map, etc etc etc etc.
Could someone please help me with this?
I feel it may have to do with the ClassImp stuff because that was practically the only modification I did
in going from JetEvents.h/cpp ->TMyRootEvent.hpp
Best,
-Yakov