diff --git a/JugBase/src/components/MC2DummyParticle.cpp b/JugBase/src/components/MC2DummyParticle.cpp
index e4fd13c94b4a5890e8bd2e03ba9df655f97ccca6..720879c51542ef5423f2d38e461e5a8bb19c18c2 100644
--- a/JugBase/src/components/MC2DummyParticle.cpp
+++ b/JugBase/src/components/MC2DummyParticle.cpp
@@ -12,24 +12,29 @@
 // Event Model related classes
 #include "dd4pod/Geant4ParticleCollection.h"
 #include "eicd/ReconstructedParticleCollection.h"
+#include "eicd/ReconstructedParticleRelationsCollection.h"
 
-namespace Jug {
-  namespace Base {
+namespace Jug::Base {
 
     class MC2DummyParticle : public GaudiAlgorithm, AlgorithmIDMixin<int32_t> {
     public:
       DataHandle<dd4pod::Geant4ParticleCollection> m_inputHitCollection{"mcparticles", Gaudi::DataHandle::Reader, this};
       DataHandle<eic::ReconstructedParticleCollection> m_outputHitCollection{"DummyReconstructedParticles",
                                                                              Gaudi::DataHandle::Writer, this};
+      DataHandle<eic::ReconstructedParticleRelationsCollection> 
+        m_outputRelCollection{"DummyReconstructedParticleRelations", Gaudi::DataHandle::Writer, this};
       Rndm::Numbers                                    m_gaussDist;
       Gaudi::Property<double>                          m_smearing{this, "smearing", 0.01 /* 1 percent*/};
 
+      const int32_t kMonteCarloSource{uniqueID<int32_t>("mcparticles")};
+
       MC2DummyParticle(const std::string& name, ISvcLocator* svcLoc) 
         : GaudiAlgorithm(name, svcLoc)
         , AlgorithmIDMixin(name, info())
       {
         declareProperty("inputCollection", m_inputHitCollection, "mcparticles");
         declareProperty("outputCollection", m_outputHitCollection, "DummyReconstructedParticles");
+        declareProperty("outputRelations", m_outputRelCollection, "DummyReconstructedParticles");
       }
       StatusCode initialize() override
       {
@@ -49,6 +54,7 @@ namespace Jug {
         const dd4pod::Geant4ParticleCollection* parts = m_inputHitCollection.get();
         // output collection
         auto out_parts = m_outputHitCollection.createAndPut();
+        auto relations = m_outputRelCollection.createAndPut();
         int ID = 0;
         for (const auto& p : *parts) {
           if (p.genStatus() != 1) {
@@ -72,14 +78,13 @@ namespace Jug {
           eic::VectorXYZ psmear{px, py, pz};
 
           eic::ReconstructedParticle rec_part{
-            ID++,                             // Unique index
+            {ID++, algorithmID()},            // Unique index
             psmear,                           // 3-momentum [GeV]
             {vx, vy, vz},                     // Vertex [mm]
             static_cast<float>(p.time()),     // time [ns]
             p.pdgID(),                        // PDG type
             static_cast<int16_t>(p.status()), // Status
             static_cast<int16_t>(p.charge()), // Charge
-            algorithmID(),                    // Algorithm type
             1.,                               // particle weight
             {psmear.theta(), psmear.phi()},   // direction
             momentum,                         // 3-momentum magnitude [GeV]
@@ -87,6 +92,10 @@ namespace Jug {
             static_cast<float>(p.mass())};    // mass [GeV]
 
           out_parts->push_back(rec_part);
+
+          eic::ReconstructedParticleRelations rel;
+          rel.mcID({p.ID(), kMonteCarloSource});
+          relations->push_back(rel);
         }
         return StatusCode::SUCCESS;
       }
@@ -94,6 +103,5 @@ namespace Jug {
 
     DECLARE_COMPONENT(MC2DummyParticle)
 
-  } // namespace Base
-} // namespace Jug
+} // namespace Jug::Base
 
diff --git a/JugDigi/src/components/CalorimeterHitDigi.cpp b/JugDigi/src/components/CalorimeterHitDigi.cpp
index fc820768283e9d3df250b9e8fe8db00148a787b2..61562a51ebe94a24e4e26f1bb7719c3b6d958163 100644
--- a/JugDigi/src/components/CalorimeterHitDigi.cpp
+++ b/JugDigi/src/components/CalorimeterHitDigi.cpp
@@ -15,14 +15,15 @@
 #include "Gaudi/Property.h"
 #include "GaudiKernel/RndmGenerators.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "dd4pod/CalorimeterHitCollection.h"
 #include "eicd/RawCalorimeterHitCollection.h"
 #include "eicd/RawCalorimeterHitData.h"
 
+
 using namespace Gaudi::Units;
 
 namespace Jug::Digi {
@@ -32,7 +33,7 @@ namespace Jug::Digi {
    * \ingroup digi
    * \ingroup calorimetry
    */
-  class CalorimeterHitDigi : public GaudiAlgorithm {
+  class CalorimeterHitDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
   public:
     // additional smearing resolutions
     Gaudi::Property<std::vector<double>> u_eRes{this, "energyResolutions", {}}; // a/sqrt(E/GeV) + b + c/(E/GeV)
@@ -53,7 +54,9 @@ namespace Jug::Digi {
     double dyRangeADC, tRes, eRes[3] = {0., 0., 0.};
 
     //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
-    CalorimeterHitDigi(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
+    CalorimeterHitDigi(const std::string& name, ISvcLocator* svcLoc) 
+      : GaudiAlgorithm(name, svcLoc)
+      , AlgorithmIDMixin{name, info()}
     {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
       declareProperty("outputHitCollection", m_outputHitCollection, "");
@@ -97,10 +100,11 @@ namespace Jug::Digi {
         double                 ped     = m_pedMeanADC + m_normDist() * m_pedSigmaADC;
         long long              adc = std::llround(ped + ahit.energyDeposit() * (1. + eResRel) / dyRangeADC * m_capADC);
         eic::RawCalorimeterHit rawhit(
+            {nhits++, algorithmID()},
             (long long)ahit.cellID(), 
             (adc > m_capADC.value() ? m_capADC.value() : adc),
-            static_cast<int64_t>(1e6*(double)ahit.truth().time + m_normDist() * tRes), // @FIXME: this shouldn't be hardcoded, but should still be stored as an integer type
-            nhits++);
+            static_cast<int64_t>(1e6*(double)ahit.truth().time + m_normDist() * tRes) // @FIXME: this shouldn't be hardcoded, but should still be stored as an integer type
+            );
         rawhits->push_back(rawhit);
       }
       return StatusCode::SUCCESS;
diff --git a/JugDigi/src/components/CrystalEndcapsDigi.cpp b/JugDigi/src/components/CrystalEndcapsDigi.cpp
index 9f3abfe09fbf81e21072d07ac7c75d463094a7c7..1a9dcb0b851f42ca7974990efe83372a0f175a22 100644
--- a/JugDigi/src/components/CrystalEndcapsDigi.cpp
+++ b/JugDigi/src/components/CrystalEndcapsDigi.cpp
@@ -7,8 +7,8 @@
 #include "Gaudi/Property.h"
 #include "GaudiKernel/PhysicalConstants.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "eicd/RawCalorimeterHitCollection.h"
@@ -22,7 +22,7 @@ namespace Jug {
      *
      * \ingroup digi
      */
-   class CrystalEndcapsDigi : public GaudiAlgorithm {
+   class CrystalEndcapsDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
    public:
 
     Gaudi::Property<double>      m_energyResolution{this, "energyResolution", 0.02};  // 2%sqrt(E)
@@ -32,7 +32,8 @@ namespace Jug {
 
     //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
     CrystalEndcapsDigi(const std::string& name, ISvcLocator* svcLoc)
-        : GaudiAlgorithm(name, svcLoc) {
+        : GaudiAlgorithm(name, svcLoc) 
+        , AlgorithmIDMixin(name, info()) {
       declareProperty("inputHitCollection", m_inputHitCollection,"");
       declareProperty("outputHitCollection", m_outputHitCollection, "");
     }
@@ -61,9 +62,10 @@ namespace Jug {
       for (const auto& ahit : *simhits) {
         double res = m_gaussDist()/sqrt(ahit.energyDeposit());
         eic::RawCalorimeterHit rawhit(
+          {nhits++, algorithmID()},
           (long long) ahit.cellID(),
           std::llround(ahit.energyDeposit() * (1. + res)*1.0e6), // convert to keV integer
-          (double) ahit.truth().time, nhits++);
+          (double) ahit.truth().time);
         rawhits->push_back(rawhit);
       }
       return StatusCode::SUCCESS;
diff --git a/JugDigi/src/components/EMCalorimeterDigi.cpp b/JugDigi/src/components/EMCalorimeterDigi.cpp
index 0be573682c6c62b8c056ef5db9a2ff2867e94154..10257d6c1d51d8031731af7ec09c43a71ab7aca7 100644
--- a/JugDigi/src/components/EMCalorimeterDigi.cpp
+++ b/JugDigi/src/components/EMCalorimeterDigi.cpp
@@ -7,8 +7,8 @@
 #include "GaudiKernel/RndmGenerators.h"
 #include "Gaudi/Property.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "eicd/RawCalorimeterHitCollection.h"
@@ -22,7 +22,7 @@ namespace Jug {
      *
      * \ingroup digi
      */
-    class EMCalorimeterDigi : public GaudiAlgorithm {
+    class EMCalorimeterDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
     public:
       using SimHit = dd4pod::CalorimeterHitCollection;
       using RawHit = eic::RawCalorimeterHitCollection;
@@ -32,7 +32,9 @@ namespace Jug {
       Gaudi::Property<double> m_energyResolution{this, "energyResolution", 0.05 /* 5 percent*/};
       Rndm::Numbers           m_gaussDist;
 
-      EMCalorimeterDigi(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
+      EMCalorimeterDigi(const std::string& name, ISvcLocator* svcLoc) 
+        : GaudiAlgorithm(name, svcLoc)
+        , AlgorithmIDMixin(name, info())
       {
         declareProperty("inputHitCollection", m_inputHitCollection, "");
         declareProperty("outputHitCollection", m_outputHitCollection, "");
@@ -62,9 +64,10 @@ namespace Jug {
           // std::cout << ahit << "\n";
           double sqrtE = std::sqrt(ahit.energyDeposit()) ;
           double aterm = m_gaussDist()*sqrtE;
-          eic::RawCalorimeterHit rawhit((long long)ahit.cellID(),
+          eic::RawCalorimeterHit rawhit({nhits++, algorithmID()}, 
+                                        (long long)ahit.cellID(),
                                         std::llround((ahit.energyDeposit() + aterm) * 1e6),
-                                        ahit.truth().time * 1e6, nhits++);
+                                        ahit.truth().time * 1e6);
           rawhits->push_back(rawhit);
         }
         return StatusCode::SUCCESS;
diff --git a/JugDigi/src/components/EcalTungstenSamplingDigi.cpp b/JugDigi/src/components/EcalTungstenSamplingDigi.cpp
index a8046c3f560749b17bc5c9162a7dd536c32d844c..d0c5ed08e7451ae7e6d3b6908a4b1562bfbebfa6 100644
--- a/JugDigi/src/components/EcalTungstenSamplingDigi.cpp
+++ b/JugDigi/src/components/EcalTungstenSamplingDigi.cpp
@@ -8,8 +8,8 @@
 #include "Gaudi/Property.h"
 #include "GaudiKernel/RndmGenerators.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "dd4pod/CalorimeterHitCollection.h"
@@ -25,7 +25,7 @@ namespace Jug {
      *
      * \ingroup digi
      */
-    class EcalTungstenSamplingDigi : public GaudiAlgorithm {
+    class EcalTungstenSamplingDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
     public:
       Gaudi::Property<double>                      m_eRes{this, "energyResolution", 0.11}; // a%/sqrt(E/GeV)
       Gaudi::Property<std::vector<double>>         u_eRes{this, "energyResolutions", {}}; // a%/sqrt(E/GeV) + b% + c%/E
@@ -44,7 +44,9 @@ namespace Jug {
       double res[3] = {0., 0., 0.};
 
       //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
-      EcalTungstenSamplingDigi(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
+      EcalTungstenSamplingDigi(const std::string& name, ISvcLocator* svcLoc) 
+        : GaudiAlgorithm(name, svcLoc)
+        , AlgorithmIDMixin(name, info())
       {
         declareProperty("inputHitCollection", m_inputHitCollection, "");
         declareProperty("outputHitCollection", m_outputHitCollection, "");
@@ -86,10 +88,10 @@ namespace Jug {
           double ped = m_pedMeanADC + m_normDist()*m_pedSigmaADC;
           long long adc = std::llround(ped + ahit.energyDeposit()*(1. + resval) * m_eUnit/m_dyRangeADC*m_capADC);
           eic::RawCalorimeterHit rawhit(
+              {nhits++, algorithmID()},
               (long long)ahit.cellID(),
               (adc > m_capADC ? m_capADC.value() : adc),
-              (double)ahit.truth().time*m_tUnit/ns + m_normDist()*m_tRes/ns,
-              nhits++);
+              (double)ahit.truth().time*m_tUnit/ns + m_normDist()*m_tRes/ns);
           rawhits->push_back(rawhit);
         }
         return StatusCode::SUCCESS;
diff --git a/JugDigi/src/components/ExampleCaloDigi.cpp b/JugDigi/src/components/ExampleCaloDigi.cpp
index 4152034a24e381f12f690b5f5e2974e5777f05c0..39281ec9a64db3286b7ebad750ebb6dea784a88c 100644
--- a/JugDigi/src/components/ExampleCaloDigi.cpp
+++ b/JugDigi/src/components/ExampleCaloDigi.cpp
@@ -5,8 +5,8 @@
 #include "GaudiAlg/Producer.h"
 #include "GaudiAlg/GaudiTool.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 //#include "GaudiExamples/MyTrack.h"
@@ -17,85 +17,11 @@
 namespace Jug {
   namespace Digi {
 
-  //using BaseClass_t = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>;
-
-  ///** Do not use this as an example!!!
-  // * This is for testing purposes only.
-  // */
-  //struct ExampleCaloDigiFunc final
-  //    : Gaudi::Functional::Producer<std::vector<eic::RawCalorimeterHitData>(const dd4pod::CalorimeterHitCollection&),
-  //                                  BaseClass_t> {
-
-  //  ExampleCaloDigiFunc(const std::string& name, ISvcLocator* pSvc)
-  //      : Transformer(name, pSvc, KeyValue("InputData", {"FAEC_ShHits"})},
-  //                 KeyValue("OutputData", {"ForwardPreshowerHits"})) {
-  //    declareProperty("InputData", m_inputHitCollection, "FAEC_ShHits");
-  //  }
-  //  StatusCode initialize() override {
-  //    if (Gaudi::Functional::Transformer<std::vector<eic::RawCalorimeterHitData>(const dd4pod::CalorimeterHitCollection&),
-  //                                    BaseClass_t>::initialize()
-  //            .isFailure())
-  //      return StatusCode::FAILURE;
-  //    // f_counter = m_starting_value.value();
-  //    return StatusCode::SUCCESS;
-  //  }
-
-  //  std::vector<eic::RawCalorimeterHitData> operator()(const dd4pod::CalorimeterHitCollection& in_hits) const override {
-  //    //const dd4pod::CalorimeterHitCollection* in_hits =
-  //    //    m_inputHitCollection.get();
-  //    std::vector<eic::RawCalorimeterHitData> out_hits;
-  //    for (auto i = in_hits.begin(), end = in_hits.end(); i != end; ++i) {
-  //      out_hits.push_back(eic::RawCalorimeterHitData{
-  //          (long long)i->cellID(), (long long)i->cellID(),
-  //          (long long)i->energyDeposit() * 100, 0});
-  //    }
-  //    return out_hits;
-  //  }
-  //};
-  //DECLARE_COMPONENT(ExampleCaloDigiFunc)
-
-  ///** Do not use this as an example!!!
-  // * This is for testing purposes only.
-  // */
-  //struct ExampleCaloDigiFunc2 final
-  //    : Gaudi::Functional::Producer<std::vector<eic::RawCalorimeterHitData>(),
-  //                                  BaseClass_t> {
-
-  //  ExampleCaloDigiFunc2(const std::string& name, ISvcLocator* pSvc)
-  //      : Producer(name, pSvc, //,//KeyValue("InputData", {"FAEC_ShHits"})},
-  //                 KeyValue("OutputData", {"ForwardPreshowerHits"})) {
-  //    declareProperty("InputData", m_inputHitCollection, "FAEC_ShHits");
-  //  }
-  //  StatusCode initialize() override {
-  //    if (Gaudi::Functional::Producer<std::vector<eic::RawCalorimeterHitData>(),
-  //                                    BaseClass_t>::initialize()
-  //            .isFailure())
-  //      return StatusCode::FAILURE;
-  //    // f_counter = m_starting_value.value();
-  //    return StatusCode::SUCCESS;
-  //  }
-
-  //  std::vector<eic::RawCalorimeterHitData> operator()() const override {
-  //    const dd4pod::CalorimeterHitCollection* in_hits =
-  //        m_inputHitCollection.get();
-  //    std::vector<eic::RawCalorimeterHitData> out_hits;
-  //    for (auto i = in_hits->begin(), end = in_hits->end(); i != end; ++i) {
-  //      out_hits.push_back(eic::RawCalorimeterHitData{
-  //          (long long)i->cellID(), (long long)i->cellID(),
-  //          (long long)i->energyDeposit() * 100, 0});
-  //    }
-  //    return out_hits;
-  //  }
-  //  mutable DataHandle<dd4pod::CalorimeterHitCollection> m_inputHitCollection{
-  //      "inputHitCollection", Gaudi::DataHandle::Reader, this};
-  //};
-  //DECLARE_COMPONENT(ExampleCaloDigiFunc2)
-  
-   class ExampleCaloDigi : public GaudiAlgorithm {
+   class ExampleCaloDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
    public:
     //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
     ExampleCaloDigi(const std::string& name, ISvcLocator* svcLoc)
-        : GaudiAlgorithm(name, svcLoc) {
+        : GaudiAlgorithm(name, svcLoc), AlgorithmIDMixin(name, info()) {
           declareProperty("inputHitCollection", m_inputHitCollection,"");
           declareProperty("outputHitCollection", m_outputHitCollection, "");
         }
@@ -113,7 +39,7 @@ namespace Jug {
       int nhits = 0;
       for(const auto& ahit : *simhits) {
         //std::cout << ahit << "\n";
-        eic::RawCalorimeterHit rawhit((long long)ahit.cellID(), std::llround(ahit.energyDeposit() * 100), 0, nhits++);
+        eic::RawCalorimeterHit rawhit({nhits++, algorithmID()}, (long long)ahit.cellID(), std::llround(ahit.energyDeposit() * 100), 0);
         rawhits->push_back(rawhit);
       }
       return StatusCode::SUCCESS;
diff --git a/JugDigi/src/components/HadronicCalDigi.cpp b/JugDigi/src/components/HadronicCalDigi.cpp
index a11a2ac95ef878d95450a6a9cf77125c462a6bc5..6d12de12454f96d513745516587d1c3a304ea6b9 100644
--- a/JugDigi/src/components/HadronicCalDigi.cpp
+++ b/JugDigi/src/components/HadronicCalDigi.cpp
@@ -7,8 +7,8 @@
 #include "GaudiKernel/RndmGenerators.h"
 #include "Gaudi/Property.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "eicd/RawCalorimeterHitCollection.h"
@@ -30,7 +30,7 @@ namespace Jug {
      *
      * \ingroup digi
      */
-    class HadronicCalDigi : public GaudiAlgorithm {
+    class HadronicCalDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
     public:
       Gaudi::Property<double>                      m_energyResolution_a{this, "energyResolution_a", 0.5 /*50 percent*/};
       Gaudi::Property<double>                      m_energyResolution_b{this, "energyResolution_b", 0.05 /* 5 percent*/};
@@ -42,7 +42,8 @@ namespace Jug {
                                                                          Gaudi::DataHandle::Writer, this};
 
     public:
-      HadronicCalDigi(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc) {
+      HadronicCalDigi(const std::string& name, ISvcLocator* svcLoc)
+          : GaudiAlgorithm(name, svcLoc), AlgorithmIDMixin(name, info()) {
         declareProperty("inputHitCollection", m_inputHitCollection, "");
         declareProperty("outputHitCollection", m_outputHitCollection, "");
       }
@@ -78,8 +79,9 @@ namespace Jug {
           double aterm = m_gaussDist_a()*sqrtE;
           double bterm = ahit.energyDeposit()*m_gaussDist_b();
           // here 1000 is arbitrary scale factor
-          eic::RawCalorimeterHit rawhit((long long)ahit.cellID(),
-                                        std::llround(ahit.energyDeposit() +aterm + bterm * 1000), 0, nhits++);
+          eic::RawCalorimeterHit rawhit({nhits++, algorithmID()}, 
+                                        (long long)ahit.cellID(),
+                                        std::llround(ahit.energyDeposit() +aterm + bterm * 1000), 0);
           rawhits->push_back(rawhit);
         }
         return StatusCode::SUCCESS;
diff --git a/JugDigi/src/components/PhotoMultiplierDigi.cpp b/JugDigi/src/components/PhotoMultiplierDigi.cpp
index 6e1a667287c7af2703ca35a637dcd2de14ae35ae..0a8ce97684ef21e4db6fc256e35db5e88484f85f 100644
--- a/JugDigi/src/components/PhotoMultiplierDigi.cpp
+++ b/JugDigi/src/components/PhotoMultiplierDigi.cpp
@@ -18,6 +18,7 @@
 #include "GaudiKernel/PhysicalConstants.h"
 
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "eicd/RawPMTHitCollection.h"
@@ -32,7 +33,7 @@ namespace Jug::Digi {
  *
  * \ingroup digi
  */
-class PhotoMultiplierDigi : public GaudiAlgorithm
+class PhotoMultiplierDigi : public GaudiAlgorithm, AlgorithmIDMixin<>
 {
 public:
     DataHandle<dd4pod::PhotoMultiplierHitCollection>
@@ -52,6 +53,7 @@ public:
     // constructor
     PhotoMultiplierDigi(const std::string& name, ISvcLocator* svcLoc)
         : GaudiAlgorithm(name, svcLoc)
+        , AlgorithmIDMixin(name, info())
     {
         declareProperty("inputHitCollection", m_inputHitCollection,"");
         declareProperty("outputHitCollection", m_outputHitCollection, "");
@@ -122,8 +124,8 @@ public:
         for (auto &it : hit_groups) {
             for (auto &data : it.second) {
                 eic::RawPMTHit hit{
+                  {ID++, algorithmID()},
                   it.first,
-                  ID++,
                   static_cast<uint32_t>(data.signal), 
                   static_cast<uint32_t>(data.time/(m_timeStep/ns))};
                 raw.push_back(hit);
diff --git a/JugDigi/src/components/SOIPIXTrackerDigi.cpp b/JugDigi/src/components/SOIPIXTrackerDigi.cpp
index 784caf917fdc6632f4f638f99f27a96d2c30c4ef..b55cbd77d8128b073b488ca4d18fdce734c4edb0 100644
--- a/JugDigi/src/components/SOIPIXTrackerDigi.cpp
+++ b/JugDigi/src/components/SOIPIXTrackerDigi.cpp
@@ -6,8 +6,8 @@
 #include "GaudiKernel/RndmGenerators.h"
 #include "Gaudi/Property.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 //#include "GaudiExamples/MyTrack.h"
@@ -21,7 +21,7 @@ namespace Jug {
      *
      * \ingroup digi
      */
-   class SOIPIXTrackerDigi : public GaudiAlgorithm {
+   class SOIPIXTrackerDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
    public:
     Gaudi::Property<double>                  m_timeResolution{this, "timeResolution", 1e3};  // ns -- todo add units
     Rndm::Numbers                            m_gaussDist;
@@ -30,11 +30,11 @@ namespace Jug {
 
    public:
     //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
-    SOIPIXTrackerDigi(const std::string& name, ISvcLocator* svcLoc)
-        : GaudiAlgorithm(name, svcLoc) {
-          declareProperty("inputHitCollection", m_inputHitCollection,"");
-          declareProperty("outputHitCollection", m_outputHitCollection, "");
-        }
+     SOIPIXTrackerDigi(const std::string& name, ISvcLocator* svcLoc)
+         : GaudiAlgorithm(name, svcLoc), AlgorithmIDMixin(name, info()) {
+       declareProperty("inputHitCollection", m_inputHitCollection, "");
+       declareProperty("outputHitCollection", m_outputHitCollection, "");
+     }
     StatusCode initialize() override {
       if (GaudiAlgorithm::initialize().isFailure())
         return StatusCode::FAILURE;
@@ -56,9 +56,9 @@ namespace Jug {
         // std::cout << ahit << "\n";
         if (cell_hit_map.count(ahit.cellID()) == 0) {
           cell_hit_map[ahit.cellID()] = rawhits->size();
-          eic::RawTrackerHit rawhit((long long)ahit.cellID(),
-                                    ID++,
-                                    ahit.truth().time * 1e6 + m_gaussDist() * 1e6, // ns->fs
+          eic::RawTrackerHit rawhit({ID++, algorithmID()}, (long long)ahit.cellID(),
+                                    ahit.truth().time * 1e6 +
+                                        m_gaussDist() * 1e6, // ns->fs
                                     std::llround(ahit.energyDeposit() * 1e6));
           rawhits->push_back(rawhit);
         } else {
diff --git a/JugDigi/src/components/SiliconTrackerDigi.cpp b/JugDigi/src/components/SiliconTrackerDigi.cpp
index 2ba4cd3896539382757964e6ffe4953ad147c21a..c12f71350e33b4212a7f4b1bc948611bd061f480 100644
--- a/JugDigi/src/components/SiliconTrackerDigi.cpp
+++ b/JugDigi/src/components/SiliconTrackerDigi.cpp
@@ -6,12 +6,10 @@
 #include "GaudiKernel/RndmGenerators.h"
 #include "Gaudi/Property.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
-//#include "GaudiExamples/MyTrack.h"
-//
 // dd4pod's tracker hit is the input collectiopn
 #include "dd4pod/TrackerHitCollection.h"
 // eicd's RawTrackerHit is the output
@@ -23,7 +21,7 @@ namespace Jug::Digi {
    *
    * \ingroup digi
    */
-  class SiliconTrackerDigi : public GaudiAlgorithm {
+  class SiliconTrackerDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
   public:
     Gaudi::Property<double>                  m_timeResolution{this, "timeResolution", 10}; // todo : add units
     Rndm::Numbers                            m_gaussDist;
@@ -34,7 +32,9 @@ namespace Jug::Digi {
 
   public:
     //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
-    SiliconTrackerDigi(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
+    SiliconTrackerDigi(const std::string& name, ISvcLocator* svcLoc) 
+      : GaudiAlgorithm(name, svcLoc)
+      , AlgorithmIDMixin(name, info())
     {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
       declareProperty("outputHitCollection", m_outputHitCollection, "");
@@ -68,8 +68,8 @@ namespace Jug::Digi {
         // std::cout << ahit << "\n";
         if (cell_hit_map.count(ahit.cellID()) == 0) {
           cell_hit_map[ahit.cellID()] = rawhits->size();
-          eic::RawTrackerHit rawhit((int64_t)ahit.cellID(),
-                                    ID++,
+          eic::RawTrackerHit rawhit({ID++, algorithmID()},
+                                    (int64_t)ahit.cellID(),
                                     ahit.truth().time * 1e6 + m_gaussDist() * 1e3, // ns->fs
                                     std::llround(ahit.energyDeposit() * 1e6));
           rawhits->push_back(rawhit);
diff --git a/JugDigi/src/components/UFSDTrackerDigi.cpp b/JugDigi/src/components/UFSDTrackerDigi.cpp
index 3f7878763088f3becd3a9659443ad2cd957cf72b..d2cdaf6209439396e1d47fcfbfd5d3089fdba375 100644
--- a/JugDigi/src/components/UFSDTrackerDigi.cpp
+++ b/JugDigi/src/components/UFSDTrackerDigi.cpp
@@ -6,8 +6,8 @@
 #include "GaudiKernel/RndmGenerators.h"
 #include "Gaudi/Property.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 //#include "GaudiExamples/MyTrack.h"
@@ -23,7 +23,7 @@ namespace Jug::Digi {
    *
    * \ingroup digi
    */
-  class UFSDTrackerDigi : public GaudiAlgorithm {
+  class UFSDTrackerDigi : public GaudiAlgorithm, AlgorithmIDMixin<> {
   public:
     Gaudi::Property<double>                  m_timeResolution{this, "timeResolution", 10}; // todo : add units
     Rndm::Numbers                            m_gaussDist;
@@ -34,7 +34,9 @@ namespace Jug::Digi {
 
   public:
     //  ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
-    UFSDTrackerDigi(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
+    UFSDTrackerDigi(const std::string& name, ISvcLocator* svcLoc) 
+      : GaudiAlgorithm(name, svcLoc)
+      , AlgorithmIDMixin(name, info())
     {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
       declareProperty("outputHitCollection", m_outputHitCollection, "");
@@ -68,8 +70,8 @@ namespace Jug::Digi {
         // std::cout << ahit << "\n";
         if (cell_hit_map.count(ahit.cellID()) == 0) {
           cell_hit_map[ahit.cellID()] = rawhits->size();
-          eic::RawTrackerHit rawhit((int64_t)ahit.cellID(),
-                                    ID++,
+          eic::RawTrackerHit rawhit({ID++, algorithmID()},
+                                    (int64_t)ahit.cellID(),
                                     ahit.truth().time * 1e6 + m_gaussDist() * 1e3, // ns->fs
                                     std::llround(ahit.energyDeposit() * 1e6));
           rawhits->push_back(rawhit);
diff --git a/JugReco/src/components/CalorimeterHitReco.cpp b/JugReco/src/components/CalorimeterHitReco.cpp
index 00da050a1f908a3f24345dc39a408834f3b0fa56..c7803285bd5324c6492da285e9725a15b32b0ffe 100644
--- a/JugReco/src/components/CalorimeterHitReco.cpp
+++ b/JugReco/src/components/CalorimeterHitReco.cpp
@@ -211,11 +211,10 @@ namespace Jug::Reco {
         //         m_geoSvc->cellIDPositionConverter()->findContext(id)->volumePlacement().volIDs().str()
         //         << endmsg;
         hits.push_back({
+            {rh.ID(), algorithmID()}, // ID
             rh.cellID(),    // cellID
-            rh.ID(),        // ID
             lid,            // layer
             sid,            // sector
-            algorithmID(),  // hit source (a hash of the algorithm name)
             energy,         // energy
             0,              // @TODO: energy error
             time,           // time
diff --git a/JugReco/src/components/CalorimeterHitsEtaPhiProjector.cpp b/JugReco/src/components/CalorimeterHitsEtaPhiProjector.cpp
index 953e209b01799566fd2c556d37deb42f49b3ca79..d0defdb246b83c1cdd4bba9e06d931bd50168206 100644
--- a/JugReco/src/components/CalorimeterHitsEtaPhiProjector.cpp
+++ b/JugReco/src/components/CalorimeterHitsEtaPhiProjector.cpp
@@ -108,6 +108,7 @@ namespace Jug::Reco {
       for (const auto &[bins, hits] : merged_hits) {
         const auto ref = hits.front();
         eic::CalorimeterHit hit;
+        hit.ID({ref.ID(), algorithmID()});
         hit.cellID(ref.cellID());
         hit.sector(ref.sector());
         hit.layer(ref.layer());
@@ -125,7 +126,6 @@ namespace Jug::Reco {
         for (const auto &h : hits) {
             hit.energy(hit.energy() + h.energy());
         }
-        hit.source(algorithmID());
         mhits.push_back(hit);
       }
 
diff --git a/JugReco/src/components/CalorimeterHitsMerger.cpp b/JugReco/src/components/CalorimeterHitsMerger.cpp
index 174ce91cec38430ecc33e61e6897c1f0c4d7be3b..5e86ae2bda096b14b3571b7d9b7cb061553e04d7 100644
--- a/JugReco/src/components/CalorimeterHitsMerger.cpp
+++ b/JugReco/src/components/CalorimeterHitsMerger.cpp
@@ -133,7 +133,6 @@ namespace Jug::Reco {
       auto poscon = m_geoSvc->cellIDPositionConverter();
       auto volman = m_geoSvc->detector()->volumeManager();
 
-      int nresults = 0;
       for (auto &[id, hits] : merge_map) {
         // reference fields id
         int64_t ref_id = id | ref_mask;
@@ -153,11 +152,10 @@ namespace Jug::Reco {
         }
         const auto &href = hits.front();
         outputs.push_back(eic::CalorimeterHit{
+                          {hits.front().ID(), algorithmID()},
                           ref_id,
-                          nresults++,
                           href.layer(),
                           href.sector(),
-                          algorithmID(),
                           energy,
                           0, //@TODO: energy uncertainty
                           href.time(),
diff --git a/JugReco/src/components/CalorimeterIslandCluster.cpp b/JugReco/src/components/CalorimeterIslandCluster.cpp
index 59fe127f80577d3c741c3e0b417b2d684415276a..3a77d11a9c2914604a86a6fa4f5d0a30fa7956b0 100644
--- a/JugReco/src/components/CalorimeterIslandCluster.cpp
+++ b/JugReco/src/components/CalorimeterIslandCluster.cpp
@@ -29,6 +29,7 @@
 
 #include "JugBase/DataHandle.h"
 #include "JugBase/IGeoSvc.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "eicd/CalorimeterHitCollection.h"
@@ -86,7 +87,7 @@ namespace Jug::Reco {
    *
    * \ingroup reco
    */
-  class CalorimeterIslandCluster : public GaudiAlgorithm {
+  class CalorimeterIslandCluster : public GaudiAlgorithm, AlgorithmIDMixin<> {
   public:
     Gaudi::Property<bool>                       m_splitCluster{this, "splitCluster", true};
     Gaudi::Property<double>                     m_minClusterHitEdep{this, "minClusterHitEdep", 0.};
@@ -113,6 +114,7 @@ namespace Jug::Reco {
 
     CalorimeterIslandCluster(const std::string& name, ISvcLocator* svcLoc)
         : GaudiAlgorithm(name, svcLoc)
+        , AlgorithmIDMixin(name, info())
     {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
       declareProperty("outputProtoClusterCollection", m_outputProtoCollection, "");
@@ -321,7 +323,9 @@ namespace Jug::Reco {
         return;
       } else if (maxima.size() == 1) {
         for (auto& hit : group) {
-          proto.create(hit.ID(), clusterID, 1.);
+          eic::ProtoCluster pcl{
+              hit.ID(), {static_cast<int32_t>(clusterID), algorithmID()}, 1.};
+          proto.push_back(pcl);
         }
         clusterID += 1;
         return;
@@ -359,7 +363,9 @@ namespace Jug::Reco {
           if (weight <= 1e-6) {
             continue;
           }
-          proto.create(it->ID(), n_clus + k, weight);
+          eic::ProtoCluster pcl{
+              it->ID(), {static_cast<int32_t>(n_clus + k), algorithmID()}, weight};
+          proto.push_back(pcl);
         }
       }
       clusterID += maxima.size();
diff --git a/JugReco/src/components/ClusterRecoCoG.cpp b/JugReco/src/components/ClusterRecoCoG.cpp
index 2edc71c9a49a955f78bbb726f6f8cc283da45d3a..3dbe281249a608dc8d34a8f46761bfa61f315edb 100644
--- a/JugReco/src/components/ClusterRecoCoG.cpp
+++ b/JugReco/src/components/ClusterRecoCoG.cpp
@@ -140,7 +140,7 @@ namespace Jug::Reco {
       std::map<int, std::vector<std::pair<eic::ConstProtoCluster, 
                                           eic::ConstCalorimeterHit>>> cluster_map;
       for (const auto& pc : proto) {
-        const size_t clusterID = pc.clusterID();
+        const size_t clusterID = pc.clusterID().value;
         if (!cluster_map.count(clusterID)) {
           cluster_map[clusterID] = {};
         }
@@ -183,8 +183,7 @@ namespace Jug::Reco {
                              const int idx) const
     {
       eic::Cluster cl;
-      cl.source(algorithmID());
-      cl.ID(idx);
+      cl.ID({idx, algorithmID()});
       cl.nhits(hit_info.size());
 
       // no hits
diff --git a/JugReco/src/components/CrystalEndcapsReco.cpp b/JugReco/src/components/CrystalEndcapsReco.cpp
index 9c28f8a62d176e38776311153dcb45f22446357a..89cdcf3c5494ba800b3818e041baefc570409566 100644
--- a/JugReco/src/components/CrystalEndcapsReco.cpp
+++ b/JugReco/src/components/CrystalEndcapsReco.cpp
@@ -83,9 +83,16 @@ namespace Jug::Reco {
               m_geoSvc->cellIDPositionConverter()->findContext(id)->volumePlacement().position();
           // cell dimension
           auto dim = m_geoSvc->cellIDPositionConverter()->cellDimensions(id);
-          hits.push_back(eic::CalorimeterHit{id, nhits++, -1, -1, 0, energy, 0., time, 
-                                            {gpos.x(), gpos.y(), gpos.z()}, 
-                                            {pos.x(), pos.y(), pos.z()}, {dim[0], dim[1], 0.}});
+          hits.push_back(eic::CalorimeterHit{{nhits++, 0},
+                                             id,
+                                             -1,
+                                             -1,
+                                             energy,
+                                             0.,
+                                             time,
+                                             {gpos.x(), gpos.y(), gpos.z()},
+                                             {pos.x(), pos.y(), pos.z()},
+                                             {dim[0], dim[1], 0.}});
         }
       }
 
diff --git a/JugReco/src/components/DummyFarForwardParticles.cpp b/JugReco/src/components/DummyFarForwardParticles.cpp
index a537faa9f17648725cc40774a361af2d82ce6450..15da559226f37537b9601b56a8fb1a19f6c6469a 100644
--- a/JugReco/src/components/DummyFarForwardParticles.cpp
+++ b/JugReco/src/components/DummyFarForwardParticles.cpp
@@ -14,6 +14,7 @@
 // Event Model related classes
 #include "dd4pod/Geant4ParticleCollection.h"
 #include "eicd/ReconstructedParticleCollection.h"
+#include "eicd/ReconstructedParticleRelationsCollection.h"
 #include "eicd/VectorPolar.h"
 
 namespace Jug::Reco {
@@ -21,8 +22,11 @@ namespace Jug::Reco {
 class DummyFarForwardParticles : public GaudiAlgorithm, AlgorithmIDMixin<> {
 public:
   DataHandle<dd4pod::Geant4ParticleCollection> m_inputParticles{"inputMCParticles", Gaudi::DataHandle::Reader, this};
-  DataHandle<eic::ReconstructedParticleCollection> m_outputParticles{"outputParticles", Gaudi::DataHandle::Writer,
+  DataHandle<eic::ReconstructedParticleCollection> m_outputParticles{"DummyFarForwardParticles", Gaudi::DataHandle::Writer,
                                                                      this};
+  DataHandle<eic::ReconstructedParticleRelationsCollection> m_outputRelations{"DummyFarForwardRelations", Gaudi::DataHandle::Writer,
+                                                                     this};
+
   Gaudi::Property<bool> m_enableZDC{this, "enableZDC", true};
   Gaudi::Property<bool> m_enableB0{this, "enableB0", true};
   Gaudi::Property<bool> m_enableRP{this, "enableRP", true};
@@ -55,10 +59,18 @@ public:
 
   Rndm::Numbers m_gaussDist;
 
+  // Monte Carlo particle source identifier
+  const int32_t m_kMonteCarloSource{uniqueID<int32_t>("mcparticles")};
+
+  private:
+  using RecData = std::pair<eic::ReconstructedParticle, eic::ReconstructedParticleRelations>;
+
+  public:
   DummyFarForwardParticles(const std::string& name, ISvcLocator* svcLoc)
       : GaudiAlgorithm(name, svcLoc), AlgorithmIDMixin(name, info()) {
     declareProperty("inputMCParticles", m_inputParticles, "mcparticles");
     declareProperty("outputParticles", m_outputParticles, "ReconstructedParticles");
+    declareProperty("outputRelations", m_outputRelations, "ReconstructedParticleRelations");
   }
   StatusCode initialize() override {
     if (GaudiAlgorithm::initialize().isFailure())
@@ -76,8 +88,9 @@ public:
   StatusCode execute() override {
     const auto& mc = *(m_inputParticles.get());
     auto& rc       = *(m_outputParticles.createAndPut());
+    auto& rel      = *(m_outputRelations.createAndPut());
 
-    std::vector<std::vector<eic::ReconstructedParticle>> rc_parts;
+    std::vector<std::vector<RecData>> rc_parts;
     if (m_enableZDC) {
       rc_parts.push_back(zdc(mc));
     }
@@ -92,7 +105,8 @@ public:
     }
     for (const auto& det : rc_parts) {
       for (const auto& part : det) {
-        rc.push_back(part);
+        rc.push_back(part.first);
+        rel.push_back(part.second);
       }
     }
     return StatusCode::SUCCESS;
@@ -101,8 +115,8 @@ public:
 private:
   // ZDC smearing as in eic_smear
   // https://github.com/eic/eicsmeardetectors/blob/9a1831dd97bf517b80a06043b9ee4bfb96b483d8/SmearMatrixDetector_0_1_FF.cxx#L224
-  std::vector<eic::ReconstructedParticle> zdc(const dd4pod::Geant4ParticleCollection& mc) {
-    std::vector<eic::ReconstructedParticle> rc;
+  std::vector<RecData> zdc(const dd4pod::Geant4ParticleCollection& mc) {
+    std::vector<RecData> rc;
     for (const auto& part : mc) {
       if (part.genStatus() != 1) {
         continue;
@@ -128,20 +142,23 @@ private:
       const double moms = sqrt(Es * Es - part.mass() * part.mass());
       const eic::VectorPolar mom3s_ion{moms, ths, phis};
       const auto mom3s = rotateIonToLabDirection(mom3s_ion);
-      eic::ReconstructedParticle rec_part{part.ID(),
+      eic::ReconstructedParticle rec_part{{part.ID(), algorithmID()},
                                           mom3s,
                                           {part.vs().x, part.vs().y, part.vs().z},
                                           static_cast<float>(part.time()),
                                           part.pdgID(),
                                           0,
                                           static_cast<int16_t>(part.charge()),
-                                          algorithmID(),
                                           1.,
                                           {mom3s.theta(), mom3s.phi()},
                                           static_cast<float>(moms),
                                           static_cast<float>(Es),
                                           static_cast<float>(part.mass())};
-      rc.push_back(rec_part);
+      eic::ReconstructedParticleRelations rel;
+      rel.recID(rec_part.ID());
+      rel.mcID({part.ID(), m_kMonteCarloSource});
+      rc.push_back({rec_part, rel});
+
       if (msgLevel(MSG::DEBUG)) {
         debug()
             << fmt::format(
@@ -154,8 +171,8 @@ private:
   }
   // Fast B0 as in
   // https://github.com/eic/eicsmeardetectors/blob/9a1831dd97bf517b80a06043b9ee4bfb96b483d8/SmearMatrixDetector_0_1_FF.cxx#L254
-  std::vector<eic::ReconstructedParticle> b0(const dd4pod::Geant4ParticleCollection& mc) {
-    std::vector<eic::ReconstructedParticle> rc;
+  std::vector<RecData> b0(const dd4pod::Geant4ParticleCollection& mc) {
+    std::vector<RecData> rc;
     for (const auto& part : mc) {
       if (part.genStatus() != 1) {
         continue;
@@ -172,7 +189,7 @@ private:
       }
       rc.push_back(smearMomentum(part));
       if (msgLevel(MSG::DEBUG)) {
-        auto& rec_part = rc.back();
+        auto& rec_part = rc.back().first;
         debug() << fmt::format("Found B0 particle: {}, ptrue: {}, pmeas: {}, pttrue: {}, ptmeas: {}, theta_true: {}, "
                                "theta_meas: {}",
                                part.pdgID(), part.ps().mag(), rec_part.momentum(), std::hypot(part.ps().x, part.ps().y),
@@ -184,8 +201,8 @@ private:
     return rc;
   }
 
-  std::vector<eic::ReconstructedParticle> rp(const dd4pod::Geant4ParticleCollection& mc) {
-    std::vector<eic::ReconstructedParticle> rc;
+  std::vector<RecData> rp(const dd4pod::Geant4ParticleCollection& mc) {
+    std::vector<RecData> rc;
     for (const auto& part : mc) {
       if (part.genStatus() != 1) {
         continue;
@@ -201,7 +218,7 @@ private:
       }
       rc.push_back(smearMomentum(part));
       if (msgLevel(MSG::DEBUG)) {
-        auto& rec_part = rc.back();
+        auto& rec_part = rc.back().first;
         debug() << fmt::format("Found RP particle: {}, ptrue: {}, pmeas: {}, pttrue: {}, ptmeas: {}, theta_true: {}, "
                                "theta_meas: {}",
                                part.pdgID(), part.ps().mag(), rec_part.momentum(), std::hypot(part.ps().x, part.ps().y),
@@ -212,8 +229,8 @@ private:
     return rc;
   }
 
-  std::vector<eic::ReconstructedParticle> omd(const dd4pod::Geant4ParticleCollection& mc) {
-    std::vector<eic::ReconstructedParticle> rc;
+  std::vector<RecData> omd(const dd4pod::Geant4ParticleCollection& mc) {
+    std::vector<RecData> rc;
     for (const auto& part : mc) {
       if (part.genStatus() != 1) {
         continue;
@@ -235,7 +252,7 @@ private:
       }
       rc.push_back(smearMomentum(part));
       if (msgLevel(MSG::DEBUG)) {
-        auto& rec_part = rc.back();
+        auto& rec_part = rc.back().first;
         debug() << fmt::format("Found OMD particle: {}, ptrue: {}, pmeas: {}, pttrue: {}, ptmeas: {}, theta_true: {}, "
                                "theta_meas: {}",
                                part.pdgID(), part.ps().mag(), rec_part.momentum(), std::hypot(part.ps().x, part.ps().y),
@@ -248,7 +265,7 @@ private:
 
   // all momentum smearing in EIC-smear for the far-forward region uses
   // the same 2 relations for P and Pt smearing (B0, RP, OMD)
-  eic::ReconstructedParticle smearMomentum(const dd4pod::ConstGeant4Particle& part) {
+  RecData smearMomentum(const dd4pod::ConstGeant4Particle& part) {
     const auto mom_ion = rotateLabToIonDirection(part.ps());
     const double p     = mom_ion.mag();
     const double dp    = (0.005 * p) * m_gaussDist();
@@ -264,19 +281,23 @@ private:
     // And build our 3-vector
     const eic::VectorXYZ psmear_ion = {pxs, pys, pzs};
     const auto psmear               = rotateIonToLabDirection(psmear_ion);
-    return {part.ID(),
-            psmear,
-            {part.vs().x, part.vs().y, part.vs().z},
-            static_cast<float>(part.time()),
-            part.pdgID(),
-            0,
-            static_cast<int16_t>(part.charge()),
-            algorithmID(),
-            1.,
-            {psmear.theta(), psmear.phi()},
-            static_cast<float>(ps),
-            static_cast<float>(std::hypot(psmear.mag(), part.mass())),
-            static_cast<float>(part.mass())};
+    eic::ReconstructedParticle rec{
+        {part.ID(), algorithmID()},
+        psmear,
+        {part.vs().x, part.vs().y, part.vs().z},
+        static_cast<float>(part.time()),
+        part.pdgID(),
+        0,
+        static_cast<int16_t>(part.charge()),
+        1.,
+        {psmear.theta(), psmear.phi()},
+        static_cast<float>(ps),
+        static_cast<float>(std::hypot(psmear.mag(), part.mass())),
+        static_cast<float>(part.mass())};
+    eic::ReconstructedParticleRelations rel;
+    rel.recID(rec.ID());
+    rel.mcID({part.ID(), m_kMonteCarloSource});
+    return {rec, rel};
   }
 
   // Rotate 25mrad about the y-axis
diff --git a/JugReco/src/components/EMCalReconstruction.cpp b/JugReco/src/components/EMCalReconstruction.cpp
index b4ff87369f8f15ae7122a61917136a87b18a9a5c..c7e8fa035c83dcf2933ec6ae689f76341f24afc0 100644
--- a/JugReco/src/components/EMCalReconstruction.cpp
+++ b/JugReco/src/components/EMCalReconstruction.cpp
@@ -1,3 +1,5 @@
+// DEPRECATED
+
 #include <algorithm>
 
 #include "Gaudi/Property.h"
@@ -90,11 +92,10 @@ namespace Jug::Reco {
           // cell dimension
           auto dim = m_geoSvc->cellIDPositionConverter()->cellDimensions(id);
           hits.push_back(eic::CalorimeterHit{
+              {nhits, 0}, // NO SOURCE SET
               id,
-              nhits++,
               -1,
               -1,
-              0,
               static_cast<float>(energy / m_samplingFraction), // Why are we applying the sampling fraction already here?
               0,
               time,
diff --git a/JugReco/src/components/EcalTungstenSamplingReco.cpp b/JugReco/src/components/EcalTungstenSamplingReco.cpp
index e565f683036a08d692d9e58a2e781225790710ff..ced8094cf698852dff02262e0ab766e1550781d2 100644
--- a/JugReco/src/components/EcalTungstenSamplingReco.cpp
+++ b/JugReco/src/components/EcalTungstenSamplingReco.cpp
@@ -142,11 +142,10 @@ namespace Jug::Reco {
         //        m_geoSvc->cellIDPositionConverter()->findContext(id)->volumePlacement().volIDs().str()
         //        << endmsg;
         hits.push_back(
-            eic::CalorimeterHit{id,
-                                nhits++,
+            eic::CalorimeterHit{{nhits++, 0},
+                                id,
                                 lid,
                                 sid,
-                                0,
                                 energy,
                                 0.,
                                 time,
diff --git a/JugReco/src/components/EnergyPositionClusterMerger.cpp b/JugReco/src/components/EnergyPositionClusterMerger.cpp
index 39aa263d1168a70a3175e3f1acc1ecff702f8490..8494a4755010c8b7a3638a57ecdf386ff745240e 100644
--- a/JugReco/src/components/EnergyPositionClusterMerger.cpp
+++ b/JugReco/src/components/EnergyPositionClusterMerger.cpp
@@ -109,8 +109,7 @@ public:
       if (best_match >= 0) {
         const auto& ec = e_clus[best_match];
         auto new_clus  = merged.create();
-        new_clus.ID(idx++);
-        new_clus.source(algorithmID());
+        new_clus.ID({idx++, algorithmID()});
         new_clus.energy(ec.energy());
         new_clus.energyError(ec.energyError());
         new_clus.time(pc.time());
@@ -122,12 +121,12 @@ public:
         auto rel = relations.create();
         rel.clusterID(new_clus.ID());
         rel.size(2);
-        rel.parent()[0] = {pc.source(), pc.ID()};
-        rel.parent()[1] = {ec.source(), ec.ID()};
+        rel.parent()[0] = pc.ID();
+        rel.parent()[1] = ec.ID();
         // label our energy cluster as consumed
         consumed[best_match] = true;
         if (msgLevel(MSG::DEBUG)) {
-          debug() << fmt::format("Matched position cluster {} with energy cluster {}\n", pc.ID(), ec.ID()) << endmsg;
+          debug() << fmt::format("Matched position cluster {} with energy cluster {}\n", pc.ID().value, ec.ID().value) << endmsg;
           debug() << fmt::format("  - Position cluster: (E: {}, phi: {}, z: {})", pc.energy(), pc.position().phi(),
                                  pc.position().z)
                   << endmsg;
diff --git a/JugReco/src/components/HCalReconstruction.cpp b/JugReco/src/components/HCalReconstruction.cpp
index e834af473b2c23a9f0ab19ceef79ae398b95deb0..30286b6d4559928752ecb4de6d23fc073576ea43 100644
--- a/JugReco/src/components/HCalReconstruction.cpp
+++ b/JugReco/src/components/HCalReconstruction.cpp
@@ -1,3 +1,5 @@
+// DEPRECATED
+
 #include <algorithm>
 
 #include "Gaudi/Property.h"
@@ -90,11 +92,10 @@ namespace Jug::Reco {
           // cell dimension
           auto dim = m_geoSvc->cellIDPositionConverter()->cellDimensions(id);
           hits.push_back(eic::CalorimeterHit{
+              {nhits++, 0}, // NO SOURCE SET FOR DEPRECATED ALGO
               id,
-              nhits++,
               -1,
               -1,
-              0,
               static_cast<float>(energy / m_samplingFraction),
               0,
               time,
diff --git a/JugReco/src/components/ImagingClusterReco.cpp b/JugReco/src/components/ImagingClusterReco.cpp
index 85abd8d0c6640e19af9118d673c2f1de41e72542..0b4cf6ed4a5a62bd89ec3ac4dd32b2521c125e7b 100644
--- a/JugReco/src/components/ImagingClusterReco.cpp
+++ b/JugReco/src/components/ImagingClusterReco.cpp
@@ -92,7 +92,7 @@ public:
     std::map<int, std::vector<std::pair<eic::ConstProtoCluster, 
                                         eic::ConstCalorimeterHit>>> cluster_map;
     for (const auto& pc : proto) {
-      const size_t clusterID = pc.clusterID();
+      const size_t clusterID = pc.clusterID().value;
       if (!cluster_map.count(clusterID)) {
         cluster_map[clusterID] = {};
       }
@@ -105,6 +105,8 @@ public:
       cluster_map[clusterID].push_back({pc, hits[idx]});
     }
 
+    const int32_t nclus = static_cast<int32_t>(cluster_map.size());
+
     for (const auto& [cid, hit_info] : cluster_map) {
       // get cluster and associated layers
       auto cl        = reconstruct_cluster(hit_info, cid);
@@ -115,7 +117,9 @@ public:
 
       // store layer and clusters on the datastore
       for (auto& layer : cl_layers) {
-        layer.ID(layers.size()); // unique ID for this clusterlayer
+        // unique ID for this clusterlayer, starting at the last
+        // cluster ID value to guarantee uniqueness
+        layer.ID({nclus + static_cast<int32_t>(layers.size()), algorithmID()});
         layers.push_back(layer);
         // cl.addlayers(layer); // deprectated
       }
@@ -127,7 +131,7 @@ public:
     int idx = 0;
     if (msgLevel(MSG::DEBUG)) {
       for (const auto& cl : clusters) {
-        debug() << fmt::format("Cluster {:d}: Edep = {:.3f} MeV, Dir = ({:.3f}, {:.3f}) deg", cl.ID(),
+        debug() << fmt::format("Cluster {:d}: Edep = {:.3f} MeV, Dir = ({:.3f}, {:.3f}) deg", cl.ID().value,
                                cl.energy() * 1000., info[idx].direction().theta / M_PI * 180.,
                                info[idx].direction().phi / M_PI * 180.)
                 << endmsg;
@@ -167,7 +171,7 @@ private:
   eic::ClusterLayer reconstruct_layer(const std::vector<std::pair<eic::ConstProtoCluster, eic::ConstCalorimeterHit>>& hit_info,
                                       const int cid, const int lid) const {
     // use full members initialization here so it could catch changes in ecid
-    eic::ClusterLayer layer{-1, cid, lid, static_cast<uint32_t>(hit_info.size()), algorithmID(), 0., 0., 0., 0., {}};
+    eic::ClusterLayer layer{{}, {cid, algorithmID()}, lid, static_cast<uint32_t>(hit_info.size()), 0., 0., 0., 0., {}};
 
     // mean position and total energy
     eic::VectorXYZ pos;
@@ -193,8 +197,7 @@ private:
   reconstruct_cluster(const std::vector<std::pair<eic::ConstProtoCluster, eic::ConstCalorimeterHit>>& hit_info,
                       const int cid) const {
     eic::Cluster cluster;
-    cluster.ID(cid);
-    cluster.source(algorithmID());
+    cluster.ID({cid, algorithmID()});
     // eta, phi center, weighted by energy
     double meta = 0.;
     double mphi = 0.;
diff --git a/JugReco/src/components/ImagingPixelMerger.cpp b/JugReco/src/components/ImagingPixelMerger.cpp
index 102c2237e6a7d9ae4d3f58b789168b9d8c4ddc54..4e041eb4b4ac12c9349a92de14fc3e604f4c12c6 100644
--- a/JugReco/src/components/ImagingPixelMerger.cpp
+++ b/JugReco/src/components/ImagingPixelMerger.cpp
@@ -139,9 +139,8 @@ namespace Jug::Reco {
           eic::VectorXYZ pos {eic::VectorPolar(0., 0., grid.phi)};
           // @TODO: This seems incomplete...
           auto h = mhits.create();
-          h.ID(k);
+          h.ID({k, algorithmID()});
           h.layer(i);
-          h.source(algorithmID());
           h.energy(grid.energy);
           h.position(pos);
         }
diff --git a/JugReco/src/components/ImagingPixelReco.cpp b/JugReco/src/components/ImagingPixelReco.cpp
index 74ebe43bcfbb4cb7986bca19a3bb2096631e4318..0d8cbe8194508761ebee40be7286ade5c68b858a 100644
--- a/JugReco/src/components/ImagingPixelReco.cpp
+++ b/JugReco/src/components/ImagingPixelReco.cpp
@@ -139,11 +139,10 @@ namespace Jug::Reco {
         auto pos       = alignment.worldToLocal(dd4hep::Position(gpos.x(), gpos.y(), gpos.z()));
 
         hits.push_back(eic::CalorimeterHit{
+            {nhits++, algorithmID()},    // ID
             id,           // cellID
-            nhits++,      // ID
             lid,          // layer
             sid,          // sector
-            algorithmID(),// hit source algorithm
             static_cast<float>(energy), // energy
             0,                          // energyError
             static_cast<float>(time),   // time
diff --git a/JugReco/src/components/ImagingTopoCluster.cpp b/JugReco/src/components/ImagingTopoCluster.cpp
index 2943a8e41d9cc1f13d1c81cd409de3be3744b242..a53f400bec1a75e8adc73d484e727b6e7ec72797 100644
--- a/JugReco/src/components/ImagingTopoCluster.cpp
+++ b/JugReco/src/components/ImagingTopoCluster.cpp
@@ -22,9 +22,9 @@
 #include "DDRec/Surface.h"
 #include "DDRec/SurfaceManager.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
 #include "JugBase/IGeoSvc.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "eicd/ProtoClusterCollection.h"
@@ -44,7 +44,7 @@ namespace Jug::Reco {
    *
    * \ingroup reco
    */
-  class ImagingTopoCluster : public GaudiAlgorithm {
+  class ImagingTopoCluster : public GaudiAlgorithm, AlgorithmIDMixin<> {
   public:
     // maximum difference in layer numbers that can be considered as neighbours
     Gaudi::Property<int> m_neighbourLayersRange{this, "neighbourLayersRange", 1};
@@ -74,7 +74,9 @@ namespace Jug::Reco {
     double localDistXY[2], layerDistEtaPhi[2], sectorDist;
     double minClusterHitEdep, minClusterCenterEdep, minClusterEdep, minClusterNhits;
 
-    ImagingTopoCluster(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
+    ImagingTopoCluster(const std::string& name, ISvcLocator* svcLoc) 
+      : GaudiAlgorithm(name, svcLoc)
+      , AlgorithmIDMixin(name, info())
     {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
       declareProperty("outputProtoClusterCollection", m_outputProtoClusterCollection, "");
@@ -154,7 +156,7 @@ namespace Jug::Reco {
       }
 
       // form clusters
-      size_t clusterID = 0;
+      int32_t clusterID = 0;
       for (const auto& group : groups) {
         if (static_cast<int>(group.size()) < m_minClusterNhits.value()) {
           continue;
@@ -167,7 +169,8 @@ namespace Jug::Reco {
           continue;
         }
         for (const auto& hit : group) {
-          proto.create(hit.ID(), clusterID, 1.);
+          eic::ProtoCluster pcl {hit.ID(), {clusterID, algorithmID()}, 1.};
+          proto.push_back(pcl);
         }
         clusterID += 1;
       }
diff --git a/JugReco/src/components/ParticlesWithTruthPID.cpp b/JugReco/src/components/ParticlesWithTruthPID.cpp
index 0001be3e6a91e230df570db72a7cc552ee449827..1ca09520803b5bf5ededfb1391d48d4e76b0a589 100644
--- a/JugReco/src/components/ParticlesWithTruthPID.cpp
+++ b/JugReco/src/components/ParticlesWithTruthPID.cpp
@@ -15,6 +15,7 @@
 // Event Model related classes
 #include "dd4pod/Geant4ParticleCollection.h"
 #include "eicd/ReconstructedParticleCollection.h"
+#include "eicd/ReconstructedParticleRelationsCollection.h"
 #include "eicd/TrackParametersCollection.h"
 #include "eicd/VectorPolar.h"
 
@@ -26,8 +27,10 @@ public:
                                                                       this};
   DataHandle<eic::TrackParametersCollection> m_inputTrackCollection{"inputTrackParameters", Gaudi::DataHandle::Reader,
                                                                     this};
-  DataHandle<eic::ReconstructedParticleCollection> m_outputParticleCollection{"outputParticles",
-                                                                              Gaudi::DataHandle::Writer, this};
+  DataHandle<eic::ReconstructedParticleCollection> m_outputParticleCollection{
+      "ReconstructedParticles", Gaudi::DataHandle::Writer, this};
+  DataHandle<eic::ReconstructedParticleRelationsCollection> m_outputRelationsCollection{
+      "ReconstructedParticleRelations", Gaudi::DataHandle::Writer, this};
 
   // Matching momentum tolerance requires 10% by default;
   Gaudi::Property<double> m_pRelativeTolerance{this, "pRelativeTolerance", {0.1}};
@@ -36,11 +39,14 @@ public:
   // Matchin eta tolerance of 0.1
   Gaudi::Property<double> m_etaTolerance{this, "etaTolerance", {0.2}};
 
+  const int32_t m_kMonteCarloSource{uniqueID<int32_t>("mcparticles")};
+
   ParticlesWithTruthPID(const std::string& name, ISvcLocator* svcLoc)
       : GaudiAlgorithm(name, svcLoc), AlgorithmIDMixin(name, info()) {
     declareProperty("inputMCParticles", m_inputTruthCollection, "mcparticles");
     declareProperty("inputTrackParameters", m_inputTrackCollection, "outputTrackParameters");
     declareProperty("outputParticles", m_outputParticleCollection, "ReconstructedParticles");
+    declareProperty("outputRelations", m_outputParticleCollection, "ReconstructedParticleRelations");
   }
   StatusCode initialize() override {
     if (GaudiAlgorithm::initialize().isFailure())
@@ -53,6 +59,7 @@ public:
     const auto& mc     = *(m_inputTruthCollection.get());
     const auto& tracks = *(m_inputTrackCollection.get());
     auto& part         = *(m_outputParticleCollection.createAndPut());
+    auto& rel          = *(m_outputRelationsCollection.createAndPut());
 
     const double sinPhiOver2Tolerance = sin(0.5 * m_phiTolerance);
     std::vector<bool> consumed(mc.size(), false);
@@ -88,6 +95,7 @@ public:
       eic::VectorXYZ vertex;
       float time = 0;
       float mass = 0;
+      eic::Index mcID;
       if (best_match >= 0) {
         consumed[best_match] = true;
         const auto& mcpart   = mc[best_match];
@@ -95,25 +103,29 @@ public:
         vertex               = {mcpart.vs().x, mcpart.vs().y, mcpart.vs().z};
         time                 = mcpart.time();
         mass                 = mcpart.mass();
+        mcID                 = {mcpart.ID(), m_kMonteCarloSource};
       }
-      eic::ReconstructedParticle rec_part{ID++,
+      eic::ReconstructedParticle rec_part{{ID++, algorithmID()},
                                           mom,
                                           vertex,
                                           time,
                                           best_pid,
                                           static_cast<int16_t>(best_match >= 0 ? 0 : -1) /* status */,
                                           static_cast<int16_t>(charge_rec),
-                                          algorithmID(),
                                           1. /* weight */,
                                           {mom.theta(), mom.phi()},
                                           mom.mag(),
                                           std::hypot(mom.mag(), mass),
                                           mass};
+      eic::ReconstructedParticleRelations rel_part;
+      rel_part.recID(rec_part.ID());
+      rel_part.mcID(mcID);
       part.push_back(rec_part);
+      rel.push_back(rel_part);
       if (msgLevel(MSG::DEBUG)) {
         if (best_match > 0) {
           const auto& mcpart = mc[best_match];
-          debug() << fmt::format("Matched track {} with MC particle {}\n", trk.ID(), best_match) << endmsg;
+          debug() << fmt::format("Matched track {} with MC particle {}\n", trk.ID().value, best_match) << endmsg;
           debug() << fmt::format("  - Track: (mom: {}, theta: {}, phi: {}, charge: {})", mom.mag(), mom.theta(),
                                  mom.phi(), charge_rec)
                   << endmsg;
@@ -122,7 +134,7 @@ public:
                                  mcpart.pdgID())
                   << endmsg;
         } else {
-          debug() << fmt::format("Did not find a good match for track {} \n", trk.ID()) << endmsg;
+          debug() << fmt::format("Did not find a good match for track {} \n", trk.ID().value) << endmsg;
           debug() << fmt::format("  - Track: (mom: {}, theta: {}, phi: {}, charge: {})", mom.mag(), mom.theta(),
                                  mom.phi(), charge_rec)
                   << endmsg;
diff --git a/JugReco/src/components/PhotoMultiplierReco.cpp b/JugReco/src/components/PhotoMultiplierReco.cpp
index 3183b4f1c60142c22dc92ec22432a8fbdf1d38de..94498175b6218ecb7a38bee8858526d244a84b4e 100644
--- a/JugReco/src/components/PhotoMultiplierReco.cpp
+++ b/JugReco/src/components/PhotoMultiplierReco.cpp
@@ -96,9 +96,8 @@ namespace Jug::Reco {
           // cell dimension
           auto dim = m_geoSvc->cellIDPositionConverter()->cellDimensions(id);
           hits.push_back(eic::PMTHit{
+              {rh.ID(), algorithmID()},
               rh.cellID(),
-              rh.ID(),
-              algorithmID(),
               npe,
               time,
               m_timeStep / ns,
diff --git a/JugReco/src/components/PhotoRingClusters.cpp b/JugReco/src/components/PhotoRingClusters.cpp
index 39c8e4ba428aa2543011f90e6667dc2ce80932bd..6878f9e8ca735a86824168fc35b65de7e238b77f 100644
--- a/JugReco/src/components/PhotoRingClusters.cpp
+++ b/JugReco/src/components/PhotoRingClusters.cpp
@@ -19,9 +19,9 @@
 #include "DDRec/Surface.h"
 #include "DDRec/SurfaceManager.h"
 
-// FCCSW
 #include "JugBase/DataHandle.h"
 #include "JugBase/IGeoSvc.h"
+#include "JugBase/UniqueID.h"
 
 // Event Model related classes
 #include "FuzzyKClusters.h"
@@ -37,7 +37,7 @@ namespace Jug::Reco {
    *
    * \ingroup reco
    */
-  class PhotoRingClusters : public GaudiAlgorithm {
+  class PhotoRingClusters : public GaudiAlgorithm, AlgorithmIDMixin<> {
   public:
     DataHandle<eic::PMTHitCollection>      m_inputHitCollection{"inputHitCollection", Gaudi::DataHandle::Reader, this};
     DataHandle<eic::RingImageCollection> m_outputClusterCollection{"outputClusterCollection",
@@ -53,7 +53,9 @@ namespace Jug::Reco {
     SmartIF<IGeoSvc> m_geoSvc;
 
     // ill-formed: using GaudiAlgorithm::GaudiAlgorithm;
-    PhotoRingClusters(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
+    PhotoRingClusters(const std::string& name, ISvcLocator* svcLoc) 
+      : GaudiAlgorithm(name, svcLoc)
+      , AlgorithmIDMixin(name, info())
     {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
       declareProperty("outputClusterCollection", m_outputClusterCollection, "");
@@ -99,7 +101,7 @@ namespace Jug::Reco {
       //        if those are in fact needed
       for (int i = 0; i < res.rows(); ++i) {
         auto cl = clusters.create();
-        cl.ID(i);
+        cl.ID({i, algorithmID()});
         cl.position({res(i, 0), res(i, 1), 0});
         // @TODO: positionError() not set
         // @TODO: theta() not set
diff --git a/JugReco/src/components/SimpleClustering.cpp b/JugReco/src/components/SimpleClustering.cpp
index 97844dcaa941f6b6a9623ff627346f97bf90b11b..646cf1f0997ca3f0eec6e7f1bb18bceadbc6815d 100644
--- a/JugReco/src/components/SimpleClustering.cpp
+++ b/JugReco/src/components/SimpleClustering.cpp
@@ -119,8 +119,7 @@ namespace Jug::Reco {
         }
 
         eic::Cluster cl;
-        cl.ID(clusters.size());
-        cl.source(algorithmID());
+        cl.ID({clusters.size(), algorithmID()});
         cl.nhits(cluster_hits.size());
         for (const auto& h : cluster_hits) {
           cl.energy(cl.energy() + h.energy());
diff --git a/JugReco/src/components/TrackerHitReconstruction.cpp b/JugReco/src/components/TrackerHitReconstruction.cpp
index d497b4917a36a4e28b58ce40e4c0ee449e21b099..1a091540611ff1a3fb12c0b1c55a06e075b44706 100644
--- a/JugReco/src/components/TrackerHitReconstruction.cpp
+++ b/JugReco/src/components/TrackerHitReconstruction.cpp
@@ -91,11 +91,10 @@ namespace Jug {
           // std::array<double,3> posarr; pos.GetCoordinates(posarr);
           // std::array<double,3> dimarr; dim.GetCoordinates(posarr);
           // eic::TrackerHit hit;
-          eic::TrackerHit hit{(long long)ahit.cellID(),
-                              ahit.ID(),
+          eic::TrackerHit hit{{ahit.ID().value, algorithmID()},
+                              ahit.cellID(),
                               {pos.x() / mm, pos.y() / mm, pos.z() / mm, (float)ahit.time()/1000}, // mm, ns
                               {(dim[0]/mm)*(dim[0]/mm), (dim[1]/mm)*(dim[1]/mm), 0.0, 0.0},        // 
-                              algorithmID(),
                               (float)ahit.charge() / 1.0e6, // GeV
                               0.0f};
           rec_hits->push_back(hit);
diff --git a/JugTrack/src/components/ParticlesFromTrackFit.cpp b/JugTrack/src/components/ParticlesFromTrackFit.cpp
index 1cc38de4f0e3c68fdf6b12ae0b649f4776c0f79c..7b8f44923f97ae8182b068269f29fee98f46b9f9 100644
--- a/JugTrack/src/components/ParticlesFromTrackFit.cpp
+++ b/JugTrack/src/components/ParticlesFromTrackFit.cpp
@@ -119,7 +119,7 @@ namespace Jug::Reco {
             }
 
             eic::TrackParameters pars{
-              ID++,
+              {ID++, algorithmID()},
               {parameter[Acts::eBoundLoc0], parameter[Acts::eBoundLoc1]},
               {sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)),
                sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))},
@@ -157,7 +157,7 @@ namespace Jug::Reco {
             }
 
             eic::BasicParticle p{
-                -1,
+                {-1, 0},
                 eic::VectorPolar(   // 3-momentum vector
                   {1.0/std::abs(params[Acts::eBoundQOverP]),    
                    params[Acts::eBoundTheta], params[Acts::eBoundPhi]}),
@@ -166,7 +166,6 @@ namespace Jug::Reco {
                 0,                  // PDG particle code
                 0,                  // status
                 static_cast<int16_t>(std::copysign(1., params[Acts::eBoundQOverP])), // charge
-                algorithmID(),      // source
                 1.                  // weight
             }; // charge
             rec_parts->push_back(p);
@@ -175,7 +174,7 @@ namespace Jug::Reco {
 
       // set our IDs
       for (int i = 0; i < rec_parts->size(); ++i) {
-        (*rec_parts)[i].ID(i);
+        (*rec_parts)[i].ID({i, algorithmID()});
       }
       
       return StatusCode::SUCCESS;