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