Re: [ROOT] bug in TTree::Branch?

From: Susan Kasahara (schubert@hep.umn.edu)
Date: Mon Dec 06 2004 - 16:59:03 MET


Hi Rene,
Thanks for your reply.  I understand that one approach is more efficient 
than the
other, but I still think there is a problem in the second case and this 
has more general
application than the Event example.   It appears to me that the 
TTree::Branch method intention is
to delete the internally constructed Event object and resets the event 
ptr to 0 on output,
and in fact I do see the event ptr reset to 0, but the Event destructor 
is not invoked before this.
For example, modifying the second test script to print the event ptrs 
before & after:
{

gSystem -> Load("libEvent.so");

TFile* file = new TFile("test.root","RECREATE");
TTree* tree = new TTree("Event","Event tree");

Event* event = 0;
cout << "Create Event tree branch, event = " << event << endl;
TBranch *branch = tree->Branch("event", "Event", &event, 64000,99);
cout << "Done with branch create, event =  " << event << endl;

}

yields this:
root [0] .x testEvent2.C
Create Event tree branch, event = 0
Event constructor
Done with branch create, event =  0
root[1]

Thanks again for your help.
-Sue

Rene Brun wrote:

>Hi Sue,
>
>The current behaviour is correct.
>If you have : Event* event = new Event();
>TTree::Branch uses the existing object to organize the sub branches.
>If you have: Event* event = 0;
>TTree::Branch must create an object via the default constructor.
>This object is not deleted when exiting the branch constructor
>  -because most of the time the default object created may be used for filling.
>  -if it was deleted, you will have to create one and call SetBranchAddress.
>For this reason, it is always more convenient
>  -to create an object before calling TTree::Branch
>  -to set the pointer to 0 when reading the Tree.
>This is the recommended process in our Event example.
>
>Rene brun
>
>
>Sue Kasahara wrote:
>  
>
>>Hi root talk,
>>I've discovered what I think is a bug in the TTree::Branch method:
>>    virtual TBranch     *Branch(const char *name, const char *classname,
>>void *addobj, Int_t bufsize=32000, Int_t splitlevel=99);
>>which is that if I pass it the address of a null ptr, the internally
>>constructed object of class "classname" is not properly destructed
>>before exiting the method.
>>I can illustrate the problem with the test/Event example, which I've
>>altered only slightly to print two messages: one when the Event
>>constructor is
>>invoked, and one when the Event destructor is invoked.
>>If I execute the following script in a root session:
>>{
>>
>>gSystem -> Load("libEvent.so");
>>
>>TFile* file = new TFile("test.root","RECREATE");
>>TTree* tree = new TTree("Event","Event tree");
>>
>>Event* event = new Event();
>>cout << "Create Event tree branch " << endl;
>>TBranch *branch = tree->Branch("event", "Event", &event, 64000,99);
>>cout << "Done with branch create " << endl;
>>if ( event ) delete event; event = 0;
>>
>>}
>>
>>I receive the expected result:
>>root [0] .x testEvent.C
>>Event constructor
>>Create Event tree branch
>>Done with branch create
>>Event destructor
>>root[1]
>>
>>but if I execute this script:
>>{
>>
>>gSystem -> Load("libEvent.so");
>>
>>TFile* file = new TFile("test.root","RECREATE");
>>TTree* tree = new TTree("Event","Event tree");
>>
>>Event* event = 0;
>>cout << "Create Event tree branch " << endl;
>>TBranch *branch = tree->Branch("event", "Event", &event, 64000,99);
>>cout << "Done with branch create " << endl;
>>
>>}
>>
>>root [0] .x testEvent2.C
>>Create Event tree branch
>>Event constructor
>>Done with branch create
>>root[1]
>>
>>which is unexpected because the Event destructor is never invoked.
>>I'm attaching the modified Event.cxx that I use in this example.  I'm using
>>root cvs from today 5 Dec 2004,  (I also observed the problem with root from
>>23 Oct 2004.), on linux with gcc 3.2.3.
>>Thanks for your help,
>>-Sue
>>
>>  --------------------------------------------------------------------------------
>>// @(#)root/test:$Name:  $:$Id: Event.cxx,v 1.27 2004/01/25 20:33:32 brun Exp $
>>// Author: Rene Brun   19/08/96
>>
>>////////////////////////////////////////////////////////////////////////
>>//
>>//                       Event and Track classes
>>//                       =======================
>>//
>>//  The Event class is a naive/simple example of an event structure.
>>//     public:
>>//        char           fType[20];
>>//        char          *fEventName;         //run+event number in character format
>>//        Int_t          fNtrack;
>>//        Int_t          fNseg;
>>//        Int_t          fNvertex;
>>//        UInt_t         fFlag;
>>//        Double32_t     fTemperature;
>>//        Int_t          fMeasures[10];
>>//        Double32_t     fMatrix[4][4];
>>//        Double32_t    *fClosestDistance; //[fNvertex] indexed array!
>>//        EventHeader    fEvtHdr;
>>//        TClonesArray  *fTracks;
>>//        TRefArray     *fHighPt;            //array of High Pt tracks only
>>//        TRefArray     *fMuons;             //array of Muon tracks only
>>//        TRef           fLastTrack;         //pointer to last track
>>//        TRef           fHistoWeb;          //EXEC:GetHistoWeb reference to an histogram in a TWebFile
>>//        TH1F          *fH;
>>//        TBits          fTriggerBits;       //Bits triggered by this event.
>>//
>>//   The EventHeader class has 3 data members (integers):
>>//     public:
>>//        Int_t          fEvtNum;
>>//        Int_t          fRun;
>>//        Int_t          fDate;
>>//
>>//
>>//   The Event data member fTracks is a pointer to a TClonesArray.
>>//   It is an array of a variable number of tracks per event.
>>//   Each element of the array is an object of class Track with the members:
>>//     private:
>>//        Float_t      fPx;           //X component of the momentum
>>//        Float_t      fPy;           //Y component of the momentum
>>//        Float_t      fPz;           //Z component of the momentum
>>//        Float_t      fRandom;       //A random track quantity
>>//        Float_t      fMass2;        //The mass square of this particle
>>//        Float_t      fBx;           //X intercept at the vertex
>>//        Float_t      fBy;           //Y intercept at the vertex
>>//        Float_t      fMeanCharge;   //Mean charge deposition of all hits of this track
>>//        Float_t      fXfirst;       //X coordinate of the first point
>>//        Float_t      fXlast;        //X coordinate of the last point
>>//        Float_t      fYfirst;       //Y coordinate of the first point
>>//        Float_t      fYlast;        //Y coordinate of the last point
>>//        Float_t      fZfirst;       //Z coordinate of the first point
>>//        Float_t      fZlast;        //Z coordinate of the last point
>>//        Double32_t   fCharge;       //Charge of this track
>>//        Double32_t   fVertex[3];    //Track vertex position
>>//        Int_t        fNpoint;       //Number of points for this track
>>//        Short_t      fValid;        //Validity criterion
>>//        Int_t        fNsp;          //Number of points for this track with a special value
>>//        Double32_t  *fPointValue;   //[fNsp] a special quantity for some point.
>>//        TBits        fTriggerBits;  //Bits triggered by this track.
>>//
>>//   An example of a batch program to use the Event/Track classes is given
>>//   in this directory: MainEvent.
>>//   Look also in the same directory at the following macros:
>>//     - eventa.C  an example how to read the tree
>>//     - eventb.C  how to read events conditionally
>>//
>>//   During the processing of the event (optionally) also a large number
>>//   of histograms can be filled. The creation and handling of the
>>//   histograms is taken care of by the HistogramManager class.
>>//
>>////////////////////////////////////////////////////////////////////////
>>#include <iostream>
>>using namespace std;
>>
>>#include "TRandom.h"
>>#include "TDirectory.h"
>>#include "TProcessID.h"
>>
>>#include "Event.h"
>>
>>ClassImp(EventHeader)
>>ClassImp(Event)
>>ClassImp(Track)
>>ClassImp(HistogramManager)
>>
>>TClonesArray *Event::fgTracks = 0;
>>TH1F *Event::fgHist = 0;
>>
>>//______________________________________________________________________________
>>Event::Event()
>>{
>>   // Create an Event object.
>>   // When the constructor is invoked for the first time, the class static
>>   // variable fgTracks is 0 and the TClonesArray fgTracks is created.
>>
>>  cout << "Event constructor " << endl;
>>
>>   if (!fgTracks) fgTracks = new TClonesArray("Track", 1000);
>>   fTracks = fgTracks;
>>   fHighPt = new TRefArray;
>>   fMuons  = new TRefArray;
>>   fNtrack = 0;
>>   fH      = 0;
>>   Int_t i0,i1;
>>   for (i0 = 0; i0 < 4; i0++) {
>>      for (i1 = 0; i1 < 4; i1++) {
>>         fMatrix[i0][i1] = 0.0;
>>      }
>>   }
>>   for (i0 = 0; i0 <10; i0++) fMeasures[i0] = 0;
>>   for (i0 = 0; i0 <20; i0++) fType[i0] = 0;
>>   fClosestDistance = 0;
>>   fEventName = 0;
>>   fWebHistogram.SetAction(this);
>>}
>>
>>//______________________________________________________________________________
>>Event::~Event()
>>{
>>  cout << "Event destructor " << endl;
>>
>>   Clear();
>>   if (fH == fgHist) fgHist = 0;
>>   delete fH; fH = 0;
>>   delete fHighPt; fHighPt = 0;
>>   delete fMuons;  fMuons = 0;
>>   delete [] fClosestDistance;
>>   if (fEventName) delete [] fEventName;
>>}
>>
>>//______________________________________________________________________________
>>void Event::Build(Int_t ev, Int_t arg5, Float_t ptmin) {
>>  char etype[20];
>>  Float_t sigmat, sigmas;
>>  gRandom->Rannor(sigmat,sigmas);
>>  Int_t ntrack   = Int_t(arg5 +arg5*sigmat/120.);
>>  Float_t random = gRandom->Rndm(1);
>>
>>  //Save current Object count
>>  Int_t ObjectNumber = TProcessID::GetObjectCount();
>>  Clear();
>>  fHighPt->Delete();
>>  fMuons->Delete();
>>
>>  Int_t nch = 15;
>>  if (ev >= 100)   nch += 3;
>>  if (ev >= 10000) nch += 3;
>>  if (fEventName) delete [] fEventName;
>>  fEventName = new char[nch];
>>  sprintf(fEventName,"Event%d_Run%d",ev,200);
>>  sprintf(etype,"type%d",ev%5);
>>  SetType(etype);
>>  SetHeader(ev, 200, 960312, random);
>>  SetNseg(Int_t(10*ntrack+20*sigmas));
>>  SetNvertex(Int_t(1+20*gRandom->Rndm()));
>>  SetFlag(UInt_t(random+0.5));
>>  SetTemperature(random+20.);
>>
>>  for(UChar_t m = 0; m < 10; m++) {
>>     SetMeasure(m, Int_t(gRandom->Gaus(m,m+1)));
>>  }
>>  for(UChar_t i0 = 0; i0 < 4; i0++) {
>>    for(UChar_t i1 = 0; i1 < 4; i1++) {
>>       SetMatrix(i0,i1,gRandom->Gaus(i0*i1,1));
>>    }
>>  }
>>
>>  fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1)));
>>  fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1)));
>>  fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1)));
>>
>>  //  Create and Fill the Track objects
>>  for (Int_t t = 0; t < ntrack; t++) AddTrack(random,ptmin);
>>
>>  //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);
>>}
>>
>>//______________________________________________________________________________
>>Track *Event::AddTrack(Float_t random, Float_t ptmin)
>>{
>>   // Add a new track to the list of tracks for this event.
>>   // To avoid calling the very time consuming operator new for each track,
>>   // the standard but not well know C++ operator "new with placement"
>>   // is called. If tracks[i] is 0, a new Track object will be created
>>   // otherwise the previous Track[i] will be overwritten.
>>
>>   TClonesArray &tracks = *fTracks;
>>   Track *track = new(tracks[fNtrack++]) Track(random);
>>   //Save reference to last Track in the collection of Tracks
>>   fLastTrack = track;
>>   //Save reference in fHighPt if track is a high Pt track
>>   if (track->GetPt() > ptmin)   fHighPt->Add(track);
>>   //Save reference in fMuons if track is a muon candidate
>>   if (track->GetMass2() < 0.11) fMuons->Add(track);
>>   return track;
>>}
>>
>>//______________________________________________________________________________
>>void Event::Clear(Option_t * /*option*/)
>>{
>>   fTracks->Clear("C"); //will also call Track::Clear
>>   fHighPt->Delete();
>>   fMuons->Delete();
>>}
>>
>>//______________________________________________________________________________
>>void Event::Reset(Option_t * /*option*/)
>>{
>>// Static function to reset all static objects for this event
>>//   fgTracks->Delete(option);
>>
>>   delete fgTracks; fgTracks = 0;
>>   fgHist   = 0;
>>}
>>
>>//______________________________________________________________________________
>>void Event::SetHeader(Int_t i, Int_t run, Int_t date, Float_t random)
>>{
>>   fNtrack = 0;
>>   fEvtHdr.Set(i, run, date);
>>   if (!fgHist) fgHist = new TH1F("hstat","Event Histogram",100,0,1);
>>   fH = fgHist;
>>   fH->Fill(random);
>>}
>>
>>//______________________________________________________________________________
>>void Event::SetMeasure(UChar_t which, Int_t what) {
>>   if (which<10) fMeasures[which] = what;
>>}
>>
>>//______________________________________________________________________________
>>void Event::SetRandomVertex() {
>>   // This delete is to test the relocation of variable length array
>>   if (fClosestDistance) delete [] fClosestDistance;
>>   if (!fNvertex) {
>>      fClosestDistance = 0;
>>      return;
>>   }
>>   fClosestDistance = new Double32_t[fNvertex];
>>   for (Int_t k = 0; k < fNvertex; k++ ) {
>>      fClosestDistance[k] = gRandom->Gaus(1,1);
>>   }
>>}
>>
>>//______________________________________________________________________________
>>Track::Track(const Track &orig) : TObject(orig)
>>{
>>   // Copy a track object
>>
>>   fPx = orig.fPx;
>>   fPy = orig.fPy;
>>   fPz = orig.fPx;
>>   fRandom = orig.fRandom;
>>   fMass2 = orig.fMass2;
>>   fBx = orig.fBx;
>>   fBy = orig.fBy;
>>   fMeanCharge = orig.fMeanCharge;
>>   fXfirst = orig.fXfirst;
>>   fXlast  = orig.fXlast;
>>   fYfirst = orig.fYfirst;
>>   fYlast  = orig.fYlast;
>>   fZfirst = orig.fZfirst;
>>   fZlast  = orig.fZlast;
>>   fCharge = orig.fCharge;
>>
>>   fVertex[0] = orig.fVertex[0];
>>   fVertex[1] = orig.fVertex[1];
>>   fVertex[2] = orig.fVertex[2];
>>   fNpoint = orig.fNpoint;
>>   fNsp = orig.fNsp;
>>   if (fNsp) {
>>      fPointValue = new Double32_t[fNsp];
>>      for(int i=0; i<fNsp; i++) {
>>         fPointValue[i] = orig.fPointValue[i];
>>      }
>>   } else {
>>      fPointValue = 0;
>>   }
>>   fValid  = orig.fValid;
>>
>>   fTriggerBits = orig.fTriggerBits;
>>
>>}
>>
>>//______________________________________________________________________________
>>Track::Track(Float_t random) : TObject(),fTriggerBits(64)
>>{
>>   // Create a track object.
>>   // Note that in this example, data members do not have any physical meaning.
>>
>>   Float_t a,b,px,py;
>>   gRandom->Rannor(px,py);
>>   fPx = px;
>>   fPy = py;
>>   fPz = TMath::Sqrt(px*px+py*py);
>>   fRandom = 1000*random;
>>   if (fRandom < 10) fMass2 = 0.106;
>>   else if (fRandom < 100) fMass2 = 0.8;
>>   else if (fRandom < 500) fMass2 = 4.5;
>>   else if (fRandom < 900) fMass2 = 8.9;
>>   else  fMass2 = 9.8;
>>   gRandom->Rannor(a,b);
>>   fBx = 0.1*a;
>>   fBy = 0.1*b;
>>   fMeanCharge = 0.01*gRandom->Rndm(1);
>>   gRandom->Rannor(a,b);
>>   fXfirst = a*10;
>>   fXlast  = b*10;
>>   gRandom->Rannor(a,b);
>>   fYfirst = a*12;
>>   fYlast  = b*16;
>>   gRandom->Rannor(a,b);
>>   fZfirst = 50 + 5*a;
>>   fZlast  = 200 + 10*b;
>>   fCharge = Double32_t(Int_t(3*gRandom->Rndm(1)) - 1);
>>
>>   fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1)));
>>   fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1)));
>>   fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1)));
>>
>>   fVertex[0] = gRandom->Gaus(0,0.1);
>>   fVertex[1] = gRandom->Gaus(0,0.2);
>>   fVertex[2] = gRandom->Gaus(0,10);
>>   fNpoint = Int_t(60+10*gRandom->Rndm(1));
>>   fNsp = Int_t(3*gRandom->Rndm(1));
>>   if (fNsp) {
>>      fPointValue = new Double32_t[fNsp];
>>      for(int i=0; i<fNsp; i++) {
>>         fPointValue[i] = i+1;
>>      }
>>   } else {
>>      fPointValue = 0;
>>   }
>>   fValid  = Int_t(0.6+gRandom->Rndm(1));
>>}
>>
>>//______________________________________________________________________________
>>void Track::Clear(Option_t * /*option*/)
>>{
>>   fTriggerBits.Clear();
>>   delete [] fPointValue;
>>   fPointValue=0;
>>}
>>
>>//______________________________________________________________________________
>>HistogramManager::HistogramManager(TDirectory *dir)
>>{
>>   // Create histogram manager object. Histograms will be created
>>   // in the "dir" directory.
>>
>>   // Save current directory and cd to "dir".
>>   TDirectory *saved = gDirectory;
>>   dir->cd();
>>
>>   fNtrack      = new TH1F("hNtrack",    "Ntrack",100,575,625);
>>   fNseg        = new TH1F("hNseg",      "Nseg",100,5800,6200);
>>   fTemperature = new TH1F("hTemperature","Temperature",100,19.5,20.5);
>>   fPx          = new TH1F("hPx",        "Px",100,-4,4);
>>   fPy          = new TH1F("hPy",        "Py",100,-4,4);
>>   fPz          = new TH1F("hPz",        "Pz",100,0,5);
>>   fRandom      = new TH1F("hRandom",    "Random",100,0,1000);
>>   fMass2       = new TH1F("hMass2",     "Mass2",100,0,12);
>>   fBx          = new TH1F("hBx",        "Bx",100,-0.5,0.5);
>>   fBy          = new TH1F("hBy",        "By",100,-0.5,0.5);
>>   fMeanCharge  = new TH1F("hMeanCharge","MeanCharge",100,0,0.01);
>>   fXfirst      = new TH1F("hXfirst",    "Xfirst",100,-40,40);
>>   fXlast       = new TH1F("hXlast",     "Xlast",100,-40,40);
>>   fYfirst      = new TH1F("hYfirst",    "Yfirst",100,-40,40);
>>   fYlast       = new TH1F("hYlast",     "Ylast",100,-40,40);
>>   fZfirst      = new TH1F("hZfirst",    "Zfirst",100,0,80);
>>   fZlast       = new TH1F("hZlast",     "Zlast",100,0,250);
>>   fCharge      = new TH1F("hCharge",    "Charge",100,-1.5,1.5);
>>   fNpoint      = new TH1F("hNpoint",    "Npoint",100,50,80);
>>   fValid       = new TH1F("hValid",     "Valid",100,0,1.2);
>>
>>   // cd back to original directory
>>   saved->cd();
>>}
>>
>>//______________________________________________________________________________
>>HistogramManager::~HistogramManager()
>>{
>>   // Clean up all histograms.
>>
>>   // Nothing to do. Histograms will be deleted when the directory
>>   // in which tey are stored is closed.
>>}
>>
>>//______________________________________________________________________________
>>void HistogramManager::Hfill(Event *event)
>>{
>>   // Fill histograms.
>>
>>   fNtrack->Fill(event->GetNtrack());
>>   fNseg->Fill(event->GetNseg());
>>   fTemperature->Fill(event->GetTemperature());
>>
>>   for (Int_t itrack = 0; itrack < event->GetNtrack(); itrack++) {
>>      Track *track = (Track*)event->GetTracks()->UncheckedAt(itrack);
>>      fPx->Fill(track->GetPx());
>>      fPy->Fill(track->GetPy());
>>      fPz->Fill(track->GetPz());
>>      fRandom->Fill(track->GetRandom());
>>      fMass2->Fill(track->GetMass2());
>>      fBx->Fill(track->GetBx());
>>      fBy->Fill(track->GetBy());
>>      fMeanCharge->Fill(track->GetMeanCharge());
>>      fXfirst->Fill(track->GetXfirst());
>>      fXlast->Fill(track->GetXlast());
>>      fYfirst->Fill(track->GetYfirst());
>>      fYlast->Fill(track->GetYlast());
>>      fZfirst->Fill(track->GetZfirst());
>>      fZlast->Fill(track->GetZlast());
>>      fCharge->Fill(track->GetCharge());
>>      fNpoint->Fill(track->GetNpoint());
>>      fValid->Fill(track->GetValid());
>>   }
>>}
>>    
>>



This archive was generated by hypermail 2b29 : Sun Jan 02 2005 - 05:50:10 MET