From 2c5c98f32bb075c5c52737bc1483f5b59cc71b7c Mon Sep 17 00:00:00 2001
From: Volker Friese <v.friese@gsi.de>
Date: Fri, 28 Jul 2023 12:44:27 +0000
Subject: [PATCH] Rework event building configuration. Refs #2921

---
 algo/CMakeLists.txt                         |   5 +
 algo/evbuild/Config.cxx                     |  36 +++
 algo/evbuild/Config.h                       |  39 +++
 algo/evbuild/EventBuilder.cxx               | 172 +++++++------
 algo/evbuild/EventBuilder.h                 | 229 ++++++++---------
 algo/evbuild/EventBuilderConfig.cxx         |  39 +++
 algo/evbuild/EventBuilderConfig.h           |  42 +++
 algo/evbuild/EventbuildChain.cxx            |  81 +++---
 algo/evbuild/EventbuildChain.h              |  33 ++-
 algo/evselector/DigiEventSelector.cxx       |  26 +-
 algo/evselector/DigiEventSelector.h         |  14 +-
 algo/evselector/DigiEventSelectorConfig.cxx |  56 ++++
 algo/evselector/DigiEventSelectorConfig.h   |  57 +++++
 algo/global/Reco.cxx                        |  13 +-
 algo/global/Reco.h                          |   2 +-
 algo/params/EventbuildConfig.yaml           |  21 ++
 algo/params/config.yaml                     |  24 --
 algo/qa/DigiEventQa.cxx                     |  36 ++-
 algo/qa/DigiEventQa.h                       |  28 +-
 algo/test/_GTestDigiEventSelector.cxx       | 267 +++++++++++---------
 algo/test/_GTestEventBuilder.cxx            |  26 +-
 algo/test/_GTestTimeClusterTrigger.cxx      |  15 +-
 algo/trigger/DigiTriggerConfig.cxx          |  48 ++++
 algo/trigger/DigiTriggerConfig.h            |  72 ++++++
 algo/trigger/TimeClusterTrigger.cxx         |  28 +-
 algo/trigger/TimeClusterTrigger.h           |  21 +-
 macro/reco/CMakeLists.txt                   |   3 +-
 macro/reco/reco_config.yaml                 |  17 ++
 macro/reco/reco_fairroot.C                  |  46 +---
 reco/CMakeLists.txt                         |   2 +-
 reco/app/cbmreco_fairrun/Application.cxx    |  13 +-
 reco/mq/CbmDevBuildEvents.cxx               |   7 +-
 reco/mq/CbmDevBuildEvents.h                 |   2 +-
 reco/mq/CbmDevTrigger.cxx                   |   2 +-
 reco/mq/CbmDevTrigger.h                     |   2 +-
 reco/tasks/CbmReco.cxx                      |  47 ++--
 reco/tasks/CbmReco.h                        |  16 +-
 reco/tasks/CbmTaskBuildEvents.cxx           |  45 ++--
 reco/tasks/CbmTaskBuildEvents.h             |  22 +-
 reco/tasks/CbmTaskDigiEventQa.cxx           |  19 +-
 reco/tasks/CbmTaskDigiEventQa.h             |   8 +-
 reco/tasks/CbmTaskTriggerDigi.cxx           |  10 +-
 reco/tasks/CbmTaskTriggerDigi.h             |  43 ++--
 43 files changed, 1124 insertions(+), 610 deletions(-)
 create mode 100644 algo/evbuild/Config.cxx
 create mode 100644 algo/evbuild/Config.h
 create mode 100644 algo/evbuild/EventBuilderConfig.cxx
 create mode 100644 algo/evbuild/EventBuilderConfig.h
 create mode 100644 algo/evselector/DigiEventSelectorConfig.cxx
 create mode 100644 algo/evselector/DigiEventSelectorConfig.h
 create mode 100644 algo/params/EventbuildConfig.yaml
 delete mode 100644 algo/params/config.yaml
 create mode 100644 algo/trigger/DigiTriggerConfig.cxx
 create mode 100644 algo/trigger/DigiTriggerConfig.h
 create mode 100644 macro/reco/reco_config.yaml

diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index dabaaa06f4..60fe4c1d66 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -16,10 +16,14 @@ set(SRCS
   base/MainConfig.cxx
   base/util/TimingsFormat.cxx
   data/sts/LandauTable.cxx
+  evbuild/Config.cxx
   evbuild/EventBuilder.cxx
+  evbuild/EventBuilderConfig.cxx
   evbuild/EventbuildChain.cxx
+  trigger/DigiTriggerConfig.cxx
   trigger/TimeClusterTrigger.cxx
   evselector/DigiEventSelector.cxx
+  evselector/DigiEventSelectorConfig.cxx
   unpack/Unpack.cxx
   unpack/UnpackChain.cxx
   detectors/sts/ReadoutConfig.cxx
@@ -75,6 +79,7 @@ target_include_directories(Algo
          ${CMAKE_CURRENT_SOURCE_DIR}/unpack
          ${CMAKE_CURRENT_SOURCE_DIR}/detectors
          ${CMAKE_CURRENT_SOURCE_DIR}/qa
+         ${CMAKE_CURRENT_SOURCE_DIR}
          ${CMAKE_SOURCE_DIR}/core/data/global
 )
 
diff --git a/algo/evbuild/Config.cxx b/algo/evbuild/Config.cxx
new file mode 100644
index 0000000000..b690b5b1db
--- /dev/null
+++ b/algo/evbuild/Config.cxx
@@ -0,0 +1,36 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#include "Config.h"
+
+#include <fstream>
+
+#include <yaml-cpp/yaml.h>
+
+namespace cbm::algo::evbuild
+{
+
+  // -----   Constructor from YAML   --------------------------------------------
+  Config::Config(YAML::Node node)
+    : fTrigger(node["trigger"])
+    , fBuilder(node["eventbuilder"])
+    , fSelector(node["selector"])
+  {
+    if (!node) throw std::runtime_error("no configuration node for event building");
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----   Save configuration to YAML file   ----------------------------------
+  YAML::Node Config::ToYaml() const
+  {
+    YAML::Node result;
+    result["trigger"]      = fTrigger.ToYaml();   // Digi trigger config
+    result["eventbuilder"] = fBuilder.ToYaml();   // Event builder config
+    result["selector"]     = fSelector.ToYaml();  // Event selector config
+    return result;
+  }
+  // ----------------------------------------------------------------------------
+
+}  // namespace cbm::algo::evbuild
diff --git a/algo/evbuild/Config.h b/algo/evbuild/Config.h
new file mode 100644
index 0000000000..d2b722f956
--- /dev/null
+++ b/algo/evbuild/Config.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+
+#ifndef ALGO_EVBUILD_CONFIG_H
+#define ALGO_EVBUILD_CONFIG_H 1
+
+#include <yaml-cpp/yaml.h>
+
+#include "DigiEventSelectorConfig.h"
+#include "DigiTriggerConfig.h"
+#include "EventBuilderConfig.h"
+
+namespace cbm::algo::evbuild
+{
+
+  /** @class Config
+   ** @brief Configuration of digi event building
+   ** @author Volker Friese <v.friese@gsi.de>
+   ** @since 10 July 2023
+   **/
+  class Config {
+  public:  // methods
+    /** @brief Constructor from YAML **/
+    Config(YAML::Node node);
+
+    /** @brief Save to YAML file **/
+    YAML::Node ToYaml() const;
+
+  public:                               // data members
+    DigiTriggerConfig fTrigger;         ///< Digi trigger configuration
+    EventBuilderConfig fBuilder;        ///< Event builder configuration
+    DigiEventSelectorConfig fSelector;  ///< Event selector configuration
+  };
+
+}  // namespace cbm::algo::evbuild
+
+#endif /* ALGO_EVBUILD_CONFIG_H */
diff --git a/algo/evbuild/EventBuilder.cxx b/algo/evbuild/EventBuilder.cxx
index 2f04b6f131..c901c8a781 100644
--- a/algo/evbuild/EventBuilder.cxx
+++ b/algo/evbuild/EventBuilder.cxx
@@ -5,96 +5,112 @@
 #include "EventBuilder.h"
 
 #include <cassert>
+#include <iomanip>
 
 using std::is_sorted;
 using std::vector;
 
-namespace cbm
+namespace cbm::algo::evbuild
 {
-  namespace algo
+
+  // -----   Algorithm execution   --------------------------------------------
+  EventBuilder::resultType EventBuilder::operator()(const CbmDigiTimeslice& ts, const vector<double> triggers) const
   {
-    // --- Execution
-    EventBuilder::resultType EventBuilder::operator()(const CbmDigiTimeslice& ts, const vector<double> triggers) const
-    {
-      // --- Output data
-      resultType result = {};
-      result.first.resize(triggers.size());
+    // --- Output data
+    resultType result = {};
+    result.first.resize(triggers.size());
 
-      std::transform(triggers.begin(), triggers.end(), result.first.begin(),
-                     [&ts, &result, this](const double& trigger) { return BuildEvent(ts, result.second, trigger); });
+    std::transform(triggers.begin(), triggers.end(), result.first.begin(),
+                   [&ts, &result, this](const double& trigger) { return BuildEvent(ts, result.second, trigger); });
 
-      EventBuilderMonitorData& monitor = result.second;
-      monitor.fSts.fNum += ts.fData.fSts.fDigis.size();
-      monitor.fRich.fNum += ts.fData.fRich.fDigis.size();
-      monitor.fMuch.fNum += ts.fData.fMuch.fDigis.size();
-      monitor.fTrd.fNum += ts.fData.fTrd.fDigis.size();
-      monitor.fTrd2d.fNum += ts.fData.fTrd2d.fDigis.size();
-      monitor.fTof.fNum += ts.fData.fTof.fDigis.size();
-      monitor.fPsd.fNum += ts.fData.fPsd.fDigis.size();
-      monitor.fBmon.fNum += ts.fData.fT0.fDigis.size();
-      return result;
-    }
+    EventBuilderMonitorData& monitor = result.second;
+    monitor.fSts.fNum += ts.fData.fSts.fDigis.size();
+    monitor.fRich.fNum += ts.fData.fRich.fDigis.size();
+    monitor.fMuch.fNum += ts.fData.fMuch.fDigis.size();
+    monitor.fTrd.fNum += ts.fData.fTrd.fDigis.size();
+    monitor.fTrd2d.fNum += ts.fData.fTrd2d.fDigis.size();
+    monitor.fTof.fNum += ts.fData.fTof.fDigis.size();
+    monitor.fPsd.fNum += ts.fData.fPsd.fDigis.size();
+    monitor.fBmon.fNum += ts.fData.fT0.fDigis.size();
+    return result;
+  }
 
-    // --- Build a single event
-    CbmDigiEvent EventBuilder::BuildEvent(const CbmDigiTimeslice& ts, EventBuilderMonitorData& monitor,
-                                          double trigger) const
-    {
-      CbmDigiEvent event;
-      event.fTime = trigger;
+  // --- Build a single event
+  CbmDigiEvent EventBuilder::BuildEvent(const CbmDigiTimeslice& ts, EventBuilderMonitorData& monitor,
+                                        double trigger) const
+  {
+    CbmDigiEvent event;
+    event.fTime = trigger;
 
-      // --- Loop over systems
-      for (auto entry : fEventWindows) {
+    // --- Loop over systems
+    for (auto entry : fConfig.fWindows) {
 
-        auto system       = entry.first;
-        const double tMin = trigger + entry.second.first;
-        const double tMax = trigger + entry.second.second;
+      auto system       = entry.first;
+      const double tMin = trigger + entry.second.first;
+      const double tMax = trigger + entry.second.second;
 
-        // --- Build the event using trigger window
-        switch (system) {
-          case ECbmModuleId::kSts: {
-            event.fData.fSts.fDigis = CopyRange(ts.fData.fSts.fDigis, tMin, tMax);
-            break;
-          }
-          case ECbmModuleId::kRich: {
-            event.fData.fRich.fDigis = CopyRange(ts.fData.fRich.fDigis, tMin, tMax);
-            break;
-          }
-          case ECbmModuleId::kMuch: {
-            event.fData.fMuch.fDigis = CopyRange(ts.fData.fMuch.fDigis, tMin, tMax);
-            break;
-          }
-          case ECbmModuleId::kTrd: {
-            event.fData.fTrd.fDigis = CopyRange(ts.fData.fTrd.fDigis, tMin, tMax);
-            break;
-          }
-          case ECbmModuleId::kTrd2d: {
-            event.fData.fTrd2d.fDigis = CopyRange(ts.fData.fTrd2d.fDigis, tMin, tMax);
-            break;
-          }
-          case ECbmModuleId::kTof: {
-            event.fData.fTof.fDigis = CopyRange(ts.fData.fTof.fDigis, tMin, tMax);
-            break;
-          }
-          case ECbmModuleId::kPsd: {
-            event.fData.fPsd.fDigis = CopyRange(ts.fData.fPsd.fDigis, tMin, tMax);
-            break;
-          }
-          case ECbmModuleId::kT0: {
-            event.fData.fT0.fDigis = CopyRange(ts.fData.fT0.fDigis, tMin, tMax);
-            break;
-          }
-          default: break;
+      // --- Build the event using trigger window
+      switch (system) {
+        case ECbmModuleId::kSts: {
+          event.fData.fSts.fDigis = CopyRange(ts.fData.fSts.fDigis, tMin, tMax);
+          break;
+        }
+        case ECbmModuleId::kRich: {
+          event.fData.fRich.fDigis = CopyRange(ts.fData.fRich.fDigis, tMin, tMax);
+          break;
+        }
+        case ECbmModuleId::kMuch: {
+          event.fData.fMuch.fDigis = CopyRange(ts.fData.fMuch.fDigis, tMin, tMax);
+          break;
+        }
+        case ECbmModuleId::kTrd: {
+          event.fData.fTrd.fDigis = CopyRange(ts.fData.fTrd.fDigis, tMin, tMax);
+          break;
+        }
+        case ECbmModuleId::kTrd2d: {
+          event.fData.fTrd2d.fDigis = CopyRange(ts.fData.fTrd2d.fDigis, tMin, tMax);
+          break;
+        }
+        case ECbmModuleId::kTof: {
+          event.fData.fTof.fDigis = CopyRange(ts.fData.fTof.fDigis, tMin, tMax);
+          break;
         }
+        case ECbmModuleId::kPsd: {
+          event.fData.fPsd.fDigis = CopyRange(ts.fData.fPsd.fDigis, tMin, tMax);
+          break;
+        }
+        case ECbmModuleId::kT0: {
+          event.fData.fT0.fDigis = CopyRange(ts.fData.fT0.fDigis, tMin, tMax);
+          break;
+        }
+        default: break;
       }
-      monitor.fSts.fNumInEvents += event.fData.fSts.fDigis.size();
-      monitor.fRich.fNumInEvents += event.fData.fRich.fDigis.size();
-      monitor.fMuch.fNumInEvents += event.fData.fMuch.fDigis.size();
-      monitor.fTrd.fNumInEvents += event.fData.fTrd.fDigis.size();
-      monitor.fTrd2d.fNumInEvents += event.fData.fTrd2d.fDigis.size();
-      monitor.fTof.fNumInEvents += event.fData.fTof.fDigis.size();
-      monitor.fPsd.fNumInEvents += event.fData.fPsd.fDigis.size();
-      monitor.fBmon.fNumInEvents += event.fData.fT0.fDigis.size();
-      return event;
     }
-  }  // namespace algo
-}  // namespace cbm
+    monitor.fSts.fNumInEvents += event.fData.fSts.fDigis.size();
+    monitor.fRich.fNumInEvents += event.fData.fRich.fDigis.size();
+    monitor.fMuch.fNumInEvents += event.fData.fMuch.fDigis.size();
+    monitor.fTrd.fNumInEvents += event.fData.fTrd.fDigis.size();
+    monitor.fTrd2d.fNumInEvents += event.fData.fTrd2d.fDigis.size();
+    monitor.fTof.fNumInEvents += event.fData.fTof.fDigis.size();
+    monitor.fPsd.fNumInEvents += event.fData.fPsd.fDigis.size();
+    monitor.fBmon.fNumInEvents += event.fData.fT0.fDigis.size();
+    return event;
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----   Info to string   -------------------------------------------------
+  std::string EventBuilder::ToString() const
+  {
+    std::stringstream out;
+    out << "--- Using EventBuilder with event windows:";
+    for (const auto& entry : fConfig.fWindows) {
+      out << "\n  " << std::left << std::setw(5) << ::ToString(entry.first) << ": ";
+      out << "  [" << std::right << std::setw(5) << entry.second.first;
+      out << ", " << std::right << std::setw(5) << entry.second.second << "] ns";
+    }
+    return out.str();
+  }
+  // --------------------------------------------------------------------------
+
+}  // namespace cbm::algo::evbuild
diff --git a/algo/evbuild/EventBuilder.h b/algo/evbuild/EventBuilder.h
index 2d6128801f..973a13dd2e 100644
--- a/algo/evbuild/EventBuilder.h
+++ b/algo/evbuild/EventBuilder.h
@@ -11,139 +11,124 @@
 
 #include <algorithm>
 #include <map>
+#include <string>
 #include <vector>
 
-namespace cbm
-{
-  namespace algo
-  {
-    /** @brief Time comparison of two objects with time stamps (class implementing GetTime()) **/
-    template<typename Data1, typename Data2>
-    bool IsBefore(const Data1& obj1, const Data2& obj2)
-    {
-      return obj1.GetTime() < obj2.GetTime();
-    }
+#include "EventBuilderConfig.h"
 
+namespace cbm::algo::evbuild
+{
 
-    /** @struct EventBuilderDetectorMonitorData
-     ** @author Dominik Smith <d.smith@gsi.de>
-     ** @since 23 Jun 2023
-     ** @brief Monitoring data for event building for one detector
+  /** @struct EventBuilderDetectorMonitorData
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 23 Jun 2023
+   ** @brief Monitoring data for event building for one detector
+   **/
+  struct EventBuilderDetectorMonitorData {
+    size_t fNumInEvents;  ///< Number of digis collected into events
+    size_t fNum;          ///< Full number of digis in input source
+  };
+
+
+  /** @struct EventBuilderMonitorData
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 23 Jun 2023
+   ** @brief Monitoring data for event building
+   **/
+  struct EventBuilderMonitorData {
+    EventBuilderDetectorMonitorData fSts;    ///< Monitoring data for STS
+    EventBuilderDetectorMonitorData fMuch;   ///< Monitoring data for MUCH
+    EventBuilderDetectorMonitorData fTof;    ///< Monitoring data for TOF
+    EventBuilderDetectorMonitorData fBmon;   ///< Monitoring data for T0
+    EventBuilderDetectorMonitorData fTrd;    ///< Monitoring data for TRD
+    EventBuilderDetectorMonitorData fTrd2d;  ///< Monitoring data for TRD2D
+    EventBuilderDetectorMonitorData fRich;   ///< Monitoring data for RICH
+    EventBuilderDetectorMonitorData fPsd;    ///< Monitoring data for PSD
+  };
+
+
+  /** @class EventBuilder
+   ** @author Volker Friese <v.friese@gsi.de>
+   ** @since 2021
+   ** @brief Constructs CbmDigiEvents out of CbmDigiTimeslices
+   **
+   ** Events are constructed by copying digi data from the source (CbmDigiTimeslice).
+   ** Digis are selected in trigger windows, the sizes of which relative to a trigger time are configurable.
+   ** For each trigger time, an event is generated. The time intervals may overlap, resulting in digis
+   ** being attributed to multiple events.
+   **
+   ** The source digi vectors (in CbmDigiTimeslice) must be sorted w.r.t. time, otherwise the behaviour is
+   ** undefined.
+   **
+   ** The trigger vector must be sorted.
+   **/
+  class EventBuilder {
+
+  public:
+    typedef std::pair<std::vector<CbmDigiEvent>, EventBuilderMonitorData> resultType;
+
+    /** @brief Constructor **/
+    EventBuilder(const EventBuilderConfig& config) : fConfig(config) {}
+
+
+    /** @brief Destructor **/
+    virtual ~EventBuilder() {};
+
+
+    /** @brief Execution
+     ** @param  ts       Digi source (timeslice)
+     ** @param  triggers List of trigger times
+     ** @return Vector of constructed events and monitoring data
      **/
-    struct EventBuilderDetectorMonitorData {
-      size_t fNumInEvents;  ///< Number of digis collected into events
-      size_t fNum;          ///< Full number of digis in input source
-    };
+    resultType operator()(const CbmDigiTimeslice& ts, const std::vector<double> triggers) const;
 
 
-    /** @struct EventBuilderMonitorData
-     ** @author Dominik Smith <d.smith@gsi.de>
-     ** @since 23 Jun 2023
-     ** @brief Monitoring data for event building
+    /** @brief Info to string **/
+    std::string ToString() const;
+
+
+  private:  // methods
+    /** @brief Build a single event from a trigger time
+     ** @param  ts      Digi source (timeslice)
+     ** @param  monitor Monitoring data
+     ** @param  trigger Trigger time
+     ** @return Digi event
      **/
-    struct EventBuilderMonitorData {
-      EventBuilderDetectorMonitorData fSts;    ///< Monitoring data for STS
-      EventBuilderDetectorMonitorData fMuch;   ///< Monitoring data for MUCH
-      EventBuilderDetectorMonitorData fTof;    ///< Monitoring data for TOF
-      EventBuilderDetectorMonitorData fBmon;   ///< Monitoring data for T0
-      EventBuilderDetectorMonitorData fTrd;    ///< Monitoring data for TRD
-      EventBuilderDetectorMonitorData fTrd2d;  ///< Monitoring data for TRD2D
-      EventBuilderDetectorMonitorData fRich;   ///< Monitoring data for RICH
-      EventBuilderDetectorMonitorData fPsd;    ///< Monitoring data for PSD
-    };
-
-
-    /** @class EventBuilder
-     ** @author Volker Friese <v.friese@gsi.de>
-     ** @since 2021
-     ** @brief Constructs CbmDigiEvents out of CbmDigiTimeslices
+    CbmDigiEvent BuildEvent(const CbmDigiTimeslice& ts, EventBuilderMonitorData& monitor, double trigger) const;
+
+
+    /** @brief Copy data objects in a given time interval from the source to the target vector
+     ** @param source Source data vector
+     ** @param tMin   Minimal time
+     ** @param tMax   Maximal time
+     ** @return Target data vector
      **
-     ** Events are constructed by copying digi data from the source (CbmDigiTimeslice).
-     ** Digis are selected in trigger windows, the sizes of which relative to a trigger time are configurable.
-     ** For each trigger time, an event is generated. The time intervals may overlap, resulting in digis
-     ** being attributed to multiple events.
+     ** The Data class specialisation must implement the method double GetTime(), which is used to
+     ** check whether the Data object falls into the specified time interval.
      **
-     ** The source digi vectors (in CbmDigiTimeslice) must be sorted w.r.t. time, otherwise the behaviour is
-     ** undefined.
+     ** The source vector must be ordered w.r.t. GetTime(), otherwise the behaviour is undefined.
      **
-     ** The trigger vector must be sorted.
+     ** TODO: The current implementation searches, for each trigger, the entire source vector. This
+     ** can surely be optimised when the contract that the trigger vector be sorted is properly exploited,
+     ** e.g., by starting the search for the first digi in the trigger window from the start of the
+     ** previous trigger window. This, however, requires bookkeeping hardly to be realised without
+     ** changing the state of the class. I leave this for the future and for bright specialists.
      **/
-    class EventBuilder {
-
-    public:
-      typedef std::pair<std::vector<CbmDigiEvent>, EventBuilderMonitorData> resultType;
-
-      /** @brief Constructor **/
-      EventBuilder() {};
-
-
-      /** @brief Destructor **/
-      virtual ~EventBuilder() {};
-
-
-      /** @brief Execution
-       ** @param  ts       Digi source (timeslice)
-       ** @param  triggers List of trigger times
-       ** @return Vector of constructed events and monitoring data
-       **/
-      resultType operator()(const CbmDigiTimeslice& ts, const std::vector<double> triggers) const;
-
-
-      /** @brief Build a single event from a trigger time
-       ** @param  ts      Digi source (timeslice)
-       ** @param  monitor Monitoring data
-       ** @param  trigger Trigger time
-       ** @return Digi event
-       **/
-      CbmDigiEvent BuildEvent(const CbmDigiTimeslice& ts, EventBuilderMonitorData& monitor, double trigger) const;
-
-
-      /** @brief Configure the event windows
-       ** @param system  Detector system identifier
-       ** @param tMin    Event window start time w.r.t. event time
-       ** @param tMax    Event window end time w.r.t. event time
-       **/
-      void SetEventWindow(ECbmModuleId system, double tMin, double tMax)
-      {
-        fEventWindows[system] = std::make_pair(tMin, tMax);
-      }
-
-    private:  // methods
-      /** @brief Copy data objects in a given time interval from the source to the target vector
-       ** @param source Source data vector
-       ** @param tMin   Minimal time
-       ** @param tMax   Maximal time
-       ** @return Target data vector
-       **
-       ** The Data class specialisation must implement the method double GetTime(), which is used to
-       ** check whether the Data object falls into the specified time interval.
-       **
-       ** The source vector must be ordered w.r.t. GetTime(), otherwise the behaviour is undefined.
-       **
-       ** TODO: The current implementation searches, for each trigger, the entire source vector. This
-       ** can surely be optimised when the contract that the trigger vector be sorted is properly exploited,
-       ** e.g., by starting the search for the first digi in the trigger window from the start of the
-       ** previous trigger window. This, however, requires bookkeeping hardly to be realised without
-       ** changing the state of the class. I leave this for the future and for bright specialists.
-       **/
-      template<typename Data>
-      static typename std::vector<Data> CopyRange(const std::vector<Data>& source, double tMin, double tMax)
-      {
-        auto comp1 = [](const Data& obj, double value) { return obj.GetTime() < value; };
-        auto comp2 = [](double value, const Data& obj) { return value < obj.GetTime(); };
-        auto lower = std::lower_bound(source.begin(), source.end(), tMin, comp1);
-        auto upper = std::upper_bound(lower, source.end(), tMax, comp2);
-        return std::vector<Data>(lower, upper);
-      }
-
-
-    private:  // data members
-      /** Event time window relative to the trigger time for each detector system
-       ** Key is system identifier, value is (t_min, t_max).
-       **/
-      std::map<ECbmModuleId, std::pair<double, double>> fEventWindows;
-    };
-  }  // namespace algo
-}  // namespace cbm
+    template<typename Data>
+    static typename std::vector<Data> CopyRange(const std::vector<Data>& source, double tMin, double tMax)
+    {
+      auto comp1 = [](const Data& obj, double value) { return obj.GetTime() < value; };
+      auto comp2 = [](double value, const Data& obj) { return value < obj.GetTime(); };
+      auto lower = std::lower_bound(source.begin(), source.end(), tMin, comp1);
+      auto upper = std::upper_bound(lower, source.end(), tMax, comp2);
+      return std::vector<Data>(lower, upper);
+    }
+
+
+  private:                       // data members
+    EventBuilderConfig fConfig;  ///< Configuration / parameters
+  };
+
+}  // namespace cbm::algo::evbuild
 
 #endif /* CBM_ALGO_EVENTBUILDER_H */
diff --git a/algo/evbuild/EventBuilderConfig.cxx b/algo/evbuild/EventBuilderConfig.cxx
new file mode 100644
index 0000000000..e0817b04a4
--- /dev/null
+++ b/algo/evbuild/EventBuilderConfig.cxx
@@ -0,0 +1,39 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#include "EventBuilderConfig.h"
+
+
+namespace cbm::algo::evbuild
+{
+
+  // -----   Constructor from YAML   ------------------------------------------
+  EventBuilderConfig::EventBuilderConfig(YAML::Node config)
+  {
+    if (!config) throw std::runtime_error("EventBuilderConfig: no configuration node");
+    for (YAML::const_iterator it = config.begin(); it != config.end(); ++it) {
+      auto det      = ToCbmModuleIdCaseInsensitive(it->first.as<std::string>());
+      auto lower    = it->second[0].as<double>();
+      auto upper    = it->second[1].as<double>();
+      fWindows[det] = std::make_pair(lower, upper);
+    }
+    // TODO: Check if complete (should the parameters be mandatory?)
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----   Save to YAML   ---------------------------------------------------
+  YAML::Node EventBuilderConfig::ToYaml() const
+  {
+    YAML::Node result;
+    for (const auto& entry : fWindows) {
+      auto det    = ToString(entry.first);
+      result[det] = entry.second;
+    }
+    return result;
+  }
+  // --------------------------------------------------------------------------
+
+
+}  // namespace cbm::algo::evbuild
diff --git a/algo/evbuild/EventBuilderConfig.h b/algo/evbuild/EventBuilderConfig.h
new file mode 100644
index 0000000000..a828be62bf
--- /dev/null
+++ b/algo/evbuild/EventBuilderConfig.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#ifndef CBM_ALGO_EVBUILD_EVENTBUILDERCONFIG_H
+#define CBM_ALGO_EVBUILD_EVENTBUILDERCONFIG_H 1
+
+#include "CbmDefs.h"
+
+#include <map>
+
+#include <yaml-cpp/yaml.h>
+
+
+namespace cbm::algo::evbuild
+{
+
+  /** @class EventBuilderConfig
+   ** @brief Configuration of the EventBuilder class
+   ** @author Volker Friese <v.friese@gsi.de>
+   ** @since 12.11.2021
+   **
+   ** Holds time windows around the trigger time in which digis are associated to an event.
+   **/
+  class EventBuilderConfig {
+
+  public:
+    /** @brief Constructor from YAML **/
+    EventBuilderConfig(YAML::Node config);
+
+    /** @brief Save to YAML **/
+    YAML::Node ToYaml() const;
+
+
+  public:
+    std::map<ECbmModuleId, std::pair<double, double>> fWindows;  ///< Key: detector; value: [tmin, tmax]
+  };
+
+
+}  // namespace cbm::algo::evbuild
+
+#endif /* CBM_ALGO_EVBUILD_EVENTBUILDERCONFIG_H */
diff --git a/algo/evbuild/EventbuildChain.cxx b/algo/evbuild/EventbuildChain.cxx
index ac234de30f..4674f5f39a 100644
--- a/algo/evbuild/EventbuildChain.cxx
+++ b/algo/evbuild/EventbuildChain.cxx
@@ -4,48 +4,26 @@
 
 #include "EventbuildChain.h"
 
-using namespace cbm::algo;
+#include "CbmDigiTimeslice.h"
 
+#include <sstream>
+#include <string>
 
-// -----   Initialization   ---------------------------------------------------
-void EventbuildChain::Init(const MainConfig& config)
-{
+#include "evbuild/Config.h"
+
+
+using namespace cbm::algo::evbuild;
 
-  // TODO: Initialization should be part of the constructor, such that uninitialised objects
-  // cannot be instantiated.
-
-
-  fConfig = config;  // is used also in the Run method
-
-  // --- Configure the event builder
-  for (const auto& entry : fConfig.fEvtbuildWindows) {
-    auto system       = entry.first;
-    const double tMin = entry.second.first;
-    const double tMax = entry.second.second;
-    fEventBuilder.SetEventWindow(system, tMin, tMax);
-    L_(info) << "--- Use algo EventBuilder for " << ToString(system) << " with event window [" << tMin << ", " << tMax
-             << "] ns";
-  }
-
-  // --- Configure the event selector
-  evbuild::DigiEventSelectorParams selectPar;
-  selectPar.fMinNumDigis[ECbmModuleId::kT0]   = fConfig.fSelectMinDigisBmon;
-  selectPar.fMinNumLayers[ECbmModuleId::kSts] = fConfig.fSelectMinStationsSts;
-  selectPar.fMinNumLayers[ECbmModuleId::kTof] = fConfig.fSelectMinStationsTof;
-  fSelector                                   = std::make_unique<evbuild::DigiEventSelector>(selectPar);
-
-  // --- Configure the event QA
-  const double border    = 10.;  // TODO: Histogram border hard-coded
-  const uint32_t numBins = 100;  // TODO: Histogram bin number hard-coded
-  for (const auto& entry : config.fEvtbuildWindows) {
-    ECbmModuleId system     = entry.first;
-    double lower            = entry.second.first - border;   // Lower edge of histogram
-    double upper            = entry.second.second + border;  // Upper edge of histogram
-    fQaConfig.fData[system] = {numBins, lower, upper};
-  }
-
-  // N.b. The trigger algorithm need not be configured; its parameters are passed with each
-  // execution call.
+
+// -----   Constructor   ------------------------------------------------------
+EventbuildChain::EventbuildChain(const Config& config)
+  : fTriggerDet(config.fTrigger.Detector())
+  , fTrigger(config.fTrigger)
+  , fBuilder(config.fBuilder)
+  , fSelector(config.fSelector)
+  , fQa(DigiEventQaConfig(config.fBuilder, 10., 100))
+{
+  Status();
 }
 // ----------------------------------------------------------------------------
 
@@ -55,22 +33,21 @@ std::vector<CbmDigiEvent> EventbuildChain::Run(const CbmDigiTimeslice& timeslice
 {
 
   // --- Extract the digi time stamps of the trigger detector
-  std::vector<double> digiTimes = GetDigiTimes(timeslice, fConfig.fTriggerDet);
+  std::vector<double> digiTimes = GetDigiTimes(timeslice, fTriggerDet);
 
   // --- Call the trigger algorithm
-  std::vector<double> triggers =
-    fTrigger(digiTimes, fConfig.fTriggerWin, fConfig.fTriggerThreshold, fConfig.fTriggerDeadTime).first;
+  std::vector<double> triggers = fTrigger(digiTimes).first;
 
   // --- Perform event building
-  std::vector<CbmDigiEvent> events = fEventBuilder(timeslice, triggers).first;
+  std::vector<CbmDigiEvent> events = fBuilder(timeslice, triggers).first;
 
   // --- Apply event selector
-  auto notSelected = [&](CbmDigiEvent& ev) { return !((*fSelector)(ev)); };
+  auto notSelected = [&](CbmDigiEvent& ev) { return !(fSelector(ev)); };
   auto removeIt    = std::remove_if(events.begin(), events.end(), notSelected);
   events.erase(removeIt, events.end());
 
   // --- Run event QA
-  qa::DigiEventQaData qaData = fQa(events, fQaConfig);
+  DigiEventQaData qaData = fQa(events);
 
   // --- Some log
   L_(info) << "Triggers: " << triggers.size() << ", events " << events.size();
@@ -80,6 +57,20 @@ std::vector<CbmDigiEvent> EventbuildChain::Run(const CbmDigiTimeslice& timeslice
 // ----------------------------------------------------------------------------
 
 
+// -----   Status info   ------------------------------------------------------
+void EventbuildChain::Status() const
+{
+  L_(info) << "===   Eventbuiler configuration   ====================";
+  L_(info) << "--- Using trigger detector " << ::ToString(fTriggerDet);
+  L_(info) << fTrigger.ToString();
+  L_(info) << fBuilder.ToString();
+  L_(info) << fSelector.ToString();
+  L_(info) << fQa.ToString();
+  L_(info) << "======================================================";
+}
+// ----------------------------------------------------------------------------
+
+
 // -----   Get digi times from CbmDigiTimeslice   -----------------------------
 std::vector<double> EventbuildChain::GetDigiTimes(const CbmDigiTimeslice& timeslice, ECbmModuleId system)
 {
diff --git a/algo/evbuild/EventbuildChain.h b/algo/evbuild/EventbuildChain.h
index 11a3a4a7d3..ae35c95bc4 100644
--- a/algo/evbuild/EventbuildChain.h
+++ b/algo/evbuild/EventbuildChain.h
@@ -6,46 +6,51 @@
 #define CBM_ALGO_EVBUILD_EVBUILDCHAIN_H 1
 
 #include "CbmDefs.h"
-#include "CbmDigiTimeslice.h"
 
 #include "TimeClusterTrigger.h"
 
 #include "DigiEventQa.h"
 #include "DigiEventSelector.h"
 #include "EventBuilder.h"
-#include "MainConfig.h"
 #include "SubChain.h"
 
-namespace cbm::algo
+
+class CbmDigiTimeslice;
+
+namespace cbm::algo::evbuild
 {
 
+  class Config;
+
   /** @class EventbuildChain
    ** @brief Steering class for event building from digi timeslices
    ** @author Volker Friese <v.friese@gsi.de>
    ** @since 11 July 2023
    **
    ** Constructs a vector of CbmDigiEvents from a CbmDigiTimeslice. Uses the algorithms
-   ** - TimeClusterTrigger for the event time definiton
+   ** - TimeClusterTrigger for the event time definition
    ** - EventBuilder for construction of events by time intervals around the trigger time
    ** - DigiEventSelector for selection of constructed events according to the specified criteria
    **/
   class EventbuildChain : public SubChain {
 
   public:
-    /** @brief Initialization **/
-    void Init(const MainConfig& config);
+    /** @brief Constructor **/
+    EventbuildChain(const Config& config);
 
     /** @brief Execution **/
     std::vector<CbmDigiEvent> Run(const CbmDigiTimeslice&);
 
+    /** @brief Status info to logger **/
+    void Status() const;
+
 
-  private:                                                  // members
-    MainConfig fConfig;                                     ///< Configuration / parameters
-    TimeClusterTrigger fTrigger;                            ///< Trigger algorithm
-    EventBuilder fEventBuilder;                             ///< Event builder algorithm
-    std::unique_ptr<evbuild::DigiEventSelector> fSelector;  ///< Event selector algorithm
-    qa::DigiEventQa fQa;                                    ///< Event QA algorithm
-    qa::DigiEventQaConfig fQaConfig;                        ///< Configuration for event QA
+  private:                                               // members
+    ECbmModuleId fTriggerDet = ECbmModuleId::kNotExist;  ///< Trigger detector
+    TimeClusterTrigger fTrigger;                         ///< Trigger algorithm
+    EventBuilder fBuilder;                               ///< Event builder algorithm
+    DigiEventSelector fSelector;                         ///< Event selector algorithm
+    DigiEventQa fQa;                                     ///< Event QA algorithm
 
 
   private:  // methods
@@ -56,7 +61,7 @@ namespace cbm::algo
     std::vector<double> GetDigiTimes(const CbmDigiTimeslice& timeslice, ECbmModuleId system);
   };
 
-}  // namespace cbm::algo
+}  // namespace cbm::algo::evbuild
 
 
 #endif  //CBM_ALGO_EVBUILD_EVBUILDCHAIN
diff --git a/algo/evselector/DigiEventSelector.cxx b/algo/evselector/DigiEventSelector.cxx
index 59743bec71..4b53fd9dfc 100644
--- a/algo/evselector/DigiEventSelector.cxx
+++ b/algo/evselector/DigiEventSelector.cxx
@@ -23,7 +23,7 @@ namespace cbm::algo::evbuild
   {
 
     // --- Test number of digis per detector system
-    for (auto& entry : fParams.fMinNumDigis) {
+    for (auto& entry : fConfig.fMinNumDigis) {
       if (!(event.fData.Size(entry.first) >= entry.second)) {
         return false;
         break;
@@ -31,7 +31,7 @@ namespace cbm::algo::evbuild
     }
 
     // --- Test number of layers with digis per detector system
-    for (auto& entry : fParams.fMinNumLayers) {
+    for (auto& entry : fConfig.fMinNumLayers) {
       if (entry.second == 0) continue;
       switch (entry.first) {
         case ECbmModuleId::kSts:
@@ -41,7 +41,7 @@ namespace cbm::algo::evbuild
           if (!CheckTofLayers(event.fData.fTof.fDigis, entry.second)) return false;
           break;
         default:
-          throw std::runtime_error("Number of layers for " + ToString(entry.first) + " is not implemented");
+          throw std::runtime_error("Number of layers for " + ::ToString(entry.first) + " is not implemented");
           break;
       }
     }
@@ -125,4 +125,24 @@ namespace cbm::algo::evbuild
   // --------------------------------------------------------------------------
 
 
+  // -----   Info to string   -------------------------------------------------
+  std::string DigiEventSelector::ToString() const
+  {
+    std::stringstream out;
+    out << "--- Using DigiEventSelector with";
+    out << (fConfig.IsEmpty() ? " no selection criteria" : " selection criteria: ");
+    if (!fConfig.fMinNumDigis.empty()) {
+      out << "\n   min. digis : ";
+      for (const auto& entry : fConfig.fMinNumDigis)
+        out << ::ToString(entry.first) << " " << entry.second << "  ";
+    }
+    if (!fConfig.fMinNumLayers.empty()) {
+      out << "\n   min. layers: ";
+      for (const auto& entry : fConfig.fMinNumLayers)
+        out << ::ToString(entry.first) << " " << entry.second << "  ";
+    }
+    return out.str();
+  }
+  // --------------------------------------------------------------------------
+
 }  // namespace cbm::algo::evbuild
diff --git a/algo/evselector/DigiEventSelector.h b/algo/evselector/DigiEventSelector.h
index 28a0a2491d..4155c7eb86 100644
--- a/algo/evselector/DigiEventSelector.h
+++ b/algo/evselector/DigiEventSelector.h
@@ -10,6 +10,8 @@
 #include <cstdint>
 #include <map>
 
+#include "DigiEventSelectorConfig.h"
+
 namespace cbm::algo::evbuild
 {
 
@@ -37,8 +39,8 @@ namespace cbm::algo::evbuild
   class DigiEventSelector {
 
   public:
-    /** @brief Constructor with parameters **/
-    DigiEventSelector(DigiEventSelectorParams params) : fParams(params) {}
+    /** @brief Constructor with configuration **/
+    DigiEventSelector(DigiEventSelectorConfig config) : fConfig(config) {};
 
     /** @brief Test one event for the selection criteria
      ** @param event DigiEvent
@@ -47,6 +49,10 @@ namespace cbm::algo::evbuild
     bool operator()(const CbmDigiEvent& event) const;
 
 
+    /** @brief Info to string **/
+    std::string ToString() const;
+
+
   private:  // methods
     /** @brief Test for the number of STS stations
      ** @param digis Vector of STS digis
@@ -63,8 +69,8 @@ namespace cbm::algo::evbuild
     bool CheckTofLayers(const std::vector<CbmTofDigi>& digis, size_t minNum) const;
 
 
-  private:                                  // members
-    const DigiEventSelectorParams fParams;  ///< Selection parameters
+  private:                            // members
+    DigiEventSelectorConfig fConfig;  ///< Configuration / parameters
   };
 
 }  // namespace cbm::algo::evbuild
diff --git a/algo/evselector/DigiEventSelectorConfig.cxx b/algo/evselector/DigiEventSelectorConfig.cxx
new file mode 100644
index 0000000000..3b09a84bb2
--- /dev/null
+++ b/algo/evselector/DigiEventSelectorConfig.cxx
@@ -0,0 +1,56 @@
+/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Shreya Roy. Pierre-Alain Loizeau, Volker Friese [committer], Dominik Smith */
+
+#include "DigiEventSelectorConfig.h"
+
+#include "AlgoFairloggerCompat.h"
+
+
+namespace cbm::algo::evbuild
+{
+
+  // -----   Constructor from YAML   ------------------------------------------
+  DigiEventSelectorConfig::DigiEventSelectorConfig(YAML::Node config)
+  {
+    if (!config) return;
+    if (auto numDigis = config["minDigis"]) {
+      for (YAML::const_iterator it = numDigis.begin(); it != numDigis.end(); it++) {
+        auto det   = ToCbmModuleIdCaseInsensitive(it->first.as<std::string>());
+        auto value = it->second.as<size_t>();
+        if (value > 0) fMinNumDigis[det] = value;
+        else
+          L_(warning) << "DigiEventSelectorConfig: Ignoring minimum 0 for digis in " << ::ToString(det);
+      }
+    }
+    if (auto numLayers = config["minLayers"]) {
+      for (YAML::const_iterator it = numLayers.begin(); it != numLayers.end(); it++) {
+        auto det   = ToCbmModuleIdCaseInsensitive(it->first.as<std::string>());
+        auto value = it->second.as<size_t>();
+        if (value > 0) fMinNumLayers[det] = value;
+        else
+          L_(warning) << "DigiEventSelectorConfig: Ignoring minimum 0 for layers in " << ::ToString(det);
+      }
+    }
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----   Save to YAML   ---------------------------------------------------
+  YAML::Node DigiEventSelectorConfig::ToYaml() const
+  {
+    YAML::Node result;
+    for (const auto& entry : fMinNumDigis) {
+      auto det                = ToString(entry.first);
+      result["minDigis"][det] = entry.second;
+    }
+    for (const auto& entry : fMinNumLayers) {
+      auto det                 = ToString(entry.first);
+      result["minLayers"][det] = entry.second;
+    }
+    return result;
+  }
+  // --------------------------------------------------------------------------
+
+
+}  // namespace cbm::algo::evbuild
diff --git a/algo/evselector/DigiEventSelectorConfig.h b/algo/evselector/DigiEventSelectorConfig.h
new file mode 100644
index 0000000000..1076f3d69a
--- /dev/null
+++ b/algo/evselector/DigiEventSelectorConfig.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Shreya Roy. Pierre-Alain Loizeau, Volker Friese [committer], Dominik Smith */
+
+#ifndef CBM_ALGO_EVBUILD_DIGIEVENTSELECTORCONFIG_H
+#define CBM_ALGO_EVBUILD_DIGIEVENTSELECTORCONFIG_H 1
+
+#include "CbmDigiEvent.h"
+
+#include <cstdint>
+#include <map>
+
+#include <yaml-cpp/yaml.h>
+
+
+namespace cbm::algo::evbuild
+{
+
+  class EventbuildChain;
+
+
+  /** @class DigiEventSelectorConfig
+   ** @brief Configuration of the DigiEventSelector class
+   ** @author Dominik Smith <d.smith@ gsi.de>
+   ** @author Shreya Roy <s.roy@gsi.de>
+   ** @author Volker Friese <v.friese@gsi.de>
+   ** @since 26.01.2023
+   **
+   ** Holds minimum values for number of digis per event and detector system and for the
+   ** number of active layers/stations (containing at least one digi).
+   **
+   ** None of the parameters are mandatory.
+   **/
+  class DigiEventSelectorConfig {
+
+    friend class DigiEventSelector;
+
+  public:
+    /** @brief Constructor from YAML **/
+    DigiEventSelectorConfig(YAML::Node config);
+
+    /** @brief Presence of selection criteria **/
+    bool IsEmpty() const { return fMinNumDigis.empty() && fMinNumLayers.empty(); }
+
+    /** @brief Save to YAML **/
+    YAML::Node ToYaml() const;
+
+
+  private:
+    std::map<ECbmModuleId, size_t> fMinNumDigis;   ///< Key: detector, value: minimal number of digis
+    std::map<ECbmModuleId, size_t> fMinNumLayers;  ///< Key: detector, value: Minimal number of layers
+  };
+
+
+}  // namespace cbm::algo::evbuild
+
+#endif /* CBM_ALGO_EVBUILD_DIGIEVENTSELECTORCONFIG_H */
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index 3a5f1a6e31..b1a225fec7 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -10,8 +10,8 @@
 
 #include <xpu/host.h>
 
-#include "MainConfig.h"
 #include "config/Yaml.h"
+#include "evbuild/Config.h"
 #include "log.hpp"
 #include "util/TimingsFormat.h"
 #include "util/TsUtils.h"
@@ -60,16 +60,13 @@ void Reco::Init(const Options& opts)
   YAML::Node yaml         = YAML::LoadFile(recoParamsPath.string());
   fContext.recoParams     = config::Read<RecoParams>(yaml);
 
-  // --- Main configuration
-  fs::path configFile = opts.ParamsDir() / "config.yaml";
-  MainConfig config;
-  config.LoadYaml(configFile.string());
-
   // Unpackers
   fUnpack.Init();
 
   // --- Event building
-  fEventBuild.Init(config);
+  fs::path configFile = opts.ParamsDir() / "EventbuildConfig.yaml";
+  evbuild::Config config(YAML::LoadFile(configFile.string()));
+  fEventBuild = std::make_unique<evbuild::EventbuildChain>(config);
 
   // STS Hitfinder
   fs::path stsHitfinderParamsPath    = opts.ParamsDir() / "StsHitfinder.yaml";
@@ -116,7 +113,7 @@ RecoResults Reco::Run(const fles::Timeslice& ts)
 
   // --- Digi event building
   std::vector<CbmDigiEvent> events;
-  if (Opts().HasStep(Step::DigiTrigger)) events = fEventBuild.Run(unpackResult.first);
+  if (Opts().HasStep(Step::DigiTrigger)) events = fEventBuild->Run(unpackResult.first);
 
   sts::HitfinderMonitor stsHitfinderMonitor;
   if (Opts().HasStep(Step::LocalReco) && Opts().HasDetector(fles::Subsystem::STS))
diff --git a/algo/global/Reco.h b/algo/global/Reco.h
index ac41bb2a94..aa5ad55fae 100644
--- a/algo/global/Reco.h
+++ b/algo/global/Reco.h
@@ -47,7 +47,7 @@ namespace cbm::algo
     UnpackChain fUnpack;
     sts::HitfinderChain fStsHitFinder;
 
-    EventbuildChain fEventBuild;
+    std::unique_ptr<evbuild::EventbuildChain> fEventBuild;
 
     void Validate(const Options& opts);
 
diff --git a/algo/params/EventbuildConfig.yaml b/algo/params/EventbuildConfig.yaml
new file mode 100644
index 0000000000..a7267aff92
--- /dev/null
+++ b/algo/params/EventbuildConfig.yaml
@@ -0,0 +1,21 @@
+---
+trigger:
+  detector: TOF
+  window: 80
+  threshold: 8
+  deadtime: 50
+eventbuilder:
+  T0:    [-65, 65]
+  STS:   [-75, 75]
+  MUCH:  [-50, 500]
+  TRD :  [-100, 300]
+  TRd2D: [-100, 350]
+  TOF:   [-10, 70]
+  RICH:  [-20, 120]
+selector:
+  minDigis:
+    T0: 1
+  minLayers:
+    STS: 0
+    TOF: 0
+
diff --git a/algo/params/config.yaml b/algo/params/config.yaml
deleted file mode 100644
index 677b1bf105..0000000000
--- a/algo/params/config.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-trigger:
-  detector: TOF
-  window: 80
-  threshold: 8
-  deadtime: 50
-eventbuilder:
-  windows:
-    T0:    [-65, 65]
-    STS:   [-75, 75]
-    MUCH:  [-50, 500]
-    TRD :  [-100, 300]
-    TRd2D: [-100, 350]
-    TOF:   [-10, 70]
-    RICH:  [-20, 120]
-selector:
-    minStationsSts: 0
-    minStationsTof: 0
-    minDigisBmon: 1
-store:
-  timeslice: false
-  triggers: false
-  events: true
-qa:
-  refreshrate: 100
diff --git a/algo/qa/DigiEventQa.cxx b/algo/qa/DigiEventQa.cxx
index 284b1d8cce..f25dfaac32 100644
--- a/algo/qa/DigiEventQa.cxx
+++ b/algo/qa/DigiEventQa.cxx
@@ -4,29 +4,33 @@
 
 #include "DigiEventQa.h"
 
+#include <iomanip>
+#include <sstream>
+#include <string>
+
 using std::string;
 using std::vector;
 
-namespace cbm::algo::qa
+namespace cbm::algo::evbuild
 {
 
   // ---   Execution   --------------------------------------------------------
-  DigiEventQaData DigiEventQa::operator()(const vector<CbmDigiEvent>& events, const DigiEventQaConfig& config) const
+  DigiEventQaData DigiEventQa::operator()(const vector<CbmDigiEvent>& events) const
   {
 
     // --- Instantiate return object
     DigiEventQaData result;
-    for (const auto& entry : config.fData) {
+    for (const auto& entry : fConfig.fData) {
       ECbmModuleId subsystem = entry.first;
-      string hist_name       = "digi_time_" + ToString(subsystem);
-      auto& detConfig        = config.fData.at(subsystem);
+      string hist_name       = "digi_time_" + ::ToString(subsystem);
+      auto& detConfig        = fConfig.fData.at(subsystem);
       result.fDigiTimeHistos.try_emplace(subsystem, detConfig.fNumBins, detConfig.fMinValue, detConfig.fMaxValue,
                                          hist_name);
     }
 
     // --- Event loop. Fill histograms.
     for (const auto& event : events)
-      for (auto& subsystem : config.fData)
+      for (auto& subsystem : fConfig.fData)
         QaDigiTimeInEvent(event, subsystem.first, result.fDigiTimeHistos.at(subsystem.first));
     result.fNumEvents = events.size();
 
@@ -47,10 +51,26 @@ namespace cbm::algo::qa
       case ECbmModuleId::kTrd2d: FillDeltaT<CbmTrdDigi>(event.fData.fTrd2d.fDigis, event.fTime, histo); break;
       case ECbmModuleId::kTof: FillDeltaT<CbmTofDigi>(event.fData.fTof.fDigis, event.fTime, histo); break;
       case ECbmModuleId::kPsd: FillDeltaT<CbmPsdDigi>(event.fData.fPsd.fDigis, event.fTime, histo); break;
-      default: throw std::runtime_error("DigiEventQa: Invalid system Id " + ToString(system));
+      default: throw std::runtime_error("DigiEventQa: Invalid system Id " + ::ToString(system));
+    }
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----   Info to string   -------------------------------------------------
+  std::string DigiEventQa::ToString() const
+  {
+    std::stringstream out;
+    out << "--- Using DigiEventQa with parameters:";
+    for (const auto& entry : fConfig.fData) {
+      out << "\n   " << std::left << std::setw(5) << ::ToString(entry.first) << ": ";
+      out << "bins" << std::right << std::setw(5) << entry.second.fNumBins;
+      out << "  range [" << std::right << std::setw(5) << entry.second.fMinValue;
+      out << ", " << std::right << std::setw(5) << entry.second.fMaxValue << "] ns";
     }
+    return out.str();
   }
   // --------------------------------------------------------------------------
 
 
-} /* namespace cbm::algo::qa */
+}  // namespace cbm::algo::evbuild
diff --git a/algo/qa/DigiEventQa.h b/algo/qa/DigiEventQa.h
index 1ba0e75e5e..eb58a89471 100644
--- a/algo/qa/DigiEventQa.h
+++ b/algo/qa/DigiEventQa.h
@@ -12,9 +12,10 @@
 #include <vector>
 
 #include "Histo1D.h"
+#include "evbuild/EventBuilderConfig.h"
 
 
-namespace cbm::algo::qa
+namespace cbm::algo::evbuild
 {
 
   /** @struct DigiEventQaData
@@ -60,6 +61,16 @@ namespace cbm::algo::qa
         ss << "\n   Subsystem " << ::ToString(entry.first) << "  " << entry.second.ToString();
       return ss.str();
     }
+    DigiEventQaConfig() = default;
+    DigiEventQaConfig(const EventBuilderConfig& evbuildConfig, double borderSize, uint32_t numBins)
+    {
+      for (const auto& entry : evbuildConfig.fWindows) {
+        auto detector   = entry.first;
+        double tmin     = entry.second.first - borderSize;
+        double tmax     = entry.second.second + borderSize;
+        fData[detector] = {numBins, tmin, tmax};
+      }
+    }
   };
 
 
@@ -71,7 +82,7 @@ namespace cbm::algo::qa
   class DigiEventQa {
   public:
     /** @brief Constructor **/
-    DigiEventQa() = default;
+    DigiEventQa(const DigiEventQaConfig& config) : fConfig(config) {};
 
     /** @brief Destructor **/
     virtual ~DigiEventQa() = default;
@@ -80,10 +91,13 @@ namespace cbm::algo::qa
      ** @param events Vector of DigiEvents to analyse
      ** @return QA data object
      **/
-    DigiEventQaData operator()(const std::vector<CbmDigiEvent>& events, const DigiEventQaConfig& config) const;
+    DigiEventQaData operator()(const std::vector<CbmDigiEvent>& events) const;
+
+    /** @brief Info to string **/
+    std::string ToString() const;
 
 
-  private:
+  private:  // methods
     /** @brief Fill histogram with digi time within event
      ** @param digis  Vector with digi objects
      ** @param eventTime  Time of event
@@ -104,9 +118,13 @@ namespace cbm::algo::qa
      ** @param histo  Histogram to be filled
      **/
     void QaDigiTimeInEvent(const CbmDigiEvent& event, ECbmModuleId system, Histo1D& histo) const;
+
+
+  private:  // members
+    DigiEventQaConfig fConfig;
   };
 
 
-} /* namespace cbm::algo::qa */
+}  // namespace cbm::algo::evbuild
 
 #endif /* ALGO_QA_DIGIEVENTQA_H */
diff --git a/algo/test/_GTestDigiEventSelector.cxx b/algo/test/_GTestDigiEventSelector.cxx
index 375b5f9180..d873199491 100644
--- a/algo/test/_GTestDigiEventSelector.cxx
+++ b/algo/test/_GTestDigiEventSelector.cxx
@@ -6,7 +6,10 @@
 
 #include <unordered_set>
 
+#include <yaml-cpp/yaml.h>
+
 #include "DigiEventSelector.h"
+#include "DigiEventSelectorConfig.h"
 #include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
 
@@ -42,137 +45,175 @@ TEST(_GTestDigiEventSelector, CheckDigiEventSelectorAlgorithmSimple)
   for (size_t i = 0; i < nPsd; i++)
     event.fData.fPsd.fDigis.push_back(CbmPsdDigi());
 
-  // --- Check with created numbers of digis
-  cbm::algo::evbuild::DigiEventSelectorParams filterParPass;
-  filterParPass.fMinNumDigis[ECbmModuleId::kT0]    = nBmon;
-  filterParPass.fMinNumDigis[ECbmModuleId::kSts]   = nSts;
-  filterParPass.fMinNumDigis[ECbmModuleId::kMuch]  = nMuch;
-  filterParPass.fMinNumDigis[ECbmModuleId::kRich]  = nRich;
-  filterParPass.fMinNumDigis[ECbmModuleId::kTrd]   = nTrd;
-  filterParPass.fMinNumDigis[ECbmModuleId::kTrd2d] = nTrd2d;
-  filterParPass.fMinNumDigis[ECbmModuleId::kTof]   = nTof;
-  filterParPass.fMinNumDigis[ECbmModuleId::kPsd]   = nPsd;
-  cbm::algo::evbuild::DigiEventSelector evfilter1a(filterParPass);
-  EXPECT_EQ(evfilter1a(event), true);
-
-  cbm::algo::evbuild::DigiEventSelectorParams filterParFail;
-
-  filterParFail                                 = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kT0] = nBmon + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1b(filterParFail);
-  EXPECT_EQ(evfilter1b(event), false);
-
-  filterParFail                                  = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kSts] = nSts + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1c(filterParFail);
-  EXPECT_EQ(evfilter1c(event), false);
-
-  filterParFail                                   = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kMuch] = nMuch + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1d(filterParFail);
-  EXPECT_EQ(evfilter1d(event), false);
-
-  filterParFail                                   = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kRich] = nRich + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1e(filterParFail);
-  EXPECT_EQ(evfilter1e(event), false);
-
-  filterParFail                                  = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kTrd] = nTrd + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1f(filterParFail);
-  EXPECT_EQ(evfilter1f(event), false);
-
-  filterParFail                                    = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kTrd2d] = nTrd2d + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1g(filterParFail);
-  EXPECT_EQ(evfilter1g(event), false);
-
-  filterParFail                                  = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kTof] = nTof + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1h(filterParFail);
-  EXPECT_EQ(evfilter1h(event), false);
-
-  filterParFail                                  = filterParPass;
-  filterParFail.fMinNumDigis[ECbmModuleId::kPsd] = nPsd + 1;
-  cbm::algo::evbuild::DigiEventSelector evfilter1i(filterParFail);
-  EXPECT_EQ(evfilter1i(event), false);
-
-
-  // --- Test number of STS stations
+
+  YAML::Node node;
+  node["minDigis"][ToString(ECbmModuleId::kT0)]    = nBmon;
+  node["minDigis"][ToString(ECbmModuleId::kSts)]   = nSts;
+  node["minDigis"][ToString(ECbmModuleId::kMuch)]  = nMuch;
+  node["minDigis"][ToString(ECbmModuleId::kRich)]  = nRich;
+  node["minDigis"][ToString(ECbmModuleId::kTrd)]   = nTrd;
+  node["minDigis"][ToString(ECbmModuleId::kTrd2d)] = nTrd2d;
+  node["minDigis"][ToString(ECbmModuleId::kTof)]   = nTof;
+  node["minDigis"][ToString(ECbmModuleId::kPsd)]   = nPsd;
+
   {
-    const uint maxStsStations = 8;
-    const uint maxStsModules  = 12;
-    const uint maxStsLadders  = 4;
+    // --- Check with created numbers of digis - should pass
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), true);
+  }
 
-    for (uint numStations = 1; numStations < maxStsStations; numStations++) {
-      //Prepare input
-      CbmDigiEvent eventIn;
-      //Produce digi pairs with valid addresses
-      for (uint station = 0; station < numStations; station++) {
-        for (uint module = 0; module < maxStsModules; module++) {
-          for (uint ladder = 0; ladder < maxStsLadders; ladder++) {
-            for (uint halfladder = 0; halfladder <= 1; halfladder++) {
-              //add digis pairs
-              int32_t address = CbmStsAddress::GetAddress(station, ladder, halfladder, module);
-              eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(address, 0, 0.0, 0.0));
-              eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(address, 1024, 0.0, 0.0));  //other side channel
-
-              //add digis from next station without partner for intentionally failed test
-              int32_t nextAddress = CbmStsAddress::GetAddress(numStations, ladder, 0, module);
-              eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(nextAddress, 1024, 0.0, 0.0));
-            }
-          }
-        }
-      }
+  {
+    // --- Increment T0 - should fail
+    node["minDigis"][ToString(ECbmModuleId::kT0)] = nBmon + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
+  }
 
-      //Prepare event filter
-      cbm::algo::evbuild::DigiEventSelectorParams filterParams;
-      filterParams.fMinNumLayers[ECbmModuleId::kSts] = numStations;
-      cbm::algo::evbuild::DigiEventSelector evfilter11(filterParams);
+  {
+    // --- Increment STS - should fail
+    node["minDigis"][ToString(ECbmModuleId::kSts)] = nSts + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
+  }
 
-      EXPECT_EQ(evfilter11(eventIn), true);
+  {
+    // --- Increment MUCH - should fail
+    node["minDigis"][ToString(ECbmModuleId::kMuch)] = nMuch + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
+  }
 
-      //Test if digi without partner is properly disregarded
-      filterParams.fMinNumLayers[ECbmModuleId::kSts] = numStations + 1;
-      cbm::algo::evbuild::DigiEventSelector evfilter12(filterParams);
+  {
+    // --- Increment RICH - should fail
+    node["minDigis"][ToString(ECbmModuleId::kRich)] = nRich + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
+  }
 
-      EXPECT_EQ(evfilter12(eventIn), false);
-    }
+  {
+    // --- Increment TRD - should fail
+    node["minDigis"][ToString(ECbmModuleId::kTrd)] = nTrd + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
   }
 
+  {
+    // --- Increment TRD2D - should fail
+    node["minDigis"][ToString(ECbmModuleId::kTrd2d)] = nTrd2d + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
+  }
 
-  // --- Test number of TOF layers
   {
-    //Prepare input
-    CbmDigiEvent eventIn;
+    // --- Increment TOF - should fail
+    node["minDigis"][ToString(ECbmModuleId::kTof)] = nTof + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
+  }
 
-    const uint8_t numSmTypes         = 10;
-    const uint8_t numRpc[numSmTypes] = {5, 3, 5, 1, 1, 1, 2, 2, 1, 2};
-    const uint8_t numSm[numSmTypes]  = {5, 0, 1, 0, 0, 1, 1, 1, 2, 1};
-    std::unordered_set<int32_t> setTofStation;
+  {
+    // --- Increment PSD - should fail
+    node["minDigis"][ToString(ECbmModuleId::kPsd)] = nPsd + 1;
+    cbm::algo::evbuild::DigiEventSelectorConfig config(node);
+    cbm::algo::evbuild::DigiEventSelector select(config);
+    EXPECT_EQ(select(event), false);
+  }
+
+
+  {
+    // --- Test number of STS stations
+    {
+      const uint maxStsStations = 8;
+      const uint maxStsModules  = 12;
+      const uint maxStsLadders  = 4;
+
+      for (uint numStations = 1; numStations < maxStsStations; numStations++) {
+        //Prepare input
+        CbmDigiEvent eventIn;
+        //Produce digi pairs with valid addresses
+        for (uint station = 0; station < numStations; station++) {
+          for (uint module = 0; module < maxStsModules; module++) {
+            for (uint ladder = 0; ladder < maxStsLadders; ladder++) {
+              for (uint halfladder = 0; halfladder <= 1; halfladder++) {
+                //add digis pairs
+                int32_t address = CbmStsAddress::GetAddress(station, ladder, halfladder, module);
+                eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(address, 0, 0.0, 0.0));
+                eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(address, 1024, 0.0, 0.0));  //other side channel
+
+                //add digis from next station without partner for intentionally failed test
+                int32_t nextAddress = CbmStsAddress::GetAddress(numStations, ladder, 0, module);
+                eventIn.fData.fSts.fDigis.push_back(CbmStsDigi(nextAddress, 1024, 0.0, 0.0));
+              }
+            }
+          }
+        }
+
+        YAML::Node node2;
+
+        {  // Test correct number of stations - should pass
+          node2["minLayers"][ToString(ECbmModuleId::kSts)] = numStations;
+          cbm::algo::evbuild::DigiEventSelectorConfig config(node2);
+          cbm::algo::evbuild::DigiEventSelector select(config);
+          EXPECT_EQ(select(eventIn), true);
+        }
 
-    for (uint smType = 0; smType < numSmTypes; smType++) {
-      for (uint sm = 0; sm < numSm[smType]; sm++) {
-        for (uint rpc = 0; rpc < numRpc[smType]; rpc++) {
+        {
+          //  Test if digi without partner is properly disregarded
+          node2["minLayers"][ToString(ECbmModuleId::kSts)] = numStations + 1;
+          cbm::algo::evbuild::DigiEventSelectorConfig config(node2);
+          cbm::algo::evbuild::DigiEventSelector select(config);
+          EXPECT_EQ(select(eventIn), false);
+        }
+      }
+    }
 
-          uint32_t addrFront = CbmTofAddress::GetUniqueAddress(sm, rpc, 0, 0, smType, 0);
-          uint32_t addrBack  = CbmTofAddress::GetUniqueAddress(sm, rpc, 0, 1, smType, 0);
-          eventIn.fData.fTof.fDigis.push_back(CbmTofDigi(addrFront, 0.0, 0.0));
-          eventIn.fData.fTof.fDigis.push_back(CbmTofDigi(addrBack, 0.0, 0.0));
 
-          const int32_t TofStationId = cbm::algo::TofConfig::GetTofTrackingStation(smType, sm, rpc);
-          setTofStation.insert(TofStationId);
+    // --- Test number of TOF layers
+    {
+      //Prepare input
+      CbmDigiEvent eventIn;
+
+      const uint8_t numSmTypes         = 10;
+      const uint8_t numRpc[numSmTypes] = {5, 3, 5, 1, 1, 1, 2, 2, 1, 2};
+      const uint8_t numSm[numSmTypes]  = {5, 0, 1, 0, 0, 1, 1, 1, 2, 1};
+      std::unordered_set<int32_t> setTofStation;
 
-          cbm::algo::evbuild::DigiEventSelectorParams filterParams;
-          filterParams.fMinNumLayers[ECbmModuleId::kTof] = setTofStation.size();
-          cbm::algo::evbuild::DigiEventSelector evfilter21(filterParams);
+      for (uint smType = 0; smType < numSmTypes; smType++) {
+        for (uint sm = 0; sm < numSm[smType]; sm++) {
+          for (uint rpc = 0; rpc < numRpc[smType]; rpc++) {
 
-          EXPECT_EQ(evfilter21(eventIn), true);
+            uint32_t addrFront = CbmTofAddress::GetUniqueAddress(sm, rpc, 0, 0, smType, 0);
+            uint32_t addrBack  = CbmTofAddress::GetUniqueAddress(sm, rpc, 0, 1, smType, 0);
+            eventIn.fData.fTof.fDigis.push_back(CbmTofDigi(addrFront, 0.0, 0.0));
+            eventIn.fData.fTof.fDigis.push_back(CbmTofDigi(addrBack, 0.0, 0.0));
 
-          filterParams.fMinNumLayers[ECbmModuleId::kTof] = setTofStation.size() + 1;
-          cbm::algo::evbuild::DigiEventSelector evfilter22(filterParams);
+            const int32_t TofStationId = cbm::algo::TofConfig::GetTofTrackingStation(smType, sm, rpc);
+            setTofStation.insert(TofStationId);
 
-          EXPECT_EQ(evfilter22(eventIn), false);
+            YAML::Node node2;
+
+            {  // Test actual number of layers -- should pass
+              node2["minLayers"][ToString(ECbmModuleId::kTof)] = setTofStation.size();
+              cbm::algo::evbuild::DigiEventSelectorConfig config(node2);
+              cbm::algo::evbuild::DigiEventSelector select(config);
+              EXPECT_EQ(select(eventIn), true);
+            }
+
+            {  // Test with one more station - should fail
+              node2["minLayers"][ToString(ECbmModuleId::kTof)] = setTofStation.size() + 1;
+              cbm::algo::evbuild::DigiEventSelectorConfig config(node2);
+              cbm::algo::evbuild::DigiEventSelector select(config);
+              EXPECT_EQ(select(eventIn), false);
+            }
+          }
         }
       }
     }
diff --git a/algo/test/_GTestEventBuilder.cxx b/algo/test/_GTestEventBuilder.cxx
index 6227df9cb6..51646ebeb6 100644
--- a/algo/test/_GTestEventBuilder.cxx
+++ b/algo/test/_GTestEventBuilder.cxx
@@ -2,6 +2,8 @@
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Dominik Smith [committer] */
 
+#include <yaml-cpp/yaml.h>
+
 #include "EventBuilder.h"
 #include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
@@ -11,14 +13,16 @@ TEST(_GTestEventBuilder, CheckEventBuilderAlgorithmSimple)
   SCOPED_TRACE("CheckEventBuilderAlgorithSimple");
 
   //Initialize event builder
-  cbm::algo::EventBuilder evbuild;
-  evbuild.SetEventWindow(ECbmModuleId::kMuch, -45.0, 45.0);
-  evbuild.SetEventWindow(ECbmModuleId::kSts, -45.0, 45.0);
-  evbuild.SetEventWindow(ECbmModuleId::kTof, -45.0, 45.0);
-  evbuild.SetEventWindow(ECbmModuleId::kTrd, -45.0, 45.0);
-  evbuild.SetEventWindow(ECbmModuleId::kRich, -45.0, 45.0);
-  evbuild.SetEventWindow(ECbmModuleId::kPsd, -45.0, 45.0);
-  evbuild.SetEventWindow(ECbmModuleId::kT0, -45.0, 45.0);
+  YAML::Node configNode;
+  configNode[ToString(ECbmModuleId::kMuch)] = std::pair<double, double> {-45., 45.};
+  configNode[ToString(ECbmModuleId::kSts)]  = std::pair<double, double> {-45., 45.};
+  configNode[ToString(ECbmModuleId::kTof)]  = std::pair<double, double> {-45., 45.};
+  configNode[ToString(ECbmModuleId::kTrd)]  = std::pair<double, double> {-45., 45.};
+  configNode[ToString(ECbmModuleId::kRich)] = std::pair<double, double> {-45., 45.};
+  configNode[ToString(ECbmModuleId::kPsd)]  = std::pair<double, double> {-45., 45.};
+  configNode[ToString(ECbmModuleId::kT0)]   = std::pair<double, double> {-45., 45.};
+  cbm::algo::evbuild::EventBuilderConfig config(configNode);
+  cbm::algo::evbuild::EventBuilder evbuild(config);
 
   CbmDigiTimeslice tsIn;
   const uint nInput         = 1000;
@@ -45,9 +49,9 @@ TEST(_GTestEventBuilder, CheckEventBuilderAlgorithmSimple)
     triggerIn.push_back(i * triggerSpacing);
   }
 
-  cbm::algo::EventBuilder::resultType result  = evbuild(tsIn, triggerIn);
-  std::vector<CbmDigiEvent>& eventsOut        = result.first;
-  cbm::algo::EventBuilderMonitorData& monitor = result.second;
+  cbm::algo::evbuild::EventBuilder::resultType result  = evbuild(tsIn, triggerIn);
+  std::vector<CbmDigiEvent>& eventsOut                 = result.first;
+  cbm::algo::evbuild::EventBuilderMonitorData& monitor = result.second;
 
   EXPECT_EQ(eventsOut.size(), nTrigger);
 
diff --git a/algo/test/_GTestTimeClusterTrigger.cxx b/algo/test/_GTestTimeClusterTrigger.cxx
index 35e8891a98..f2932774ab 100644
--- a/algo/test/_GTestTimeClusterTrigger.cxx
+++ b/algo/test/_GTestTimeClusterTrigger.cxx
@@ -7,26 +7,29 @@
 #include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
 
+using namespace cbm::algo::evbuild;
+
 TEST(_GTestTimeClusterTrigger, CheckTriggerAlgorithmSimple)
 {
   SCOPED_TRACE("CheckTriggerAlgorithSimple");
 
-  cbm::algo::TimeClusterTrigger trigger;
-  std::vector<double> dataIn;
-
   const uint nInput         = 1000.;
   const double inputSpacing = 10.0;
   const double deadTime     = 5.;
   const double windowSize   = 1000.;
   const uint nMinNumber     = 100;
 
+  DigiTriggerConfig config = {ECbmModuleId::kSts, windowSize, nMinNumber, deadTime};
+  TimeClusterTrigger trigger(config);
+
+  std::vector<double> dataIn;
   for (uint i = 0; i < nInput; i++) {
     dataIn.push_back(i * inputSpacing);
   }
 
-  cbm::algo::TimeClusterTrigger::resultType result  = trigger(dataIn, windowSize, nMinNumber, deadTime);
-  std::vector<double>& dataOut                      = result.first;
-  cbm::algo::TimeClusterTriggerMonitorData& monitor = result.second;
+  TimeClusterTrigger::resultType result  = trigger(dataIn);
+  std::vector<double>& dataOut           = result.first;
+  TimeClusterTriggerMonitorData& monitor = result.second;
 
   EXPECT_EQ(dataOut.size(), 10);
 
diff --git a/algo/trigger/DigiTriggerConfig.cxx b/algo/trigger/DigiTriggerConfig.cxx
new file mode 100644
index 0000000000..9fbc2ed1f0
--- /dev/null
+++ b/algo/trigger/DigiTriggerConfig.cxx
@@ -0,0 +1,48 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#include "DigiTriggerConfig.h"
+
+
+namespace cbm::algo::evbuild
+{
+
+  // -----   Constructor from YAML   ------------------------------------------
+  DigiTriggerConfig::DigiTriggerConfig(YAML::Node config)
+  {
+    if (!config) throw std::runtime_error("no configuration node for DigiTrigger");
+
+    auto detector = config["detector"];
+    if (!detector) throw std::runtime_error("trigger detector is not specified");
+    fDetector = ToCbmModuleIdCaseInsensitive(detector.as<std::string>());
+
+    auto window = config["window"];
+    if (!window) throw std::runtime_error("trigger window is not specified");
+    fWindow = window.as<double>();
+
+    auto threshold = config["threshold"];
+    if (!threshold) throw std::runtime_error("trigger threshold is not specified");
+    fThreshold = threshold.as<size_t>();
+
+    auto deadTime = config["deadtime"];
+    if (!deadTime) throw std::runtime_error("trigger dead time is not specified");
+    fDeadTime = deadTime.as<double>();
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----   Save to YAML   ---------------------------------------------------
+  YAML::Node DigiTriggerConfig::ToYaml() const
+  {
+    YAML::Node result;
+    result["detector"]  = ToString(fDetector);
+    result["window"]    = fWindow;
+    result["threshold"] = fThreshold;
+    result["deadtime"]  = fDeadTime;
+    return result;
+  }
+  // --------------------------------------------------------------------------
+
+
+}  // namespace cbm::algo::evbuild
diff --git a/algo/trigger/DigiTriggerConfig.h b/algo/trigger/DigiTriggerConfig.h
new file mode 100644
index 0000000000..a52008e725
--- /dev/null
+++ b/algo/trigger/DigiTriggerConfig.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#ifndef CBM_ALGO_EVBUILD_DIGITRIGGERCONFIG_H
+#define CBM_ALGO_EVBUILD_DIGITRIGGERCONFIG_H 1
+
+#include "CbmDefs.h"
+
+#include <map>
+
+#include <yaml-cpp/yaml.h>
+
+
+namespace cbm::algo::evbuild
+{
+
+  /** @class DigiTriggerConfig
+   ** @brief Configuration of the digi trigger class (TimeClusterTrigger)
+   ** @author Volker Friese <v.friese@gsi.de>
+   ** @since 21.11.2021
+   **/
+  class DigiTriggerConfig {
+
+  public:
+    /** @brief Constructor with parameters
+     ** @param detector  Detector to be used for triggering
+     ** @param window    Time interval to look for clusters in [ns]
+     ** @param threshold Minimal required number of data within the time window
+     ** @param deadTime  Minimal time between two subsequent triggers
+     **/
+    DigiTriggerConfig(ECbmModuleId detector, double window, size_t threshold, double deadTime)
+      : fDetector(detector)
+      , fWindow(window)
+      , fThreshold(threshold)
+      , fDeadTime(deadTime)
+    {
+    }
+
+    /** @brief Constructor from YAML **/
+    DigiTriggerConfig(YAML::Node config);
+
+    /** @brief Destructor **/
+    ~DigiTriggerConfig() = default;
+
+    /** @brief Trigger dead time **/
+    double DeadTime() const { return fDeadTime; }
+
+    /** @brief Trigger detector **/
+    ECbmModuleId Detector() const { return fDetector; }
+
+    /** @brief Trigger threshold **/
+    size_t Threshold() const { return fThreshold; }
+
+    /** @brief Save to YAML **/
+    YAML::Node ToYaml() const;
+
+    /** @brief Trigger window **/
+    double Window() const { return fWindow; }
+
+
+  private:
+    ECbmModuleId fDetector;  ///< Trigger detector
+    double fWindow;          ///< Trigger window size [ns]
+    size_t fThreshold;       ///< Minimum number if digis in trigger window
+    double fDeadTime;        ///< Minimal time between two trigger [ns]
+  };
+
+
+}  // namespace cbm::algo::evbuild
+
+#endif /* CBM_ALGO_EVBUILD_DIGITRIGGERCONFIG_H */
diff --git a/algo/trigger/TimeClusterTrigger.cxx b/algo/trigger/TimeClusterTrigger.cxx
index fe21815e2d..6cf6a87b8d 100644
--- a/algo/trigger/TimeClusterTrigger.cxx
+++ b/algo/trigger/TimeClusterTrigger.cxx
@@ -7,17 +7,25 @@
 #include <algorithm>
 #include <cassert>
 #include <iterator>
+#include <sstream>
 #include <vector>
 
+using std::string;
+using std::stringstream;
 using std::vector;
 
-namespace cbm::algo
+namespace cbm::algo::evbuild
 {
 
-  TimeClusterTrigger::resultType TimeClusterTrigger::operator()(const vector<double>& dataVec, double winSize,
-                                                                int32_t minNumData, double deadTime) const
+  TimeClusterTrigger::resultType TimeClusterTrigger::operator()(const vector<double>& dataVec) const
   {
-    assert(std::is_sorted(dataVec.begin(), dataVec.end()));
+
+    if (!std::is_sorted(dataVec.begin(), dataVec.end())) throw std::runtime_error("TimeClusterTrigger: unsorted input");
+
+    // --- Parameters
+    double winSize     = fConfig.Window();
+    int32_t minNumData = fConfig.Threshold();
+    double deadTime    = fConfig.DeadTime();
 
     // --- Output data
     resultType result                      = {};
@@ -57,4 +65,14 @@ namespace cbm::algo
     return result;
   }
 
-}  // namespace cbm::algo
+
+  string TimeClusterTrigger::ToString() const
+  {
+    stringstream out;
+    out << "--- Using TimeClusterTrigger with trigger window " << fConfig.Window() << " ns";
+    out << ", threshold " << fConfig.Threshold();
+    out << ", dead time " << fConfig.DeadTime() << " ns";
+    return out.str();
+  }
+
+}  // namespace cbm::algo::evbuild
diff --git a/algo/trigger/TimeClusterTrigger.h b/algo/trigger/TimeClusterTrigger.h
index 0ad85df3ee..ce8eec7098 100644
--- a/algo/trigger/TimeClusterTrigger.h
+++ b/algo/trigger/TimeClusterTrigger.h
@@ -9,7 +9,9 @@
 #include <cstdint>
 #include <vector>
 
-namespace cbm::algo
+#include "DigiTriggerConfig.h"
+
+namespace cbm::algo::evbuild
 {
 
   /** @struct TimeClusterTriggerMonitorData
@@ -25,7 +27,7 @@ namespace cbm::algo
   /** @class TimeClusterTrigger
    ** @author Volker Friese <v.friese@gsi.de>
    ** @author Dominik Smith <d.smith@gsi.de>
-   ** @since 2021
+   ** @since 21.11.2021
    ** @brief Finds clusters in time-series data
    **
    ** A trigger is generated when the number density of data exceeds a given threshold. Each datum
@@ -38,6 +40,9 @@ namespace cbm::algo
   public:
     typedef std::pair<std::vector<double>, TimeClusterTriggerMonitorData> resultType;
 
+    /** @brief Constructor **/
+    TimeClusterTrigger(const DigiTriggerConfig& config) : fConfig(config) {}
+
     /** @brief Execution
      ** @param  dataVec     Source data vector
      ** @param  winSize     Size of trigger window
@@ -45,11 +50,17 @@ namespace cbm::algo
      ** @param  deadTime    Minimum time between two triggers
      ** @return Vector of trigger times and monitoring data
      **/
-    resultType operator()(const std::vector<double>& dataVec, double winSize, int32_t minNumData,
-                          double deadTime) const;
+    resultType operator()(const std::vector<double>& dataVec) const;
+
+    /** @brief Info to string **/
+    std::string ToString() const;
+
+
+  private:
+    DigiTriggerConfig fConfig;
   };
 
 
-}  // namespace cbm::algo
+}  // namespace cbm::algo::evbuild
 
 #endif /* CBM_ALGO_TIMECLUSTERTRIGGER_H */
diff --git a/macro/reco/CMakeLists.txt b/macro/reco/CMakeLists.txt
index 0ae6e5c100..08a67b050f 100644
--- a/macro/reco/CMakeLists.txt
+++ b/macro/reco/CMakeLists.txt
@@ -139,8 +139,9 @@ foreach(setup IN LISTS cbm_setup)
   # --- Test reco_reco_sim
   # --- Reconstruction from time-based simulation
   set(testname reco_reco_sim_${sname})
+  set(configfile ${VMCWORKDIR}/macro/reco/reco_config.yaml)
   add_test(${testname} ${MACRODIR}/reco_fairroot.sh
-  	\"${datadir}/${sname}.raw.root\" \"${datadir}/${sname}.reco.root\")
+  	\"${datadir}/${sname}.raw.root\" \"${configfile}\" \"${datadir}/${sname}.reco.root\")
   set_tests_properties(${testname} PROPERTIES
   	TIMEOUT ${timeOutTime}
 	FAIL_REGULAR_EXPRESSION	"segmentation violation"
diff --git a/macro/reco/reco_config.yaml b/macro/reco/reco_config.yaml
new file mode 100644
index 0000000000..0e0860758d
--- /dev/null
+++ b/macro/reco/reco_config.yaml
@@ -0,0 +1,17 @@
+trigger:
+  detector: STS
+  window: 10
+  threshold: 100
+  deadtime: 50
+eventbuilder:
+  T0:    [-20, 30]
+  STS:   [-20, 30]
+  MUCH:  [-20, 30]
+  TRD :  [-20, 30]
+  TRd2D: [-20, 30]
+  TOF:   [-20, 30]
+  RICH:  [-20, 30]
+selector:
+  minDigis:
+    T0: 1
+
diff --git a/macro/reco/reco_fairroot.C b/macro/reco/reco_fairroot.C
index b693b3a18c..a234228a34 100644
--- a/macro/reco/reco_fairroot.C
+++ b/macro/reco/reco_fairroot.C
@@ -11,6 +11,8 @@
 #include <TSystem.h>
 
 #include <iostream>
+
+#include "algo/evbuild/Config.h"
 #endif
 
 #include <FairLogger.h>
@@ -35,12 +37,10 @@ using std::string;
  ** If the input file name is left empty, a default file from the repository will be used.
  **/
 
-void reco_fairroot(TString tsaFile, TString outFile, int32_t numTs = std::numeric_limits<int32_t>::max(),
-                   uint16_t port = 0)
+void reco_fairroot(TString tsaFile, TString configFile, TString outFile,
+                   int32_t numTs = std::numeric_limits<int32_t>::max(), uint16_t port = 0)
 {
 
-  // ========================================================================
-  //          Adjust this part according to your requirements
 
   // --- Logger settings ----------------------------------------------------
   TString logLevel     = "INFO";
@@ -48,49 +48,21 @@ void reco_fairroot(TString tsaFile, TString outFile, int32_t numTs = std::numeri
   // ------------------------------------------------------------------------
 
 
-  // --- Configuration  -----------------------------------------------------
-  // Digi trigger
-  cbm::algo::MainConfig config;
-  config.fTriggerDet       = ECbmModuleId::kSts;  // trigger detector
-  config.fTriggerWin       = 10.;                 // trigger window in [ns]
-  config.fTriggerThreshold = 100;                 // trigger threshold in number of digis
-  config.fTriggerDeadTime  = 50.;                 // trigger dead time [ns]
-
-  // Event builder
-  config.fEvtbuildWindows[ECbmModuleId::kSts] = std::make_pair(-20., 30.);  // Event window for STS
-
-  // Branch persistence
-  config.fStoreTimeslice = false;  /// Store branch DigiTimeSlice
-  config.fStoreTrigger   = false;  /// Store branch Trigger
-  config.fStoreEvents    = true;   /// Store branch DigiEvent
-  // ------------------------------------------------------------------------
-
-
+  // -----   Logger settings   ----------------------------------------------
+  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
+  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
   // ------------------------------------------------------------------------
-  // In general, the following parts need not be touched
-  // ========================================================================
 
 
   // -----   Environment   --------------------------------------------------
-  TString myName = "reco_fairoot";                 // this macro's name for screen output
-  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
-  // ------------------------------------------------------------------------
-
-  // Tested with file 1588_node8_1_0000.tsa
-  // TODO: Would need a small up-to-date default input file; the one distributed with
-  // the code is outdated.
-
-
-  // -----   Logger settings   ----------------------------------------------
-  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
-  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
+  TString myName = "reco_fairoot";  // this macro's name for screen output
   // ------------------------------------------------------------------------
 
 
   // -----   Run reconstruction   -------------------------------------------
   TStopwatch timer;
   timer.Start();
-  CbmReco run(tsaFile.Data(), outFile.Data(), numTs, config, port);
+  CbmReco run(tsaFile.Data(), outFile.Data(), configFile.Data(), numTs, port);
   run.Run();
   timer.Stop();
   // ------------------------------------------------------------------------
diff --git a/reco/CMakeLists.txt b/reco/CMakeLists.txt
index 6bcd5fd587..a15721ac5d 100644
--- a/reco/CMakeLists.txt
+++ b/reco/CMakeLists.txt
@@ -14,7 +14,7 @@ add_subdirectory(global)
 add_subdirectory(KF)
 add_subdirectory(L1)
 add_subdirectory(littrack)
-add_subdirectory(mq)
+# add_subdirectory(mq)
 add_subdirectory(offline)
 add_subdirectory(qa)
 add_subdirectory(steer)
diff --git a/reco/app/cbmreco_fairrun/Application.cxx b/reco/app/cbmreco_fairrun/Application.cxx
index 9979a9a10b..e58543c8aa 100644
--- a/reco/app/cbmreco_fairrun/Application.cxx
+++ b/reco/app/cbmreco_fairrun/Application.cxx
@@ -5,8 +5,11 @@
 #include "Application.h"
 
 #include <chrono>
+#include <fstream>
 #include <thread>
 
+#include <yaml-cpp/yaml.h>
+
 #include "MainConfig.h"
 
 Application::Application(ProgramOptions const& opt) : fOpt(opt)
@@ -14,11 +17,13 @@ Application::Application(ProgramOptions const& opt) : fOpt(opt)
   // start up monitoring
   if (!fOpt.MonitorUri().empty()) { fMonitor = std::make_unique<cbm::Monitor>(fOpt.MonitorUri()); }
 
-  cbm::algo::MainConfig config;
-  config.LoadYaml(fOpt.ConfigYamlFile());
-  if (!fOpt.SaveConfigYamlFile().empty()) { config.SaveYaml(fOpt.SaveConfigYamlFile()); }
+  cbm::algo::evbuild::Config config(YAML::LoadFile(fOpt.ConfigYamlFile()));
+  if (!fOpt.SaveConfigYamlFile().empty()) {
+    std::ofstream fout(fOpt.SaveConfigYamlFile());
+    fout << config.ToYaml();
+  }
 
-  fCbmReco = std::make_unique<CbmReco>(fOpt.InputUri(), fOpt.OutputRootFile(), fOpt.MaxNumTs(), config,
+  fCbmReco = std::make_unique<CbmReco>(fOpt.InputUri(), fOpt.OutputRootFile(), fOpt.ConfigYamlFile(), fOpt.MaxNumTs(),
                                        fOpt.HttpServerPort(), fMonitor.get());
 }
 
diff --git a/reco/mq/CbmDevBuildEvents.cxx b/reco/mq/CbmDevBuildEvents.cxx
index 08f6f4f757..577ba917f2 100644
--- a/reco/mq/CbmDevBuildEvents.cxx
+++ b/reco/mq/CbmDevBuildEvents.cxx
@@ -16,6 +16,7 @@
 
 #include "BoostSerializer.h"
 
+#include "EventBuilderConfig.h"
 #include "RootSerializer.h"
 
 /// FAIRSOFT headers (geant, boost, ...)
@@ -125,8 +126,8 @@ try {
     /// Window end
     charPosDel++;
     double dWinEnd = std::stod(sNext.substr(charPosDel));
-
-    fEvbuildAlgo.SetEventWindow(selDet, dWinBeg, dWinEnd);
+    cbm::algo::evbuild::EventBuilderConfig config;
+    fEvbuildAlgo = std::make_unique<cbm::algo::evbuild::EventBuilder>(config);
   }
 }
 catch (InitTaskError& e) {
@@ -219,7 +220,7 @@ bool CbmDevBuildEvents::HandleData(FairMQParts& parts, int /*index*/)
   LOG(debug) << "triggers: " << triggers.size();
 
   /// Create events
-  std::vector<CbmDigiEvent> vEvents = fEvbuildAlgo(ts, triggers).first;
+  std::vector<CbmDigiEvent> vEvents = (*fEvbuildAlgo)(ts, triggers).first;
   LOG(debug) << "vEvents size: " << vEvents.size();
 
   /// Send output message
diff --git a/reco/mq/CbmDevBuildEvents.h b/reco/mq/CbmDevBuildEvents.h
index 7b4a52a4f5..18a8660996 100644
--- a/reco/mq/CbmDevBuildEvents.h
+++ b/reco/mq/CbmDevBuildEvents.h
@@ -56,7 +56,7 @@ private:
   //  uint64_t fulTsCounter   = 0;
 
   /// Processing algos
-  cbm::algo::EventBuilder fEvbuildAlgo;
+  std::unique_ptr<cbm::algo::evbuild::EventBuilder> fEvbuildAlgo;
 
   /// Data storage
   std::string fsOutputFileName             = "";
diff --git a/reco/mq/CbmDevTrigger.cxx b/reco/mq/CbmDevTrigger.cxx
index 04acb3914e..f24e6a797d 100644
--- a/reco/mq/CbmDevTrigger.cxx
+++ b/reco/mq/CbmDevTrigger.cxx
@@ -148,7 +148,7 @@ std::vector<double> CbmDevTrigger::GetTriggerTimes(const CbmDigiTimeslice& ts)
     default: LOG(fatal) << "CbmDevTrigger::GetTriggerTimes(): Reading digis from unknown detector type!";
   }
   LOG(debug) << "CbmDevTrigger::GetTriggerTimes(): Building triggers from " << vDigiTimes.size() << " digis.";
-  return fTriggerAlgo(vDigiTimes, fTriggerWindow, fMinNumDigis, fDeadTime).first;
+  return (*fTriggerAlgo)(vDigiTimes).first;
 }
 
 bool CbmDevTrigger::SendTriggers(const std::vector<double>& vTriggers, FairMQParts& partsIn)
diff --git a/reco/mq/CbmDevTrigger.h b/reco/mq/CbmDevTrigger.h
index 5ab19fdf16..b5743194ce 100644
--- a/reco/mq/CbmDevTrigger.h
+++ b/reco/mq/CbmDevTrigger.h
@@ -54,7 +54,7 @@ private:
   uint64_t fNumMessages = 0;
 
   /// Processing algos
-  cbm::algo::TimeClusterTrigger fTriggerAlgo;
+  std::unique_ptr<cbm::algo::evbuild::TimeClusterTrigger> fTriggerAlgo;
 
   // Trigger algorithm params
   double fTriggerWindow = 0.;
diff --git a/reco/tasks/CbmReco.cxx b/reco/tasks/CbmReco.cxx
index 7b68270a69..3045c23c93 100644
--- a/reco/tasks/CbmReco.cxx
+++ b/reco/tasks/CbmReco.cxx
@@ -23,19 +23,21 @@
 #include <memory>
 #include <string>
 
+#include <yaml-cpp/yaml.h>
+
 #include "DigiEventSelector.h"
+#include "DigiEventSelectorConfig.h"
 
 using std::make_unique;
 using std::string;
 
 
 // -----   Constructor from single source   -----------------------------------
-CbmReco::CbmReco(string source, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config, uint16_t port,
-                 cbm::Monitor* monitor)
+CbmReco::CbmReco(string source, string outFile, string configFile, int32_t numTs, uint16_t port, cbm::Monitor* monitor)
   : fSourceNames {source}
   , fOutputFileName(outFile)
+  , fConfigFileName(configFile)
   , fNumTs(numTs)
-  , fConfig(config)
   , fHttpServerPort(port)
   , fMonitor(monitor)
 {
@@ -44,12 +46,12 @@ CbmReco::CbmReco(string source, TString outFile, int32_t numTs, const cbm::algo:
 
 
 // -----   Constructor from multiple sources   --------------------------------
-CbmReco::CbmReco(std::vector<string> sources, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config,
-                 uint16_t port, cbm::Monitor* monitor)
+CbmReco::CbmReco(std::vector<string> sources, string outFile, string configFile, int32_t numTs, uint16_t port,
+                 cbm::Monitor* monitor)
   : fSourceNames(sources)
   , fOutputFileName(outFile)
+  , fConfigFileName(configFile)
   , fNumTs(numTs)
-  , fConfig(config)
   , fHttpServerPort(port)
   , fMonitor(monitor)
 {
@@ -106,10 +108,10 @@ int32_t CbmReco::Run()
   }
 
   // --- Output file
-  auto sink = make_unique<FairRootFileSink>(fOutputFileName.Data());
-  if (sink) LOG(info) << "Reco: Using output file " << fOutputFileName.Data();
+  auto sink = make_unique<FairRootFileSink>(fOutputFileName);
+  if (sink) LOG(info) << "Reco: Using output file " << fOutputFileName;
   else {
-    LOG(error) << "Reco: Could not open output " << fOutputFileName.Data() << "; aborting.";
+    LOG(error) << "Reco: Could not open output " << fOutputFileName << "; aborting.";
     return -1;
   }
   run.SetSink(sink.release());
@@ -122,39 +124,38 @@ int32_t CbmReco::Run()
   if (!isRootInput) {
     auto unpack = make_unique<CbmTaskUnpack>();
     unpack->SetMonitor(fMonitor);
-    unpack->SetOutputBranchPersistent("DigiTimeslice.", fConfig.fStoreTimeslice);
+    unpack->SetOutputBranchPersistent("DigiTimeslice.", false);
     run.AddTask(unpack.release());
   }
 
+  // --- Event building configuration
+  cbm::algo::evbuild::Config evbuildConfig(YAML::LoadFile(fConfigFileName));
+
   // --- Digi trigger
   auto trigger = make_unique<CbmTaskTriggerDigi>();
-  trigger->AddSystem(fConfig.fTriggerDet);
-  trigger->SetAlgoParams(fConfig.fTriggerWin, fConfig.fTriggerThreshold, fConfig.fTriggerDeadTime);
-  trigger->SetOutputBranchPersistent("Trigger", fConfig.fStoreTrigger);
+  trigger->AddSystem(evbuildConfig.fTrigger.Detector());
+  trigger->SetConfig(evbuildConfig.fTrigger);
+  trigger->SetOutputBranchPersistent("Trigger", false);
   run.AddTask(trigger.release());
 
   // --- Event selector parameters
-  cbm::algo::evbuild::DigiEventSelectorParams selectPar;
-  selectPar.fMinNumDigis[ECbmModuleId::kT0]   = fConfig.fSelectMinDigisBmon;
-  selectPar.fMinNumLayers[ECbmModuleId::kSts] = fConfig.fSelectMinStationsSts;
-  selectPar.fMinNumLayers[ECbmModuleId::kTof] = fConfig.fSelectMinStationsTof;
+  cbm::algo::evbuild::DigiEventSelectorConfig selectConfig = evbuildConfig.fSelector;
 
   // --- Event building
   auto evtBuild = make_unique<CbmTaskBuildEvents>();
-  for (auto& entry : fConfig.fEvtbuildWindows)
-    evtBuild->SetEventWindow(entry.first, entry.second.first, entry.second.second);
-  evtBuild->SetOutputBranchPersistent("DigiEvent", fConfig.fStoreEvents);
-  evtBuild->SetDigiEventSelector(selectPar);
+  evtBuild->SetConfig(evbuildConfig.fBuilder);
+  evtBuild->SetOutputBranchPersistent("DigiEvent", true);
+  evtBuild->SetDigiEventSelector(selectConfig);
   run.AddTask(evtBuild.release());
 
   // --- Event QA
   auto evtQa = make_unique<CbmTaskDigiEventQa>();
-  evtQa->Config(fConfig);
+  evtQa->Config(evbuildConfig);
   run.AddTask(evtQa.release());
 
   // ----- HttpServer for online monitoring
   if (fHttpServerPort) {
-    run.ActivateHttpServer(fConfig.fHttpServerRefreshRate, fHttpServerPort);
+    run.ActivateHttpServer(100, fHttpServerPort);
     run.GetHttpServer()->GetSniffer()->SetScanGlobalDir(kFALSE);
   }
 
diff --git a/reco/tasks/CbmReco.h b/reco/tasks/CbmReco.h
index 112095846d..77d11ab08e 100644
--- a/reco/tasks/CbmReco.h
+++ b/reco/tasks/CbmReco.h
@@ -25,7 +25,7 @@ namespace cbm
 #include <string>
 #include <utility>
 
-#include "MainConfig.h"
+#include "evbuild/Config.h"
 
 
 /** @class CbmReco
@@ -45,7 +45,7 @@ class CbmReco {
 
 public:
   /** @brief Default constructor **/
-  CbmReco() {};
+  //CbmReco() {};
 
 
   /** @brief Standard constructor for a single source
@@ -55,8 +55,8 @@ public:
    ** @param config  Configuration
    ** @param port    Port number for the http server. If 0, server will not be activated.
    **/
-  CbmReco(std::string source, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config, uint16_t port = 0,
-          cbm::Monitor* monitor = nullptr);
+  CbmReco(std::string source, std::string outFile, std::string configFile,
+          int32_t numTs = std::numeric_limits<int32_t>::max(), uint16_t port = 0, cbm::Monitor* monitor = nullptr);
 
 
   /** @brief Standard constructor for list of sources
@@ -66,8 +66,8 @@ public:
    ** @param config  Configuration
    ** @param port    Port number for the http server
    **/
-  CbmReco(std::vector<std::string> sources, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config,
-          uint16_t port = 0, cbm::Monitor* monitor = nullptr);
+  CbmReco(std::vector<std::string> sources, std::string outFile, std::string configFile,
+          int32_t numTs = std::numeric_limits<int32_t>::max(), uint16_t port = 0, cbm::Monitor* monitor = nullptr);
 
 
   /** @brief Destructor **/
@@ -88,9 +88,9 @@ public:
 
 private:
   std::vector<std::string> fSourceNames = {};  ///< Sources (input files or stream)
-  TString fOutputFileName               = "";  ///< Output file
+  std::string fOutputFileName           = "";  ///< Output file (ROOT)
+  std::string fConfigFileName           = "";  ///< Configuration file (YAML)
   int32_t fNumTs                        = 0;   ///< Number of timeslices to process
-  cbm::algo::MainConfig fConfig         = {};  ///< Configuration
   uint16_t fHttpServerPort              = 0;
   cbm::Monitor* fMonitor                = nullptr;
 
diff --git a/reco/tasks/CbmTaskBuildEvents.cxx b/reco/tasks/CbmTaskBuildEvents.cxx
index 8312e9f83a..301d72d8f6 100644
--- a/reco/tasks/CbmTaskBuildEvents.cxx
+++ b/reco/tasks/CbmTaskBuildEvents.cxx
@@ -35,9 +35,10 @@ CbmTaskBuildEvents::~CbmTaskBuildEvents()
 CbmDigiTimeslice CbmTaskBuildEvents::FillTimeSlice()
 {
   CbmDigiTimeslice ts;
-  for (const auto& entry : fEventWindows) {
+  for (const auto& entry : fConfig->fWindows) {
     auto system                   = entry.first;
     CbmDigiBranchBase* digiBranch = fDigiMan->GetBranch(system);
+    if (digiBranch == nullptr) continue;
     switch (system) {
       case ECbmModuleId::kSts: {
         const vector<CbmStsDigi>* digiVec =
@@ -120,10 +121,10 @@ void CbmTaskBuildEvents::Exec(Option_t*)
   // --- If the input is already CbmDigiTimeslice (from unpacking), use that directly
   if (fTimeslice) {
     timerStep.Start();
-    *fEvents = fAlgo(*fTimeslice, *fTriggers).first;
+    *fEvents = (*fAlgo)(*fTimeslice, *fTriggers).first;
     timerStep.Stop();
     fTimeBuildEvt += timerStep.RealTime();
-    for (const auto& entry : fEventWindows)
+    for (const auto& entry : fConfig->fWindows)
       numDigisTs[entry.first] = GetNumDigis(fTimeslice->fData, entry.first);
   }
 
@@ -131,12 +132,12 @@ void CbmTaskBuildEvents::Exec(Option_t*)
   else {
     timerStep.Start();
     CbmDigiTimeslice ts = FillTimeSlice();
-    for (const auto& entry : fEventWindows)
-      numDigisTs[entry.first] = GetNumDigis(ts.fData, entry.first);
+    for (const auto& entry : fConfig->fWindows)
+      numDigisTs[entry.first] = ts.fData.Size(entry.first);
     timerStep.Stop();
     fTimeFillTs += timerStep.RealTime();
     timerStep.Start();
-    *fEvents = fAlgo(ts, *fTriggers).first;
+    *fEvents = (*fAlgo)(ts, *fTriggers).first;
     timerStep.Stop();
     fTimeBuildEvt += timerStep.RealTime();
   }
@@ -154,7 +155,7 @@ void CbmTaskBuildEvents::Exec(Option_t*)
   // --- Timeslice statistics
   size_t numTriggers = fTriggers->size();
   size_t numEvents   = fEvents->size();
-  for (const auto& entry : fEventWindows) {
+  for (const auto& entry : fConfig->fWindows) {
     for (auto& event : (*fEvents)) {
       numDigisEv[entry.first] += GetNumDigis(event.fData, entry.first);
     }
@@ -168,7 +169,7 @@ void CbmTaskBuildEvents::Exec(Option_t*)
   logOut << fixed << setw(8) << setprecision(1) << right << timerTot.RealTime() * 1000. << " ms] ";
   logOut << "TS " << fNumTs << ", triggers " << numTriggers << ", events " << numEvents;
 
-  for (const auto& entry : fEventWindows) {
+  for (const auto& entry : fConfig->fWindows) {
     auto system = entry.first;
     logOut << ", frac " << ToString(system) << " digis "
            << 100. * double(numDigisEv[system]) / double(numDigisTs[system]) << " %";
@@ -181,7 +182,7 @@ void CbmTaskBuildEvents::Exec(Option_t*)
   fNumTriggers += numTriggers;
   fNumEvents += numEvents;
 
-  for (const auto& entry : fEventWindows) {
+  for (const auto& entry : fConfig->fWindows) {
     auto system = entry.first;
     fNumDigisTs[system] += numDigisTs[system];
     fNumDigisEv[system] += numDigisEv[system];
@@ -198,7 +199,7 @@ void CbmTaskBuildEvents::Finish()
   LOG(info) << "Timeslices           : " << fNumTs;
   LOG(info) << "Triggers             : " << fNumTriggers;
   LOG(info) << "Events               : " << fNumEvents;
-  for (const auto& entry : fEventWindows) {
+  for (const auto& entry : fConfig->fWindows) {
     auto system = entry.first;
     LOG(info) << setw(4) << left << ToString(system) << " digis in TS     : " << fNumDigisTs[system];
     LOG(info) << setw(4) << left << ToString(system) << " digis in events : " << fNumDigisEv[system] << " = " << fixed
@@ -254,18 +255,15 @@ InitStatus CbmTaskBuildEvents::Init()
   else {
     fDigiMan = CbmDigiManager::Instance();
     fDigiMan->Init();
-    for (const auto& entry : fEventWindows) {
+    for (const auto& entry : fConfig->fWindows) {
       auto system = entry.first;
-      if (!fDigiMan->IsPresent(system)) {
-        LOG(fatal) << GetName() << ": No digi branch for " << ToString(system);
-        return kFATAL;
-      }
+      if (!fDigiMan->IsPresent(system)) { LOG(warn) << GetName() << ": No digi branch for " << ToString(system); }
       LOG(info) << "--- Found digi branch for " << ToString(system);
     }
   }
 
   // --- Initialize diagnostics
-  for (const auto& entry : fEventWindows) {
+  for (const auto& entry : fConfig->fWindows) {
     auto system         = entry.first;
     fNumDigisTs[system] = 0;
     fNumDigisEv[system] = 0;
@@ -293,14 +291,13 @@ InitStatus CbmTaskBuildEvents::Init()
   LOG(info) << "--- Registered branch DigiEvent";
 
   // --- Configure algorithm
-  for (const auto& entry : fEventWindows) {
-    auto system       = entry.first;
-    const double tMin = entry.second.first;
-    const double tMax = entry.second.second;
-    fAlgo.SetEventWindow(system, tMin, tMax);
-    LOG(info) << "--- Use algo EventBuilder with event window [" << tMin << ", " << tMax << "] ns for "
-              << ToString(system);
-  }
+  fAlgo.reset(new cbm::algo::evbuild::EventBuilder(*fConfig));
+  LOG(info) << fAlgo->ToString();
+
+  // --- Log selector
+  if (fSelector) LOG(info) << fSelector->ToString();
+  else
+    LOG(info) << "--- No event selection";
 
   LOG(info) << "==================================================";
 
diff --git a/reco/tasks/CbmTaskBuildEvents.h b/reco/tasks/CbmTaskBuildEvents.h
index 495d285083..f94e2bc097 100644
--- a/reco/tasks/CbmTaskBuildEvents.h
+++ b/reco/tasks/CbmTaskBuildEvents.h
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "DigiEventSelector.h"
+#include "DigiEventSelectorConfig.h"
 #include "EventBuilder.h"
 
 class CbmDigiManager;
@@ -55,23 +56,20 @@ public:
   CbmTaskBuildEvents& operator=(const CbmTaskBuildEvents&) = delete;
 
 
-  /** @brief Configure the event building time intervals
-   ** @param system  Detector system identifier
-   ** @param tMin    Event window start time w.r.t. event time
-   ** @param tMax    Event window end time w.r.t. event time
-   **/
-  void SetEventWindow(ECbmModuleId system, double tMin, double tMax)
+  /** @brief Configure the event builder algorithm **/
+  void SetConfig(const cbm::algo::evbuild::EventBuilderConfig& config)
   {
-    fEventWindows[system] = std::make_pair(tMin, tMax);
+    fConfig.reset(new cbm::algo::evbuild::EventBuilderConfig(config));
   }
 
+
   /** @brief Activate event selector which requires a minimum number of fired layers
    ** @param params Struct with minimum number of layers for different detectors
    **/
 
-  void SetDigiEventSelector(cbm::algo::evbuild::DigiEventSelectorParams params)
+  void SetDigiEventSelector(cbm::algo::evbuild::DigiEventSelectorConfig config)
   {
-    fSelector.reset(new cbm::algo::evbuild::DigiEventSelector(params));
+    fSelector.reset(new cbm::algo::evbuild::DigiEventSelector(config));
   }
 
 
@@ -97,10 +95,8 @@ private:                                                             // members
   const std::vector<double>* fTriggers = nullptr;                    //! Input data (triggers)
   std::vector<CbmDigiEvent>* fEvents   = nullptr;                    //! Output data (events)
   std::unique_ptr<cbm::algo::evbuild::DigiEventSelector> fSelector;  //! Event selector
-
-  cbm::algo::EventBuilder fAlgo {};  //! Algorithm
-
-  std::map<ECbmModuleId, std::pair<double, double>> fEventWindows;
+  std::unique_ptr<cbm::algo::evbuild::EventBuilder> fAlgo;           //! Algorithm
+  std::unique_ptr<cbm::algo::evbuild::EventBuilderConfig> fConfig;   //! Event builder configuration
 
   // for diagnostics
   std::map<ECbmModuleId, size_t> fNumDigisTs;  //  Number of digis in timeslices
diff --git a/reco/tasks/CbmTaskDigiEventQa.cxx b/reco/tasks/CbmTaskDigiEventQa.cxx
index 8ba57674fd..e8206b2fa8 100644
--- a/reco/tasks/CbmTaskDigiEventQa.cxx
+++ b/reco/tasks/CbmTaskDigiEventQa.cxx
@@ -19,9 +19,9 @@
 #include "algo/qa/Histo1D.h"
 
 using namespace std;
-using cbm::algo::qa::DigiEventQaConfig;
-using cbm::algo::qa::DigiEventQaData;
-using cbm::algo::qa::DigiEventQaDetConfig;
+using cbm::algo::evbuild::DigiEventQaConfig;
+using cbm::algo::evbuild::DigiEventQaData;
+using cbm::algo::evbuild::DigiEventQaDetConfig;
 
 #define NUM_BINS 100
 #define BORDER 10.
@@ -38,13 +38,13 @@ CbmTaskDigiEventQa::~CbmTaskDigiEventQa() {}
 
 
 // -----   Configuration   ---------------------------------------------------
-void CbmTaskDigiEventQa::Config(const cbm::algo::MainConfig& config)
+void CbmTaskDigiEventQa::Config(const cbm::algo::evbuild::Config& config)
 {
 
   // The histogram ranges are defined by the event building windows. The number of bins
   // is hard-coded. To be changed on request.
 
-  for (const auto& entry : config.fEvtbuildWindows) {
+  for (const auto& entry : config.fBuilder.fWindows) {
     ECbmModuleId system = entry.first;
 
     // --- Create histogram
@@ -73,7 +73,7 @@ void CbmTaskDigiEventQa::Exec(Option_t*)
 
   // --- Algo execution
   DigiEventQaConfig config;
-  DigiEventQaData result = fAlgo(*fEvents, fConfig);
+  DigiEventQaData result = (*fAlgo)(*fEvents);
 
   // --- Copy QA results (Histo1D) into ROOT output histograms
   // TODO: Probably not the most efficient implementation. Creates first a ROOT histogram from a CBM one (data copy),
@@ -148,10 +148,11 @@ InitStatus CbmTaskDigiEventQa::Init()
   else
     LOG(info) << "--- No Http server present";
 
-  // --- Log configuration
-  LOG(info) << "--- Algo configuration for " << fConfig.fData.size() << " subsystem(s): " << fConfig.ToString();
-  LOG(info) << "==================================================";
+  // --- Configure algorithm
+  fAlgo = std::make_unique<cbm::algo::evbuild::DigiEventQa>(fConfig);
+  LOG(info) << fAlgo->ToString();
 
+  LOG(info) << "==================================================";
   return kSUCCESS;
 }
 // ----------------------------------------------------------------------------
diff --git a/reco/tasks/CbmTaskDigiEventQa.h b/reco/tasks/CbmTaskDigiEventQa.h
index c1779db923..ebd6566753 100644
--- a/reco/tasks/CbmTaskDigiEventQa.h
+++ b/reco/tasks/CbmTaskDigiEventQa.h
@@ -12,7 +12,7 @@
 
 #include <vector>
 
-#include "MainConfig.h"
+#include "algo/evbuild/Config.h"
 #include "algo/qa/DigiEventQa.h"
 #include "algo/qa/Histo1D.h"
 
@@ -48,7 +48,7 @@ public:
    **
    ** Histograms are created with limits adjusted to the windows use by the event builder.
    **/
-  void Config(const cbm::algo::MainConfig& config);
+  void Config(const cbm::algo::evbuild::Config& config);
 
 
   /** @brief Task execution **/
@@ -82,8 +82,8 @@ private:                                               // members
   size_t fNumDigis                         = 0;        ///< Number of analysed digis
   double fExecTime                         = 0.;       ///< Execution time [s]
 
-  cbm::algo::qa::DigiEventQa fAlgo         = {};
-  cbm::algo::qa::DigiEventQaConfig fConfig = {};
+  std::unique_ptr<cbm::algo::evbuild::DigiEventQa> fAlgo;
+  cbm::algo::evbuild::DigiEventQaConfig fConfig;
 
   // ---- Histograms with digi times
   std::map<ECbmModuleId, TH1D*> fDigiTimeHistos = {};
diff --git a/reco/tasks/CbmTaskTriggerDigi.cxx b/reco/tasks/CbmTaskTriggerDigi.cxx
index 31eee2cbba..5f231b0233 100644
--- a/reco/tasks/CbmTaskTriggerDigi.cxx
+++ b/reco/tasks/CbmTaskTriggerDigi.cxx
@@ -103,7 +103,7 @@ void CbmTaskTriggerDigi::Exec(Option_t*)
 
   // --- Call the trigger algorithm
   timerStep.Start();
-  *fTriggers = fAlgo(digiTimes, fTriggerWindow, fMinNumDigis, fDeadTime).first;
+  *fTriggers = (*fAlgo)(digiTimes).first;
   timerStep.Stop();
   fTimeFind += timerStep.RealTime();
 
@@ -253,10 +253,12 @@ InitStatus CbmTaskTriggerDigi::Init()
   }
   LOG(info) << "--- Registered branch Trigger";
 
-  LOG(info) << "--- Use algo TimeClusterTrigger with TriggerWin " << fTriggerWindow << " ns, threshold " << fMinNumDigis
-            << ", dead time " << fDeadTime << " ns";
-  LOG(info) << "==================================================";
+  // --- Configure algorithm
+  fAlgo.reset(new cbm::algo::evbuild::TimeClusterTrigger(*fConfig));
+  LOG(info) << "--- Using trigger detector " << ::ToString(fConfig->Detector());
+  LOG(info) << fAlgo->ToString();
 
+  LOG(info) << "==================================================";
   return kSUCCESS;
 }
 // ----------------------------------------------------------------------------
diff --git a/reco/tasks/CbmTaskTriggerDigi.h b/reco/tasks/CbmTaskTriggerDigi.h
index 3a6f0bf59d..247536f249 100644
--- a/reco/tasks/CbmTaskTriggerDigi.h
+++ b/reco/tasks/CbmTaskTriggerDigi.h
@@ -60,16 +60,10 @@ public:
   CbmTaskTriggerDigi& operator=(const CbmTaskTriggerDigi&) = delete;
 
 
-  /** @brief Configure the trigger algorithm
-   ** @param triggerWindow    Size of trigger window [ns]
-   ** @param minNumDigis      Trigger threshold on number of digis in trigger windows
-   ** @param deadTime         Minimum time between two triggers [ns]
-   **/
-  void SetAlgoParams(double triggerWindow, int32_t minNumDigis, double deadTime)
+  /** @brief Configure the trigger algorithm **/
+  void SetConfig(const cbm::algo::evbuild::DigiTriggerConfig& config)
   {
-    fTriggerWindow = triggerWindow;
-    fMinNumDigis   = minNumDigis;
-    fDeadTime      = deadTime;
+    fConfig.reset(new cbm::algo::evbuild::DigiTriggerConfig(config));
   }
 
   /** @brief Add a detector system to the trigger algorithm
@@ -114,21 +108,22 @@ private:  // methods
   std::vector<double> GetDigiTimes(ECbmModuleId system);
 
 
-private:                                         // members
-  const CbmDigiTimeslice* fTimeslice = nullptr;  //! Input data (from unpacking)
-  CbmDigiManager* fDigiMan           = nullptr;  //! Input data (from simulation)
-  std::vector<ECbmModuleId> fSystems {};         //  List of detector systems
-  std::vector<double>* fTriggers = nullptr;      //! Output data
-  cbm::algo::TimeClusterTrigger fAlgo {};        //! Algorithm
-  double fTriggerWindow = 0.;
-  int32_t fMinNumDigis  = 0;
-  double fDeadTime      = 0.;
-  size_t fNumTs         = 0;  //  Number of processed time slices
-  size_t fNumDigis      = 0;  //  Number of digis from trigger detector
-  size_t fNumTriggers   = 0;  //  Number of found triggers
-  double fTimeExtract   = 0.;
-  double fTimeFind      = 0.;
-  double fTimeTot       = 0.;
+private:                                                                     // members
+  const CbmDigiTimeslice* fTimeslice = nullptr;                              //! Input data (from unpacking)
+  CbmDigiManager* fDigiMan           = nullptr;                              //! Input data (from simulation)
+  std::vector<ECbmModuleId> fSystems {};                                     //  List of detector systems
+  std::vector<double>* fTriggers                                 = nullptr;  //! Output data
+  std::unique_ptr<cbm::algo::evbuild::TimeClusterTrigger> fAlgo  = nullptr;  //! Algorithm
+  std::unique_ptr<cbm::algo::evbuild::DigiTriggerConfig> fConfig = nullptr;  //! Configuration / parameters
+  double fTriggerWindow                                          = 0.;
+  int32_t fMinNumDigis                                           = 0;
+  double fDeadTime                                               = 0.;
+  size_t fNumTs                                                  = 0;  //  Number of processed time slices
+  size_t fNumDigis                                               = 0;  //  Number of digis from trigger detector
+  size_t fNumTriggers                                            = 0;  //  Number of found triggers
+  double fTimeExtract                                            = 0.;
+  double fTimeFind                                               = 0.;
+  double fTimeTot                                                = 0.;
 
 
   ClassDef(CbmTaskTriggerDigi, 1);
-- 
GitLab