From e03390a95508c5c6f1543caec44f897a3d20452d Mon Sep 17 00:00:00 2001
From: Rafal Bielski <rafal.bielski@cern.ch>
Date: Tue, 27 Nov 2018 17:31:34 +0100
Subject: [PATCH] New HLTResultMT ByteStream decoder algorithm

Changes include:
* implement HLTResultMTByteStreamDecoderAlg and the corresponding tool -> this reentrant algorithm replaces the functionality of Gaudi Converter for BS decoding, since Converters are inherently not compatible with athenaMT
* make the Converter method HLT::HLTResultMTByteStreamCnv::createObj fail when used with a message to use the Alg instead
* allow TriggerEDMDeserialiserAlg to skip events with no payload - this is needed at least for testing our first bytestream files with new HLTResultMT
* rename one of the HLTResultMT::setStatus overload to setErrorCodes because the overload was ambiguous (compilation error when used)
* add the implementation of operator<<(std::ostream&, const HLT::HLTResultMT&) for useful debug printouts
* add MTCalibPebDecisions to the list of serialised collections in MTCalibPeb.py in order to produce some payload
* fix the payload writing in HLT::HLTResultMTByteStreamCnv::createRep (missing reference operator)
---
 .../TrigExPartialEB/share/MTCalibPeb.py       |   3 +-
 .../TrigSteeringEvent/HLTResultMT.h           |  13 +-
 .../TrigSteeringEvent/src/HLTResultMT.cxx     |  53 ++++++-
 .../src/HLTResultMTByteStreamCnv.cxx          |  14 +-
 .../src/HLTResultMTByteStreamDecoderAlg.cxx   |  70 +++++++++
 .../src/HLTResultMTByteStreamDecoderAlg.h     |  53 +++++++
 .../src/HLTResultMTByteStreamDecoderTool.cxx  | 137 ++++++++++++++++++
 .../src/HLTResultMTByteStreamDecoderTool.h    |  35 +++++
 .../TrigHLTResultByteStream_entries.cxx       |   4 +
 .../src/TriggerEDMDeserialiserAlg.cxx         |   5 +-
 10 files changed, 371 insertions(+), 16 deletions(-)
 create mode 100644 Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.cxx
 create mode 100644 Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.h
 create mode 100644 Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
 create mode 100644 Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.h

diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
index 5ce18abe2e3..c87f070860c 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
@@ -85,7 +85,8 @@ from TrigOutputHandling.TrigOutputHandlingConf import TriggerEDMSerialiserTool,
 
 # Tool serialising EDM objects to fill the HLT result
 serialiser = TriggerEDMSerialiserTool()
-serialiser.CollectionsToSerialize = [] # nothing at the moment
+serialiser.CollectionsToSerialize = ["xAOD::TrigCompositeContainer_v1#MTCalibPebDecisions",
+                                     "xAOD::TrigCompositeAuxContainer_v1#MTCalibPebDecisionsAux."]
 
 # Tool adding stream tags to HLT result
 stmaker = StreamTagMakerTool()
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
index 0c3ee5ea511..16457d822ee 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
+++ b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
@@ -125,11 +125,11 @@ namespace HLT {
     void setStatus(const std::vector<uint32_t>& status);
 
     /// Replace error codes with the given codes
-    void setStatus(const std::vector<uint32_t>& errorCodes,
-                   const eformat::helper::Status firstStatusWord = {
-                     eformat::GenericStatus::DATA_CORRUPTION,
-                     eformat::FullEventStatus::PSC_PROBLEM
-                   });
+    void setErrorCodes(const std::vector<uint32_t>& errorCodes,
+                       const eformat::helper::Status firstStatusWord = {
+                         eformat::GenericStatus::DATA_CORRUPTION,
+                         eformat::FullEventStatus::PSC_PROBLEM
+                       });
 
     /** @brief Append an error code
      *
@@ -166,6 +166,9 @@ namespace HLT {
   };
 } // namespace HLT
 
+/// operator<< overload for printing to std::ostream
+std::ostream& operator<<(std::ostream& str, const HLT::HLTResultMT& hltResult);
+
 CLASS_DEF(HLT::HLTResultMT, 172156324, 1)
 
 #endif // TRIGSTEERINGEVENT_HLTResultMT_H
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
index c525f322323..417adb41f23 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
+++ b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
@@ -189,8 +189,8 @@ void HLT::HLTResultMT::setStatus(const std::vector<uint32_t>& status) {
 }
 
 // -----------------------------------------------------------------------------
-void HLT::HLTResultMT::setStatus(const std::vector<uint32_t>& errorCodes,
-                                 const eformat::helper::Status firstStatusWord) {
+void HLT::HLTResultMT::setErrorCodes(const std::vector<uint32_t>& errorCodes,
+                                     const eformat::helper::Status firstStatusWord) {
   m_status.clear();
   m_status.push_back(firstStatusWord.code());
   m_status.insert(m_status.end(),errorCodes.cbegin(),errorCodes.cend());
@@ -203,3 +203,52 @@ void HLT::HLTResultMT::addErrorCode(const uint32_t& errorCode,
   else m_status[0] |= firstStatusWord.code();
   m_status.push_back(errorCode);
 }
+
+// =============================================================================
+std::ostream& operator<<(std::ostream& str, const HLT::HLTResultMT& hltResult) {
+  auto printWord = [&str](const uint32_t word, const size_t width=8){
+    str << "0x" << std::hex << std::setw(width) << std::setfill('0') << word << " " << std::dec;
+  };
+  str << "Printing HLTResultMT:" << std::endl;
+
+  // Status
+  str << "--> Status words = ";
+  for (const uint32_t word : hltResult.getStatus()) {
+    printWord(word);
+  }
+  str << std::endl;
+
+  // Stream tags
+  str << "--> Stream tags  = ";
+  bool first = true;
+  for (const eformat::helper::StreamTag& st : hltResult.getStreamTags()) {
+    if (first) first=false;
+    else str << "                   ";
+    str << "{" << st.name << ", " << st.type << ", obeysLB=" << st.obeys_lumiblock << ", robs=[";
+    for (const auto& robid : st.robs) printWord(robid);
+    str << "], dets = [";
+    for (const auto& detid : st.dets) printWord(detid,2);
+    str << "]}" << std::endl;
+  }
+
+  // HLT bits
+  std::vector<uint32_t> hltBitWords;
+  hltBitWords.resize(hltResult.getHltBits().num_blocks());
+  boost::to_block_range(hltResult.getHltBits(),hltBitWords.begin());
+  str << "--> HLT bits     = ";
+  for (const uint32_t word : hltBitWords) {
+    printWord(word);
+  }
+  str << std::endl;
+
+  // Payload size
+  str << "--> Payload size = ";
+  first = true;
+  for (const auto& p : hltResult.getSerialisedData()) {
+    if (first) first=false;
+    else str << "                   ";
+    str << "{module " << p.first << ": " << p.second.size() << " words}" << std::endl;
+  }
+
+  return str;
+}
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx
index 163051bfd64..151519a2af0 100644
--- a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamCnv.cxx
@@ -61,10 +61,9 @@ StatusCode HLT::HLTResultMTByteStreamCnv::finalize() {
 // Implementation of Converter::createObj
 // =============================================================================
 StatusCode HLT::HLTResultMTByteStreamCnv::createObj(IOpaqueAddress* /*pAddr*/, DataObject*& /*pObj*/) {
-  ATH_MSG_VERBOSE("start of " << __FUNCTION__);
-  // Not yet implemented
-  ATH_MSG_VERBOSE("end of " << __FUNCTION__);
-  return StatusCode::SUCCESS;
+  ATH_REPORT_ERROR(StatusCode::FAILURE) << "Using BS converter to decode HLTResultMT is not supported!"
+                                        << " Use HLTResultMTByteStreamDecoderAlg instead";
+  return StatusCode::FAILURE;
 }
 
 // =============================================================================
@@ -124,8 +123,8 @@ StatusCode HLT::HLTResultMTByteStreamCnv::createRep(DataObject* pObj, IOpaqueAdd
   // Loop over all module IDs and fill the ROBFragments
   ATH_MSG_DEBUG("Iterating over modules to assemble output data");
   for (const auto& p : hltResult->getSerialisedData()) {
-    uint16_t moduleId = p.first;
-    std::vector<uint32_t> data = p.second;
+    const uint16_t moduleId = p.first;
+    const std::vector<uint32_t>& data = p.second;
 
     // Get a pointer to ROD data vector to be filled
     eformat::helper::SourceIdentifier sid(eformat::TDAQ_HLT,moduleId);
@@ -137,7 +136,8 @@ StatusCode HLT::HLTResultMTByteStreamCnv::createRep(DataObject* pObj, IOpaqueAdd
 
     // Fill the ROD data vector
     rod->assign(data.cbegin(), data.cend());
-    ATH_MSG_DEBUG("Assembled data for module 0x" << MSG::hex << sid.code() << MSG::dec);
+    ATH_MSG_DEBUG("Assembled data for module 0x" << MSG::hex << sid.code() << MSG::dec << " with "
+                  << data.size() << " words of serialised payload");
   }
 
   ATH_MSG_DEBUG("Appending data to RawEventWrite");
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.cxx b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.cxx
new file mode 100644
index 00000000000..a6c321d9dc5
--- /dev/null
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.cxx
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "HLTResultMTByteStreamDecoderAlg.h"
+
+// =============================================================================
+// Standard constructor
+// =============================================================================
+HLTResultMTByteStreamDecoderAlg::HLTResultMTByteStreamDecoderAlg(const std::string& name, ISvcLocator* svcLoc)
+: AthReentrantAlgorithm(name, svcLoc),
+  m_robDataProviderSvc("ROBDataProviderSvc", name) {}
+
+// =============================================================================
+// Implementation of AthReentrantAlgorithm::initialize
+// =============================================================================
+StatusCode HLTResultMTByteStreamDecoderAlg::initialize() {
+  ATH_MSG_INFO("Initialising " << name());
+  ATH_CHECK(m_hltResultWHKey.initialize());
+  ATH_CHECK(m_robDataProviderSvc.retrieve());
+
+  // Convert module IDs to HLT result ROB IDs
+  for (const uint16_t moduleId : m_moduleIdsToDecode) {
+    eformat::helper::SourceIdentifier sid(eformat::TDAQ_HLT, moduleId);
+    m_robIdsToDecode.push_back(sid.code());
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+// Implementation of AthReentrantAlgorithm::finalize
+// =============================================================================
+StatusCode HLTResultMTByteStreamDecoderAlg::finalize() {
+  ATH_MSG_INFO("Finalising " << name());
+  ATH_CHECK(m_robDataProviderSvc.release());
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+// Implementation of AthReentrantAlgorithm::execute_r
+// =============================================================================
+StatusCode HLTResultMTByteStreamDecoderAlg::execute_r(const EventContext& eventContext) const {
+  ATH_MSG_DEBUG("Executing " << name());
+
+  // Create and record the HLTResultMT object
+  auto hltResult = SG::makeHandle(m_hltResultWHKey,eventContext);
+  ATH_CHECK( hltResult.record(std::make_unique<HLT::HLTResultMT>()) );
+  ATH_MSG_DEBUG("Recorded HLTResultMT with key " << m_hltResultWHKey.key());
+
+  // Retrieve the RawEvent pointer
+  const RawEvent* re = m_robDataProviderSvc->getEvent(eventContext); // Owned by ROBDataProvider or InputSvc
+  if (!re) {
+    ATH_MSG_ERROR("Failed to retrieve the RawEvent pointer from ROBDataProvider");
+    return StatusCode::FAILURE;
+  }
+
+  // Fill the result object from ByteStream event header
+  ATH_CHECK(m_decoderTool->decodeHeader(re, *hltResult));
+
+  // Read the HLT result payload
+  IROBDataProviderSvc::VROBFRAG vrobf; // vector of ROBFragments to be filled
+  m_robDataProviderSvc->getROBData(m_robIdsToDecode, vrobf, name());
+  ATH_CHECK(m_decoderTool->decodePayload(vrobf, *hltResult));
+
+  // Print the result
+  ATH_MSG_DEBUG(*hltResult);
+
+  return StatusCode::SUCCESS;
+}
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.h b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.h
new file mode 100644
index 00000000000..64e4b468ea5
--- /dev/null
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderAlg.h
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGHLTRESULTBYTESTREAM_HLTResultMTByteStreamDecoderAlg_H
+#define TRIGHLTRESULTBYTESTREAM_HLTResultMTByteStreamDecoderAlg_H
+
+// Trigger includes
+#include "HLTResultMTByteStreamDecoderTool.h"
+#include "TrigSteeringEvent/HLTResultMT.h"
+
+// Athena includes
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+#include "StoreGate/WriteHandle.h"
+
+/** @class HLTResultMTByteStreamDecoderAlg
+ *  @brief Algorithm creating HLTResultMT from ByteStream representation
+ **/
+class HLTResultMTByteStreamDecoderAlg : public AthReentrantAlgorithm {
+public:
+  /// Standard constructor
+  HLTResultMTByteStreamDecoderAlg(const std::string& name, ISvcLocator* svcLoc);
+
+  // ------------------------- AthReentrantAlgorithm methods -------------------
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+  virtual StatusCode execute_r(const EventContext& eventContext) const override;
+
+private:
+  // ------------------------- Properties --------------------------------------
+  /// Module IDs to decode
+  Gaudi::Property<std::vector<uint16_t>> m_moduleIdsToDecode {
+    this, "ModuleIdsToDecode", {0,1,2,3,4,5,6},
+    "List of module IDs from which payload will be decoded"
+  };
+  /// StoreGate key for the output HLTResultMT
+  SG::WriteHandleKey<HLT::HLTResultMT> m_hltResultWHKey {this, "HLTResultWHKey", "HLTResultMT",
+                                                         "Key of the output HLTResultMT object"};
+
+  // ------------------------- Tool/Service handles ----------------------------
+  /// Tool performing the decoding work
+  ToolHandle<HLTResultMTByteStreamDecoderTool> m_decoderTool {this, "DecoderTool", "HLTResultMTByteStreamDecoderTool",
+                                                              "Tool performing the decoding work"};
+  /// ROBDataProvider service handle
+  ServiceHandle<IROBDataProviderSvc> m_robDataProviderSvc;
+
+  // ------------------------- Other private members ---------------------------
+  /// Full ROB IDs constructed from the ModuleIdsToDecode property
+  std::vector<uint32_t> m_robIdsToDecode;
+};
+
+#endif // TRIGHLTRESULTBYTESTREAM_HLTResultMTByteStreamDecoderAlg_H
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
new file mode 100644
index 00000000000..15bb3dfcaa9
--- /dev/null
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
@@ -0,0 +1,137 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Trigger includes
+#include "HLTResultMTByteStreamDecoderTool.h"
+
+// TDAQ includes
+#include "eformat/StreamTag.h"
+
+// =============================================================================
+// Standard constructor
+// =============================================================================
+HLTResultMTByteStreamDecoderTool::HLTResultMTByteStreamDecoderTool(const std::string& type,
+                                                                   const std::string& name,
+                                                                   const IInterface* parent)
+: AthAlgTool(type,name,parent) {}
+
+// =============================================================================
+// Implementation of AthAlgTool::initialize
+// =============================================================================
+StatusCode HLTResultMTByteStreamDecoderTool::initialize() {
+  ATH_MSG_INFO("Initialising " << name());
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+// Implementation of AthAlgTool::finalize
+// =============================================================================
+StatusCode HLTResultMTByteStreamDecoderTool::finalize() {
+  ATH_MSG_INFO("Finalising " << name());
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+StatusCode HLTResultMTByteStreamDecoderTool::decodeHeader(const RawEvent* rawEvent, HLT::HLTResultMT& resultToFill) const {
+
+  if (!rawEvent) {
+    ATH_MSG_ERROR("Decoding requested with nullptr RawEvent");
+    return StatusCode::FAILURE;
+  }
+  ATH_MSG_DEBUG("Decoding HLTResultMT from ByteStream event " << rawEvent->global_id());
+
+  // ---------------------------------------------------------------------------
+  // Read the status words (error codes from online event processing)
+  // ---------------------------------------------------------------------------
+  std::vector<uint32_t> statusWords;
+  // try-catch around eformat calls and raw-pointer operations
+  try {
+    const uint32_t nStatus = rawEvent->nstatus();
+    const uint32_t* rawStatus = rawEvent->status(); // owned by rawEvent
+    for (uint32_t i=0; i<nStatus; ++i)
+      statusWords.push_back(rawStatus[i]);
+  }
+  catch (const std::exception& ex) {
+    ATH_MSG_ERROR("std::exception caught when reading status words: " << ex.what());
+    return StatusCode::FAILURE;
+  }
+  catch (...) {
+    ATH_MSG_ERROR("Unknown exception caught when reading status words");
+    return StatusCode::FAILURE;
+  }
+  resultToFill.setStatus(statusWords);
+  ATH_MSG_DEBUG("Successfully read " << statusWords.size() << " status words");
+
+  // ---------------------------------------------------------------------------
+  // Read the stream tags
+  // ---------------------------------------------------------------------------
+  std::vector<eformat::helper::StreamTag> streamTags;
+  // try-catch around eformat calls and raw-pointer operations
+  try {
+    eformat::helper::decode(rawEvent->nstream_tag(),rawEvent->stream_tag(),streamTags);
+  }
+  catch (const std::exception& ex) {
+    ATH_MSG_ERROR("std::exception caught when reading stream tags: " << ex.what());
+    return StatusCode::FAILURE;
+  }
+  catch (...) {
+    ATH_MSG_ERROR("Unknown exception caught when reading stream tags");
+    return StatusCode::FAILURE;
+  }
+  resultToFill.setStreamTags(streamTags);
+  ATH_MSG_DEBUG("Successfully read " << streamTags.size() << " stream tags");
+
+  // ---------------------------------------------------------------------------
+  // Read the HLT bits
+  // ---------------------------------------------------------------------------
+  std::vector<uint32_t> hltBitWords;
+  // try-catch around eformat calls and raw-pointer operations
+  try {
+    const uint32_t nHltInfo = rawEvent->nhlt_info();
+    const uint32_t* hltInfo = rawEvent->hlt_info(); // owned by rawEvent
+    for (uint32_t i=0; i<nHltInfo; ++i)
+      hltBitWords.push_back(hltInfo[i]);
+  }
+  catch (const std::exception& ex) {
+    ATH_MSG_ERROR("std::exception caught when reading HLT bits: " << ex.what());
+    return StatusCode::FAILURE;
+  }
+  catch (...) {
+    ATH_MSG_ERROR("Unknown exception caught when reading HLT bits");
+    return StatusCode::FAILURE;
+  }
+  resultToFill.setHltBits( {hltBitWords.begin(), hltBitWords.end()} );
+  ATH_MSG_DEBUG("Successfully read " << hltBitWords.size() << " HLT bit words");
+
+  return StatusCode::SUCCESS;
+}
+
+// =============================================================================
+StatusCode HLTResultMTByteStreamDecoderTool::decodePayload(const std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*>& vrobf,
+                                                           HLT::HLTResultMT& resultToFill) const {
+  for (const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment* robf : vrobf) {
+    eformat::helper::SourceIdentifier sid(robf->rob_source_id());
+    ATH_MSG_DEBUG("Reading ROBFragment " << sid.human());
+    std::vector<uint32_t> data;
+    // try-catch around eformat calls and raw-pointer operations
+    try {
+      const uint32_t nRodData = robf->rod_ndata();
+      const uint32_t* rodData = robf->rod_data(); // owned by robf
+      for (uint32_t i=0; i<nRodData; ++i)
+        data.push_back(rodData[i]);
+    }
+    catch (const std::exception& ex) {
+      ATH_MSG_ERROR("std::exception caught when reading HLT result payload: " << ex.what());
+      return StatusCode::FAILURE;
+    }
+    catch (...) {
+      ATH_MSG_ERROR("Unknown exception caught when reading HLT result payload");
+      return StatusCode::FAILURE;
+    }
+    resultToFill.addSerialisedDataWithCheck(sid.module_id(), data);
+    ATH_MSG_DEBUG("Successfully read " << data.size() << " words of HLT result payload for module ID "
+                  << sid.module_id());
+  }
+  return StatusCode::SUCCESS;
+}
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.h b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.h
new file mode 100644
index 00000000000..42369dd26ab
--- /dev/null
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.h
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGHLTRESULTBYTESTREAM_HLTResultMTByteStreamDecoderTool_H
+#define TRIGHLTRESULTBYTESTREAM_HLTResultMTByteStreamDecoderTool_H
+
+// Trigger includes
+#include "TrigSteeringEvent/HLTResultMT.h"
+
+// Athena includes
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "ByteStreamData/RawEvent.h"
+
+/** @class HLTResultMTByteStreamDecoderTool
+ *  @brief Tool filling an HLTResultMT from ByteStream event data
+ **/
+class HLTResultMTByteStreamDecoderTool : virtual public AthAlgTool {
+public:
+  /// Standard constructor
+  HLTResultMTByteStreamDecoderTool(const std::string& type, const std::string& name, const IInterface* parent);
+
+  // ------------------------- AthAlgTool methods ------------------------------
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+
+  // ------------------------- Specific methods of this class ------------------
+  /// Fills the HLTResultMT object from the ByteStream event header
+  StatusCode decodeHeader(const RawEvent* rawEvent, HLT::HLTResultMT& resultToFill) const;
+  /// Fills the HLTResultMT object from vector of ROBFragments
+  StatusCode decodePayload(const std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*>& vrobf,
+                           HLT::HLTResultMT& resultToFill) const;
+};
+
+#endif // TRIGHLTRESULTBYTESTREAM_HLTResultMTByteStreamDecoderTool_H
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/components/TrigHLTResultByteStream_entries.cxx b/Trigger/TrigSteer/TrigHLTResultByteStream/src/components/TrigHLTResultByteStream_entries.cxx
index 65f438152d9..c086dca1c26 100644
--- a/Trigger/TrigSteer/TrigHLTResultByteStream/src/components/TrigHLTResultByteStream_entries.cxx
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/components/TrigHLTResultByteStream_entries.cxx
@@ -2,8 +2,12 @@
 #include "TrigHLTResultByteStream/HLTResultByteStreamCnv.h"
 #include "TrigHLTResultByteStream/HLTResultMTByteStreamCnv.h"
 #include "TrigHLTResultByteStream/HLTResultByteStreamTool.h"
+#include "../HLTResultMTByteStreamDecoderAlg.h"
+#include "../HLTResultMTByteStreamDecoderTool.h"
 
 DECLARE_CONVERTER( HLT::HLTResultByteStreamCnv )
 DECLARE_CONVERTER( HLT::HLTResultMTByteStreamCnv )
 DECLARE_COMPONENT( HLT::HLTResultByteStreamTool )
+DECLARE_COMPONENT( HLTResultMTByteStreamDecoderAlg )
+DECLARE_COMPONENT( HLTResultMTByteStreamDecoderTool )
 
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMDeserialiserAlg.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMDeserialiserAlg.cxx
index 0d7c964dbc0..ff04f8a2e91 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMDeserialiserAlg.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMDeserialiserAlg.cxx
@@ -51,7 +51,10 @@ StatusCode TriggerEDMDeserialiserAlg::execute_r(const EventContext& context) con
   auto resultHandle = SG::makeHandle( m_resultKey, context );
   const Payload* dataptr = nullptr;
   // TODO: revise if there are use cases where result may be not available in some events
-  ATH_CHECK( resultHandle->getSerialisedData( m_moduleID, dataptr ) );
+  if ( resultHandle->getSerialisedData( m_moduleID, dataptr ).isFailure() ) {
+    ATH_MSG_DEBUG("No payload available with moduleId " << m_moduleID << " in this event");
+    return StatusCode::SUCCESS;
+  }
   PayloadIterator start = dataptr->begin();
   
   while ( start != dataptr->end() )  {
-- 
GitLab