Revised EDM Model Notes
                                03-08 March 1999
                                   Rob Kennedy



I)   Prototype Scale-up plans
II)  Miscellaneous
III) ToyModel description
IV)  Review of existing use-cases
V)   StorableObject

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

I) The design and implementation of the new Event Data Model will proceed in at
least three incremental stages

	1) ToyModel - Quicky implementation of bare bones EDM infrastructure to
test ideas and use-cases in the EDM proposal. Toy implementations of a few
higher-level physics objects, collections, and non-physics objects are used to
demonstrate use-cases. Actual I/O is primitive, if at all.

	Completion due 01 April 1999. This date is firm, as proposal should be
"delivered" before this date.

	2) Prototype - More realistic implementation of EDM infrastructure,
uses a few realistic (near-release-form) higher-level physics objects and
associated collections, and uses an initial implementation of I/O using ROOT.
Integration with Framework/AC++ begins after this.

	Completion due 01 May 1999. This date is arbitrarily chosen.

	3) Release - Robust implementation of all of EDM infrastructure, uses a
variety of released higher-level physics objects and associated collections, and
uses a robust implementation of I/O using ROOT and ROOT branches. Integration
with Framework is completed.

	Completion due 01 June 1999. This date is firm, as it coincides with the
June Milestone.


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

II) Miscellaneous

A) ObjectNumbers are unique across all ObjectNames. This is a change from what
has been presented (where ObjectNumbers were unique only for a particular
ObjectName). The altered approach will be easier to implement, yields space
savings. Is there a backward-compatibility problem as was feared?

B) EDM calls setLinks() inside of File::write(), setPointers() inside of
File::read(). The user does not have to do anything by default.

	In a change from the presentation Wednesday on the EDM, several of us
have agreed to consider having the setPointers() and setLinks() methods to
manage StorablePointers called by the EDM on all objects in the EventRecord 
automatically as a part of writing an event out or reading it back in. Users 
would not have to call these methods at all. SetPointers would be called in 
File::read(). IMHO, we should not call setLinks() in EventRecord::insert() 
since then the user would have to get the order of insert() calls for 
associated objects correct. So, we call setLinks() in File::write().

	A consequence of this is that mutually associated objects can be
managed without a separate association object having to be stored. In other
words, cyclic link chains can be stored in place if we call setLinks() in 
File::write() and setPointers() in File::read(). This loosens the constraint 
that all objects be read-only in a very specific way... StorablePointers keep 
their logical state, but change in their physical state during read() and 
write() to/from a transient format and a storable format.

	Every StorableObject object would have to have a setLinks() and a 
setPointers() method even if it does not contain a StorablePointer. This 
permits the EDM to iterate through all objects in the EventRecord, setting 
links or restoring transient pointers. If an object is dropped from an event 
(due to an I/O list drop), associations to it will still be set (setLinks() is 
called before I/O module drops objects) in order to keep the maximum internal 
consistency.

	Users may still prefer to use separate AssociationSummary objects to
store complicated associations separate from other StorableObject's data, but
that is a choice now, rather than a requirement of the model.

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

III) ToyModel description

A) Goal

	The goal of the ToyModel stage is to demonstrate the use-cases listed
in the EDM proposal and explore possible variants in design and implementation
that may come from discussions on the EDM. Implementation terminology (class
names, methods) as well as the EDM itself are somewhat frozen after this stage
is completed. The ToyModel does *not* fully implement the final EDM, only those
pieces necessary to demonstrate the basics in the proposal are valid.

B) Classes to implement

Round 1

	 1) StorableObject
	 2) ObjectName
	 3) ObjectNumber
	 4) ObjectId
	 5) StorableCollection
	 6) StorableRefCollection
	 7) StorableRefList
	 8) EventRecordId
	 9) EventRecordInternals
	10) ObjectNumberManager (used by EventRecord)
	11) EventRecord
	12) StorablePointer
	13) ObjectHandle
	14) ToyTrack

This is enough to create an event (header + tracks), store it, restore it, and
testing ObjectNumber policy as it applies to the EventRecordInternals object
itself.

Round 2


	1) ToyMuon
	2) ToyMuonList
	3) ToyTrackList
	4) ToyBrother
	5) ToySister
	6) AssociationSummary

This will test storing and retrieving storable objects, unidirectional
associations, homogeneous collection support, cyclic association chains, and
heterogenous collection support.

Round 3

	?) I/O List classes
	?) Primitive ROOT I/O

This will test I/O filtering ideas and ROOT I/O ideas.


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

IV)

TotalMissingE is a class derived from StorableObject which has no associations.

// Create and Store a StorableObject
// =================================
bool event_AAA(EventRecord* p_event)
{
  float E_mag = 0.0 ;
  float E_eta = 0.0 ;
  float E_phi = 0.0 ;

  ObjectHandle<TotalMissingE> myMissECalc = new TotalMissingE(E_mag, E_eta, E_phi) ;

// Note: Add an argument identifying *who* created this StorableObject
// Note: Add an argument identifying *what* were parameters used

  StorableLink myMissEID = p_record->insert(myMissECalc) ;
  if (myMissEID.is_invalid()) { /* ERROR: */ }

  return(true) ;
}

// Retrieve a StorableObject
// =================================
bool event_BBB(EventRecord* p_event)
{
  RecordIterator otherIter(p_record, SelectByName("TotalMissingE") ) ;
  if otherIter.is_invalid()) { /* ERROR: object is not in event */ }

  ObjectHandle<TotalMissingE> otherMissECalc(myIter) ; // OBJECT MARKED AS READ-ONLY
  if (otherMissECalc.is_invalid()) { /* ERROR: failure in constructor */ }

  float E_mag = otherMissECalc->e_mag() ;
  float E_eta = otherMissECalc->e_eta() ;
  float E_phi = otherMissECalc->e_phi() ;

  otherMissECalc.set_et_mag(9.0) ; // ERROR: object is read-only

  return(true) ;
}

// Update a StorableObject
// =================================
bool event_BBB(EventRecord* p_event)
{
  RecordIterator otherIter(p_record, SelectByName("TotalMissingE") ) ;
  if otherIter.is_invalid()) { /* ERROR: object is not in event */ }

  ObjectHandle<TotalMissingE> otherMissECalc(myIter) ; // OBJECT MARKED AS READ-ONLY
  if (otherMissECalc.is_invalid()) { /* ERROR: failure in constructor */ }

  ObjectHandle<TotalMissingE> otherMissECalc = new TotalMissingE(otherMissECalc) ;

// Note: Add an argument identifying *who* created this StorableObject
// Note: Add an argument identifying *what* were parameters used

  myMissECalc->set_e_mag(9.0) ;
  myMissECalc->set_e_eta(1.0) ;
  myMissECalc->set_e_phi(3.0) ;

  ObjectId myMissEID = p_record->insert(myMissECalc) ; // myMissEID != otherMissEID
  if (myMissEID.is_invalid()) { /* ERROR: insert failed */ }

  return(true) ;
}

// Delete a StorableObject
// =================================
// Only AC++ actually deletes objects. A user can add a particular object or
// a class of objects to a ``drop on output'' object list.


Muon is associated with a Track expressed as a StorablePointer. Both Track and
Muon derive from StorableObject.

i) Create and Store

  ObjectHandle<Track> = new Track(...) ;
  ObjectHandle<Muon>  = new Muon(&aTrack) ;

  ObjectId trackId = p_record->insert(aTrack) ;
  ObjectId muonId  = p_record->insert(aMuon) ;

// setLinks() is called in File::write().

ii) retrieve

// setPointers() is called in File::read().

  RecordIterator muonIter(p_record, SelectByName("Muon") ) ;
  ObjectHandle<Muon> aMuon(muonIter) ;         // OBJECT MARKED AS READ-ONLY
  ObjectHandle<Track> aTrack(aMuon->track()) ; // OBJECT MARKED AS READ-ONLY
  double muon_pt = aMuon->pt() ;


i) Create and Store

  ObjectHandle<Brother> = new Brother(...) ;       // NULL link to sister
  ObjectHandle<Sister>  = new Sister(&aBrother) ;
  aBrother.setPointer(&aSister) ; // state now fully defined

  ObjectId brotherId = p_record->insert(aBrother) ;
  ObjectId sisterId  = p_record->insert(aSister) ;

// If setLinks() is called in File::write(), Bi-directional links now supported.

ii) Retrieve

// setPointers() is called in File::read().

  ObjectId brotherId = relationship.brotherId() ;
  RecordIterator brotherIter(p_record, SelectById(brotherId) ) ;

  ObjectHandle<Brother> aBrother(brotherIter) ;       // READ-ONLY
  ObjectHandle<Sister>  aSister(aBrother->sister()) ; // READ-ONLY


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

V) These are first drafts for the ToyModel. JBK has an alternative means of
forcing the inheritance tree onto the heap.

class StorableObject: virtual public MemoryPool
{
  public:

  StorableObject(void) ;
  StorableObject(const StorableObject& object) ;
  StorableObject& operator=(const StorableObject& object) ;
  friend bool operator==(const StorableObject& object1,
                         const StorableObject& object2) ;
  friend bool operator!=(const StorableObject& object1,
                         const StorableObject& object2) ;

  virtual ObjectId     id(void) const ;
  virtual ObjectName   name(void) const ;
  virtual ObjectNumber number(void) const ;
  virtual bool is_stored(void) const ; // == (_number != ObjectNumber::Null)
  virtual bool is_valid(void) const ;
  virtual void print(void) const ;

  virtual bool set_links(void) = 0 ;
  virtual bool set_pointers(void) = 0 ;

  virtual bool stream_read(STREAM& stream) = 0 ;  // STREAM == ?TBuffer?
  virtual bool stream_write(STREAM& stream) = 0 ; // STREAM == ?TBuffer?
  virtual bool is_persistable(void) const { return(false) ; }

  protected:

  ObjectNumber _number ;
  bool         _is_read_only ;

  void set_object_number(const ObjectNumber& number) ; // EventRecord::insert()
  void set_read_only(void) ;                           // EventRecord::insert()

  virtual ~StorableObject(void) ; // Can only create via new on the heap
} ;


class ToyTrack: virtual public StorableObject
{
  public:

  ToyTrack(void) ;
  ToyTrack(const ToyTrack& object) ;
  ToyTrack& operator=(const ToyTrack& object) ;
  friend bool operator==(const ToyTrack& object1,
                         const ToyTrack& object2) ;
  friend bool operator!=(const ToyTrack& object1,
                         const ToyTrack& object2) ;


  virtual bool set_links(void) ;
  virtual bool set_pointers(void) ;

  virtual bool stream_read(STREAM& stream) ;
  virtual bool stream_write(STREAM& stream) ;
  virtual bool is_persistable(void) const { return(true) ; }

  SignValue em_charge_sign(void) const ; // == positive, negative, neutral
  float x0(void) const ;
  float y0(void) const ;
  float z0(void) const ;
  float px(void) const ;
  float py(void) const ;
  float pz(void) const ;
  float pt(void) const ;
  float energy(void) const ;

  void set_em_charge_sign(const SignValue value) ;
  void set_x0(const float value) ;
  void set_y0(const float value) ;
  void set_z0(const float value) ;
  void set_px(const float value) ;
  void set_py(const float value) ;
  void set_pz(const float value) ;
  void set_energy(const float value) ;

  protected:

  SignValue _em_charge_sign ;
  float _x0 ;  // SpaceLocation of Intercept
  float _y0 ;
  float _z0 ;
  float _px ;  // FourMomentum
  float _py ;
  float _pz ;
  float _energy ;

  virtual ~ToyTrack(void) ; // Can only create via new on the heap
} ;