diff --git a/Detectors/MUON/MCH/Base/CMakeLists.txt b/Detectors/MUON/MCH/Base/CMakeLists.txt index 47d54ad648397..e6c1b6e64b40a 100644 --- a/Detectors/MUON/MCH/Base/CMakeLists.txt +++ b/Detectors/MUON/MCH/Base/CMakeLists.txt @@ -11,6 +11,7 @@ o2_add_library(MCHBase SOURCES + src/Error.cxx src/ErrorMap.cxx src/MathiesonOriginal.cxx src/PreCluster.cxx @@ -30,6 +31,12 @@ o2_add_test(trackable PUBLIC_LINK_LIBRARIES O2::MCHBase LABELS muon;mch) +o2_add_test(error + SOURCES src/testError.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES O2::MCHBase + LABELS muon;mch) + o2_add_test(errormap SOURCES src/testErrorMap.cxx COMPONENT_NAME mch diff --git a/Detectors/MUON/MCH/Base/include/MCHBase/Error.h b/Detectors/MUON/MCH/Base/include/MCHBase/Error.h new file mode 100644 index 0000000000000..da58b4e971a00 --- /dev/null +++ b/Detectors/MUON/MCH/Base/include/MCHBase/Error.h @@ -0,0 +1,97 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** + * @file Error.h + * @brief definition of the MCH processing errors + * @author Philippe Pillot, Subatech + */ + +#ifndef O2_MCH_BASE_ERROR_H +#define O2_MCH_BASE_ERROR_H + +#include +#include +#include + +namespace o2::mch +{ + +/** groups of MCH processing errors, each group corresponding to a processing units */ +enum class ErrorGroup : uint8_t { + Unassigned, + Decoding, + Filtering, + TimeClustering, + PreClustering, + Clustering, + Tracking +}; + +namespace internal +{ +/** + * @brief helper function to construct the error type GID (not supposed to be used outside of this header) + * @details - the 8 most significant bits identify the error group + * - the other bits identify the error type within the group + * @param group group to which this error belongs + * @param id error UID within this group + */ +constexpr uint32_t buildTypeGID(ErrorGroup group, uint32_t id) { return (static_cast(group) << 24) + id; } +} // namespace internal + +/** types of MCH processing errors */ +enum class ErrorType : uint32_t { + PreClustering_MultipleDigitsInSamePad = internal::buildTypeGID(ErrorGroup::PreClustering, 0), + PreClustering_LostDigit = internal::buildTypeGID(ErrorGroup::PreClustering, 1), + Clustering_TooManyLocalMaxima = internal::buildTypeGID(ErrorGroup::Clustering, 0), + Tracking_TooManyCandidates = internal::buildTypeGID(ErrorGroup::Tracking, 0), + Tracking_TooLong = internal::buildTypeGID(ErrorGroup::Tracking, 1) +}; + +/** + * returns the group to which this error type belongs + * @param error error type + */ +constexpr ErrorGroup errorGroup(ErrorType error) { return static_cast(static_cast(error) >> 24); } + +/** generic structure to handle MCH processing errors */ +struct Error { + static const std::map groupNames; ///< names of known error group + static const std::map typeNames; ///< names of known error type + static const std::map typeDescriptions; ///< descriptions of known error type + + ErrorType type{0}; ///< type of processing error + uint32_t id0 = 0; ///< additional descriptor used for certain error types + uint32_t id1 = 0; ///< additional descriptor used for certain error types + uint64_t count = 0; ///< number of occurences + + /** + * returns the known error type names within the given group + * @param group error group + */ + static const std::map getTypeNames(ErrorGroup group); + + /** returns the group to which this error belongs */ + ErrorGroup getGroup() const { return o2::mch::errorGroup(type); } + /** returns the name of the group to which this error belongs */ + std::string getGroupName() const; + /** returns the type name of this error */ + std::string getTypeName() const; + /** returns the type description of this error */ + std::string getTypeDescription() const; + /** returns the error message corresponding to this error */ + std::string asString() const; +}; + +} // namespace o2::mch + +#endif // O2_MCH_BASE_ERROR_H diff --git a/Detectors/MUON/MCH/Base/include/MCHBase/ErrorMap.h b/Detectors/MUON/MCH/Base/include/MCHBase/ErrorMap.h index 42403fe60db61..1c11650aeba68 100644 --- a/Detectors/MUON/MCH/Base/include/MCHBase/ErrorMap.h +++ b/Detectors/MUON/MCH/Base/include/MCHBase/ErrorMap.h @@ -12,58 +12,65 @@ #ifndef O2_MCH_BASE_ERROR_MAP_H_H #define O2_MCH_BASE_ERROR_MAP_H_H -#include -#include #include #include +#include + +#include + +#include "MCHBase/Error.h" namespace o2::mch { -/** A container class to summarize errors encountered during processing. - * - * The interface is : - * add(errorType, id0, id1) +/** @brief A container class to summarize errors encountered during processing. * - * where errorType, id0 and id1 are integers (unsigned, 32 bits wide) + * @details The main interface is : + * add(errorType, id0, id1[, count]) * - * ErrorMap stores the number of times the add method has been - * called for the {errorType,id0,id1} triplet. - * - * The exact meaning of the triplet members is left to the client of ErrorMap. + * where errorType is the type of the error and id0 and id1 are additional + * descriptors, whose meaning depends on the error type (see Error.h/cxx) * + * additional interfaces are provided to add and access the errors, + * or execute a function on all or some of them */ class ErrorMap { public: - /* ErrorFunction is a function that receive a triplet {errorType,id0,id1) - * and the number of times (count) that triplet has been seen. - */ - using ErrorFunction = std::function; + using ErrorFunction = std::function; + + /** increment the count of the {errorType,id0,id1} triplet by n */ + void add(ErrorType errorType, uint32_t id0, uint32_t id1, uint64_t n = 1); + /** add or increment this error */ + void add(Error error); + /** add or increment these errors */ + void add(gsl::span errors); + /** add or increment these errors */ + void add(const ErrorMap& errors); + + /** erase all encountered errors */ + void clear() { mErrors.clear(); } - /* increment the count of the {errorType,id0,id1} triplet by one.*/ - void add(uint32_t errorType, uint32_t id0, uint32_t id1); + /** return the number of encountered types of error */ + uint64_t getNumberOfErrorTypes() const { return mErrors.size(); } + /** return the total number of encountered errors */ + uint64_t getNumberOfErrors() const; + /** return the total number of encountered errors of a given type */ + uint64_t getNumberOfErrors(ErrorType type) const; + /** return the total number of encountered errors of a given group */ + uint64_t getNumberOfErrors(ErrorGroup group) const; - /* execute function f on all {errorType,id0,id1} triplets. - * - * The function is passed the triplet and the corresponding occurence count - * of that triplet. - */ + /** execute function f on all encountered errors */ void forEach(ErrorFunction f) const; + /** execute function f on all encountered errors of a given type */ + void forEach(ErrorType type, ErrorFunction f) const; + /** execute function f on all encountered errors of a given group */ + void forEach(ErrorGroup group, ErrorFunction f) const; private: - std::map> mErrorCounts; + std::map> mErrors{}; ///< map of encountered errors }; -/* convenience function to get the number of error types */ -uint64_t numberOfErrorTypes(const ErrorMap& em); - -/* convenience function to get the total number of errors */ -uint64_t totalNumberOfErrors(const ErrorMap& em); - -}; // namespace o2::mch +} // namespace o2::mch #endif diff --git a/Detectors/MUON/MCH/Base/src/Error.cxx b/Detectors/MUON/MCH/Base/src/Error.cxx new file mode 100644 index 0000000000000..edef77ab0ad54 --- /dev/null +++ b/Detectors/MUON/MCH/Base/src/Error.cxx @@ -0,0 +1,105 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/** + * @file Error.cxx + * @brief implementation of the MCH processing errors + * @author Philippe Pillot, Subatech + */ + +#include "MCHBase/Error.h" + +#include + +namespace o2::mch +{ + +const std::map Error::groupNames = { + {ErrorGroup::Unassigned, "Unassigned"}, + {ErrorGroup::Decoding, "Decoding"}, + {ErrorGroup::Filtering, "Filtering"}, + {ErrorGroup::TimeClustering, "TimeClustering"}, + {ErrorGroup::PreClustering, "PreClustering"}, + {ErrorGroup::Clustering, "Clustering"}, + {ErrorGroup::Tracking, "Tracking"}}; + +const std::map Error::typeNames = { + {ErrorType::PreClustering_MultipleDigitsInSamePad, "MultipleDigitsInSamePad"}, + {ErrorType::PreClustering_LostDigit, "LostDigit"}, + {ErrorType::Clustering_TooManyLocalMaxima, "TooManyLocalMaxima"}, + {ErrorType::Tracking_TooManyCandidates, "TooManyCandidates"}, + {ErrorType::Tracking_TooLong, "TooLong"}}; + +const std::map Error::typeDescriptions = { + {ErrorType::PreClustering_MultipleDigitsInSamePad, "multiple digits on the same pad"}, + {ErrorType::PreClustering_LostDigit, "lost digit"}, + {ErrorType::Clustering_TooManyLocalMaxima, "too many local maxima"}, + {ErrorType::Tracking_TooManyCandidates, "too many track candidates"}, + {ErrorType::Tracking_TooLong, "too long"}}; + +const std::map Error::getTypeNames(ErrorGroup group) +{ + std::map groupTypeNames{}; + for (const auto& typeName : typeNames) { + if (errorGroup(typeName.first) == group) { + groupTypeNames.emplace(typeName); + } + } + return groupTypeNames; +} + +std::string Error::getGroupName() const +{ + const auto itName = groupNames.find(getGroup()); + if (itName != groupNames.end()) { + return itName->second; + } + return "Unknown"; +} + +std::string Error::getTypeName() const +{ + const auto itName = typeNames.find(type); + if (itName != typeNames.end()) { + return itName->second; + } + return "Unknown"; +} + +std::string Error::getTypeDescription() const +{ + const auto itDescription = typeDescriptions.find(type); + if (itDescription != typeDescriptions.end()) { + return itDescription->second; + } + return ""; +} + +std::string Error::asString() const +{ + auto description = fmt::format("{} error: {}", getGroupName(), getTypeDescription()); + + // add extra description when relevant + switch (type) { + case ErrorType::PreClustering_MultipleDigitsInSamePad: + description += fmt::format(" (DE {} pad {})", id0, id1); + break; + case ErrorType::Clustering_TooManyLocalMaxima: + description += fmt::format(" (DE {})", id0); + break; + default: + break; + } + + return description + fmt::format(": seen {} time{}", count, count > 1 ? "s" : ""); +} + +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Base/src/ErrorMap.cxx b/Detectors/MUON/MCH/Base/src/ErrorMap.cxx index 3102846667c5e..fda004bdb6c4d 100644 --- a/Detectors/MUON/MCH/Base/src/ErrorMap.cxx +++ b/Detectors/MUON/MCH/Base/src/ErrorMap.cxx @@ -11,6 +11,8 @@ #include "MCHBase/ErrorMap.h" +#include + namespace o2::mch { @@ -28,46 +30,92 @@ std::pair decode(uint64_t x) return std::make_pair(a, b); } -void ErrorMap::add(uint32_t errorType, uint32_t id0, uint32_t id1) +void ErrorMap::add(ErrorType errorType, uint32_t id0, uint32_t id1, uint64_t n) { - mErrorCounts[errorType][encode(id0, id1)]++; + auto [itError, isNew] = mErrors[errorType].emplace(encode(id0, id1), Error{errorType, id0, id1, n}); + if (!isNew) { + itError->second.count += n; + } } -void ErrorMap::forEach(ErrorFunction f) const +void ErrorMap::add(Error error) { - for (auto errorType : mErrorCounts) { - for (auto errorCounts : errorType.second) { - uint64_t count = errorCounts.second; - uint64_t id = errorCounts.first; - auto [id0, id1] = decode(id); - f(errorType.first, id0, id1, count); - } + auto [itError, isNew] = mErrors[error.type].emplace(encode(error.id0, error.id1), error); + if (!isNew) { + itError->second.count += error.count; } } -uint64_t numberOfErrorTypes(const ErrorMap& em) +void ErrorMap::add(gsl::span errors) +{ + for (auto error : errors) { + add(error); + } +} + +void ErrorMap::add(const ErrorMap& errors) +{ + errors.forEach([this](Error error) { + add(error); + }); +} + +uint64_t ErrorMap::getNumberOfErrors() const { - std::set errorTypes; - auto countErrorTypes = [&errorTypes](uint32_t errorType, - uint32_t /*id0*/, - uint32_t /*id1*/, - uint64_t /*count*/) { - errorTypes.emplace(errorType); - }; - em.forEach(countErrorTypes); - return errorTypes.size(); + uint64_t n{0}; + forEach([&n](Error error) { + n += error.count; + }); + return n; +} + +uint64_t ErrorMap::getNumberOfErrors(ErrorType type) const +{ + uint64_t n{0}; + forEach(type, [&n](Error error) { + n += error.count; + }); + return n; } -uint64_t totalNumberOfErrors(const ErrorMap& em) +uint64_t ErrorMap::getNumberOfErrors(ErrorGroup group) const { uint64_t n{0}; - auto countErrors = [&n](uint32_t /*errorType*/, - uint32_t /*id0*/, - uint32_t /*id1*/, - uint64_t count) { - n += count; - }; - em.forEach(countErrors); + forEach(group, [&n](Error error) { + n += error.count; + }); return n; } -}; // namespace o2::mch + +void ErrorMap::forEach(ErrorFunction f) const +{ + for (const auto& typeErrors : mErrors) { + for (auto error : typeErrors.second) { + f(error.second); + } + } +} + +void ErrorMap::forEach(ErrorType type, ErrorFunction f) const +{ + for (const auto& [thisType, errors] : mErrors) { + if (thisType == type) { + for (auto error : errors) { + f(error.second); + } + } + } +} + +void ErrorMap::forEach(ErrorGroup group, ErrorFunction f) const +{ + for (const auto& [thisType, errors] : mErrors) { + if (errorGroup(thisType) == group) { + for (auto error : errors) { + f(error.second); + } + } + } +} + +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/Base/src/testError.cxx b/Detectors/MUON/MCH/Base/src/testError.cxx new file mode 100644 index 0000000000000..ab40e55756978 --- /dev/null +++ b/Detectors/MUON/MCH/Base/src/testError.cxx @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE error test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include +#include "MCHBase/Error.h" +#include + +using o2::mch::Error; +using o2::mch::ErrorGroup; +using o2::mch::ErrorType; + +/// @brief expected ID of each error group +// this needs to be updated every time a new group is added +// changing the IDs of existing groups will break the backward compatibility +const std::map errorGroupIds = { + {ErrorGroup::Unassigned, 0U}, + {ErrorGroup::Decoding, 1U}, + {ErrorGroup::Filtering, 2U}, + {ErrorGroup::TimeClustering, 3U}, + {ErrorGroup::PreClustering, 4U}, + {ErrorGroup::Clustering, 5U}, + {ErrorGroup::Tracking, 6U}}; + +/// @brief expected ID of each error type +// this needs to be updated every time a new type is added +// changing the IDs of existing types will break the backward compatibility +const std::map errorTypeIds = { + {ErrorType::PreClustering_MultipleDigitsInSamePad, 67108864U}, + {ErrorType::PreClustering_LostDigit, 67108865U}, + {ErrorType::Clustering_TooManyLocalMaxima, 83886080U}, + {ErrorType::Tracking_TooManyCandidates, 100663296U}, + {ErrorType::Tracking_TooLong, 100663297U}}; + +BOOST_AUTO_TEST_CASE(ErrorGroupConsistency) +{ + BOOST_CHECK_EQUAL(errorGroupIds.size(), Error::groupNames.size()); + for (auto [group, id] : errorGroupIds) { + BOOST_CHECK_EQUAL(static_cast(group), id); + BOOST_CHECK_EQUAL(Error::groupNames.count(group), 1); + } +} + +BOOST_AUTO_TEST_CASE(ErrorTypeConsistency) +{ + BOOST_CHECK_EQUAL(errorTypeIds.size(), Error::typeNames.size()); + BOOST_CHECK_EQUAL(errorTypeIds.size(), Error::typeDescriptions.size()); + for (auto [type, id] : errorTypeIds) { + BOOST_CHECK_EQUAL(static_cast(type), id); + BOOST_CHECK_EQUAL(Error::typeNames.count(type), 1); + BOOST_CHECK_EQUAL(Error::typeDescriptions.count(type), 1); + BOOST_CHECK_EQUAL(errorGroupIds.count(o2::mch::errorGroup(type)), 1); + } +} diff --git a/Detectors/MUON/MCH/Base/src/testErrorMap.cxx b/Detectors/MUON/MCH/Base/src/testErrorMap.cxx index d64cdedd51ae3..77873a81faf70 100644 --- a/Detectors/MUON/MCH/Base/src/testErrorMap.cxx +++ b/Detectors/MUON/MCH/Base/src/testErrorMap.cxx @@ -16,52 +16,76 @@ #include "MCHBase/ErrorMap.h" #include +using o2::mch::Error; +using o2::mch::ErrorGroup; using o2::mch::ErrorMap; +using o2::mch::ErrorType; BOOST_AUTO_TEST_CASE(DefaultErrorMapShouldBeEmpty) { ErrorMap em; - BOOST_CHECK_EQUAL(o2::mch::numberOfErrorTypes(em), 0); - BOOST_CHECK_EQUAL(o2::mch::totalNumberOfErrors(em), 0); + BOOST_CHECK_EQUAL(em.getNumberOfErrorTypes(), 0); + BOOST_CHECK_EQUAL(em.getNumberOfErrors(), 0); } BOOST_AUTO_TEST_CASE(AddingErrorType) { ErrorMap em; - em.add(0, 0, 0); - em.add(1, 0, 0); - em.add(2, 0, 0); - BOOST_CHECK_EQUAL(o2::mch::numberOfErrorTypes(em), 3); + em.add(ErrorType{0}, 0, 0); + em.add(ErrorType{1}, 0, 0); + em.add(ErrorType{2}, 0, 0); + BOOST_CHECK_EQUAL(em.getNumberOfErrorTypes(), 3); } BOOST_AUTO_TEST_CASE(AddingError) { ErrorMap em; - em.add(0, 0, 0); - em.add(0, 0, 0); - em.add(0, 0, 0); - BOOST_CHECK_EQUAL(o2::mch::numberOfErrorTypes(em), 1); - BOOST_CHECK_EQUAL(o2::mch::totalNumberOfErrors(em), 3); + em.add(ErrorType{0}, 0, 0); + em.add(ErrorType{1}, 0, 0, 2); + em.add(Error{ErrorType{0}, 1, 2, 3}); + BOOST_CHECK_EQUAL(em.getNumberOfErrorTypes(), 2); + BOOST_CHECK_EQUAL(em.getNumberOfErrors(), 6); + BOOST_CHECK_EQUAL(em.getNumberOfErrors(ErrorType{0}), 4); + BOOST_CHECK_EQUAL(em.getNumberOfErrors(ErrorGroup{0}), 6); +} + +BOOST_AUTO_TEST_CASE(MergingError) +{ + ErrorMap em1; + em1.add(ErrorType{0}, 0, 0); + em1.add(ErrorType{1}, 0, 0); + ErrorMap em2; + em2.add(ErrorType{0}, 1, 2); + em2.add(ErrorType{0}, 0, 0); + em2.add(em1); + BOOST_CHECK_EQUAL(em2.getNumberOfErrorTypes(), 2); + BOOST_CHECK_EQUAL(em2.getNumberOfErrors(), 4); } BOOST_AUTO_TEST_CASE(ErrorFunction) { ErrorMap em; - em.add(0, 0, 0); - em.add(0, 0, 0); - em.add(0, 0, 0); - em.add(0, 1, 2); + em.add(ErrorType{0}, 0, 0); + em.add(ErrorType{0}, 0, 0); + em.add(ErrorType{1}, 0, 0); + em.add(ErrorType{0}, 1, 2); std::vector lines; - auto f = [&lines](uint32_t errorType, uint32_t id0, uint32_t id1, - uint64_t count) { - lines.emplace_back(fmt::format("ET {} ID [{},{}] seen {} time(s)", errorType, id0, id1, count)); + auto f = [&lines](Error error) { + lines.emplace_back(fmt::format("ET {} ID [{},{}] seen {} time(s)", + static_cast(error.type), error.id0, error.id1, error.count)); }; em.forEach(f); - for (auto s : lines) { - std::cout << s << "\n"; - } - BOOST_REQUIRE_EQUAL(lines.size(), 2); - BOOST_CHECK_EQUAL(lines[0], "ET 0 ID [0,0] seen 3 time(s)"); + BOOST_REQUIRE_EQUAL(lines.size(), 3); + BOOST_CHECK_EQUAL(lines[0], "ET 0 ID [0,0] seen 2 time(s)"); BOOST_CHECK_EQUAL(lines[1], "ET 0 ID [1,2] seen 1 time(s)"); + BOOST_CHECK_EQUAL(lines[2], "ET 1 ID [0,0] seen 1 time(s)"); + + uint64_t n(0); + em.forEach(ErrorType{0}, [&n](Error error) { + if (error.id0 == 0) { + n += error.count; + } + }); + BOOST_CHECK_EQUAL(n, 2); } diff --git a/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h b/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h index e7d45af7871c5..9afeca97fa862 100644 --- a/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h +++ b/Detectors/MUON/MCH/Clustering/include/MCHClustering/ClusterFinderOriginal.h @@ -29,6 +29,7 @@ #include "DataFormatsMCH/Digit.h" #include "DataFormatsMCH/Cluster.h" +#include "MCHBase/ErrorMap.h" #include "MCHMappingInterface/Segmentation.h" #include "MCHPreClustering/PreClusterFinder.h" @@ -63,6 +64,9 @@ class ClusterFinderOriginal /// return the list of digits used in reconstructed clusters const std::vector& getUsedDigits() const { return mUsedDigits; } + /// return the counting of encountered errors + ErrorMap& getErrorMap() { return mErrorMap; } + private: static constexpr double SDistancePrecision = 1.e-3; ///< precision used to check overlaps and so on (cm) static constexpr int SNFitClustersMax = 3; ///< maximum number of clusters fitted at the same time @@ -128,6 +132,8 @@ class ClusterFinderOriginal std::vector mClusters{}; ///< list of reconstructed clusters std::vector mUsedDigits{}; ///< list of digits used in reconstructed clusters + ErrorMap mErrorMap{}; ///< counting of encountered errors + PreClusterFinder mPreClusterFinder{}; ///< preclusterizer }; diff --git a/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx b/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx index 679d0ad8fc53d..76fe9672bd43f 100644 --- a/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx +++ b/Detectors/MUON/MCH/Clustering/src/ClusterFinderOriginal.cxx @@ -35,6 +35,7 @@ #include +#include "MCHBase/Error.h" #include "MCHBase/MathiesonOriginal.h" #include "MCHBase/ResponseParam.h" #include "MCHClustering/ClusterizerParam.h" @@ -603,6 +604,7 @@ void ClusterFinderOriginal::findLocalMaxima(std::unique_ptr& histAnode, } } if (localMaxima.size() > 99) { + mErrorMap.add(ErrorType::Clustering_TooManyLocalMaxima, mSegmentation->detElemId(), 0); LOG(warning) << "Too many local maxima !!!"; break; } diff --git a/Detectors/MUON/MCH/PreClustering/README.md b/Detectors/MUON/MCH/PreClustering/README.md index c9a29b6c6f175..bd80ead7e42d3 100644 --- a/Detectors/MUON/MCH/PreClustering/README.md +++ b/Detectors/MUON/MCH/PreClustering/README.md @@ -23,7 +23,7 @@ o2-mch-digits-to-preclusters-workflow Take as input the list of all digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) in the current time frame, with the data description "DIGITS", and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the digits associated to each interaction. The ROF records input can have the data description "inputrofs:MCH/DIGITROFS" if the direct output of the raw decoder is used, or "inputrofs:MCH/TIMECLUSTERROFS" if the time clustering output is used (default option). The ROF input description can be set on the command line via the `rof-spec` option. -Send the list of all preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) in the time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the preclusters associated to each interaction in three separate messages with the data description "PRECLUSTERS", "PRECLUSTERDIGITS" and "PRECLUSTERROFS", respectively. +Send the list of all preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) in the time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)), the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the preclusters associated to each interaction and the list of processing errors ([Error](../Base/include/MCHBase/Error.h)) in four separate messages with the data description "PRECLUSTERS", "PRECLUSTERDIGITS", "PRECLUSTERROFS" and "PRECLUSTERERRORS", respectively. ## Workflow / Spec options diff --git a/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h b/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h index a5e8f2f681dc8..867f995df416a 100644 --- a/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h +++ b/Detectors/MUON/MCH/PreClustering/include/MCHPreClustering/PreClusterFinder.h @@ -57,7 +57,8 @@ class PreClusterFinder void getPreClusters(std::vector& preClusters, std::vector& digits); - ErrorMap errorMap() const { return mErrorMap; } + /// return the counting of encountered errors + ErrorMap& getErrorMap() { return mErrorMap; } private: struct DetectionElement; @@ -93,9 +94,7 @@ class PreClusterFinder int mNPreClusters[SNDEs][2]{}; ///< number of preclusters in each cathods of each DE std::vector> mPreClusters[SNDEs][2]{}; ///< preclusters in each cathods of each DE - enum ErrorTypes : uint32_t { kMultipleDigitInSamePad = 0 }; - - ErrorMap mErrorMap; ///< counting of encountered errors + ErrorMap mErrorMap{}; ///< counting of encountered errors }; } // namespace mch diff --git a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx index 34acad63ca0b0..2c9820a102aaf 100644 --- a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx +++ b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinder.cxx @@ -19,6 +19,7 @@ #include #include +#include "MCHBase/Error.h" #include "PreClusterFinderMapping.h" namespace o2::mch @@ -65,13 +66,9 @@ void PreClusterFinder::init() void PreClusterFinder::deinit() { /// clear the internal structure - auto print = [](uint32_t /*errorType*/, uint32_t deId, uint32_t padid, - uint64_t count) { - LOGP(warning, "multiple digits on the same pad (DE {} pad {}): seen {} time{}", deId, padid, count, count > 1 ? "s" : ""); - }; - mErrorMap.forEach(print); reset(); mDEIndices.clear(); + mErrorMap.clear(); } //_________________________________________________________________________________________________ @@ -141,7 +138,7 @@ void PreClusterFinder::loadDigit(const Digit& digit) // check that the pad is not already fired if (de.mapping->pads[iPad].useMe) { - mErrorMap.add(kMultipleDigitInSamePad, digit.getDetID(), iPad); + mErrorMap.add(ErrorType::PreClustering_MultipleDigitsInSamePad, digit.getDetID(), iPad); return; } @@ -541,4 +538,4 @@ void PreClusterFinder::createMapping() LOG(info) << "create mapping in: " << std::chrono::duration(tEnd - tStart).count() << " ms"; } -} // namespace o2 +} // namespace o2::mch diff --git a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderSpec.cxx b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderSpec.cxx index 7e030c597be7a..4b0ecb7b17fe2 100644 --- a/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderSpec.cxx +++ b/Detectors/MUON/MCH/PreClustering/src/PreClusterFinderSpec.cxx @@ -35,9 +35,11 @@ #include "Framework/WorkflowSpec.h" #include "DataFormatsMCH/ROFRecord.h" +#include "MCHBase/Error.h" +#include "MCHBase/ErrorMap.h" #include "MCHBase/PreCluster.h" -#include "MCHPreClustering/PreClusterFinder.h" #include "MCHBase/SanityCheck.h" +#include "MCHPreClustering/PreClusterFinder.h" #include #include @@ -52,7 +54,7 @@ using namespace std; using namespace o2::framework; enum tCheckNoLeftoverDigits { - CHECK_NO_LEFTOVER_DIGITS_OFF, + CHECK_NO_LEFTOVER_DIGITS_QUIET, CHECK_NO_LEFTOVER_DIGITS_ERROR, CHECK_NO_LEFTOVER_DIGITS_FATAL }; @@ -80,12 +82,15 @@ class PreClusterFinderTask auto tEnd = std::chrono::high_resolution_clock::now(); LOG(info) << "deinitializing preclusterizer in: " << std::chrono::duration(tEnd - tStart).count() << " ms"; + mErrorMap.forEach([](Error error) { + LOGP(warning, error.asString()); + }); }; ic.services().get().set(CallbackService::Id::Stop, stop); auto checkNoLeftoverDigits = ic.options().get("check-no-leftover-digits"); - if (checkNoLeftoverDigits == "off") { - mCheckNoLeftoverDigits = CHECK_NO_LEFTOVER_DIGITS_OFF; + if (checkNoLeftoverDigits == "quiet") { + mCheckNoLeftoverDigits = CHECK_NO_LEFTOVER_DIGITS_QUIET; } else if (checkNoLeftoverDigits == "error") { mCheckNoLeftoverDigits = CHECK_NO_LEFTOVER_DIGITS_ERROR; } else if (checkNoLeftoverDigits == "fatal") { @@ -132,6 +137,8 @@ class PreClusterFinderTask // prepare to receive new data mPreClusters.clear(); mUsedDigits.clear(); + auto& errorMap = mPreClusterFinder.getErrorMap(); + errorMap.clear(); if (!abort) { @@ -174,30 +181,35 @@ class PreClusterFinderTask } // check sizes of input and output digits vectors - bool digitsSizesDiffer = (nRemovedDigits + mUsedDigits.size() != nDigitsInRofs); - switch (mCheckNoLeftoverDigits) { - case CHECK_NO_LEFTOVER_DIGITS_OFF: - break; - case CHECK_NO_LEFTOVER_DIGITS_ERROR: - if (digitsSizesDiffer) { + if (nRemovedDigits + mUsedDigits.size() != nDigitsInRofs) { + errorMap.add(ErrorType::PreClustering_LostDigit, 0, 0, nDigitsInRofs - nRemovedDigits - mUsedDigits.size()); + switch (mCheckNoLeftoverDigits) { + case CHECK_NO_LEFTOVER_DIGITS_QUIET: + break; + case CHECK_NO_LEFTOVER_DIGITS_ERROR: static int nAlarms = 0; if (nAlarms++ < 5) { LOG(warning) << "some digits have been lost during the preclustering"; } - } - break; - case CHECK_NO_LEFTOVER_DIGITS_FATAL: - if (digitsSizesDiffer) { + break; + case CHECK_NO_LEFTOVER_DIGITS_FATAL: throw runtime_error("some digits have been lost during the preclustering"); - } - break; - }; + break; + }; + } } // create the output messages for preclusters and associated digits pc.outputs().snapshot(OutputRef{"preclusters"}, mPreClusters); pc.outputs().snapshot(OutputRef{"preclusterdigits"}, mUsedDigits); + // create the output message for preclustering errors + auto& preClusterErrors = pc.outputs().make>(OutputRef{"preclustererrors"}); + errorMap.forEach([&preClusterErrors](Error error) { + preClusterErrors.emplace_back(error); + }); + mErrorMap.add(errorMap); + LOGP(info, "Processed {} digit rofs with {} digits and output {} precluster rofs with {} preclusters and {} digits", digitROFs.size(), nDigitsInRofs, @@ -209,6 +221,7 @@ class PreClusterFinderTask PreClusterFinder mPreClusterFinder{}; ///< preclusterizer std::vector mPreClusters{}; ///< vector of preclusters std::vector mUsedDigits{}; ///< vector of digits in the preclusters + ErrorMap mErrorMap{}; ///< counting of encountered errors int mCheckNoLeftoverDigits{CHECK_NO_LEFTOVER_DIGITS_ERROR}; ///< digits vector size check option bool mDiscardHighOccDEs = false; ///< discard DEs with occupancy > 20% @@ -230,14 +243,15 @@ o2::framework::DataProcessorSpec getPreClusterFinderSpec(const char* specName, fmt::format("digits:MCH/{}/0;digitrofs:MCH/{}/0", inputDigitDataDescription, inputDigitRofDataDescription); - std::string helpstr = "[off/error/fatal] check that all digits are included in pre-clusters"; + std::string helpstr = "[quiet/error/fatal] check that all digits are included in pre-clusters"; return DataProcessorSpec{ specName, o2::framework::select(input.c_str()), Outputs{OutputSpec{{"preclusterrofs"}, "MCH", "PRECLUSTERROFS", 0, Lifetime::Timeframe}, OutputSpec{{"preclusters"}, "MCH", "PRECLUSTERS", 0, Lifetime::Timeframe}, - OutputSpec{{"preclusterdigits"}, "MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}}, + OutputSpec{{"preclusterdigits"}, "MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}, + OutputSpec{{"preclustererrors"}, "MCH", "PRECLUSTERERRORS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask()}, Options{{"check-no-leftover-digits", VariantType::String, "error", {helpstr}}, {{"sanity-check"}, VariantType::Bool, false, {"perform some input digit sanity checks"}}, diff --git a/Detectors/MUON/MCH/Tracking/README.md b/Detectors/MUON/MCH/Tracking/README.md index bdee89b3e282f..a9240247347db 100644 --- a/Detectors/MUON/MCH/Tracking/README.md +++ b/Detectors/MUON/MCH/Tracking/README.md @@ -152,7 +152,7 @@ Take as input the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Det o2-mch-clusters-to-tracks-workflow ``` -Take as input the list of all clusters ([Cluster](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Cluster.h)) in the current time frame, with the data description "CLUSTERS", and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction, with the data description "CLUSTERROFS". Send the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) in the time frame, the list of all associated clusters ([Cluster](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Cluster.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the tracks associated to each interaction in three separate messages with the data description "TRACKS", "TRACKCLUSTERS" and "TRACKROFS", respectively. Depending on the options, it may also need as input the list of digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) associated to clusters, with the data description "CLUSTERDIGITS", and send the list of digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) associated to tracks, with the data description "TRACKDIGITS". +Take as input the list of all clusters ([Cluster](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Cluster.h)) in the current time frame, with the data description "CLUSTERS", and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction, with the data description "CLUSTERROFS". Send the list of all MCH tracks ([TrackMCH](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/TrackMCH.h)) in the time frame, the list of all associated clusters ([Cluster](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Cluster.h)), the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the tracks associated to each interaction and the list of processing errors ([Error](../Base/include/MCHBase/Error.h)) in four separate messages with the data description "TRACKS", "TRACKCLUSTERS", "TRACKROFS" and "TRACKERRORS", respectively. Depending on the options, it may also need as input the list of digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) associated to clusters, with the data description "CLUSTERDIGITS", and send the list of digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) associated to tracks, with the data description "TRACKDIGITS". #### Workflow / Spec options: diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h index db55a16957d94..97754fe16098f 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinder.h @@ -28,6 +28,7 @@ #include #include "DataFormatsMCH/Cluster.h" +#include "MCHBase/ErrorMap.h" #include "MCHTracking/Track.h" #include "MCHTracking/TrackFitter.h" @@ -53,6 +54,9 @@ class TrackFinder const std::list& findTracks(gsl::span clusters); + /// return the counting of encountered errors + ErrorMap& getErrorMap() { return mErrorMap; } + /// set the debug level defining the verbosity void debug(int debugLevel) { mDebugLevel = debugLevel; } @@ -141,6 +145,8 @@ class TrackFinder std::chrono::time_point mStartTime{}; ///< time when the tracking start + ErrorMap mErrorMap{}; ///< counting of encountered errors + double mChamberResolutionX2 = 0.; ///< chamber resolution square (cm^2) in x direction double mChamberResolutionY2 = 0.; ///< chamber resolution square (cm^2) in y direction double mBendingVertexDispersion2 = 0.; ///< vertex dispersion square (cm^2) in y direction diff --git a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h index 002a190891a62..319e9966846bc 100644 --- a/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h +++ b/Detectors/MUON/MCH/Tracking/include/MCHTracking/TrackFinderOriginal.h @@ -24,6 +24,7 @@ #include #include "DataFormatsMCH/Cluster.h" +#include "MCHBase/ErrorMap.h" #include "MCHTracking/Track.h" #include "MCHTracking/TrackFitter.h" @@ -49,6 +50,9 @@ class TrackFinderOriginal const std::list& findTracks(gsl::span clusters); + /// return the counting of encountered errors + ErrorMap& getErrorMap() { return mErrorMap; } + /// set the debug level defining the verbosity void debug(int debugLevel) { mDebugLevel = debugLevel; } @@ -102,6 +106,8 @@ class TrackFinderOriginal std::list mTracks{}; ///< list of reconstructed tracks + ErrorMap mErrorMap{}; ///< counting of encountered errors + double mChamberResolutionX2 = 0.; ///< chamber resolution square (cm^2) in x direction double mChamberResolutionY2 = 0.; ///< chamber resolution square (cm^2) in y direction double mBendingVertexDispersion2 = 0.; ///< vertex dispersion square (cm^2) in y direction diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx index a7f30d58b1ceb..980df4519ce4b 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFinder.cxx @@ -26,6 +26,7 @@ #include #include "Field/MagneticField.h" +#include "MCHBase/Error.h" #include "MCHBase/TrackerParam.h" #include "MCHTracking/TrackExtrap.h" @@ -833,6 +834,7 @@ std::list::iterator TrackFinder::followTrackInChamber(std::list::i std::chrono::duration currentTrackingDuration = std::chrono::steady_clock::now() - mStartTime; if (currentTrackingDuration.count() > TrackerParam::Instance().maxTrackingDuration) { + mErrorMap.add(ErrorType::Tracking_TooLong, 0, 0); throw length_error(string("Tracking is taking too long (") + std::round(currentTrackingDuration.count()) + " s)"); } @@ -1352,6 +1354,7 @@ void TrackFinder::createTrack(const Cluster& cl1, const Cluster& cl2) /// Throw an exception if the maximum number of tracks is exceeded if (mTracks.size() >= TrackerParam::Instance().maxCandidates) { + mErrorMap.add(ErrorType::Tracking_TooManyCandidates, 0, 0); throw length_error(string("Too many track candidates (") + mTracks.size() + ")"); } @@ -1377,6 +1380,7 @@ std::list::iterator TrackFinder::addTrack(const std::list::iterato /// Add the given track at the requested position in the list of tracks /// Throw an exception if the maximum number of tracks is exceeded if (mTracks.size() >= TrackerParam::Instance().maxCandidates) { + mErrorMap.add(ErrorType::Tracking_TooManyCandidates, 0, 0); throw length_error(string("Too many track candidates (") + mTracks.size() + ")"); } return mTracks.emplace(pos, track); diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx index be8f1fd8a9e0d..e6a81c718c0c6 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginal.cxx @@ -24,6 +24,7 @@ #include #include "Field/MagneticField.h" +#include "MCHBase/Error.h" #include "MCHBase/TrackerParam.h" #include "MCHTracking/TrackExtrap.h" @@ -119,7 +120,7 @@ const std::list& TrackFinderOriginal::findTracks(gsl::span mTimeFollowTracks += tEnd - tStart; } catch (exception const& e) { - LOG(error) << e.what() << " --> abort"; + LOG(warning) << e.what() << " --> abort"; mTracks.clear(); return mTracks; } @@ -410,6 +411,7 @@ void TrackFinderOriginal::createTrack(const Cluster& cl1, const Cluster& cl2) /// Throw an exception if the maximum number of tracks is exceeded if (mTracks.size() >= TrackerParam::Instance().maxCandidates) { + mErrorMap.add(ErrorType::Tracking_TooManyCandidates, 0, 0); throw length_error(string("Too many track candidates (") + mTracks.size() + ")"); } @@ -499,6 +501,7 @@ std::list::iterator TrackFinderOriginal::addTrack(const std::list: /// Add the given track at the requested position in the list of tracks /// Throw an exception if the maximum number of tracks is exceeded if (mTracks.size() >= TrackerParam::Instance().maxCandidates) { + mErrorMap.add(ErrorType::Tracking_TooManyCandidates, 0, 0); throw length_error(string("Too many track candidates (") + mTracks.size() + ")"); } return mTracks.emplace(pos, track); diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx index 8115a3ee94d85..f013f89f9d420 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx @@ -45,6 +45,8 @@ #include "DataFormatsParameters/GRPObject.h" #include "DetectorsBase/GRPGeomHelper.h" #include "DetectorsBase/Propagator.h" +#include "MCHBase/Error.h" +#include "MCHBase/ErrorMap.h" #include "MCHTracking/TrackParam.h" #include "MCHTracking/Track.h" #include "MCHTracking/TrackFinder.h" @@ -102,6 +104,9 @@ class TrackFinderTask mTrackFinder.printStats(); mTrackFinder.printTimers(); LOG(info) << "tracking duration = " << mElapsedTime.count() << " s"; + mErrorMap.forEach([](Error error) { + LOGP(warning, error.asString()); + }); }; ic.services().get().set(CallbackService::Id::Stop, stop); } @@ -147,6 +152,8 @@ class TrackFinderTask trackROFs.reserve(clusterROFs.size()); auto timeStart = std::chrono::high_resolution_clock::now(); + auto& errorMap = mTrackFinder.getErrorMap(); + errorMap.clear(); for (const auto& clusterROF : clusterROFs) { @@ -163,6 +170,13 @@ class TrackFinderTask clusterROF.getBCWidth()); } + // create the output message for tracking errors + auto& trackErrors = pc.outputs().make>(OutputRef{"trackerrors"}); + errorMap.forEach([&trackErrors](Error error) { + trackErrors.emplace_back(error); + }); + mErrorMap.add(errorMap); + auto timeEnd = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = timeEnd - timeStart; LOGP(info, "Found {:3d} MCH tracks from {:4d} clusters in {:2d} ROFs in {:8.0f} ms", @@ -259,6 +273,7 @@ class TrackFinderTask std::shared_ptr mCCDBRequest{}; ///< pointer to the CCDB requests float mTrackTime3Sigma{6.0}; ///< three times the digit time resolution, in BC units T mTrackFinder{}; ///< track finder + ErrorMap mErrorMap{}; ///< counting of encountered errors std::chrono::duration mElapsedTime{}; ///< timer }; @@ -280,6 +295,7 @@ o2::framework::DataProcessorSpec getTrackFinderSpec(const char* specName, bool c if (digits) { outputSpecs.emplace_back(OutputSpec{{"trackdigits"}, "MCH", "TRACKDIGITS", 0, Lifetime::Timeframe}); } + outputSpecs.emplace_back(OutputSpec{{"trackerrors"}, "MCH", "TRACKERRORS", 0, Lifetime::Timeframe}); auto ccdbRequest = disableCCDBMagField ? nullptr : std::make_shared(false, // orbitResetTime diff --git a/Detectors/MUON/MCH/Workflow/README.md b/Detectors/MUON/MCH/Workflow/README.md index 1b6bcaa977753..910be77bded8c 100644 --- a/Detectors/MUON/MCH/Workflow/README.md +++ b/Detectors/MUON/MCH/Workflow/README.md @@ -135,7 +135,7 @@ Group the digits in preclusters. [more...](/Detectors/MUON/MCH/PreClustering/REA o2-mch-preclusters-to-clusters-original-workflow ``` -Take as input the list of all preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) in the current time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the preclusters associated to each interaction, with the data description "PRECLUSTERS", "PRECLUSTERDIGITS" and "PRECLUSTERROFS", respectively. Send the list of all clusters ([Cluster](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Cluster.h)) in the time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction in three separate messages with the data description "CLUSTERS", "CLUSTERDIGITS" and "CLUSTERROFS", respectively. +Take as input the list of all preclusters ([PreCluster](../Base/include/MCHBase/PreCluster.h)) in the current time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)) and the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the preclusters associated to each interaction, with the data description "PRECLUSTERS", "PRECLUSTERDIGITS" and "PRECLUSTERROFS", respectively. Send the list of all clusters ([Cluster](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Cluster.h)) in the time frame, the list of all associated digits ([Digit](/DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/Digit.h)), the list of ROF records ([ROFRecord](../../../../DataFormats/Detectors/MUON/MCH/include/DataFormatsMCH/ROFRecord.h)) pointing to the clusters associated to each interaction and the list of processing errors ([Error](../Base/include/MCHBase/Error.h)) in four separate messages with the data description "CLUSTERS", "CLUSTERDIGITS", "CLUSTERROFS" and "CLUSTERERRORS", respectively. Option `--run2-config` allows to configure the clustering to process run2 data. diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx b/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx index 957643c40e2ce..b8945cc606ab6 100644 --- a/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx @@ -37,6 +37,8 @@ #include "CommonUtils/ConfigurableParam.h" #include "DataFormatsMCH/ROFRecord.h" #include "DataFormatsMCH/Digit.h" +#include "MCHBase/Error.h" +#include "MCHBase/ErrorMap.h" #include "MCHBase/PreCluster.h" #include "DataFormatsMCH/Cluster.h" #include "MCHClustering/ClusterFinderOriginal.h" @@ -70,6 +72,9 @@ class ClusterFinderOriginalTask /// Print the timer and clear the clusterizer when the processing is over ic.services().get().set(CallbackService::Id::Stop, [this]() { LOG(info) << "cluster finder duration = " << mTimeClusterFinder.count() << " s"; + mErrorMap.forEach([](Error error) { + LOGP(warning, error.asString()); + }); this->mClusterFinder.deinit(); }); } @@ -90,6 +95,8 @@ class ClusterFinderOriginalTask auto& usedDigits = pc.outputs().make>(OutputRef{"clusterdigits"}); clusterROFs.reserve(preClusterROFs.size()); + auto& errorMap = mClusterFinder.getErrorMap(); + errorMap.clear(); for (const auto& preClusterROF : preClusterROFs) { // prepare to clusterize the current ROF @@ -123,6 +130,13 @@ class ClusterFinderOriginalTask preClusterROF.getBCWidth()); } + // create the output message for clustering errors + auto& clusterErrors = pc.outputs().make>(OutputRef{"clustererrors"}); + errorMap.forEach([&clusterErrors](Error error) { + clusterErrors.emplace_back(error); + }); + mErrorMap.add(errorMap); + LOGP(info, "Found {:4d} clusters from {:4d} preclusters in {:2d} ROFs", clusters.size(), preClusters.size(), preClusterROFs.size()); } @@ -172,6 +186,7 @@ class ClusterFinderOriginalTask bool mAttachInitalPrecluster = false; ///< attach all digits of initial precluster to cluster ClusterFinderOriginal mClusterFinder{}; ///< clusterizer + ErrorMap mErrorMap{}; ///< counting of encountered errors std::chrono::duration mTimeClusterFinder{}; ///< timer }; @@ -185,7 +200,8 @@ o2::framework::DataProcessorSpec getClusterFinderOriginalSpec(const char* specNa InputSpec{"digits", "MCH", "PRECLUSTERDIGITS", 0, Lifetime::Timeframe}}, Outputs{OutputSpec{{"clusterrofs"}, "MCH", "CLUSTERROFS", 0, Lifetime::Timeframe}, OutputSpec{{"clusters"}, "MCH", "CLUSTERS", 0, Lifetime::Timeframe}, - OutputSpec{{"clusterdigits"}, "MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe}}, + OutputSpec{{"clusterdigits"}, "MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe}, + OutputSpec{{"clustererrors"}, "MCH", "CLUSTERERRORS", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask()}, Options{{"mch-config", VariantType::String, "", {"JSON or INI file with clustering parameters"}}, {"run2-config", VariantType::Bool, false, {"setup for run2 data"}},