diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index dabaaa06f46dad0bca02e29a42b93df1e26e4c88..60fe4c1d66aec22cbb0ef35de26f3c337153616c 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 0000000000000000000000000000000000000000..b690b5b1db4827838b1c49890bfa849f4ee96577 --- /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 0000000000000000000000000000000000000000..d2b722f95652151fc01ce036a30975426a73ca41 --- /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 2f04b6f131992b67cf34f0cf194e1ec067347f54..c901c8a7818046c6f3caacbefc26e41c96ec4e38 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 2d6128801f183ea02c1e439b78571e95e7a87532..973a13dd2e5e95277598fba23b5cf363506ed7a9 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 0000000000000000000000000000000000000000..e0817b04a49b8010007baf04a5f00b67bf425fe5 --- /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 0000000000000000000000000000000000000000..a828be62bf169d240db49d056d6a77153652df25 --- /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 ac234de30f953e2d44b95c7d4150f6d1831fef09..4674f5f39abc316b46edebb80d539351482c333d 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 11a3a4a7d32a3191cd028d4de58a909ebb4fbf0a..ae35c95bc496b9d1c8562c1d28014b37a267342b 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 59743bec715da3270703893410d72ccd9c703d52..4b53fd9dfc743c0b94506b6620adaaed7c28a55c 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 28a0a2491d5de73a4ef2ae4e95092aedc76b1fb0..4155c7eb86983b9c6155c75f3def4fb8af2da28d 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 0000000000000000000000000000000000000000..3b09a84bb2e7f76f90564eb991e0fd2c415928a9 --- /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 0000000000000000000000000000000000000000..1076f3d69ad01bf8f8661b3d5568dc5e80600c07 --- /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 3a5f1a6e3144387cbba32586bc5cc290b5a68945..b1a225fec74ff2d0f2a6ad6c8405dbca8118e48e 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 ac41bb2a94e3d5067a1492db3981d566581daa09..aa5ad55fae89453ba318aab43c527fb054bb8df1 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 0000000000000000000000000000000000000000..a7267aff92af8a01b59b421f1825ed392dc9d488 --- /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 677b1bf105bcfdb56691cf5290df3c08dfeeb794..0000000000000000000000000000000000000000 --- 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 284b1d8cce4d3e3a887f06846e52e55ff234f357..f25dfaac320d09f018f521bc84ad5e93b830fd7a 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 1ba0e75e5ea00ec1c6a7f16c47b01d7974f06cda..eb58a894710b86f821d6269d9b8782741f058b8d 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 375b5f9180661391a3889f9a61f80f7a19701b88..d873199491e44d4d92d5ab3d20c4cc8d280291d5 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 6227df9cb6e74ae30b1844aab1fe8376c1a6d3dd..51646ebeb6e71f5a9d63bb338ec3f6dc8bd2a521 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 35e8891a98217ed66c81f06fbbb0209557a1b00c..f2932774ab997b0fc2ca17eadc41357c1da95ae2 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 0000000000000000000000000000000000000000..9fbc2ed1f0ffca987fdef3db58d0c744a37a3b38 --- /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 0000000000000000000000000000000000000000..a52008e7256b69f12d26b5f921d555ed9818cb4a --- /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 fe21815e2d1ac4ab0d7b5ee96d89ba5fb5ff12f3..6cf6a87b8dc77f318c11640cd452a4be4d77971d 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 0ad85df3eee8efe449c101766cbaf6b41facce24..ce8eec7098a8f2bf9726c7d2a0f7dd96df1821d4 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 0ae6e5c100adf687744832ae8ab3533c019c3154..08a67b050fe5f5f332bbaff49a5ad44bd8c723fa 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 0000000000000000000000000000000000000000..0e0860758d53af9bc2d524d965358b6097a9f11e --- /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 b693b3a18ce5801e3264c716fa89526a1485ed3a..a234228a34820402b37cfdaf06596bd948bee501 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 6bcd5fd587f3d91485f9b88597118d9279539004..a15721ac5dc3e5c50c00c73277f0164b0ea14f82 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 9979a9a10b6db43c1e0e3579d16147424ff61572..e58543c8aa150d0b86cdf7d5f7596c303f8f9c96 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 08f6f4f757970757656413686712ae7644ebf051..577ba917f2f5acc8316635b96ad8ac943b31a160 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 7b4a52a4f5f3e3fccea7add29f6a1e8bad90f316..18a8660996c4a0c2b42aadd5d15a6972cdc1adf0 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 04acb3914eaceec8506aecc76a418c005100e169..f24e6a797dd41798632ddc485a06d23fe9652762 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 5ab19fdf16ded615eb797db1462477a019725c5a..b5743194ce7a58444f31429791447e72fa0da140 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 7b68270a69f367dc569321c2e5efefd35ad3b464..3045c23c93eb6722e689f939346725020e1b59e7 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 112095846db7ab49602293b770c2db77634ba9c0..77d11ab08e00047d518de2dfb20cd754001c8d07 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 8312e9f83a34956290203239605435e029e1f419..301d72d8f6c5c58fabc16a947f69f915f3fb803a 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 495d285083c2779f5d7d93c9ab2ac90ad480a453..f94e2bc097dc1e87f2d5117ffe9d03fcf6768b5c 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 8ba57674fd3bc2b8bf7acf1fa5c1e373fd9a0adb..e8206b2fa87cf92fe8008690b5cf8965daea2a15 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 c1779db923e8232ec088aa4f8873ae4afbadf68c..ebd65667530c3229353dd4ff17d2bbd14fcf26f3 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 31eee2cbbab01c72b98105e5b5c66915842550bc..5f231b0233c562be2249cd09f28659641e37ddce 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 3a6f0bf59dcd4eb4a577e25e5518130382e6e608..247536f249de17f1d61f71bbe1a3e244a3e02115 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);