diff --git a/eic_data.yaml b/eic_data.yaml
index b7f246b83c6fbfb741daf0c8656cc186f02ffbfc..2f9cc5ac889d765cac8cc3b17349bb5e27bd6861 100644
--- a/eic_data.yaml
+++ b/eic_data.yaml
@@ -24,33 +24,25 @@ options :
 
 components:
 
-  ## simple numerical index, but with good automatic default values
-  eic::Index:
-    Members:
-      - int32_t value
-    ExtraCode:
-      declaration: "
-        Index() : value{-1} {}\n
-        Index(int32_t idx) : value {idx} {}\n
-        Index& operator=(int32_t idx) {value = idx; return *this;}\n
-        operator int32_t() const {return value;}\n
-        bool valid() const {return value >= 0;}\n
-        bool empty() const {return value < 0;}\n
-      "
-
-  ## Relation to another field. Has 2 components: source and ID where
+  ## Unique field identifier. Has 2 components: source and ID where
   ## source identifies the originating collection (or algorithm) and ID 
   ## the ID of the entry within this collection. 
-  eic::Relation:
+  ## Defaults to -1 for an unset index.
+  eic::Index:
     Members:
+      - int32_t    value
       - int32_t    source
-      - eic::Index ID
     ExtraCode:
       declaration: "
-        Relation() = default;\n
-        Relation(Index src, Index id) : source{src}, ID{id} {}\n
-        bool valid() const {return ID.valid();}\n
-        bool empty() const {return !valid();}\n
+        Index() : source{0}, value{-1} {}\n
+        Index(int32_t id, int32_t src) : value{id}, source{src} {}\n
+        Index(Index rhs, int32_t new_src) : Index(rhs.value, new_src) {} \n
+        bool empty() const {return value < 0;}\n
+        bool valid() const {return value >= 0 && source != 0;}\n
+        bool equals(const eic::Index& rhs) const {return rhs.source == source && rhs.value == value;}\n
+        bool operator==(const eic::Index& rhs) const {return equals(rhs);}\n
+        bool operator!=(const eic::Index& rhs) const {return !equals(rhs);}\n
+        explicit operator bool() const {return valid();}
       "
 
   ## simple weight that defaults to 1 if not set
@@ -276,7 +268,6 @@ datatypes:
       - int32_t           pid               // particle PDG code
       - int16_t           status            // Status code
       - int16_t           charge            // Particle charge (or sign)
-      - int32_t           source            // std::hash of producing algorithm name
       - eic::Weight       weight            // Particle weight, e.g. from PID algorithm [0-1]
 
   eic::ReconstructedParticle:
@@ -290,7 +281,6 @@ datatypes:
       - int32_t           pid               // PID of reconstructed particle.
       - int16_t           status            // Status code
       - int16_t           charge            // Particle charge (or sign)
-      - int32_t           source            // std::hash of producing algorithm name
       - eic::Weight       weight            // Particle weight, e.g. from PID algorithm [0-1]
       - eic::Direction    direction         // Direction (theta/phi of this particle [mrad])
       - float             momentum          // particle 3-momentum magnitude [GeV]
@@ -302,12 +292,13 @@ datatypes:
     Author: "S. Joosten"
     Members:
       - eic::Index        recID             // ReconstructedParticle index
-      - eic::Relation     vertex            // Start vertex for this particle
-      - eic::Relation     track             // Index of the associated track, if any
-      - eic::Relation     ecal              // Index of associated pos/barrel/neg ECAL cluster, if any
-      - eic::Relation     hcal              // Index of associated pos/barrel/neg HCAL cluster, if any
-      - eic::Relation     cher              // Index of associated pos/barrel/neg Cherenkov info, if any
-      - eic::Relation     tof               // Index of the associated TOF info, if any
+      - eic::Index        vertexID          // Start vertex for this particle
+      - eic::Index        trackID           // Index of the associated track, if any
+      - eic::Index        ecalID            // Index of associated pos/barrel/neg ECAL cluster, if any
+      - eic::Index        hcalID            // Index of associated pos/barrel/neg HCAL cluster, if any
+      - eic::Index        cherID            // Index of associated pos/barrel/neg Cherenkov info, if any
+      - eic::Index        tofID             // Index of the associated TOF info, if any
+      - eic::Index        mcID              // Index of the associated MC particle, if any
 
   ## ==========================================================================
   ## Calorimetry
@@ -316,20 +307,19 @@ datatypes:
     Description: "Raw (digitized) calorimeter hit"
     Author: "W. Armstrong, S. Joosten"
     Members:
+      - eic::Index        ID                // unique ID for this hit
       - int64_t           cellID            // The detector specific (geometrical) cell id.
       - int64_t           amplitude         // The amplitude of the hit in ADC counts.
       - int64_t           time              // Timing in TDC
-      - eic::Index        ID                // unique ID for this hit
 
   eic::CalorimeterHit:
     Description: "Calorimeter hit"
     Author: "W. Armstrong, S. Joosten"
     Members:
-      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - eic::Index        ID                // unique ID for this hit
+      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - int32_t           layer             // layer for this hit
       - int32_t           sector            // sector for this hit
-      - int32_t           source            // std::hash of producing algorithm name
       - float             energy            // The energy for this hit in [GeV].
       - float             energyError       // Error on energy [GeV].
       - float             time              // The time of the hit in [ns].
@@ -348,14 +338,13 @@ datatypes:
     Members:
       - eic::Index        hitID             // Hit ID
       - eic::Index        clusterID         // ID of the cluster associated with this hit (-1 if none)
-      - float             weight            // How much of this hit belongs to the cluster? [0->1]
+      - eic::Weight       weight            // How much of this hit belongs to the cluster? [0->1]
 
   eic::Cluster:
     Description: "EIC cluster"
     Author: "W. Armstrong, S. Joosten, C.Peng"
     Members:
       - eic::Index        ID                // unique ID for this cluster
-      - int32_t           source            // std::hash of producing algorithm name
       - float             energy            // Reconstructed energy of the cluster [GeV].
       - float             energyError       // Error on the cluster energy [GeV]
       - float             time              // [ns]
@@ -390,7 +379,6 @@ datatypes:
       - eic::Index        clusterID         // associated full 3D cluster, -1 if none
       - int32_t           layer             // layer number for this cluster layer
       - uint32_t          nhits             // Number of hits
-      - int32_t           source            // std::hash of producing algorithm name
       - float             energy            // Energy in this cluster layer [GeV]
       - float             energyError       // Error on energy [GeV]
       - float             radius            // Shower radius [mm]
@@ -403,7 +391,7 @@ datatypes:
     Members:
       - eic::Index        clusterID         // associated cluster ID
       - uint32_t          size              // number of valid parents
-      - std::array<eic::Relation, 4> parent // (up to 4) parents for this cluster
+      - std::array<eic::Index, 4> parent    // (up to 4) parents for this cluster
 
   ## ==========================================================================
   ## RICH/Cherenkov data structures
@@ -413,8 +401,8 @@ datatypes:
     Description: "EIC Raw PMT hit"
     Author: "S. Joosten, C. Peng"
     Members:
-      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - eic::Index        ID                // unique hit ID
+      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - uint32_t          amplitude         // PMT signal amplitude [ADC]
       - uint32_t          time              // PMT signal time [TDC]
 
@@ -422,9 +410,8 @@ datatypes:
     Description: "EIC PMT hit"
     Author: "S. Joosten, C. Peng"
     Members:
-      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - eic::Index        ID                // Unique hit ID
-      - int32_t           source            // std::hash of producing algorithm name
+      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - float             npe               // estimated number of photo-electrons [#]
       - float             time              // Time [ns]
       - float             timeError         // Error on the time [ns]
@@ -437,7 +424,6 @@ datatypes:
     Author: "S. Joosten, C. Peng"
     Members:
       - eic::Index        ID                // Unique cluster ID
-      - int32_t           source            // std::hash of producing algorithm name
       - float             npe               // number of photo-electrons [#]
       - eic::VectorXYZ    position          // Global position of the cluster [mm]
       - eic::VectorXYZ    positionError     // Error on the position
@@ -454,8 +440,8 @@ datatypes:
     Description: "Raw (digitized) tracker hit"
     Author: "W. Armstrong, S. Joosten"
     Members:
-      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - eic::Index        ID                // unique ID for this hit
+      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - int32_t           time              // tdc value.
       - int32_t           charge            // adc value
 
@@ -463,11 +449,10 @@ datatypes:
     Description: "Tracker hit (reconstructed from Raw)"
     Author: "W. Armstrong, S. Joosten"
     Members:
-      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - eic::Index        ID                // unique ID for this hit
+      - int64_t           cellID            // The detector specific (geometrical) cell id.
       - eic::VectorXYZT   position          // Hit (cell) position and time [mm, ns]
       - eic::CovDiagXYZT  covMatrix         // Covariance Matrix
-      - int32_t           source            // std::hash of producing algorithm name
       - float             edep              // Energy deposit in this hit [GeV]
       - float             edepError         // Error on the energy deposit [GeV]
     ConstExtraCode:
@@ -510,7 +495,6 @@ datatypes:
     Members:
       - eic::Index        ID                // unique vertex ID
       - eic::VectorXYZ    position          // postion of vertex [mm]
-      - int32_t           source            // std::hash of producing algorithm name
       - float             time              // time of vertex [ns]
       - float             chi2              // Chi squared of the vertex fit.
       - float             probability       // Probability of the vertex fit