From 34bc53a4814dcce583efa2d04c0f474fb7db1b52 Mon Sep 17 00:00:00 2001
From: Peter Sherwood <peter.sherwood@cern.ch>
Date: Wed, 18 May 2022 12:27:08 +0200
Subject: [PATCH 1/2] Trigger jets - add support for out of time jet chains

---
 .../TrigHLTJetHypo/python/scenario_simple.py  | 11 +++-
 .../python/test_hypoConfigBuilder.py          | 35 ++++++++--
 .../TrigHLTJetHypo/src/TimingCondition.cxx    | 66 +++++++++++++++++++
 .../TrigHLTJetHypo/src/TimingCondition.h      | 42 ++++++++++++
 .../src/TrigJetConditionConfig_timing.cxx     | 33 ++++++++++
 .../src/TrigJetConditionConfig_timing.h       | 34 ++++++++++
 .../src/components/TrigHLTJetHypo_entries.cxx |  2 +
 7 files changed, 217 insertions(+), 6 deletions(-)
 create mode 100644 Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx
 create mode 100644 Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.h
 create mode 100644 Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.cxx
 create mode 100644 Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.h

diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/scenario_simple.py b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/scenario_simple.py
index 3d0d50eae327..07f77bcb87fd 100644
--- a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/scenario_simple.py
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/scenario_simple.py
@@ -17,7 +17,7 @@ from copy import deepcopy
 # make a list of all possible cut items for the simple scenario
 
 all_elemental_keys = ('etaRange', 'jvt', 'smc',
-                      'threshold', 'momCuts', 'bdips')
+                      'threshold', 'momCuts', 'bdips', 'timing')
 
 # Extract moment cuts
 def _cuts_from_momCuts(momCuts):
@@ -71,6 +71,13 @@ def get_condition_args_from_chainpart(cp):
             vals = defaults(key, lo=lo)
             condargs.append((key, deepcopy(vals)))
 
+        if k == 'timing':
+            key    = 'timing'
+            values = v.split(key)
+            lo   = values[0]
+            vals = defaults(key, lo=lo)
+            condargs.append((key, deepcopy(vals)))
+
         if k == 'bdips':
             key = 'bdips'
             values = v.split(key)
@@ -146,7 +153,7 @@ def scenario_simple(chain_parts):
         # elemental Conditions
 
         condargs = get_condition_args_from_chainpart(cp)
-        
+
         multiplicity = int(cp['multiplicity'])
         chainPartInd = cp['chainPartIndex']
  
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/test_hypoConfigBuilder.py b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/test_hypoConfigBuilder.py
index d4f933fa3c2d..a6f41843d59d 100644
--- a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/test_hypoConfigBuilder.py
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/test_hypoConfigBuilder.py
@@ -6,6 +6,8 @@ from __future__ import print_function
 from TriggerMenuMT.HLT.Menu.Physics_pp_run3_v1 import (
     SingleJetGroup,
     MultiJetGroup,
+    PrimaryLegGroup,
+    MultiBjetGroup,
 )
 
 DevGroup = ['Development']
@@ -30,8 +32,8 @@ logger = logging.getLogger( __name__)
 logger.setLevel(DEBUG)
 
 chains = [
-    ChainProp(name='HLT_j0_DIJET80j12ptXX700djmassXXdjdphi260_L1J20',
-              l1SeedThresholds=['FSNOSEED'],groups=MultiJetGroup),
+    ChainProp(name='HLT_j0_DIJET70j12ptXX1000djmassXXdjdphi200XX400djdeta_pf_ftf_L1MJJ-500-NFF',
+              l1SeedThresholds=['FSNOSEED'],stream=['VBFDelayed'], groups=PrimaryLegGroup+MultiBjetGroup),
 
     ChainProp(name='HLT_j0_DIJET70j12ptXX1000djmassXXdjdphi200XX400djdeta_L1J20',
               l1SeedThresholds=['FSNOSEED'],groups=MultiJetGroup),
@@ -52,7 +54,7 @@ chains = [
 
     ChainProp(name='HLT_j0_perf_a10sd_cssk_pf_nojcalib_ftf_L1RD0_FILLED', l1SeedThresholds=['FSNOSEED'], stream=['Main'], groups=['PS:Online']+SingleJetGroup),
 
-    ChainProp(name='HLT_j260_320eta490_L1J75_31ETA49',
+    ChainProp(name='HLT_j260f_L1J75_31ETA49',
               groups=SingleJetGroup),
 
     ChainProp(name='HLT_j80_j60_L1J15',
@@ -97,7 +99,12 @@ chains = [
 
     ChainProp(name='HLT_j0_HT1000_j0_DIJET80j12ptXX0j12eta240XX700djmass_L1J20', l1SeedThresholds=['FSNOSEED']*2, groups=MultiJetGroup),
 
-     ChainProp(name='HLT_2j35_0eta240_roiftf_2j35_0eta240_85bdips_roiftf_presel4c35_L14J15p0ETA25', l1SeedThresholds=['FSNOSEED','FSNOSEED'], groups=MultiJetGroup+DevGroup),
+    ChainProp(name='HLT_2j35c_2j35c_85bdips_roiftf_presel4c35_L14J15p0ETA25', l1SeedThresholds=['FSNOSEED','FSNOSEED'], groups=MultiJetGroup+DevGroup),
+
+    
+    ChainProp(name='HLT_3j45_j45_2timing_roiftf_presel4c35_L14J15p0ETA25', l1SeedThresholds=['FSNOSEED']*2, groups=MultiJetGroup+DevGroup),
+
+    ChainProp(name='HLT_j220__2timing_roiftf_presel4c35_L14J15p0ETA25', l1SeedThresholds=['FSNOSEED'], groups=MultiJetGroup+DevGroup),
 ]
 
 def testChainDictMaker(idict):
@@ -150,7 +157,27 @@ if __name__ == '__main__':
 
     iprop = args.iprop
     dicts = testChainDictMaker(iprop)
+
+    def order_chainparts(d):
+        cdict = d[1]
+        # crass "fix" for out of order chainparts
+        # these errors probably arise from calling
+        # not-quite-correct menu code.
+        chain_part_inds = [cp['chainPartIndex'] for cp in cdict['chainParts']]
+        fix = chain_part_inds == sorted(chain_part_inds)
+        if not fix:
+            fix = chain_part_inds[-1] - chain_part_inds[0] == len(chain_part_inds)
+
+            
+        if fix:
+            cpi = 0
+            for cp in cdict['chainParts']:
+                cp['chainPartIndex'] = cpi
+                cpi += 1
+                           
+
     for d in dicts:
+        order_chainparts(d)
         pprint(d)
 
     do_dot = args.dot
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx
new file mode 100644
index 000000000000..0d2dbcdcb27b
--- /dev/null
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx
@@ -0,0 +1,66 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "./TimingCondition.h"
+#include "./ITrigJetHypoInfoCollector.h"
+#include <sstream>
+#include <stdexcept>
+#include <TLorentzVector.h>
+#include <limits>
+#include <memory>
+
+TimingCondition::TimingCondition(double t_min,
+				 double t_max):
+  m_min(t_min), m_max(t_max) {
+}
+  
+
+bool TimingCondition::isSatisfied(const HypoJetVector& ips, const std::unique_ptr<ITrigJetHypoInfoCollector>& collector) const{
+
+  if(ips.size() != 1){
+    std::stringstream ss;
+    ss << "TimingCondition::isSatisfied must see exactly 1 particle, but received "
+       << ips.size()
+       << '\n';
+    throw std::runtime_error(ss.str());
+  }
+
+  auto jet = ips[0];
+
+  float timing {0.};
+  if(!(jet->getAttribute("Timing",timing))){
+    throw std::runtime_error("ERROR: TimingCondition cannot retrieve jet moment 'Timing'");
+  }
+  bool pass = timing >= m_min and timing < m_max;
+
+  if(collector){
+    std::stringstream ss0;
+    const void* address = static_cast<const void*>(this);
+    ss0 << "TimingCondition: (" << address 
+        << ") timing[" << m_min << ", " << m_max << "]" 
+        << " pass: " <<std::boolalpha << pass <<  '\n';
+
+
+    auto j_addr = static_cast<const void*>(jet.get());
+    std::stringstream ss1;
+
+    ss1 << "  jet : "  << j_addr << ")  timing " << " pt " << timing << '\n';
+    collector -> collect(ss0.str(), ss1.str());
+  }
+  return pass;
+
+}
+
+std::string TimingCondition::toString() const {
+
+  std::stringstream ss;
+
+  const void* address = static_cast<const void*>(this);
+  ss << "TimingCondition: (" << address << ") Capacity: " << s_capacity
+     << " etaMin "<<  m_min 
+     << " etaMax " << m_max 
+     <<'\n';
+  
+  return ss.str();
+}
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.h b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.h
new file mode 100644
index 000000000000..08fb65deef7b
--- /dev/null
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.h
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGHLTJETHYPO_TIMINGCONDITION_H
+#define TRIGHLTJETHYPO_TIMINGCONDITION_H
+
+/********************************************************************
+ *
+ * NAME:     TimingCondition.h
+ * PACKAGE:  Trigger/TrigHypothesis/TrigHLTJetHypo
+ *
+ *********************************************************************/
+
+#include "TrigHLTJetHypo/TrigHLTJetHypoUtils/IJet.h"
+#include "./ICondition.h"
+#include <vector>
+#include <string>
+
+class ITrigJetHypoInfoCollector;
+
+class TimingCondition: public ICondition{
+ public:
+  TimingCondition(double t_min,
+		  double t_max);
+
+  bool isSatisfied(const HypoJetVector&, const std::unique_ptr<ITrigJetHypoInfoCollector>&) const override;
+  
+  std::string toString() const override;
+
+  virtual unsigned int capacity() const override{return s_capacity;}
+
+ private:
+
+  
+  double m_min;
+  double m_max;
+  const static unsigned int s_capacity{1};
+
+};
+
+#endif
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.cxx b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.cxx
new file mode 100644
index 000000000000..5f23c910d7a4
--- /dev/null
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.cxx
@@ -0,0 +1,33 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+  Instantiator for TIMING Condition
+ */
+#include "TrigJetConditionConfig_timing.h"
+#include "GaudiKernel/StatusCode.h"
+#include "./TimingCondition.h"
+#include "./ArgStrToDouble.h"
+
+TrigJetConditionConfig_timing::TrigJetConditionConfig_timing(const std::string& type, const std::string& name, const IInterface* parent) :
+  base_class(type, name, parent){
+}
+
+
+StatusCode TrigJetConditionConfig_timing::initialize() {
+  CHECK(checkVals());
+  
+  return StatusCode::SUCCESS;
+}
+
+
+Condition TrigJetConditionConfig_timing::getCondition() const {
+  auto a2d = ArgStrToDouble();
+  return std::make_unique<TimingCondition>(a2d(m_min), a2d(m_max));
+}
+
+ 
+StatusCode TrigJetConditionConfig_timing::checkVals() const {
+  return StatusCode::SUCCESS;
+}
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.h b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.h
new file mode 100644
index 000000000000..7b64ef912590
--- /dev/null
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TrigJetConditionConfig_timing.h
@@ -0,0 +1,34 @@
+
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGJETCONDITIONCONFIG_TIMING_H
+#define TRIGJETCONDITIONCONFIG_TIMING_H
+
+
+#include "ITrigJetConditionConfig.h"
+#include "./ConditionsDefs.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+
+class TrigJetConditionConfig_timing:
+public extends<AthAlgTool, ITrigJetConditionConfig> {
+
+ public:
+  
+  TrigJetConditionConfig_timing(const std::string& type, const std::string& name, const IInterface* parent);
+
+  virtual StatusCode initialize() override;
+  virtual Condition getCondition() const override;
+
+ private:
+
+  Gaudi::Property<std::string>
+    m_min{this, "min", {}, "min timing value"};
+  
+  Gaudi::Property<std::string>
+    m_max{this, "max", {}, "max timing value"};
+
+  StatusCode checkVals()  const;
+};
+#endif
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/components/TrigHLTJetHypo_entries.cxx b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/components/TrigHLTJetHypo_entries.cxx
index b867beaf729c..e6518eab3535 100644
--- a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/components/TrigHLTJetHypo_entries.cxx
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/components/TrigHLTJetHypo_entries.cxx
@@ -25,6 +25,7 @@
 #include "../TrigJetConditionConfig_acceptAll.h"
 #include "../TrigJetConditionConfig_moment.h"
 #include "../TrigJetConditionConfig_repeated.h"
+#include "../TrigJetConditionConfig_timing.h"
 
 //
 #include "../TrigJetHypoTool.h"
@@ -52,6 +53,7 @@ DECLARE_COMPONENT(TrigJetConditionConfig_dijet_deta)
 DECLARE_COMPONENT(TrigJetConditionConfig_dijet_dphi)
 DECLARE_COMPONENT(TrigJetConditionConfig_smc)
 DECLARE_COMPONENT(TrigJetConditionConfig_jvt)
+DECLARE_COMPONENT(TrigJetConditionConfig_timing)
 DECLARE_COMPONENT(TrigJetConditionConfig_clean)
 DECLARE_COMPONENT(TrigJetConditionConfig_bdips)
 DECLARE_COMPONENT(TrigJetConditionConfig_acceptAll)
-- 
GitLab


From 0c37554b5eefea75de0b6aa9da6b289f1d4a6b27 Mon Sep 17 00:00:00 2001
From: Peter Sherwood <peter.sherwood@cern.ch>
Date: Thu, 19 May 2022 14:22:03 +0200
Subject: [PATCH 2/2] jet hypo more support changes for the out-of-time jet
 trigger.

TrigHLTJetHypo/python/ConditionDefaults.py
	supply default limits  and scale factors for the timing jet moment

TrigHLTJetHypo/python/FastReductionAlgToolFactory.py
	Add the configurer for the TimingCondition

TrigHLTJetHypo/src/TimingCondition.cxx
	tweaks to debug output

python/HLT/Menu/SignatureDicts.py
	add necessary entries to allow timing chains to be added to trigger menus
---
 .../TrigHLTJetHypo/python/ConditionDefaults.py              | 2 ++
 .../TrigHLTJetHypo/python/FastReductionAlgToolFactory.py    | 1 +
 .../TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx   | 6 +++---
 .../TriggerMenuMT/python/HLT/Menu/SignatureDicts.py         | 6 +++++-
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/ConditionDefaults.py b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/ConditionDefaults.py
index 8a81d7eef16f..d43e2e54fa87 100644
--- a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/ConditionDefaults.py
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/ConditionDefaults.py
@@ -34,6 +34,7 @@ class ConditionDefaults:
             'jvt': {'min': '0', 'max': 'inf'},
             'bdips': {'min': '-inf', 'max': 'inf'},
             'momCuts': {'min': '-inf', 'max': 'inf'},
+            'timing': {'min': '0', 'max': 'inf'},
         }
 
         self.scale_factor = {
@@ -54,6 +55,7 @@ class ConditionDefaults:
             'jvt': 0.01,
             'bdips': 1.,
             'momCuts': 0.01,
+            'timing': 1.0,
         }
   
     def __call__(self, key, lo='', hi=''):
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/FastReductionAlgToolFactory.py b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/FastReductionAlgToolFactory.py
index 5272a678cb79..97cbe9a9b122 100644
--- a/Trigger/TrigHypothesis/TrigHLTJetHypo/python/FastReductionAlgToolFactory.py
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/python/FastReductionAlgToolFactory.py
@@ -51,6 +51,7 @@ class FastReductionAlgToolFactory:
             'bdips': [CompFactory.TrigJetConditionConfig_bdips, 0],
             'clean': [CompFactory.TrigJetConditionConfig_clean, 0],
             'all': [CompFactory.TrigJetConditionConfig_acceptAll, 0],
+            'timing': [CompFactory.TrigJetConditionConfig_timing, 0],
             }
 
         for var in jetMoments:
diff --git a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx
index 0d2dbcdcb27b..745dd54fced5 100644
--- a/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx
+++ b/Trigger/TrigHypothesis/TrigHLTJetHypo/src/TimingCondition.cxx
@@ -45,7 +45,7 @@ bool TimingCondition::isSatisfied(const HypoJetVector& ips, const std::unique_pt
     auto j_addr = static_cast<const void*>(jet.get());
     std::stringstream ss1;
 
-    ss1 << "  jet : "  << j_addr << ")  timing " << " pt " << timing << '\n';
+    ss1 << "  jet : "  << j_addr << ")  timing "  << timing << '\n';
     collector -> collect(ss0.str(), ss1.str());
   }
   return pass;
@@ -58,8 +58,8 @@ std::string TimingCondition::toString() const {
 
   const void* address = static_cast<const void*>(this);
   ss << "TimingCondition: (" << address << ") Capacity: " << s_capacity
-     << " etaMin "<<  m_min 
-     << " etaMax " << m_max 
+     << " timingMin "<<  m_min 
+     << " timingMax " << m_max 
      <<'\n';
   
   return ss.str();
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/SignatureDicts.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/SignatureDicts.py
index cc60f459e056..4095d2546f19 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/SignatureDicts.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/SignatureDicts.py
@@ -274,7 +274,10 @@ JetChainParts = {
     'jvt'           : # Jet Vertex Tagger pileup discriminant
       ['010jvt', '011jvt', '015jvt', '020jvt', '050jvt', '059jvt'],
     'momCuts'       : # Generic moment cut on single jets
-      ['050momemfrac100', 'momhecfrac010', '050momemfrac100XXmomhecfrac010'],
+       ['050momemfrac100', 'momhecfrac010', '050momemfrac100XXmomhecfrac010'],
+    'timing'        : # delayed jets
+    ['2timing'],
+    
     'prefilters'      : # Pre-hypo jet selectors (including cleaning)
     ['CLEANlb', 'CLEANllp', 'MASK300ceta210XX300nphi10',
      # ptrangeXrY (X, Y matches regex \d+)  triggers a prehypo selection of
@@ -328,6 +331,7 @@ JetChainParts_Default = {
     'etaRange'      : '0eta320',
     'jvt'           : '',
     'momCuts'       : '',
+    'timing'       : '',
     'prefilters'    : [],
     'bdips'         : '',
     'hypoScenario'  : 'simple',
-- 
GitLab