Hi Rene,
Okay, thanks. In the meantime, is it possible to make this transition
using a customized Streamer (or some other device) to map the
movement of the datamember to the base class? I am encountering
just such a transition as we move to a new data model.
I've tried implementing a customized Streamer for the EventHeader
class version 2. The purpose of the customized Streamer is to properly
fill in the fRun data member when reading in old files generated with
EventHeader version 1. I find that this customized Streamer works when
the EventHeader branch in the version 1 file is not split (e.g. I generate the old
output file running Event with no arguments).
But when I split the EventHeader branch in the old version 1 data file, e.g. using:
$ Event 10 1 99 1
I find that when reading this old file using the new EventHeader version 2
code, my customized Streamer is never invoked.
So, is a customized Streamer the way to handle this type of transition and
if not, what is the correct way? I've attached the steps I'm taking to run
the tests and the code with the customized Streamer.
Thanks again for your help.
-Sue
These are the steps I'm taking (using today's cvs root and gcc 3.2):
1)Using unmodified $ROOTSYS/test/Event code, I generate an output file
i)$ Event 10 (to generate an unsplit tree)
ii)$ Event 10 1 99 1 (to generate a split tree)
2)Modify the Event.h,.cxx, and EventLinkDef.h code to produce EventHeader
version 2 with customized Streamer
This code is attached.
3)Run root and use the provided eventa.cxx code to read the tree in:
root[0].x eventload.cxx // load the new libraries with EventHeader version 2
root[1].x eventa.cxx // read the old file generated with EventHeader version 1
Rene Brun wrote:
> Hi Sue,
>
> The schema evolution will work in your example if you
> move a member from a derived class to an EXISTING base class.
> In your case RunHeader is a new class. This case is not currently
> supported, but should not be too complex to support.
> On my long list of things to do.
>
> Rene Brun
>
> On Tue, 19 Nov 2002, Susan Kasahara wrote:
>
> > Hi roottalk,
> > I'm trying to understand automatic schema evolution in root.
> > I have used automatic schema evolution all along in generating
> > my files (old & new), using the '+' flag in the class pragma
> > statement in the LinkDef.h file to activate this. I am having
> > a problem now when attempting to move a data member
> > from a derived class to a base class.
> > When I read the documentation (root user manual version 3.02c),
> > I interpret the section on Schema Evolution to indicate that
> > root will map a persistent data member to one memory in the
> > event that a data member is moved from a derived class to a
> > base class, or vice versa. But in tests I find that when I move
> > a data member to a base class, this mapping
> > doesn't seem to take place. Instead the moved data member is simply
> > skipped on input.
> > For example, if I move the fRun data member of the EventHeader
> > class in $ROOTSYS/test/Event.h to a new base class "RunHeader", e.g.
> > change the current:
> >
> > class EventHeader {
> >
> > private:
> > Int_t fEvtNum;
> > Int_t fRun;
> > Int_t fDate;
> > public:
> > ...
> > ClassDef(EventHeader,1)
> > };
> >
> > to:
> >
> > class RunHeader {
> > protected:
> > Int_t fRun;
> >
> > public:
> > ...
> > ClassDef(RunHeader,1)
> > };
> >
> > class EventHeader : public RunHeader {
> > private:
> > Int_t fEvent;
> > Int_t fDate;
> > public:
> > ...
> > ClassDef(EventHeader,2)
> > };
> >
> > I find that using EventHeader version 2 I am able to read old files
> > that have been generated with EventHeader version 1, but the fRun
> > data member, now in the RunHeader base class, is not filled in
> > properly.
> >
> > So, two questions:
> > 1)Should I be able to move a data member to base class and expect
> > root's schema evolution to be able to map this transition when
> > reading old data files?
> > 2)If not, how do I handle this mapping myself?
> >
> > I am using cvs root from today with gcc 3.2 on linux.
> > Thanks for your help,
> > -Sue
> >
#ifndef ROOT_Event
#define ROOT_Event
//////////////////////////////////////////////////////////////////////////
// //
// Event //
// //
// Description of the event and track parameters //
// //
//////////////////////////////////////////////////////////////////////////
#include "TObject.h"
#include "TClonesArray.h"
#include "TRefArray.h"
#include "TRef.h"
#include "TH1.h"
#include "TMath.h"
class TDirectory;
class Track : public TObject {
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
Float_t fCharge; //Charge of this track
Float_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
Float_t* fPointValue; //[fNsp] a special quantity for some point.
public:
Track() { fPointValue = 0; }
Track(Float_t random);
virtual ~Track() {Clear();}
void Clear(Option_t *option="") { delete [] fPointValue; fPointValue=0; }
Float_t GetPx() const { return fPx; }
Float_t GetPy() const { return fPy; }
Float_t GetPz() const { return fPz; }
Float_t GetPt() const { return TMath::Sqrt(fPx*fPx + fPy*fPy); }
Float_t GetRandom() const { return fRandom; }
Float_t GetBx() const { return fBx; }
Float_t GetBy() const { return fBy; }
Float_t GetMass2() const { return fMass2; }
Float_t GetMeanCharge() const { return fMeanCharge; }
Float_t GetXfirst() const { return fXfirst; }
Float_t GetXlast() const { return fXlast; }
Float_t GetYfirst() const { return fYfirst; }
Float_t GetYlast() const { return fYlast; }
Float_t GetZfirst() const { return fZfirst; }
Float_t GetZlast() const { return fZlast; }
Float_t GetCharge() const { return fCharge; }
Float_t GetVertex(Int_t i=0) {return (i<3)?fVertex[i]:0;}
Int_t GetNpoint() const { return fNpoint; }
Short_t GetValid() const { return fValid; }
virtual void SetValid(Int_t valid=1) { fValid = valid; }
Int_t GetN() const { return fNsp; }
Float_t GetPointValue(Int_t i=0) const { return (i<fNsp)?fPointValue[i]:0; }
ClassDef(Track,2) //A track segment
};
class RunHeader {
public:
RunHeader() : fRun(0) {}
virtual ~RunHeader() {}
Int_t GetRun() const { return fRun; }
protected:
Int_t fRun;
ClassDef(RunHeader,1) // Run Header
};
class EventHeader : public RunHeader {
private:
Int_t fEvtNum;
Int_t fDate;
public:
EventHeader() : fEvtNum(0), fDate(0) { }
virtual ~EventHeader() { }
void Set(Int_t i, Int_t r, Int_t d) { fEvtNum = i; fRun = r; fDate = d; }
Int_t GetEvtNum() const { return fEvtNum; }
Int_t GetDate() const { return fDate; }
ClassDef(EventHeader,2) //Event Header
};
class Event : public TObject {
private:
char fType[20]; //event type
char *fEventName; //run+event number in character format
Int_t fNtrack; //Number of tracks
Int_t fNseg; //Number of track segments
Int_t fNvertex;
UInt_t fFlag;
Float_t fTemperature;
Int_t fMeasures[10];
Float_t fMatrix[4][4];
Float_t *fClosestDistance; //[fNvertex]
EventHeader fEvtHdr;
TClonesArray *fTracks; //->array with all tracks
TRefArray *fHighPt; //array of High Pt tracks only
TRefArray *fMuons; //array of Muon tracks only
TRef fLastTrack; //reference pointer to last track
TRef fWebHistogram; //EXEC:GetWebHistogram reference to an histogram in a TWebFile
TH1F *fH; //->
static TClonesArray *fgTracks;
static TH1F *fgHist;
public:
Event();
virtual ~Event();
void Build(Int_t ev, Int_t arg5=600, Float_t ptmin=1);
void Clear(Option_t *option ="");
static void Reset(Option_t *option ="");
void ResetHistogramPointer() {fH=0;}
void SetNseg(Int_t n) { fNseg = n; }
void SetNtrack(Int_t n) { fNtrack = n; }
void SetNvertex(Int_t n) { fNvertex = n; SetRandomVertex(); }
void SetFlag(UInt_t f) { fFlag = f; }
void SetTemperature(Float_t t) { fTemperature = t; }
void SetType(char *type) {strcpy(fType,type);}
void SetHeader(Int_t i, Int_t run, Int_t date, Float_t random);
Track *AddTrack(Float_t random, Float_t ptmin=1);
void SetMeasure(UChar_t which, Int_t what);
void SetMatrix(UChar_t x, UChar_t y, Float_t what) { if (x<3&&y<3) fMatrix[x][y]=what;}
void SetRandomVertex();
Float_t GetClosestDistance(Int_t i) {return fClosestDistance[i];}
char *GetType() {return fType;}
Int_t GetNtrack() const { return fNtrack; }
Int_t GetNseg() const { return fNseg; }
Int_t GetNvertex() const { return fNvertex; }
UInt_t GetFlag() const { return fFlag; }
Float_t GetTemperature() const { return fTemperature; }
EventHeader *GetHeader() { return &fEvtHdr; }
TClonesArray *GetTracks() const {return fTracks;}
TRefArray *GetHighPt() const {return fHighPt;}
TRefArray *GetMuons() const {return fMuons;}
Track *GetLastTrack() const {return (Track*)fLastTrack.GetObject();}
TH1F *GetHistogram() const {return fH;}
TH1 *GetWebHistogram() const {return (TH1*)fWebHistogram.GetObject();}
Int_t GetMeasure(UChar_t which) { return (which<10)?fMeasures[which]:0; }
Float_t GetMatrix(UChar_t x, UChar_t y) { return (x<4&&y<4)?fMatrix[x][y]:0; }
ClassDef(Event,1) //Event structure
};
class HistogramManager {
private:
TH1F *fNtrack;
TH1F *fNseg;
TH1F *fTemperature;
TH1F *fPx;
TH1F *fPy;
TH1F *fPz;
TH1F *fRandom;
TH1F *fMass2;
TH1F *fBx;
TH1F *fBy;
TH1F *fMeanCharge;
TH1F *fXfirst;
TH1F *fXlast;
TH1F *fYfirst;
TH1F *fYlast;
TH1F *fZfirst;
TH1F *fZlast;
TH1F *fCharge;
TH1F *fNpoint;
TH1F *fValid;
public:
HistogramManager(TDirectory *dir);
virtual ~HistogramManager();
void Hfill(Event *event);
ClassDef(HistogramManager,1) //Manages all histograms
};
#endif
// @(#)root/test:$Name: $:$Id: Event.cxx,v 1.19 2002/08/20 15:21:42 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];
// Int_t fNtrack;
// Int_t fNseg;
// Int_t fNvertex;
// UInt_t fFlag;
// Float_t fTemperature;
// Int_t fMeasures[10];
// Float_t fMatrix[4][4];
// Float_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;
//
// 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
// Float_t fCharge; //Charge of this track
// Float_t fVertex[3]; //Track vertex position
// Int_t fNpoint; //Number of points for this track
// Short_t fValid; //Validity criterion
//
// 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 std::cout;
using std::endl;
#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;
//______________________________________________________________________________
void EventHeader::Streamer(TBuffer &R__b)
{
cout << "In EventHeader::Streamer " << endl;
if ( R__b.IsReading() ) {
cout << "Buffer is reading " << endl;
UInt_t R__s, R__c;
Version_t R__v = R__b.ReadVersion(&R__s,&R__c);
cout << "Version "<< R__v << endl;
if ( R__v > 1 ) {
EventHeader::Class()->ReadBuffer(R__b,this,R__v,R__s,R__c);
return;
}
cout << "Processing old version " << endl;
// process old versions pre-RunHeader base class
R__b >> fEvtNum;
R__b >> fRun;
R__b >> fDate;
R__b.CheckByteCount(R__s,R__c,EventHeader::IsA());
// end of old versions
} else {
EventHeader::Class()->WriteBuffer(R__b,this);
}
}
//______________________________________________________________________________
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.
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;
fClosestDistance = 0;
fEventName = 0;
fWebHistogram.SetAction(this);
}
//______________________________________________________________________________
Event::~Event()
{
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));
}
}
// 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 Float_t[fNvertex];
for (Int_t k = 0; k < fNvertex; k++ ) {
fClosestDistance[k] = gRandom->Gaus(1,1);
}
}
//______________________________________________________________________________
Track::Track(Float_t random) : TObject()
{
// 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 = Float_t(Int_t(3*gRandom->Rndm(1)) - 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 Float_t[fNsp];
for(int i=0; i<fNsp; i++) {
fPointValue[i] = i+1;
}
} else {
fPointValue = 0;
}
fValid = Int_t(0.6+gRandom->Rndm(1));
}
//______________________________________________________________________________
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());
}
}
#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class RunHeader+;
#pragma link C++ class EventHeader-;
#pragma link C++ class Event+;
#pragma link C++ class HistogramManager+;
#pragma link C++ class Track+;
#endif
This archive was generated by hypermail 2b29 : Sat Jan 04 2003 - 23:51:20 MET