From 2ee0c347fc702400e3faf667f150dd4cda774331 Mon Sep 17 00:00:00 2001 From: Rafal Bielski <rafal.bielski@cern.ch> Date: Tue, 3 Mar 2020 17:05:10 +0100 Subject: [PATCH 1/4] Add hooks for L1TriggerResult BS Converter --- .../TrigControl/TrigServices/CMakeLists.txt | 2 +- .../TrigServices/src/HltEventLoopMgr.cxx | 25 ++++++ .../TrigServices/src/HltEventLoopMgr.h | 8 ++ .../IL1TriggerByteStreamTool.h | 2 +- .../L1TriggerResultByteStreamCnv.h | 57 ++++++++++++ .../src/L1TriggerResultByteStreamCnv.cxx | 90 +++++++++++++++++++ .../TrigT1ResultByteStream_entries.cxx | 3 +- 7 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h create mode 100644 Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx diff --git a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt index 2d4a6096c81f..3d20158c9555 100644 --- a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt +++ b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt @@ -22,7 +22,7 @@ atlas_add_component( TrigServices ${TDAQ-COMMON_LIBRARIES} ${TDAQ_LIBRARIES} ${CORAL_LIBRARIES} AthenaBaseComps AthenaInterprocess AthenaKernel AthenaMonitoringKernelLib AthenaPoolUtilities ByteStreamCnvSvcBaseLib ByteStreamData EventInfoUtils GaudiKernel RDBAccessSvcLib StoreGateLib TrigKernel - TrigOutputHandlingLib TrigSteeringEvent xAODEventInfo ) + TrigOutputHandlingLib TrigSteeringEvent xAODEventInfo xAODTrigger ) # Install files from the package: atlas_install_python_modules( python/*.py diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx index ecda27029d09..da1f5678a833 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx +++ b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx @@ -202,6 +202,8 @@ StatusCode HltEventLoopMgr::initialize() // HLTResultMT ReadHandle (created dynamically from the result builder property) m_hltResultRHKey = m_hltResultMaker->resultName(); ATH_CHECK(m_hltResultRHKey.initialize()); + // L1TriggerResult ReadHandle + ATH_CHECK(m_l1TriggerResultRHKey.initialize(m_rewriteLVL1.value())); ATH_MSG_VERBOSE("end of " << __FUNCTION__); return StatusCode::SUCCESS; @@ -1280,6 +1282,28 @@ HltEventLoopMgr::DrainSchedulerStatusCode HltEventLoopMgr::drainScheduler() HLT_DRAINSCHED_CHECK(sc, "Conversion service failed to convert HLTResult", HLT::OnlineErrorCode::OUTPUT_BUILD_FAILURE, thisFinishedEvtContext); + // Retrieve and convert the L1 result to the output data format + IOpaqueAddress* l1addr = nullptr; + if (m_rewriteLVL1) { + auto l1TriggerResult = SG::makeHandle(m_l1TriggerResultRHKey, *thisFinishedEvtContext); + if (!l1TriggerResult.isValid()) markFailed(); + HLT_DRAINSCHED_CHECK(sc, "Failed to retrieve the L1 Trigger Result for RewriteLVL1", + HLT::OnlineErrorCode::OUTPUT_BUILD_FAILURE, thisFinishedEvtContext); + + DataObject* l1TriggerResultDO = m_evtStore->accessData(l1TriggerResult.clid(),l1TriggerResult.key()); + if (!l1TriggerResultDO) markFailed(); + HLT_DRAINSCHED_CHECK(sc, "Failed to retrieve the L1 Trigger Result DataObject for RewriteLVL1", + HLT::OnlineErrorCode::OUTPUT_BUILD_FAILURE, thisFinishedEvtContext); + + sc = m_outputCnvSvc->createRep(l1TriggerResultDO,l1addr); + if (sc.isFailure()) { + delete l1addr; + atLeastOneFailed = true; + } + HLT_DRAINSCHED_CHECK(sc, "Conversion service failed to convert L1 Trigger Result for RewriteLVL1", + HLT::OnlineErrorCode::OUTPUT_BUILD_FAILURE, thisFinishedEvtContext); + } + // Save event processing time before sending output bool eventAccepted = !hltResult->getStreamTags().empty(); auto eventTime = std::chrono::steady_clock::now() - m_eventTimerStartPoint[thisFinishedEvtContext->slot()]; @@ -1296,6 +1320,7 @@ HltEventLoopMgr::DrainSchedulerStatusCode HltEventLoopMgr::drainScheduler() // The output has been sent out, the ByteStreamAddress can be deleted delete addr; + delete l1addr; //-------------------------------------------------------------------------- // Flag idle slot to the timeout thread and reset the timer diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.h b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.h index b797037052d2..8933575fa87f 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.h +++ b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.h @@ -17,6 +17,7 @@ #include "AthenaMonitoringKernel/Monitored.h" #include "CxxUtils/checker_macros.h" #include "xAODEventInfo/EventInfo.h" +#include "xAODTrigger/TrigCompositeContainer.h" #include "StoreGate/ReadHandleKey.h" #include "StoreGate/WriteHandleKey.h" @@ -235,12 +236,19 @@ private: Gaudi::Property<unsigned long long> m_forceSOR_ns{ this, "forceStartOfRunTime", 0, "Override SOR time during prepareForRun (epoch in nano-seconds)"}; + Gaudi::Property<bool> m_rewriteLVL1{ + this, "RewriteLVL1", false, + "Encode L1 results to ByteStream and write to the output. Possible only with athenaHLT, not online."}; + SG::WriteHandleKey<EventContext> m_eventContextWHKey{ this, "EventContextWHKey", "EventContext", "StoreGate key for recording EventContext"}; SG::ReadHandleKey<xAOD::EventInfo> m_eventInfoRHKey{ this, "EventInfoRHKey", "EventInfo", "StoreGate key for reading xAOD::EventInfo"}; + SG::ReadHandleKey<xAOD::TrigCompositeContainer> m_l1TriggerResultRHKey{ + this, "L1TriggerResultRHKey", "L1TriggerResult", "StoreGate key for reading L1TriggerResult for RewriteLVL1"}; + SG::ReadHandleKey<HLT::HLTResultMT> m_hltResultRHKey; ///< StoreGate key for reading the HLT result // ------------------------- Other private members --------------------------- diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h index 300b84b6efa4..7dc2720e1217 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h +++ b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h @@ -5,8 +5,8 @@ #define TRIGT1RESULTBYTESTREAM_IL1TRIGGERBYTESTREAMTOOL_H #include "ByteStreamData/RawEvent.h" -#include "xAODTrigger/TrigComposite.h" #include "GaudiKernel/IAlgTool.h" +#include "GaudiKernel/EventContext.h" /** * @class IL1TriggerByteStreamTool diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h new file mode 100644 index 000000000000..2bc7e8b2a1d2 --- /dev/null +++ b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TRIGT1RESULTBYTESTREAM_L1TRIGGERRESULTBYTESTREAMCNV_H +#define TRIGT1RESULTBYTESTREAM_L1TRIGGERRESULTBYTESTREAMCNV_H + +// Trigger includes +// #include "TrigHLTResultByteStream/HLTSrcIdMap.h" + +// Athena includes +#include "AthenaBaseComps/AthMessaging.h" +#include "ByteStreamCnvSvcBase/IByteStreamEventAccess.h" +#include "ByteStreamCnvSvcBase/FullEventAssembler.h" + +// Gaudi includes +#include "GaudiKernel/Converter.h" + +/** @class L1TriggerResultByteStreamCnv + * @brief ByteStream converter for L1TriggerResult + **/ +class L1TriggerResultByteStreamCnv : public Converter, public AthMessaging { +public: + /// Standard constructor + L1TriggerResultByteStreamCnv(ISvcLocator* svcLoc); + /// Standard destructor + virtual ~L1TriggerResultByteStreamCnv(); + + // ------------------------- Converter methods ----------------------------- + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + + /// Create xAOD (L1TriggerResult) from ByteStream + virtual StatusCode createObj(IOpaqueAddress* pAddr, DataObject*& pObj) override; + /// Create ByteStream from xAOD (L1TriggerResult) + virtual StatusCode createRep(DataObject* pObj, IOpaqueAddress*& pAddr) override; + + // ------------------------- Converter definition helpers ------------------ + /// Storage type used by this converter + static long storageType(); + /// CLID of the class of the L1TriggerResult converted by this converter (xAOD::TrigCompositeContainer) + static const CLID& classID(); + + long repSvcType() const override { return i_repSvcType(); } //!< return repSvcType + +private: + /// Helper to obtain the RawEvent pointer + ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; + + /// Helper for filling ROBFragments + // FullEventAssembler<HLTSrcIdMap> m_fullEventAssembler; + + /// Buffer for serialised StreamTag data + std::unique_ptr<uint32_t[]> m_streamTagData; +}; + +#endif // TRIGT1RESULTBYTESTREAM_L1TRIGGERRESULTBYTESTREAMCNV_H diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx new file mode 100644 index 000000000000..46ae5e49a77e --- /dev/null +++ b/Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx @@ -0,0 +1,90 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +// Trigger includes +#include "TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h" +#include "xAODTrigger/TrigCompositeContainer.h" + +// Athena includes +#include "AthenaBaseComps/AthCheckMacros.h" +#include "AthenaKernel/ClassID_traits.h" +#include "AthenaKernel/StorableConversions.h" +#include "ByteStreamCnvSvcBase/ByteStreamAddress.h" +#include "ByteStreamData/RawEvent.h" + +// Gaudi includes +#include "GaudiKernel/IRegistry.h" + +// TDAQ includes +#include "eformat/Issue.h" +#include "eformat/SourceIdentifier.h" + +// ============================================================================= +// Standard constructor +// ============================================================================= +L1TriggerResultByteStreamCnv::L1TriggerResultByteStreamCnv(ISvcLocator* svcLoc) : + Converter(storageType(), classID(), svcLoc), + AthMessaging(msgSvc(), "L1TriggerResultByteStreamCnv"), + m_ByteStreamEventAccess("ByteStreamCnvSvc", "L1TriggerResultByteStreamCnv") { + // m_fullEventAssembler.idMap().setDetId(eformat::TDAQ_HLT); + // m_fullEventAssembler.setRodMinorVersion(hltRodMinorVersion); + } + +// ============================================================================= +// Standard destructor +// ============================================================================= +L1TriggerResultByteStreamCnv::~L1TriggerResultByteStreamCnv() {} + +// ============================================================================= +// Implementation of Converter::initialize +// ============================================================================= +StatusCode L1TriggerResultByteStreamCnv::initialize() { + ATH_MSG_VERBOSE("start of " << __FUNCTION__); + ATH_CHECK(m_ByteStreamEventAccess.retrieve()); + ATH_MSG_VERBOSE("end of " << __FUNCTION__); + return StatusCode::SUCCESS; +} + +// ============================================================================= +// Implementation of Converter::finalize +// ============================================================================= +StatusCode L1TriggerResultByteStreamCnv::finalize() { + ATH_MSG_VERBOSE("start of " << __FUNCTION__); + if (m_ByteStreamEventAccess.release().isFailure()) + ATH_MSG_WARNING("Failed to release service " << m_ByteStreamEventAccess.typeAndName()); + ATH_MSG_VERBOSE("end of " << __FUNCTION__); + return StatusCode::SUCCESS; +} + +// ============================================================================= +// Implementation of Converter::createObj +// ============================================================================= +StatusCode L1TriggerResultByteStreamCnv::createObj(IOpaqueAddress* /*pAddr*/, DataObject*& /*pObj*/) { + ATH_MSG_ERROR("L1TriggerResult cannot be created directly from ByteStream!" + << " Use the L1TriggerResultMaker algorithm instead"); + return StatusCode::FAILURE; +} + +// ============================================================================= +// Implementation of Converter::createRep +// ============================================================================= +StatusCode L1TriggerResultByteStreamCnv::createRep(DataObject* pObj, IOpaqueAddress*& pAddr) { + ATH_MSG_VERBOSE("start of " << __FUNCTION__); + + ATH_MSG_INFO("RB: Hello, this is " << __FUNCTION__); + + ATH_MSG_VERBOSE("end of " << __FUNCTION__); + return StatusCode::SUCCESS; +} + +// ============================================================================= +// CLID / storageType +// ============================================================================= +const CLID& L1TriggerResultByteStreamCnv::classID() { + return ClassID_traits<xAOD::TrigCompositeContainer>::ID(); +} + +long L1TriggerResultByteStreamCnv::storageType() { + return ByteStreamAddress::storageType(); +} diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/src/components/TrigT1ResultByteStream_entries.cxx b/Trigger/TrigT1/TrigT1ResultByteStream/src/components/TrigT1ResultByteStream_entries.cxx index 8c5b33ce982b..2f65b961e984 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/src/components/TrigT1ResultByteStream_entries.cxx +++ b/Trigger/TrigT1/TrigT1ResultByteStream/src/components/TrigT1ResultByteStream_entries.cxx @@ -1,4 +1,4 @@ - +#include "TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h" #include "TrigT1ResultByteStream/RoIBResultByteStreamCnv.h" #include "TrigT1ResultByteStream/RecRoIBResultByteStreamCnv.h" @@ -26,6 +26,7 @@ typedef RoIBResultByteStreamCnv<ROBF> RoIBResultByteStreamCnvT ; typedef RecRoIBResultByteStreamCnv<ROBF> RecRoIBResultByteStreamCnvT ; // declare +DECLARE_CONVERTER( L1TriggerResultByteStreamCnv ) DECLARE_CONVERTER( RoIBResultByteStreamCnvT ) DECLARE_CONVERTER( RecRoIBResultByteStreamCnvT ) DECLARE_CONVERTER( MuCTPIByteStreamCnv ) -- GitLab From 30229b2de717fdc45615bc2bd390142f9681db94 Mon Sep 17 00:00:00 2001 From: Rafal Bielski <rafal.bielski@cern.ch> Date: Tue, 3 Mar 2020 18:23:09 +0100 Subject: [PATCH 2/4] Implement L1 BS encoding example --- .../TrigServices/src/HltEventLoopMgr.cxx | 5 ++ .../IL1TriggerByteStreamTool.h | 2 +- .../L1TriggerResultByteStreamCnv.h | 16 ++--- .../python/TrigT1ResultByteStreamConfig.py | 44 ++++++++++--- .../src/ExampleL1TriggerByteStreamTool.cxx | 27 +++++++- .../src/ExampleL1TriggerByteStreamTool.h | 2 +- .../src/L1TriggerResultByteStreamCnv.cxx | 61 +++++++++++++++++-- .../TriggerJobOpts/python/Modifiers.py | 27 ++------ 8 files changed, 138 insertions(+), 46 deletions(-) diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx index da1f5678a833..f8db3ec7761d 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx +++ b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx @@ -130,6 +130,11 @@ StatusCode HltEventLoopMgr::initialize() ATH_MSG_INFO(" ---> AlgErrorDebugStreamName = " << m_algErrorDebugStreamName.value()); ATH_MSG_INFO(" ---> TimeoutDebugStreamName = " << m_timeoutDebugStreamName.value()); ATH_MSG_INFO(" ---> TruncationDebugStreamName = " << m_truncationDebugStreamName.value()); + ATH_MSG_INFO(" ---> SORPath = " << m_sorPath.value()); + ATH_MSG_INFO(" ---> setMagFieldFromPtree = " << m_setMagFieldFromPtree.value()); + ATH_MSG_INFO(" ---> forceRunNumber = " << m_forceRunNumber.value()); + ATH_MSG_INFO(" ---> forceStartOfRunTime = " << m_forceSOR_ns.value()); + ATH_MSG_INFO(" ---> RewriteLVL1 = " << m_rewriteLVL1.value()); ATH_MSG_INFO(" ---> EventContextWHKey = " << m_eventContextWHKey.key()); ATH_MSG_INFO(" ---> EventInfoRHKey = " << m_eventInfoRHKey.key()); diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h index 7dc2720e1217..306f3883370a 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h +++ b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h @@ -32,7 +32,7 @@ public: * The implementation should take the xAOD RoI object from the event store using a ReadHandle it declares, * convert it to raw data, and fill the vrobf vector. **/ - virtual StatusCode convertToBS(std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*>& vrobf, + virtual StatusCode convertToBS(std::vector<OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment*>& vrobf, const EventContext& eventContext) const = 0; /** diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h index 2bc7e8b2a1d2..d069fb6c0500 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h +++ b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/L1TriggerResultByteStreamCnv.h @@ -1,12 +1,12 @@ /* - Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ #ifndef TRIGT1RESULTBYTESTREAM_L1TRIGGERRESULTBYTESTREAMCNV_H #define TRIGT1RESULTBYTESTREAM_L1TRIGGERRESULTBYTESTREAMCNV_H // Trigger includes -// #include "TrigHLTResultByteStream/HLTSrcIdMap.h" +#include "TrigT1ResultByteStream/IL1TriggerByteStreamTool.h" // Athena includes #include "AthenaBaseComps/AthMessaging.h" @@ -47,11 +47,13 @@ private: /// Helper to obtain the RawEvent pointer ServiceHandle<IByteStreamEventAccess> m_ByteStreamEventAccess; - /// Helper for filling ROBFragments - // FullEventAssembler<HLTSrcIdMap> m_fullEventAssembler; - - /// Buffer for serialised StreamTag data - std::unique_ptr<uint32_t[]> m_streamTagData; + // Tools performing the decoding work - *public* tools hard-coded in C++ because of Converter interface limitations + /// Encoder tool for L1Muon RoIs + ToolHandle<IL1TriggerByteStreamTool> m_muonEncoderTool; + // Placeholder for other L1 xAOD outputs: + // - CTP result + // - L1Topo result + // - L1Calo (Run3) RoIs }; #endif // TRIGT1RESULTBYTESTREAM_L1TRIGGERRESULTBYTESTREAMCNV_H diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/python/TrigT1ResultByteStreamConfig.py b/Trigger/TrigT1/TrigT1ResultByteStream/python/TrigT1ResultByteStreamConfig.py index f746167aab49..80ca34dac0d1 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/python/TrigT1ResultByteStreamConfig.py +++ b/Trigger/TrigT1/TrigT1ResultByteStream/python/TrigT1ResultByteStreamConfig.py @@ -14,17 +14,30 @@ def RoIBResultDecoderCfg(flags): acc.addEventAlgo(decoderAlg) return acc +from TrigT1ResultByteStream.TrigT1ResultByteStreamConf import ExampleL1TriggerByteStreamTool as _ExampleL1TriggerByteStreamTool +class ExampleL1TriggerByteStreamTool(_ExampleL1TriggerByteStreamTool): + def __init__(self, name, writeBS=False, *args, **kwargs): + super(ExampleL1TriggerByteStreamTool, self).__init__(name, *args, **kwargs) + from libpyeformat_helper import SourceIdentifier,SubDetector + muctpi_moduleid = 1 + muctpi_robid = int(SourceIdentifier(SubDetector.TDAQ_MUON_CTP_INTERFACE, muctpi_moduleid)) + self.MUCTPIModuleId = muctpi_moduleid + self.ROBIDs = [muctpi_robid] + if writeBS: + # write BS == read xAOD + self.MuonRoIContainerReadKey="LVL1MuonRoIs" + self.MuonRoIContainerWriteKey="" + else: + # read BS == write xAOD + self.MuonRoIContainerReadKey="" + self.MuonRoIContainerWriteKey="LVL1MuonRoIs" + def L1TriggerByteStreamDecoderCfg(flags): - from TrigT1ResultByteStream.TrigT1ResultByteStreamConf import L1TriggerByteStreamDecoderAlg,ExampleL1TriggerByteStreamTool - from libpyeformat_helper import SourceIdentifier,SubDetector + from TrigT1ResultByteStream.TrigT1ResultByteStreamConf import L1TriggerByteStreamDecoderAlg + from TrigT1ResultByteStream.TrigT1ResultByteStreamConfig import ExampleL1TriggerByteStreamTool # Placeholder for real decoder tools - now it's just an example - muctpi_moduleid = 1 - muctpi_robid = int(SourceIdentifier(SubDetector.TDAQ_MUON_CTP_INTERFACE, muctpi_moduleid)) - exampleTool = ExampleL1TriggerByteStreamTool(ROBIDs=[muctpi_robid], - MUCTPIModuleId=muctpi_moduleid, - MuonRoIContainerWriteKey="LVL1MuonRoIs") - + exampleTool = ExampleL1TriggerByteStreamTool(name="L1MuonBSDecoderTool", writeBS=False) decoderTools = [exampleTool] decoderAlg = L1TriggerByteStreamDecoderAlg(name="L1TriggerByteStreamDecoder", @@ -35,6 +48,15 @@ def L1TriggerByteStreamDecoderCfg(flags): acc.addEventAlgo(decoderAlg) return acc +def L1TriggerByteStreamEncoderCfg(flags): + from TrigT1ResultByteStream.TrigT1ResultByteStreamConfig import ExampleL1TriggerByteStreamTool + exampleTool = ExampleL1TriggerByteStreamTool(name="L1MuonBSEncoderTool", writeBS=True) + + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + acc = ComponentAccumulator() + acc.addPublicTool(exampleTool) + return acc + def L1ByteStreamDecodersRecExSetup(enableRun2L1=True, enableRun3L1=True): # Use new-style config from the above functions and import into old-style JO from AthenaConfiguration.ComponentAccumulator import CAtoGlobalWrapper @@ -43,3 +65,9 @@ def L1ByteStreamDecodersRecExSetup(enableRun2L1=True, enableRun3L1=True): CAtoGlobalWrapper(RoIBResultDecoderCfg,ConfigFlags) if enableRun3L1: CAtoGlobalWrapper(L1TriggerByteStreamDecoderCfg,ConfigFlags) + +def L1ByteStreamEncodersRecExSetup(): + # Use new-style config from the above functions and import into old-style JO + from AthenaConfiguration.ComponentAccumulator import CAtoGlobalWrapper + from AthenaConfiguration.AllConfigFlags import ConfigFlags + CAtoGlobalWrapper(L1TriggerByteStreamEncoderCfg,ConfigFlags) diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx index 716f047ce303..63e20d66a8db 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx +++ b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx @@ -6,8 +6,10 @@ #include "xAODTrigger/MuonRoI.h" #include "xAODTrigger/MuonRoIAuxContainer.h" #include "eformat/SourceIdentifier.h" +#include "eformat/Status.h" using ROBF = OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment; +using WROBF = OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment; ExampleL1TriggerByteStreamTool::ExampleL1TriggerByteStreamTool(const std::string& type, const std::string& name, @@ -55,6 +57,7 @@ StatusCode ExampleL1TriggerByteStreamTool::convertFromBS(const std::vector<const const uint32_t* data = rob->rod_data(); ATH_MSG_DEBUG("Starting to decode " << ndata << " ROD words"); for (uint32_t i=0; i<ndata; ++i, ++data) { + ATH_MSG_DEBUG("Muon RoI raw word: " << *data); // Here comes the decoding // Using some dummy values as this is not real decoding, just an example handle->push_back(new xAOD::MuonRoI); @@ -66,13 +69,33 @@ StatusCode ExampleL1TriggerByteStreamTool::convertFromBS(const std::vector<const } /// xAOD->BS conversion -StatusCode ExampleL1TriggerByteStreamTool::convertToBS(std::vector<const ROBF*>& /*vrobf*/, +StatusCode ExampleL1TriggerByteStreamTool::convertToBS(std::vector<WROBF*>& vrobf, const EventContext& eventContext) const { // Retrieve the RoI container auto muonRoIs = SG::makeHandle(m_roiReadKey, eventContext); ATH_CHECK(muonRoIs.isValid()); - // TODO: implement this part when new code requesting the xAOD->BS conversion is implemented (ATR-19542) + ATH_MSG_DEBUG("Converting " << muonRoIs->size() << " L1 Muon RoIs to ByteStream"); + std::unique_ptr<uint32_t[]> data = std::make_unique<uint32_t[]>(muonRoIs->size()); + for (size_t i=0; i<muonRoIs->size(); ++i) { + data[i] = muonRoIs->at(i)->roiWord(); + } + + const eformat::helper::SourceIdentifier sid(eformat::TDAQ_MUON_CTP_INTERFACE, m_muCTPIModuleID.value()); + const EventIDBase& eid = eventContext.eventID(); + // The WROBF allocated here and the data buffer inside it have to be deleted + // by the TrigByteStreamCnvSvc after writing to the output file + vrobf.push_back(new WROBF( + sid.code(), + eid.run_number(), + eid.event_number(), + eid.bunch_crossing_id(), + 0, // lvl1_type will be overwritten downstream from full event fragment + 0, // detev_type is system-specific + muonRoIs->size(), + std::move(data.release()), + eformat::STATUS_BACK // status_position is system-specific + )); return StatusCode::SUCCESS; } diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h index dd6c72cf0c7a..cee710ee3a6d 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h +++ b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h @@ -37,7 +37,7 @@ public: virtual StatusCode convertFromBS(const std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*>& vrobf, const EventContext& eventContext) const override; /// xAOD->BS conversion - virtual StatusCode convertToBS(std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*>& vrobf, + virtual StatusCode convertToBS(std::vector<OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment*>& vrobf, const EventContext& eventContext) const override; /// Declare ROB IDs for conversion virtual const std::vector<uint32_t> robIds() const override {return m_robIds.value();} diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx b/Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx index 46ae5e49a77e..67f6170e9e41 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx +++ b/Trigger/TrigT1/TrigT1ResultByteStream/src/L1TriggerResultByteStreamCnv.cxx @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ // Trigger includes @@ -15,21 +15,22 @@ // Gaudi includes #include "GaudiKernel/IRegistry.h" +#include "GaudiKernel/ThreadLocalContext.h" // TDAQ includes #include "eformat/Issue.h" #include "eformat/SourceIdentifier.h" +using WROBF = OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment; + // ============================================================================= // Standard constructor // ============================================================================= L1TriggerResultByteStreamCnv::L1TriggerResultByteStreamCnv(ISvcLocator* svcLoc) : Converter(storageType(), classID(), svcLoc), AthMessaging(msgSvc(), "L1TriggerResultByteStreamCnv"), - m_ByteStreamEventAccess("ByteStreamCnvSvc", "L1TriggerResultByteStreamCnv") { - // m_fullEventAssembler.idMap().setDetId(eformat::TDAQ_HLT); - // m_fullEventAssembler.setRodMinorVersion(hltRodMinorVersion); - } + m_ByteStreamEventAccess("ByteStreamCnvSvc", "L1TriggerResultByteStreamCnv"), + m_muonEncoderTool("ExampleL1TriggerByteStreamTool/ToolSvc.L1MuonBSEncoderTool") {} // ============================================================================= // Standard destructor @@ -42,6 +43,8 @@ L1TriggerResultByteStreamCnv::~L1TriggerResultByteStreamCnv() {} StatusCode L1TriggerResultByteStreamCnv::initialize() { ATH_MSG_VERBOSE("start of " << __FUNCTION__); ATH_CHECK(m_ByteStreamEventAccess.retrieve()); + ATH_CHECK(m_muonEncoderTool.retrieve()); + ATH_MSG_VERBOSE("end of " << __FUNCTION__); return StatusCode::SUCCESS; } @@ -53,6 +56,8 @@ StatusCode L1TriggerResultByteStreamCnv::finalize() { ATH_MSG_VERBOSE("start of " << __FUNCTION__); if (m_ByteStreamEventAccess.release().isFailure()) ATH_MSG_WARNING("Failed to release service " << m_ByteStreamEventAccess.typeAndName()); + if (m_muonEncoderTool.release().isFailure()) + ATH_MSG_WARNING("Failed to release tool " << m_muonEncoderTool.typeAndName()); ATH_MSG_VERBOSE("end of " << __FUNCTION__); return StatusCode::SUCCESS; } @@ -72,7 +77,51 @@ StatusCode L1TriggerResultByteStreamCnv::createObj(IOpaqueAddress* /*pAddr*/, Da StatusCode L1TriggerResultByteStreamCnv::createRep(DataObject* pObj, IOpaqueAddress*& pAddr) { ATH_MSG_VERBOSE("start of " << __FUNCTION__); - ATH_MSG_INFO("RB: Hello, this is " << __FUNCTION__); + // Cast the DataObject to L1TriggerResult + xAOD::TrigCompositeContainer* l1TriggerResult = nullptr; + bool castSuccessful = SG::fromStorable(pObj, l1TriggerResult); + if (!castSuccessful || !l1TriggerResult) { + ATH_MSG_ERROR("Failed to convert DataObject to xAOD::TrigCompositeContainer for L1TriggerResult"); + return StatusCode::FAILURE; + } + + // Obtain the RawEventWrite (aka eformat::write::FullEventFragment) pointer + RawEventWrite* re = m_ByteStreamEventAccess->getRawEvent(); + if (!re) { + ATH_MSG_ERROR("Failed to obtain a pointer to RawEventWrite"); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("Obtained RawEventWrite pointer = " << re); + + // CTP encoding should come here when implemented and update full event header (L1 trigger bits) + // in addition to encoding the corresponding ROBFragment. + // The xAOD CTP result object holding the bits will be obtained here via ElementLink from l1TriggerResult + + // Example muon RoI encoding - placeholder for concrete implementation + std::vector<WROBF*> muon_robs; + ATH_CHECK(m_muonEncoderTool->convertToBS(muon_robs, Gaudi::Hive::currentContext())); // TODO: find a way to avoid ThreadLocalContext + ATH_MSG_DEBUG("Created " << muon_robs.size() << " L1Muon ROB Fragments"); + for (WROBF* rob : muon_robs) { + if (msgLvl(MSG::DEBUG)) { + const uint32_t ndata = rob->rod_ndata(); + const uint32_t* data = rob->rod_data(); + ATH_MSG_DEBUG("This ROB has " << ndata << " data words"); + for (uint32_t i=0; i<ndata; ++i, ++data) { + ATH_MSG_DEBUG("--- " << MSG::hex << *data << MSG::dec); + } + } + // Set LVL1 Trigger Type from the full event + rob->rod_lvl1_type(re->lvl1_trigger_type()); + // Add the ROBFragment to the full event + re->append(rob); + ATH_MSG_DEBUG("Added ROB fragment " << MSG::hex << rob->source_id() << MSG::dec << " to the output raw event"); + } + + // Placeholder for other systems: L1Topo, L1Calo + + // Create a ByteStreamAddress for L1TriggerResult + ByteStreamAddress* bsAddr = new ByteStreamAddress(classID(), pObj->registry()->name(), ""); + pAddr = static_cast<IOpaqueAddress*>(bsAddr); ATH_MSG_VERBOSE("end of " << __FUNCTION__); return StatusCode::SUCCESS; diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/Modifiers.py b/Trigger/TriggerCommon/TriggerJobOpts/python/Modifiers.py index 21ccb15e1517..932b1d6de013 100644 --- a/Trigger/TriggerCommon/TriggerJobOpts/python/Modifiers.py +++ b/Trigger/TriggerCommon/TriggerJobOpts/python/Modifiers.py @@ -770,33 +770,18 @@ class rewriteLVL1(_modifier): Rewrite LVL1 (use together with rerunLVL1) """ # Example: - # athena -c "testPhysicsV3=1;rerunLVL1=1;rewriteLVL1=1;doLVL2=False;doEF=False;BSRDOInput='input.data'" TriggerJobOpts/runHLT_standalone.py + # athenaHLT -c "setMenu='PhysicsP1_pp_run3_v1';rerunLVL1=True;rewriteLVL1=True;" --filesInput=input.data TriggerJobOpts/runHLT_standalone.py + + def preSetup(self): + from TrigT1ResultByteStream.TrigT1ResultByteStreamConfig import L1ByteStreamEncodersRecExSetup + L1ByteStreamEncodersRecExSetup() def postSetup(self): from AthenaCommon.AppMgr import ServiceMgr as svcMgr - from AthenaCommon.AthenaCommonFlags import athenaCommonFlags from TriggerJobOpts.TriggerFlags import TriggerFlags - # Process all events - theApp.EvtMax = -1 TriggerFlags.writeBS = True - - athenaCommonFlags.BSRDOOutput = 'AppName=Athena, OutputDirectory=./, FileTag=testWrite' - # Persistent BS construction and intialization - from ByteStreamCnvSvc import WriteByteStream - StreamBSFileOutput = WriteByteStream.getStream("EventStorage","StreamBSFileOutput") - - # Bytestream conversion - StreamBSFileOutput.ItemList += [ "ROIB::RoIBResult#*" ] - - # Merge with original bytestream - from ByteStreamCnvSvc.ByteStreamCnvSvcConf import ByteStreamMergeOutputSvc - svcMgr += ByteStreamMergeOutputSvc(ByteStreamOutputSvc='ByteStreamEventStorageOutputSvc', - ByteStreamInputSvc='ByteStreamInputSvc', - overWriteHeader=True) - - StreamBSFileOutput.OutputFile = "ByteStreamMergeOutputSvc" - svcMgr.ByteStreamCnvSvc.ByteStreamOutputSvcList=['ByteStreamMergeOutputSvc'] + svcMgr.HltEventLoopMgr.RewriteLVL1 = True class writeBS(_modifier): -- GitLab From ecddb8ed4dfac0b1b92fc191c4cfaae7fc1da17f Mon Sep 17 00:00:00 2001 From: Rafal Bielski <rafal.bielski@cern.ch> Date: Mon, 9 Mar 2020 14:16:53 +0100 Subject: [PATCH 3/4] Implement cache for output ByteStream data --- .../IL1TriggerByteStreamTool.h | 43 ++++++++++++++++++- .../src/ExampleL1TriggerByteStreamTool.cxx | 16 ++++--- .../src/ExampleL1TriggerByteStreamTool.h | 2 +- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h index 306f3883370a..473e51dc80f3 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h +++ b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h @@ -5,6 +5,7 @@ #define TRIGT1RESULTBYTESTREAM_IL1TRIGGERBYTESTREAMTOOL_H #include "ByteStreamData/RawEvent.h" +#include "AthenaKernel/SlotSpecificObj.h" #include "GaudiKernel/IAlgTool.h" #include "GaudiKernel/EventContext.h" @@ -30,10 +31,12 @@ public: * @brief Convert xAOD -> BS * * The implementation should take the xAOD RoI object from the event store using a ReadHandle it declares, - * convert it to raw data, and fill the vrobf vector. + * convert it to raw data, and fill the vrobf vector. The function is not const, as it needs to rely on + * the internal cache to track data allocated for BS representation. The provided helpers clearCache, + * newRodData, newRobFragment should be used to allocate memory for the BS representation. **/ virtual StatusCode convertToBS(std::vector<OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment*>& vrobf, - const EventContext& eventContext) const = 0; + const EventContext& eventContext) = 0; /** * @brief List of IDs of ROBs which the convert methods expect in the vrobf input/output parameter @@ -43,6 +46,42 @@ public: * in the interface, so it is delegated to the implementation. **/ virtual const std::vector<uint32_t> robIds() const = 0; + +protected: + /// Helper to clear the ByteStream data cache for a given event slot + inline void clearCache(const EventContext& eventContext) { + m_cache[eventContext.slot()].clear(); + } + /// Allocate new array of raw ROD words for output ByteStream data + inline uint32_t* newRodData(const EventContext& eventContext, const size_t size) { + m_cache[eventContext.slot()].rodData.push_back(std::make_unique<uint32_t[]>(size)); + return m_cache[eventContext.slot()].rodData.back().get(); + } + /// Allocate new ROBFragment for output ByteStream data + template<typename ...Ts> inline OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment* newRobFragment(const EventContext& eventContext, Ts... args) { + m_cache[eventContext.slot()].robFragments.push_back(std::make_unique<OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment>(args...)); + return m_cache[eventContext.slot()].robFragments.back().get(); + } +private: + /** + * @brief Cache which tracks memory allocated for ByteStream data representation in the convertToBS method. + * + * The raw ROD data and the ROBFragment object need to remain valid until they are packed into the output + * full event at the very end of event processing. Due to this requirement, the cache is cleared only on the + * next event by calling the clearCache method. + **/ + struct Cache { + std::vector<std::unique_ptr<uint32_t[]>> rodData; + std::vector<std::unique_ptr<OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment>> robFragments; + ~Cache() {clear();} + void clear() { + for (auto& ptr : rodData) ptr.reset(); + rodData.clear(); + for (auto& ptr : robFragments) ptr.reset(); + robFragments.clear(); + } + }; + std::unordered_map<EventContext::ContextID_t, Cache> m_cache; // one cache per event slot }; #endif // TRIGT1RESULTBYTESTREAM_IL1TRIGGERBYTESTREAMTOOL_H diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx index 63e20d66a8db..95901cf65bfc 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx +++ b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.cxx @@ -70,22 +70,26 @@ StatusCode ExampleL1TriggerByteStreamTool::convertFromBS(const std::vector<const /// xAOD->BS conversion StatusCode ExampleL1TriggerByteStreamTool::convertToBS(std::vector<WROBF*>& vrobf, - const EventContext& eventContext) const { + const EventContext& eventContext) { // Retrieve the RoI container auto muonRoIs = SG::makeHandle(m_roiReadKey, eventContext); ATH_CHECK(muonRoIs.isValid()); + // Clear BS data cache + clearCache(eventContext); + + // Create raw ROD data words ATH_MSG_DEBUG("Converting " << muonRoIs->size() << " L1 Muon RoIs to ByteStream"); - std::unique_ptr<uint32_t[]> data = std::make_unique<uint32_t[]>(muonRoIs->size()); + uint32_t* data = newRodData(eventContext, muonRoIs->size()); for (size_t i=0; i<muonRoIs->size(); ++i) { data[i] = muonRoIs->at(i)->roiWord(); } + // Create ROBFragment containing the ROD words const eformat::helper::SourceIdentifier sid(eformat::TDAQ_MUON_CTP_INTERFACE, m_muCTPIModuleID.value()); const EventIDBase& eid = eventContext.eventID(); - // The WROBF allocated here and the data buffer inside it have to be deleted - // by the TrigByteStreamCnvSvc after writing to the output file - vrobf.push_back(new WROBF( + vrobf.push_back(newRobFragment( + eventContext, sid.code(), eid.run_number(), eid.event_number(), @@ -93,7 +97,7 @@ StatusCode ExampleL1TriggerByteStreamTool::convertToBS(std::vector<WROBF*>& vrob 0, // lvl1_type will be overwritten downstream from full event fragment 0, // detev_type is system-specific muonRoIs->size(), - std::move(data.release()), + data, eformat::STATUS_BACK // status_position is system-specific )); diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h index cee710ee3a6d..eb13d733f3d4 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h +++ b/Trigger/TrigT1/TrigT1ResultByteStream/src/ExampleL1TriggerByteStreamTool.h @@ -38,7 +38,7 @@ public: const EventContext& eventContext) const override; /// xAOD->BS conversion virtual StatusCode convertToBS(std::vector<OFFLINE_FRAGMENTS_NAMESPACE_WRITE::ROBFragment*>& vrobf, - const EventContext& eventContext) const override; + const EventContext& eventContext) override; /// Declare ROB IDs for conversion virtual const std::vector<uint32_t> robIds() const override {return m_robIds.value();} -- GitLab From 4df75229139434c6a74533a14ba2b4140b87d30a Mon Sep 17 00:00:00 2001 From: Rafal Bielski <rafal.bielski@cern.ch> Date: Mon, 9 Mar 2020 14:36:00 +0100 Subject: [PATCH 4/4] Remove unused header --- .../TrigT1ResultByteStream/IL1TriggerByteStreamTool.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h index 473e51dc80f3..cd0ea734e55b 100644 --- a/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h +++ b/Trigger/TrigT1/TrigT1ResultByteStream/TrigT1ResultByteStream/IL1TriggerByteStreamTool.h @@ -5,7 +5,6 @@ #define TRIGT1RESULTBYTESTREAM_IL1TRIGGERBYTESTREAMTOOL_H #include "ByteStreamData/RawEvent.h" -#include "AthenaKernel/SlotSpecificObj.h" #include "GaudiKernel/IAlgTool.h" #include "GaudiKernel/EventContext.h" -- GitLab