diff --git a/reco/eventbuilder/digis/Cbm2021EventBuilderAlgo.cxx b/reco/eventbuilder/digis/Cbm2021EventBuilderAlgo.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..774ea4363ca53f45fdf9a56b153554e730796ac8
--- /dev/null
+++ b/reco/eventbuilder/digis/Cbm2021EventBuilderAlgo.cxx
@@ -0,0 +1,1107 @@
+/********************************************************************************
+ *    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 "Cbm2021EventBuilderAlgo.h"
+
+/// CBM headers
+#include "CbmEvent.h"
+#include "CbmMuchBeamTimeDigi.h"
+#include "CbmMuchDigi.h"
+#include "CbmPsdDigi.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 "TH1.h"
+#include "TH2.h"
+#include "THttpServer.h"
+
+/// C/C++ headers
+
+// ---- Default constructor --------------------------------------------
+Cbm2021EventBuilderAlgo::Cbm2021EventBuilderAlgo() {}
+
+// ---- Destructor -----------------------------------------------------
+Cbm2021EventBuilderAlgo::~Cbm2021EventBuilderAlgo() {}
+
+// ---- Init -----------------------------------------------------------
+Bool_t Cbm2021EventBuilderAlgo::InitAlgo() {
+  LOG(info)
+    << "Cbm2021EventBuilderAlgo::InitAlgo => Starting sequence";
+
+  // Get a handle from the IO manager
+  FairRootManager* ioman = FairRootManager::Instance();
+
+  /// Check if reference detector data are available
+  if (kFALSE == CheckDataAvailable(fRefDet)) {
+    LOG(fatal) << "No digi input for reference detector, stopping there!";
+  }  // if( kFALSE == CheckDataAvailable( fRefDet ) )
+
+  /// Check if data for detectors in selection list are available
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    if (kFALSE == CheckDataAvailable(*det)) {
+      LOG(fatal)
+        << "No digi input for one of selection detector, stopping there!";
+    }  // if( kFALSE == CheckDataAvailable( *det ) )
+  }  // for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det)
+
+  /// Access the TS metadata to know TS start time if needed
+  if (fdTsStartTime < 0 || fdTsLength < 0 || fdTsOverLength < 0) {
+    fTimeSliceMetaDataArray =
+      dynamic_cast<TClonesArray*>(ioman->GetObject("TimesliceMetaData"));
+    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 (!fTimeSliceMetaDataArray)
+  }    // if ( fdTsStartTime < 0 || fdTsLength < 0 || fdTsOverLength < 0 )
+
+  if (fbFillHistos) { CreateHistograms(); }  // if( fbFillHistos )
+
+  LOG(info) << "Cbm2021EventBuilderAlgo::InitAlgo => Done";
+
+  return kTRUE;
+}
+
+// ---- ProcessTs ------------------------------------------------------
+void Cbm2021EventBuilderAlgo::ProcessTs() {
+  LOG_IF(info, fuNrTs % 1000 == 0) << "Begin of TS " << fuNrTs;
+
+  InitTs();
+
+  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;
+  }  // if( nullptr != fCurrentEvent )
+
+  LOG(debug) << "Found " << fEventVector.size() << " triggered events";
+
+  if (fbFillHistos) { FillHistos(); }  // if( fbFillHistos )
+
+  fuNrTs++;
+}
+void Cbm2021EventBuilderAlgo::ClearEventVector() {
+  /// Need to delete the object the pointer points to first
+  int counter = 0;
+  for (CbmEvent* event : fEventVector) {
+    LOG(debug) << "Event " << counter << " has " << event->GetNofData()
+               << " digis";
+    delete event;
+    counter++;
+  }  // for( CbmEvent* event: fEventVector)
+
+  fEventVector.clear();
+}
+// ---- Finish ---------------------------------------------------------
+void Cbm2021EventBuilderAlgo::Finish() {
+  LOG(info) << "Total errors: " << fuErrors;
+}
+
+// ---------------------------------------------------------------------
+Bool_t Cbm2021EventBuilderAlgo::CheckDataAvailable(
+  EventBuilderDetector& det) {
+  // Get a handle from the IO manager
+  FairRootManager* ioman = FairRootManager::Instance();
+
+  if (ECbmModuleId::kT0 == det.detId) {
+    // T0 is not included in DigiManager
+    fT0DigiVec = ioman->InitObjectAs<std::vector<CbmTofDigi> const*>("T0Digi");
+    if (!fT0DigiVec) {
+      LOG(info) << "No T0 digi input found.";
+      return kFALSE;
+    }    
+  } 
+  else if (ECbmModuleId::kSts == det.detId) {
+    if (!fStsDigis) {
+      LOG(info) << "No " << det.sName << " digi input found.";
+      return kFALSE;
+    }
+  }
+  else if (ECbmModuleId::kMuch == det.detId) {
+    if (!fMuchDigis && !fMuchBeamTimeDigis ) {
+      LOG(info) << "No " << det.sName << " digi input found.";
+      return kFALSE;
+    }
+  }
+  else if (ECbmModuleId::kTrd == det.detId) {
+    if (!fTrdDigis) {
+      LOG(info) << "No " << det.sName << " digi input found.";
+      return kFALSE;
+    }
+  }
+  else if (ECbmModuleId::kTof == det.detId) {
+    if (!fTofDigis) {
+      LOG(info) << "No " << det.sName << " digi input found.";
+      return kFALSE;
+    }
+  }
+  else if (ECbmModuleId::kRich == det.detId) {
+    if (!fRichDigis) {
+      LOG(info) << "No " << det.sName << " digi input found.";
+      return kFALSE;
+    }
+  }
+  else if (ECbmModuleId::kPsd == det.detId) {
+    if (!fPsdDigis) {
+      LOG(info) << "No " << det.sName << " digi input found.";
+      return kFALSE;
+    }
+  }
+  return kTRUE;
+}
+// ---------------------------------------------------------------------
+void Cbm2021EventBuilderAlgo::InitTs() {
+  /// Reset TS based variables (analysis per TS = no building over the border)
+  /// Reference detector
+  fRefDet.fuStartIndex = 0;
+  fRefDet.fuEndIndex   = 0;
+  /// Loop on detectors in selection list
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    (*det).fuStartIndex = 0;
+    (*det).fuEndIndex   = 0;
+  }  // for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin(); det != fvDets.end(); ++det)
+}
+
+void Cbm2021EventBuilderAlgo::BuildEvents() {
+  /// Call LoopOnSeed with proper template argument
+  switch (fRefDet.detId) {
+    case ECbmModuleId::kSts: {
+      LoopOnSeeds<CbmStsDigi>();
+      break;
+    }  // case ECbmModuleId::kSts:
+    case ECbmModuleId::kMuch: {
+      if (fbUseMuchBeamtimeDigi) {
+        LoopOnSeeds<CbmMuchBeamTimeDigi>();
+      }  // if (fbUseMuchBeamtimeDigi)
+      else {
+        LoopOnSeeds<CbmMuchDigi>();
+      }  // else of if (fbUseMuchBeamtimeDigi)
+      break;
+    }  // case ECbmModuleId::kMuch:
+    case ECbmModuleId::kTrd: {
+      LoopOnSeeds<CbmTrdDigi>();
+      break;
+    }  // case ECbmModuleId::kTrd:
+    case ECbmModuleId::kTof: {
+      LoopOnSeeds<CbmTofDigi>();
+      break;
+    }  // case ECbmModuleId::kTof:
+    case ECbmModuleId::kRich: {
+      LoopOnSeeds<CbmRichDigi>();
+      break;
+    }  // case ECbmModuleId::kRich:
+    case ECbmModuleId::kPsd: {
+      LoopOnSeeds<CbmPsdDigi>();
+      break;
+    }  // case ECbmModuleId::kPsd:
+    case ECbmModuleId::kT0: {
+      LoopOnSeeds<CbmTofDigi>();
+      break;
+    }  // case ECbmModuleId::kT0:
+    default: {
+      LOG(fatal) << "Cbm2021EventBuilderAlgo::BuildEvents => "
+                 << "Trying to search event seeds with unsupported det: "
+                 << fRefDet.sName;
+      break;
+    }  // default:
+  }    // switch( *det )
+}
+
+UInt_t Cbm2021EventBuilderAlgo::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) << "Cbm2021EventBuilderAlgo::GetNofDigis => "
+                 << "Trying to get digi number with unsupported detector.";
+      return -1;
+    }  
+  }    
+}
+
+bool Cbm2021EventBuilderAlgo::DetIsPresent( 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; //what to do here? Not in digi manager.
+    }  
+    default: {
+      LOG(fatal) << "Cbm2021EventBuilderAlgo::GetNofDigis => "
+                 << "Trying to get digi number with unsupported detector.";
+      return -1;
+    }  
+  }    
+}
+
+template<> const CbmStsDigi* Cbm2021EventBuilderAlgo::GetDigi( UInt_t uDigi ) {
+	return &((*fStsDigis)[uDigi]);
+}
+template<> const CbmMuchBeamTimeDigi* Cbm2021EventBuilderAlgo::GetDigi( UInt_t uDigi ) {
+	return &((*fMuchBeamTimeDigis)[uDigi]);
+}
+template<> const CbmMuchDigi* Cbm2021EventBuilderAlgo::GetDigi( UInt_t uDigi ) {
+	return &((*fMuchDigis)[uDigi]);
+}
+template<> const CbmTrdDigi* Cbm2021EventBuilderAlgo::GetDigi( UInt_t uDigi ) {
+	return &((*fTrdDigis)[uDigi]);
+}
+template<> const CbmTofDigi* Cbm2021EventBuilderAlgo::GetDigi( UInt_t uDigi ) {
+	return &((*fTofDigis)[uDigi]);
+}
+template<> const CbmRichDigi* Cbm2021EventBuilderAlgo::GetDigi( UInt_t uDigi ) {
+	return &((*fRichDigis)[uDigi]);
+}
+template<> const CbmPsdDigi* Cbm2021EventBuilderAlgo::GetDigi( UInt_t uDigi ) {
+	return &((*fPsdDigis)[uDigi]);
+}
+
+template<class DigiSeed>
+void Cbm2021EventBuilderAlgo::LoopOnSeeds() {
+  /// 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 (fdTsStartTime < 0 || fdTsLength < 0 || fdTsOverLength < 0) {
+    pTsMetaData =
+      dynamic_cast<TimesliceMetaData*>(fTimeSliceMetaDataArray->At(0));
+    if (nullptr == pTsMetaData)
+      LOG(fatal) << Form("Cbm2021EventBuilderAlgo::LoopOnSeeds => "
+                         "No TS metadata found for TS %6u.",
+                         fuNrTs);
+
+    dTsStartTime  = pTsMetaData->GetStartTime();
+    dOverlapStart = pTsMetaData->GetOverlapStartTime();
+    dOverlapSize  = pTsMetaData->GetOverlapDuration();
+  }  // if ( fdTsStartTime < 0 || fdTsLength < 0  || fdTsOverLength < 0 )
+
+  /// Print warning in first TS if time window borders out of potential overlap
+  if ((0.0 < fdEarliestTimeWinBeg && dOverlapSize < fdLatestTimeWinEnd)
+      || (dOverlapSize < fdWidestTimeWinRange)) {
+    LOG(warning) << "Cbm2021EventBuilderAlgo::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
+  Double_t dSeedWindowBeg =
+    dTsStartTime + (0.0 < fdEarliestTimeWinBeg ? 0.0 : -fdEarliestTimeWinBeg);
+  Double_t dSeedWindowEnd =
+    dOverlapStart + (0.0 < fdEarliestTimeWinBeg ? 0.0 : -fdEarliestTimeWinBeg);
+  if (fbIgnoreTsOverlap) {
+    dSeedWindowBeg = dTsStartTime;
+    dSeedWindowEnd = dOverlapStart;
+  }  // if( fbIgnoreTsOverlap )
+
+  if (ECbmModuleId::kT0 == fRefDet.detId) {
+    if (fT0DigiVec) {
+      /// Loop on size of vector
+      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);
+      }  // for( UInt_t uDigi = 0; uDigi < uNbRefDigis; ++uDigi )
+    }    // if ( fT0DigiVec )
+    else
+      LOG(fatal) << "Cbm2021EventBuilderAlgo::LoopOnSeeds => "
+                 << "T0 as reference detector but vector not found!";
+  }  // if (ECbmModuleId::kT0 == fRefDet.detId)
+  else {
+    UInt_t uNbRefDigis = (0 < GetNofDigis(fRefDet.detId)
+                            ? GetNofDigis(fRefDet.detId)
+                            : 0);
+    /// 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);
+      /// Check that _entry is not out of range
+      if (nullptr != pDigi) {
+        Double_t dTime = pDigi->GetTime();
+
+        /// Check if seed in acceptance window
+        if (dTime < dSeedWindowBeg) {
+          continue;
+        }  // if( dTime < dSeedWindowBeg )
+        else if (dSeedWindowEnd < dTime) {
+          break;
+        }  // else if( dSeedWindowEnd < dTime )
+
+        /// Check Seed and build event if needed
+        CheckSeed(dTime, uDigi);
+      }  // if( nullptr != pDigi )
+    }    // for( UInt_t uDigi = 0; uDigi < uNbRefDigis; ++uDigi )
+  }  // else of if (ECbmModuleId::kT0 == fRefDet.detId) => Digi containers controlled by DigiManager
+}
+
+void Cbm2021EventBuilderAlgo::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
+      && (EOverlapMode::AllowOverlap != fOverMode
+          || dSeedTime - fdPrevEvtTime < fRefDet.GetTimeWinRange())
+      && dSeedTime - fdPrevEvtTime < fdWidestTimeWinRange) {
+    /// Within overlap range
+    switch (fOverMode) {
+      case EOverlapMode::NoOverlap: {
+        /// No overlap allowed => reject
+        LOG(debug1) << "Reject seed due to overlap";
+        return;
+        break;
+      }  // case EOverlapMode::NoOverlap:
+      case EOverlapMode::MergeOverlap: {
+        /// Merge overlap mode => do nothing and go on filling current event
+        break;
+      }  // case EOverlapMode::MergeOverlap:
+      case EOverlapMode::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;
+      }  // case EOverlapMode::AllowOverlap:
+    }    // switch( fOverMode )
+  }      // 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++;
+    }  // if( nullptr != fCurrentEvent )
+    fCurrentEvent = new CbmEvent(fuCurEv, dSeedTime, 0.);
+  }  // else of if( prev Event exists and mode forbiden overlap present )
+
+  /// If window open for reference detector, search for other reference Digis matching it
+  /// Otherwise only add the current seed
+  if (fRefDet.fdTimeWinBeg < fRefDet.fdTimeWinEnd) {
+    switch (fRefDet.detId) {
+      case ECbmModuleId::kSts: {
+        SearchMatches<CbmStsDigi>(dSeedTime, fRefDet);
+        break;
+      }  // case ECbmModuleId::kSts:
+      case ECbmModuleId::kMuch: {
+        if (fbUseMuchBeamtimeDigi) {
+          SearchMatches<CbmMuchBeamTimeDigi>(dSeedTime, fRefDet);
+        }  // if (fbUseMuchBeamtimeDigi)
+        else {
+          SearchMatches<CbmMuchDigi>(dSeedTime, fRefDet);
+        }  // else of if (fbUseMuchBeamtimeDigi)
+        break;
+      }  // case ECbmModuleId::kMuch:
+      case ECbmModuleId::kTrd: {
+        SearchMatches<CbmTrdDigi>(dSeedTime, fRefDet);
+        break;
+      }  // case ECbmModuleId::kTrd:
+      case ECbmModuleId::kTof: {
+        SearchMatches<CbmTofDigi>(dSeedTime, fRefDet);
+        break;
+      }  // case ECbmModuleId::kTof:
+      case ECbmModuleId::kRich: {
+        SearchMatches<CbmRichDigi>(dSeedTime, fRefDet);
+        break;
+      }  // case ECbmModuleId::kRich:
+      case ECbmModuleId::kPsd: {
+        SearchMatches<CbmPsdDigi>(dSeedTime, fRefDet);
+        break;
+      }  // case ECbmModuleId::kPsd:
+      case ECbmModuleId::kT0: {
+        SearchMatches<CbmTofDigi>(dSeedTime, fRefDet);
+        break;
+      }  // case ECbmModuleId::kT0:
+      default: {
+        LOG(fatal) << "Cbm2021EventBuilderAlgo::LoopOnSeeds => "
+                   << "Trying to search matches with unsupported det: "
+                   << fRefDet.sName << std::endl
+                   << "You may want to add support for it in the method.";
+        break;
+      }  // default:
+    }    // switch( fRefDet )
+
+    /// Also add the seed if the window starts after the seed
+    if (0 < fRefDet.fdTimeWinBeg) AddDigiToEvent(fRefDet, uSeedDigiIdx);
+  }  // if( fdRefTimeWinBeg < fdRefTimeWinEnd )
+  else {
+    AddDigiToEvent(fRefDet, uSeedDigiIdx);
+  }  // else of if( fdRefTimeWinBeg < fdRefTimeWinEnd )
+
+  /// Search for matches for each detector in selection list
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    switch ((*det).detId) {
+      case ECbmModuleId::kSts: {
+        SearchMatches<CbmStsDigi>(dSeedTime, *det);
+        break;
+      }  // case ECbmModuleId::kSts:
+      case ECbmModuleId::kMuch: {
+        if (fbUseMuchBeamtimeDigi) {
+          SearchMatches<CbmMuchBeamTimeDigi>(dSeedTime, *det);
+        }  // if (fbUseMuchBeamtimeDigi)
+        else {
+          SearchMatches<CbmMuchDigi>(dSeedTime, *det);
+        }  // else of if (fbUseMuchBeamtimeDigi)
+        break;
+      }  // case ECbmModuleId::kMuch:
+      case ECbmModuleId::kTrd: {
+        SearchMatches<CbmTrdDigi>(dSeedTime, *det);
+        break;
+      }  // case ECbmModuleId::kTrd:
+      case ECbmModuleId::kTof: {
+        SearchMatches<CbmTofDigi>(dSeedTime, *det);
+        break;
+      }  // case ECbmModuleId::kTof:
+      case ECbmModuleId::kRich: {
+        SearchMatches<CbmRichDigi>(dSeedTime, *det);
+        break;
+      }  // case ECbmModuleId::kRich:
+      case ECbmModuleId::kPsd: {
+        SearchMatches<CbmPsdDigi>(dSeedTime, *det);
+        break;
+      }  // case ECbmModuleId::kPsd:
+      case ECbmModuleId::kT0: {
+        SearchMatches<CbmTofDigi>(dSeedTime, *det);
+        break;
+      }  // case ECbmModuleId::kT0:
+      default: {
+        LOG(fatal) << "Cbm2021EventBuilderAlgo::LoopOnSeeds => "
+                   << "Trying to search matches with unsupported det: "
+                   << (*det).sName << std::endl
+                   << "You may want to add support for it in the method.";
+        break;
+      }  // default:
+    }    // switch( *det )
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+  /// 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 (EOverlapMode::NoOverlap == fOverMode
+        || EOverlapMode::MergeOverlap == fOverMode) {
+
+      /// Update reference detector
+      fRefDet.fuStartIndex = fRefDet.fuEndIndex;
+
+      /// Loop on selection detectors
+      for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+           det != fvDets.end();
+           ++det) {
+        (*det).fuStartIndex = (*det).fuEndIndex;
+      }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+    }    // If no overlap or merge overlap
+  }      // if( !HasTrigger( fCurrentEvent ) )
+  else {
+    LOG(debug1) << "Reject seed due to Trigger requirements";
+    delete fCurrentEvent;
+    fCurrentEvent = nullptr;  /// delete does NOT set a pointer to nullptr...
+  }                           // else of if( !HasTrigger( fCurrentEvent ) )
+}
+
+template<class DigiCheck>
+void Cbm2021EventBuilderAlgo::SearchMatches(
+  Double_t dSeedTime,
+  EventBuilderDetector& 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) {
+    if (fT0DigiVec) {
+      /// Loop on size of vector
+      UInt_t uNbSelDigis = fT0DigiVec->size();
+      /// Loop on size of vector
+      for (UInt_t uDigi = detMatch.fuStartIndex; uDigi < uNbSelDigis; ++uDigi) {
+        Double_t dTime = fT0DigiVec->at(uDigi).GetTime();
+
+        Double_t dTimeDiff = dTime - dSeedTime;
+
+        /// Check if within time window, update start/stop indices if needed
+        if (dTimeDiff < detMatch.fdTimeWinBeg) {
+          ++uLocalIndexStart;
+          continue;
+        }  // if( dTimeDiff < detMatch.fdTimeWinBeg )
+        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;
+        }  // else if( detMatch.fdTimeWinEnd < dTimeDiff ) of if( dTimeDiff < detMatch.fdTimeWinBeg )
+
+        AddDigiToEvent(detMatch, uDigi);
+
+        if (fdPrevEvtEndTime < dTime) fdPrevEvtEndTime = dTime;
+      }  // for( UInt_t uDigi = 0; uDigi < uNbSelDigis; ++uDigi )
+
+      /// catch the case where we reach the end of the vector before being out of the time window
+      if (uLocalIndexEnd < uLocalIndexStart) uLocalIndexEnd = uNbSelDigis;
+    }  // if ( fT0DigiVec )
+    else
+      LOG(fatal) << "Cbm2021EventBuilderAlgo::SearchMatches => "
+                 << "T0 as selection detector but vector not found!";
+  }  // if( ECbmModuleId::kT0 == detMatch.detId )
+  else {
+    UInt_t uNbSelDigis = (0 < GetNofDigis(detMatch.detId)
+                            ? GetNofDigis(detMatch.detId)
+                            : 0);
+    /// Loop on size of vector
+    for (UInt_t uDigi = detMatch.fuStartIndex; uDigi < uNbSelDigis; ++uDigi) {
+      const DigiCheck* pDigi = GetDigi<DigiCheck>(uDigi);
+      /// Check that _entry is not out of range
+      if (nullptr != pDigi) {
+        Double_t dTime     = pDigi->GetTime();
+        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;
+        }  // if( dTimeDiff < detMatch.fdTimeWinBeg )
+        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;
+        }  // else if( detMatch.fdTimeWinEnd < dTimeDiff ) of if( dTimeDiff < detMatch.fdTimeWinBeg )
+
+        AddDigiToEvent(detMatch, uDigi);
+
+        if (fdPrevEvtEndTime < dTime) fdPrevEvtEndTime = dTime;
+      }  // if( nullptr != pDigi )
+    }    // for( UInt_t uDigi = 0; uDigi < uNbSelDigis; ++uDigi )
+
+    /// catch the case where we reach the end of the vector before being out of the time window
+    if (uLocalIndexEnd < uLocalIndexStart) uLocalIndexEnd = uNbSelDigis;
+  }  // else of if( ECbmModuleId::kT0 == detMatch.detId ) => Digi containers controlled by DigiManager
+
+  /// Update the StartIndex and EndIndex for the next event seed
+  detMatch.fuStartIndex = uLocalIndexStart;
+  detMatch.fuEndIndex   = uLocalIndexEnd;
+}
+
+void Cbm2021EventBuilderAlgo::AddDigiToEvent(
+  EventBuilderDetector& det,
+  Int_t _entry) {
+  fCurrentEvent->AddData(det.dataType, _entry);
+}
+
+Bool_t Cbm2021EventBuilderAlgo::HasTrigger(CbmEvent* event) {
+  /// Check first reference detector
+  if (kFALSE == CheckTriggerConditions(event, fRefDet)) {
+    return kFALSE;
+  }  // if (kFALSE == CheckTriggerConditions(event, fRefDet) )
+
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    if (kFALSE == CheckTriggerConditions(event, *det)) return kFALSE;
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+  /// All Ok, trigger is there
+  return kTRUE;
+}
+
+Bool_t Cbm2021EventBuilderAlgo::CheckTriggerConditions(
+  CbmEvent* event,
+  EventBuilderDetector& det) {
+  /// Check if both Trigger conditions disabled for this detector
+  if (0 == det.fuTriggerMinDigis && det.fiTriggerMaxDigis < 0) {
+    return kTRUE;
+  }  // if( 0 == det.fuTriggerMinDigis && det.fiTriggerMaxDigis < 0 )
+
+  /// Check if detector present
+  if (ECbmModuleId::kT0 == det.detId) {
+    /// FIXME: special case to be removed once T0 supported by DigiManager
+    if (!(fT0DigiVec)) {
+      LOG(warning) << "Event does not have digis storage for T0"
+                   << " while the following trigger minimum are defined: "
+                   << det.fuTriggerMinDigis << " " << det.fiTriggerMaxDigis;
+      return kFALSE;
+    }  // if( !(fT0DigiVec) )
+  }    // if( ECbmDataType::kT0Digi == det.detId )
+  else {
+    if (!DetIsPresent(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;
+    }  // if( !fDigiMan->IsPresent( det ) )
+  }    // else of if( ECbmDataType::kT0Digi == det )
+
+  /// Check trigger rejection by minimal number or absence
+  Int_t iNbDigis = event->GetNofData(det.dataType);
+  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;
+  }  // if((-1 == iNbDigis) || (static_cast<UInt_t>(iNbDigis) < det.fuTriggerMinDigis))
+  /// 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 if( iNbDigis < det.fiTriggerMaxDigis )
+  else {
+    return kTRUE;
+  }  // else of else if( iNbDigis < det.fiTriggerMaxDigis )
+}
+//----------------------------------------------------------------------
+void Cbm2021EventBuilderAlgo::CreateHistograms() {
+  /// FIXME: Disable clang formatting for histograms declaration for now
+  /* clang-format off */
+  fhEventTime = new TH1F("hEventTime",
+                         "seed time of the events; Seed time [s]; Events",
+                         60000, 0, 600);
+  fhEventDt   = new TH1F( "fhEventDt",
+                          "interval in seed time of consecutive events; Seed time [s]; Events",
+                          2100, -100.5, 1999.5);
+  fhEventSize =
+    new TH1F("hEventSize",
+             "nb of all  digis in the event; Nb Digis []; Events []",
+             10000, 0, 10000);
+  fhNbDigiPerEvtTime =
+    new TH2I("hNbDigiPerEvtTime",
+             "nb of all  digis per event vs seed time of the events; Seed time "
+             "[s]; Nb Digis []; Events []",
+              600, 0,   600,
+             1000, 0, 10000);
+
+  /// Loop on selection detectors
+  for (std::vector< EventBuilderDetector >::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;
+    } // if( "Invalid" == (*det).sName )
+
+    fvhNbDigiPerEvtTimeDet.push_back(
+      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() ),
+                 600, 0,  600,
+                4000, 0, 4000) );
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+  AddHistoToVector(fhEventTime,            "evtbuild");
+  AddHistoToVector(fhEventDt,              "evtbuild");
+  AddHistoToVector(fhEventSize,            "evtbuild");
+  AddHistoToVector(fhNbDigiPerEvtTime,     "evtbuild");
+  for (std::vector<TH2*>::iterator itHist = fvhNbDigiPerEvtTimeDet.begin();
+       itHist != fvhNbDigiPerEvtTimeDet.end();
+       ++itHist) {
+    if( nullptr != (*itHist) )
+    {
+      AddHistoToVector((*itHist),   "evtbuild");
+    } // if( nullptr != (*itHist) )
+  }  // for( std::vector<TH2*>::iterator itHist = fvhNbDigiPerEvtTimeDet.begin(); itHist != fvhNbDigiPerEvtTimeDet.end(); ++itHist )
+
+  /// FIXME: Re-enable clang formatting after histograms declaration
+  /* clang-format on */
+}
+void Cbm2021EventBuilderAlgo::FillHistos() {
+  Double_t dPreEvtTime = -1.0;
+  for (CbmEvent* evt : fEventVector) {
+    fhEventTime->Fill(evt->GetStartTime() * 1e-9);
+    if (0.0 <= dPreEvtTime) {
+      fhEventDt->Fill(evt->GetStartTime() - dPreEvtTime);
+    }  // if( 0.0 <= dPreEvtTime )
+    fhEventSize->Fill(evt->GetNofData());
+    fhNbDigiPerEvtTime->Fill(evt->GetStartTime() * 1e-9, evt->GetNofData());
+
+    /// Loop on selection detectors
+    for (UInt_t uDetIdx = 0; uDetIdx < fvDets.size(); ++uDetIdx) {
+      if (nullptr == fvhNbDigiPerEvtTimeDet[uDetIdx]) continue;
+
+      fvhNbDigiPerEvtTimeDet[uDetIdx]->Fill(
+        evt->GetStartTime() * 1e-9, evt->GetNofData(fvDets[uDetIdx].dataType));
+    }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+    dPreEvtTime = evt->GetStartTime();
+  }  // for( CbmEvent * evt: fEventVector )
+}
+void Cbm2021EventBuilderAlgo::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();
+  }  // for( std::vector<TH2*>::iterator itHist = fvhNbDigiPerEvtTimeDet.begin(); itHist != fvhNbDigiPerEvtTimeDet.end(); ++itHist )
+
+  /*
+   if( kTRUE == bResetTime )
+   {
+      /// Also reset the Start time for the evolution plots!
+      fdStartTime = -1.0;
+   } // if( kTRUE == bResetTime )
+*/
+}
+//----------------------------------------------------------------------
+void Cbm2021EventBuilderAlgo::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(EventBuilderDetector(refDet,
+                                            dataTypeIn,
+                                            sNameIn,
+                                            uTriggerMinDigisIn,
+                                            iTriggerMaxDigisIn,
+                                            fdTimeWinBegIn,
+                                            fdTimeWinEndIn));
+}
+void Cbm2021EventBuilderAlgo::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(EventBuilderDetector(selDet,
+                                   dataTypeIn,
+                                   sNameIn,
+                                   uTriggerMinDigisIn,
+                                   iTriggerMaxDigisIn,
+                                   fdTimeWinBegIn,
+                                   fdTimeWinEndIn));
+}
+//----------------------------------------------------------------------
+//----------------------------------------------------------------------
+void Cbm2021EventBuilderAlgo::SetReferenceDetector(
+  EventBuilderDetector refDetIn) {
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    if ((*det) == refDetIn) {
+      LOG(warning)
+        << "Cbm2021EventBuilderAlgo::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( (*det)  == refDetIn )
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+  if (fRefDet == refDetIn) {
+    LOG(warning)
+      << "Cbm2021EventBuilderAlgo::SetReferenceDetector => "
+         "Doing nothing, identical reference detector already in use";
+  }  // if( fRefDet == refDetIn )
+  else {
+    LOG(info) << "Cbm2021EventBuilderAlgo::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!";
+  }  // else of if( fRefDet == refDetIn )
+  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 Cbm2021EventBuilderAlgo::AddDetector(
+  EventBuilderDetector selDet) {
+  if (fRefDet == selDet) {
+    LOG(fatal) << "Cbm2021EventBuilderAlgo::AddDetector => Cannot "
+                  "add the reference detector as selection detector!"
+               << std::endl
+               << "=> Maybe first change the reference detector with "
+                  "SetReferenceDetector?";
+  }  // if( fRefDet == selDet )
+
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    if ((*det) == selDet) {
+      LOG(warning) << "Cbm2021EventBuilderAlgo::AddDetector => "
+                      "Doing nothing, selection detector already in list!"
+                   << selDet.sName;
+      return;
+    }  // if( (*det)  == selDet )
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+  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 Cbm2021EventBuilderAlgo::RemoveDetector(
+  EventBuilderDetector selDet) {
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    if ((*det) == selDet) {
+      fvDets.erase(det);
+      return;
+    }  // if( (*det)  == selDet )
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+  LOG(warning) << "Cbm2021EventBuilderAlgo::RemoveDetector => Doing "
+                  "nothing, selection detector not in list!"
+               << selDet.sName;
+}
+//----------------------------------------------------------------------
+void Cbm2021EventBuilderAlgo::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;
+  }  // if( fRefDet == selDet )
+
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::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;
+    }  // if( (*det).detId  == selDet )
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+  LOG(warning)
+    << "Cbm2021EventBuilderAlgo::SetTriggerMinNumber => "
+       "Doing nothing, detector neither reference nor in selection list!"
+    << selDet;
+}
+void Cbm2021EventBuilderAlgo::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;
+  }  // if( fRefDet == selDet )
+
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::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;
+    }  // if( (*det).detId  == selDet )
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+  LOG(warning)
+    << "Cbm2021EventBuilderAlgo::SetTriggerMaxNumber => "
+       "Doing nothing, detector neither reference nor in selection list!"
+    << selDet;
+}
+void Cbm2021EventBuilderAlgo::SetTriggerWindow(ECbmModuleId selDet,
+                                                          Double_t dWinBeg,
+                                                          Double_t dWinEnd) {
+  /// Check if valid time window: end strictly after beginning
+  if (dWinEnd <= dWinBeg)
+    LOG(fatal) << "Cbm2021EventBuilderAlgo::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;
+  }  // if( fRefDet == selDet )
+
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    if ((*det).detId == selDet) {
+      (*det).fdTimeWinBeg = dWinBeg;
+      (*det).fdTimeWinEnd = dWinEnd;
+
+      bFound = kTRUE;
+    }  // if( (*det).detId  == selDet )
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+
+  if (kFALSE == bFound) {
+    LOG(warning)
+      << "Cbm2021EventBuilderAlgo::SetTriggerWindow => "
+         "Doing nothing, detector neither reference nor in selection list!"
+      << selDet;
+  }  // if( kFALSE == bFound )
+
+  /// 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 Cbm2021EventBuilderAlgo::UpdateTimeWinBoundariesExtrema() {
+  /// Initialize with reference detector
+  fdEarliestTimeWinBeg = fRefDet.fdTimeWinBeg;
+  fdLatestTimeWinEnd   = fRefDet.fdTimeWinEnd;
+
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    fdEarliestTimeWinBeg = std::min(fdEarliestTimeWinBeg, (*det).fdTimeWinBeg);
+    fdLatestTimeWinEnd   = std::max(fdLatestTimeWinEnd, (*det).fdTimeWinEnd);
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+}
+void Cbm2021EventBuilderAlgo::UpdateWidestTimeWinRange() {
+  /// Initialize with reference detector
+  fdWidestTimeWinRange = fRefDet.fdTimeWinEnd - fRefDet.fdTimeWinBeg;
+
+  /// Loop on selection detectors
+  for (std::vector<EventBuilderDetector>::iterator det = fvDets.begin();
+       det != fvDets.end();
+       ++det) {
+    fdWidestTimeWinRange =
+      std::max(fdWidestTimeWinRange, (*det).fdTimeWinEnd - (*det).fdTimeWinBeg);
+  }  // for( std::vector< EventBuilderDetector >::iterator det = fvDets.begin(); det != fvDets.end(); ++det )
+}
+//----------------------------------------------------------------------
+
+ClassImp(Cbm2021EventBuilderAlgo)
diff --git a/reco/eventbuilder/digis/Cbm2021EventBuilderAlgo.h b/reco/eventbuilder/digis/Cbm2021EventBuilderAlgo.h
new file mode 100644
index 0000000000000000000000000000000000000000..f132b866974b0f667ff9e41940ea5e7030afba75
--- /dev/null
+++ b/reco/eventbuilder/digis/Cbm2021EventBuilderAlgo.h
@@ -0,0 +1,337 @@
+/********************************************************************************
+ *    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 CBM2021EVENTBUILDERALGO_H
+#define CBM2021EVENTBUILDERALGO_H
+
+/// CBM headers
+#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 <array>
+#include <map>
+#include <set>
+#include <tuple>
+#include <vector>
+
+#include <boost/any.hpp> 
+
+class TimesliceMetaData;
+class CbmEvent;
+class TClonesArray;
+class TH1;
+class TH2;
+class TNamed;
+class TCanvas;
+
+enum class EOverlapMode { NoOverlap, MergeOverlap, AllowOverlap };
+
+class EventBuilderDetector {
+public:
+  EventBuilderDetector() { ; }
+  EventBuilderDetector(ECbmModuleId detIdIn,
+                       ECbmDataType dataTypeIn,
+                       std::string sNameIn) {
+    detId    = detIdIn;
+    dataType = dataTypeIn;
+    sName    = sNameIn;
+  }
+  EventBuilderDetector(ECbmModuleId detIdIn,
+                       ECbmDataType dataTypeIn,
+                       std::string sNameIn,
+                       UInt_t uTriggerMinDigisIn,
+                       Int_t iTriggerMaxDigisIn,
+                       Double_t fdTimeWinBegIn,
+                       Double_t fdTimeWinEndIn)
+    : EventBuilderDetector(detIdIn, dataTypeIn, sNameIn) {
+    fuTriggerMinDigis = uTriggerMinDigisIn;
+    fiTriggerMaxDigis = iTriggerMaxDigisIn;
+
+    fdTimeWinBeg = fdTimeWinBegIn;
+    fdTimeWinEnd = fdTimeWinEndIn;
+  }
+
+  bool operator==(const EventBuilderDetector& other) const {
+    return (other.detId == this->detId);
+  }
+  bool operator!=(const EventBuilderDetector& 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 EventBuilderDetector kEventBuilderDetSts =
+  EventBuilderDetector(ECbmModuleId::kSts, ECbmDataType::kStsDigi, "Sts");
+static const EventBuilderDetector kEventBuilderDetMuch =
+  EventBuilderDetector(ECbmModuleId::kMuch, ECbmDataType::kMuchDigi, "Much");
+static const EventBuilderDetector kEventBuilderDetTrd =
+  EventBuilderDetector(ECbmModuleId::kTrd, ECbmDataType::kTrdDigi, "Trd");
+static const EventBuilderDetector kEventBuilderDetTof =
+  EventBuilderDetector(ECbmModuleId::kTof, ECbmDataType::kTofDigi, "Tof");
+static const EventBuilderDetector kEventBuilderDetRich =
+  EventBuilderDetector(ECbmModuleId::kRich, ECbmDataType::kRichDigi, "Rich");
+static const EventBuilderDetector kEventBuilderDetPsd =
+  EventBuilderDetector(ECbmModuleId::kPsd, ECbmDataType::kPsdDigi, "Psd");
+static const EventBuilderDetector kEventBuilderDetT0 =
+  EventBuilderDetector(ECbmModuleId::kT0, ECbmDataType::kT0Digi, "T0");
+static const EventBuilderDetector kEventBuilderDetUndef =
+  EventBuilderDetector();
+
+class Cbm2021EventBuilderAlgo {
+public:
+  /** Default constructor **/
+  Cbm2021EventBuilderAlgo();
+
+  Cbm2021EventBuilderAlgo(
+    const Cbm2021EventBuilderAlgo&) = delete;
+  Cbm2021EventBuilderAlgo
+  operator=(const Cbm2021EventBuilderAlgo&) = delete;
+
+  /** Destructor **/
+  ~Cbm2021EventBuilderAlgo();
+
+  /** 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);
+
+  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(EventBuilderDetector refDetIn);
+  void AddDetector(EventBuilderDetector selDet);
+  void RemoveDetector(EventBuilderDetector 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;
+  }
+
+  /// Control flags
+  void SetEventOverlapMode(EOverlapMode 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 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;
+  }
+
+  /// Data output access
+  std::vector<CbmEvent*>& GetEventVector() { return fEventVector; }
+  void ClearEventVector();
+
+private:
+  /// Internal methods
+  Bool_t CheckDataAvailable(EventBuilderDetector& det);
+  void InitTs();
+  void BuildEvents();
+
+  void CreateHistograms();
+  void FillHistos();
+
+  template<class DigiSeed>
+  void LoopOnSeeds();
+  void CheckSeed(Double_t dSeedTime, UInt_t uSeedDigiIdx);
+  template<class DigiCheck>
+  void SearchMatches(Double_t dSeedTime, EventBuilderDetector& detMatch);
+  void AddDigiToEvent(EventBuilderDetector& det, Int_t uIdx);
+  Bool_t HasTrigger(CbmEvent*);
+  Bool_t CheckTriggerConditions(CbmEvent* event, EventBuilderDetector& det);
+
+  void UpdateTimeWinBoundariesExtrema();
+  void UpdateWidestTimeWinRange();
+
+  /// 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
+    /// Event building mode and detectors selection
+  EOverlapMode fOverMode {EOverlapMode::AllowOverlap};
+
+  EventBuilderDetector fRefDet =
+    EventBuilderDetector(ECbmModuleId::kT0, ECbmDataType::kT0Digi, "T0");
+  std::vector<EventBuilderDetector> fvDets = {
+    EventBuilderDetector(ECbmModuleId::kSts, ECbmDataType::kStsDigi, "kSts"),
+    EventBuilderDetector(ECbmModuleId::kMuch, ECbmDataType::kMuchDigi, "kMuch"),
+    EventBuilderDetector(ECbmModuleId::kTrd, ECbmDataType::kTrdDigi, "kTrd"),
+    EventBuilderDetector(ECbmModuleId::kTof, ECbmDataType::kTofDigi, "kTof"),
+    EventBuilderDetector(ECbmModuleId::kRich, ECbmDataType::kRichDigi, "kRich"),
+    EventBuilderDetector(ECbmModuleId::kPsd, ECbmDataType::kPsdDigi, "kPsd")};
+
+  Double_t fdEarliestTimeWinBeg = kdDefaultTimeWinBeg;
+  Double_t fdLatestTimeWinEnd   = kdDefaultTimeWinEnd;
+  Double_t fdWidestTimeWinRange = kdDefaultTimeWinEnd - kdDefaultTimeWinBeg;
+
+  Double_t fdTsStartTime  = -1;
+  Double_t fdTsLength     = -1;
+  Double_t fdTsOverLength = -1;
+
+  /// Data input
+  /// FIXME: usage of CbmDigiManager in FairMq context?!?
+  ///        => Maybe by registering vector (or vector reference) to ioman in Device?
+  //CbmDigiManager* fDigiMan                  = nullptr;  //!
+  const std::vector<CbmTofDigi>* fT0DigiVec = nullptr;  //!
+  TClonesArray* fTimeSliceMetaDataArray     = nullptr;  //!
+  const TimesliceMetaData* pTsMetaData      = 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;
+
+  bool DetIsPresent( ECbmModuleId detId ); 
+  UInt_t GetNofDigis( ECbmModuleId detId ); 
+  template <class Digi> const Digi* GetDigi( UInt_t uDigi );
+
+  /// Data ouptut
+  CbmEvent* fCurrentEvent =
+    nullptr;  //! pointer to the event which is currently build
+  std::vector<CbmEvent*> 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 fuErrors        = 0;   //! Error 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(Cbm2021EventBuilderAlgo, 1);
+};
+
+#endif  //  CBM2021EVENTBUILDERALGO_H
diff --git a/reco/eventbuilder/digis/Cbm2021EventBuilderTask.cxx b/reco/eventbuilder/digis/Cbm2021EventBuilderTask.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d338f840abdfdc3a0329bc9f26177338f845da0e
--- /dev/null
+++ b/reco/eventbuilder/digis/Cbm2021EventBuilderTask.cxx
@@ -0,0 +1,342 @@
+/********************************************************************************
+ *    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 "Cbm2021EventBuilderAlgo.h"
+#include "Cbm2021EventBuilderTask.h"
+
+#include "CbmEvent.h"
+#include "CbmDigiManager.h"
+
+#include "FairLogger.h"
+#include "FairRootManager.h"
+#include "FairRunOnline.h"
+
+#include "TClonesArray.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "THttpServer.h"
+#include <TFile.h>
+
+// ---- Default constructor -------------------------------------------
+Cbm2021EventBuilderTask::Cbm2021EventBuilderTask()
+  : FairTask("Cbm2021EventBuilderTask") {
+  /// Create Algo. To be made generic/switchable when more event building algo are available!
+  fpAlgo = new Cbm2021EventBuilderAlgo();
+}
+
+// ---- Destructor ----------------------------------------------------
+Cbm2021EventBuilderTask::~Cbm2021EventBuilderTask() {
+}
+
+// ----  Initialisation  ----------------------------------------------
+void Cbm2021EventBuilderTask::SetParContainers() {
+  /// Nothing to do
+}
+
+// ---- Init ----------------------------------------------------------
+InitStatus Cbm2021EventBuilderTask::Init() {
+  /// Get a handle from the IO manager
+  FairRootManager* ioman = FairRootManager::Instance();
+
+  // 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("CbmEvent", 100);
+  ioman->Register(
+    "CbmEvent", "Cbm_Event", fEvents, IsOutputBranchPersistent("CbmEvent"));
+
+  if (!fEvents) LOG(fatal) << "Output branch was not created";
+
+  /// Call Algo Init method
+  if (kTRUE == fpAlgo->InitAlgo())
+    return kSUCCESS;
+  else
+    return kFATAL;
+}
+
+// ---- ReInit  -------------------------------------------------------
+InitStatus Cbm2021EventBuilderTask::ReInit() { return kSUCCESS; }
+
+// ---- Exec ----------------------------------------------------------
+void Cbm2021EventBuilderTask::Exec(Option_t* /*option*/) {
+  LOG(debug2)
+    << "Cbm2021EventBuilderTask::Exec => Starting sequence";
+
+  //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->insert( fStsDigis->begin()+i, *Digi );
+    }
+    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->insert( fMuchBeamTimeDigis->begin()+i, *Digi );
+      }
+      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->insert( fMuchDigis->begin()+i, *Digi );
+      }
+      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->insert( fTrdDigis->begin()+i, *Digi );
+    }
+    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->insert( fTofDigis->begin()+i, *Digi );
+    }
+    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->insert( fRichDigis->begin()+i, *Digi );
+    }
+    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->insert( fPsdDigis->begin()+i, *Digi );
+    }
+    LOG(debug) << "Read: "<< fDigiMan->GetNofDigis(ECbmModuleId::kPsd) << " PSD digis.";
+    LOG(debug) << "In DigiManager: "<< fPsdDigis->size() << " PSD digis.";
+  }
+
+  /// Call Algo ProcessTs method
+  fpAlgo->ProcessTs();
+
+  /// Save the resulting vector of events in TClonesArray
+  FillOutput();
+  LOG(debug2) << "Cbm2021EventBuilderTask::Exec => Done";
+}
+
+
+// ---- Finish --------------------------------------------------------
+void Cbm2021EventBuilderTask::Finish() {
+  if (fbFillHistos) { SaveHistos(); }  // if( fbFillHistos )
+
+  /// Call Algo finish method
+  fpAlgo->Finish();
+}
+
+//----------------------------------------------------------------------
+void Cbm2021EventBuilderTask::FillOutput() {
+  /// Clear TClonesArray before usage.
+  fEvents->Delete();
+
+  /// Get vector reference from algo
+  std::vector<CbmEvent*> vEvents = fpAlgo->GetEventVector();
+
+  /// Move CbmEvent from temporary vector to TClonesArray
+  for (CbmEvent* event : vEvents) {
+    LOG(debug) << "Vector: " << event->ToString();
+    new ((*fEvents)[fEvents->GetEntriesFast()]) CbmEvent(std::move(*event));
+    LOG(debug) << "TClonesArray: "
+               << static_cast<CbmEvent*>(
+                    fEvents->At(fEvents->GetEntriesFast() - 1))
+                    ->ToString();
+  }  // for( CbmEvent* event: vEvents )
+
+  /// Clear event vector after usage
+  fpAlgo->ClearEventVector();
+}
+//----------------------------------------------------------------------
+void Cbm2021EventBuilderTask::SaveHistos() {
+  /// 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
+    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();
+  }  // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto )
+
+  /// Restore original directory position
+  oldDir->cd();
+  histoFile->Close();
+}
+//----------------------------------------------------------------------
+void Cbm2021EventBuilderTask::SetFillHistos(Bool_t bFlag) {
+  fbFillHistos = bFlag;
+  if (nullptr != fpAlgo) fpAlgo->SetFillHistos(fbFillHistos);
+}
+void Cbm2021EventBuilderTask::SetOutFilename(TString sNameIn) {
+  fsOutFileName = sNameIn;
+}
+
+void Cbm2021EventBuilderTask::SetReferenceDetector(
+  EventBuilderDetector refDet) {
+  if (nullptr != fpAlgo) fpAlgo->SetReferenceDetector(refDet);
+}
+void Cbm2021EventBuilderTask::AddDetector(
+  EventBuilderDetector selDet) {
+  if (nullptr != fpAlgo) fpAlgo->AddDetector(selDet);
+}
+void Cbm2021EventBuilderTask::RemoveDetector(
+  EventBuilderDetector selDet) {
+  if (nullptr != fpAlgo) fpAlgo->RemoveDetector(selDet);
+}
+
+void Cbm2021EventBuilderTask::SetTriggerMinNumber(
+  ECbmModuleId selDet,
+  UInt_t uVal) {
+  if (nullptr != fpAlgo) fpAlgo->SetTriggerMinNumber(selDet, uVal);
+}
+void Cbm2021EventBuilderTask::SetTriggerMaxNumber(
+  ECbmModuleId selDet,
+  Int_t iVal) {
+  if (nullptr != fpAlgo) fpAlgo->SetTriggerMaxNumber(selDet, iVal);
+}
+
+void Cbm2021EventBuilderTask::SetTriggerWindow(ECbmModuleId det,
+                                                          Double_t dWinBeg,
+                                                          Double_t dWinEnd) {
+  if (nullptr != fpAlgo) fpAlgo->SetTriggerWindow(det, dWinBeg, dWinEnd);
+}
+
+
+void Cbm2021EventBuilderTask::SetTsParameters(
+  Double_t dTsStartTime,
+  Double_t dTsLength,
+  Double_t dTsOverLength) {
+  if (nullptr != fpAlgo)
+    fpAlgo->SetTsParameters(dTsStartTime, dTsLength, dTsOverLength);
+}
+
+void Cbm2021EventBuilderTask::SetEventOverlapMode(
+  EOverlapMode mode) {
+  if (nullptr != fpAlgo) fpAlgo->SetEventOverlapMode(mode);
+}
+void Cbm2021EventBuilderTask::SetIgnoreTsOverlap(Bool_t bFlagIn) {
+  if (nullptr != fpAlgo) fpAlgo->SetIgnoreTsOverlap(bFlagIn);
+}
+void Cbm2021EventBuilderTask::ChangeMuchBeamtimeDigiFlag(
+  Bool_t bFlagIn) {
+  if (nullptr != fpAlgo) fpAlgo->ChangeMuchBeamtimeDigiFlag(bFlagIn);
+  fbUseMuchBeamtimeDigi = bFlagIn;
+}
+
+//----------------------------------------------------------------------
+
+ClassImp(Cbm2021EventBuilderTask)
diff --git a/reco/eventbuilder/digis/Cbm2021EventBuilderTask.h b/reco/eventbuilder/digis/Cbm2021EventBuilderTask.h
new file mode 100644
index 0000000000000000000000000000000000000000..48c46db8685a3eb46170748c1bf027708c77ce8d
--- /dev/null
+++ b/reco/eventbuilder/digis/Cbm2021EventBuilderTask.h
@@ -0,0 +1,118 @@
+/********************************************************************************
+ *    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 CBMM2021EVENTBUILDERTASK_H
+#define CBMM2021EVENTBUILDERTASK_H 
+
+/// FAIRROOT headers
+#include "FairTask.h"
+
+/// FAIRSOFT headers (geant, boost, ...)
+
+/// C/C++ headers
+#include "CbmMuchBeamTimeDigi.h"
+#include "CbmMuchDigi.h"
+#include "CbmPsdDigi.h"
+#include "CbmRichDigi.h"
+#include "CbmStsDigi.h"
+#include "CbmTofDigi.h"
+#include "CbmTrdDigi.h"
+
+#include <array>
+#include <map>
+#include <set>
+#include <tuple>
+#include <vector>
+
+class CbmDigiManager;
+class Cbm2021EventBuilderAlgo;
+class EventBuilderDetector;
+class TClonesArray;
+
+class Cbm2021EventBuilderTask : public FairTask {
+public:
+  /** Default constructor **/
+  Cbm2021EventBuilderTask();
+
+  Cbm2021EventBuilderTask(
+    const Cbm2021EventBuilderTask&) = delete;
+  Cbm2021EventBuilderTask
+  operator=(const Cbm2021EventBuilderTask&) = delete;
+
+  /** Constructor with parameters (Optional) **/
+  //  Cbm2021EventBuilderTask(Int_t verbose);
+
+
+  /** Destructor **/
+  ~Cbm2021EventBuilderTask();
+
+
+  /** 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();
+
+  void SetFillHistos(Bool_t bFlag = kTRUE);
+  void SetOutFilename(TString sNameIn);
+
+  void SetReferenceDetector(EventBuilderDetector refDet);
+  void AddDetector(EventBuilderDetector selDet);
+  void RemoveDetector(EventBuilderDetector selDet);
+
+  void SetTriggerMinNumber(ECbmModuleId selDet, UInt_t uVal);
+  void SetTriggerMaxNumber(ECbmModuleId selDet, Int_t iVal);
+
+  void SetTriggerWindow(ECbmModuleId det, Double_t dWinBeg, Double_t dWinEnd);
+
+  void SetTsParameters(Double_t dTsStartTime,
+                       Double_t dTsLength,
+                       Double_t dTsOverLength);
+
+  void SetEventOverlapMode(EOverlapMode mode);
+  void SetIgnoreTsOverlap(Bool_t bFlagIn);
+
+  void ChangeMuchBeamtimeDigiFlag(Bool_t bFlagIn = kFALSE);
+
+private:
+  void FillOutput();
+  void SaveHistos();
+
+  CbmDigiManager* fDigiMan = 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;
+
+  Bool_t fbUseMuchBeamtimeDigi = kTRUE;  //! Switch between MUCH digi classes
+
+  Cbm2021EventBuilderAlgo* fpAlgo = nullptr;
+
+  TClonesArray* fEvents = nullptr;  //! output container of CbmEvents
+
+  Bool_t fbFillHistos {kTRUE};  //! Switch ON/OFF filling of histograms
+
+  /** Name of the histogram output file **/
+  TString fsOutFileName {"data/HistosEvtWin.root"};
+
+  ClassDef(Cbm2021EventBuilderTask, 1);
+};
+
+#endif  // CBMM2021EVENTBUILDERTASK_H