diff --git a/Trigger/TrigSteer/TrigOutputHandling/python/TrigOutputHandlingConfig.py b/Trigger/TrigSteer/TrigOutputHandling/python/TrigOutputHandlingConfig.py index 5da5bd79be0b23c3074274be5589a74715ea4797..a3f488c27c9960bc8b1d789d95ba2e94150ae2f7 100644 --- a/Trigger/TrigSteer/TrigOutputHandling/python/TrigOutputHandlingConfig.py +++ b/Trigger/TrigSteer/TrigOutputHandling/python/TrigOutputHandlingConfig.py @@ -110,3 +110,18 @@ def TriggerBitsMakerToolCfg(name="TriggerBitsMakerTool"): # Extra configuration may come here return bitsmaker + +def DecisionSummaryMakerAlgCfg(name="DecisionSummaryMakerAlg"): + alg = CompFactory.DecisionSummaryMakerAlg(name) + from AthenaMonitoringKernel.GenericMonitoringTool import GenericMonitoringTool + alg.MonTool = GenericMonitoringTool('MonTool', HistPath='HLTFramework/'+name) + alg.MonTool.defineHistogram('RoIsDEta', path='EXPERT', type='TH1F', + title='Change of RoI eta position between initial and final RoI;delta eta;N final RoIs', + xbins=51, xmin=-1.02, xmax=1.02) + alg.MonTool.defineHistogram('RoIsDPhi', path='EXPERT', type='TH1F', + title='Change of RoI phi position between initial and final RoI;delta phi;N final RoIs', + xbins=51, xmin=-1.02, xmax=1.02) + alg.MonTool.defineHistogram('RoIsDZed', path='EXPERT', type='TH1F', + title='Change of RoI z position between initial and final RoI;delta z;N final RoIs', + xbins=51, xmin=-204, xmax=204) + return alg diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx index a3225afa47d438200d70b94e0a7a5babd0aa499e..e29f9b992f75a3ddf0a203e867a76ddf62e78583 100644 --- a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx +++ b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.cxx @@ -1,8 +1,10 @@ /* Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration */ -#include "TrigCompositeUtils/HLTIdentifier.h" #include "DecisionSummaryMakerAlg.h" +#include "TrigCompositeUtils/HLTIdentifier.h" +#include "TrigSteeringEvent/TrigRoiDescriptorCollection.h" +#include "CxxUtils/phihelper.h" DecisionSummaryMakerAlg::DecisionSummaryMakerAlg(const std::string& name, ISvcLocator* pSvcLocator) : AthReentrantAlgorithm(name, pSvcLocator) {} @@ -26,6 +28,9 @@ StatusCode DecisionSummaryMakerAlg::initialize() { ATH_CHECK( m_trigCostSvcHandle.retrieve() ); } ATH_CHECK( m_prescaler.retrieve() ); + if (!m_monTool.empty()) { + ATH_CHECK(m_monTool.retrieve()); + } return StatusCode::SUCCESS; } @@ -104,6 +109,9 @@ StatusCode DecisionSummaryMakerAlg::execute(const EventContext& context) const { } } + // Monitor RoI updates between initial and final RoI + monitorRoIs(passRawOutput); + // Get the data from the HLTSeeding, this is where prescales were applied SG::ReadHandle<DecisionContainer> hltSeedingSummary( m_hltSeedingSummaryKey, context ); const Decision* l1SeededChains = nullptr; // Activated by L1 @@ -168,3 +176,77 @@ StatusCode DecisionSummaryMakerAlg::execute(const EventContext& context) const { return StatusCode::SUCCESS; } + +void DecisionSummaryMakerAlg::monitorRoIs(const TrigCompositeUtils::Decision* terminusNode) const { + using namespace TrigCompositeUtils; + using RoILinkVec = std::vector<LinkInfo<TrigRoiDescriptorCollection>>; + + auto printDecision = [this](const Decision* d){ + ATH_MSG_INFO("The decision corresponds to chain(s):"); + for (const DecisionID id : decisionIDs(d)) { + ATH_MSG_INFO("-- " << HLT::Identifier(id).name()); + } + }; + auto printDecisionAndRoI = [this,&printDecision](const Decision* d, const TrigRoiDescriptor& roi){ + printDecision(d); + ATH_MSG_INFO("and final RoI: " << roi); + }; + + // Loop over all final RoIs + const RoILinkVec allFinalRoIs = findLinks<TrigRoiDescriptorCollection>(terminusNode, roiString(), TrigDefs::lastFeatureOfType); + for (const auto& finalRoILink : allFinalRoIs) { + // Get the final TrigRoiDescriptor reference + if (!finalRoILink.isValid() || *(finalRoILink.link)==nullptr) { + ATH_MSG_WARNING("Encountered invalid final RoI link"); + printDecision(finalRoILink.source); + continue; + } + const TrigRoiDescriptor& finalRoI = **(finalRoILink.link); + + // Skip full-scan + if (finalRoI.isFullscan()) {continue;} + + // Get all initial RoIs associated with this final RoI (should be exactly one) + const RoILinkVec initialRoIs = findLinks<TrigRoiDescriptorCollection>(finalRoILink.source, initialRoIString(), TrigDefs::lastFeatureOfType); + + // Warn if the number of initial RoIs differs from one + if (initialRoIs.empty()) { + ATH_MSG_WARNING("Encountered decision node with no " << initialRoIString() << " link"); + printDecisionAndRoI(finalRoILink.source, finalRoI); + continue; + } + if (initialRoIs.size()>1) { + ATH_MSG_WARNING("Encountered decision node with multiple (" << initialRoIs.size() << ") " + << initialRoIString() << " links"); + printDecisionAndRoI(finalRoILink.source, finalRoI); + } + + // Get the initial TrigRoiDescriptor reference + const auto& initialRoILink = initialRoIs.front(); + if (!initialRoILink.isValid() || *(initialRoILink.link)==nullptr) { + ATH_MSG_WARNING("Encountered invalid initial RoI link"); + printDecisionAndRoI(finalRoILink.source, finalRoI); + continue; + } + const TrigRoiDescriptor& initialRoI = **(initialRoILink.link); + + // Skip full-scan + if (initialRoI.isFullscan()) {continue;} + + // Fill the monitoring histograms + Monitored::Scalar dEta{"RoIsDEta", finalRoI.eta() - initialRoI.eta()}; + Monitored::Scalar dPhi{"RoIsDPhi", CxxUtils::deltaPhi(finalRoI.phi(), initialRoI.phi())}; + Monitored::Scalar dZed{"RoIsDZed", finalRoI.zed() - initialRoI.zed()}; + Monitored::Group(m_monTool, dEta, dPhi, dZed); + + // Print warnings on large updates + if (m_warnOnLargeRoIUpdates.value()) { + if (std::abs(dEta) > 1.0 || std::abs(dPhi) > 1.0 || std::abs(dZed) > 200) { + ATH_MSG_WARNING("Large RoI difference between initial and final RoI: " + << "dEta=" << dEta << ", dPhi=" << dPhi << ", dZed=" << dZed + << "initialRoI: " << initialRoI << ", finalRoI: " << finalRoI); + printDecision(finalRoILink.source); + } + } + } +} diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h index 6c126276321ff70e8c902663ffa9d2f72c63f2f6..121a6335d97fcdcf62ea8248581bac06e1cc610c 100644 --- a/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h +++ b/Trigger/TrigSteer/TrigOutputHandling/src/DecisionSummaryMakerAlg.h @@ -4,11 +4,12 @@ #ifndef TRIGOUTPUTHANDLING_DECISIONSUMMARYMAKERALG_H #define TRIGOUTPUTHANDLING_DECISIONSUMMARYMAKERALG_H -#include <string> -#include "AthenaBaseComps/AthReentrantAlgorithm.h" #include "TrigCompositeUtils/TrigCompositeUtils.h" #include "TrigCostMonitor/ITrigCostSvc.h" #include "HLTSeeding/IPrescalingTool.h" +#include "AthenaBaseComps/AthReentrantAlgorithm.h" +#include "AthenaMonitoringKernel/Monitored.h" +#include <string> /** @@ -26,6 +27,9 @@ public: virtual StatusCode finalize() override; private: + /// Monitor RoI updates between initial and final RoI + void monitorRoIs(const TrigCompositeUtils::Decision* terminusNode) const; + SG::WriteHandleKey<TrigCompositeUtils::DecisionContainer> m_summaryKey{ this, "DecisionsSummaryKey", "HLTNav_Summary", "Location of final decision" }; @@ -47,12 +51,18 @@ private: ToolHandle<IPrescalingTool> m_prescaler{this, "Prescaler", "PrescalingTool/PrescalingTool", "Prescaling tool used to determine express stream prescale decisions"}; + ToolHandle<GenericMonitoringTool> m_monTool { this, "MonTool", "", + "Monitoring tool" }; + Gaudi::Property< std::map< std::string, std::vector<std::string> > > m_lastStepForChain{ this, "FinalStepDecisions", {}, "The map of chain name to names of the collections in which the final decision is found" }; Gaudi::Property<bool> m_doCostMonitoring{this, "DoCostMonitoring", false, "Enables end-of-event cost monitoring behavior."}; + Gaudi::Property<bool> m_warnOnLargeRoIUpdates{this, "WarnOnLargeRoIUpdates", true, + "Print warnings from RoI update monitoring if the difference between initial and final RoI is large"}; + Gaudi::Property<bool> m_setFilterStatus{this, "SetFilterStatus", false, "Enables chain-passed filter. This will cause the downstream EDMCreator to not run if no chains pass, saving CPU in rejected events. " "Cannot be used in jobs producing RDO output."}; diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py index 862a57f84e83385e66fab5252ea638ff0d320953..25207ec6dffb92f3c33efaa503abe214f0d61617 100644 --- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py +++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py @@ -175,9 +175,9 @@ def triggerSummaryCfg(flags, hypos): Returns: ca, algorithm """ acc = ComponentAccumulator() - DecisionSummaryMakerAlg=CompFactory.DecisionSummaryMakerAlg from TrigEDMConfig.TriggerEDMRun3 import recordable - decisionSummaryAlg = DecisionSummaryMakerAlg() + from TrigOutputHandling.TrigOutputHandlingConfig import DecisionSummaryMakerAlgCfg + decisionSummaryAlg = DecisionSummaryMakerAlgCfg() chainToLastCollection = OrderedDict() # keys are chain names, values are lists of collections