Writing an 'array' of numbers into a root file

Sergey Avvakumov (avva@puck.fnal.gov)
Tue, 10 Nov 1998 23:44:48 -0600 (EST)


Hi everybody,

I have to say from the start, that I'm quite new to c++ and ROOT, so I'm
probably asking about some trivial things. I'm trying to use ROOT to
replace some ZEBRA data banks and the information about an event consists
of few integers and floats and a variable length array of floats. So I
wrote a small program to accomplish this, trying to follow closely
examples 'Event.h, Event.cxx, MainEvent.cxx' from $ROOTSYS/test directory.
First I wanted to make a pointer to TArrayF to be a data member of my
class "MyTrack", then I read in documentation, that for classes, not
derived from TObject (and TArray is not) 'Streamer' method is not
generated automatically, so it's not possible to write them into a file.
Then I thought I can just copy 'Event.h', having a pointer to TClonesArray
a data member and just replacing 'Tracks' with 'object numbers', i.e.
floats, derived from TObject, but there is no such thing in ROOT by
default. I got my program working using 'TObjNum' class, like the one from
'tcollex.cxx', but because there's no such 'built-in' class, I thought
that there should be a better way to manage an array of floats. My last
try was to use a pointer to TVector as a data member, because it is an
array of floats, derived from TObject, this is how it looks:

MuTrack.h:

#ifndef __MuTrack__
#define __MuTrack__

//////////////////////////////////////////////////////////////////////////
// //
// MuTrack //
// //
// Class definition for storing muon track pulseheights //
// //
//////////////////////////////////////////////////////////////////////////

#include "TObject.h"
#include "TVector.h"

class MuTrack : public TObject {

private:
Int_t fLength; // Track length
Int_t fStart; // Most upstream counter of the track
Int_t fShwrLength; // Shower length of the event, muon track
// taken from
Float_t fShwrEnergy; // Shower energy
Float_t fMuEnergy; // Muon energy
TVector *fMuPulseHeights; // Vector of muon pulseheights

static TVector* fgMuPulseHeights;

public:
MuTrack(); // Default constructor
virtual ~MuTrack(); // Destructor

void SetLength(Int_t n) { fLength = n; }
void SetStart(Int_t n) { fStart = n; }
void SetShwrLength(Int_t n) { fShwrLength = n; }
void SetShwrEnergy(Float_t e) { fShwrEnergy = e; }
void SetMuEnergy(Float_t e) { fMuEnergy = e; }

void ResizeTo(Int_t n) { fMuPulseHeights->ResizeTo(n); }
void Copy(TVector& v) { fMuPulseHeights->operator=(v); }
TVector* GetMuPulseHeights() const { return fMuPulseHeights; }

ClassDef(MuTrack,1) // Class definition macro
};

#endif

------------------------------------------------------------------------

MuTrack.cxx:

#include "MuTrack.h"
#include <iostream.h>

ClassImp(MuTrack)

TVector* MuTrack::fgMuPulseHeights = 0;

//___________________________________________________________________________

MuTrack::MuTrack()
{
// Create a MuTrack object.
// When the constructor is invoked for the first time, the class static
// variable fgMuPulseHeights is 0 and the TVector fgMuPulseHeights
// is created.

if (!fgMuPulseHeights) fgMuPulseHeights = new TVector(84);
fMuPulseHeights = fgMuPulseHeights;
fLength = 0;
fStart = 0;
fShwrLength = 0;
fShwrEnergy = 0.0;
fMuEnergy = 0.0;
}

MuTrack::~MuTrack () { }

---------------------------------------------------------------------------

MainMuTrack.cxx :

#include <stdlib.h>
#include <iostream.h>

#include "TROOT.h"
#include "TFile.h"
#include "TRandom.h"
#include "TTree.h"
#include "TBranch.h"
#include "TVector.h"

#include "MuTrack.h"

//____________________________________________________________________________
int main()
{
TROOT simple("simple","Example of creation of a tree");

Int_t nevent = 400; // by default create 400 events
Int_t comp = 1; // by default file is compressed
Int_t split = 1; // by default, split Event in sub branches

TFile* hfile;
MuTrack* mutrack;
TTree* tree;

Int_t nb = 0;
Int_t ev;
Int_t bufsize;

// Create a new ROOT binary machine independent file.
// Note that this file may contain any kind of ROOT objects, histograms,
// pictures, graphics objects, detector geometries, tracks, events, etc..
// This file is now becoming the current directory.
hfile = new TFile("Event.root","RECREATE","TTree benchmark ROOT file");
hfile->SetCompressionLevel(comp);

// Create one event
mutrack = new MuTrack();

// Create a ROOT Tree and one superbranch
tree = new TTree("T","An example of a ROOT tree");
tree->SetAutoSave(1000000); // autosave when 1 Mbyte written
bufsize = 256000;
if (split) bufsize /= 4;
tree->Branch("event", "MuTrack", &mutrack, bufsize,split);

// Write out 'nevent' random events.
for (ev = 0; ev < nevent; ev++)
{
cout << "Event " << ev << endl;
Int_t length = (Int_t)(50*gRandom->Rndm(1)+1);
Int_t start = (Int_t)(80*gRandom->Rndm(1)+1);
Int_t shwrlength = (Int_t)(10*gRandom->Rndm(1)+1);
Float_t shwrenergy = gRandom->Rndm(1)*200.0;
Float_t muenergy = gRandom->Rndm(1)*90.0;

mutrack->SetLength(length);
mutrack->SetStart(start);
mutrack->SetShwrLength(shwrlength);
mutrack->SetShwrEnergy(shwrenergy);
mutrack->SetMuEnergy(muenergy);

TVector* vector = new TVector(length);
for (Int_t i = 0; i < length; i++)
{
Float_t ph = gRandom->Rndm(1)*90.0;
vector->operator()(i) = ph;
}

mutrack->ResizeTo(length);
mutrack->Copy(*vector);
delete vector;
nb += tree->Fill(); //fill the tree
}

hfile->Write();
tree->Print();

hfile->Close();
return 0;
}
---------------------------------------------------------------------------

This program works, but occasionally I it prints out error messages:

CustomReAlloc2: oldsize != size

I sort of figured out that these errors are from resizing vector
*fMuPulseHeights, the memory checker reports an error despite,
that MuTrack() constructor 'reserves' enough memory, with
fgMuPulseHeights = new TVector(84), to hold the largest
possible vector. What I don't understand is why this error
is not printed every time the size of *fMuPulseHeights gets
increased, but only occasionally.

So my questions are - first, how to fix this program, eliminating
these memory errors, and second what is the 'best' way to have an
array of floats as a data member of the class, so that it's 'easy' to
write objects of this class into a root file?

Thank you very much, especially to those, who read the entire posting.

Sergei Avvakumov
avva@fnal.gov