From e66f0fe28c754c6d763dc7161e1ed0b2c8f21e7c Mon Sep 17 00:00:00 2001
From: Jonathan Burr <jonathan.thomas.burr@cern.ch>
Date: Mon, 25 Nov 2019 13:54:27 +0100
Subject: [PATCH] Adding cell FEX code in new style, including noise cuts

---
 .../TrigEFMissingET/CMakeLists.txt            |   1 +
 .../TrigEFMissingET/src/CellFex.cxx           | 104 ++++++++++++++++++
 .../TrigEFMissingET/src/CellFex.h             |  89 +++++++++++++++
 .../components/TrigEFMissingET_entries.cxx    |   2 +
 .../HLTMenuConfig/MET/METRecoSequences.py     |  33 ++----
 5 files changed, 208 insertions(+), 21 deletions(-)
 create mode 100644 Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.cxx
 create mode 100644 Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.h

diff --git a/Trigger/TrigAlgorithms/TrigEFMissingET/CMakeLists.txt b/Trigger/TrigAlgorithms/TrigEFMissingET/CMakeLists.txt
index ca2386913230..10f5032d958a 100644
--- a/Trigger/TrigAlgorithms/TrigEFMissingET/CMakeLists.txt
+++ b/Trigger/TrigAlgorithms/TrigEFMissingET/CMakeLists.txt
@@ -80,6 +80,7 @@ atlas_add_component( TrigEFMissingET
   src/FexBase.cxx
   src/MonGroupBuilder.cxx
   src/TrkMHTFex.cxx
+  src/CellFex.cxx
   src/components/TrigEFMissingET_entries.cxx
   src/components/TrigEFMissingET_load.cxx
   INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS} ${FASTJETCONTRIB_INCLUDE_DIRS} ${FASTJET_INCLUDE_DIRS}
diff --git a/Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.cxx b/Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.cxx
new file mode 100644
index 000000000000..10032a5e9649
--- /dev/null
+++ b/Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.cxx
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+ */
+
+/******************************************************************************
+ * @package Trigger/TrigAlgorithms/TrigEFMissingET
+ * @file CellFex.cxx
+ *
+ * Implementation of cell fex class
+ * @author Jon Burr
+ *****************************************************************************/
+
+#include "CellFex.h"
+#include "TrigEFMissingET/METComponent.h"
+#include "TrigEFMissingET/SignedKinematics.h"
+#include "StoreGate/ReadCondHandle.h"
+#include "CaloGeoHelpers/CaloSampling.h"
+#include <array>
+#include <numeric>
+
+// TODO - we should check a couple of things
+// - What is the 'prefetch' used by the TopoClusterMaker? Do we need to use it?
+// - Should we be using the 2-Gaussian noise estimate or not? (Right now we do)
+// - Should we be skipping 'bad' cells in the loop? (Right now we include them
+// in the sum)
+// - Previously we had the bytestream error flag in the output objects. I can't
+// tell if there's any equivalent in the new access mechanism
+
+namespace {
+  /// The number of samplings that we use in this algorithm. We do not use the
+  /// 'mini FCal' samplings (that appear after FCAL2 in the enum) so we ensure
+  /// that we stop after the FCAL
+  static constexpr std::size_t N_SAMPLINGS{CaloSampling::FCAL2+1};
+} //> end anonymous namespace
+
+namespace HLT { namespace MET {
+  CellFex::CellFex(const std::string& name, ISvcLocator* pSvcLocator) :
+    FexBase(name, pSvcLocator)
+  {}
+
+  StatusCode CellFex::initialize()
+  {
+    CHECK( m_cellsKey.initialize() );
+    CHECK( m_noiseCDOKey.initialize() );
+    CHECK( detStore()->retrieve(m_caloCellID, "CaloCell_ID") );
+    // Build up the list of component names
+    std::vector<std::string> componentNames;
+    componentNames.reserve(N_SAMPLINGS);
+    for (std::size_t ii = 0; ii < N_SAMPLINGS; ++ii)
+      componentNames.push_back(CaloSampling::getSamplingName(ii) );
+    return initializeBase(componentNames);
+  }
+
+  StatusCode CellFex::fillMET(
+      xAOD::TrigMissingET& met,
+      const EventContext& context,
+      MonGroupBuilder&) const
+  {
+    // Retrieve the inputs
+    auto cells = SG::makeHandle(m_cellsKey, context);
+    // NB - there's no makeHandle overload for ReadCondHandle
+    SG::ReadCondHandle noiseCDO(m_noiseCDOKey, context);
+
+    // Prepare the individual components
+    std::array<METComponent, N_SAMPLINGS> sums;
+    // Iterate over the calorimeter cells
+    for (const CaloCell* icell : *cells) {
+      // Get the noise. The two different calls are equivalent for LAr cells,
+      // but do differ for the TileCal. As far as I can see, the 'two Gaussian'
+      // approach is the more recommended one.
+      float noise = m_doTwoGaussianNoise ? 
+        noiseCDO->getEffectiveSigma(icell->ID(), icell->gain(), icell->energy() ) :
+        noiseCDO->getNoise(icell->ID(), icell->gain() );
+      // Noise selections, first |E| < T1*S
+      if (m_absNoiseThreshold > 0 &&
+          std::abs(icell->energy() ) < m_absNoiseThreshold*noise)
+        continue;
+      // Then E > -T2*S
+      if (m_negNoiseThreshold > 0 &&
+          icell->energy() < -m_negNoiseThreshold*noise)
+        continue;
+      // What about bad cells?
+      if (const CaloDetDescrElement* dde = icell->caloDDE() ) {
+        // Get the right component
+        METComponent& sum = sums.at(dde->getSampling() );
+        sum += SignedKinematics::fromEnergyEtaPhi(
+            icell->energy(), dde->eta(), dde->phi() );
+      }
+      else {
+        auto id = icell->ID();
+        METComponent& sum = sums.at(m_caloCellID->sampling(id) );
+        sum += SignedKinematics::fromEnergyEtaPhi(
+            icell->energy(), m_caloCellID->eta(id), m_caloCellID->phi(id) );
+      }
+    }
+    // Save the full sum
+    std::accumulate(sums.begin(), sums.end(), METComponent{}).fillMET(met);
+    // Save each component
+    for (std::size_t ii = 0; ii < N_SAMPLINGS; ++ii)
+      sums.at(ii).fillMETComponent(ii, met);
+
+    return StatusCode::SUCCESS;
+  }
+} } //> end namespace HLT::MET
diff --git a/Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.h b/Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.h
new file mode 100644
index 000000000000..56a34ef71b44
--- /dev/null
+++ b/Trigger/TrigAlgorithms/TrigEFMissingET/src/CellFex.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+ */
+
+/******************************************************************************
+ * @package Trigger/TrigAlgorithms/TrigEFMissingET
+ * @class   CellFex
+ *
+ * @brief Fex class for the basic cell algorithm
+ * @author Jon Burr
+ *****************************************************************************/
+
+#ifndef TRIGEFMISSINGET_CELLFEX_H
+#define TRIGEFMISSINGET_CELLFEX_H 1
+
+#include "FexBase.h"
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloConditions/CaloNoise.h"
+#include "StoreGate/ReadCondHandleKey.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+
+
+namespace HLT { namespace MET {
+  /****************************************************************************
+   * @class CellFex
+   *
+   * Class to create output from the cell algorithm
+   *
+   * cell calculates the MET with a sum over all calorimeter cells. A two-sided
+   * noise cut is applied, requiring cells to have |E/S| > T1, E/S > -T2, where
+   * T1 and T2 are thresholds, and S is the 1-sigma noise threshold.
+   ***************************************************************************/
+  class CellFex : public FexBase
+  {
+    public:
+      /// Constructor
+      CellFex(const std::string& name, ISvcLocator* pSvcLocator);
+
+      /// Initialize the fex
+      virtual StatusCode initialize() override;
+
+    private:
+      /************************************************************************
+       * Properties
+       ***********************************************************************/
+      /// Input cells
+      SG::ReadHandleKey<CaloCellContainer> m_cellsKey{
+        this, "CellName", "CaloCells", "Collection containing all input cells"};
+      /// Calorimeter noise CDO (conditions data object)
+      SG::ReadCondHandleKey<CaloNoise> m_noiseCDOKey{
+        this, "CaloNoiseName","totalNoise","SG Key of CaloNoise data object"};
+      /// The threshold on the magnitude of the cell energy
+      Gaudi::Property<float> m_absNoiseThreshold{
+        this, "AbsoluteNoiseThreshold", 2, "Threshold on the magnitude of the "
+          "cell energy (as a multiple of the cell noise level). Selection "
+          "will not be applied if value is negative"};
+      /// The maximum negative cell energy
+      Gaudi::Property<float> m_negNoiseThreshold{
+        this, "NegativeNoiseThreshold", 5, "The maximum negative cell energy. "
+          "Selection will not be applied if value is negative"};
+      /// Use the 'two-gaussian' noise calculation for the TileCal
+      Gaudi::Property<bool> m_doTwoGaussianNoise{
+        this, "TwoGaussianNoise", true,
+          "Whether to use the 'two-Gaussian' noise calculation for the TileCal"};
+
+      /************************************************************************
+       * Internal functions
+       ***********************************************************************/
+      /**
+       * @brief Calculate and fill the output MET value
+       * @param met The object to fill
+       * @param context The event context
+       * @param monitors[out] Any extra monitors to fill
+       */
+      virtual StatusCode fillMET(
+          xAOD::TrigMissingET& met,
+          const EventContext& context,
+          MonGroupBuilder& monitors) const override;
+
+      /************************************************************************
+       * Data members
+       ***********************************************************************/
+      /// Fallback option for calo cells which don't have a detector description
+      /// - we can read the information from this object
+      const CaloCell_ID* m_caloCellID{nullptr};
+  }; //> end class FexBase
+} } //> end namespace HLT::MET
+
+#endif //> !TRIGEFMISSINGET_CELLFEX_H
diff --git a/Trigger/TrigAlgorithms/TrigEFMissingET/src/components/TrigEFMissingET_entries.cxx b/Trigger/TrigAlgorithms/TrigEFMissingET/src/components/TrigEFMissingET_entries.cxx
index d0439c10f396..7788a253b6a6 100644
--- a/Trigger/TrigAlgorithms/TrigEFMissingET/src/components/TrigEFMissingET_entries.cxx
+++ b/Trigger/TrigAlgorithms/TrigEFMissingET/src/components/TrigEFMissingET_entries.cxx
@@ -20,6 +20,7 @@
 #include "../EFMissingETFlagsMT.h"
 #include "../EFMissingETComponentCopier.h"
 #include "../TrkMHTFex.h"
+#include "../CellFex.h"
 
 DECLARE_COMPONENT( EFMissingET )
 DECLARE_COMPONENT( EFMissingETBaseTool )
@@ -42,3 +43,4 @@ DECLARE_COMPONENT( EFMissingETFromClustersPufitMT )
 DECLARE_COMPONENT( EFMissingETFromJetsMT )
 DECLARE_COMPONENT( EFMissingETFlagsMT )
 DECLARE_COMPONENT( HLT::MET::TrkMHTFex )
+DECLARE_COMPONENT( HLT::MET::CellFex )
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/MET/METRecoSequences.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/MET/METRecoSequences.py
index a0859aa97632..ecdaac271133 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/MET/METRecoSequences.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/MET/METRecoSequences.py
@@ -6,7 +6,8 @@ from TrigEDMConfig.TriggerEDMRun3 import recordable
 from TriggerMenuMT.HLTMenuConfig.Menu.MenuComponents import RecoFragmentsPool
 
 from TrigEFMissingET.TrigEFMissingETConf import (
-        EFMissingETAlgMT, EFMissingETFlagsMT, HLT__MET__TrkMHTFex)
+        EFMissingETAlgMT, EFMissingETFlagsMT, HLT__MET__TrkMHTFex,
+        HLT__MET__CellFex)
 from TrigEFMissingET.TrigEFMissingETMTConfig import getMETMonTool
 
 from TrigT2CaloCommon.CaloDef import clusterFSInputMaker
@@ -26,26 +27,16 @@ def metCellRecoSequence():
 
     from TrigT2CaloCommon.CaloDef import HLTFSCellMakerRecoSequence
     (cellMakerSeq, CellsName) = HLTFSCellMakerRecoSequence()
-
-    #################################################
-    # Add EFMissingETAlg and associated tools
-    #################################################
-    metAlg = EFMissingETAlgMT( name="EFMET_cell" )
-    flagsTool = EFMissingETFlagsMT("theFlagsTool")
-    metAlg.METContainerKey = recordable("HLT_MET_cell")
-    metAlg.MonTool = getMETMonTool()
-
-    #///////////////////////////////////////////
-    # Add EFMissingETFromCells tool
-    #///////////////////////////////////////////
-    from TrigEFMissingET.TrigEFMissingETConf import EFMissingETFromCellsMT
-    cellTool = EFMissingETFromCellsMT( name="METFromCellsTool" )
-    cellTool.CellsCollection = CellsName
-    metAlg.METTools = [cellTool, flagsTool]
-
-    met_recoSequence = seqAND("metCellRecoSequence", [cellMakerSeq, metAlg])
-
-    seqOut = metAlg.METContainerKey
+    alg = HLT__MET__CellFex(
+            name="EFMET_cell",
+            CellName = CellsName,
+            METContainerKey = recordable("HLT_MET_cell"),
+            AbsoluteNoiseThreshold = -1,
+            NegativeNoiseThreshold = -1,
+            MonTool = getMETMonTool() )
+
+    met_recoSequence = seqAND("metCellRecoSequence", [cellMakerSeq, alg])
+    seqOut = alg.METContainerKey
     return (met_recoSequence, seqOut)
 
 
-- 
GitLab