From 3055ed78bb7f892dab3dd441a2e4322204f28c5c Mon Sep 17 00:00:00 2001
From: Felix Weiglhofer <weiglhofer@fias.uni-frankfurt.de>
Date: Mon, 2 Oct 2023 14:44:43 +0000
Subject: [PATCH] algo: Add PODAllocator and PODVector.

---
 algo/CMakeLists.txt                     |   1 -
 algo/base/DigiData.h                    | 179 ++++++++++++++++++++++++
 algo/base/PODVector.h                   |  33 +++++
 algo/base/util/PODAllocator.h           |  42 ++++++
 algo/evbuild/EventBuilder.cxx           |  61 ++++----
 algo/evbuild/EventBuilder.h             |  17 +--
 algo/evbuild/EventbuildChain.cxx        |  59 ++++----
 algo/evbuild/EventbuildChain.h          |   9 +-
 algo/evselector/DigiEventSelector.cxx   |  13 +-
 algo/evselector/DigiEventSelector.h     |  10 +-
 algo/global/Archive.h                   |  11 +-
 algo/global/Reco.cxx                    |  25 ++--
 algo/global/Reco.h                      |   7 +-
 algo/global/RecoResults.cxx             |  12 --
 algo/global/RecoResults.h               |  49 -------
 algo/global/RecoResultsDescriptor.h     |  58 --------
 algo/qa/DigiEventQa.cxx                 |  22 +--
 algo/qa/DigiEventQa.h                   |   9 +-
 algo/test/_GTestDigiEventSelector.cxx   |  38 ++---
 algo/test/_GTestEventBuilder.cxx        |  39 +++---
 algo/unpack/Unpack.cxx                  |  49 ++++---
 algo/unpack/Unpack.h                    |  12 +-
 algo/unpack/UnpackChain.cxx             |  16 +--
 core/data/CMakeLists.txt                |   3 +-
 core/data/sts/CbmStsDigi.h              |  15 +-
 core/data/test/sts/_GTestCbmStsDigi.cxx |  12 +-
 reco/app/cbmreco/main.cxx               |   8 +-
 reco/mq/CbmDevTrigger.cxx               |  16 +--
 reco/mq/CbmDevTrigger.h                 |   3 +-
 reco/tasks/CbmTaskBuildEvents.cxx       |  21 +--
 reco/tasks/CbmTaskBuildEvents.h         |   1 +
 reco/tasks/CbmTaskDigiEventQa.cxx       |   2 +-
 reco/tasks/CbmTaskMakeRecoEvents.h      |   3 +-
 reco/tasks/CbmTaskUnpack.cxx            |   2 +-
 34 files changed, 503 insertions(+), 354 deletions(-)
 create mode 100644 algo/base/DigiData.h
 create mode 100644 algo/base/PODVector.h
 create mode 100644 algo/base/util/PODAllocator.h
 delete mode 100644 algo/global/RecoResults.cxx
 delete mode 100644 algo/global/RecoResults.h
 delete mode 100644 algo/global/RecoResultsDescriptor.h

diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index fa27d8b4c8..f9b85b2af2 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -45,7 +45,6 @@ set(SRCS
   detectors/rich/ReadoutConfig.cxx
   detectors/rich/Unpack.cxx
   global/Archive.cxx
-  global/RecoResults.cxx
   global/Reco.cxx
   qa/DigiEventQa.cxx
   qa/Histo1D.cxx
diff --git a/algo/base/DigiData.h b/algo/base/DigiData.h
new file mode 100644
index 0000000000..da3801d931
--- /dev/null
+++ b/algo/base/DigiData.h
@@ -0,0 +1,179 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_BASE_DIGI_DATA_H
+#define CBM_ALGO_BASE_DIGI_DATA_H
+
+#include "CbmDigiData.h"
+#include "CbmDigiEvent.h"
+
+// TODO: we could also use forward declarations here for Digi types and make this header more lightweight
+#include "CbmBmonDigi.h"
+#include "CbmFsdDigi.h"
+#include "CbmMuchDigi.h"
+#include "CbmPsdDigi.h"
+#include "CbmRichDigi.h"
+#include "CbmStsDigi.h"
+#include "CbmTofDigi.h"
+#include "CbmTrdDigi.h"
+
+#include "PODVector.h"
+
+namespace cbm::algo
+{
+
+  /**
+   * @brief Collection of digis from all detector systems
+   *
+   * Very similar to CbmDigiData. CbmDigiData is meant for file storage,
+   * while this is used for the actual processing. Seperate classes
+   * allow for more flexibility and easier optimization.
+   *
+   * @see CbmDigiData
+   * @note Uses PODVector for storage, so memory is not initialized by default.
+   */
+  struct DigiData {
+    PODVector<CbmStsDigi> fSts;    ///< Unpacked STS digis
+    PODVector<CbmMuchDigi> fMuch;  ///< Unpacked MUCH digis
+    PODVector<CbmTofDigi> fTof;    ///< Unpacked TOF digis
+    PODVector<CbmBmonDigi> fBmon;  ///< Unpacked T0 digis
+    PODVector<CbmTrdDigi> fTrd;    ///< Unpacked TRD digis
+    PODVector<CbmTrdDigi> fTrd2d;  ///< Unpacked TRD2D digis
+    PODVector<CbmRichDigi> fRich;  ///< Unpacked RICH digis
+    PODVector<CbmPsdDigi> fPsd;    ///< Unpacked PSD digis
+    PODVector<CbmFsdDigi> fFsd;    ///< Unpacked FSD digis
+
+    DigiData() = default;
+
+    explicit DigiData(const CbmDigiData& storable)
+      : fSts(ToPODVector(storable.fSts.fDigis))
+      , fMuch(ToPODVector(storable.fMuch.fDigis))
+      , fTof(ToPODVector(storable.fTof.fDigis))
+      , fBmon(ToPODVector(storable.fT0.fDigis))
+      , fTrd(ToPODVector(storable.fTrd.fDigis))
+      , fTrd2d(ToPODVector(storable.fTrd2d.fDigis))
+      , fRich(ToPODVector(storable.fRich.fDigis))
+      , fPsd(ToPODVector(storable.fPsd.fDigis))
+    {
+    }
+
+    /**
+     * @brief Get the number of digis for a given subsystem
+     *
+     * @param system Subsystem to get the number of digis for
+     * @todo Should use fles::Subsystem instead ECbmModuleId
+     */
+    size_t Size(ECbmModuleId system) const
+    {
+      switch (system) {
+        case ECbmModuleId::kSts: return fSts.size();
+        case ECbmModuleId::kMuch: return fMuch.size();
+        case ECbmModuleId::kTof: return fTof.size();
+        case ECbmModuleId::kT0: return fBmon.size();
+        case ECbmModuleId::kTrd: return fTrd.size();
+        case ECbmModuleId::kTrd2d: return fTrd2d.size();
+        case ECbmModuleId::kRich: return fRich.size();
+        case ECbmModuleId::kPsd: return fPsd.size();
+        case ECbmModuleId::kFsd: return fFsd.size();
+        default: throw std::runtime_error("DigiData: Invalid system Id " + ::ToString(system));
+      }
+    }
+
+    /**
+     * @brief Convert to CbmDigiData for file storage
+     *
+     * @note This is a very expensive operation, as it copies all data.
+     */
+    CbmDigiData ToStorable() const
+    {
+      return CbmDigiData {
+        .fT0 =
+          {
+            .fDigis = ToStdVector(fBmon),
+          },
+        .fSts =
+          {
+            .fDigis = ToStdVector(fSts),
+          },
+        .fMuch =
+          {
+            .fDigis = ToStdVector(fMuch),
+          },
+        .fTrd =
+          {
+            .fDigis = ToStdVector(fTrd),
+          },
+        .fTrd2d =
+          {
+            .fDigis = ToStdVector(fTrd2d),
+          },
+        .fTof =
+          {
+            .fDigis = ToStdVector(fTof),
+          },
+        .fPsd =
+          {
+            .fDigis = ToStdVector(fPsd),
+          },
+        .fFsd = {},
+      };
+    }
+  };
+
+  /**
+   * @brief Event data with event number and trigger time
+   *
+   * @see CbmDigitEvent
+   * @note Uses PODVector for storage, so memory is not initialized by default.
+   */
+  struct DigiEvent : public DigiData {
+    uint64_t fNumber;  ///< Event identifier
+    double fTime;      ///< Event trigger time [ns]
+
+    static std::vector<DigiEvent> FromCbmDigiEvents(const std::vector<CbmDigiEvent>& events)
+    {
+      std::vector<DigiEvent> result;
+      result.reserve(events.size());
+      for (const auto& event : events) {
+        result.emplace_back(event);
+      }
+      return result;
+    }
+
+    static std::vector<CbmDigiEvent> ToCbmDigiEvents(const std::vector<DigiEvent>& events)
+    {
+      std::vector<CbmDigiEvent> result;
+      result.reserve(events.size());
+      for (const auto& event : events) {
+        result.emplace_back(event.ToStorable());
+      }
+      return result;
+    }
+
+    DigiEvent() = default;
+
+    explicit DigiEvent(const CbmDigiEvent& storable)
+      : DigiData(storable.fData)
+      , fNumber(storable.fNumber)
+      , fTime(storable.fTime)
+    {
+    }
+
+    /**
+   * @brief Convert to CbmDigiEvent for file storage
+   *
+   * @note This is a very expensive operation, as it copies all data.
+   */
+    CbmDigiEvent ToStorable() const
+    {
+      return CbmDigiEvent {
+        .fData   = DigiData::ToStorable(),
+        .fNumber = fNumber,
+        .fTime   = fTime,
+      };
+    }
+  };
+
+}  // namespace cbm::algo
+
+#endif  // CBM_ALGO_BASE_DIGI_DATA_H
diff --git a/algo/base/PODVector.h b/algo/base/PODVector.h
new file mode 100644
index 0000000000..9d19e03baf
--- /dev/null
+++ b/algo/base/PODVector.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_BASE_POD_VECTOR_H
+#define CBM_ALGO_BASE_POD_VECTOR_H
+
+#include <vector>
+
+#include "util/PODAllocator.h"
+
+namespace cbm::algo
+{
+  /**
+  * @brief PODVector is a std::vector that doesn't initialize its elements.
+  */
+  template<class T>
+  using PODVector = std::vector<T, PODAllocator<T>>;
+
+  template<typename T>
+  std::vector<T> ToStdVector(const PODVector<T>& vec)
+  {
+    return std::vector<T>(vec.begin(), vec.end());
+  }
+
+  template<typename T>
+  PODVector<T> ToPODVector(const std::vector<T>& vec)
+  {
+    return PODVector<T>(vec.begin(), vec.end());
+  }
+
+}  // namespace cbm::algo
+
+#endif  // CBM_ALGO_BASE_POD_VECTOR_H
diff --git a/algo/base/util/PODAllocator.h b/algo/base/util/PODAllocator.h
new file mode 100644
index 0000000000..949be97171
--- /dev/null
+++ b/algo/base/util/PODAllocator.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer], Sebastian Heinemann */
+#ifndef CBM_ALGO_BASE_POD_ALLOCATOR_H
+#define CBM_ALGO_BASE_POD_ALLOCATOR_H
+
+#include <cstdlib>
+
+namespace cbm::algo
+{
+  /**
+  * @brief Allocator for plain old data types.
+  *
+  * Custom allocator for plain old data types (POD) that does not initialize the allocated memory.
+  */
+  template<class T>
+  class PODAllocator {
+  public:
+    // Eventually we should enable this assert, but not all Digis have a trivial constructor yet.
+    // static_assert(std::is_trivially_constructible_v<T>, "PODAllocator only works for POD types");
+
+    // Ensure T has no vtable
+    static_assert(std::is_standard_layout_v<T>, "PODAllocator only works with types with standard layout");
+
+    using value_type = T;
+
+    T* allocate(size_t size) { return static_cast<T*>(std::malloc(size * sizeof(T))); }
+    void deallocate(T* p_t, size_t) { std::free(p_t); }
+
+    template<class... Args>
+    void construct(T* obj, Args&&... args)
+    {
+      if constexpr (sizeof...(args) > 0) new (obj) T(std::forward<Args>(args)...);
+    }
+
+    // Required for std::move
+    bool operator==(const PODAllocator&) const { return true; }
+    bool operator!=(const PODAllocator&) const { return false; }
+  };
+}  // namespace cbm::algo
+
+#endif  // CBM_ALGO_BASE_POD_ALLOCATOR_H
diff --git a/algo/evbuild/EventBuilder.cxx b/algo/evbuild/EventBuilder.cxx
index 253cb8dbf8..30a6e2831f 100644
--- a/algo/evbuild/EventBuilder.cxx
+++ b/algo/evbuild/EventBuilder.cxx
@@ -14,7 +14,7 @@ namespace cbm::algo::evbuild
 {
 
   // -----   Algorithm execution   --------------------------------------------
-  EventBuilder::resultType EventBuilder::operator()(const CbmDigiTimeslice& ts, const vector<double> triggers) const
+  EventBuilder::resultType EventBuilder::operator()(const DigiData& ts, const vector<double> triggers) const
   {
     // --- Output data
     resultType result = {};
@@ -24,23 +24,22 @@ namespace cbm::algo::evbuild
                    [&ts, &result, this](const double& trigger) { return BuildEvent(ts, result.second, trigger); });
 
     EventBuilderMonitorData& monitor = result.second;
-    monitor.fSts.fNum += ts.fData.fSts.fDigis.size();
-    monitor.fRich.fNum += ts.fData.fRich.fDigis.size();
-    monitor.fMuch.fNum += ts.fData.fMuch.fDigis.size();
-    monitor.fTrd.fNum += ts.fData.fTrd.fDigis.size();
-    monitor.fTrd2d.fNum += ts.fData.fTrd2d.fDigis.size();
-    monitor.fTof.fNum += ts.fData.fTof.fDigis.size();
-    monitor.fPsd.fNum += ts.fData.fPsd.fDigis.size();
-    monitor.fFsd.fNum += ts.fData.fFsd.fDigis.size();
-    monitor.fBmon.fNum += ts.fData.fT0.fDigis.size();
+    monitor.fSts.fNum += ts.fSts.size();
+    monitor.fRich.fNum += ts.fRich.size();
+    monitor.fMuch.fNum += ts.fMuch.size();
+    monitor.fTrd.fNum += ts.fTrd.size();
+    monitor.fTrd2d.fNum += ts.fTrd2d.size();
+    monitor.fTof.fNum += ts.fTof.size();
+    monitor.fPsd.fNum += ts.fPsd.size();
+    monitor.fFsd.fNum += ts.fFsd.size();
+    monitor.fBmon.fNum += ts.fBmon.size();
     return result;
   }
 
   // --- Build a single event
-  CbmDigiEvent EventBuilder::BuildEvent(const CbmDigiTimeslice& ts, EventBuilderMonitorData& monitor,
-                                        double trigger) const
+  DigiEvent EventBuilder::BuildEvent(const DigiData& ts, EventBuilderMonitorData& monitor, double trigger) const
   {
-    CbmDigiEvent event;
+    DigiEvent event;
     event.fTime = trigger;
 
     // --- Loop over systems
@@ -53,53 +52,53 @@ namespace cbm::algo::evbuild
       // --- Build the event using trigger window
       switch (system) {
         case ECbmModuleId::kSts: {
-          event.fData.fSts.fDigis = CopyRange(ts.fData.fSts.fDigis, tMin, tMax);
+          event.fSts = CopyRange(ts.fSts, tMin, tMax);
           break;
         }
         case ECbmModuleId::kRich: {
-          event.fData.fRich.fDigis = CopyRange(ts.fData.fRich.fDigis, tMin, tMax);
+          event.fRich = CopyRange(ts.fRich, tMin, tMax);
           break;
         }
         case ECbmModuleId::kMuch: {
-          event.fData.fMuch.fDigis = CopyRange(ts.fData.fMuch.fDigis, tMin, tMax);
+          event.fMuch = CopyRange(ts.fMuch, tMin, tMax);
           break;
         }
         case ECbmModuleId::kTrd: {
-          event.fData.fTrd.fDigis = CopyRange(ts.fData.fTrd.fDigis, tMin, tMax);
+          event.fTrd = CopyRange(ts.fTrd, tMin, tMax);
           break;
         }
         case ECbmModuleId::kTrd2d: {
-          event.fData.fTrd2d.fDigis = CopyRange(ts.fData.fTrd2d.fDigis, tMin, tMax);
+          event.fTrd2d = CopyRange(ts.fTrd2d, tMin, tMax);
           break;
         }
         case ECbmModuleId::kTof: {
-          event.fData.fTof.fDigis = CopyRange(ts.fData.fTof.fDigis, tMin, tMax);
+          event.fTof = CopyRange(ts.fTof, tMin, tMax);
           break;
         }
         case ECbmModuleId::kPsd: {
-          event.fData.fPsd.fDigis = CopyRange(ts.fData.fPsd.fDigis, tMin, tMax);
+          event.fPsd = CopyRange(ts.fPsd, tMin, tMax);
           break;
         }
         case ECbmModuleId::kFsd: {
-          event.fData.fFsd.fDigis = CopyRange(ts.fData.fFsd.fDigis, tMin, tMax);
+          event.fFsd = CopyRange(ts.fFsd, tMin, tMax);
           break;
         }
         case ECbmModuleId::kT0: {
-          event.fData.fT0.fDigis = CopyRange(ts.fData.fT0.fDigis, tMin, tMax);
+          event.fBmon = CopyRange(ts.fBmon, tMin, tMax);
           break;
         }
         default: break;
       }
     }
-    monitor.fSts.fNumInEvents += event.fData.fSts.fDigis.size();
-    monitor.fRich.fNumInEvents += event.fData.fRich.fDigis.size();
-    monitor.fMuch.fNumInEvents += event.fData.fMuch.fDigis.size();
-    monitor.fTrd.fNumInEvents += event.fData.fTrd.fDigis.size();
-    monitor.fTrd2d.fNumInEvents += event.fData.fTrd2d.fDigis.size();
-    monitor.fTof.fNumInEvents += event.fData.fTof.fDigis.size();
-    monitor.fPsd.fNumInEvents += event.fData.fPsd.fDigis.size();
-    monitor.fFsd.fNumInEvents += event.fData.fFsd.fDigis.size();
-    monitor.fBmon.fNumInEvents += event.fData.fT0.fDigis.size();
+    monitor.fSts.fNumInEvents += event.fSts.size();
+    monitor.fRich.fNumInEvents += event.fRich.size();
+    monitor.fMuch.fNumInEvents += event.fMuch.size();
+    monitor.fTrd.fNumInEvents += event.fTrd.size();
+    monitor.fTrd2d.fNumInEvents += event.fTrd2d.size();
+    monitor.fTof.fNumInEvents += event.fTof.size();
+    monitor.fPsd.fNumInEvents += event.fPsd.size();
+    monitor.fFsd.fNumInEvents += event.fFsd.size();
+    monitor.fBmon.fNumInEvents += event.fBmon.size();
     return event;
   }
   // --------------------------------------------------------------------------
diff --git a/algo/evbuild/EventBuilder.h b/algo/evbuild/EventBuilder.h
index 0b62b53e83..c737b12f53 100644
--- a/algo/evbuild/EventBuilder.h
+++ b/algo/evbuild/EventBuilder.h
@@ -6,14 +6,14 @@
 #define CBM_ALGO_EVENTBUILDER_H 1
 
 #include "CbmDefs.h"
-#include "CbmDigiEvent.h"
-#include "CbmDigiTimeslice.h"
 
 #include <algorithm>
+#include <gsl/span>
 #include <map>
 #include <string>
 #include <vector>
 
+#include "DigiData.h"
 #include "EventBuilderConfig.h"
 
 namespace cbm::algo::evbuild
@@ -66,7 +66,7 @@ namespace cbm::algo::evbuild
   class EventBuilder {
 
   public:
-    typedef std::pair<std::vector<CbmDigiEvent>, EventBuilderMonitorData> resultType;
+    typedef std::pair<std::vector<DigiEvent>, EventBuilderMonitorData> resultType;
 
     /** @brief Constructor **/
     EventBuilder(const EventBuilderConfig& config) : fConfig(config) {}
@@ -81,7 +81,7 @@ namespace cbm::algo::evbuild
      ** @param  triggers List of trigger times
      ** @return Vector of constructed events and monitoring data
      **/
-    resultType operator()(const CbmDigiTimeslice& ts, const std::vector<double> triggers) const;
+    resultType operator()(const DigiData& ts, const std::vector<double> triggers) const;
 
 
     /** @brief Info to string **/
@@ -95,7 +95,7 @@ namespace cbm::algo::evbuild
      ** @param  trigger Trigger time
      ** @return Digi event
      **/
-    CbmDigiEvent BuildEvent(const CbmDigiTimeslice& ts, EventBuilderMonitorData& monitor, double trigger) const;
+    DigiEvent BuildEvent(const DigiData& ts, EventBuilderMonitorData& monitor, double trigger) const;
 
 
     /** @brief Copy data objects in a given time interval from the source to the target vector
@@ -115,14 +115,15 @@ namespace cbm::algo::evbuild
      ** previous trigger window. This, however, requires bookkeeping hardly to be realised without
      ** changing the state of the class. I leave this for the future and for bright specialists.
      **/
-    template<typename Data>
-    static typename std::vector<Data> CopyRange(const std::vector<Data>& source, double tMin, double tMax)
+    template<typename Vector>
+    static Vector CopyRange(const Vector& source, double tMin, double tMax)
     {
+      using Data = typename Vector::value_type;
       auto comp1 = [](const Data& obj, double value) { return obj.GetTime() < value; };
       auto comp2 = [](double value, const Data& obj) { return value < obj.GetTime(); };
       auto lower = std::lower_bound(source.begin(), source.end(), tMin, comp1);
       auto upper = std::upper_bound(lower, source.end(), tMax, comp2);
-      return std::vector<Data>(lower, upper);
+      return Vector(lower, upper);
     }
 
 
diff --git a/algo/evbuild/EventbuildChain.cxx b/algo/evbuild/EventbuildChain.cxx
index 07fed8de83..c044dcc56f 100644
--- a/algo/evbuild/EventbuildChain.cxx
+++ b/algo/evbuild/EventbuildChain.cxx
@@ -9,9 +9,10 @@
 #include <sstream>
 #include <string>
 
+#include "DigiData.h"
 #include "evbuild/Config.h"
 
-
+using namespace cbm::algo;
 using namespace cbm::algo::evbuild;
 
 
@@ -29,7 +30,7 @@ EventbuildChain::EventbuildChain(const Config& config)
 
 
 // -----   Run event building on a timeslice   --------------------------------
-std::vector<CbmDigiEvent> EventbuildChain::Run(const CbmDigiTimeslice& timeslice)
+std::vector<DigiEvent> EventbuildChain::Run(const DigiData& timeslice)
 {
 
   // --- Extract the digi time stamps of the trigger detector
@@ -39,10 +40,10 @@ std::vector<CbmDigiEvent> EventbuildChain::Run(const CbmDigiTimeslice& timeslice
   std::vector<double> triggers = fTrigger(digiTimes).first;
 
   // --- Perform event building
-  std::vector<CbmDigiEvent> events = fBuilder(timeslice, triggers).first;
+  std::vector<DigiEvent> events = fBuilder(timeslice, triggers).first;
 
   // --- Apply event selector
-  auto notSelected = [&](CbmDigiEvent& ev) { return !(fSelector(ev)); };
+  auto notSelected = [&](DigiEvent& ev) { return !(fSelector(ev)); };
   auto removeIt    = std::remove_if(events.begin(), events.end(), notSelected);
   events.erase(removeIt, events.end());
 
@@ -72,63 +73,63 @@ void EventbuildChain::Status() const
 
 
 // -----   Get digi times from CbmDigiTimeslice   -----------------------------
-std::vector<double> EventbuildChain::GetDigiTimes(const CbmDigiTimeslice& timeslice, ECbmModuleId system)
+std::vector<double> EventbuildChain::GetDigiTimes(const DigiData& timeslice, ECbmModuleId system)
 {
   std::vector<double> result;
   switch (system) {
     case ECbmModuleId::kSts: {
-      result.resize(timeslice.fData.fSts.fDigis.size());
-      auto it1 = timeslice.fData.fSts.fDigis.begin();
-      auto it2 = timeslice.fData.fSts.fDigis.end();
+      result.resize(timeslice.fSts.size());
+      auto it1 = timeslice.fSts.begin();
+      auto it2 = timeslice.fSts.end();
       std::transform(it1, it2, result.begin(), [](const CbmStsDigi& digi) { return digi.GetTime(); });
       break;
     }
     case ECbmModuleId::kRich: {
-      result.resize(timeslice.fData.fRich.fDigis.size());
-      auto it1 = timeslice.fData.fRich.fDigis.begin();
-      auto it2 = timeslice.fData.fRich.fDigis.end();
+      result.resize(timeslice.fRich.size());
+      auto it1 = timeslice.fRich.begin();
+      auto it2 = timeslice.fRich.end();
       std::transform(it1, it2, result.begin(), [](const CbmRichDigi& digi) { return digi.GetTime(); });
       break;
     }
     case ECbmModuleId::kMuch: {
-      result.resize(timeslice.fData.fMuch.fDigis.size());
-      auto it1 = timeslice.fData.fMuch.fDigis.begin();
-      auto it2 = timeslice.fData.fMuch.fDigis.end();
+      result.resize(timeslice.fMuch.size());
+      auto it1 = timeslice.fMuch.begin();
+      auto it2 = timeslice.fMuch.end();
       std::transform(it1, it2, result.begin(), [](const CbmMuchDigi& digi) { return digi.GetTime(); });
       break;
     }
     case ECbmModuleId::kTrd: {
-      result.resize(timeslice.fData.fTrd.fDigis.size());
-      auto it1 = timeslice.fData.fTrd.fDigis.begin();
-      auto it2 = timeslice.fData.fTrd.fDigis.end();
+      result.resize(timeslice.fTrd.size());
+      auto it1 = timeslice.fTrd.begin();
+      auto it2 = timeslice.fTrd.end();
       std::transform(it1, it2, result.begin(), [](const CbmTrdDigi& digi) { return digi.GetTime(); });
       break;
     }
     case ECbmModuleId::kTof: {
-      result.resize(timeslice.fData.fTof.fDigis.size());
-      auto it1 = timeslice.fData.fTof.fDigis.begin();
-      auto it2 = timeslice.fData.fTof.fDigis.end();
+      result.resize(timeslice.fTof.size());
+      auto it1 = timeslice.fTof.begin();
+      auto it2 = timeslice.fTof.end();
       std::transform(it1, it2, result.begin(), [](const CbmTofDigi& digi) { return digi.GetTime(); });
       break;
     }
     case ECbmModuleId::kPsd: {
-      result.resize(timeslice.fData.fPsd.fDigis.size());
-      auto it1 = timeslice.fData.fPsd.fDigis.begin();
-      auto it2 = timeslice.fData.fPsd.fDigis.end();
+      result.resize(timeslice.fPsd.size());
+      auto it1 = timeslice.fPsd.begin();
+      auto it2 = timeslice.fPsd.end();
       std::transform(it1, it2, result.begin(), [](const CbmPsdDigi& digi) { return digi.GetTime(); });
       break;
     }
     case ECbmModuleId::kFsd: {
-      result.resize(timeslice.fData.fFsd.fDigis.size());
-      auto it1 = timeslice.fData.fFsd.fDigis.begin();
-      auto it2 = timeslice.fData.fFsd.fDigis.end();
+      result.resize(timeslice.fFsd.size());
+      auto it1 = timeslice.fFsd.begin();
+      auto it2 = timeslice.fFsd.end();
       std::transform(it1, it2, result.begin(), [](const CbmFsdDigi& digi) { return digi.GetTime(); });
       break;
     }
     case ECbmModuleId::kT0: {
-      result.resize(timeslice.fData.fT0.fDigis.size());
-      auto it1 = timeslice.fData.fT0.fDigis.begin();
-      auto it2 = timeslice.fData.fT0.fDigis.end();
+      result.resize(timeslice.fBmon.size());
+      auto it1 = timeslice.fBmon.begin();
+      auto it2 = timeslice.fBmon.end();
       std::transform(it1, it2, result.begin(), [](const CbmTofDigi& digi) { return digi.GetTime(); });
       break;
     }
diff --git a/algo/evbuild/EventbuildChain.h b/algo/evbuild/EventbuildChain.h
index ae35c95bc4..728e55541e 100644
--- a/algo/evbuild/EventbuildChain.h
+++ b/algo/evbuild/EventbuildChain.h
@@ -15,7 +15,10 @@
 #include "SubChain.h"
 
 
-class CbmDigiTimeslice;
+namespace cbm::algo
+{
+  class DigiData;
+}
 
 namespace cbm::algo::evbuild
 {
@@ -39,7 +42,7 @@ namespace cbm::algo::evbuild
     EventbuildChain(const Config& config);
 
     /** @brief Execution **/
-    std::vector<CbmDigiEvent> Run(const CbmDigiTimeslice&);
+    std::vector<DigiEvent> Run(const DigiData&);
 
     /** @brief Status info to logger **/
     void Status() const;
@@ -58,7 +61,7 @@ namespace cbm::algo::evbuild
      ** @param system Detector system (enum ECbmModuleId)
      ** @return Vector of digi times for the specified system
      **/
-    std::vector<double> GetDigiTimes(const CbmDigiTimeslice& timeslice, ECbmModuleId system);
+    std::vector<double> GetDigiTimes(const DigiData& timeslice, ECbmModuleId system);
   };
 
 }  // namespace cbm::algo::evbuild
diff --git a/algo/evselector/DigiEventSelector.cxx b/algo/evselector/DigiEventSelector.cxx
index 2b7e16dc8e..a4b63a49c8 100644
--- a/algo/evselector/DigiEventSelector.cxx
+++ b/algo/evselector/DigiEventSelector.cxx
@@ -8,6 +8,7 @@
 
 #include "tof/Config.h"
 
+#include <gsl/span>
 #include <iterator>
 #include <unordered_map>
 #include <unordered_set>
@@ -19,12 +20,12 @@ namespace cbm::algo::evbuild
 {
 
   // -----   Test one digi event   --------------------------------------------
-  bool DigiEventSelector::operator()(const CbmDigiEvent& event) const
+  bool DigiEventSelector::operator()(const DigiEvent& event) const
   {
 
     // --- Test number of digis per detector system
     for (auto& entry : fConfig.fMinNumDigis) {
-      if (!(event.fData.Size(entry.first) >= entry.second)) {
+      if (!(event.Size(entry.first) >= entry.second)) {
         return false;
         break;
       }
@@ -35,10 +36,10 @@ namespace cbm::algo::evbuild
       if (entry.second == 0) continue;
       switch (entry.first) {
         case ECbmModuleId::kSts:
-          if (!CheckStsStations(event.fData.fSts.fDigis, entry.second)) return false;
+          if (!CheckStsStations(event.fSts, entry.second)) return false;
           break;
         case ECbmModuleId::kTof:
-          if (!CheckTofLayers(event.fData.fTof.fDigis, entry.second)) return false;
+          if (!CheckTofLayers(event.fTof, entry.second)) return false;
           break;
         default:
           throw std::runtime_error("Number of layers for " + ::ToString(entry.first) + " is not implemented");
@@ -52,7 +53,7 @@ namespace cbm::algo::evbuild
 
 
   // -----   Check number of STS stations   -----------------------------------
-  bool DigiEventSelector::CheckStsStations(const std::vector<CbmStsDigi>& digis, size_t minNum) const
+  bool DigiEventSelector::CheckStsStations(gsl::span<const CbmStsDigi> digis, size_t minNum) const
   {
 
     // A station is considered activated if it has at least one activated module. A module is considered
@@ -89,7 +90,7 @@ namespace cbm::algo::evbuild
 
 
   // -----   Check number of TOF layers   -------------------------------------
-  bool DigiEventSelector::CheckTofLayers(const std::vector<CbmTofDigi>& digis, size_t minNum) const
+  bool DigiEventSelector::CheckTofLayers(gsl::span<const CbmTofDigi> digis, size_t minNum) const
   {
     // A station is considered activated if it has at least one activated RPC. An RPC is considered
     // activated if it has at least one activated strip. A strip is considered activated
diff --git a/algo/evselector/DigiEventSelector.h b/algo/evselector/DigiEventSelector.h
index 4155c7eb86..567330754b 100644
--- a/algo/evselector/DigiEventSelector.h
+++ b/algo/evselector/DigiEventSelector.h
@@ -5,11 +5,11 @@
 #ifndef CBM_ALGO_DIGIEVENTSELECTOR_H
 #define CBM_ALGO_DIGIEVENTSELECTOR_H 1
 
-#include "CbmDigiEvent.h"
-
 #include <cstdint>
+#include <gsl/span>
 #include <map>
 
+#include "DigiData.h"
 #include "DigiEventSelectorConfig.h"
 
 namespace cbm::algo::evbuild
@@ -46,7 +46,7 @@ namespace cbm::algo::evbuild
      ** @param event DigiEvent
      ** @return true if event satisfies the criteria; else false
      **/
-    bool operator()(const CbmDigiEvent& event) const;
+    bool operator()(const DigiEvent& event) const;
 
 
     /** @brief Info to string **/
@@ -59,14 +59,14 @@ namespace cbm::algo::evbuild
      ** @param minNum Requested minimum of active STS stations
      ** @return True if the number of active STS layers is above the threshold
      **/
-    bool CheckStsStations(const std::vector<CbmStsDigi>& digis, size_t minNum) const;
+    bool CheckStsStations(gsl::span<const CbmStsDigi> digis, size_t minNum) const;
 
     /** @brief Test for the number of TOF layers
      ** @param digis Vector of TOF digis
      ** @param minNum Requested minimum of active TOF layers
      ** @return True if the number of active TOF layers is above the threshold
      **/
-    bool CheckTofLayers(const std::vector<CbmTofDigi>& digis, size_t minNum) const;
+    bool CheckTofLayers(gsl::span<const CbmTofDigi> digis, size_t minNum) const;
 
 
   private:                            // members
diff --git a/algo/global/Archive.h b/algo/global/Archive.h
index ffb683dbc2..cc33a83745 100644
--- a/algo/global/Archive.h
+++ b/algo/global/Archive.h
@@ -4,6 +4,8 @@
 #ifndef CBM_ALGO_GLOBAL_ARCHIVE_H
 #define CBM_ALGO_GLOBAL_ARCHIVE_H
 
+#include "CbmDigiEvent.h"
+
 #include "MicrosliceDescriptor.hpp"
 
 #include <boost/serialization/access.hpp>
@@ -13,7 +15,6 @@
 #include <vector>
 
 #include "ArchiveDescriptor.h"
-#include "RecoResults.h"
 #include "compat/Filesystem.h"
 
 namespace cbm::algo
@@ -38,12 +39,14 @@ namespace cbm::algo
 
     const ArchiveDescriptor& Descriptor() const { return fDescriptor; }
 
-    std::vector<RecoResults>& TimesliceResults() { return fTimesliceResults; }
-    const std::vector<RecoResults>& TimesliceResults() const { return fTimesliceResults; }
+    std::vector<CbmDigiEvent>& TimesliceResults() { return fTimesliceResults; }
+    const std::vector<CbmDigiEvent>& TimesliceResults() const { return fTimesliceResults; }
 
   private:
     ArchiveDescriptor fDescriptor;
-    std::vector<RecoResults> fTimesliceResults;
+    // TODO: Need a better storage class here, that can also store Hits, ...
+    // Will be changed with the rework of storage
+    std::vector<CbmDigiEvent> fTimesliceResults;
 
     friend class boost::serialization::access;
     template<class Archive>
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index f47691b519..3bd91a3b0c 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -114,12 +114,12 @@ RecoResults Reco::Run(const fles::Timeslice& ts)
   }
 
   // --- Digi event building
-  std::vector<CbmDigiEvent> events;
+  std::vector<DigiEvent> events;
   if (Opts().HasStep(Step::DigiTrigger)) events = fEventBuild->Run(unpackResult.first);
 
   sts::HitfinderMonitor stsHitfinderMonitor;
   if (Opts().HasStep(Step::LocalReco) && Opts().HasDetector(fles::Subsystem::STS))
-    stsHitfinderMonitor = fStsHitFinder(unpackResult.first.fData.fSts.fDigis);
+    stsHitfinderMonitor = fStsHitFinder(unpackResult.first.fSts);
 
   xpu::timings ts_times = xpu::pop_timer();
 
@@ -128,8 +128,8 @@ RecoResults Reco::Run(const fles::Timeslice& ts)
 
   PrintTimings(ts_times);
 
-  RecoResults results(RecoResultsDescriptor(Opts(), Params()));
-  results.Events() = std::move(events);
+  RecoResults results;
+  results.events = std::move(events);
 
   return results;
 }
@@ -159,8 +159,7 @@ void Reco::PrintTimings(xpu::timings& timings)
   }
 }
 
-void Reco::QueueUnpackerMetrics(const fles::Timeslice& ts, const UnpackMonitorData& monitor,
-                                const CbmDigiTimeslice& digis)
+void Reco::QueueUnpackerMetrics(const fles::Timeslice& ts, const UnpackMonitorData& monitor, const DigiData& digis)
 {
   if (!HasMonitor()) return;
 
@@ -172,13 +171,13 @@ void Reco::QueueUnpackerMetrics(const fles::Timeslice& ts, const UnpackMonitorDa
   size_t tsDelta = ts.index() - prevTsId;
   prevTsId       = ts.index();
 
-  auto& stsDigis   = digis.fData.fSts.fDigis;
-  auto& muchDigis  = digis.fData.fMuch.fDigis;
-  auto& tofDigis   = digis.fData.fTof.fDigis;
-  auto& bmonDigis  = digis.fData.fT0.fDigis;
-  auto& trdDigis   = digis.fData.fTrd.fDigis;
-  auto& trd2dDigis = digis.fData.fTrd2d.fDigis;
-  auto& richDigis  = digis.fData.fRich.fDigis;
+  auto& stsDigis   = digis.fSts;
+  auto& muchDigis  = digis.fMuch;
+  auto& tofDigis   = digis.fTof;
+  auto& bmonDigis  = digis.fBmon;
+  auto& trdDigis   = digis.fTrd;
+  auto& trd2dDigis = digis.fTrd2d;
+  auto& richDigis  = digis.fRich;
 
   size_t nDigisTotal = sizeBytes(stsDigis) + sizeBytes(muchDigis) + sizeBytes(tofDigis) + sizeBytes(bmonDigis)
                        + sizeBytes(trdDigis) + sizeBytes(trd2dDigis) + sizeBytes(richDigis);
diff --git a/algo/global/Reco.h b/algo/global/Reco.h
index 1b64462ac9..5cb1e71169 100644
--- a/algo/global/Reco.h
+++ b/algo/global/Reco.h
@@ -7,7 +7,6 @@
 #include <xpu/host.h>
 
 #include "EventbuildChain.h"
-#include "RecoResults.h"
 #include "SubChain.h"
 #include "UnpackChain.h"
 #include "sts/HitfinderChain.h"
@@ -21,6 +20,10 @@ namespace cbm::algo
 {
   class Options;
 
+  struct RecoResults {
+    std::vector<DigiEvent> events;
+  };
+
   class Reco : SubChain {
   public:
     Reco();
@@ -51,7 +54,7 @@ namespace cbm::algo
 
     void Validate(const Options& opts);
 
-    void QueueUnpackerMetrics(const fles::Timeslice&, const UnpackMonitorData&, const CbmDigiTimeslice&);
+    void QueueUnpackerMetrics(const fles::Timeslice&, const UnpackMonitorData&, const DigiData&);
     void QueueStsRecoMetrics(const sts::HitfinderMonitor&);
   };
 }  // namespace cbm::algo
diff --git a/algo/global/RecoResults.cxx b/algo/global/RecoResults.cxx
deleted file mode 100644
index f2d8d1de1f..0000000000
--- a/algo/global/RecoResults.cxx
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Felix Weiglhofer [committer] */
-#include "RecoResults.h"
-
-#include "CbmDigiEvent.h"
-
-using namespace cbm::algo;
-
-RecoResults::RecoResults(RecoResultsDescriptor descriptor) : fDescriptor(descriptor) {}
-RecoResults::RecoResults() {}
-RecoResults::~RecoResults() {}
diff --git a/algo/global/RecoResults.h b/algo/global/RecoResults.h
deleted file mode 100644
index 95e6c06772..0000000000
--- a/algo/global/RecoResults.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Felix Weiglhofer [committer] */
-#ifndef CBM_ALGO_GLOBAL_RECO_RESULTS_H
-#define CBM_ALGO_GLOBAL_RECO_RESULTS_H
-
-#include <boost/serialization/access.hpp>
-
-#include <vector>
-
-#include "RecoResultsDescriptor.h"
-
-class CbmStsDigi;
-class CbmDigiEvent;
-namespace cbm::algo::sts
-{
-  using Digi = CbmStsDigi;
-}
-
-namespace cbm::algo
-{
-  class RecoResults {
-
-  public:
-    // Place ctor / dtor in cxx, so that we can forward-declare the data classes and keep this header small.
-    RecoResults(RecoResultsDescriptor descriptor);
-    ~RecoResults();
-
-    const RecoResultsDescriptor& Descriptor() const { return fDescriptor; }
-    const std::vector<CbmDigiEvent>& Events() const { return fEvents; }
-    std::vector<CbmDigiEvent>& Events() { return fEvents; }
-
-  private:
-    RecoResultsDescriptor fDescriptor;
-    std::vector<CbmDigiEvent> fEvents;
-
-    friend class boost::serialization::access;
-
-    RecoResults();
-
-    template<class Archive>
-    void serialize(Archive& ar, const unsigned int /*version*/)
-    {
-      ar& fEvents;
-    }
-  };
-}  // namespace cbm::algo
-
-#endif
diff --git a/algo/global/RecoResultsDescriptor.h b/algo/global/RecoResultsDescriptor.h
deleted file mode 100644
index 715b7f5653..0000000000
--- a/algo/global/RecoResultsDescriptor.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Felix Weiglhofer [committer] */
-#ifndef CBM_ALGO_GLOBAL_RECO_RESULTS_DESCRIPTOR_H
-#define CBM_ALGO_GLOBAL_RECO_RESULTS_DESCRIPTOR_H
-
-#include <boost/serialization/access.hpp>
-#include <boost/serialization/version.hpp>
-
-#include "Options.h"
-#include "RecoParams.h"
-#include "config/Yaml.h"
-
-namespace cbm::algo
-{
-  class RecoResults;
-}
-
-namespace cbm::algo
-{
-  class RecoResultsDescriptor {
-  public:
-    RecoResultsDescriptor(Options options, RecoParams params) : fOptions(options), fParams(params) {}
-
-    const RecoParams& Params() const { return fParams; }
-    const Options& Opts() const { return fOptions; }
-
-  private:  // members
-    Options fOptions;
-    RecoParams fParams;
-
-  private:  // serialization
-    friend class boost::serialization::access;
-    friend class RecoResults;
-
-    RecoResultsDescriptor() = default;
-
-    template<class Archive>
-    void save(Archive& ar, const unsigned int /*version*/) const
-    {
-      ar& fOptions;
-      std::string yaml = config::Dump()(fParams);
-      ar& yaml;
-    }
-
-    template<class Archive>
-    void load(Archive& ar, const unsigned int /*version*/)
-    {
-      ar& fOptions;
-      std::string yaml;
-      ar& yaml;
-      auto node = YAML::Load(yaml);
-      fParams   = config::Read<RecoParams>(node);
-    }
-  };
-}  // namespace cbm::algo
-
-#endif  // CBM_ALGO_GLOBAL_RECO_RESULTS_DESCRIPTOR_H
diff --git a/algo/qa/DigiEventQa.cxx b/algo/qa/DigiEventQa.cxx
index 7fb1e011e3..25f9ed5668 100644
--- a/algo/qa/DigiEventQa.cxx
+++ b/algo/qa/DigiEventQa.cxx
@@ -15,7 +15,7 @@ namespace cbm::algo::evbuild
 {
 
   // ---   Execution   --------------------------------------------------------
-  DigiEventQaData DigiEventQa::operator()(const vector<CbmDigiEvent>& events) const
+  DigiEventQaData DigiEventQa::operator()(const vector<DigiEvent>& events) const
   {
 
     // --- Instantiate return object
@@ -40,18 +40,18 @@ namespace cbm::algo::evbuild
 
 
   // ---  QA: digi time within event   ----------------------------------------
-  void DigiEventQa::QaDigiTimeInEvent(const CbmDigiEvent& event, ECbmModuleId system, Histo1D& histo) const
+  void DigiEventQa::QaDigiTimeInEvent(const DigiEvent& event, ECbmModuleId system, Histo1D& histo) const
   {
     switch (system) {
-      case ECbmModuleId::kT0: FillDeltaT<CbmBmonDigi>(event.fData.fT0.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kSts: FillDeltaT<CbmStsDigi>(event.fData.fSts.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kMuch: FillDeltaT<CbmMuchDigi>(event.fData.fMuch.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kRich: FillDeltaT<CbmRichDigi>(event.fData.fRich.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kTrd: FillDeltaT<CbmTrdDigi>(event.fData.fTrd.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kTrd2d: FillDeltaT<CbmTrdDigi>(event.fData.fTrd2d.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kTof: FillDeltaT<CbmTofDigi>(event.fData.fTof.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kPsd: FillDeltaT<CbmPsdDigi>(event.fData.fPsd.fDigis, event.fTime, histo); break;
-      case ECbmModuleId::kFsd: FillDeltaT<CbmFsdDigi>(event.fData.fFsd.fDigis, event.fTime, histo); break;
+      case ECbmModuleId::kT0: FillDeltaT<CbmBmonDigi>(event.fBmon, event.fTime, histo); break;
+      case ECbmModuleId::kSts: FillDeltaT<CbmStsDigi>(event.fSts, event.fTime, histo); break;
+      case ECbmModuleId::kMuch: FillDeltaT<CbmMuchDigi>(event.fMuch, event.fTime, histo); break;
+      case ECbmModuleId::kRich: FillDeltaT<CbmRichDigi>(event.fRich, event.fTime, histo); break;
+      case ECbmModuleId::kTrd: FillDeltaT<CbmTrdDigi>(event.fTrd, event.fTime, histo); break;
+      case ECbmModuleId::kTrd2d: FillDeltaT<CbmTrdDigi>(event.fTrd2d, event.fTime, histo); break;
+      case ECbmModuleId::kTof: FillDeltaT<CbmTofDigi>(event.fTof, event.fTime, histo); break;
+      case ECbmModuleId::kPsd: FillDeltaT<CbmPsdDigi>(event.fPsd, event.fTime, histo); break;
+      case ECbmModuleId::kFsd: FillDeltaT<CbmFsdDigi>(event.fFsd, event.fTime, histo); break;
       default: throw std::runtime_error("DigiEventQa: Invalid system Id " + ::ToString(system));
     }
   }
diff --git a/algo/qa/DigiEventQa.h b/algo/qa/DigiEventQa.h
index eb58a89471..64ee77f58e 100644
--- a/algo/qa/DigiEventQa.h
+++ b/algo/qa/DigiEventQa.h
@@ -6,11 +6,12 @@
 #define ALGO_QA_DIGIEVENTQA_H 1
 
 #include "CbmDefs.h"
-#include "CbmDigiEvent.h"
 
+#include <gsl/span>
 #include <map>
 #include <vector>
 
+#include "DigiData.h"
 #include "Histo1D.h"
 #include "evbuild/EventBuilderConfig.h"
 
@@ -91,7 +92,7 @@ namespace cbm::algo::evbuild
      ** @param events Vector of DigiEvents to analyse
      ** @return QA data object
      **/
-    DigiEventQaData operator()(const std::vector<CbmDigiEvent>& events) const;
+    DigiEventQaData operator()(const std::vector<DigiEvent>& events) const;
 
     /** @brief Info to string **/
     std::string ToString() const;
@@ -106,7 +107,7 @@ namespace cbm::algo::evbuild
      ** The templated class is required to implement the method double GetTime().
      **/
     template<class Digi>
-    void FillDeltaT(const std::vector<Digi>& digis, double eventTime, Histo1D& histo) const
+    void FillDeltaT(gsl::span<const Digi> digis, double eventTime, Histo1D& histo) const
     {
       for (const Digi& digi : digis)
         histo.Add(digi.GetTime() - eventTime);
@@ -117,7 +118,7 @@ namespace cbm::algo::evbuild
      ** @param eventTime  Time of event
      ** @param histo  Histogram to be filled
      **/
-    void QaDigiTimeInEvent(const CbmDigiEvent& event, ECbmModuleId system, Histo1D& histo) const;
+    void QaDigiTimeInEvent(const DigiEvent& event, ECbmModuleId system, Histo1D& histo) const;
 
 
   private:  // members
diff --git a/algo/test/_GTestDigiEventSelector.cxx b/algo/test/_GTestDigiEventSelector.cxx
index 32e291a54a..5beb0fe2a2 100644
--- a/algo/test/_GTestDigiEventSelector.cxx
+++ b/algo/test/_GTestDigiEventSelector.cxx
@@ -13,6 +13,8 @@
 #include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
 
+using namespace cbm::algo;
+
 TEST(_GTestDigiEventSelector, CheckDigiEventSelectorAlgorithmSimple)
 {
   SCOPED_TRACE("CheckDigiEventSelectorAlgorithSimple");
@@ -28,25 +30,27 @@ TEST(_GTestDigiEventSelector, CheckDigiEventSelectorAlgorithmSimple)
   size_t nTof   = 7;
   size_t nPsd   = 8;
   size_t nFsd   = 9;
-  CbmDigiEvent event;
+
+  DigiEvent event;
   for (size_t i = 0; i < nBmon; i++)
-    event.fData.fT0.fDigis.push_back(CbmBmonDigi());
+    event.fBmon.push_back(CbmBmonDigi());
   for (size_t i = 0; i < nSts; i++)
-    event.fData.fSts.fDigis.push_back(CbmStsDigi());
+    event.fSts.push_back(CbmStsDigi());
   for (size_t i = 0; i < nMuch; i++)
-    event.fData.fMuch.fDigis.push_back(CbmMuchDigi());
+    event.fMuch.push_back(CbmMuchDigi());
   for (size_t i = 0; i < nRich; i++)
-    event.fData.fRich.fDigis.push_back(CbmRichDigi());
+    event.fRich.push_back(CbmRichDigi());
   for (size_t i = 0; i < nTrd; i++)
-    event.fData.fTrd.fDigis.push_back(CbmTrdDigi());
+    event.fTrd.push_back(CbmTrdDigi());
   for (size_t i = 0; i < nTrd2d; i++)
-    event.fData.fTrd2d.fDigis.push_back(CbmTrdDigi());
+    event.fTrd2d.push_back(CbmTrdDigi());
   for (size_t i = 0; i < nTof; i++)
-    event.fData.fTof.fDigis.push_back(CbmTofDigi());
+    event.fTof.push_back(CbmTofDigi());
   for (size_t i = 0; i < nPsd; i++)
-    event.fData.fPsd.fDigis.push_back(CbmPsdDigi());
+    event.fPsd.push_back(CbmPsdDigi());
   for (size_t i = 0; i < nFsd; i++)
-    event.fData.fFsd.fDigis.push_back(CbmFsdDigi());
+    event.fFsd.push_back(CbmFsdDigi());
+
 
   YAML::Node node;
   node["minDigis"][ToString(ECbmModuleId::kT0)]    = nBmon;
@@ -147,7 +151,7 @@ TEST(_GTestDigiEventSelector, CheckDigiEventSelectorAlgorithmSimple)
 
       for (uint numStations = 1; numStations < maxStsStations; numStations++) {
         //Prepare input
-        CbmDigiEvent eventIn;
+        DigiEvent eventIn;
         //Produce digi pairs with valid addresses
         for (uint station = 0; station < numStations; station++) {
           for (uint module = 0; module < maxStsModules; module++) {
@@ -155,12 +159,12 @@ TEST(_GTestDigiEventSelector, CheckDigiEventSelectorAlgorithmSimple)
               for (uint halfladder = 0; halfladder <= 1; halfladder++) {
                 //add digis pairs
                 int32_t address = CbmStsAddress::GetAddress(station, ladder, halfladder, module);
-                eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(address, 0, 0.0, 0.0));
-                eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(address, 1024, 0.0, 0.0));  //other side channel
+                eventIn.fSts.push_back(CbmStsDigi(address, 0, 0.0, 0.0));
+                eventIn.fSts.push_back(CbmStsDigi(address, 1024, 0.0, 0.0));  //other side channel
 
                 //add digis from next station without partner for intentionally failed test
                 int32_t nextAddress = CbmStsAddress::GetAddress(numStations, ladder, 0, module);
-                eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(nextAddress, 1024, 0.0, 0.0));
+                eventIn.fSts.push_back(CbmStsDigi(nextAddress, 1024, 0.0, 0.0));
               }
             }
           }
@@ -189,7 +193,7 @@ TEST(_GTestDigiEventSelector, CheckDigiEventSelectorAlgorithmSimple)
     // --- Test number of TOF layers
     {
       //Prepare input
-      CbmDigiEvent eventIn;
+      DigiEvent eventIn;
 
       const uint8_t numSmTypes         = 10;
       const uint8_t numRpc[numSmTypes] = {5, 3, 5, 1, 1, 1, 2, 2, 1, 2};
@@ -202,8 +206,8 @@ TEST(_GTestDigiEventSelector, CheckDigiEventSelectorAlgorithmSimple)
 
             uint32_t addrFront = CbmTofAddress::GetUniqueAddress(sm, rpc, 0, 0, smType, 0);
             uint32_t addrBack  = CbmTofAddress::GetUniqueAddress(sm, rpc, 0, 1, smType, 0);
-            eventIn.fData.fTof.fDigis.push_back(CbmTofDigi(addrFront, 0.0, 0.0));
-            eventIn.fData.fTof.fDigis.push_back(CbmTofDigi(addrBack, 0.0, 0.0));
+            eventIn.fTof.push_back(CbmTofDigi(addrFront, 0.0, 0.0));
+            eventIn.fTof.push_back(CbmTofDigi(addrBack, 0.0, 0.0));
 
             const int32_t TofStationId = cbm::algo::tof::Config::GetTofTrackingStation(smType, sm, rpc);
             setTofStation.insert(TofStationId);
diff --git a/algo/test/_GTestEventBuilder.cxx b/algo/test/_GTestEventBuilder.cxx
index 3af5eec0bc..9e30ce8f91 100644
--- a/algo/test/_GTestEventBuilder.cxx
+++ b/algo/test/_GTestEventBuilder.cxx
@@ -8,6 +8,8 @@
 #include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
 
+using namespace cbm::algo;
+
 TEST(_GTestEventBuilder, CheckEventBuilderAlgorithmSimple)
 {
   SCOPED_TRACE("CheckEventBuilderAlgorithSimple");
@@ -25,21 +27,20 @@ TEST(_GTestEventBuilder, CheckEventBuilderAlgorithmSimple)
   cbm::algo::evbuild::EventBuilderConfig config(configNode);
   cbm::algo::evbuild::EventBuilder evbuild(config);
 
-  CbmDigiTimeslice tsIn;
+  DigiData tsIn;
   const uint nInput         = 1000;
   const double inputSpacing = 10.0;
 
   //Produce digis with some arbitrary but valid addresses
   for (uint i = 0; i < nInput; i++) {
-    tsIn.fData.fMuch.fDigis.push_back(CbmMuchDigi(1111, 1, i * inputSpacing));
-    tsIn.fData.fSts.fDigis.push_back(CbmStsDigi(268502050, 1, i * inputSpacing, 1.0));
-    tsIn.fData.fTof.fDigis.push_back(CbmTofDigi(1111, i * inputSpacing, 1.0));
-    tsIn.fData.fTrd.fDigis.push_back(
-      CbmTrdDigi(475, 37, 150, i * inputSpacing, CbmTrdDigi::eTriggerType::kBeginTriggerTypes, 0));
-    tsIn.fData.fRich.fDigis.push_back(CbmRichDigi(1111, i * inputSpacing, 1.0));
-    tsIn.fData.fPsd.fDigis.push_back(CbmPsdDigi(1111, i * inputSpacing, 1.0));
-    tsIn.fData.fFsd.fDigis.push_back(CbmFsdDigi(1111, i * inputSpacing, 1.0));
-    tsIn.fData.fT0.fDigis.push_back(CbmBmonDigi(1111, i * inputSpacing, 1.0));
+    tsIn.fMuch.push_back(CbmMuchDigi(1111, 1, i * inputSpacing));
+    tsIn.fSts.push_back(CbmStsDigi(268502050, 1, i * inputSpacing, 1.0));
+    tsIn.fTof.push_back(CbmTofDigi(1111, i * inputSpacing, 1.0));
+    tsIn.fTrd.push_back(CbmTrdDigi(475, 37, 150, i * inputSpacing, CbmTrdDigi::eTriggerType::kBeginTriggerTypes, 0));
+    tsIn.fRich.push_back(CbmRichDigi(1111, i * inputSpacing, 1.0));
+    tsIn.fPsd.push_back(CbmPsdDigi(1111, i * inputSpacing, 1.0));
+    tsIn.fFsd.push_back(CbmFsdDigi(1111, i * inputSpacing, 1.0));
+    tsIn.fBmon.push_back(CbmBmonDigi(1111, i * inputSpacing, 1.0));
   }
 
 
@@ -52,20 +53,20 @@ TEST(_GTestEventBuilder, CheckEventBuilderAlgorithmSimple)
   }
 
   cbm::algo::evbuild::EventBuilder::resultType result  = evbuild(tsIn, triggerIn);
-  std::vector<CbmDigiEvent>& eventsOut                 = result.first;
+  std::vector<DigiEvent>& eventsOut                    = result.first;
   cbm::algo::evbuild::EventBuilderMonitorData& monitor = result.second;
 
   EXPECT_EQ(eventsOut.size(), nTrigger);
 
   for (uint i = 0; i < eventsOut.size(); i++) {
-    EXPECT_EQ(eventsOut[i].fData.fMuch.fDigis.size(), 9);
-    EXPECT_EQ(eventsOut[i].fData.fSts.fDigis.size(), 9);
-    EXPECT_EQ(eventsOut[i].fData.fTof.fDigis.size(), 9);
-    EXPECT_EQ(eventsOut[i].fData.fTrd.fDigis.size(), 9);
-    EXPECT_EQ(eventsOut[i].fData.fRich.fDigis.size(), 9);
-    EXPECT_EQ(eventsOut[i].fData.fPsd.fDigis.size(), 9);
-    EXPECT_EQ(eventsOut[i].fData.fFsd.fDigis.size(), 9);
-    EXPECT_EQ(eventsOut[i].fData.fT0.fDigis.size(), 9);
+    EXPECT_EQ(eventsOut[i].fMuch.size(), 9);
+    EXPECT_EQ(eventsOut[i].fSts.size(), 9);
+    EXPECT_EQ(eventsOut[i].fTof.size(), 9);
+    EXPECT_EQ(eventsOut[i].fTrd.size(), 9);
+    EXPECT_EQ(eventsOut[i].fRich.size(), 9);
+    EXPECT_EQ(eventsOut[i].fPsd.size(), 9);
+    EXPECT_EQ(eventsOut[i].fFsd.size(), 9);
+    EXPECT_EQ(eventsOut[i].fBmon.size(), 9);
     EXPECT_EQ(eventsOut[i].fTime, triggerIn[i]);
   }
 
diff --git a/algo/unpack/Unpack.cxx b/algo/unpack/Unpack.cxx
index 05044639fc..7b6559b4db 100644
--- a/algo/unpack/Unpack.cxx
+++ b/algo/unpack/Unpack.cxx
@@ -24,27 +24,27 @@ namespace cbm::algo
 
     // --- Output data
     resultType result          = {};
-    CbmDigiTimeslice& digiTs   = result.first;
+    DigiData& digiTs           = result.first;
     UnpackMonitorData& monitor = result.second;
 
     if (DetectorEnabled(Subsystem::STS)) {
       monitor.fNumBytesInSts +=
-        ParallelMsLoop(Subsystem::STS, monitor, digiTs.fData.fSts.fDigis, monitor.fSts, *timeslice, fAlgoSts, 0x20);
+        ParallelMsLoop(Subsystem::STS, monitor, digiTs.fSts, monitor.fSts, *timeslice, fAlgoSts, 0x20);
     }
 
     if (DetectorEnabled(Subsystem::TOF)) {
       monitor.fNumBytesInTof +=
-        ParallelMsLoop(Subsystem::TOF, monitor, digiTs.fData.fTof.fDigis, monitor.fTof, *timeslice, fAlgoTof, 0x00);
+        ParallelMsLoop(Subsystem::TOF, monitor, digiTs.fTof, monitor.fTof, *timeslice, fAlgoTof, 0x00);
     }
 
     if (DetectorEnabled(Subsystem::BMON)) {
       monitor.fNumBytesInBmon +=
-        ParallelMsLoop(Subsystem::BMON, monitor, digiTs.fData.fT0.fDigis, monitor.fBmon, *timeslice, fAlgoBmon, 0x00);
+        ParallelMsLoop(Subsystem::BMON, monitor, digiTs.fBmon, monitor.fBmon, *timeslice, fAlgoBmon, 0x00);
     }
 
     if (DetectorEnabled(Subsystem::MUCH)) {
       monitor.fNumBytesInMuch +=
-        ParallelMsLoop(Subsystem::MUCH, monitor, digiTs.fData.fMuch.fDigis, monitor.fMuch, *timeslice, fAlgoMuch, 0x20);
+        ParallelMsLoop(Subsystem::MUCH, monitor, digiTs.fMuch, monitor.fMuch, *timeslice, fAlgoMuch, 0x20);
     }
 
     // ---  Component loop
@@ -67,42 +67,41 @@ namespace cbm::algo
       // algorithms depending on the version.
 
       // if (subsystem == Subsystem::STS) {
-      //   MsLoop(timeslice, fAlgoSts, comp, equipmentId, &digiTs.fData.fSts.fDigis, monitor, &monitor.fSts, 0x20);
+      //   MsLoop(timeslice, fAlgoSts, comp, equipmentId, &digiTs.fSts, monitor, &monitor.fSts, 0x20);
       // }
       // if (subsystem == Subsystem::MUCH) {
-      //   MsLoop(timeslice, fAlgoMuch, comp, equipmentId, &digiTs.fData.fMuch.fDigis, monitor, &monitor.fMuch, 0x20);
+      //   MsLoop(timeslice, fAlgoMuch, comp, equipmentId, &digiTs.fMuch, monitor, &monitor.fMuch, 0x20);
       // }
       // if (subsystem == Subsystem::TOF) {
-      //   MsLoop(timeslice, fAlgoTof, comp, equipmentId, &digiTs.fData.fTof.fDigis, monitor, &monitor.fTof, 0x00);
+      //   MsLoop(timeslice, fAlgoTof, comp, equipmentId, &digiTs.fTof, monitor, &monitor.fTof, 0x00);
       // }
       // if (subsystem == Subsystem::BMON) {
-      //   MsLoop(timeslice, fAlgoBmon, comp, equipmentId, &digiTs.fData.fT0.fDigis, monitor, &monitor.fBmon, 0x00);
+      //   MsLoop(timeslice, fAlgoBmon, comp, equipmentId, &digiTs.fT0, monitor, &monitor.fBmon, 0x00);
       // }
       if (subsystem == Subsystem::TRD) {
         monitor.fNumBytesInTrd +=
-          MsLoop(timeslice, fAlgoTrd, comp, equipmentId, &digiTs.fData.fTrd.fDigis, monitor, &monitor.fTrd, 0x01);
+          MsLoop(timeslice, fAlgoTrd, comp, equipmentId, &digiTs.fTrd, monitor, &monitor.fTrd, 0x01);
       }
       if (subsystem == Subsystem::TRD2D) {
         monitor.fNumBytesInTrd2d +=
-          MsLoop(timeslice, fAlgoTrd2d, comp, equipmentId, &digiTs.fData.fTrd2d.fDigis, monitor, &monitor.fTrd2d, 0x02);
+          MsLoop(timeslice, fAlgoTrd2d, comp, equipmentId, &digiTs.fTrd2d, monitor, &monitor.fTrd2d, 0x02);
       }
       if (subsystem == Subsystem::RICH) {
         monitor.fNumBytesInRich +=
-          MsLoop(timeslice, fAlgoRich, comp, equipmentId, &digiTs.fData.fRich.fDigis, monitor, &monitor.fRich, 0x03);
+          MsLoop(timeslice, fAlgoRich, comp, equipmentId, &digiTs.fRich, monitor, &monitor.fRich, 0x03);
       }
     }  //# component
 
     // --- Sorting of output digis. Is required by both digi trigger and event builder.
 
     xpu::push_timer("Sort");
-    auto& digiData = digiTs.fData;
-    DoSort(digiData.fSts.fDigis);
-    DoSort(digiData.fMuch.fDigis);
-    DoSort(digiData.fTof.fDigis);
-    DoSort(digiData.fT0.fDigis);
-    DoSort(digiData.fTrd.fDigis);
-    DoSort(digiData.fTrd2d.fDigis);
-    DoSort(digiData.fRich.fDigis);
+    DoSort(digiTs.fSts);
+    DoSort(digiTs.fMuch);
+    DoSort(digiTs.fTof);
+    DoSort(digiTs.fBmon);
+    DoSort(digiTs.fTrd);
+    DoSort(digiTs.fTrd2d);
+    DoSort(digiTs.fRich);
     xpu::pop_timer();
 
     xpu::timings timings = xpu::pop_timer();
@@ -159,9 +158,9 @@ namespace cbm::algo
 
   // ----------------------------------------------------------------------------
   template<class Digi, class UnpackAlgo, class Monitor>
-  size_t Unpack::ParallelMsLoop(const Subsystem subsystem, UnpackMonitorData& genericMonitor,
-                                std::vector<Digi>& digisOut, std::vector<Monitor>& monitorOut,
-                                const fles::Timeslice& ts, const std::map<u16, UnpackAlgo>& algos, u8 sys_ver)
+  size_t Unpack::ParallelMsLoop(const Subsystem subsystem, UnpackMonitorData& genericMonitor, PODVector<Digi>& digisOut,
+                                std::vector<Monitor>& monitorOut, const fles::Timeslice& ts,
+                                const std::map<u16, UnpackAlgo>& algos, u8 sys_ver)
   {
     xpu::scoped_timer t_(fles::to_string(subsystem));
 
@@ -215,7 +214,7 @@ namespace cbm::algo
   // ----------------- Microslice loop ------------------------------------------
   template<class Digi, class UnpackAlgo, class MonitorData>
   size_t Unpack::MsLoop(const fles::Timeslice* timeslice, std::map<uint16_t, UnpackAlgo>& algoMap, const uint64_t comp,
-                        const uint16_t eqId, std::vector<Digi>* digis, UnpackMonitorData& monitor,
+                        const uint16_t eqId, PODVector<Digi>* digis, UnpackMonitorData& monitor,
                         std::vector<MonitorData>* monitorMs, uint8_t sys_ver)
   {
     // --- Component log
@@ -435,7 +434,7 @@ namespace cbm::algo
 
   // ----------------------------------------------------------------------------
   template<class Digi>
-  void Unpack::DoSort(std::vector<Digi>& digis)
+  void Unpack::DoSort(PODVector<Digi>& digis)
   {
     xpu::t_add_bytes(digis.size() * sizeof(Digi));  // Add bytes to timer, assumes xpu::timers are started in operator()
     Sort(digis.begin(), digis.end(),
diff --git a/algo/unpack/Unpack.h b/algo/unpack/Unpack.h
index 4b403b4936..4ad0379c77 100644
--- a/algo/unpack/Unpack.h
+++ b/algo/unpack/Unpack.h
@@ -6,8 +6,6 @@
 #ifndef UNPACK_H
 #define UNPACK_H 1
 
-#include "CbmDigiTimeslice.h"
-
 #include "tof/ReadoutConfig.h"
 #include "tof/Unpack.h"
 #include "trd/ReadoutConfig.h"
@@ -20,6 +18,8 @@
 #include <sstream>
 #include <vector>
 
+#include "DigiData.h"
+#include "PODVector.h"
 #include "bmon/ReadoutConfig.h"
 #include "bmon/Unpack.h"
 #include "much/ReadoutConfig.h"
@@ -79,7 +79,7 @@ namespace cbm::algo
   class Unpack {
 
   public:
-    typedef std::pair<CbmDigiTimeslice, UnpackMonitorData> resultType;
+    typedef std::pair<DigiData, UnpackMonitorData> resultType;
     using Subsystem = fles::Subsystem;
 
     /** @brief Algorithm execution
@@ -144,12 +144,12 @@ namespace cbm::algo
     /** @brief Microslice loop **/
     template<class Digi, class UnpackAlgo, class MonitorData>
     size_t MsLoop(const fles::Timeslice* timeslice, std::map<uint16_t, UnpackAlgo>& algoMap, const uint64_t comp,
-                  const uint16_t eqId, std::vector<Digi>* digis, UnpackMonitorData& monitor,
+                  const uint16_t eqId, PODVector<Digi>* digis, UnpackMonitorData& monitor,
                   std::vector<MonitorData>* monitorMs, uint8_t sys_ver);
 
     /** @brief Parallel microslice loop **/
     template<class Digi, class UnpackAlgo, class Monitor>
-    size_t ParallelMsLoop(const Subsystem subsystem, UnpackMonitorData& monitor, std::vector<Digi>& digisOut,
+    size_t ParallelMsLoop(const Subsystem subsystem, UnpackMonitorData& monitor, PODVector<Digi>& digisOut,
                           std::vector<Monitor>& monitorOut, const fles::Timeslice& ts,
                           const std::map<u16, UnpackAlgo>& algos, u8 sys_ver);
 
@@ -161,7 +161,7 @@ namespace cbm::algo
 
     /** @brief Sort Digis and add bytes to timer for throughput */
     template<class Digi>
-    void DoSort(std::vector<Digi>& digis);
+    void DoSort(PODVector<Digi>& digis);
 
 
   private:                                                  // members
diff --git a/algo/unpack/UnpackChain.cxx b/algo/unpack/UnpackChain.cxx
index 153706642b..670652090f 100644
--- a/algo/unpack/UnpackChain.cxx
+++ b/algo/unpack/UnpackChain.cxx
@@ -16,15 +16,15 @@ Unpack::resultType UnpackChain::Run(const fles::Timeslice& timeslice)
 {
   auto result = fUnpack(&timeslice);
 
-  auto& digis = result.first.fData;
+  auto& digis = result.first;
 
-  if (Opts().HasDetector(Subsystem::STS)) L_(info) << "Timeslice contains " << digis.fSts.Size() << " STS Digis";
-  if (Opts().HasDetector(Subsystem::TOF)) L_(info) << "Timeslice contains " << digis.fTof.Size() << " TOF Digis";
-  if (Opts().HasDetector(Subsystem::BMON)) L_(info) << "Timeslice contains " << digis.fT0.Size() << " BMON Digis";
-  if (Opts().HasDetector(Subsystem::MUCH)) L_(info) << "Timeslice contains " << digis.fMuch.Size() << " MUCH Digis";
-  if (Opts().HasDetector(Subsystem::TRD)) L_(info) << "Timeslice contains " << digis.fTrd.Size() << " TRD Digis";
-  if (Opts().HasDetector(Subsystem::TRD2D)) L_(info) << "Timeslice contains " << digis.fTrd2d.Size() << " TRD2D Digis";
-  if (Opts().HasDetector(Subsystem::RICH)) L_(info) << "Timeslice contains " << digis.fRich.Size() << " RICH Digis";
+  if (Opts().HasDetector(Subsystem::STS)) L_(info) << "Timeslice contains " << digis.fSts.size() << " STS Digis";
+  if (Opts().HasDetector(Subsystem::TOF)) L_(info) << "Timeslice contains " << digis.fTof.size() << " TOF Digis";
+  if (Opts().HasDetector(Subsystem::BMON)) L_(info) << "Timeslice contains " << digis.fBmon.size() << " BMON Digis";
+  if (Opts().HasDetector(Subsystem::MUCH)) L_(info) << "Timeslice contains " << digis.fMuch.size() << " MUCH Digis";
+  if (Opts().HasDetector(Subsystem::TRD)) L_(info) << "Timeslice contains " << digis.fTrd.size() << " TRD Digis";
+  if (Opts().HasDetector(Subsystem::TRD2D)) L_(info) << "Timeslice contains " << digis.fTrd2d.size() << " TRD2D Digis";
+  if (Opts().HasDetector(Subsystem::RICH)) L_(info) << "Timeslice contains " << digis.fRich.size() << " RICH Digis";
 
   return result;
 }
diff --git a/core/data/CMakeLists.txt b/core/data/CMakeLists.txt
index 568015be6d..60276a916d 100644
--- a/core/data/CMakeLists.txt
+++ b/core/data/CMakeLists.txt
@@ -101,7 +101,7 @@ set(SRCS
   psd/CbmPsdPoint.cxx
   psd/CbmPsdAddress.cxx
   psd/CbmPsdMCbmHit.cxx
-  
+
   fsd/CbmFsdDigi.cxx
   fsd/CbmFsdHit.cxx
   fsd/CbmFsdPoint.cxx
@@ -172,4 +172,3 @@ Install(FILES
         raw/bitmask_operators.hpp raw/StsXyterFinalHit.h raw/PsdGbtDataFormat-v0.00.h raw/PsdGbtDataFormat-v1.00.h
         DESTINATION include
        )
-
diff --git a/core/data/sts/CbmStsDigi.h b/core/data/sts/CbmStsDigi.h
index 2857a4200c..caf5e8289a 100644
--- a/core/data/sts/CbmStsDigi.h
+++ b/core/data/sts/CbmStsDigi.h
@@ -165,18 +165,10 @@ public:
 private:
   friend class boost::serialization::access;
 
-// CUDA requires types in shared memory to have trivial constructors / destructors
-#if XPU_IS_HIP_CUDA
-#define CPU_ONLY(x)
-#else
-#define CPU_ONLY(x) x
-#endif
-
-  uint32_t fTime CPU_ONLY(= 0);              ///< Time [ns] in lower 31 bits, highest bit is the 17th address bit.
-  uint16_t fChannelAndCharge CPU_ONLY(= 0);  ///< Channel number (lower 11 bits) and charge [ADC Units] in upper 5 bits.
-  uint16_t fAddress CPU_ONLY(= 0);           ///< Unique element address (lower 16 bits of 17)
 
-#undef CPU_ONLY
+  uint32_t fTime;              ///< Time [ns] in lower 31 bits, highest bit is the 17th address bit.
+  uint16_t fChannelAndCharge;  ///< Channel number (lower 11 bits) and charge [ADC Units] in upper 5 bits.
+  uint16_t fAddress;           ///< Unique element address (lower 16 bits of 17)
 
 
   XPU_D void PackTime(uint32_t newTime) { fTime = (fTime & kTimeAddressBitMask) | (newTime & kTimestampMask); }
@@ -219,5 +211,4 @@ private:
 #endif
 };
 
-
 #endif
diff --git a/core/data/test/sts/_GTestCbmStsDigi.cxx b/core/data/test/sts/_GTestCbmStsDigi.cxx
index a76bd1a13e..2420f6b825 100644
--- a/core/data/test/sts/_GTestCbmStsDigi.cxx
+++ b/core/data/test/sts/_GTestCbmStsDigi.cxx
@@ -17,16 +17,18 @@ static const int32_t kTestAddress = CbmStsAddress::GetAddress(5, 6, 1, 8, 0, 0,
 
 TEST(_GTestCbmStsDigi, CheckDefaultConstructor)
 {
+  // Test disabled. CbmStsDigi doesn't initialize its members in the default constructor on purpose.
+
   // Create object
-  CbmStsDigi test;
+  // CbmStsDigi test;
 
-  const int32_t defaultAddr = CbmStsAddress::GetAddress(0, 0, 0, 0, 0, 0, 1);
+  // const int32_t defaultAddr = CbmStsAddress::GetAddress(0, 0, 0, 0, 0, 0, 1);
 
-  compareStsDigiDataMembers(test, defaultAddr, 0, 0, ECbmModuleId::kSts, 0);
+  // compareStsDigiDataMembers(test, defaultAddr, 0, 0, ECbmModuleId::kSts, 0);
 
-  CbmStsDigi* test1 = new CbmStsDigi();
+  // CbmStsDigi* test1 = new CbmStsDigi();
 
-  compareStsDigiDataMembers(*test1, defaultAddr, 0, 0, ECbmModuleId::kSts, 0);
+  // compareStsDigiDataMembers(*test1, defaultAddr, 0, 0, ECbmModuleId::kSts, 0);
 }
 
 TEST(_GTestCbmStsDigi, CheckStandardConstructor)
diff --git a/reco/app/cbmreco/main.cxx b/reco/app/cbmreco/main.cxx
index 18ea5e3d0b..361e2f5d99 100644
--- a/reco/app/cbmreco/main.cxx
+++ b/reco/app/cbmreco/main.cxx
@@ -69,11 +69,15 @@ int main(int argc, char** argv)
 
     if (opts.SplitOutputPerTS() && !opts.OutputFile().empty()) {
       Archive tsResults(ArchiveDescriptor {});  // TODO: use opts.Detector() once detector flag is merged
-      tsResults.TimesliceResults().emplace_back(std::move(result));
+      for (auto& event : result.events) {
+        tsResults.TimesliceResults().emplace_back(event.ToStorable());
+      }
       tsResults.Store(opts.OutputFile(), ts->index());
     }
     else {
-      archive.TimesliceResults().emplace_back(std::move(result));
+      for (auto& event : result.events) {
+        archive.TimesliceResults().emplace_back(event.ToStorable());
+      }
     }
     tsIdx++;
 
diff --git a/reco/mq/CbmDevTrigger.cxx b/reco/mq/CbmDevTrigger.cxx
index 9cda6161ea..7c01e9a3b0 100644
--- a/reco/mq/CbmDevTrigger.cxx
+++ b/reco/mq/CbmDevTrigger.cxx
@@ -75,7 +75,7 @@ ECbmModuleId CbmDevTrigger::GetDetectorId(std::string detName)
                        : ("Psd"  == detName ? ECbmModuleId::kPsd
                        : ("Fsd"  == detName ? ECbmModuleId::kFsd
                                              : ECbmModuleId::kNotExist))))))));
-  return detId; 
+  return detId;
   /// FIXME: Re-enable clang formatting after formatted lines
   /* clang-format on */
 }
@@ -120,27 +120,27 @@ std::vector<double> CbmDevTrigger::GetTriggerTimes(const CbmDigiTimeslice& ts)
   std::vector<double> vDigiTimes;
   switch (fTriggerDet) {
     case ECbmModuleId::kMuch: {
-      vDigiTimes = GetDigiTimes(ts.fData.fMuch.fDigis);
+      vDigiTimes = GetDigiTimes<CbmMuchDigi>(ts.fData.fMuch.fDigis);
       break;
     }
     case ECbmModuleId::kSts: {
-      vDigiTimes = GetDigiTimes(ts.fData.fSts.fDigis);
+      vDigiTimes = GetDigiTimes<CbmStsDigi>(ts.fData.fSts.fDigis);
       break;
     }
     case ECbmModuleId::kTof: {
-      vDigiTimes = GetDigiTimes(ts.fData.fTof.fDigis);
+      vDigiTimes = GetDigiTimes<CbmTofDigi>(ts.fData.fTof.fDigis);
       break;
     }
     case ECbmModuleId::kTrd: {
-      vDigiTimes = GetDigiTimes(ts.fData.fTrd.fDigis);
+      vDigiTimes = GetDigiTimes<CbmTrdDigi>(ts.fData.fTrd.fDigis);
       break;
     }
     case ECbmModuleId::kRich: {
-      vDigiTimes = GetDigiTimes(ts.fData.fRich.fDigis);
+      vDigiTimes = GetDigiTimes<CbmRichDigi>(ts.fData.fRich.fDigis);
       break;
     }
     case ECbmModuleId::kPsd: {
-      vDigiTimes = GetDigiTimes(ts.fData.fPsd.fDigis);
+      vDigiTimes = GetDigiTimes<CbmPsdDigi>(ts.fData.fPsd.fDigis);
       break;
     }
     case ECbmModuleId::kFsd: {
@@ -148,7 +148,7 @@ std::vector<double> CbmDevTrigger::GetTriggerTimes(const CbmDigiTimeslice& ts)
       break;
     }
     case ECbmModuleId::kT0: {
-      vDigiTimes = GetDigiTimes(ts.fData.fT0.fDigis);
+      vDigiTimes = GetDigiTimes<CbmBmonDigi>(ts.fData.fT0.fDigis);
       break;
     }
     default: LOG(fatal) << "CbmDevTrigger::GetTriggerTimes(): Reading digis from unknown detector type!";
diff --git a/reco/mq/CbmDevTrigger.h b/reco/mq/CbmDevTrigger.h
index b5743194ce..66fd2ef0ef 100644
--- a/reco/mq/CbmDevTrigger.h
+++ b/reco/mq/CbmDevTrigger.h
@@ -26,6 +26,7 @@
 
 /// C/C++ headers
 #include <chrono>
+#include <gsl/span>
 #include <vector>
 
 class CbmDigiTimeslice;
@@ -65,7 +66,7 @@ private:
 
   // --- Extract digi times into to a vector
   template<class TDigi>
-  std::vector<double> GetDigiTimes(const std::vector<TDigi>& digiVec)
+  std::vector<double> GetDigiTimes(gsl::span<const TDigi> digiVec)
   {
     std::vector<double> digiTimes(digiVec.size());
     std::transform(digiVec.begin(), digiVec.end(), digiTimes.begin(), [](const TDigi& digi) { return digi.GetTime(); });
diff --git a/reco/tasks/CbmTaskBuildEvents.cxx b/reco/tasks/CbmTaskBuildEvents.cxx
index 301d72d8f6..b7fb3cc8c6 100644
--- a/reco/tasks/CbmTaskBuildEvents.cxx
+++ b/reco/tasks/CbmTaskBuildEvents.cxx
@@ -44,42 +44,42 @@ CbmDigiTimeslice CbmTaskBuildEvents::FillTimeSlice()
         const vector<CbmStsDigi>* digiVec =
           boost::any_cast<const vector<CbmStsDigi>*>(digiBranch->GetBranchContainer());
         assert(digiVec);
-        ts.fData.fSts.fDigis = *digiVec;
+        std::copy(digiVec->begin(), digiVec->end(), std::back_inserter(ts.fData.fSts.fDigis));
         break;
       }
       case ECbmModuleId::kRich: {
         const vector<CbmRichDigi>* digiVec =
           boost::any_cast<const vector<CbmRichDigi>*>(digiBranch->GetBranchContainer());
         assert(digiVec);
-        ts.fData.fRich.fDigis = *digiVec;
+        std::copy(digiVec->begin(), digiVec->end(), std::back_inserter(ts.fData.fRich.fDigis));
         break;
       }
       case ECbmModuleId::kMuch: {
         const vector<CbmMuchDigi>* digiVec =
           boost::any_cast<const vector<CbmMuchDigi>*>(digiBranch->GetBranchContainer());
         assert(digiVec);
-        ts.fData.fMuch.fDigis = *digiVec;
+        std::copy(digiVec->begin(), digiVec->end(), std::back_inserter(ts.fData.fMuch.fDigis));
         break;
       }
       case ECbmModuleId::kTrd: {
         const vector<CbmTrdDigi>* digiVec =
           boost::any_cast<const vector<CbmTrdDigi>*>(digiBranch->GetBranchContainer());
         assert(digiVec);
-        ts.fData.fTrd.fDigis = *digiVec;
+        std::copy(digiVec->begin(), digiVec->end(), std::back_inserter(ts.fData.fTrd.fDigis));
         break;
       }
       case ECbmModuleId::kTrd2d: {
         const vector<CbmTrdDigi>* digiVec =
           boost::any_cast<const vector<CbmTrdDigi>*>(digiBranch->GetBranchContainer());
         assert(digiVec);
-        ts.fData.fTrd2d.fDigis = *digiVec;
+        std::copy(digiVec->begin(), digiVec->end(), std::back_inserter(ts.fData.fTrd2d.fDigis));
         break;
       }
       case ECbmModuleId::kTof: {
         const vector<CbmTofDigi>* digiVec =
           boost::any_cast<const vector<CbmTofDigi>*>(digiBranch->GetBranchContainer());
         assert(digiVec);
-        ts.fData.fTof.fDigis = *digiVec;
+        std::copy(digiVec->begin(), digiVec->end(), std::back_inserter(ts.fData.fTof.fDigis));
         break;
       }
       case ECbmModuleId::kPsd: {
@@ -93,7 +93,7 @@ CbmDigiTimeslice CbmTaskBuildEvents::FillTimeSlice()
         const vector<CbmBmonDigi>* digiVec =
           boost::any_cast<const vector<CbmBmonDigi>*>(digiBranch->GetBranchContainer());
         assert(digiVec);
-        ts.fData.fT0.fDigis = *digiVec;
+        std::copy(digiVec->begin(), digiVec->end(), std::back_inserter(ts.fData.fTof.fDigis));
         break;
       }
       default: LOG(fatal) << GetName() << ": Unknown detector type!";
@@ -121,7 +121,8 @@ void CbmTaskBuildEvents::Exec(Option_t*)
   // --- If the input is already CbmDigiTimeslice (from unpacking), use that directly
   if (fTimeslice) {
     timerStep.Start();
-    *fEvents = (*fAlgo)(*fTimeslice, *fTriggers).first;
+    *fEvents =
+      cbm::algo::DigiEvent::ToCbmDigiEvents((*fAlgo)(cbm::algo::DigiData(fTimeslice->fData), *fTriggers).first);
     timerStep.Stop();
     fTimeBuildEvt += timerStep.RealTime();
     for (const auto& entry : fConfig->fWindows)
@@ -137,7 +138,7 @@ void CbmTaskBuildEvents::Exec(Option_t*)
     timerStep.Stop();
     fTimeFillTs += timerStep.RealTime();
     timerStep.Start();
-    *fEvents = (*fAlgo)(ts, *fTriggers).first;
+    *fEvents = cbm::algo::DigiEvent::ToCbmDigiEvents((*fAlgo)(cbm::algo::DigiData(ts.fData), *fTriggers).first);
     timerStep.Stop();
     fTimeBuildEvt += timerStep.RealTime();
   }
@@ -145,7 +146,7 @@ void CbmTaskBuildEvents::Exec(Option_t*)
   // Apply event selector if desired
   if (fSelector) {
     timerStep.Start();
-    auto noTrigger = [&](CbmDigiEvent& ev) { return !(*fSelector)(ev); };
+    auto noTrigger = [&](CbmDigiEvent& ev) { return !(*fSelector)(cbm::algo::DigiEvent(ev)); };
     auto removeIt  = std::remove_if(fEvents->begin(), fEvents->end(), noTrigger);
     fEvents->erase(removeIt, fEvents->end());
     timerStep.Stop();
diff --git a/reco/tasks/CbmTaskBuildEvents.h b/reco/tasks/CbmTaskBuildEvents.h
index f94e2bc097..5cf81338c9 100644
--- a/reco/tasks/CbmTaskBuildEvents.h
+++ b/reco/tasks/CbmTaskBuildEvents.h
@@ -7,6 +7,7 @@
 
 #include "CbmDefs.h"
 #include "CbmDigiEvent.h"
+#include "CbmDigiTimeslice.h"
 
 #include <FairTask.h>
 
diff --git a/reco/tasks/CbmTaskDigiEventQa.cxx b/reco/tasks/CbmTaskDigiEventQa.cxx
index e8206b2fa8..4b0e370a51 100644
--- a/reco/tasks/CbmTaskDigiEventQa.cxx
+++ b/reco/tasks/CbmTaskDigiEventQa.cxx
@@ -73,7 +73,7 @@ void CbmTaskDigiEventQa::Exec(Option_t*)
 
   // --- Algo execution
   DigiEventQaConfig config;
-  DigiEventQaData result = (*fAlgo)(*fEvents);
+  DigiEventQaData result = (*fAlgo)(cbm::algo::DigiEvent::FromCbmDigiEvents(*fEvents));
 
   // --- Copy QA results (Histo1D) into ROOT output histograms
   // TODO: Probably not the most efficient implementation. Creates first a ROOT histogram from a CBM one (data copy),
diff --git a/reco/tasks/CbmTaskMakeRecoEvents.h b/reco/tasks/CbmTaskMakeRecoEvents.h
index db5617534f..70e5433f3d 100644
--- a/reco/tasks/CbmTaskMakeRecoEvents.h
+++ b/reco/tasks/CbmTaskMakeRecoEvents.h
@@ -13,6 +13,7 @@
 
 #include <FairTask.h>
 
+#include <gsl/span>
 #include <vector>
 
 class TClonesArray;
@@ -79,7 +80,7 @@ private:  // methods
    ** the CbmEvent object.
    **/
   template<typename Digi>
-  void FillTree(const std::vector<Digi>& inVec, std::vector<Digi>* outVec, CbmEvent* event, ECbmDataType digiType)
+  void FillTree(gsl::span<const Digi> inVec, std::vector<Digi>* outVec, CbmEvent* event, ECbmDataType digiType)
   {
     size_t startIndex = outVec->size();
     size_t stopIndex  = startIndex + inVec.size();
diff --git a/reco/tasks/CbmTaskUnpack.cxx b/reco/tasks/CbmTaskUnpack.cxx
index 87eae87eb9..3fab920d5e 100644
--- a/reco/tasks/CbmTaskUnpack.cxx
+++ b/reco/tasks/CbmTaskUnpack.cxx
@@ -69,7 +69,7 @@ void CbmTaskUnpack::Exec(Option_t*)
 
   // --- Unpack the timeslice
   auto result = fUnpack(timeslice);
-  *fTimeslice = std::move(result.first);
+  fTimeslice->fData = result.first.ToStorable();
 
   // --- Timeslice log
   timer.Stop();
-- 
GitLab