diff --git a/core/data/CMakeLists.txt b/core/data/CMakeLists.txt
index caf693ea6cb476b825219a39f23841b47bdda259..6121c9f1f474d641dd85ebb593e00e0399d6044a 100644
--- a/core/data/CMakeLists.txt
+++ b/core/data/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRCS
   CbmCluster.cxx
   CbmModuleList.cxx
   CbmErrorMessage.cxx
+  CbmRawEvent.cxx
 
   CbmMCTrack.cxx
   CbmMCEventInfo.cxx
diff --git a/core/data/CbmRawEvent.cxx b/core/data/CbmRawEvent.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..93a6371a2f626c7bc2ee620b8e09c7c70a0ab90c
--- /dev/null
+++ b/core/data/CbmRawEvent.cxx
@@ -0,0 +1,51 @@
+/*
+ * CbmRawEvent.cxx
+ *
+ *  Created on: 27.03.2021
+ *      Author: vfriese
+ */
+
+
+#include "CbmRawEvent.h"
+
+
+// -----   Number of digis per system
+size_t CbmRawEvent::GetNofDigis(ECbmModuleId system) const
+{
+  switch (system) {
+    case ECbmModuleId::kMvd: return fDigisMvd.size(); break;
+    case ECbmModuleId::kSts: return fDigisSts.size(); break;
+    case ECbmModuleId::kRich: return fDigisRich.size(); break;
+    case ECbmModuleId::kMuch: return fDigisMuch.size(); break;
+    case ECbmModuleId::kTrd: return fDigisTrd.size(); break;
+    case ECbmModuleId::kTof: return fDigisTof.size(); break;
+    case ECbmModuleId::kPsd: return fDigisPsd.size(); break;
+    default: return 0; break;
+  }
+}
+
+
+// -----   Total number of digis
+size_t CbmRawEvent::GetNofDigis() const
+{
+  size_t result = fDigisMvd.size();
+  result += fDigisSts.size();
+  result += fDigisRich.size();
+  result += fDigisMuch.size();
+  result += fDigisTrd.size();
+  result += fDigisTof.size();
+  result += fDigisPsd.size();
+  return result;
+}
+
+
+// -----   String output
+std::string CbmRawEvent::ToString() const
+{
+  std::stringstream ss;
+  ss << "Event " << fNumber << " at t = " << fTime << " ns. Digis: " << GetNofDigis() << " (MVD " << fDigisMvd.size()
+     << "  STS " << fDigisSts.size() << "  RICH " << fDigisRich.size() << "  MUCH " << fDigisMuch.size() << "  TRD "
+     << fDigisTrd.size() << "  TOF " << fDigisTof.size() << "  PSD " << fDigisPsd.size() << ")";
+  return ss.str();
+}
+// -------------------------------------------------------------------------
diff --git a/core/data/CbmRawEvent.h b/core/data/CbmRawEvent.h
new file mode 100644
index 0000000000000000000000000000000000000000..c902606942179556577b582d2ef111016b976224
--- /dev/null
+++ b/core/data/CbmRawEvent.h
@@ -0,0 +1,192 @@
+/** @file CbmRawEvent.h
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @date 25.03.2021
+ **/
+
+
+#ifndef CBMRAWEVENT_H
+#define CBMRAWEVENT_H 1
+
+#include "CbmDefs.h"  // for ECbmDataType, ECbmModuleId::kStsTrack
+//#include "CbmMatch.h"  // for CbmMatch
+#include "CbmMuchDigi.h"
+#include "CbmMvdDigi.h"
+#include "CbmPsdDigi.h"
+#include "CbmRichDigi.h"
+#include "CbmStsDigi.h"
+#include "CbmTofDigi.h"
+#include "CbmTrdDigi.h"
+//#include "CbmVertex.h"  // for CbmVertex, found in core/data/global
+
+//#include <Rtypes.h>          // for THashConsistencyHolder, ClassDef
+//#include <RtypesCore.h>      // for Double_t, UInt_t, Int_t
+//#include <TMatrixFSymfwd.h>  // for TMatrixFSym
+//#include <TObject.h>         // for TObject
+
+
+//#include <map>  // for map, map<>::mapped_type
+//#include <span>
+//#include <string>  // for string
+//#include <utility>
+#include <vector>  // for vector
+
+
+/** @class CbmRawEvent
+ ** @brief Data class as collections of digis for each detector system
+ ** @author V.Friese <v.friese@gsi.de>
+ ** @version 1.0
+ **
+ **/
+class CbmRawEvent : public TObject {
+
+public:
+  /** @brief Default constructor **/
+  CbmRawEvent() {};
+
+
+  /** @brief Constructor with event number and time
+   ** @param number    Event number
+   ** @param time      Event trigger time [ns]
+   **/
+  CbmRawEvent(uint64_t number, Double_t time = 0) : fNumber(number), fTime(time) {};
+
+
+  /** @brief Copy constructor **/
+  CbmRawEvent(const CbmRawEvent&) = default;
+
+
+  /** @brief Move constructor **/
+  CbmRawEvent(CbmRawEvent&&) = default;
+
+
+  /** @brief Assignment operator **/
+  CbmRawEvent& operator=(const CbmRawEvent&) = default;
+
+
+  /** @brief Destructor **/
+  virtual ~CbmRawEvent() {};
+
+
+  /** @brief Add a digi to the event
+   ** @param data Digi
+   ** TODO: Somehow, this does not work, so dedicated methods were implemented.
+   **/
+  template<class Digi>
+  void AddDigi(ECbmModuleId system, Digi digi)
+  {
+    switch (system) {
+      case ECbmModuleId::kMvd: fDigisMvd.push_back(digi); break;
+      case ECbmModuleId::kSts: fDigisSts.push_back(digi); break;
+      case ECbmModuleId::kRich: fDigisRich.push_back(digi); break;
+      case ECbmModuleId::kMuch: fDigisMuch.push_back(digi); break;
+      case ECbmModuleId::kTrd: fDigisTrd.push_back(digi); break;
+      case ECbmModuleId::kTof: fDigisTof.push_back(digi); break;
+      case ECbmModuleId::kPsd: fDigisPsd.push_back(digi); break;
+      default: break;
+    }
+  }
+
+
+  void AddDigiMvd(CbmMvdDigi digi) { fDigisMvd.push_back(digi); }
+  void AddDigiSts(CbmStsDigi digi) { fDigisSts.push_back(digi); }
+  void AddDigiRich(CbmRichDigi digi) { fDigisRich.push_back(digi); }
+  void AddDigiMuch(CbmMuchDigi digi) { fDigisMuch.push_back(digi); }
+  void AddDigiTrd(CbmTrdDigi digi) { fDigisTrd.push_back(digi); }
+  void AddDigiTof(CbmTofDigi digi) { fDigisTof.push_back(digi); }
+  void AddDigiPsd(CbmPsdDigi digi) { fDigisPsd.push_back(digi); }
+
+
+  /** @brief Read-only access to a single digi
+   ** @param system  System identifier (ECbmModuleId)
+   ** @param index Index of digi in its vector
+   ** @return Reference to digi object
+   **/
+  template<class Digi>
+  const Digi& GetDigi(ECbmModuleId system, size_t index) const
+  {
+    switch (system) {
+      case ECbmModuleId::kMvd: return fDigisMvd.at(index); break;
+      case ECbmModuleId::kSts: return fDigisSts.at(index); break;
+      case ECbmModuleId::kRich: return fDigisRich.at(index); break;
+      case ECbmModuleId::kMuch: return fDigisMuch.at(index); break;
+      case ECbmModuleId::kTrd: return fDigisTrd.at(index); break;
+      case ECbmModuleId::kTof: return fDigisTof.at(index); break;
+      case ECbmModuleId::kPsd: return fDigisPsd.at(index); break;
+      default: break;
+    }
+  }
+
+
+  /** @brief Read-only access to digi vectors
+   ** @param system  System identifier (ECbmModuleId)
+   ** @return Reference to digi vector for the specified system
+   **/
+  template<class Digi>
+  const std::vector<Digi>& GetDigis(ECbmModuleId system) const
+  {
+    switch (system) {
+      case ECbmModuleId::kMvd: return (&fDigisMvd); break;
+      case ECbmModuleId::kSts: return (&fDigisSts); break;
+      case ECbmModuleId::kRich: return (&fDigisRich); break;
+      case ECbmModuleId::kMuch: return (&fDigisMuch); break;
+      case ECbmModuleId::kTrd: return (&fDigisTrd); break;
+      case ECbmModuleId::kTof: return (&fDigisTof); break;
+      case ECbmModuleId::kPsd: return (&fDigisPsd); break;
+      default: break;
+    }
+  }
+
+
+  /** @brief Number of digis for a given system
+   ** @param systemId   System identifier (ECbmModuleId)
+   ** @return Number of digis for the specified system
+   **/
+  size_t GetNofDigis(ECbmModuleId) const;
+
+
+  /** @brief Total number of digis (all systems)
+   ** @return Number of digis in event
+   **/
+  size_t GetNofDigis() const;
+
+
+  /** @brief Event number
+   ** @return Event number
+	 **/
+  uint64_t GetNumber() const { return fNumber; }
+
+
+  /** @brief Event time
+   ** @return Event trigger time [ns]
+   **/
+  Double_t GetTime() const { return fTime; }
+
+
+  /** @brief Set event time
+   ** @param time  Event trigger time [ns]
+	 **/
+  void SetTime(Double_t time) { fTime = time; }
+
+
+  /** @brief String output **/
+  std::string ToString() const;
+
+
+private:
+  /** Event meta data **/
+  uint64_t fNumber;  ///< Event number
+  double fTime;      ///< Trigger time for this event [ns]
+
+  std::vector<CbmMvdDigi> fDigisMvd   = {};
+  std::vector<CbmStsDigi> fDigisSts   = {};
+  std::vector<CbmRichDigi> fDigisRich = {};
+  std::vector<CbmMuchDigi> fDigisMuch = {};
+  std::vector<CbmTrdDigi> fDigisTrd   = {};
+  std::vector<CbmTofDigi> fDigisTof   = {};
+  std::vector<CbmPsdDigi> fDigisPsd   = {};
+
+
+  ClassDef(CbmRawEvent, 1);
+};
+
+#endif /* CBMRAWEVENT_H_ */
diff --git a/core/data/DataLinkDef.h b/core/data/DataLinkDef.h
index 8c8156ecb4c39248df45cba7de7dcb933541639d..be8b44cb3c204983c3ebaf83cadfc6654a4f20cb 100644
--- a/core/data/DataLinkDef.h
+++ b/core/data/DataLinkDef.h
@@ -26,6 +26,7 @@
 #pragma link C++ class CbmLink + ;
 #pragma link C++ class CbmModuleList;
 #pragma link C++ class CbmErrorMessage + ;
+#pragma link C++ class CbmRawEvent + ;
 
 // ---In base
 #pragma link C++ class CbmDigiBranchBase + ;
@@ -127,10 +128,9 @@
 #pragma link C++ class CbmDigiVector < CbmPsdDsp> + ;
 #pragma link C++ class vector < CbmEventStore> + ;
 
-#pragma read sourceClass="CbmTofDigi" version="[1-2]" targetClass="CbmTofDigi" \
-   source="UInt_t fuAddress" target="fuAddress" \
-   include="Logger.h" \
-   code="{ UInt_t system = (onfile.fuAddress >> 0) & ((1 << 4) - 1); \
+#pragma read sourceClass = "CbmTofDigi" version = "[1-2]" targetClass = "CbmTofDigi" source =                          \
+  "UInt_t fuAddress" target = "fuAddress" include = "Logger.h" code =                                                  \
+    "{ UInt_t system = (onfile.fuAddress >> 0) & ((1 << 4) - 1); \
            UInt_t smId = (onfile.fuAddress >> 4) & ((1 << 8) - 1); \
            UInt_t smType = (onfile.fuAddress >> 12) & ((1 << 4) - 1); \
            UInt_t rpcId = (onfile.fuAddress >> 16) & ((1 << 7) - 1); \
@@ -152,10 +152,8 @@
                      + ((rpcType & ((1 << 4) - 1)) << 28); \
          }"
 
-#pragma read sourceClass="CbmTofHit" version="[1-4]" targetClass="CbmTofHit" \
-   source="" target="" \
-   include="Logger.h" \
-   code="{ \
+#pragma read sourceClass = "CbmTofHit" version = "[1-4]" targetClass = "CbmTofHit" source = "" target = "" include =   \
+  "Logger.h" code                                                                                     = "{ \
            LOG(error); \
            LOG(error) << \"You are trying to read an outdated version of CbmTofHit\"; \
            LOG(error) << \"where the unique tof address can't be converted\"; \
@@ -164,10 +162,8 @@
            LOG(fatal) << \"Stop execution.\"; \
          }"
 
-#pragma read sourceClass="CbmTofPoint" version="[1-3]" targetClass="CbmTofPoint" \
-   source="" target="" \
-   include="Logger.h" \
-   code="{ \
+#pragma read sourceClass = "CbmTofPoint" version = "[1-3]" targetClass = "CbmTofPoint" source = "" target =            \
+  "" include = "Logger.h" code = "{ \
            LOG(error); \
            LOG(error) << \"You are trying to read an outdated version of CbmTofPoint\"; \
            LOG(error) << \"where the unique tof address can't be converted\"; \
diff --git a/macro/run/run_reco_mcbm.C b/macro/run/run_reco_mcbm.C
new file mode 100644
index 0000000000000000000000000000000000000000..24d42280f788de947f2e0764a852b2ee1b54ec66
--- /dev/null
+++ b/macro/run/run_reco_mcbm.C
@@ -0,0 +1,311 @@
+/* Copyright (C) 2020-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer], Dominik Smith */
+
+/** @file run_reco.C
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @since 14 November 2020
+ **/
+
+
+// --- Includes needed for IDE
+#include <RtypesCore.h>
+#if !defined(__CLING__)
+#include "CbmBuildEventsFromTracksReal.h"
+#include "CbmBuildEventsIdeal.h"
+#include "CbmBuildEventsQa.h"
+#include "CbmDefs.h"
+#include "CbmEvbuildRawTask.h"
+#include "CbmFindPrimaryVertex.h"
+#include "CbmKF.h"
+#include "CbmL1.h"
+#include "CbmL1StsTrackFinder.h"
+#include "CbmLitFindGlobalTracks.h"
+#include "CbmMCDataManager.h"
+#include "CbmMatchRecoToMC.h"
+#include "CbmMuchFindHitsGem.h"
+#include "CbmMvdClusterfinder.h"
+#include "CbmMvdHitfinder.h"
+#include "CbmPVFinderKF.h"
+#include "CbmPrimaryVertexFinder.h"
+#include "CbmPsdHitProducer.h"
+#include "CbmRecoSts.h"
+#include "CbmRichHitProducer.h"
+#include "CbmRichReconstruction.h"
+#include "CbmSetup.h"
+#include "CbmStsFindTracks.h"
+#include "CbmStsFindTracksEvents.h"
+#include "CbmStsTrackFinder.h"
+#include "CbmTaskBuildRawEvents.h"
+#include "CbmTofSimpClusterizer.h"
+#include "CbmTrdClusterFinder.h"
+#include "CbmTrdHitProducer.h"
+
+#include <FairFileSource.h>
+#include <FairMonitor.h>
+#include <FairParAsciiFileIo.h>
+#include <FairParRootFileIo.h>
+#include <FairRunAna.h>
+#include <FairRuntimeDb.h>
+#include <FairSystemInfo.h>
+
+#include <TStopwatch.h>
+#endif
+
+
+/** @brief Macro for CBM reconstruction
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @since  14 November 2020
+ ** @param input          Name of input file (w/o extension .raw.root)
+ ** @param nTimeSlices    Number of time-slices to process
+ ** @param firstTimeSlice First time-slice (entry) to be processed
+ ** @param output         Name of output file (w/o extension .rec.root)
+ ** @param sEvBuildRaw    Option for raw event building
+ ** @param setup          Name of predefined geometry setup
+ ** @param paramFile      Parameter ROOT file (w/o extension .par.root)
+ ** @param useMC          Option to provide the trackfinder with MC information
+ **
+ ** This macro performs from the digis in a time-slice. It can be used
+ ** for simulated data (result of run_digi.C) or real data after unpacking.
+ **
+ ** The macro covers both time-based reconstruction and event-based
+ ** reconstruction using raw events build from digis. This can be selected
+ ** by the forth argument. If left empty, no raw event builder will be
+ ** employed and reconstruction will be time-based. The option "Ideal"
+ ** selects the ideal raw event builder, which associates digis to events
+ ** based on the MC truth. The option "Real" selects a real raw event builder
+ ** (latest version, for older versions use "Real2018" or "Real2019").
+ ** 
+ **
+ ** The file names must be specified without extensions. The convention is
+ ** that the raw (input) file is [input].raw.root. The output file
+ ** will be [input].rec.root if not specified by the user. The parameter file
+ ** has the extension .par.root. It is assumed to be [input].par.root if
+ ** not specified by the user.
+ **
+ ** If no argument is specified, the input will be set to "test". This allows
+ ** to execute the macro chain (run_tra_file.C, run_digi.C and run_reco.C)
+ ** from the ROOT prompt without user intervention.
+ **
+ **/
+void run_reco_mcbm(TString input = "", Int_t nTimeSlices = -1, Int_t firstTimeSlice = 0, TString output = "",
+                   TString sEvBuildRaw = "", TString setup = "sis100_electron", TString paramFile = "",
+                   Bool_t useMC = false)
+{
+
+  // ========================================================================
+  //          Adjust this part according to your requirements
+
+  // --- Logger settings ----------------------------------------------------
+  TString logLevel     = "debug";
+  TString logVerbosity = "LOW";
+  // ------------------------------------------------------------------------
+
+  // -----   Environment   --------------------------------------------------
+  TString myName = "run_reco";                     // this macro's name for screen output
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  // ------------------------------------------------------------------------
+
+
+  // -----   In- and output file names   ------------------------------------
+  if (input.IsNull()) input = "test";
+  TString rawFile = input + ".raw.root";
+  TString traFile = input + ".tra.root";
+  if (output.IsNull()) output = input;
+  TString outFile = output + ".reco.root";
+  TString monFile = output + ".moni_reco.root";
+  if (paramFile.IsNull()) paramFile = input;
+  TString parFile = paramFile + ".par.root";
+  std::cout << "Inputfile " << rawFile << std::endl;
+  std::cout << "Outfile " << outFile << std::endl;
+  std::cout << "Parfile " << parFile << std::endl;
+
+  // -----   Load the geometry setup   -------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Loading setup " << setup << std::endl;
+  CbmSetup* geo = CbmSetup::Instance();
+  geo->LoadSetup(setup);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Some global switches   -----------------------------------------
+  Bool_t eventBased = !sEvBuildRaw.IsNull();
+  Bool_t useMvd     = geo->IsActive(ECbmModuleId::kMvd);
+  Bool_t useSts     = geo->IsActive(ECbmModuleId::kSts);
+  Bool_t useRich    = geo->IsActive(ECbmModuleId::kRich);
+  Bool_t useMuch    = geo->IsActive(ECbmModuleId::kMuch);
+  Bool_t useTrd     = geo->IsActive(ECbmModuleId::kTrd);
+  Bool_t useTof     = geo->IsActive(ECbmModuleId::kTof);
+  Bool_t usePsd     = geo->IsActive(ECbmModuleId::kPsd);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Parameter files as input to the runtime database   -------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Defining parameter files " << std::endl;
+  TList* parFileList = new TList();
+  TString geoTag;
+
+  // - TRD digitisation parameters
+  if (CbmSetup::Instance()->GetGeoTag(ECbmModuleId::kTrd, geoTag)) {
+    const Char_t* npar[4] = {"asic", "digi", "gas", "gain"};
+    TObjString* trdParFile(NULL);
+    for (Int_t i(0); i < 4; i++) {
+      trdParFile = new TObjString(srcDir + "/parameters/trd/trd_" + geoTag + "." + npar[i] + ".par");
+      parFileList->Add(trdParFile);
+      std::cout << "-I- " << myName << ": Using parameter file " << trdParFile->GetString() << std::endl;
+    }
+  }
+
+  // - TOF digitisation parameters
+  if (CbmSetup::Instance()->GetGeoTag(ECbmModuleId::kTof, geoTag)) {
+    TObjString* tofBdfFile = new TObjString(srcDir + "/parameters/tof/tof_" + geoTag + ".digibdf.par");
+    parFileList->Add(tofBdfFile);
+    std::cout << "-I- " << myName << ": Using parameter file " << tofBdfFile->GetString() << std::endl;
+  }
+  // ------------------------------------------------------------------------
+
+  // In general, the following parts need not be touched
+  // ========================================================================
+
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+
+  // -----   FairRunAna   ---------------------------------------------------
+  FairRunAna* run             = new FairRunAna();
+  FairFileSource* inputSource = new FairFileSource(rawFile);
+  if (useMC) { inputSource->AddFriend(traFile); }
+  run->SetSource(inputSource);
+  run->SetOutputFile(outFile);
+  run->SetGenerateRunInfo(kTRUE);
+  FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monFile);
+  // ------------------------------------------------------------------------
+
+  // -----   MCDataManager  -----------------------------------
+  if (useMC) {
+    CbmMCDataManager* mcManager = new CbmMCDataManager("MCDataManager", 0);
+    mcManager->AddFile(traFile);
+    run->AddTask(mcManager);
+  }
+  // ------------------------------------------------------------------------
+
+  // -----   Logger settings   ----------------------------------------------
+  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
+  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
+  // ------------------------------------------------------------------------
+
+
+  // -----   Raw event building from digis   --------------------------------
+  if (eventBased) {
+    if (sEvBuildRaw.EqualTo("Ideal", TString::ECaseCompare::kIgnoreCase)) {
+      FairTask* evBuildRaw = new CbmBuildEventsIdeal();
+      run->AddTask(evBuildRaw);
+      std::cout << "-I- " << myName << ": Added task " << evBuildRaw->GetName() << std::endl;
+      eventBased = kTRUE;
+    }  //? Ideal raw event building
+    else if (sEvBuildRaw.EqualTo("Real", TString::ECaseCompare::kIgnoreCase)) {
+      CbmEvbuildRawTask* evBuildRaw = new CbmEvbuildRawTask();
+
+      //Choose between NoOverlap, MergeOverlap, AllowOverlap
+      evBuildRaw->SetEventOverlapMode(EOverlapModeRaw::AllowOverlap);
+
+      // Remove detectors where digis not found
+      if (!useRich) evBuildRaw->RemoveDetector(kRawEventBuilderDetRich);
+      if (!useMuch) evBuildRaw->RemoveDetector(kRawEventBuilderDetMuch);
+      if (!usePsd) evBuildRaw->RemoveDetector(kRawEventBuilderDetPsd);
+      if (!useTof) evBuildRaw->RemoveDetector(kRawEventBuilderDetTof);
+      if (!useTrd) evBuildRaw->RemoveDetector(kRawEventBuilderDetTrd);
+      if (!useSts) {
+        std::cerr << "-E- " << myName << ": Sts must be present for raw event "
+                  << "building using ``Real2019'' option. Terminating macro." << std::endl;
+        return;
+      }
+      // Set STS as reference detector
+      evBuildRaw->SetReferenceDetector(kRawEventBuilderDetTof);
+      evBuildRaw->SetTsParameters(0.0, 1.e7, 0.0);
+
+      // Use CbmMuchDigi instead of CbmMuchBeamtimeDigi
+      evBuildRaw->ChangeMuchBeamtimeDigiFlag(kFALSE);
+
+      //evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kSts, 1000);
+      evBuildRaw->SetTriggerMinNumber(ECbmModuleId::kTof, 5);
+      //evBuildRaw->SetTriggerMaxNumber(ECbmModuleId::kSts, -1);
+      evBuildRaw->SetTriggerWindow(ECbmModuleId::kSts, -500, 500);
+
+      run->AddTask(evBuildRaw);
+      std::cout << "-I- " << myName << ": Added task " << evBuildRaw->GetName() << std::endl;
+      eventBased = kTRUE;
+    }  //? Real raw event building
+    else {
+      std::cerr << "-E- " << myName << ": Unknown option " << sEvBuildRaw
+                << " for raw event building! Terminating macro execution." << std::endl;
+      return;
+    }
+  }  //? event-based reco
+  // ------------------------------------------------------------------------
+
+
+  // -----  Parameter database   --------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Set runtime DB" << std::endl;
+  FairRuntimeDb* rtdb        = run->GetRuntimeDb();
+  FairParRootFileIo* parIo1  = new FairParRootFileIo();
+  FairParAsciiFileIo* parIo2 = new FairParAsciiFileIo();
+  parIo1->open(parFile.Data(), "UPDATE");
+  rtdb->setFirstInput(parIo1);
+  if (!parFileList->IsEmpty()) {
+    parIo2->open(parFileList, "in");
+    rtdb->setSecondInput(parIo2);
+  }
+  // ------------------------------------------------------------------------
+
+
+  // -----   Run initialisation   -------------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Initialise run" << std::endl;
+  run->Init();
+  rtdb->setOutput(parIo1);
+  rtdb->saveOutput();
+  rtdb->print();
+  // ------------------------------------------------------------------------
+
+
+  // -----   Start run   ----------------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Starting run" << std::endl;
+  run->Run(firstTimeSlice, nTimeSlices);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  FairMonitor::GetMonitor()->Print();
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  std::cout << std::endl << std::endl;
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "Output file is    " << outFile << std::endl;
+  std::cout << "Parameter file is " << parFile << std::endl;
+  std::cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << std::endl;
+  FairSystemInfo sysInfo;
+  Float_t maxMemory = sysInfo.GetMaxMemory();
+  std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
+  std::cout << maxMemory;
+  std::cout << "</DartMeasurement>" << std::endl;
+  Float_t cpuUsage = ctime / rtime;
+  std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
+  std::cout << cpuUsage;
+  std::cout << "</DartMeasurement>" << std::endl;
+  // ------------------------------------------------------------------------
+
+
+  // -----   This is to prevent a malloc error when exiting ROOT   ----------
+  // The source of the error is unknown. Related to TGeoManager.
+  RemoveGeoManager();
+  // ------------------------------------------------------------------------
+
+}  // End of main macro function
diff --git a/reco/eventbuilder/CMakeLists.txt b/reco/eventbuilder/CMakeLists.txt
index 17f0aaa1af6f661c70b2b23a2d3d5318f393d875..9473646a6df9dbec5e2f4b65e55152414569cb68 100644
--- a/reco/eventbuilder/CMakeLists.txt
+++ b/reco/eventbuilder/CMakeLists.txt
@@ -67,6 +67,8 @@ link_directories( ${LINK_DIRECTORIES})
 
 set(SRCS
 
+digis/CbmEvbuildRawAlgo.cxx
+digis/CbmEvbuildRawTask.cxx
 digis/CbmAlgoBuildRawEvents.cxx
 digis/CbmTaskBuildRawEvents.cxx
 digis/CbmBuildEventsIdeal.cxx
diff --git a/reco/eventbuilder/CbmEventBuilderLinkDef.h b/reco/eventbuilder/CbmEventBuilderLinkDef.h
index f6743998e726cae0cb26d36259d71097d861b518..0837321fcb068b1e50c1b634377452b0c42d32e4 100644
--- a/reco/eventbuilder/CbmEventBuilderLinkDef.h
+++ b/reco/eventbuilder/CbmEventBuilderLinkDef.h
@@ -8,6 +8,8 @@
 #pragma link off all classes;
 #pragma link off all functions;
 
+#pragma link C++ class CbmEvbuildRawAlgo + ;
+#pragma link C++ class CbmEvbuildRawTask + ;
 #pragma link C++ class CbmAlgoBuildRawEvents + ;
 #pragma link C++ class CbmTaskBuildRawEvents + ;
 #pragma link C++ class CbmBuildEventsFromTracksIdeal + ;
diff --git a/reco/eventbuilder/digis/CbmEvbuildRawAlgo.cxx b/reco/eventbuilder/digis/CbmEvbuildRawAlgo.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0610a9e18bdd0dfe42598da67c20a46d51ed439a
--- /dev/null
+++ b/reco/eventbuilder/digis/CbmEvbuildRawAlgo.cxx
@@ -0,0 +1,990 @@
+/********************************************************************************
+ *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
+ *                                                                              *
+ *              This software is distributed under the terms of the             *
+ *              GNU Lesser General Public Licence (LGPL) version 3,             *
+ *                  copied verbatim in the file "LICENSE"                       *
+ ********************************************************************************/
+#include "CbmEvbuildRawAlgo.h"
+
+/// CBM headers
+#include "CbmMuchBeamTimeDigi.h"
+#include "CbmMuchDigi.h"
+#include "CbmPsdDigi.h"
+#include "CbmRawEvent.h"
+#include "CbmRichDigi.h"
+#include "CbmStsDigi.h"
+#include "CbmTofDigi.h"
+#include "CbmTrdDigi.h"
+
+#include "TimesliceMetaData.h"
+
+/// FAIRROOT headers
+#include <FairLogger.h>
+#include <FairRootManager.h>
+#include <FairRunOnline.h>
+
+/// FAIRSOFT headers (geant, boost, ...)
+#include <TCanvas.h>
+#include <TClonesArray.h>
+#include <TFolder.h>
+#include <TH1.h>
+#include <TH2.h>
+#include <THttpServer.h>
+#include <TStopwatch.h>
+
+template<>
+void CbmEvbuildRawAlgo::LoopOnSeeds<Double_t>();
+
+Bool_t CbmEvbuildRawAlgo::InitAlgo()
+{
+  LOG(info) << "CbmEvbuildRawAlgo::InitAlgo => Starting sequence";
+
+  if (fbGetTimings) {
+    fTimer = new TStopwatch;
+    fTimer->Start();
+  }
+
+  /// Check if reference detector is set and seed data are available,
+  /// otherwise look for explicit seed times
+  if (fRefDet.detId == ECbmModuleId::kNotExist) {
+    if (fSeedTimes == nullptr) {
+      LOG(fatal) << "No reference detector set and no seed times supplied, stopping there!";
+    }
+  }
+  else {
+    if (fSeedTimes != nullptr) {
+      LOG(fatal) << "Cannot have explicit seed times and reference detector, stopping there!";
+    }
+    if (kFALSE == CheckDataAvailable(fRefDet)) {
+      LOG(fatal) << "Reference detector set but no digi input found, stopping there!";
+    }
+  }
+
+  /// Check if data for detectors in selection list are available
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if (kFALSE == CheckDataAvailable(*det)) {
+      LOG(fatal) << "No digi input for one of selection detector, stopping there!";
+    }
+  }
+
+  /// Access the TS metadata to know TS start time if needed
+  if (fbUseTsMetaData) {
+    if (!fTimeSliceMetaDataArray) {
+      LOG(fatal) << "No TS metadata input found"
+                 << " => Please check in the unpacking macro if the following line was "
+                    "present!"
+                 << std::endl
+                 << "source->SetWriteOutputFlag(kTRUE);  // For writing TS metadata";
+    }
+  }
+  if (fbFillHistos) { CreateHistograms(); }
+  if (fTimer != nullptr) {
+    fTimer->Stop();
+    Double_t rtime = fTimer->RealTime();
+    Double_t ctime = fTimer->CpuTime();
+    LOG(info) << "CbmEvbuildRawAlgo::Init(): Real time " << rtime << " s, CPU time " << ctime << " s";
+  }
+
+  LOG(info) << "CbmEvbuildRawAlgo::InitAlgo => Done";
+  return kTRUE;
+}
+
+void CbmEvbuildRawAlgo::Finish()
+{
+  if (fbGetTimings) { PrintTimings(); }
+}
+
+void CbmEvbuildRawAlgo::PrintTimings()
+{
+  if (fTimer == nullptr) { LOG(fatal) << "Trying to print timings but timer not set"; }
+  else {
+    Double_t rtime = fTimer->RealTime();
+    Double_t ctime = fTimer->CpuTime();
+    LOG(info) << "CbmEvbuildRawAlgo: Real time " << rtime << " s, CPU time " << ctime << " s";
+  }
+}
+
+void CbmEvbuildRawAlgo::ClearEventVector()
+{
+  /// Need to delete the object the pointer points to first
+  int counter = 0;
+  for (CbmRawEvent* event : fEventVector) {
+    LOG(debug) << "Event " << counter << " has " << event->GetNofDigis() << " digis";
+    delete event;
+    counter++;
+  }
+  fEventVector.clear();
+}
+
+void CbmEvbuildRawAlgo::ProcessTs()
+{
+  LOG_IF(info, fuNrTs % 1000 == 0) << "Begin of TS " << fuNrTs;
+  if (fTimer != nullptr) { fTimer->Start(kFALSE); }
+  LOG(debug) << "Init timeslice";
+  InitTs();
+  LOG(debug) << "Init seed window";
+  InitSeedWindow();
+  LOG(debug) << "Build events";
+  BuildEvents();
+
+  /// Store last event with trigger if not done by other seed
+  if (nullptr != fCurrentEvent) {
+    /// TODO: store start time of current event ?
+    //        fCurrentEvent->SetStartTime( fPrevTime ); // Replace Seed time with time of first digi in event?
+    //fCurrentEvent->SetEndTime(fdPrevEvtEndTime);
+    fEventVector.push_back(fCurrentEvent);
+    fuCurEv++;
+
+    /// Prevent building over TS edge
+    fCurrentEvent = nullptr;
+  }
+
+  LOG(debug) << "Found " << fEventVector.size() << " triggered events";
+  if (fbFillHistos) { FillHistos(); }
+  if (fTimer != nullptr) { fTimer->Stop(); }
+
+  fuNrTs++;
+}
+
+void CbmEvbuildRawAlgo::InitTs()
+{
+  /// Reset TS based variables (analysis per TS = no building over the border)
+
+  /// Reference detector
+  if (fRefDet.detId != ECbmModuleId::kNotExist) {
+    fRefDet.fuStartIndex = 0;
+    fRefDet.fuEndIndex   = 0;
+  }
+  /// Loop on detectors in selection list
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    (*det).fuStartIndex = 0;
+    (*det).fuEndIndex   = 0;
+  }
+}
+
+void CbmEvbuildRawAlgo::InitSeedWindow()
+{
+  /// Access the TS metadata if needed to know TS start time and overlap size
+  Double_t dTsStartTime  = fdTsStartTime;
+  Double_t dOverlapStart = fdTsStartTime + fdTsLength;
+  Double_t dOverlapSize  = fdTsOverLength;
+
+  if (fbUseTsMetaData) {
+    const TimesliceMetaData* pTsMetaData = dynamic_cast<TimesliceMetaData*>(fTimeSliceMetaDataArray->At(0));
+    if (nullptr == pTsMetaData)
+      LOG(fatal) << Form("CbmEvbuildRawAlgo::LoopOnSeeds => "
+                         "No TS metadata found for TS %6u.",
+                         fuNrTs);
+    dTsStartTime  = pTsMetaData->GetStartTime();
+    dOverlapStart = pTsMetaData->GetOverlapStartTime();
+    dOverlapSize  = pTsMetaData->GetOverlapDuration();
+  }
+
+  /// Print warning in first TS if time window borders out of potential overlap
+  if ((0.0 < fdEarliestTimeWinBeg && dOverlapSize < fdLatestTimeWinEnd) || (dOverlapSize < fdWidestTimeWinRange)) {
+    LOG(warning) << "CbmEvbuildRawAlgo::LoopOnSeeds => "
+                 << Form("Event window not fitting in TS overlap, risk of "
+                         "incomplete events: %f %f %f %f",
+                         fdEarliestTimeWinBeg, fdLatestTimeWinEnd, fdWidestTimeWinRange, dOverlapSize);
+  }  // if end of event window does not fit in overlap for a seed at edge of TS core
+
+  /// Define an acceptance window for the seeds in order to use the overlap
+  /// part of the TS to avoid incomplete events
+  if (fbIgnoreTsOverlap) {
+    fdSeedWindowBeg = dTsStartTime;
+    fdSeedWindowEnd = dOverlapStart;
+  }
+  else {
+    fdSeedWindowBeg = dTsStartTime + (0.0 < fdEarliestTimeWinBeg ? 0.0 : -fdEarliestTimeWinBeg);
+    fdSeedWindowEnd = dOverlapStart + (0.0 < fdEarliestTimeWinBeg ? 0.0 : -fdEarliestTimeWinBeg);
+  }
+}
+
+void CbmEvbuildRawAlgo::BuildEvents()
+{
+  /// Call LoopOnSeed with proper template argument
+  switch (fRefDet.detId) {
+    case ECbmModuleId::kSts: {
+      LoopOnSeeds<CbmStsDigi>();
+      break;
+    }
+    case ECbmModuleId::kMuch: {
+      if (fbUseMuchBeamtimeDigi) { LoopOnSeeds<CbmMuchBeamTimeDigi>(); }
+      else {
+        LoopOnSeeds<CbmMuchDigi>();
+      }
+      break;
+    }
+    case ECbmModuleId::kTrd: {
+      LoopOnSeeds<CbmTrdDigi>();
+      break;
+    }
+    case ECbmModuleId::kTof: {
+      LoopOnSeeds<CbmTofDigi>();
+      break;
+    }
+    case ECbmModuleId::kRich: {
+      LoopOnSeeds<CbmRichDigi>();
+      break;
+    }
+    case ECbmModuleId::kPsd: {
+      LoopOnSeeds<CbmPsdDigi>();
+      break;
+    }
+    case ECbmModuleId::kT0: {
+      LoopOnSeeds<CbmTofDigi>();
+      break;
+    }
+    case ECbmModuleId::kNotExist: {  //explicit seed times
+      LoopOnSeeds<Double_t>();
+      break;
+    }
+    default: {
+      LOG(fatal) << "CbmEvbuildRawAlgo::BuildEvents => "
+                 << "Trying to search event seeds with unsupported det: " << fRefDet.sName;
+      break;
+    }
+  }
+}
+
+template<>
+void CbmEvbuildRawAlgo::LoopOnSeeds<Double_t>()
+{
+  if (ECbmModuleId::kNotExist == fRefDet.detId) {
+    const UInt_t uNbSeeds = fSeedTimes->size();
+    /// Loop on size of vector
+    for (UInt_t uSeed = 0; uSeed < uNbSeeds; ++uSeed) {
+      LOG(debug) << Form("Checking seed %6u / %6u", uSeed, uNbSeeds);
+      Double_t dTime = fSeedTimes->at(uSeed);
+
+      /// Check if seed in acceptance window (is this needed here?)
+      if (dTime < fdSeedWindowBeg) { continue; }
+      else if (fdSeedWindowEnd < dTime) {
+        break;
+      }
+      /// Check Seed and build event if needed
+      CheckSeed(dTime, uSeed);
+    }
+  }
+  else {
+    LOG(fatal) << "Trying to read explicit seeds while reference detector is set.";
+  }
+}
+
+template<class DigiSeed>
+void CbmEvbuildRawAlgo::LoopOnSeeds()
+{
+  if (ECbmModuleId::kT0 == fRefDet.detId) {
+    const UInt_t uNbRefDigis = fT0DigiVec->size();
+    /// Loop on size of vector
+    for (UInt_t uDigi = 0; uDigi < uNbRefDigis; ++uDigi) {
+      LOG(debug) << Form("Checking seed %6u / %6u", uDigi, uNbRefDigis);
+      Double_t dTime = fT0DigiVec->at(uDigi).GetTime();
+      /// Check Seed and build event if needed
+      CheckSeed(dTime, uDigi);
+    }
+  }
+  else {
+    const UInt_t uNbRefDigis = GetNofDigis(fRefDet.detId);
+    /// Loop on size of vector
+    for (UInt_t uDigi = 0; uDigi < uNbRefDigis; ++uDigi) {
+      LOG(debug) << Form("Checking seed %6u / %6u", uDigi, uNbRefDigis);
+      const DigiSeed* pDigi = GetDigi<DigiSeed>(uDigi);
+      const Double_t dTime  = pDigi->GetTime();
+
+      /// Check if seed in acceptance window
+      if (dTime < fdSeedWindowBeg) { continue; }
+      else if (fdSeedWindowEnd < dTime) {
+        break;
+      }
+      /// Check Seed and build event if needed
+      CheckSeed(dTime, uDigi);
+    }
+  }
+}
+
+Double_t CbmEvbuildRawAlgo::GetSeedTimeWinRange()
+{
+  if (ECbmModuleId::kNotExist != fRefDet.detId) { return fRefDet.GetTimeWinRange(); }
+  else {
+    return fdSeedTimeWinEnd - fdSeedTimeWinBeg;
+  }
+}
+
+void CbmEvbuildRawAlgo::CheckSeed(Double_t dSeedTime, UInt_t uSeedDigiIdx)
+{
+  /// If previous event valid and event overlap not allowed, check if we are in overlap
+  /// and react accordingly
+  if (nullptr != fCurrentEvent
+      && (EOverlapModeRaw::AllowOverlap != fOverMode || dSeedTime - fdPrevEvtTime < GetSeedTimeWinRange())
+      && dSeedTime - fdPrevEvtTime < fdWidestTimeWinRange) {
+    /// Within overlap range
+    switch (fOverMode) {
+      case EOverlapModeRaw::NoOverlap: {
+        /// No overlap allowed => reject
+        LOG(debug1) << "Reject seed due to overlap";
+        return;
+        break;
+      }
+      case EOverlapModeRaw::MergeOverlap: {
+        /// Merge overlap mode => do nothing and go on filling current event
+        break;
+      }
+      case EOverlapModeRaw::AllowOverlap: {
+        /// In allow overlap mode => reject only if reference det is in overlap
+        /// to avoid cloning events due to single seed cluster
+        LOG(debug1) << "Reject seed because part of cluster of previous one";
+        return;
+        break;
+      }
+    }
+  }  // if( prev Event exists and mode forbiden overlap present )
+  else {
+    /// Out of overlap range or in overlap allowed mode
+    /// => store previous event if not empty and create new one
+    if (nullptr != fCurrentEvent) {
+      /// TODO: store start time of current event ?
+      //        fCurrentEvent->SetStartTime( fPrevTime ); // Replace Seed time with time of first digi in event?
+      //fCurrentEvent->SetEndTime(fdPrevEvtEndTime);
+      fEventVector.push_back(fCurrentEvent);
+      fuCurEv++;
+    }
+    fCurrentEvent = new CbmRawEvent(fuCurEv, dSeedTime);
+  }  // else of if( prev Event exists and mode forbiden overlap present )
+
+  if (fRefDet.detId != ECbmModuleId::kNotExist) {
+    /// If window open for reference detector, search for other reference Digis matching it
+    /// Otherwise only add the current seed
+    if (fRefDet.fdTimeWinBeg < fRefDet.fdTimeWinEnd) {
+      SearchMatches(dSeedTime, fRefDet);
+      /// Also add the seed if the window starts after the seed
+      if (0 < fRefDet.fdTimeWinBeg) AddDigiToEvent(fRefDet, uSeedDigiIdx);
+    }
+    else {
+      AddDigiToEvent(fRefDet, uSeedDigiIdx);
+    }
+  }
+
+  /// Search for matches for each detector in selection list
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    SearchMatches(dSeedTime, *det);
+  }
+
+  CheckTriggerCondition(dSeedTime);
+}
+
+void CbmEvbuildRawAlgo::SearchMatches(Double_t dSeedTime, RawEventBuilderDetector& detMatch)
+{
+  switch (detMatch.detId) {
+    case ECbmModuleId::kSts: {
+      SearchMatches<CbmStsDigi>(dSeedTime, detMatch);
+      break;
+    }
+    case ECbmModuleId::kMuch: {
+      if (fbUseMuchBeamtimeDigi) { SearchMatches<CbmMuchBeamTimeDigi>(dSeedTime, detMatch); }
+      else {
+        SearchMatches<CbmMuchDigi>(dSeedTime, detMatch);
+      }
+      break;
+    }
+    case ECbmModuleId::kTrd: {
+      SearchMatches<CbmTrdDigi>(dSeedTime, detMatch);
+      break;
+    }
+    case ECbmModuleId::kTof: {
+      SearchMatches<CbmTofDigi>(dSeedTime, detMatch);
+      break;
+    }
+    case ECbmModuleId::kRich: {
+      SearchMatches<CbmRichDigi>(dSeedTime, detMatch);
+      break;
+    }
+    case ECbmModuleId::kPsd: {
+      SearchMatches<CbmPsdDigi>(dSeedTime, detMatch);
+      break;
+    }
+    case ECbmModuleId::kT0: {
+      SearchMatches<CbmTofDigi>(dSeedTime, detMatch);
+      break;
+    }
+    default: {
+      LOG(fatal) << "CbmEvbuildRawAlgo::LoopOnSeeds => "
+                 << "Trying to search matches with unsupported det: " << detMatch.sName << std::endl
+                 << "You may want to add support for it in the method.";
+      break;
+    }
+  }
+}
+
+template<class DigiCheck>
+void CbmEvbuildRawAlgo::SearchMatches(Double_t dSeedTime, RawEventBuilderDetector& detMatch)
+{
+  /// This algo relies on time sorted vectors for the selected detectors
+  UInt_t uLocalIndexStart = detMatch.fuStartIndex;
+  UInt_t uLocalIndexEnd   = detMatch.fuStartIndex;
+
+  /// Check the Digis until out of window
+  if (ECbmModuleId::kT0 == detMatch.detId) {
+
+    /// Loop on size of vector
+    const UInt_t uNbSelDigis = fT0DigiVec->size();
+    for (UInt_t uDigi = detMatch.fuStartIndex; uDigi < uNbSelDigis; ++uDigi) {
+      const Double_t dTime     = fT0DigiVec->at(uDigi).GetTime();
+      const Double_t dTimeDiff = dTime - dSeedTime;
+
+      /// Check if within time window, update start/stop indices if needed
+      if (dTimeDiff < detMatch.fdTimeWinBeg) {
+        ++uLocalIndexStart;
+        continue;
+      }
+      else if (detMatch.fdTimeWinEnd < dTimeDiff) {
+        /// Store as end the first digi out of window to avoid double counting in case of
+        /// merged overlap event mode
+        uLocalIndexEnd = uDigi;
+        break;
+      }
+      AddDigiToEvent(detMatch, uDigi);
+      if (fdPrevEvtEndTime < dTime) fdPrevEvtEndTime = dTime;
+    }
+
+    /// catch the case where we reach the end of the vector before being out of the time window
+    if (uLocalIndexEnd < uLocalIndexStart) uLocalIndexEnd = uNbSelDigis;
+  }
+  else {
+    const UInt_t uNbSelDigis = GetNofDigis(detMatch.detId);
+    /// Loop on size of vector
+    for (UInt_t uDigi = detMatch.fuStartIndex; uDigi < uNbSelDigis; ++uDigi) {
+      const DigiCheck* pDigi   = GetDigi<DigiCheck>(uDigi);
+      const Double_t dTime     = pDigi->GetTime();
+      const Double_t dTimeDiff = dTime - dSeedTime;
+      LOG(debug4) << detMatch.sName << Form(" => Checking match %6u / %6u, dt %f", uDigi, uNbSelDigis, dTimeDiff);
+
+      /// Check if within time window, update start/stop indices if needed
+      if (dTimeDiff < detMatch.fdTimeWinBeg) {
+        ++uLocalIndexStart;
+        continue;
+      }
+      else if (detMatch.fdTimeWinEnd < dTimeDiff) {
+        /// Store as end the first digi out of window to avoid double counting in case of
+        /// merged overlap event mode
+        uLocalIndexEnd = uDigi;
+        break;
+      }
+      AddDigiToEvent(detMatch, uDigi);
+      if (fdPrevEvtEndTime < dTime) fdPrevEvtEndTime = dTime;
+    }
+    /// catch the case where we reach the end of the vector before being out of the time window
+    if (uLocalIndexEnd < uLocalIndexStart) uLocalIndexEnd = uNbSelDigis;
+  }
+
+  /// Update the StartIndex and EndIndex for the next event seed
+  detMatch.fuStartIndex = uLocalIndexStart;
+  detMatch.fuEndIndex   = uLocalIndexEnd;
+}
+
+void CbmEvbuildRawAlgo::AddDigiToEvent(RawEventBuilderDetector& det, Int_t _entry)
+{
+  switch (det.detId) {
+    case ECbmModuleId::kSts: fCurrentEvent->AddDigiSts(fStsDigis->at(_entry)); break;
+    case ECbmModuleId::kRich: fCurrentEvent->AddDigiRich(fRichDigis->at(_entry)); break;
+    case ECbmModuleId::kMuch: fCurrentEvent->AddDigiMuch(fMuchDigis->at(_entry)); break;
+    case ECbmModuleId::kTrd: fCurrentEvent->AddDigiTrd(fTrdDigis->at(_entry)); break;
+    case ECbmModuleId::kTof: fCurrentEvent->AddDigiTof(fTofDigis->at(_entry)); break;
+    case ECbmModuleId::kPsd: fCurrentEvent->AddDigiPsd(fPsdDigis->at(_entry)); break;
+    default: break;
+  }
+}
+
+void CbmEvbuildRawAlgo::CheckTriggerCondition(Double_t dSeedTime)
+{
+  /// Check if event is filling trigger conditions and clear it if not
+  if (HasTrigger(fCurrentEvent)) {
+    fdPrevEvtTime = dSeedTime;
+
+    /// In case of NoOverlap or MergeOverlap, we can and should start checking the next window
+    /// from end of current window in order to save CPU and avoid duplicating
+    if (EOverlapModeRaw::NoOverlap == fOverMode || EOverlapModeRaw::MergeOverlap == fOverMode) {
+      /// Update reference detector
+      if (fRefDet.detId != ECbmModuleId::kNotExist) { fRefDet.fuStartIndex = fRefDet.fuEndIndex; }
+      /// Loop on selection detectors
+      for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+        (*det).fuStartIndex = (*det).fuEndIndex;
+      }
+    }
+  }
+  else {
+    LOG(debug1) << "Reject seed due to Trigger requirements";
+    delete fCurrentEvent;
+    fCurrentEvent = nullptr;  /// delete does NOT set a pointer to nullptr...
+  }
+}
+
+Bool_t CbmEvbuildRawAlgo::HasTrigger(CbmRawEvent* event)
+{
+  /// Check first reference detector
+  if (fRefDet.detId != ECbmModuleId::kNotExist) {
+    if (kFALSE == CheckTriggerConditions(event, fRefDet)) { return kFALSE; }
+  }
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if (kFALSE == CheckTriggerConditions(event, *det)) return kFALSE;
+  }
+  /// All Ok, trigger is there
+  return kTRUE;
+}
+
+Bool_t CbmEvbuildRawAlgo::CheckTriggerConditions(CbmRawEvent* event, RawEventBuilderDetector& det)
+{
+  /// Check if both Trigger conditions disabled for this detector
+  if (0 == det.fuTriggerMinDigis && det.fiTriggerMaxDigis < 0) { return kTRUE; }
+
+  /// Check if detector present
+  if (!CheckDataAvailable(det.detId)) {
+    LOG(warning) << "Event does not have digis storage for " << det.sName
+                 << " while the following trigger min/max are defined: " << det.fuTriggerMinDigis << " "
+                 << det.fiTriggerMaxDigis;
+    return kFALSE;
+  }
+
+  /// Check trigger rejection by minimal number or absence
+  const Int_t iNbDigis = event->GetNofDigis(det.detId);
+  if ((-1 == iNbDigis) || (static_cast<UInt_t>(iNbDigis) < det.fuTriggerMinDigis)) {
+    LOG(debug2) << "Event does not have enough digis: " << iNbDigis << " vs " << det.fuTriggerMinDigis << " for "
+                << det.sName;
+    return kFALSE;
+  }
+
+  /// Check trigger rejection by maximal number
+  else if (0 < det.fiTriggerMaxDigis && det.fiTriggerMaxDigis < iNbDigis) {
+    LOG(debug2) << "Event Has too many digis: " << iNbDigis << " vs " << det.fiTriggerMaxDigis << " for " << det.sName;
+    return kFALSE;
+  }
+  else {
+    return kTRUE;
+  }
+}
+
+//----------------------------------------------------------------------
+
+Bool_t CbmEvbuildRawAlgo::CheckDataAvailable(RawEventBuilderDetector& det)
+{
+  if (!CheckDataAvailable(det.detId)) {
+    LOG(info) << "No " << det.sName << " digi input found.";
+    return kFALSE;
+  }
+  return kTRUE;
+}
+
+bool CbmEvbuildRawAlgo::CheckDataAvailable(ECbmModuleId detId)
+{
+  switch (detId) {
+    case ECbmModuleId::kSts: {
+      return fStsDigis != nullptr;
+    }
+    case ECbmModuleId::kMuch: {
+      if (fbUseMuchBeamtimeDigi) { return fMuchBeamTimeDigis != nullptr; }
+      else {
+        return fMuchDigis != nullptr;
+      }
+    }
+    case ECbmModuleId::kTrd: {
+      return fTrdDigis != nullptr;
+    }
+    case ECbmModuleId::kTof: {
+      return fTofDigis != nullptr;
+    }
+    case ECbmModuleId::kRich: {
+      return fRichDigis != nullptr;
+    }
+    case ECbmModuleId::kPsd: {
+      return fPsdDigis != nullptr;
+    }
+    case ECbmModuleId::kT0: {
+      return fT0DigiVec != nullptr;
+    }
+    default: {
+      LOG(fatal) << "CbmEvbuildRawAlgo::CheckDataAvailable => "
+                 << "Unsupported detector.";
+      return -1;
+    }
+  }
+}
+
+UInt_t CbmEvbuildRawAlgo::GetNofDigis(ECbmModuleId detId)
+{
+  switch (detId) {
+    case ECbmModuleId::kSts: {
+      return fStsDigis->size();
+    }
+    case ECbmModuleId::kMuch: {
+      if (fbUseMuchBeamtimeDigi) { return fMuchBeamTimeDigis->size(); }
+      else {
+        return fMuchDigis->size();
+      }
+    }
+    case ECbmModuleId::kTrd: {
+      return fTrdDigis->size();
+    }
+    case ECbmModuleId::kTof: {
+      return fTofDigis->size();
+    }
+    case ECbmModuleId::kRich: {
+      return fRichDigis->size();
+    }
+    case ECbmModuleId::kPsd: {
+      return fPsdDigis->size();
+    }
+    case ECbmModuleId::kT0: {
+      return fT0DigiVec->size();  //what to do here? Not in digi manager.
+    }
+    default: {
+      LOG(fatal) << "CbmEvbuildRawAlgo::GetNofDigis => "
+                 << "Trying to get digi number with unsupported detector.";
+      return -1;
+    }
+  }
+}
+
+template<>
+const CbmStsDigi* CbmEvbuildRawAlgo::GetDigi(UInt_t uDigi)
+{
+  return &((*fStsDigis)[uDigi]);
+}
+template<>
+const CbmMuchBeamTimeDigi* CbmEvbuildRawAlgo::GetDigi(UInt_t uDigi)
+{
+  return &((*fMuchBeamTimeDigis)[uDigi]);
+}
+template<>
+const CbmMuchDigi* CbmEvbuildRawAlgo::GetDigi(UInt_t uDigi)
+{
+  return &((*fMuchDigis)[uDigi]);
+}
+template<>
+const CbmTrdDigi* CbmEvbuildRawAlgo::GetDigi(UInt_t uDigi)
+{
+  return &((*fTrdDigis)[uDigi]);
+}
+template<>
+const CbmTofDigi* CbmEvbuildRawAlgo::GetDigi(UInt_t uDigi)
+{
+  return &((*fTofDigis)[uDigi]);
+}
+template<>
+const CbmRichDigi* CbmEvbuildRawAlgo::GetDigi(UInt_t uDigi)
+{
+  return &((*fRichDigis)[uDigi]);
+}
+template<>
+const CbmPsdDigi* CbmEvbuildRawAlgo::GetDigi(UInt_t uDigi)
+{
+  return &((*fPsdDigis)[uDigi]);
+}
+
+//----------------------------------------------------------------------
+void CbmEvbuildRawAlgo::CreateHistograms()
+{
+  outFolder = new TFolder("AlgoBuildRawEventsHist", " AlgoBuildRawEvents Histos");
+  outFolder->Clear();
+
+  fhEventTime = new TH1F("hEventTime", "seed time of the events; Seed time [s]; Events", 1000, 0, 0.001);
+  fhEventTime->SetCanExtend(TH1::kAllAxes);
+
+  fhEventDt =
+    new TH1F("fhEventDt", "interval in seed time of consecutive events; Seed time [s]; Events", 1000, 0, 0.0001);
+  fhEventDt->SetCanExtend(TH1::kAllAxes);
+
+  fhEventSize = new TH1F("hEventSize", "nb of all  digis in the event; Nb Digis []; Events []", 1000, 0, 100);
+  fhEventSize->SetCanExtend(TH1::kAllAxes);
+
+  fhNbDigiPerEvtTime = new TH2I("hNbDigiPerEvtTime",
+                                "nb of all  digis per event vs seed time of the events; Seed time "
+                                "[s]; Nb Digis []; Events []",
+                                1000, 0, 0.001, 1000, 0, 100);
+  fhNbDigiPerEvtTime->SetCanExtend(TH2::kAllAxes);
+
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    /// In case name not provided, do not create the histo to avoid name conflicts!
+    if ("Invalid" == (*det).sName) {
+      fvhNbDigiPerEvtTimeDet.push_back(nullptr);
+      continue;
+    }
+    TH2I* hNbDigiPerEvtTimeDet = new TH2I(Form("hNbDigiPerEvtTime%s", (*det).sName.data()),
+                                          Form("nb of %s digis per event vs seed time of the events; Seed time "
+                                               "[s]; Nb Digis []; Events []",
+                                               (*det).sName.data()),
+                                          1000, 0, 0.001, 1000, 0, 100);
+    hNbDigiPerEvtTimeDet->SetCanExtend(TH2::kAllAxes);
+    fvhNbDigiPerEvtTimeDet.push_back(hNbDigiPerEvtTimeDet);
+  }
+
+  AddHistoToVector(fhEventTime, "evtbuild");
+  AddHistoToVector(fhEventDt, "evtbuild");
+  AddHistoToVector(fhEventSize, "evtbuild");
+  AddHistoToVector(fhNbDigiPerEvtTime, "evtbuild");
+  outFolder->Add(fhEventTime);
+  outFolder->Add(fhEventDt);
+  outFolder->Add(fhEventSize);
+  outFolder->Add(fhNbDigiPerEvtTime);
+
+  for (std::vector<TH2*>::iterator itHist = fvhNbDigiPerEvtTimeDet.begin(); itHist != fvhNbDigiPerEvtTimeDet.end();
+       ++itHist) {
+    if (nullptr != (*itHist)) {
+      AddHistoToVector((*itHist), "evtbuild");
+      outFolder->Add((*itHist));
+    }
+  }
+}
+
+void CbmEvbuildRawAlgo::FillHistos()
+{
+  Double_t dPreEvtTime = -1.0;
+  for (CbmRawEvent* evt : fEventVector) {
+    fhEventTime->Fill(evt->GetTime() * 1e-9);
+    if (0.0 <= dPreEvtTime) { fhEventDt->Fill((evt->GetTime() - dPreEvtTime) * 1e-9); }
+
+    fhEventSize->Fill(evt->GetNofDigis());
+    fhNbDigiPerEvtTime->Fill(evt->GetTime() * 1e-9, evt->GetNofDigis());
+
+    /// Loop on selection detectors
+    for (UInt_t uDetIdx = 0; uDetIdx < fvDets.size(); ++uDetIdx) {
+      if (nullptr == fvhNbDigiPerEvtTimeDet[uDetIdx]) continue;
+      fvhNbDigiPerEvtTimeDet[uDetIdx]->Fill(evt->GetTime() * 1e-9, evt->GetNofDigis(fvDets[uDetIdx].detId));
+    }
+    dPreEvtTime = evt->GetTime();
+  }
+}
+
+void CbmEvbuildRawAlgo::ResetHistograms(Bool_t /*bResetTime*/)
+{
+  fhEventTime->Reset();
+  fhEventDt->Reset();
+  fhEventSize->Reset();
+
+  fhNbDigiPerEvtTime->Reset();
+  /// Loop on histograms
+  for (std::vector<TH2*>::iterator itHist = fvhNbDigiPerEvtTimeDet.begin(); itHist != fvhNbDigiPerEvtTimeDet.end();
+       ++itHist) {
+    (*itHist)->Reset();
+  }
+  /*
+   if( kTRUE == bResetTime )
+   {
+      /// Also reset the Start time for the evolution plots!
+      fdStartTime = -1.0;
+   } 
+   */
+}
+
+void CbmEvbuildRawAlgo::SetReferenceDetector(ECbmModuleId refDet, ECbmDataType dataTypeIn, std::string sNameIn,
+                                             UInt_t uTriggerMinDigisIn, Int_t iTriggerMaxDigisIn,
+                                             Double_t fdTimeWinBegIn, Double_t fdTimeWinEndIn)
+{
+  /// FIXME: Deprecated method to be removed later. For now create temp object.
+  SetReferenceDetector(RawEventBuilderDetector(refDet, dataTypeIn, sNameIn, uTriggerMinDigisIn, iTriggerMaxDigisIn,
+                                               fdTimeWinBegIn, fdTimeWinEndIn));
+}
+void CbmEvbuildRawAlgo::AddDetector(ECbmModuleId selDet, ECbmDataType dataTypeIn, std::string sNameIn,
+                                    UInt_t uTriggerMinDigisIn, Int_t iTriggerMaxDigisIn, Double_t fdTimeWinBegIn,
+                                    Double_t fdTimeWinEndIn)
+{
+  /// FIXME: Deprecated method to be removed later. For now create temp object.
+  AddDetector(RawEventBuilderDetector(selDet, dataTypeIn, sNameIn, uTriggerMinDigisIn, iTriggerMaxDigisIn,
+                                      fdTimeWinBegIn, fdTimeWinEndIn));
+}
+
+void CbmEvbuildRawAlgo::SetReferenceDetector(RawEventBuilderDetector refDetIn)
+{
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if ((*det) == refDetIn) {
+      LOG(warning) << "CbmEvbuildRawAlgo::SetReferenceDetector => "
+                      "Reference detector already in selection detector list!"
+                   << refDetIn.sName;
+      LOG(warning) << "                                                         => "
+                      "It will be automatically removed from selection detector list!";
+      LOG(warning) << "                                                         => "
+                      "Please also remember to update the selection windows to store "
+                      "clusters!";
+      RemoveDetector(refDetIn);
+    }
+  }
+
+  if (fRefDet == refDetIn) {
+    LOG(warning) << "CbmEvbuildRawAlgo::SetReferenceDetector => "
+                    "Doing nothing, identical reference detector already in use";
+  }
+  else {
+    LOG(info) << "CbmEvbuildRawAlgo::SetReferenceDetector => "
+              << "Replacing " << fRefDet.sName << " with " << refDetIn.sName << " as reference detector";
+    LOG(warning) << "                                                         => "
+                    "You may want to use AddDetector after this command to add in "
+                    "selection "
+                 << refDetIn.sName;
+    LOG(warning) << "                                                         => "
+                    "Please also remember to update the selection windows!";
+  }
+  fRefDet = refDetIn;
+
+  /// Update the variables storing the earliest and latest time window boundaries
+  UpdateTimeWinBoundariesExtrema();
+  /// Update the variable storing the size if widest time window for overlap detection
+  UpdateWidestTimeWinRange();
+}
+
+void CbmEvbuildRawAlgo::AddDetector(RawEventBuilderDetector selDet)
+{
+  if (fRefDet == selDet) {
+    LOG(fatal) << "CbmEvbuildRawAlgo::AddDetector => Cannot "
+                  "add the reference detector as selection detector!"
+               << std::endl
+               << "=> Maybe first change the reference detector with "
+                  "SetReferenceDetector?";
+  }
+
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if ((*det) == selDet) {
+      LOG(warning) << "CbmEvbuildRawAlgo::AddDetector => "
+                      "Doing nothing, selection detector already in list!"
+                   << selDet.sName;
+      return;
+    }
+  }
+  fvDets.push_back(selDet);
+
+  /// Update the variables storing the earliest and latest time window boundaries
+  UpdateTimeWinBoundariesExtrema();
+  /// Update the variable storing the size if widest time window for overlap detection
+  UpdateWidestTimeWinRange();
+}
+
+void CbmEvbuildRawAlgo::RemoveDetector(RawEventBuilderDetector selDet)
+{
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if ((*det) == selDet) {
+      fvDets.erase(det);
+      return;
+    }
+  }
+  LOG(warning) << "CbmEvbuildRawAlgo::RemoveDetector => Doing "
+                  "nothing, selection detector not in list!"
+               << selDet.sName;
+}
+
+void CbmEvbuildRawAlgo::SetTriggerMinNumber(ECbmModuleId selDet, UInt_t uVal)
+{
+  /// Check first if reference detector
+  if (fRefDet.detId == selDet) {
+    fRefDet.fuTriggerMinDigis = uVal;
+    LOG(debug) << "Set Trigger min limit for " << fRefDet.sName << " to " << uVal;
+    return;
+  }
+
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if ((*det).detId == selDet) {
+      (*det).fuTriggerMinDigis = uVal;
+      LOG(debug) << "Set Trigger min limit for " << (*det).sName << " to " << uVal;
+      return;
+    }
+  }
+  LOG(warning) << "CbmEvbuildRawAlgo::SetTriggerMinNumber => "
+                  "Doing nothing, detector neither reference nor in selection list!"
+               << selDet;
+}
+
+void CbmEvbuildRawAlgo::SetTriggerMaxNumber(ECbmModuleId selDet, Int_t iVal)
+{
+  /// Check first if reference detector
+  if (fRefDet.detId == selDet) {
+    fRefDet.fiTriggerMaxDigis = iVal;
+    LOG(debug) << "Set Trigger min limit for " << fRefDet.sName << " to " << iVal;
+    return;
+  }
+
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if ((*det).detId == selDet) {
+      (*det).fiTriggerMaxDigis = iVal;
+      LOG(debug) << "Set Trigger min limit for " << (*det).sName << " to " << iVal;
+      return;
+    }
+  }
+  LOG(warning) << "CbmEvbuildRawAlgo::SetTriggerMaxNumber => "
+                  "Doing nothing, detector neither reference nor in selection list!"
+               << selDet;
+}
+
+void CbmEvbuildRawAlgo::SetTriggerWindow(ECbmModuleId selDet, Double_t dWinBeg, Double_t dWinEnd)
+{
+  /// Check if valid time window: end strictly after beginning
+  if (dWinEnd <= dWinBeg) {
+    LOG(fatal) << "CbmEvbuildRawAlgo::SetTriggerWindow => "
+                  "Invalid time window: [ "
+               << dWinBeg << ", " << dWinEnd << " ]";
+  }
+
+  Bool_t bFound = kFALSE;
+  /// Check first if reference detector
+  if (fRefDet.detId == selDet) {
+    fRefDet.fdTimeWinBeg = dWinBeg;
+    fRefDet.fdTimeWinEnd = dWinEnd;
+    bFound               = kTRUE;
+  }
+
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    if ((*det).detId == selDet) {
+      (*det).fdTimeWinBeg = dWinBeg;
+      (*det).fdTimeWinEnd = dWinEnd;
+      bFound              = kTRUE;
+    }
+  }
+
+  if (kFALSE == bFound) {
+    LOG(warning) << "CbmEvbuildRawAlgo::SetTriggerWindow => "
+                    "Doing nothing, detector neither reference nor in selection list!"
+                 << selDet;
+  }
+
+  /// Update the variables storing the earliest and latest time window boundaries
+  UpdateTimeWinBoundariesExtrema();
+  /// Update the variable storing the size if widest time window for overlap detection
+  UpdateWidestTimeWinRange();
+}
+
+void CbmEvbuildRawAlgo::UpdateTimeWinBoundariesExtrema()
+{
+  /// Initialize with reference detector or explicit times
+  if (fRefDet.detId != ECbmModuleId::kNotExist) {
+    fdEarliestTimeWinBeg = fRefDet.fdTimeWinBeg;
+    fdLatestTimeWinEnd   = fRefDet.fdTimeWinEnd;
+  }
+  else {
+    fdEarliestTimeWinBeg = fdSeedTimeWinBeg;
+    fdLatestTimeWinEnd   = fdSeedTimeWinEnd;
+  }
+
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    fdEarliestTimeWinBeg = std::min(fdEarliestTimeWinBeg, (*det).fdTimeWinBeg);
+    fdLatestTimeWinEnd   = std::max(fdLatestTimeWinEnd, (*det).fdTimeWinEnd);
+  }
+}
+
+void CbmEvbuildRawAlgo::UpdateWidestTimeWinRange()
+{
+  /// Initialize with reference detector
+  fdWidestTimeWinRange = GetSeedTimeWinRange();
+
+  /// Loop on selection detectors
+  for (std::vector<RawEventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det) {
+    fdWidestTimeWinRange = std::max(fdWidestTimeWinRange, (*det).fdTimeWinEnd - (*det).fdTimeWinBeg);
+  }
+}
+
+ClassImp(CbmEvbuildRawAlgo)
diff --git a/reco/eventbuilder/digis/CbmEvbuildRawAlgo.h b/reco/eventbuilder/digis/CbmEvbuildRawAlgo.h
new file mode 100644
index 0000000000000000000000000000000000000000..cdf52673488994db4d237717c81e02f77a65b969
--- /dev/null
+++ b/reco/eventbuilder/digis/CbmEvbuildRawAlgo.h
@@ -0,0 +1,343 @@
+/********************************************************************************
+ *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
+ *                                                                              *
+ *              This software is distributed under the terms of the             *
+ *              GNU Lesser General Public Licence (LGPL) version 3,             *
+ *                  copied verbatim in the file "LICENSE"                       *
+ ********************************************************************************/
+#ifndef CBMEVBUILDRAWALGO_H
+#define CBMEVBUILDRAWALGO_H
+
+/// CBM headers
+#include "CbmAlgoBuildRawEvents.h"
+#include "CbmMuchBeamTimeDigi.h"
+#include "CbmMuchDigi.h"
+#include "CbmPsdDigi.h"
+#include "CbmRichDigi.h"
+#include "CbmStsDigi.h"
+#include "CbmTofDigi.h"
+#include "CbmTrdDigi.h"
+
+/// FAIRROOT headers
+#include "FairTask.h"
+
+/// FAIRSOFT headers (geant, boost, ...)
+
+/// C/C++ headers
+#include <tuple>
+
+#include <boost/any.hpp>
+
+#include <array>
+#include <map>
+#include <set>
+#include <vector>
+
+class TimesliceMetaData;
+class CbmRawEvent;
+class TClonesArray;
+class TH1;
+class TH2;
+class TNamed;
+class TStopwatch;
+class TCanvas;
+
+/*
+enum class EOverlapModeRaw
+{
+  NoOverlap,
+  MergeOverlap,
+  AllowOverlap
+};
+*/
+
+/*
+class RawEventBuilderDetector {
+public:
+  RawEventBuilderDetector() = default;
+
+  RawEventBuilderDetector(ECbmModuleId detIdIn, ECbmDataType dataTypeIn, std::string sNameIn)
+    : detId {detIdIn}
+    , dataType {dataTypeIn}
+    , sName {sNameIn}
+  {
+  }
+
+  RawEventBuilderDetector(ECbmModuleId detIdIn, ECbmDataType dataTypeIn, std::string sNameIn, UInt_t uTriggerMinDigisIn,
+                          Int_t iTriggerMaxDigisIn, Double_t fdTimeWinBegIn, Double_t fdTimeWinEndIn)
+    : RawEventBuilderDetector(detIdIn, dataTypeIn, sNameIn)
+  {
+    fuTriggerMinDigis = uTriggerMinDigisIn;
+    fiTriggerMaxDigis = iTriggerMaxDigisIn;
+    fdTimeWinBeg      = fdTimeWinBegIn;
+    fdTimeWinEnd      = fdTimeWinEndIn;
+  }
+
+  bool operator==(const RawEventBuilderDetector& other) const { return (other.detId == this->detId); }
+  bool operator!=(const RawEventBuilderDetector& other) const { return (other.detId != this->detId); }
+
+  Double_t GetTimeWinRange() { return fdTimeWinEnd - fdTimeWinBeg; }
+
+  /// Settings
+  ECbmModuleId detId    = ECbmModuleId::kNotExist;
+  ECbmDataType dataType = ECbmDataType::kUnknown;
+  std::string sName     = "Invalid";
+  /// Minimum number of T0 digis needed to generate a trigger, 0 means don't use for trigger generation
+  UInt_t fuTriggerMinDigis = 0;
+  /// Maximum number of digis per detector to generate an event, -1 means no cut, 0 means anti-coinc trigger
+  Int_t fiTriggerMaxDigis = -1;
+  /// Selection Window
+  Double_t fdTimeWinBeg = -100;
+  Double_t fdTimeWinEnd = 100;
+  /// Book-keeping variables
+  UInt_t fuStartIndex = 0;
+  UInt_t fuEndIndex   = 0;
+};
+
+/// Pre-defined detector types
+static const RawEventBuilderDetector kRawEventBuilderDetSts =
+  RawEventBuilderDetector(ECbmModuleId::kSts, ECbmDataType::kStsDigi, "Sts");
+static const RawEventBuilderDetector kRawEventBuilderDetMuch =
+  RawEventBuilderDetector(ECbmModuleId::kMuch, ECbmDataType::kMuchDigi, "Much");
+static const RawEventBuilderDetector kRawEventBuilderDetTrd =
+  RawEventBuilderDetector(ECbmModuleId::kTrd, ECbmDataType::kTrdDigi, "Trd");
+static const RawEventBuilderDetector kRawEventBuilderDetTof =
+  RawEventBuilderDetector(ECbmModuleId::kTof, ECbmDataType::kTofDigi, "Tof");
+static const RawEventBuilderDetector kRawEventBuilderDetRich =
+  RawEventBuilderDetector(ECbmModuleId::kRich, ECbmDataType::kRichDigi, "Rich");
+static const RawEventBuilderDetector kRawEventBuilderDetPsd =
+  RawEventBuilderDetector(ECbmModuleId::kPsd, ECbmDataType::kPsdDigi, "Psd");
+static const RawEventBuilderDetector kRawEventBuilderDetT0 =
+  RawEventBuilderDetector(ECbmModuleId::kT0, ECbmDataType::kT0Digi, "T0");
+static const RawEventBuilderDetector kRawEventBuilderDetUndef = RawEventBuilderDetector();
+
+*/
+
+class CbmEvbuildRawAlgo {
+public:
+  /** Default constructor **/
+  CbmEvbuildRawAlgo() = default;
+
+  CbmEvbuildRawAlgo(const CbmEvbuildRawAlgo&) = delete;
+  CbmEvbuildRawAlgo operator=(const CbmEvbuildRawAlgo&) = delete;
+
+  /** Destructor **/
+  ~CbmEvbuildRawAlgo() {};
+
+  /** Initiliazation at the beginning of a run **/
+  Bool_t InitAlgo();
+
+  /** Executed for each TS. **/
+  void ProcessTs();
+
+  /** Finish called at the end of the run **/
+  void Finish();
+
+  void SetFillHistos(Bool_t var) { fbFillHistos = var; }
+  void ResetHistograms(Bool_t bResetTime = kTRUE);
+
+  /** stopwatch timing **/
+  void SetTimings(Bool_t var) { fbGetTimings = var; }
+  void PrintTimings();
+
+  void SetReferenceDetector(ECbmModuleId refDet, ECbmDataType dataTypeIn, std::string sNameIn,
+                            UInt_t uTriggerMinDigisIn = 0, Int_t iTriggerMaxDigisIn = -1,
+                            Double_t fdTimeWinBegIn = -100, Double_t fdTimeWinEndIn = 100);
+  void AddDetector(ECbmModuleId selDet, ECbmDataType dataTypeIn, std::string sNameIn, UInt_t uTriggerMinDigisIn = 0,
+                   Int_t iTriggerMaxDigisIn = -1, Double_t fdTimeWinBegIn = -100, Double_t fdTimeWinEndIn = 100);
+
+  void SetReferenceDetector(RawEventBuilderDetector refDetIn);
+  void AddDetector(RawEventBuilderDetector selDet);
+  void RemoveDetector(RawEventBuilderDetector selDet);
+
+  void SetTriggerMinNumber(ECbmModuleId selDet, UInt_t uVal);
+  void SetTriggerMaxNumber(ECbmModuleId selDet, Int_t iVal);
+  void SetTriggerWindow(ECbmModuleId selDet, Double_t dWinBeg, Double_t dWinEnd);
+
+  void SetTsParameters(Double_t dTsStartTime, Double_t dTsLength, Double_t dTsOverLength)
+  {
+    fdTsStartTime   = dTsStartTime;
+    fdTsLength      = dTsLength;
+    fdTsOverLength  = dTsOverLength;
+    fbUseTsMetaData = kFALSE;
+  }
+
+  void SetSeedTimeWindow(Double_t timeWinBeg, Double_t timeWinEnd)
+  {
+    fdSeedTimeWinBeg = timeWinBeg;
+    fdSeedTimeWinEnd = timeWinEnd;
+    UpdateTimeWinBoundariesExtrema();
+    UpdateWidestTimeWinRange();
+  }
+
+  /// Control flags
+  void SetEventOverlapMode(EOverlapModeRaw mode) { fOverMode = mode; }
+  void SetIgnoreTsOverlap(Bool_t bFlagIn = kTRUE) { fbIgnoreTsOverlap = bFlagIn; }
+
+  void ChangeMuchBeamtimeDigiFlag(Bool_t bFlagIn = kFALSE) { fbUseMuchBeamtimeDigi = bFlagIn; }
+
+  /// For monitor algos
+  void AddHistoToVector(TNamed* pointer, std::string sFolder = "")
+  {
+    fvpAllHistoPointers.push_back(std::pair<TNamed*, std::string>(pointer, sFolder));
+  }
+  std::vector<std::pair<TNamed*, std::string>> GetHistoVector() { return fvpAllHistoPointers; }
+  void AddCanvasToVector(TCanvas* pointer, std::string sFolder = "")
+  {
+    fvpAllCanvasPointers.push_back(std::pair<TCanvas*, std::string>(pointer, sFolder));
+  }
+  std::vector<std::pair<TCanvas*, std::string>> GetCanvasVector() { return fvpAllCanvasPointers; }
+
+  /// Set digi containers
+  void SetT0Digis(const std::vector<CbmTofDigi>* T0DigiVec) { fT0DigiVec = T0DigiVec; }
+  void SetStsDigis(std::vector<CbmStsDigi>* StsDigis) { fStsDigis = StsDigis; }
+  void SetMuchDigis(std::vector<CbmMuchDigi>* MuchDigis) { fMuchDigis = MuchDigis; }
+  void SetTrdDigis(std::vector<CbmTrdDigi>* TrdDigis) { fTrdDigis = TrdDigis; }
+  void SetTofDigis(std::vector<CbmTofDigi>* TofDigis) { fTofDigis = TofDigis; }
+  void SetRichDigis(std::vector<CbmRichDigi>* RichDigis) { fRichDigis = RichDigis; }
+  void SetPsdDigis(std::vector<CbmPsdDigi>* PsdDigis) { fPsdDigis = PsdDigis; }
+  void SetMuchBeamTimeDigis(std::vector<CbmMuchBeamTimeDigi>* MuchBeamTimeDigis)
+  {
+    fMuchBeamTimeDigis = MuchBeamTimeDigis;
+  }
+
+  void SetSeedTimes(std::vector<Double_t>* SeedTimes) { fSeedTimes = SeedTimes; }
+
+  // TS metadata
+  void SetTimeSliceMetaDataArray(TClonesArray* TimeSliceMetaDataArray)
+  {
+    fTimeSliceMetaDataArray = TimeSliceMetaDataArray;
+  }
+
+  // Output folder for histograms
+  TFolder* GetOutFolder() { return outFolder; }
+
+  /// Data output access
+  std::vector<CbmRawEvent*>& GetEventVector() { return fEventVector; }
+  void ClearEventVector();
+
+private:
+  /// Internal methods
+  Bool_t CheckDataAvailable(RawEventBuilderDetector& det);
+  void InitTs();
+  void InitSeedWindow();
+  void BuildEvents();
+
+  void CreateHistograms();
+  void FillHistos();
+
+  template<class DigiSeed>
+  void LoopOnSeeds();
+
+  void CheckSeed(Double_t dSeedTime, UInt_t uSeedDigiIdx);
+  void CheckTriggerCondition(Double_t dSeedTime);
+
+  template<class DigiCheck>
+  void SearchMatches(Double_t dSeedTime, RawEventBuilderDetector& detMatch);
+  void SearchMatches(Double_t dSeedTime, RawEventBuilderDetector& detMatch);
+  void AddDigiToEvent(RawEventBuilderDetector& det, Int_t uIdx);
+  Bool_t HasTrigger(CbmRawEvent*);
+  Bool_t CheckTriggerConditions(CbmRawEvent* event, RawEventBuilderDetector& det);
+
+  void UpdateTimeWinBoundariesExtrema();
+  void UpdateWidestTimeWinRange();
+
+  TFolder* outFolder;  // oputput folder to store histograms
+
+  /// Constants
+  static constexpr Double_t kdDefaultTimeWinBeg = -100.0;
+  static constexpr Double_t kdDefaultTimeWinEnd = 100.0;
+
+  /// User parameters
+  /// Control flags
+  Bool_t fbIgnoreTsOverlap = kFALSE;      //! Ignore data in Overlap part of the TS
+  Bool_t fbFillHistos {kTRUE};            //! Switch ON/OFF filling of histograms
+  Bool_t fbUseMuchBeamtimeDigi = kTRUE;   //! Switch between MUCH digi classes
+  Bool_t fbGetTimings          = kFALSE;  //! Measure CPU time using stopwatch
+  Bool_t fbUseTsMetaData       = kTRUE;   //! Read Ts Parameters from input tree
+    /// Event building mode and detectors selection
+  EOverlapModeRaw fOverMode {EOverlapModeRaw::AllowOverlap};
+
+  TStopwatch* fTimer = nullptr;  //! is create when fbGetTimings is set before init
+
+  RawEventBuilderDetector fRefDet             = RawEventBuilderDetector(ECbmModuleId::kT0, ECbmDataType::kT0Digi, "T0");
+  std::vector<RawEventBuilderDetector> fvDets = {
+    RawEventBuilderDetector(ECbmModuleId::kSts, ECbmDataType::kStsDigi, "kSts"),
+    RawEventBuilderDetector(ECbmModuleId::kMuch, ECbmDataType::kMuchDigi, "kMuch"),
+    RawEventBuilderDetector(ECbmModuleId::kTrd, ECbmDataType::kTrdDigi, "kTrd"),
+    RawEventBuilderDetector(ECbmModuleId::kTof, ECbmDataType::kTofDigi, "kTof"),
+    RawEventBuilderDetector(ECbmModuleId::kRich, ECbmDataType::kRichDigi, "kRich"),
+    RawEventBuilderDetector(ECbmModuleId::kPsd, ECbmDataType::kPsdDigi, "kPsd")};
+
+  Double_t fdEarliestTimeWinBeg = kdDefaultTimeWinBeg;
+  Double_t fdLatestTimeWinEnd   = kdDefaultTimeWinEnd;
+  Double_t fdWidestTimeWinRange = kdDefaultTimeWinEnd - kdDefaultTimeWinBeg;
+  ///Seed window
+  Double_t fdSeedWindowBeg = 0;
+  Double_t fdSeedWindowEnd = 0;
+
+  Double_t fdTsStartTime  = -1;
+  Double_t fdTsLength     = -1;
+  Double_t fdTsOverLength = -1;
+
+  /// Data input
+  TClonesArray* fTimeSliceMetaDataArray = nullptr;  //!
+
+  const std::vector<CbmTofDigi>* fT0DigiVec                  = nullptr;
+  const std::vector<CbmMuchDigi>* fMuchDigis                 = nullptr;
+  const std::vector<CbmMuchBeamTimeDigi>* fMuchBeamTimeDigis = nullptr;
+  const std::vector<CbmStsDigi>* fStsDigis                   = nullptr;
+  const std::vector<CbmTrdDigi>* fTrdDigis                   = nullptr;
+  const std::vector<CbmTofDigi>* fTofDigis                   = nullptr;
+  const std::vector<CbmRichDigi>* fRichDigis                 = nullptr;
+  const std::vector<CbmPsdDigi>* fPsdDigis                   = nullptr;
+
+  // If explicit seed times are supplied.
+  const std::vector<Double_t>* fSeedTimes = nullptr;
+  Double_t fdSeedTimeWinBeg               = -100.0;
+  Double_t fdSeedTimeWinEnd               = 100.0;
+
+  bool CheckDataAvailable(ECbmModuleId detId);
+  UInt_t GetNofDigis(ECbmModuleId detId);
+  template<class Digi>
+  const Digi* GetDigi(UInt_t uDigi);
+
+  Double_t GetSeedTimeWinRange();
+
+  /// Data ouptut
+  CbmRawEvent* fCurrentEvent             = nullptr;  //! pointer to the event which is currently build
+  std::vector<CbmRawEvent*> fEventVector = {};       //! vector with all created events
+
+  /// Monitoring histograms
+  /// => Pointers should be filled with TH1*, TH2*, TProfile*, ...
+  /// ==> To check if object N is of type T, use "T ObjectPointer = dynamic_cast<T>( fvpAllHistoPointers[N].first );" and check for nullptr
+  /// ==> To get back the original class name use "fvpAllHistoPointers[N].first->ClassName()" which returns a const char * (e.g. "TH1I")
+  /// ===> Usage example with feeding a THttpServer:
+  /// ===> #include "TH2.h"
+  /// ===> std::string sClassName = vHistos[ uHisto ].first.ClassName();
+  /// ===> if( !strncmp( sClassName, "TH1", 3 ) )
+  /// ===>    server->Register( vHistos[ uHisto ].second.data(), dynamic_cast< TH1 * >(vHistos[ uHisto ].first) );
+  /// ===> else if( !strncmp( sClassName, "TH2", 3 ) )
+  /// ===>    server->Register( vHistos[ uHisto ].second.data(), dynamic_cast< TH2 * >(vHistos[ uHisto ].first) );
+  std::vector<std::pair<TNamed*, std::string>>
+    fvpAllHistoPointers;  //! Vector of pointers to histograms + optional folder name
+  std::vector<std::pair<TCanvas*, std::string>>
+    fvpAllCanvasPointers;  //! Vector of pointers to canvases + optional folder name
+
+  TH1* fhEventTime        = nullptr;  //! histogram with the seed time of the events
+  TH1* fhEventDt          = nullptr;  //! histogram with the interval in seed time of consecutive events
+  TH1* fhEventSize        = nullptr;  //! histogram with the nb of all  digis in the event
+  TH2* fhNbDigiPerEvtTime = nullptr;  //! histogram with the nb of all  digis per event vs seed time of the events
+  std::vector<TH2*> fvhNbDigiPerEvtTimeDet =
+    {};  //! histograms with the nb of digis in each detector per event vs seed time of the events
+
+  /// Internal state variables
+  UInt_t fuCurEv            = 0;   //! Event Counter
+  UInt_t fuNrTs             = 0;   //! Timeslice Counter
+  Double_t fdPrevEvtTime    = 0.;  //! Save previous time information
+  Double_t fdPrevEvtEndTime = 0.;  //! Save previous event last digi time information
+
+  ClassDefNV(CbmEvbuildRawAlgo, 1);
+};
+
+#endif  // CBMEVBUILDRAWALGO_H
diff --git a/reco/eventbuilder/digis/CbmEvbuildRawTask.cxx b/reco/eventbuilder/digis/CbmEvbuildRawTask.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..729a2c9522157e4fc4a98320e3664d7f5e89a529
--- /dev/null
+++ b/reco/eventbuilder/digis/CbmEvbuildRawTask.cxx
@@ -0,0 +1,500 @@
+/********************************************************************************
+ *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
+ *                                                                              *
+ *              This software is distributed under the terms of the             *
+ *              GNU Lesser General Public Licence (LGPL) version 3,             *
+ *                  copied verbatim in the file "LICENSE"                       *
+ ********************************************************************************/
+#include "CbmEvbuildRawTask.h"
+
+#include "CbmDigiManager.h"
+#include "CbmRawEvent.h"
+
+#include <FairLogger.h>
+#include <FairRootManager.h>
+#include <FairRunOnline.h>
+
+#include <TClonesArray.h>
+#include <TFile.h>
+#include <TFolder.h>
+#include <TH1.h>
+#include <TH2.h>
+#include <THttpServer.h>
+#include <TStopwatch.h>
+
+#include <iomanip>
+
+using std::cout;
+using std::endl;
+using std::fixed;
+using std::left;
+using std::pair;
+using std::right;
+using std::setprecision;
+using std::setw;
+using std::stringstream;
+
+
+CbmEvbuildRawTask::CbmEvbuildRawTask() : FairTask("BuildRawEvents")
+{
+  /// Create Algo. To be made generic/switchable when more event building algo are available!
+  fpAlgo = new CbmEvbuildRawAlgo();
+}
+
+CbmEvbuildRawTask::~CbmEvbuildRawTask() {}
+
+void CbmEvbuildRawTask::SetParContainers() {}
+
+void CbmEvbuildRawTask::SetSeedTimeFiller(RawEventBuilderDetector seedDet)
+{
+  if (fSeedTimeDetList.size() > 0) { LOG(fatal) << "Cannot use seed detector list and single instance together."; }
+
+  fSeedTimeDet = seedDet;
+  if (fSeedTimeDet != kRawEventBuilderDetUndef) {
+    if (fSeedTimes == nullptr) { fSeedTimes = new std::vector<Double_t>; }
+  }
+  else {
+    if (fSeedTimes != nullptr) {
+      fSeedTimes->clear();
+      delete fSeedTimes;
+      fSeedTimes = nullptr;
+    }
+  }
+  fpAlgo->SetSeedTimes(fSeedTimes);
+}
+
+void CbmEvbuildRawTask::AddSeedTimeFillerToList(RawEventBuilderDetector seedDet)
+{
+  if (fSeedTimeDet != kRawEventBuilderDetUndef) {
+    LOG(fatal) << "Cannot use seed detector list and single instance together.";
+  }
+  if (fSeedTimes == nullptr) { fSeedTimes = new std::vector<Double_t>; }
+
+  fSeedTimeDetList.push_back(seedDet);
+  fpAlgo->SetSeedTimes(fSeedTimes);
+}
+
+InitStatus CbmEvbuildRawTask::Init()
+{
+  if (fbGetTimings) {
+    fTimer = new TStopwatch;
+    fTimer->Start();
+    fCopyTimer = new TStopwatch;
+    fCopyTimer->Reset();
+  }
+
+  /// Get a handle from the IO manager
+  FairRootManager* ioman = FairRootManager::Instance();
+
+  //T0 not included in digi manager.
+  fT0Digis = ioman->InitObjectAs<std::vector<CbmTofDigi> const*>("T0Digi");
+  if (!fT0Digis) { LOG(info) << "No T0 digi input."; }
+  else {
+    LOG(info) << "T0 digi input.";
+    fpAlgo->SetT0Digis(fT0Digis);
+  }
+
+  // Get a pointer to the previous already existing data level
+  fDigiMan = CbmDigiManager::Instance();
+  if (fbUseMuchBeamtimeDigi) { fDigiMan->UseMuchBeamTimeDigi(); }
+  fDigiMan->Init();
+
+  //Init STS digis
+  if (!fDigiMan->IsPresent(ECbmModuleId::kSts)) { LOG(info) << "No STS digi input."; }
+  else {
+    LOG(info) << "STS digi input.";
+    fStsDigis = new std::vector<CbmStsDigi>;
+    fpAlgo->SetStsDigis(fStsDigis);
+  }
+
+  //Init MUCH digis
+  if (!fDigiMan->IsPresent(ECbmModuleId::kMuch)) { LOG(info) << "No MUCH digi input."; }
+  else {
+    LOG(info) << "MUCH digi input.";
+    if (fbUseMuchBeamtimeDigi) {
+      fMuchBeamTimeDigis = new std::vector<CbmMuchBeamTimeDigi>;
+      fpAlgo->SetMuchBeamTimeDigis(fMuchBeamTimeDigis);
+    }
+    else {
+      fMuchDigis = new std::vector<CbmMuchDigi>;
+      fpAlgo->SetMuchDigis(fMuchDigis);
+    }
+  }
+
+  //Init TRD digis
+  if (!fDigiMan->IsPresent(ECbmModuleId::kTrd)) { LOG(info) << "No TRD digi input."; }
+  else {
+    LOG(info) << "TRD digi input.";
+    fTrdDigis = new std::vector<CbmTrdDigi>;
+    fpAlgo->SetTrdDigis(fTrdDigis);
+  }
+
+  //Init TOF digis
+  if (!fDigiMan->IsPresent(ECbmModuleId::kTof)) { LOG(info) << "No TOF digi input."; }
+  else {
+    LOG(info) << "TOF digi input.";
+    fTofDigis = new std::vector<CbmTofDigi>;
+    fpAlgo->SetTofDigis(fTofDigis);
+  }
+
+  //Init RICH digis
+  if (!fDigiMan->IsPresent(ECbmModuleId::kRich)) { LOG(info) << "No RICH digi input."; }
+  else {
+    LOG(info) << "RICH digi input.";
+    fRichDigis = new std::vector<CbmRichDigi>;
+    fpAlgo->SetRichDigis(fRichDigis);
+  }
+
+  //Init PSD digis
+  if (!fDigiMan->IsPresent(ECbmModuleId::kPsd)) { LOG(info) << "No PSD digi input."; }
+  else {
+    LOG(info) << "PSD digi input.";
+    fPsdDigis = new std::vector<CbmPsdDigi>;
+    fpAlgo->SetPsdDigis(fPsdDigis);
+  }
+
+  /// Register output array (CbmEvent)
+  fEvents = new TClonesArray("CbmRawEvent", 100);
+  ioman->Register("RawEvent", "CBM Raw Event", fEvents, IsOutputBranchPersistent("RawEvent"));
+  if (!fEvents) LOG(fatal) << "Output branch was not created";
+
+  // Set timeslice meta data
+  fpAlgo->SetTimeSliceMetaDataArray(dynamic_cast<TClonesArray*>(ioman->GetObject("TimesliceMetaData")));
+
+  if (fTimer != nullptr) {
+    fTimer->Stop();
+    Double_t rtime = fTimer->RealTime();
+    Double_t ctime = fTimer->CpuTime();
+    LOG(info) << "CbmEvbuildRawTask::Init(): Real time " << rtime << " s, CPU time " << ctime << " s";
+  }
+
+  /// Call Algo Init method
+  if (kTRUE == fpAlgo->InitAlgo()) return kSUCCESS;
+  else
+    return kFATAL;
+}
+
+
+InitStatus CbmEvbuildRawTask::ReInit() { return kSUCCESS; }
+
+void CbmEvbuildRawTask::Exec(Option_t* /*option*/)
+{
+  if (fTimer != nullptr) { fTimer->Start(kFALSE); }
+  TStopwatch timer;
+  timer.Start();
+
+  LOG(debug2) << "CbmEvbuildRawTask::Exec => Starting sequence";
+  //Warning: Int_t must be used for the loop counters instead of UInt_t,
+  //as the digi manager can return -1, which would be casted to +1
+  //during comparison, leading to an error.
+
+  if (fSeedTimeDet != kRawEventBuilderDetUndef && fSeedTimeDetList.size() > 0) {
+    LOG(fatal) << "Cannot use seed detector list and single instance together.";
+  }
+
+  //Reset explicit seed times if set
+  if (fSeedTimeDet != kRawEventBuilderDetUndef || fSeedTimeDetList.size() > 0) { fSeedTimes->clear(); }
+
+  if (fCopyTimer != nullptr) { fCopyTimer->Start(kFALSE); }
+
+  //Read STS digis
+  if (fDigiMan->IsPresent(ECbmModuleId::kSts)) {
+    fStsDigis->clear();
+    for (Int_t i = 0; i < fDigiMan->GetNofDigis(ECbmModuleId::kSts); i++) {
+      const CbmStsDigi* Digi = fDigiMan->Get<CbmStsDigi>(i);
+      fStsDigis->push_back(*Digi);
+      if (fSeedTimeDet.detId == ECbmModuleId::kSts) { fSeedTimes->push_back(Digi->GetTime()); }
+    }
+    LOG(debug) << "Read: " << fStsDigis->size() << " STS digis.";
+    LOG(debug) << "In DigiManager: " << fDigiMan->GetNofDigis(ECbmModuleId::kSts) << " STS digis.";
+  }
+
+  //Read MUCH digis
+  if (fDigiMan->IsPresent(ECbmModuleId::kMuch)) {
+    if (fbUseMuchBeamtimeDigi) {
+      fMuchBeamTimeDigis->clear();
+      for (Int_t i = 0; i < fDigiMan->GetNofDigis(ECbmModuleId::kMuch); i++) {
+        const CbmMuchBeamTimeDigi* Digi = fDigiMan->Get<CbmMuchBeamTimeDigi>(i);
+        fMuchBeamTimeDigis->push_back(*Digi);
+        if (fSeedTimeDet.detId == ECbmModuleId::kMuch) { fSeedTimes->push_back(Digi->GetTime()); }
+      }
+      LOG(debug) << "Read: " << fDigiMan->GetNofDigis(ECbmModuleId::kMuch) << " MUCH digis.";
+      LOG(debug) << "In DigiManager: " << fMuchBeamTimeDigis->size() << " MUCH digis.";
+    }
+    else {
+      fMuchDigis->clear();
+      for (Int_t i = 0; i < fDigiMan->GetNofDigis(ECbmModuleId::kMuch); i++) {
+        const CbmMuchDigi* Digi = fDigiMan->Get<CbmMuchDigi>(i);
+        fMuchDigis->push_back(*Digi);
+        if (fSeedTimeDet.detId == ECbmModuleId::kMuch) { fSeedTimes->push_back(Digi->GetTime()); }
+      }
+      LOG(debug) << "Read: " << fDigiMan->GetNofDigis(ECbmModuleId::kMuch) << " MUCH digis.";
+      LOG(debug) << "In DigiManager: " << fMuchDigis->size() << " MUCH digis.";
+    }
+  }
+
+  //Read TRD digis
+  if (fDigiMan->IsPresent(ECbmModuleId::kTrd)) {
+    fTrdDigis->clear();
+    for (Int_t i = 0; i < fDigiMan->GetNofDigis(ECbmModuleId::kTrd); i++) {
+      const CbmTrdDigi* Digi = fDigiMan->Get<CbmTrdDigi>(i);
+      fTrdDigis->push_back(*Digi);
+      if (fSeedTimeDet.detId == ECbmModuleId::kTrd) { fSeedTimes->push_back(Digi->GetTime()); }
+    }
+    LOG(debug) << "Read: " << fDigiMan->GetNofDigis(ECbmModuleId::kTrd) << " TRD digis.";
+    LOG(debug) << "In DigiManager: " << fTrdDigis->size() << " TRD digis.";
+  }
+
+  //Read TOF digis
+  if (fDigiMan->IsPresent(ECbmModuleId::kTof)) {
+    fTofDigis->clear();
+    for (Int_t i = 0; i < fDigiMan->GetNofDigis(ECbmModuleId::kTof); i++) {
+      const CbmTofDigi* Digi = fDigiMan->Get<CbmTofDigi>(i);
+      fTofDigis->push_back(*Digi);
+      if (fSeedTimeDet.detId == ECbmModuleId::kTof) { fSeedTimes->push_back(Digi->GetTime()); }
+    }
+    LOG(debug) << "Read: " << fDigiMan->GetNofDigis(ECbmModuleId::kTof) << " TOF digis.";
+    LOG(debug) << "In DigiManager: " << fTofDigis->size() << " TOF digis.";
+  }
+
+  //Read RICH digis
+  if (fDigiMan->IsPresent(ECbmModuleId::kRich)) {
+    fRichDigis->clear();
+    for (Int_t i = 0; i < fDigiMan->GetNofDigis(ECbmModuleId::kRich); i++) {
+      const CbmRichDigi* Digi = fDigiMan->Get<CbmRichDigi>(i);
+      fRichDigis->push_back(*Digi);
+      if (fSeedTimeDet.detId == ECbmModuleId::kRich) { fSeedTimes->push_back(Digi->GetTime()); }
+    }
+    LOG(debug) << "Read: " << fDigiMan->GetNofDigis(ECbmModuleId::kRich) << " RICH digis.";
+    LOG(debug) << "In DigiManager: " << fRichDigis->size() << " RICH digis.";
+  }
+
+  //Read PSD digis
+  if (fDigiMan->IsPresent(ECbmModuleId::kPsd)) {
+    fPsdDigis->clear();
+    for (Int_t i = 0; i < fDigiMan->GetNofDigis(ECbmModuleId::kPsd); i++) {
+      const CbmPsdDigi* Digi = fDigiMan->Get<CbmPsdDigi>(i);
+      fPsdDigis->push_back(*Digi);
+      if (fSeedTimeDet.detId == ECbmModuleId::kPsd) { fSeedTimes->push_back(Digi->GetTime()); }
+    }
+    LOG(debug) << "Read: " << fDigiMan->GetNofDigis(ECbmModuleId::kPsd) << " PSD digis.";
+    LOG(debug) << "In DigiManager: " << fPsdDigis->size() << " PSD digis.";
+  }
+
+  if (fCopyTimer != nullptr) { fCopyTimer->Stop(); }
+
+  if (fSeedTimeDetList.size() > 0) { FillSeedTimesFromDetList(); }
+  //DumpSeedTimesFromDetList();
+
+  /// Call Algo ProcessTs method
+  fpAlgo->ProcessTs();
+
+  /// Save the resulting vector of events in TClonesArray
+  FillOutput();
+  LOG(debug2) << "CbmEvbuildRawTask::Exec => Done";
+
+  if (fTimer != nullptr) { fTimer->Stop(); }
+
+  // --- Timeslice log and statistics
+  timer.Stop();
+  stringstream logOut;
+  logOut << setw(20) << left << GetName() << " [";
+  logOut << fixed << setw(8) << setprecision(1) << right << timer.RealTime() * 1000. << " ms] ";
+  logOut << "TS " << fNofTs;
+  if (fEvents) logOut << ", events " << fEvents->GetEntriesFast();
+  LOG(info) << logOut.str();
+  fNofTs++;
+  fNofEvents += fEvents->GetEntriesFast();
+  fTime += timer.RealTime();
+}
+
+void CbmEvbuildRawTask::FillSeedTimesFromDetList()
+{
+  std::map<ECbmModuleId, UInt_t> DigiNumbers;
+  std::map<ECbmModuleId, UInt_t> DigiCounters;
+  fSeedTimes->clear();
+
+  for (RawEventBuilderDetector& system : fSeedTimeDetList) {
+    DigiNumbers[system.detId]  = GetNofDigis(system.detId);
+    DigiCounters[system.detId] = 0;
+  }
+
+  do {
+    ECbmModuleId nextAddedSystem;
+    Double_t earliestTime = -1;
+
+    for (RawEventBuilderDetector& system : fSeedTimeDetList) {
+      if (DigiCounters[system.detId] < DigiNumbers[system.detId]) {
+        Double_t thisTime = GetDigiTime(system.detId, DigiCounters[system.detId]);
+        if (thisTime < earliestTime || earliestTime == -1) {
+          nextAddedSystem = system.detId;
+          earliestTime    = thisTime;
+        }
+      }
+    }
+    if (earliestTime != -1) {
+      fSeedTimes->push_back(earliestTime);
+      DigiCounters[nextAddedSystem]++;
+    }
+    else {
+      break;
+    }
+  } while (true);
+}
+
+void CbmEvbuildRawTask::DumpSeedTimesFromDetList()
+{
+  std::ofstream timesUnsorted("digiTimesUnsorted.dat", std::ofstream::out);
+  timesUnsorted << std::setprecision(16);
+
+  for (RawEventBuilderDetector& system : fSeedTimeDetList) {
+    for (UInt_t i = 0; i < GetNofDigis(system.detId); i++) {
+      timesUnsorted << GetDigiTime(system.detId, i) << std::endl;
+    }
+  }
+  timesUnsorted.close();
+  LOG(info) << "Completed write of unsorted digi list.";
+
+  std::ofstream timesSorted("digiTimesSorted.dat", std::ofstream::out);
+  timesSorted << std::setprecision(16);
+
+  for (UInt_t i = 0; i < fSeedTimes->size(); i++) {
+    timesSorted << fSeedTimes->at(i) << std::endl;
+  }
+  timesSorted.close();
+  LOG(info) << "Completed DumpSeedTimesFromDetList(). Closing.";
+  exit(0);  //terminate as this method should only be used for diagnostics
+}
+
+Double_t CbmEvbuildRawTask::GetDigiTime(ECbmModuleId _system, UInt_t _entry)
+{
+  switch (_system) {
+    case ECbmModuleId::kMuch:
+      if (fbUseMuchBeamtimeDigi) { return (fMuchBeamTimeDigis->at(_entry)).GetTime(); }
+      else {
+        return (fMuchDigis->at(_entry)).GetTime();
+      }
+    case ECbmModuleId::kSts: return (fStsDigis->at(_entry)).GetTime();
+    case ECbmModuleId::kTrd: return (fTrdDigis->at(_entry)).GetTime();
+    case ECbmModuleId::kTof: return (fTofDigis->at(_entry)).GetTime();
+    case ECbmModuleId::kRich: return (fRichDigis->at(_entry)).GetTime();
+    case ECbmModuleId::kPsd: return (fPsdDigis->at(_entry)).GetTime();
+    case ECbmModuleId::kHodo: return (fT0Digis->at(_entry)).GetTime();
+    default: break;
+  }
+  return -1;
+}
+
+UInt_t CbmEvbuildRawTask::GetNofDigis(ECbmModuleId _system)
+{
+  switch (_system) {
+    case ECbmModuleId::kMuch:
+      if (fbUseMuchBeamtimeDigi) { return fMuchBeamTimeDigis->size(); }
+      else {
+        return fMuchDigis->size();
+      }
+    case ECbmModuleId::kSts: return fStsDigis->size();
+    case ECbmModuleId::kTrd: return fTrdDigis->size();
+    case ECbmModuleId::kTof: return fTofDigis->size();
+    case ECbmModuleId::kRich: return fRichDigis->size();
+    case ECbmModuleId::kPsd: return fPsdDigis->size();
+    case ECbmModuleId::kHodo: return fT0Digis->size();
+    default: break;
+  }
+  return 0;
+}
+
+void CbmEvbuildRawTask::PrintTimings()
+{
+  if (fTimer == nullptr) { LOG(fatal) << "Trying to print timings but timer not set"; }
+  else {
+    Double_t rtime = fTimer->RealTime();
+    Double_t ctime = fTimer->CpuTime();
+    LOG(info) << "CbmEvbuildRawTask: Real time " << rtime << " s, CPU time " << ctime << " s";
+  }
+  if (fCopyTimer == nullptr) { LOG(fatal) << "Trying to print timings but timer not set"; }
+  else {
+    Double_t rtime = fCopyTimer->RealTime();
+    Double_t ctime = fCopyTimer->CpuTime();
+    LOG(info) << "CbmEvbuildRawTask (digi copy only): Real time " << rtime << " s, CPU time " << ctime << " s";
+  }
+}
+
+void CbmEvbuildRawTask::Finish()
+{
+  /// Call Algo finish method
+  fpAlgo->Finish();
+  if (fbFillHistos) { SaveHistos(); }
+  if (fbGetTimings) { PrintTimings(); }
+
+  std::cout << std::endl;
+  LOG(info) << "=====================================";
+  LOG(info) << GetName() << ": Run summary";
+  LOG(info) << "Time slices          : " << fNofTs;
+  LOG(info) << "Events               : " << fNofEvents;
+  LOG(info) << "Time  / TS           : " << fixed << setprecision(2) << 1000. * fTime / Double_t(fNofTs) << " ms";
+  LOG(info) << "=====================================";
+}
+
+void CbmEvbuildRawTask::FillOutput()
+{
+  /// Clear TClonesArray before usage.
+  fEvents->Delete();
+
+  /// Get vector reference from algo
+  std::vector<CbmRawEvent*> vEvents = fpAlgo->GetEventVector();
+
+  /// Move CbmEvent from temporary vector to TClonesArray
+  for (CbmRawEvent* event : vEvents) {
+    LOG(debug) << "Vector: " << event->ToString();
+    new ((*fEvents)[fEvents->GetEntriesFast()]) CbmRawEvent(std::move(*event));
+    LOG(debug) << "TClonesArray: " << static_cast<CbmRawEvent*>(fEvents->At(fEvents->GetEntriesFast() - 1))->ToString();
+  }
+  /// Clear event vector after usage
+  fpAlgo->ClearEventVector();
+}
+
+void CbmEvbuildRawTask::SaveHistos()
+{
+  if (fbWriteHistosToFairSink) {
+    if (!FairRootManager::Instance() || !FairRootManager::Instance()->GetSink()) {
+      LOG(error) << "No sink found";
+      return;
+    }
+    FairSink* sink = FairRootManager::Instance()->GetSink();
+    sink->WriteObject(dynamic_cast<TObject*>(fpAlgo->GetOutFolder()), nullptr);
+  }
+  else {
+
+    /// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
+    std::vector<std::pair<TNamed*, std::string>> vHistos = fpAlgo->GetHistoVector();
+
+    /// (Re-)Create ROOT file to store the histos
+    TDirectory* oldDir = NULL;
+    TFile* histoFile   = NULL;
+    /// Store current directory position to allow restore later
+    oldDir = gDirectory;
+    /// open separate histo file in recreate mode
+    histoFile = new TFile(fsOutFileName, "RECREATE");
+    histoFile->cd();
+
+    /// Save all plots and create folders if needed
+    for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
+      /// Make sure we end up in chosen folder
+      const TString sFolder = vHistos[uHisto].second.data();
+      if (nullptr == gDirectory->Get(sFolder)) gDirectory->mkdir(sFolder);
+      gDirectory->cd(sFolder);
+
+      /// Write plot
+      vHistos[uHisto].first->Write();
+      histoFile->cd();
+    }
+
+    /// Restore original directory position
+    oldDir->cd();
+    histoFile->Close();
+  }
+}
+
+
+ClassImp(CbmEvbuildRawTask)
diff --git a/reco/eventbuilder/digis/CbmEvbuildRawTask.h b/reco/eventbuilder/digis/CbmEvbuildRawTask.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2a3c29b94e4560a3de4e7f00cdb31be3e4e7474
--- /dev/null
+++ b/reco/eventbuilder/digis/CbmEvbuildRawTask.h
@@ -0,0 +1,177 @@
+/********************************************************************************
+ *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
+ *                                                                              *
+ *              This software is distributed under the terms of the             *
+ *              GNU Lesser General Public Licence (LGPL) version 3,             *
+ *                  copied verbatim in the file "LICENSE"                       *
+ ********************************************************************************/
+#ifndef CBMEVBUILDRAWTASK_H
+#define CBMEVBUILDRAWTASK_H
+
+/// FAIRROOT headers
+#include "FairTask.h"
+
+/// FAIRSOFT headers (geant, boost, ...)
+
+/// C/C++ headers
+#include "CbmEvbuildRawAlgo.h"
+#include "CbmMuchBeamTimeDigi.h"
+#include "CbmMuchDigi.h"
+#include "CbmPsdDigi.h"
+#include "CbmRichDigi.h"
+#include "CbmStsDigi.h"
+#include "CbmTofDigi.h"
+#include "CbmTrdDigi.h"
+
+#include <tuple>
+
+#include <array>
+#include <map>
+#include <set>
+#include <vector>
+
+class CbmDigiManager;
+class RawEventBuilderDetector;
+class TClonesArray;
+class TStopwatch;
+
+enum class EOverlapModeRaw;
+
+class CbmEvbuildRawTask : public FairTask {
+public:
+  /** Default constructor **/
+  CbmEvbuildRawTask();
+
+  CbmEvbuildRawTask(const CbmEvbuildRawTask&) = delete;
+  CbmEvbuildRawTask operator=(const CbmEvbuildRawTask&) = delete;
+
+  /** Constructor with parameters (Optional) **/
+  //  CbmEvbuildRawTask(Int_t verbose);
+
+  /** Destructor **/
+  ~CbmEvbuildRawTask();
+
+  /** Initiliazation of task at the beginning of a run **/
+  virtual InitStatus Init();
+
+  /** ReInitiliazation of task when the runID changes **/
+  virtual InitStatus ReInit();
+
+  /** Executed for each event. **/
+  virtual void Exec(Option_t*);
+
+  /** Load the parameter container from the runtime database **/
+  virtual void SetParContainers();
+
+  /** Finish task called at the end of the run **/
+  virtual void Finish();
+
+  /** Setters **/
+  void SetOutFilename(TString sNameIn) { fsOutFileName = sNameIn; }
+  void SetWriteHistosToFairSink(Bool_t var) { fbWriteHistosToFairSink = var; }
+
+  void SetFillHistos(Bool_t bFlag = kTRUE)
+  {
+    fbFillHistos = bFlag;
+    if (nullptr != fpAlgo) fpAlgo->SetFillHistos(fbFillHistos);
+  }
+  void SetReferenceDetector(RawEventBuilderDetector refDet)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetReferenceDetector(refDet);
+  }
+  void AddDetector(RawEventBuilderDetector selDet)
+  {
+    if (nullptr != fpAlgo) fpAlgo->AddDetector(selDet);
+  }
+  void RemoveDetector(RawEventBuilderDetector selDet)
+  {
+    if (nullptr != fpAlgo) fpAlgo->RemoveDetector(selDet);
+  }
+  void SetTriggerMinNumber(ECbmModuleId selDet, UInt_t uVal)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetTriggerMinNumber(selDet, uVal);
+  }
+  void SetTriggerMaxNumber(ECbmModuleId selDet, Int_t iVal)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetTriggerMaxNumber(selDet, iVal);
+  }
+  void SetTriggerWindow(ECbmModuleId det, Double_t dWinBeg, Double_t dWinEnd)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetTriggerWindow(det, dWinBeg, dWinEnd);
+  }
+  void SetTsParameters(Double_t dTsStartTime, Double_t dTsLength, Double_t dTsOverLength)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetTsParameters(dTsStartTime, dTsLength, dTsOverLength);
+  }
+  void SetEventOverlapMode(EOverlapModeRaw mode)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetEventOverlapMode(mode);
+  }
+  void SetIgnoreTsOverlap(Bool_t bFlagIn)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetIgnoreTsOverlap(bFlagIn);
+  }
+  void ChangeMuchBeamtimeDigiFlag(Bool_t bFlagIn = kFALSE)
+  {
+    if (nullptr != fpAlgo) fpAlgo->ChangeMuchBeamtimeDigiFlag(bFlagIn);
+    fbUseMuchBeamtimeDigi = bFlagIn;
+  }
+  void SetTimings(Bool_t bFlagIn = kTRUE)
+  {
+    if (nullptr != fpAlgo) fpAlgo->SetTimings(bFlagIn);
+    fbGetTimings = bFlagIn;
+  }
+
+  void PrintTimings();
+  void SetSeedTimeFiller(RawEventBuilderDetector seedDet);
+  void AddSeedTimeFillerToList(RawEventBuilderDetector seedDet);
+  void DumpSeedTimesFromDetList();
+  void SetSeedTimeWindow(Double_t beg, Double_t end) { fpAlgo->SetSeedTimeWindow(beg, end); }
+
+private:
+  void FillOutput();
+  void SaveHistos();
+
+  Bool_t fbUseMuchBeamtimeDigi = kTRUE;  //! Switch between MUCH digi classes
+
+  CbmDigiManager* fDigiMan                             = nullptr;
+  const std::vector<CbmTofDigi>* fT0Digis              = nullptr;
+  std::vector<CbmMuchDigi>* fMuchDigis                 = nullptr;
+  std::vector<CbmMuchBeamTimeDigi>* fMuchBeamTimeDigis = nullptr;
+  std::vector<CbmStsDigi>* fStsDigis                   = nullptr;
+  std::vector<CbmTrdDigi>* fTrdDigis                   = nullptr;
+  std::vector<CbmTofDigi>* fTofDigis                   = nullptr;
+  std::vector<CbmRichDigi>* fRichDigis                 = nullptr;
+  std::vector<CbmPsdDigi>* fPsdDigis                   = nullptr;
+  std::vector<Double_t>* fSeedTimes                    = nullptr;
+
+  std::vector<RawEventBuilderDetector> fSeedTimeDetList;            //if multiple are desired
+  RawEventBuilderDetector fSeedTimeDet = kRawEventBuilderDetUndef;  //single seed det
+
+  Double_t GetDigiTime(ECbmModuleId _system, UInt_t _entry);
+  UInt_t GetNofDigis(ECbmModuleId _system);
+
+  void FillSeedTimesFromDetList();
+
+  TStopwatch* fTimer     = nullptr;  //! is created when fbGetTimings is set before init
+  TStopwatch* fCopyTimer = nullptr;  //! timing only for filling of std::vector<Digi> fields
+
+  CbmEvbuildRawAlgo* fpAlgo = nullptr;
+
+  TClonesArray* fEvents = nullptr;  //! output container of CbmEvents
+
+  Bool_t fbFillHistos {kTRUE};             //! Switch ON/OFF filling of histograms
+  Bool_t fbWriteHistosToFairSink {kTRUE};  //! Write histos to FairRootManager instead of separate file
+  Bool_t fbGetTimings = kFALSE;            //! Measure CPU time using stopwatch
+
+  /** Name of the histogram output file **/
+  TString fsOutFileName {"data/HistosEvtWin.root"};
+
+  Int_t fNofTs        = 0;
+  Long64_t fNofEvents = 0;
+  Double_t fTime      = 0.;
+
+  ClassDef(CbmEvbuildRawTask, 1);
+};
+
+#endif  // CBMEVBUILDRAWTASK_H