From 47adbf9afcf095ffb06030f626920f6f81c4a6b2 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Fri, 8 Jul 2022 11:57:01 +0200
Subject: [PATCH 01/33] added dRtoLargestPtJet

---
 HH4bAnalysis/share/VariableDumperConfig.py |  2 ++
 HH4bAnalysis/src/VariableDumperAlg.cxx     | 28 ++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 8e4aeba20..d17e481e2 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -358,6 +358,8 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
         "AnalysisJetsBTAG_%SYS%.pt  -> recojet_antikt4_%SYS%_pt",
         "AnalysisJetsBTAG_%SYS%.eta -> recojet_antikt4_%SYS%_eta",
         "AnalysisJetsBTAG_%SYS%.phi -> recojet_antikt4_%SYS%_phi",
+        "AnalysisJetsBTAG_%SYS%.dRtoLargestPtJet ->"
+        " recojet_antikt4_%SYS%_dRtoLargestPtJet",
         "AnalysisJetsBTAGOR_%SYS%.m  -> recojet_antikt4_OR_%SYS%_m",
         "AnalysisJetsBTAGOR_%SYS%.pt  -> recojet_antikt4_OR_%SYS%_pt",
         "AnalysisJetsBTAGOR_%SYS%.eta -> recojet_antikt4_OR_%SYS%_eta",
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index be9837d1c..bea8c58d6 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -70,6 +70,34 @@ namespace HH4B
       const xAOD::JetContainer *antiKt4RecoJets(nullptr);
       ANA_CHECK(m_jetsmallRHandle.retrieve(antiKt4RecoJets, sys));
       // do something with antiKt4RecoJets
+
+      // set defaults
+      double maxJetPt = -1;
+      double thisJetPt = -1;
+      int maxJetPtIndex = -1;
+
+      // find jet index with largest pt
+      for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
+      {
+        const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
+        thisJetPt = thisJet->pt();
+        if (thisJetPt > maxJetPt)
+        {
+          maxJetPt = thisJetPt;
+          maxJetPtIndex = jetIndex;
+        }
+      }
+
+      // calculate dR to other jets
+      const xAOD::Jet *maxPtJet = antiKt4RecoJets->at(maxJetPtIndex);
+
+      for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
+      {
+        const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
+        thisJet->auxdecor<double>("dRtoLargestPtJet") =
+            thisJet->p4().DeltaR(maxPtJet->p4());
+      }
+
       const xAOD::JetContainer *antiKt10RecoJets(nullptr);
       ANA_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
       // do something with antiKt10RecoJets
-- 
GitLab


From 6c3d1e4aa823a7e2af08e0fd08198ba11d8d410b Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Tue, 12 Jul 2022 14:16:14 +0200
Subject: [PATCH 02/33] save VR sequence

---
 HH4bAnalysis/share/VariableDumperConfig.py    |  35 ++++-
 .../share/utils/containerNameHelper.py        |   3 +
 HH4bAnalysis/src/VariableDumperAlg.cxx        | 141 ++++++++++++++----
 HH4bAnalysis/src/VariableDumperAlg.h          |   5 +
 .../src/tools/getBoostedHiggsCandidates.cxx   |  21 +++
 .../src/tools/getBoostedHiggsCandidates.h     |  10 ++
 HH4bAnalysis/src/tools/kLargestJets.cxx       |  49 ++++++
 HH4bAnalysis/src/tools/kLargestJets.h         |  18 +++
 8 files changed, 248 insertions(+), 34 deletions(-)
 create mode 100644 HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
 create mode 100644 HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
 create mode 100644 HH4bAnalysis/src/tools/kLargestJets.cxx
 create mode 100644 HH4bAnalysis/src/tools/kLargestJets.h

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index c9a495f3f..0c6989a9c 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -51,6 +51,7 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
 
     reco4JetContainerName = getContainerName("Reco4PFlowJets", isDaodPhyslite)
     reco10JetContainerName = getContainerName("Reco10PFlowJets", isDaodPhyslite)
+    recoVRJetContainerName = getContainerName("RecoVRPFlowJets", isDaodPhyslite)
     muonsContainerName = getContainerName("Muons", isDaodPhyslite)
     electronsContainerName = getContainerName("Electrons", isDaodPhyslite)
     photonsContainerName = getContainerName("Photons", isDaodPhyslite)
@@ -206,7 +207,7 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
         generator="default",  # Pythia8 not available in makeFTagAnalysisSequence CDI
         postfix="",
         preselection=None,
-        kinematicSelection=False,
+        kinematicSelection=True,
         noEfficiency=False,
         legacyRecommendations=True,
         enableCutflow=False,
@@ -261,6 +262,31 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
     for largeJetAlg in largeJetAlgsCnv:
         cfg.addEventAlgo(largeJetAlg, largeRrecojetSequenceCnv.getName())
 
+    from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
+
+    largeRrecojetSequence = makeJetAnalysisSequence(
+        dataType,
+        reco10JetContainerName,
+        postfix="VR",
+        deepCopyOutput=False,
+        shallowViewOutput=True,
+        runGhostMuonAssociation=False,
+        enableCutflow=False,
+        enableKinematicHistograms=False,
+        largeRMass="Comb",
+    )
+    largeRrecojetSequence.configure(
+        inputName=recoVRJetContainerName, outputName="AnalysisVRRecoJets_%SYS%"
+    )
+    # print(largeRrecojetSequence)  # For debugging
+    # Convert to new configurables
+    largeRrecojetSequenceCnv, largeJetAlgsCnv = convertSequenceAndGetAlgs(
+        CompFactory, largeRrecojetSequence
+    )
+    cfg.addSequence(largeRrecojetSequenceCnv)
+    for largeJetAlg in largeJetAlgsCnv:
+        cfg.addEventAlgo(largeJetAlg, largeRrecojetSequenceCnv.getName())
+
     # Include, and then set up the overlap analysis algorithm sequence:
     from AsgAnalysisAlgorithms.OverlapAnalysisSequence import (
         makeOverlapAnalysisSequence,
@@ -337,6 +363,11 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
         # we currently don't have any pileup calib files setup
         # 'EventInfo.PileupWeight_%SYS% -> pileupWeight_%SYS%',
         "EventInfo.mcEventWeights   -> mcEventWeights",
+        "EventInfo.m_h1   -> m_h1",
+        "EventInfo.m_h2   -> m_h2",
+        "EventInfo.m_hh   -> m_hh",
+        "EventInfo.dR_jets_in_h1   -> dR_jets_in_h1",
+        "EventInfo.dR_jets_in_h2   -> dR_jets_in_h2",
         "AnalysisElectrons_%SYS%.pt  -> el_%SYS%_pt",
         "AnalysisElectrons_%SYS%.eta -> el_%SYS%_eta",
         "AnalysisElectrons_%SYS%.phi -> el_%SYS%_phi",
@@ -359,8 +390,6 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
         "AnalysisJetsBTAG_%SYS%.pt  -> recojet_antikt4_%SYS%_pt",
         "AnalysisJetsBTAG_%SYS%.eta -> recojet_antikt4_%SYS%_eta",
         "AnalysisJetsBTAG_%SYS%.phi -> recojet_antikt4_%SYS%_phi",
-        "AnalysisJetsBTAG_%SYS%.dRtoLargestPtJet ->"
-        " recojet_antikt4_%SYS%_dRtoLargestPtJet",
         "AnalysisJetsBTAGOR_%SYS%.m  -> recojet_antikt4_OR_%SYS%_m",
         "AnalysisJetsBTAGOR_%SYS%.pt  -> recojet_antikt4_OR_%SYS%_pt",
         "AnalysisJetsBTAGOR_%SYS%.eta -> recojet_antikt4_OR_%SYS%_eta",
diff --git a/HH4bAnalysis/share/utils/containerNameHelper.py b/HH4bAnalysis/share/utils/containerNameHelper.py
index 121a76bde..359a74d88 100644
--- a/HH4bAnalysis/share/utils/containerNameHelper.py
+++ b/HH4bAnalysis/share/utils/containerNameHelper.py
@@ -3,6 +3,7 @@
 # custom container names used in this framework
 RECO_4_PFLOW_JETS_KEY = "Reco4PFlowJets"
 RECO_10_PFLOW_JETS_KEY = "Reco10PFlowJets"
+RECO_VR_TRACK_JETS_KEY = "RecoVRTrackJets"
 TRUTH_4_JETS_KEY = "Truth4Jets"
 TRUTH_10_JETS_KEY = "Truth10Jets"
 MUONS_KEY = "Muons"
@@ -13,6 +14,7 @@ container_map = {
     "DAOD_PHYS": {
         RECO_4_PFLOW_JETS_KEY: "AntiKt4EMPFlowJets",
         RECO_10_PFLOW_JETS_KEY: "AntiKt10LCTopoTrimmedPtFrac5SmallR20Jets",
+        RECO_VR_TRACK_JETS_KEY: "AntiKtVR30Rmax4Rmin02PV0TrackJets",
         TRUTH_4_JETS_KEY: "AntiKt4TruthDressedWZJets",
         TRUTH_10_JETS_KEY: "AntiKt10TruthTrimmedPtFrac5SmallR20Jets",
         MUONS_KEY: "Muons",
@@ -22,6 +24,7 @@ container_map = {
     "DAOD_PHYSLITE": {
         RECO_4_PFLOW_JETS_KEY: "AnalysisJets",
         RECO_10_PFLOW_JETS_KEY: "?",
+        RECO_VR_TRACK_JETS_KEY: "?",
         TRUTH_4_JETS_KEY: "AntiKt4TruthDressedWZJets",
         TRUTH_10_JETS_KEY: "?",
         MUONS_KEY: "AnalysisMuons",
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 676bf43a5..efe31cee0 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -7,6 +7,8 @@
 
 // Class definition
 #include "VariableDumperAlg.h"
+// #include "tools/getBoostedHiggsCandidates.h"
+// #include "tools/kLargestJets.h"
 
 //
 // method implementations
@@ -18,7 +20,10 @@ namespace HH4B
                                         ISvcLocator *pSvcLocator)
       : AthHistogramAlgorithm(name, pSvcLocator),
         m_acc_DFCommonJets_eventClean_LooseBad(
-            "DFCommonJets_eventClean_LooseBad")
+            "DFCommonJets_eventClean_LooseBad") m_acc_VRTrackJets
+
+        SG::AuxElement::ConstAccessor<char> m_acc_VRTrackJets;
+  AntiKtVR30Rmax4Rmin02PV0TrackJets(DataVector<xAOD::Jet_v1>)[Jet]
   {
     declareProperty("applyJetCleaning", m_applyJetCleaning);
   }
@@ -38,6 +43,7 @@ namespace HH4B
     ATH_CHECK(m_systematicsList.addHandle(m_muonHandle));
     ATH_CHECK(m_systematicsList.addHandle(m_jetsmallRHandle));
     ATH_CHECK(m_systematicsList.addHandle(m_jetlargeRHandle));
+    ATH_CHECK(m_btagSelTool.retrieve());
 
     ATH_CHECK(m_EventInfoKey.initialize());
     ATH_CHECK(m_systematicsList.initialize());
@@ -79,39 +85,112 @@ namespace HH4B
       ATH_CHECK(m_muonHandle.retrieve(muons, sys));
       // do something with muons
       const xAOD::JetContainer *antiKt4RecoJets(nullptr);
-      ANA_CHECK(m_jetsmallRHandle.retrieve(antiKt4RecoJets, sys));
+      ATH_CHECK(m_jetsmallRHandle.retrieve(antiKt4RecoJets, sys));
       // do something with antiKt4RecoJets
-
-      // set defaults
-      double maxJetPt = -1;
-      double thisJetPt = -1;
-      int maxJetPtIndex = -1;
-
-      // find jet index with largest pt
-      for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
-      {
-        const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
-        thisJetPt = thisJet->pt();
-        if (thisJetPt > maxJetPt)
-        {
-          maxJetPt = thisJetPt;
-          maxJetPtIndex = jetIndex;
-        }
-      }
-
-      // calculate dR to other jets
-      const xAOD::Jet *maxPtJet = antiKt4RecoJets->at(maxJetPtIndex);
-
-      for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
-      {
-        const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
-        thisJet->auxdecor<double>("dRtoLargestPtJet") =
-            thisJet->p4().DeltaR(maxPtJet->p4());
-      }
-
       const xAOD::JetContainer *antiKt10RecoJets(nullptr);
-      ANA_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
+      ATH_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
+      // do something with antiKt10RecoJets
+      const xAOD::JetContainer *antiKtVRRecoJets(nullptr);
+      ATH_CHECK(m_jetVRHandle.retrieve(antiKtVRRecoJets, sys));
       // do something with antiKt10RecoJets
+      ATH_MSG_DEBUG("Number of 0.4 jets in event " << antiKt4RecoJets->size());
+      ATH_MSG_DEBUG("Number of 1.0 jets in event "
+                    << antiKt10RecoJets->size());
+
+      // std::cout << antiKt4RecoJets->size() << "\n";
+      // std::cout << jetSmallBTag->size() << "\n";
+
+      // for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
+      // {
+      //   const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
+      //   // std::cout << jetIndex;
+      //   // std::cout << antiKt4RecoJets->size();
+      //   SG::AuxElement::ConstAccessor<char> isTag77(
+      //       "ftag_kin_select_DL1r_FixedCutBEff_77");
+      //   std::cout << isTag77(*thisJet) << "\n";
+      // }
+
+      // TODO: send in btagged jets
+      // set defaults
+      eventInfo->auxdecor<double>("dR_jets_in_h1") = -1;
+      eventInfo->auxdecor<double>("dR_jets_in_h2") = -1;
+      eventInfo->auxdecor<double>("m_h1") = -1;
+      eventInfo->auxdecor<double>("m_h2") = -1;
+      eventInfo->auxdecor<double>("m_hh") = -1;
+
+      // // check if we have 4 jets
+      // if (antiKt4RecoJets->size() < 4)
+      // {
+      //   return StatusCode::SUCCESS;
+      // }
+      // // get indices of 4 largest pt jets
+      // std::vector<int> fourLargestPtJetsIndices =
+      //     kLargestJets(antiKt4RecoJets, 4);
+
+      // const xAOD::Jet *largestPtJet =
+      //     antiKt4RecoJets->at(fourLargestPtJetsIndices[0]);
+
+      // // calc dR to other higgs candidate jets
+      // std::vector<double> dRtoLargestPtJet;
+      // for (int jetIndex : fourLargestPtJetsIndices)
+      // {
+      //   const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
+      //   double thisDRtoLargestPtJet =
+      //   thisJet->p4().DeltaR(largestPtJet->p4());
+      //   dRtoLargestPtJet.push_back(thisDRtoLargestPtJet);
+      //   ATH_MSG_DEBUG(thisDRtoLargestPtJet);
+      // }
+
+      // // get closest jet to leading jet
+      // int closestToLeadingJetEntry =
+      //     std::min_element(dRtoLargestPtJet.begin(), dRtoLargestPtJet.end())
+      //     - dRtoLargestPtJet.begin();
+      // const xAOD::Jet *closestToLeadingJet = antiKt4RecoJets->at(
+      //     fourLargestPtJetsIndices[closestToLeadingJetEntry]);
+
+      // // make higgs candidates
+      // TLorentzVector h1_cand = largestPtJet->p4() +
+      // closestToLeadingJet->p4(); double dR_jets_in_h1 =
+      //     largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
+      // // make a copy of the indices and delete the ones of the h1_cand
+      // // order matters!
+      // std::vector<int> otherJetIndices = fourLargestPtJetsIndices;
+      // otherJetIndices.erase(otherJetIndices.begin() +
+      //                       closestToLeadingJetEntry);
+      // otherJetIndices.erase(otherJetIndices.begin());
+
+      // const xAOD::Jet *otherJet1 = antiKt4RecoJets->at(otherJetIndices[0]);
+      // const xAOD::Jet *otherJet2 = antiKt4RecoJets->at(otherJetIndices[1]);
+
+      // TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
+      // double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
+
+      // double m_h1 = h1_cand.M();
+      // double m_h2 = h2_cand.M();
+      // double m_hh = (h1_cand + h2_cand).M();
+
+      // TODO: return resolved function as std::map "m_h1"
+
+      // for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
+      // {
+      //   const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
+      //   // std::cout << jetIndex;
+      //   // std::cout << antiKt4RecoJets->size();
+      //   SG::AuxElement::ConstAccessor<char> isTag77(
+      //       "ftag_kin_select_DL1r_FixedCutBEff_77");
+      //   std::cout << isTag77(*thisJet) << "\n";
+      // }
+
+      // recommended by ftag  Remove the event if any of your signal jets have
+      // relativeDeltaRToVRJet < 1.0.
+      // getBoostedHiggsCandidates(antiKt10RecoJets);
+
+      //  write out Higgs candidates
+      eventInfo->auxdecor<double>("m_h1") = m_h1;
+      eventInfo->auxdecor<double>("m_h2") = m_h2;
+      eventInfo->auxdecor<double>("m_hh") = m_hh;
+      eventInfo->auxdecor<double>("dR_jets_in_resolved_h1") = dR_jets_in_h1;
+      eventInfo->auxdecor<double>("dR_jets_in_resolved_h2") = dR_jets_in_h2;
     }
 
     return StatusCode::SUCCESS;
diff --git a/HH4bAnalysis/src/VariableDumperAlg.h b/HH4bAnalysis/src/VariableDumperAlg.h
index 401fd82d7..80c818d94 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.h
+++ b/HH4bAnalysis/src/VariableDumperAlg.h
@@ -15,6 +15,7 @@
 #include <AthContainers/AuxElement.h>
 #include <SystematicsHandles/SysListHandle.h>
 #include <SystematicsHandles/SysReadHandle.h>
+#include <TLorentzVector.h>
 #include <xAODEgamma/ElectronContainer.h>
 #include <xAODEgamma/PhotonContainer.h>
 #include <xAODEventInfo/EventInfo.h>
@@ -79,6 +80,10 @@ private:
         this, "jetlargeR", "AnalysisLargeRRecoJets_%SYS%",
         "the large-R jet collection to run on"};
 
+    CP::SysReadHandle<xAOD::JetContainer> m_jetVRHandle{
+        this, "jetVRR", "AnalysisVRRecoJets_%SYS%",
+        "the Variable radius jet collection to run on"};
+
     // output variables for the current event
     unsigned int m_runNumber = 0;
     unsigned long long m_eventNumber = 0;
diff --git a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
new file mode 100644
index 000000000..ebf42668a
--- /dev/null
+++ b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
@@ -0,0 +1,21 @@
+#include "getBoostedHiggsCandidates.h"
+#include "kLargestJets.h"
+#include "map"
+// #include "vector"
+#include "string"
+#include "xAODJet/JetContainer.h"
+
+std::map<std::string, double>
+getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets)
+{
+  std::map<std::string, double> h_cand_vars;
+  h_cand_vars["sun"] = 3;
+
+  std::vector<int> twoLargestPtJetsIndices = kLargestJets(largeRjets, 2);
+
+  // need track jet container inside first and second
+  // how to associate, until when are they still inside large R
+  // tag them as b's
+
+  return h_cand_vars;
+};
\ No newline at end of file
diff --git a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
new file mode 100644
index 000000000..f1a1b1996
--- /dev/null
+++ b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
@@ -0,0 +1,10 @@
+#ifndef HH4BANALYSIS_GET_BOOSTED_HIGGS_CANDIDATES
+#define HH4BANALYSIS_GET_BOOSTED_HIGGS_CANDIDATES
+
+#include "map"
+#include "xAODJet/JetContainer.h"
+
+std::map<std::string, double>
+getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets);
+
+#endif
\ No newline at end of file
diff --git a/HH4bAnalysis/src/tools/kLargestJets.cxx b/HH4bAnalysis/src/tools/kLargestJets.cxx
new file mode 100644
index 000000000..06a7dcb84
--- /dev/null
+++ b/HH4bAnalysis/src/tools/kLargestJets.cxx
@@ -0,0 +1,49 @@
+#include "queue"
+#include "xAODJet/JetContainer.h"
+
+// efficient algorithm to find k largest elements in size n vector with
+// efficienvy O(n log k)
+// see https://stackoverflow.com/a/38391603
+
+// returns jet indices in descending order of the largest k found pt's
+std::vector<int> kLargestJets(const xAOD::JetContainer *jets, int k_)
+{
+  // Priority queues are a type of container adaptors, specifically designed
+  // such that its first element is always the greatest of the elements it
+  // contains. Using std::greater<T> causes the smallest element to appear as
+  // the top().
+  std::priority_queue<std::pair<double, int>,
+                      std::vector<std::pair<double, int>>,
+                      std::greater<std::pair<double, int>>>
+      queue;
+  long unsigned int k = k_; // number of indices we need
+
+  // loop over jets
+  const xAOD::Jet *thisJet;
+  double thisJetPt;
+  for (long unsigned int i = 0; i < jets->size(); i++)
+  {
+    thisJet = jets->at(i);
+    thisJetPt = thisJet->pt();
+    // fill queue with first k values
+    if (queue.size() < k)
+      // push	inserts element into queue and sorts it
+      queue.push(std::pair<double, int>(thisJetPt, i));
+    // if smallest element in queue is smaller than thisJetPt, replace
+    else if (queue.top().first < thisJetPt)
+    {
+      queue.pop();
+      queue.push(std::pair<double, int>(thisJetPt, i));
+    }
+  }
+
+  // return vector indices in descending order of the largest k found elements
+  k = queue.size();
+  std::vector<int> res(k);
+  for (long unsigned int i = 0; i < k; ++i)
+  {
+    res[k - i - 1] = queue.top().second;
+    queue.pop();
+  }
+  return res;
+}
diff --git a/HH4bAnalysis/src/tools/kLargestJets.h b/HH4bAnalysis/src/tools/kLargestJets.h
new file mode 100644
index 000000000..a5e004508
--- /dev/null
+++ b/HH4bAnalysis/src/tools/kLargestJets.h
@@ -0,0 +1,18 @@
+#ifndef HH4BANALYSIS_K_LARGEST_JETS
+#define HH4BANALYSIS_K_LARGEST_JETS
+
+#include "vector"
+#include "xAODJet/JetContainer.h"
+
+// efficient algorithm to find k largest elements in size n vector with
+// efficienvy O(n log k). see https://stackoverflow.com/a/38391603
+
+// it works something like this :
+// jet_with_pt's {2, 8, 7, 5, 9, 3, 6, 1, 10, 4};
+// kLargestJets(jets,5) returns
+// [8,4,1,2,6]
+
+// returns jet indices in descending order of the largest k found pt's
+std::vector<int> kLargestJets(const xAOD::JetContainer *jets, int k_);
+
+#endif
\ No newline at end of file
-- 
GitLab


From 6bd60b83d73364cddfdaeb0150955b747cf8e073 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Wed, 13 Jul 2022 15:43:15 +0200
Subject: [PATCH 03/33] saving

---
 HH4bAnalysis/share/VariableDumperConfig.py    |  52 ++----
 HH4bAnalysis/src/ResolvedAnalysis.cxx         |  34 ++++
 HH4bAnalysis/src/VariableDumperAlg.cxx        | 157 +++++++++---------
 HH4bAnalysis/src/VariableDumperAlg.h          |   8 +-
 .../src/tools/getBoostedHiggsCandidates.cxx   |  12 +-
 .../src/tools/getBoostedHiggsCandidates.h     |   6 +-
 6 files changed, 146 insertions(+), 123 deletions(-)
 create mode 100644 HH4bAnalysis/src/ResolvedAnalysis.cxx

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 0c6989a9c..ff73a2508 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -51,7 +51,7 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
 
     reco4JetContainerName = getContainerName("Reco4PFlowJets", isDaodPhyslite)
     reco10JetContainerName = getContainerName("Reco10PFlowJets", isDaodPhyslite)
-    recoVRJetContainerName = getContainerName("RecoVRPFlowJets", isDaodPhyslite)
+    recoVRJetContainerName = getContainerName("RecoVRTrackJets", isDaodPhyslite)
     muonsContainerName = getContainerName("Muons", isDaodPhyslite)
     electronsContainerName = getContainerName("Electrons", isDaodPhyslite)
     photonsContainerName = getContainerName("Photons", isDaodPhyslite)
@@ -225,17 +225,17 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
 
     # Define and configure a tool instance
     # Properties can be set as keyword arguments to the tool constructor
-    # bTagSelectionTool = CompFactory.BTaggingSelectionTool(
-    #     "bTagSelectionTool",
-    #     FlvTagCutDefinitionsFileName=(
-    #         "xAODBTaggingEfficiency/13TeV/2021-22-13TeV-MC16-CDI-2021-12-02_v2.root"
-    #     ),
-    #     TaggerName="DL1dv00",
-    #     OperatingPoint="FixedCutBEff_77",
-    #     JetAuthor=reco4JetContainerName,
-    #     MinPt=20e3,
-    #     MaxEta=2.5,
-    # )
+    bTagSelectionTool = CompFactory.BTaggingSelectionTool(
+        "bTagSelectionTool",
+        FlvTagCutDefinitionsFileName=(
+            "xAODBTaggingEfficiency/13TeV/2021-22-13TeV-MC16-CDI-2021-12-02_v2.root"
+        ),
+        TaggerName="DL1dv00",
+        OperatingPoint="FixedCutBEff_77",
+        JetAuthor=reco4JetContainerName,
+        MinPt=20e3,
+        MaxEta=2.5,
+    )
 
     from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
 
@@ -262,31 +262,6 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
     for largeJetAlg in largeJetAlgsCnv:
         cfg.addEventAlgo(largeJetAlg, largeRrecojetSequenceCnv.getName())
 
-    from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
-
-    largeRrecojetSequence = makeJetAnalysisSequence(
-        dataType,
-        reco10JetContainerName,
-        postfix="VR",
-        deepCopyOutput=False,
-        shallowViewOutput=True,
-        runGhostMuonAssociation=False,
-        enableCutflow=False,
-        enableKinematicHistograms=False,
-        largeRMass="Comb",
-    )
-    largeRrecojetSequence.configure(
-        inputName=recoVRJetContainerName, outputName="AnalysisVRRecoJets_%SYS%"
-    )
-    # print(largeRrecojetSequence)  # For debugging
-    # Convert to new configurables
-    largeRrecojetSequenceCnv, largeJetAlgsCnv = convertSequenceAndGetAlgs(
-        CompFactory, largeRrecojetSequence
-    )
-    cfg.addSequence(largeRrecojetSequenceCnv)
-    for largeJetAlg in largeJetAlgsCnv:
-        cfg.addEventAlgo(largeJetAlg, largeRrecojetSequenceCnv.getName())
-
     # Include, and then set up the overlap analysis algorithm sequence:
     from AsgAnalysisAlgorithms.OverlapAnalysisSequence import (
         makeOverlapAnalysisSequence,
@@ -343,9 +318,10 @@ def VariableDumperCfg(flags, isDaodPhyslite, outfname):
         CompFactory.HH4B.VariableDumperAlg(
             "VariableDumper",
             EventInfoKey="EventInfo",
+            VRTrackJetsKey=recoVRJetContainerName,
             RootStreamName="ANALYSIS",
             applyJetCleaning=True,
-            # BTaggingSelectionTool=bTagSelectionTool,
+            BTaggingSelectionTool=bTagSelectionTool,
         )
     )
 
diff --git a/HH4bAnalysis/src/ResolvedAnalysis.cxx b/HH4bAnalysis/src/ResolvedAnalysis.cxx
new file mode 100644
index 000000000..7ad886b71
--- /dev/null
+++ b/HH4bAnalysis/src/ResolvedAnalysis.cxx
@@ -0,0 +1,34 @@
+// A simple TTreeReader use: read data from hsimple.root (written by hsimple.C)
+
+#include "TFile.h"
+#include "TH1F.h"
+#include "TTreeReader.h"
+#include "TTreeReaderValue.h"
+
+void hsimpleReader()
+{
+  // Create a histogram for the values we read.
+  TH1F("h1", "ntuple", 100, -4, 4);
+
+  // Open the file containing the tree.
+  TFile *myFile = TFile::Open("$ROOTSYS/tutorials/hsimple.root");
+
+  // Create a TTreeReader for the tree, for instance by passing the
+  // TTree's name and the TDirectory / TFile it is in.
+  TTreeReader myReader("ntuple", myFile);
+
+  // The branch "px" contains floats; access them as myPx.
+  TTreeReaderValue<Float_t> myPx(myReader, "px");
+  // The branch "py" contains floats, too; access those as myPy.
+  TTreeReaderValue<Float_t> myPy(myReader, "py");
+
+  // Loop over all entries of the TTree or TChain.
+  while (myReader.Next())
+  {
+    // Just access the data as if myPx and myPy were iterators (note the '*'
+    // in front of them):
+    myHist->Fill(*myPx + *myPy);
+  }
+
+  myHist->Draw();
+}
\ No newline at end of file
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index efe31cee0..d14bae242 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -7,9 +7,9 @@
 
 // Class definition
 #include "VariableDumperAlg.h"
-// #include "tools/getBoostedHiggsCandidates.h"
+#include "tools/getBoostedHiggsCandidates.h"
 // #include "tools/kLargestJets.h"
-
+#include "map"
 //
 // method implementations
 //
@@ -20,10 +20,8 @@ namespace HH4B
                                         ISvcLocator *pSvcLocator)
       : AthHistogramAlgorithm(name, pSvcLocator),
         m_acc_DFCommonJets_eventClean_LooseBad(
-            "DFCommonJets_eventClean_LooseBad") m_acc_VRTrackJets
-
-        SG::AuxElement::ConstAccessor<char> m_acc_VRTrackJets;
-  AntiKtVR30Rmax4Rmin02PV0TrackJets(DataVector<xAOD::Jet_v1>)[Jet]
+            "DFCommonJets_eventClean_LooseBad"),
+        m_acc_VRTrackJets("AntiKtVR30Rmax4Rmin02PV0TrackJets")
   {
     declareProperty("applyJetCleaning", m_applyJetCleaning);
   }
@@ -46,6 +44,7 @@ namespace HH4B
     ATH_CHECK(m_btagSelTool.retrieve());
 
     ATH_CHECK(m_EventInfoKey.initialize());
+    ATH_CHECK(m_VRTrackJetsKey.initialize());
     ATH_CHECK(m_systematicsList.initialize());
 
     ATH_MSG_INFO("Will search \"" << m_EventInfoKey.key()
@@ -63,7 +62,10 @@ namespace HH4B
       std::string sysname;
       ATH_CHECK(m_systematicsList.service().makeSystematicsName(sysname,
                                                                 "%SYS%", sys));
+
       ATH_MSG_INFO("Will apply sysname \"" << sysname << "\" for event");
+
+      // Do something with Eventinfo
       SG::ReadHandle<xAOD::EventInfo> eventInfo(m_EventInfoKey);
       ATH_CHECK(eventInfo.isValid());
       // jet cleaning
@@ -90,15 +92,28 @@ namespace HH4B
       const xAOD::JetContainer *antiKt10RecoJets(nullptr);
       ATH_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
       // do something with antiKt10RecoJets
-      const xAOD::JetContainer *antiKtVRRecoJets(nullptr);
-      ATH_CHECK(m_jetVRHandle.retrieve(antiKtVRRecoJets, sys));
-      // do something with antiKt10RecoJets
-      ATH_MSG_DEBUG("Number of 0.4 jets in event " << antiKt4RecoJets->size());
-      ATH_MSG_DEBUG("Number of 1.0 jets in event "
-                    << antiKt10RecoJets->size());
+      // get Variable Radius Track jets for large R jet substructure
+      SG::ReadHandle<xAOD::JetContainer> VRTrackJetsHandle(m_VRTrackJetsKey);
+      ATH_CHECK(VRTrackJetsHandle.isValid());
+      // convert handle to container
+      const xAOD::JetContainer *VRTrackJets = VRTrackJetsHandle.cptr();
+
+      // set defaults
+      std::map<std::string, double> h_cand_vars;
+      h_cand_vars["m_h1"] = -1;
+      h_cand_vars["m_h2"] = -1;
+      h_cand_vars["m_hh"] = -1;
+      h_cand_vars["dR_jets_in_h1"] = -1;
+      h_cand_vars["dR_jets_in_h2"] = -1;
+
+      getBoostedHiggsCandidates(antiKt10RecoJets, VRTrackJets, h_cand_vars);
+
+      // recommended by ftag  Remove the event if any of your signal jets have
+      // relativeDeltaRToVRJet < 1.0.
+      // getBoostedHiggsCandidates(antiKt10RecoJets);
 
       // std::cout << antiKt4RecoJets->size() << "\n";
-      // std::cout << jetSmallBTag->size() << "\n";
+      // std::cout << VRTrackJets->size() << "\n";
 
       // for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
       // {
@@ -112,62 +127,58 @@ namespace HH4B
 
       // TODO: send in btagged jets
       // set defaults
-      eventInfo->auxdecor<double>("dR_jets_in_h1") = -1;
-      eventInfo->auxdecor<double>("dR_jets_in_h2") = -1;
-      eventInfo->auxdecor<double>("m_h1") = -1;
-      eventInfo->auxdecor<double>("m_h2") = -1;
-      eventInfo->auxdecor<double>("m_hh") = -1;
-
-      // // check if we have 4 jets
-      // if (antiKt4RecoJets->size() < 4)
-      // {
-      //   return StatusCode::SUCCESS;
-      // }
-      // // get indices of 4 largest pt jets
-      // std::vector<int> fourLargestPtJetsIndices =
-      //     kLargestJets(antiKt4RecoJets, 4);
 
-      // const xAOD::Jet *largestPtJet =
-      //     antiKt4RecoJets->at(fourLargestPtJetsIndices[0]);
+      // check if we have 4 jets
+      if (antiKt4RecoJets->size() < 4)
+      {
+        return StatusCode::SUCCESS;
+      }
+      // get indices of 4 largest pt jets
+      std::vector<int> fourLargestPtJetsIndices =
+          kLargestJets(antiKt4RecoJets, 4);
+
+      const xAOD::Jet *largestPtJet =
+          antiKt4RecoJets->at(fourLargestPtJetsIndices[0]);
 
-      // // calc dR to other higgs candidate jets
-      // std::vector<double> dRtoLargestPtJet;
-      // for (int jetIndex : fourLargestPtJetsIndices)
-      // {
-      //   const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
-      //   double thisDRtoLargestPtJet =
-      //   thisJet->p4().DeltaR(largestPtJet->p4());
-      //   dRtoLargestPtJet.push_back(thisDRtoLargestPtJet);
-      //   ATH_MSG_DEBUG(thisDRtoLargestPtJet);
-      // }
+      // calc dR to other higgs candidate jets
+      std::vector<double> dRtoLargestPtJet;
+      for (int jetIndex : fourLargestPtJetsIndices)
+      {
+        const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
+        double thisDRtoLargestPtJet = thisJet->p4().DeltaR(largestPtJet->p4());
+        dRtoLargestPtJet.push_back(thisDRtoLargestPtJet);
+        ATH_MSG_DEBUG(thisDRtoLargestPtJet);
+      }
+
+      // get closest jet to leading jet
+      int closestToLeadingJetEntry =
+          std::min_element(dRtoLargestPtJet.begin(), dRtoLargestPtJet.end()) -
+          dRtoLargestPtJet.begin();
+      const xAOD::Jet *closestToLeadingJet = antiKt4RecoJets->at(
+          fourLargestPtJetsIndices[closestToLeadingJetEntry]);
+
+      // make higgs candidates
+      TLorentzVector h1_cand = largestPtJet->p4() + closestToLeadingJet->p4();
 
-      // // get closest jet to leading jet
-      // int closestToLeadingJetEntry =
-      //     std::min_element(dRtoLargestPtJet.begin(), dRtoLargestPtJet.end())
-      //     - dRtoLargestPtJet.begin();
-      // const xAOD::Jet *closestToLeadingJet = antiKt4RecoJets->at(
-      //     fourLargestPtJetsIndices[closestToLeadingJetEntry]);
-
-      // // make higgs candidates
-      // TLorentzVector h1_cand = largestPtJet->p4() +
-      // closestToLeadingJet->p4(); double dR_jets_in_h1 =
-      //     largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
-      // // make a copy of the indices and delete the ones of the h1_cand
-      // // order matters!
-      // std::vector<int> otherJetIndices = fourLargestPtJetsIndices;
-      // otherJetIndices.erase(otherJetIndices.begin() +
-      //                       closestToLeadingJetEntry);
-      // otherJetIndices.erase(otherJetIndices.begin());
-
-      // const xAOD::Jet *otherJet1 = antiKt4RecoJets->at(otherJetIndices[0]);
-      // const xAOD::Jet *otherJet2 = antiKt4RecoJets->at(otherJetIndices[1]);
-
-      // TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
-      // double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
-
-      // double m_h1 = h1_cand.M();
-      // double m_h2 = h2_cand.M();
-      // double m_hh = (h1_cand + h2_cand).M();
+      double dR_jets_in_h1 =
+          largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
+
+      // make a copy of the indices and delete the ones of the h1_cand
+      // order matters!
+      std::vector<int> otherJetIndices = fourLargestPtJetsIndices;
+      otherJetIndices.erase(otherJetIndices.begin() +
+                            closestToLeadingJetEntry);
+      otherJetIndices.erase(otherJetIndices.begin());
+
+      const xAOD::Jet *otherJet1 = antiKt4RecoJets->at(otherJetIndices[0]);
+      const xAOD::Jet *otherJet2 = antiKt4RecoJets->at(otherJetIndices[1]);
+
+      TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
+      double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
+
+      double m_h1 = h1_cand.M();
+      double m_h2 = h2_cand.M();
+      double m_hh = (h1_cand + h2_cand).M();
 
       // TODO: return resolved function as std::map "m_h1"
 
@@ -181,16 +192,12 @@ namespace HH4B
       //   std::cout << isTag77(*thisJet) << "\n";
       // }
 
-      // recommended by ftag  Remove the event if any of your signal jets have
-      // relativeDeltaRToVRJet < 1.0.
-      // getBoostedHiggsCandidates(antiKt10RecoJets);
-
       //  write out Higgs candidates
-      eventInfo->auxdecor<double>("m_h1") = m_h1;
-      eventInfo->auxdecor<double>("m_h2") = m_h2;
-      eventInfo->auxdecor<double>("m_hh") = m_hh;
-      eventInfo->auxdecor<double>("dR_jets_in_resolved_h1") = dR_jets_in_h1;
-      eventInfo->auxdecor<double>("dR_jets_in_resolved_h2") = dR_jets_in_h2;
+      // eventInfo->auxdecor<double>("m_h1") = m_h1;
+      // eventInfo->auxdecor<double>("m_h2") = m_h2;
+      // eventInfo->auxdecor<double>("m_hh") = m_hh;
+      // eventInfo->auxdecor<double>("dR_jets_in_resolved_h1") = dR_jets_in_h1;
+      // eventInfo->auxdecor<double>("dR_jets_in_resolved_h2") = dR_jets_in_h2;
     }
 
     return StatusCode::SUCCESS;
diff --git a/HH4bAnalysis/src/VariableDumperAlg.h b/HH4bAnalysis/src/VariableDumperAlg.h
index 80c818d94..0147f98b1 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.h
+++ b/HH4bAnalysis/src/VariableDumperAlg.h
@@ -53,13 +53,15 @@ private:
     // Member variables for configuration
     SG::ReadHandleKey<xAOD::EventInfo> m_EventInfoKey{
         this, "EventInfoKey", "", "EventInfo container to dump"};
-
+    SG::ReadHandleKey<xAOD::JetContainer> m_VRTrackJetsKey{
+        this, "VRTrackJetsKey", "", "VRTrackJets container to use"};
     // for jet cleaning: quality criteria to identify events which are
     // consistent with noise in the calorimeter or non-collision background
     // For details last paragraph on page 6:
     // https://cds.cern.ch/record/2809414/files/ATLAS-COM-CONF-2022-035.pdf
     bool m_applyJetCleaning;
     SG::AuxElement::ConstAccessor<char> m_acc_DFCommonJets_eventClean_LooseBad;
+    SG::AuxElement::ConstAccessor<char> m_acc_VRTrackJets;
 
     CP::SysReadHandle<xAOD::ElectronContainer> m_electronHandle{
         this, "electrons", "AnalysisElectrons_%SYS%",
@@ -80,10 +82,6 @@ private:
         this, "jetlargeR", "AnalysisLargeRRecoJets_%SYS%",
         "the large-R jet collection to run on"};
 
-    CP::SysReadHandle<xAOD::JetContainer> m_jetVRHandle{
-        this, "jetVRR", "AnalysisVRRecoJets_%SYS%",
-        "the Variable radius jet collection to run on"};
-
     // output variables for the current event
     unsigned int m_runNumber = 0;
     unsigned long long m_eventNumber = 0;
diff --git a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
index ebf42668a..32cf7ad86 100644
--- a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
+++ b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
@@ -6,11 +6,17 @@
 #include "xAODJet/JetContainer.h"
 
 std::map<std::string, double>
-getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets)
+getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
+                          const xAOD::JetContainer *VRTrackJets,
+                          std::map<std::string, double> h_cand_vars);
 {
-  std::map<std::string, double> h_cand_vars;
-  h_cand_vars["sun"] = 3;
 
+  // need two large R
+  // least pt of large R's 250
+  // largest at least 450
+  // eta < 2.0
+
+  // delta eta between large r jets
   std::vector<int> twoLargestPtJetsIndices = kLargestJets(largeRjets, 2);
 
   // need track jet container inside first and second
diff --git a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
index f1a1b1996..3599290a4 100644
--- a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
+++ b/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
@@ -5,6 +5,8 @@
 #include "xAODJet/JetContainer.h"
 
 std::map<std::string, double>
-getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets);
+getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
+                          const xAOD::JetContainer *VRTrackJets,
+                          std::map<std::string, double> h_cand_vars);
 
-#endif
\ No newline at end of file
+#endif
-- 
GitLab


From 18b195d092011830645fcd6516ea0384250d14b2 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Mon, 18 Jul 2022 09:23:42 +0200
Subject: [PATCH 04/33] saving

---
 ...iggsCandidates.cxx => BoostedAnalysis.cxx} |  6 +-
 ...tedHiggsCandidates.h => BoostedAnalysis.h} |  4 +-
 HH4bAnalysis/src/ResolvedAnalysis.cxx         | 49 +++++++---------
 HH4bAnalysis/src/ResolvedAnalysis.h           | 12 ++++
 HH4bAnalysis/src/VariableDumperAlg.cxx        | 58 +------------------
 5 files changed, 43 insertions(+), 86 deletions(-)
 rename HH4bAnalysis/src/{tools/getBoostedHiggsCandidates.cxx => BoostedAnalysis.cxx} (79%)
 rename HH4bAnalysis/src/{tools/getBoostedHiggsCandidates.h => BoostedAnalysis.h} (74%)
 create mode 100644 HH4bAnalysis/src/ResolvedAnalysis.h

diff --git a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx b/HH4bAnalysis/src/BoostedAnalysis.cxx
similarity index 79%
rename from HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
rename to HH4bAnalysis/src/BoostedAnalysis.cxx
index 32cf7ad86..03fcbb0a1 100644
--- a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.cxx
+++ b/HH4bAnalysis/src/BoostedAnalysis.cxx
@@ -1,4 +1,4 @@
-#include "getBoostedHiggsCandidates.h"
+#include "BoostedAnalysis.h"
 #include "kLargestJets.h"
 #include "map"
 // #include "vector"
@@ -23,5 +23,9 @@ getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
   // how to associate, until when are they still inside large R
   // tag them as b's
 
+  // recommended by ftag  Remove the event if any of your signal jets have
+  // relativeDeltaRToVRJet < 1.0.
+  // getBoostedHiggsCandidates(antiKt10RecoJets);
+
   return h_cand_vars;
 };
\ No newline at end of file
diff --git a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h b/HH4bAnalysis/src/BoostedAnalysis.h
similarity index 74%
rename from HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
rename to HH4bAnalysis/src/BoostedAnalysis.h
index 3599290a4..6738ea504 100644
--- a/HH4bAnalysis/src/tools/getBoostedHiggsCandidates.h
+++ b/HH4bAnalysis/src/BoostedAnalysis.h
@@ -1,5 +1,5 @@
-#ifndef HH4BANALYSIS_GET_BOOSTED_HIGGS_CANDIDATES
-#define HH4BANALYSIS_GET_BOOSTED_HIGGS_CANDIDATES
+#ifndef HH4BANALYSIS_BOOSTED_ANALYSIS
+#define HH4BANALYSIS_BOOSTED_ANALYSIS
 
 #include "map"
 #include "xAODJet/JetContainer.h"
diff --git a/HH4bAnalysis/src/ResolvedAnalysis.cxx b/HH4bAnalysis/src/ResolvedAnalysis.cxx
index 7ad886b71..ce3256ab1 100644
--- a/HH4bAnalysis/src/ResolvedAnalysis.cxx
+++ b/HH4bAnalysis/src/ResolvedAnalysis.cxx
@@ -1,34 +1,27 @@
-// A simple TTreeReader use: read data from hsimple.root (written by hsimple.C)
+#include "ResolvedAnalysis.h"
+#include "kLargestJets.h"
+#include "map"
+// #include "vector"
+#include "string"
+#include "xAODJet/JetContainer.h"
 
-#include "TFile.h"
-#include "TH1F.h"
-#include "TTreeReader.h"
-#include "TTreeReaderValue.h"
-
-void hsimpleReader()
+std::map<std::string, double>
+getResolvedHiggsCandidates(const xAOD::JetContainer *largeRjets,
+                           const xAOD::JetContainer *VRTrackJets,
+                           std::map<std::string, double> h_cand_vars);
 {
-  // Create a histogram for the values we read.
-  TH1F("h1", "ntuple", 100, -4, 4);
-
-  // Open the file containing the tree.
-  TFile *myFile = TFile::Open("$ROOTSYS/tutorials/hsimple.root");
 
-  // Create a TTreeReader for the tree, for instance by passing the
-  // TTree's name and the TDirectory / TFile it is in.
-  TTreeReader myReader("ntuple", myFile);
+  // need two large R
+  // least pt of large R's 250
+  // largest at least 450
+  // eta < 2.0
 
-  // The branch "px" contains floats; access them as myPx.
-  TTreeReaderValue<Float_t> myPx(myReader, "px");
-  // The branch "py" contains floats, too; access those as myPy.
-  TTreeReaderValue<Float_t> myPy(myReader, "py");
+  // delta eta between large r jets
+  std::vector<int> twoLargestPtJetsIndices = kLargestJets(largeRjets, 2);
 
-  // Loop over all entries of the TTree or TChain.
-  while (myReader.Next())
-  {
-    // Just access the data as if myPx and myPy were iterators (note the '*'
-    // in front of them):
-    myHist->Fill(*myPx + *myPy);
-  }
+  // need track jet container inside first and second
+  // how to associate, until when are they still inside large R
+  // tag them as b's
 
-  myHist->Draw();
-}
\ No newline at end of file
+  return h_cand_vars;
+};
\ No newline at end of file
diff --git a/HH4bAnalysis/src/ResolvedAnalysis.h b/HH4bAnalysis/src/ResolvedAnalysis.h
new file mode 100644
index 000000000..d2376e0eb
--- /dev/null
+++ b/HH4bAnalysis/src/ResolvedAnalysis.h
@@ -0,0 +1,12 @@
+#ifndef HH4BANALYSIS_BOOSTED_ANALYSIS
+#define HH4BANALYSIS_BOOSTED_ANALYSIS
+
+#include "map"
+#include "xAODJet/JetContainer.h"
+
+std::map<std::string, double>
+getResolvedHiggsCandidates(const xAOD::JetContainer *largeRjets,
+                           const xAOD::JetContainer *VRTrackJets,
+                           std::map<std::string, double> h_cand_vars);
+
+#endif
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index d14bae242..894a43615 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -7,7 +7,7 @@
 
 // Class definition
 #include "VariableDumperAlg.h"
-#include "tools/getBoostedHiggsCandidates.h"
+#include "getBoostedHiggsCandidates.h"
 // #include "tools/kLargestJets.h"
 #include "map"
 //
@@ -106,7 +106,8 @@ namespace HH4B
       h_cand_vars["dR_jets_in_h1"] = -1;
       h_cand_vars["dR_jets_in_h2"] = -1;
 
-      getBoostedHiggsCandidates(antiKt10RecoJets, VRTrackJets, h_cand_vars);
+      h_cand_vars = getBoostedHiggsCandidates(antiKt10RecoJets, VRTrackJets,
+                                              h_cand_vars);
 
       // recommended by ftag  Remove the event if any of your signal jets have
       // relativeDeltaRToVRJet < 1.0.
@@ -126,59 +127,6 @@ namespace HH4B
       // }
 
       // TODO: send in btagged jets
-      // set defaults
-
-      // check if we have 4 jets
-      if (antiKt4RecoJets->size() < 4)
-      {
-        return StatusCode::SUCCESS;
-      }
-      // get indices of 4 largest pt jets
-      std::vector<int> fourLargestPtJetsIndices =
-          kLargestJets(antiKt4RecoJets, 4);
-
-      const xAOD::Jet *largestPtJet =
-          antiKt4RecoJets->at(fourLargestPtJetsIndices[0]);
-
-      // calc dR to other higgs candidate jets
-      std::vector<double> dRtoLargestPtJet;
-      for (int jetIndex : fourLargestPtJetsIndices)
-      {
-        const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
-        double thisDRtoLargestPtJet = thisJet->p4().DeltaR(largestPtJet->p4());
-        dRtoLargestPtJet.push_back(thisDRtoLargestPtJet);
-        ATH_MSG_DEBUG(thisDRtoLargestPtJet);
-      }
-
-      // get closest jet to leading jet
-      int closestToLeadingJetEntry =
-          std::min_element(dRtoLargestPtJet.begin(), dRtoLargestPtJet.end()) -
-          dRtoLargestPtJet.begin();
-      const xAOD::Jet *closestToLeadingJet = antiKt4RecoJets->at(
-          fourLargestPtJetsIndices[closestToLeadingJetEntry]);
-
-      // make higgs candidates
-      TLorentzVector h1_cand = largestPtJet->p4() + closestToLeadingJet->p4();
-
-      double dR_jets_in_h1 =
-          largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
-
-      // make a copy of the indices and delete the ones of the h1_cand
-      // order matters!
-      std::vector<int> otherJetIndices = fourLargestPtJetsIndices;
-      otherJetIndices.erase(otherJetIndices.begin() +
-                            closestToLeadingJetEntry);
-      otherJetIndices.erase(otherJetIndices.begin());
-
-      const xAOD::Jet *otherJet1 = antiKt4RecoJets->at(otherJetIndices[0]);
-      const xAOD::Jet *otherJet2 = antiKt4RecoJets->at(otherJetIndices[1]);
-
-      TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
-      double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
-
-      double m_h1 = h1_cand.M();
-      double m_h2 = h2_cand.M();
-      double m_hh = (h1_cand + h2_cand).M();
 
       // TODO: return resolved function as std::map "m_h1"
 
-- 
GitLab


From e5b38644bb93a4b6f36c961de0a846d0c3cefe55 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Tue, 19 Jul 2022 19:00:30 +0200
Subject: [PATCH 05/33] progress...

---
 HH4bAnalysis/share/VariableDumperConfig.py |  60 ++++++++++--
 HH4bAnalysis/src/BoostedAnalysis.cxx       |  93 ++++++++++++++++--
 HH4bAnalysis/src/BoostedAnalysis.h         |   1 -
 HH4bAnalysis/src/ResolvedAnalysis.cxx      |  64 +++++++++---
 HH4bAnalysis/src/ResolvedAnalysis.h        |   9 +-
 HH4bAnalysis/src/VariableDumperAlg.cxx     | 108 ++++++++-------------
 HH4bAnalysis/src/VariableDumperAlg.h       |  11 +--
 7 files changed, 235 insertions(+), 111 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index d6f4115f5..5ceab230a 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -8,6 +8,8 @@
 # Basic setup
 import sys
 
+from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence
+from AnaAlgorithm.DualUseConfig import createAlgorithm
 from AthenaCommon import Logging
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
@@ -230,14 +232,55 @@ def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
         inputName=reco4JetContainerName,
         outputName="AnalysisJets_%SYS%",
     )
-    # print(jetSequence)  # For debugging
+    print(jetSequence)  # For debugging
     # Convert to new configurables
     jetSequenceCnv, jetAlgsCnv = convertSequenceAndGetAlgs(CompFactory, jetSequence)
     cfg.addSequence(jetSequenceCnv)
     for jetAlg in jetAlgsCnv:
         cfg.addEventAlgo(jetAlg, jetSequenceCnv.getName())
 
-    from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
+    # Variable Radius jets Ftag sqeuence
+    VRSequence = AnaAlgSequence("VRTrackFTagAnalysisSequence")
+    # the following lines make a shallow copy,
+    # this isn't needed anymore with this MR
+    # https://gitlab.cern.ch/atlas/athena/-/merge_requests/54929
+    alg = createAlgorithm("CP::AsgViewFromSelectionAlg", "VRJetSelectionAlg")
+    VRSequence.append(
+        alg,
+        inputPropName="input",
+        outputPropName="output",
+        stageName="selection",
+        dynConfig={},
+    )
+    VRftagSequence = makeFTagAnalysisSequence(
+        VRSequence,
+        dataType,
+        "AntiKtVR30Rmax4Rmin02TrackJets",
+        btagWP="FixedCutBEff_77",
+        btagger="DL1r",
+        postfix="VR",
+        preselection=None,
+        kinematicSelection=True,
+        noEfficiency=False,
+        legacyRecommendations=False,
+        enableCutflow=False,
+        minPt=20000,
+    )
+
+    for ftagAlg in VRftagSequence:
+        if "FTagSelectionAlg" in ftagAlg.getName():
+            ftagAlg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile
+        if "FTagEfficiencyScaleFactorAlg" in ftagAlg.getName():
+            ftagAlg.efficiencyTool.ScaleFactorFileName = bTagCalibFile
+
+    VRSequence.configure(
+        inputName=recoVRJetContainerName, outputName="VRTrackJetsBTAG_%SYS%"
+    )
+
+    VRjetSequenceCnv, VRjetAlgsCnv = convertSequenceAndGetAlgs(CompFactory, VRSequence)
+    cfg.addSequence(VRjetSequenceCnv)
+    for VRjetAlg in VRjetAlgsCnv:
+        cfg.addEventAlgo(VRjetAlg, VRjetSequenceCnv.getName())
 
     largeRrecojetSequence = makeJetAnalysisSequence(
         dataType,
@@ -318,9 +361,8 @@ def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
         CompFactory.HH4B.VariableDumperAlg(
             "VariableDumper",
             EventInfoKey="EventInfo",
-            VRTrackJetsKey=recoVRJetContainerName,
             RootStreamName="ANALYSIS",
-            applyJetCleaning=True,
+            # btag_wps=btag_wps,
         )
     )
 
@@ -338,11 +380,6 @@ def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
         # we currently don't have any pileup calib files setup
         # 'EventInfo.PileupWeight_%SYS% -> pileupWeight_%SYS%',
         "EventInfo.mcEventWeights   -> mcEventWeights",
-        "EventInfo.m_h1   -> m_h1",
-        "EventInfo.m_h2   -> m_h2",
-        "EventInfo.m_hh   -> m_hh",
-        "EventInfo.dR_jets_in_h1   -> dR_jets_in_h1",
-        "EventInfo.dR_jets_in_h2   -> dR_jets_in_h2",
         "AnalysisElectrons_%SYS%.pt  -> el_%SYS%_pt",
         "AnalysisElectrons_%SYS%.eta -> el_%SYS%_eta",
         "AnalysisElectrons_%SYS%.phi -> el_%SYS%_phi",
@@ -377,6 +414,11 @@ def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
         "AnalysisLargeRRecoJetsOR_%SYS%.pt  -> recojet_antikt10_OR_%SYS%_pt",
         "AnalysisLargeRRecoJetsOR_%SYS%.eta -> recojet_antikt10_OR_%SYS%_eta",
         "AnalysisLargeRRecoJetsOR_%SYS%.phi -> recojet_antikt10_OR_%SYS%_phi",
+        "EventInfo.resolved_m_h1   -> resolved_m_h1",
+        "EventInfo.resolved_m_h2   -> resolved_m_h2",
+        "EventInfo.resolved_m_hh   -> resolved_m_hh",
+        "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
+        "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
     ]
     ntupleMaker.Branches += [
         f"AnalysisJets_%SYS%.ftag_select_{btag_wp} -> recojet_antikt4_%SYS%_{btag_wp}"
diff --git a/HH4bAnalysis/src/BoostedAnalysis.cxx b/HH4bAnalysis/src/BoostedAnalysis.cxx
index 03fcbb0a1..3f1016e03 100644
--- a/HH4bAnalysis/src/BoostedAnalysis.cxx
+++ b/HH4bAnalysis/src/BoostedAnalysis.cxx
@@ -1,23 +1,26 @@
 #include "BoostedAnalysis.h"
-#include "kLargestJets.h"
 #include "map"
-// #include "vector"
 #include "string"
+#include "tools/kLargestJets.h"
 #include "xAODJet/JetContainer.h"
 
 std::map<std::string, double>
 getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
-                          const xAOD::JetContainer *VRTrackJets,
-                          std::map<std::string, double> h_cand_vars);
+                          std::map<std::string, double> h_cand_vars)
 {
 
-  // need two large R
   // least pt of large R's 250
   // largest at least 450
   // eta < 2.0
 
   // delta eta between large r jets
-  std::vector<int> twoLargestPtJetsIndices = kLargestJets(largeRjets, 2);
+
+  // check if we have at least 2 large R jets
+  if (largeRjets->size() < 2)
+  {
+    return h_cand_vars;
+  }
+  std::vector<int> twoLeadingPtJetsIndices = kLargestJets(largeRjets, 2);
 
   // need track jet container inside first and second
   // how to associate, until when are they still inside large R
@@ -25,7 +28,83 @@ getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
 
   // recommended by ftag  Remove the event if any of your signal jets have
   // relativeDeltaRToVRJet < 1.0.
-  // getBoostedHiggsCandidates(antiKt10RecoJets);
+
+  // ghost associated track jets are only on the untrimmed 1.0 jets
+  SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
+      m_acc_largeR_untrimmed("Parent");
+  SG::AuxElement::ConstAccessor<
+      std::vector<ElementLink<xAOD::IParticleContainer>>>
+      m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
+
+  SG::AuxElement::ConstAccessor<char> isBtag(
+      "ftag_select_DL1r_FixedCutBEff_77");
+  std::vector<std::vector<ElementLink<xAOD::IParticleContainer>>>
+      btagged_VRTrackjets;
+  // loop over the two large R jets
+  for (int i : twoLeadingPtJetsIndices)
+  {
+    const xAOD::Jet *thisJet = largeRjets->at(i);
+    // get ghost associated VR track jets
+    const xAOD::Jet *thisJet_untrimmed = *m_acc_largeR_untrimmed(*thisJet);
+    const std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
+        m_acc_VRTrackJets(*thisJet_untrimmed);
+    // get the btagged VR trackjets per large R jet
+    for (auto VRjet : VRTrackjets)
+    {
+      if (isBtag(**VRjet))
+      {
+        // (i is the large R jet index not a counter)
+        btagged_VRTrackjets[i].emplace_back(VRjet);
+      }
+    }
+    // check if we have at least 2 per large R jet, otherwise exit
+    // (subject to change)
+    if (btagged_VRTrackjets[i].size() < 2)
+    {
+      return h_cand_vars;
+    }
+  }
+  // // make higgs candidates
+  // TLorentzVector h1_cand = largestPtJet->p4() + closestToLeadingJet->p4();
+  // double dR_jets_in_h1 =
+  // largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
+
+  // // make a copy of the indices and delete the ones of the h1_cand to get
+  // the
+  // // ones of the h2_cand, order matters!
+  // std::vector<int> otherJetIndices = fourLargestPtJetsIndices;
+  // otherJetIndices.erase(otherJetIndices.begin() + closestToLeadingJetEntry);
+  // otherJetIndices.erase(otherJetIndices.begin());
+
+  // const xAOD::Jet *otherJet1 = smallRjets->at(otherJetIndices[0]);
+  // const xAOD::Jet *otherJet2 = smallRjets->at(otherJetIndices[1]);
+
+  // TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
+  // double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
+
+  // // write to dictionary
+  // h_cand_vars["resolved_m_h1"] = h1_cand.M();
+  // h_cand_vars["resolved_m_h2"] = h2_cand.M();
+  // h_cand_vars["resolved_m_hh"] = (h1_cand + h2_cand).M();
+  // h_cand_vars["resolved_dR_jets_in_h1"] = dR_jets_in_h1;
+  // h_cand_vars["resolved_dR_jets_in_h2"] = dR_jets_in_h2;
+
+  //   const xAOD::Jet *thisJet;
+
+  //   SG::AuxElement::ConstAccessor<char> isTag77(
+
+  // GhostVR30Rmax4Rmin02PV0TrackJet
+  //   SG::AuxElement::ConstAccessor<char> isTag77(
+  //       "ftag_select_DL1r_FixedCutBEff_77");
+  //   for (long unsigned int i = 0; i < VRTrackJets->size(); i++)
+  //   {
+  //     thisJet = VRTrackJets->at(i);
+  //     std::cout << int(isTag77(*thisJet)) << std::endl;
+  //   }
+
+  // bool pass_btag = false;
+  // if (isTag77.isAvailable(*jet))
+  //   VRtrackjet_btag77.push_back(isTag77(*jet));
 
   return h_cand_vars;
 };
\ No newline at end of file
diff --git a/HH4bAnalysis/src/BoostedAnalysis.h b/HH4bAnalysis/src/BoostedAnalysis.h
index 6738ea504..2efad7b90 100644
--- a/HH4bAnalysis/src/BoostedAnalysis.h
+++ b/HH4bAnalysis/src/BoostedAnalysis.h
@@ -6,7 +6,6 @@
 
 std::map<std::string, double>
 getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
-                          const xAOD::JetContainer *VRTrackJets,
                           std::map<std::string, double> h_cand_vars);
 
 #endif
diff --git a/HH4bAnalysis/src/ResolvedAnalysis.cxx b/HH4bAnalysis/src/ResolvedAnalysis.cxx
index ce3256ab1..b590e8e8e 100644
--- a/HH4bAnalysis/src/ResolvedAnalysis.cxx
+++ b/HH4bAnalysis/src/ResolvedAnalysis.cxx
@@ -1,27 +1,61 @@
 #include "ResolvedAnalysis.h"
-#include "kLargestJets.h"
 #include "map"
-// #include "vector"
-#include "string"
+#include "tools/kLargestJets.h"
 #include "xAODJet/JetContainer.h"
 
 std::map<std::string, double>
-getResolvedHiggsCandidates(const xAOD::JetContainer *largeRjets,
-                           const xAOD::JetContainer *VRTrackJets,
-                           std::map<std::string, double> h_cand_vars);
+getResolvedHiggsCandidates(const xAOD::JetContainer *smallRjets,
+                           std::map<std::string, double> &h_cand_vars)
 {
+  // check if we have at least 4 jets
+  if (smallRjets->size() < 4)
+  {
+    return h_cand_vars;
+  }
+  // get indices of 4 largest pt jets
+  // need to do this because sequence filtering destroys order
+  std::vector<int> fourLeadingPtJetsIndices = kLargestJets(smallRjets, 4);
+  // get largest pt jet
+  const xAOD::Jet *largestPtJet = smallRjets->at(fourLeadingPtJetsIndices[0]);
 
-  // need two large R
-  // least pt of large R's 250
-  // largest at least 450
-  // eta < 2.0
+  // calculate dR to other higgs candidate jets
+  std::vector<double> dRtoLargestPtJet;
+  for (int jetIndex : fourLeadingPtJetsIndices)
+  {
+    const xAOD::Jet *thisJet = smallRjets->at(jetIndex);
+    double thisDRtoLargestPtJet = thisJet->p4().DeltaR(largestPtJet->p4());
+    dRtoLargestPtJet.push_back(thisDRtoLargestPtJet);
+  }
 
-  // delta eta between large r jets
-  std::vector<int> twoLargestPtJetsIndices = kLargestJets(largeRjets, 2);
+  // get closest jet to leading jet
+  int closestToLeadingJetEntry =
+      std::min_element(dRtoLargestPtJet.begin(), dRtoLargestPtJet.end()) -
+      dRtoLargestPtJet.begin();
+  const xAOD::Jet *closestToLeadingJet =
+      smallRjets->at(fourLeadingPtJetsIndices[closestToLeadingJetEntry]);
 
-  // need track jet container inside first and second
-  // how to associate, until when are they still inside large R
-  // tag them as b's
+  // make higgs candidates
+  TLorentzVector h1_cand = largestPtJet->p4() + closestToLeadingJet->p4();
+  double dR_jets_in_h1 = largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
+
+  // make a copy of the indices and delete the ones of the h1_cand to get the
+  // ones of the h2_cand, order matters!
+  std::vector<int> otherJetIndices = fourLeadingPtJetsIndices;
+  otherJetIndices.erase(otherJetIndices.begin() + closestToLeadingJetEntry);
+  otherJetIndices.erase(otherJetIndices.begin());
+
+  const xAOD::Jet *otherJet1 = smallRjets->at(otherJetIndices[0]);
+  const xAOD::Jet *otherJet2 = smallRjets->at(otherJetIndices[1]);
+
+  TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
+  double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
+
+  // write to dictionary
+  h_cand_vars["resolved_m_h1"] = h1_cand.M();
+  h_cand_vars["resolved_m_h2"] = h2_cand.M();
+  h_cand_vars["resolved_m_hh"] = (h1_cand + h2_cand).M();
+  h_cand_vars["resolved_dR_jets_in_h1"] = dR_jets_in_h1;
+  h_cand_vars["resolved_dR_jets_in_h2"] = dR_jets_in_h2;
 
   return h_cand_vars;
 };
\ No newline at end of file
diff --git a/HH4bAnalysis/src/ResolvedAnalysis.h b/HH4bAnalysis/src/ResolvedAnalysis.h
index d2376e0eb..d9d38b545 100644
--- a/HH4bAnalysis/src/ResolvedAnalysis.h
+++ b/HH4bAnalysis/src/ResolvedAnalysis.h
@@ -1,12 +1,11 @@
-#ifndef HH4BANALYSIS_BOOSTED_ANALYSIS
-#define HH4BANALYSIS_BOOSTED_ANALYSIS
+#ifndef HH4BANALYSIS_RESOLVED_ANALYSIS
+#define HH4BANALYSIS_RESOLVED_ANALYSIS
 
 #include "map"
 #include "xAODJet/JetContainer.h"
 
 std::map<std::string, double>
-getResolvedHiggsCandidates(const xAOD::JetContainer *largeRjets,
-                           const xAOD::JetContainer *VRTrackJets,
-                           std::map<std::string, double> h_cand_vars);
+getResolvedHiggsCandidates(const xAOD::JetContainer *smallRjets,
+                           std::map<std::string, double> &h_cand_vars);
 
 #endif
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 894a43615..957379cf0 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -7,8 +7,8 @@
 
 // Class definition
 #include "VariableDumperAlg.h"
-#include "getBoostedHiggsCandidates.h"
-// #include "tools/kLargestJets.h"
+#include "BoostedAnalysis.h"
+#include "ResolvedAnalysis.h"
 #include "map"
 //
 // method implementations
@@ -18,12 +18,8 @@ namespace HH4B
 {
   VariableDumperAlg ::VariableDumperAlg(const std::string &name,
                                         ISvcLocator *pSvcLocator)
-      : AthHistogramAlgorithm(name, pSvcLocator),
-        m_acc_DFCommonJets_eventClean_LooseBad(
-            "DFCommonJets_eventClean_LooseBad"),
-        m_acc_VRTrackJets("AntiKtVR30Rmax4Rmin02PV0TrackJets")
+      : AthHistogramAlgorithm(name, pSvcLocator)
   {
-    declareProperty("applyJetCleaning", m_applyJetCleaning);
   }
 
   StatusCode VariableDumperAlg ::initialize()
@@ -41,10 +37,8 @@ namespace HH4B
     ATH_CHECK(m_systematicsList.addHandle(m_muonHandle));
     ATH_CHECK(m_systematicsList.addHandle(m_jetsmallRHandle));
     ATH_CHECK(m_systematicsList.addHandle(m_jetlargeRHandle));
-    ATH_CHECK(m_btagSelTool.retrieve());
-
+    ATH_CHECK(m_systematicsList.addHandle(m_VRtrackjetHandle));
     ATH_CHECK(m_EventInfoKey.initialize());
-    ATH_CHECK(m_VRTrackJetsKey.initialize());
     ATH_CHECK(m_systematicsList.initialize());
 
     ATH_MSG_INFO("Will search \"" << m_EventInfoKey.key()
@@ -69,13 +63,13 @@ namespace HH4B
       SG::ReadHandle<xAOD::EventInfo> eventInfo(m_EventInfoKey);
       ATH_CHECK(eventInfo.isValid());
       // jet cleaning
-      if (m_applyJetCleaning)
-      {
-        if (!m_acc_DFCommonJets_eventClean_LooseBad(*eventInfo))
-        {
-          return StatusCode::SUCCESS; // go to next event
-        }
-      }
+      // if (m_applyJetCleaning)
+      // {
+      //   if (!m_acc_DFCommonJets_eventClean_LooseBad(*eventInfo))
+      //   {
+      //     return StatusCode::SUCCESS; // go to next event
+      //   }
+      // }
 
       const xAOD::ElectronContainer *electrons(nullptr);
       ATH_CHECK(m_electronHandle.retrieve(electrons, sys));
@@ -92,60 +86,38 @@ namespace HH4B
       const xAOD::JetContainer *antiKt10RecoJets(nullptr);
       ATH_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
       // do something with antiKt10RecoJets
-      // get Variable Radius Track jets for large R jet substructure
-      SG::ReadHandle<xAOD::JetContainer> VRTrackJetsHandle(m_VRTrackJetsKey);
-      ATH_CHECK(VRTrackJetsHandle.isValid());
-      // convert handle to container
-      const xAOD::JetContainer *VRTrackJets = VRTrackJetsHandle.cptr();
-
-      // set defaults
+      const xAOD::JetContainer *VRTrackJets(nullptr);
+      ATH_CHECK(m_VRtrackjetHandle.retrieve(VRTrackJets, sys));
+      // do something with VRTrackJets
+
+      // variable list
+      // TODO: need to find way to initialize all the v
+      std::vector<std::string> h_cand_vars_list({
+          "resolved_m_h1",
+          "resolved_m_h2",
+          "resolved_m_hh",
+          "resolved_dR_jets_in_h1",
+          "resolved_dR_jets_in_h2",
+      });
+
+      // set defaults in h_cand_vars dictionary
       std::map<std::string, double> h_cand_vars;
-      h_cand_vars["m_h1"] = -1;
-      h_cand_vars["m_h2"] = -1;
-      h_cand_vars["m_hh"] = -1;
-      h_cand_vars["dR_jets_in_h1"] = -1;
-      h_cand_vars["dR_jets_in_h2"] = -1;
-
-      h_cand_vars = getBoostedHiggsCandidates(antiKt10RecoJets, VRTrackJets,
-                                              h_cand_vars);
-
-      // recommended by ftag  Remove the event if any of your signal jets have
-      // relativeDeltaRToVRJet < 1.0.
-      // getBoostedHiggsCandidates(antiKt10RecoJets);
-
-      // std::cout << antiKt4RecoJets->size() << "\n";
-      // std::cout << VRTrackJets->size() << "\n";
-
-      // for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
-      // {
-      //   const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
-      //   // std::cout << jetIndex;
-      //   // std::cout << antiKt4RecoJets->size();
-      //   SG::AuxElement::ConstAccessor<char> isTag77(
-      //       "ftag_kin_select_DL1r_FixedCutBEff_77");
-      //   std::cout << isTag77(*thisJet) << "\n";
-      // }
-
-      // TODO: send in btagged jets
-
-      // TODO: return resolved function as std::map "m_h1"
+      for (std::string var : h_cand_vars_list)
+      {
+        h_cand_vars[var] = -1;
+      }
 
-      // for (int jetIndex = 0; jetIndex < antiKt4RecoJets->size(); jetIndex++)
-      // {
-      //   const xAOD::Jet *thisJet = antiKt4RecoJets->at(jetIndex);
-      //   // std::cout << jetIndex;
-      //   // std::cout << antiKt4RecoJets->size();
-      //   SG::AuxElement::ConstAccessor<char> isTag77(
-      //       "ftag_kin_select_DL1r_FixedCutBEff_77");
-      //   std::cout << isTag77(*thisJet) << "\n";
-      // }
+      // TODO: make configurable with which btagging WP Higgs candidates are
+      // created
+      // std::vector<std::string>
+      h_cand_vars = getResolvedHiggsCandidates(antiKt4RecoJets, h_cand_vars);
+      h_cand_vars = getBoostedHiggsCandidates(antiKt10RecoJets, h_cand_vars);
 
-      //  write out Higgs candidates
-      // eventInfo->auxdecor<double>("m_h1") = m_h1;
-      // eventInfo->auxdecor<double>("m_h2") = m_h2;
-      // eventInfo->auxdecor<double>("m_hh") = m_hh;
-      // eventInfo->auxdecor<double>("dR_jets_in_resolved_h1") = dR_jets_in_h1;
-      // eventInfo->auxdecor<double>("dR_jets_in_resolved_h2") = dR_jets_in_h2;
+      // decorate eventInfo with Higgs candidates
+      for (std::string var : h_cand_vars_list)
+      {
+        eventInfo->auxdecor<double>(var) = h_cand_vars[var];
+      }
     }
 
     return StatusCode::SUCCESS;
diff --git a/HH4bAnalysis/src/VariableDumperAlg.h b/HH4bAnalysis/src/VariableDumperAlg.h
index e47da448e..a06415b3e 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.h
+++ b/HH4bAnalysis/src/VariableDumperAlg.h
@@ -50,16 +50,11 @@ private:
     // Member variables for configuration
     SG::ReadHandleKey<xAOD::EventInfo> m_EventInfoKey{
         this, "EventInfoKey", "", "EventInfo container to dump"};
-    SG::ReadHandleKey<xAOD::JetContainer> m_VRTrackJetsKey{
-        this, "VRTrackJetsKey", "", "VRTrackJets container to use"};
+    // TODO: jet cleaning will become of own selection/filter algorithm
     // for jet cleaning: quality criteria to identify events which are
     // consistent with noise in the calorimeter or non-collision background
     // For details last paragraph on page 6:
     // https://cds.cern.ch/record/2809414/files/ATLAS-COM-CONF-2022-035.pdf
-    bool m_applyJetCleaning;
-    SG::AuxElement::ConstAccessor<char> m_acc_DFCommonJets_eventClean_LooseBad;
-    SG::AuxElement::ConstAccessor<char> m_acc_VRTrackJets;
-
     CP::SysReadHandle<xAOD::ElectronContainer> m_electronHandle{
         this, "electrons", "AnalysisElectrons_%SYS%",
         "the electron collection to run on"};
@@ -78,6 +73,10 @@ private:
     CP::SysReadHandle<xAOD::JetContainer> m_jetlargeRHandle{
         this, "jetlargeR", "AnalysisLargeRRecoJets_%SYS%",
         "the large-R jet collection to run on"};
+
+    CP::SysReadHandle<xAOD::JetContainer> m_VRtrackjetHandle{
+        this, "VRtrackjets", "VRTrackJetsBTAG_%SYS%",
+        "the VR track jet collection to run on"};
   };
 }
 
-- 
GitLab


From c123c0c5051b33fd3be1eb361a1b88c65eded48e Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 21 Jul 2022 10:12:54 +0200
Subject: [PATCH 06/33] proof of principle

---
 HH4bAnalysis/share/VariableDumperConfig.py |   5 +
 HH4bAnalysis/src/BoostedAnalysis.cxx       | 128 ++++++++++++---------
 HH4bAnalysis/src/VariableDumperAlg.cxx     |   6 +-
 HH4bAnalysis/src/tools/kLargestJets.cxx    |   2 +-
 4 files changed, 84 insertions(+), 57 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 5ceab230a..b1b9a94cc 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -419,6 +419,11 @@ def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
         "EventInfo.resolved_m_hh   -> resolved_m_hh",
         "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
         "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
+        "EventInfo.boosted_m_h1   -> boosted_m_h1",
+        "EventInfo.boosted_m_h2   -> boosted_m_h2",
+        "EventInfo.boosted_m_hh   -> boosted_m_hh",
+        "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
+        "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
     ]
     ntupleMaker.Branches += [
         f"AnalysisJets_%SYS%.ftag_select_{btag_wp} -> recojet_antikt4_%SYS%_{btag_wp}"
diff --git a/HH4bAnalysis/src/BoostedAnalysis.cxx b/HH4bAnalysis/src/BoostedAnalysis.cxx
index 3f1016e03..3ed325d2c 100644
--- a/HH4bAnalysis/src/BoostedAnalysis.cxx
+++ b/HH4bAnalysis/src/BoostedAnalysis.cxx
@@ -3,31 +3,35 @@
 #include "string"
 #include "tools/kLargestJets.h"
 #include "xAODJet/JetContainer.h"
+#include <AthContainers/ConstDataVector.h>
+
+// struct higgs_cand
+// {
+//   int largeRjetIndex;
+// }
 
 std::map<std::string, double>
 getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
                           std::map<std::string, double> h_cand_vars)
 {
+  // TODO: list
 
+  // cuts
+  // recommended by ftag : Remove the event if any of your signal jets have
+  // relativeDeltaRToVRJet < 1.0.
   // least pt of large R's 250
   // largest at least 450
   // eta < 2.0
 
   // delta eta between large r jets
+  // make btagging configurable
 
   // check if we have at least 2 large R jets
   if (largeRjets->size() < 2)
   {
     return h_cand_vars;
   }
-  std::vector<int> twoLeadingPtJetsIndices = kLargestJets(largeRjets, 2);
-
-  // need track jet container inside first and second
-  // how to associate, until when are they still inside large R
-  // tag them as b's
-
-  // recommended by ftag  Remove the event if any of your signal jets have
-  // relativeDeltaRToVRJet < 1.0.
+  std::vector<int> twoLeadingPtLargeRjetsIndices = kLargestJets(largeRjets, 2);
 
   // ghost associated track jets are only on the untrimmed 1.0 jets
   SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
@@ -35,21 +39,29 @@ getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
   SG::AuxElement::ConstAccessor<
       std::vector<ElementLink<xAOD::IParticleContainer>>>
       m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
-
   SG::AuxElement::ConstAccessor<char> isBtag(
       "ftag_select_DL1r_FixedCutBEff_77");
+
+  // need to allocate size of this to work with the
+  // twoLeadingPtLargeRjetsIndices
+  int allocation_size = *max_element(twoLeadingPtLargeRjetsIndices.begin(),
+                                     twoLeadingPtLargeRjetsIndices.end()) +
+                        1;
   std::vector<std::vector<ElementLink<xAOD::IParticleContainer>>>
-      btagged_VRTrackjets;
-  // loop over the two large R jets
-  for (int i : twoLeadingPtJetsIndices)
+      btagged_VRTrackjets(allocation_size);
+
+  // loop over the two large R jets to get the btagged VR jets inside of each
+  // (i is the large R jet index not a counter)
+  for (int i : twoLeadingPtLargeRjetsIndices)
   {
+
     const xAOD::Jet *thisJet = largeRjets->at(i);
-    // get ghost associated VR track jets
+    // get ghost associated VR track jets from untrimmed large R
     const xAOD::Jet *thisJet_untrimmed = *m_acc_largeR_untrimmed(*thisJet);
     const std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
         m_acc_VRTrackJets(*thisJet_untrimmed);
     // get the btagged VR trackjets per large R jet
-    for (auto VRjet : VRTrackjets)
+    for (ElementLink<xAOD::IParticleContainer> VRjet : VRTrackjets)
     {
       if (isBtag(**VRjet))
       {
@@ -57,54 +69,60 @@ getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
         btagged_VRTrackjets[i].emplace_back(VRjet);
       }
     }
+  }
+
+  // get leading pt jets of btagged VRtrackJets in largeRjet i
+  // e.g. h_cand_indices[twoLeadingPtLargeRjetsIndices[0]] contains pt-sorted
+  // VRtrackjet indices for the leading (twoLeadingPtLargeRjetsIndices[0])
+  // largeRjet
+
+  std::vector<std::vector<int>> h_cand_indices(allocation_size);
+  for (int i : twoLeadingPtLargeRjetsIndices)
+  {
     // check if we have at least 2 per large R jet, otherwise exit
     // (subject to change)
     if (btagged_VRTrackjets[i].size() < 2)
     {
       return h_cand_vars;
     }
+
+    ConstDataVector<xAOD::JetContainer> tmpVRjets(SG::VIEW_ELEMENTS);
+    // cast VRjet to xAOD::jet to use kLargestJets sorting function
+    // we do it this way since we want to make shallow copies
+    // tmpVRjets is recreated per i
+    for (auto VRjet : btagged_VRTrackjets[i])
+    {
+      const auto *jet = dynamic_cast<const xAOD::Jet *>(*VRjet);
+      tmpVRjets.push_back(jet);
+    }
+
+    h_cand_indices[i] = kLargestJets(tmpVRjets.asDataVector(), 2);
   }
-  // // make higgs candidates
-  // TLorentzVector h1_cand = largestPtJet->p4() + closestToLeadingJet->p4();
-  // double dR_jets_in_h1 =
-  // largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
-
-  // // make a copy of the indices and delete the ones of the h1_cand to get
-  // the
-  // // ones of the h2_cand, order matters!
-  // std::vector<int> otherJetIndices = fourLargestPtJetsIndices;
-  // otherJetIndices.erase(otherJetIndices.begin() + closestToLeadingJetEntry);
-  // otherJetIndices.erase(otherJetIndices.begin());
-
-  // const xAOD::Jet *otherJet1 = smallRjets->at(otherJetIndices[0]);
-  // const xAOD::Jet *otherJet2 = smallRjets->at(otherJetIndices[1]);
-
-  // TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
-  // double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
-
-  // // write to dictionary
-  // h_cand_vars["resolved_m_h1"] = h1_cand.M();
-  // h_cand_vars["resolved_m_h2"] = h2_cand.M();
-  // h_cand_vars["resolved_m_hh"] = (h1_cand + h2_cand).M();
-  // h_cand_vars["resolved_dR_jets_in_h1"] = dR_jets_in_h1;
-  // h_cand_vars["resolved_dR_jets_in_h2"] = dR_jets_in_h2;
-
-  //   const xAOD::Jet *thisJet;
-
-  //   SG::AuxElement::ConstAccessor<char> isTag77(
-
-  // GhostVR30Rmax4Rmin02PV0TrackJet
-  //   SG::AuxElement::ConstAccessor<char> isTag77(
-  //       "ftag_select_DL1r_FixedCutBEff_77");
-  //   for (long unsigned int i = 0; i < VRTrackJets->size(); i++)
-  //   {
-  //     thisJet = VRTrackJets->at(i);
-  //     std::cout << int(isTag77(*thisJet)) << std::endl;
-  //   }
-
-  // bool pass_btag = false;
-  // if (isTag77.isAvailable(*jet))
-  //   VRtrackjet_btag77.push_back(isTag77(*jet));
+
+  // make higgs candidates
+
+  std::vector<TLorentzVector> h_cand(allocation_size);
+  std::vector<double> dR_jets_in_h_cand(allocation_size);
+
+  for (int i : twoLeadingPtLargeRjetsIndices)
+  {
+    auto leadingVR_h_cand = *btagged_VRTrackjets[i][h_cand_indices[i][0]];
+    auto subleadingVR_h_cand = *btagged_VRTrackjets[i][h_cand_indices[i][1]];
+    h_cand[i] = leadingVR_h_cand->p4() + subleadingVR_h_cand->p4();
+    dR_jets_in_h_cand[i] =
+        leadingVR_h_cand->p4().DeltaR(subleadingVR_h_cand->p4());
+  }
+
+  // write to dictionary
+  auto h1_cand = h_cand[twoLeadingPtLargeRjetsIndices[0]];
+  auto h2_cand = h_cand[twoLeadingPtLargeRjetsIndices[1]];
+  h_cand_vars["boosted_m_h1"] = h1_cand.M();
+  h_cand_vars["boosted_m_h2"] = h2_cand.M();
+  h_cand_vars["boosted_m_hh"] = (h1_cand + h2_cand).M();
+  h_cand_vars["boosted_dR_jets_in_h1"] =
+      dR_jets_in_h_cand[twoLeadingPtLargeRjetsIndices[0]];
+  h_cand_vars["boosted_dR_jets_in_h2"] =
+      dR_jets_in_h_cand[twoLeadingPtLargeRjetsIndices[1]];
 
   return h_cand_vars;
 };
\ No newline at end of file
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 957379cf0..d4476ac56 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -91,13 +91,17 @@ namespace HH4B
       // do something with VRTrackJets
 
       // variable list
-      // TODO: need to find way to initialize all the v
       std::vector<std::string> h_cand_vars_list({
           "resolved_m_h1",
           "resolved_m_h2",
           "resolved_m_hh",
           "resolved_dR_jets_in_h1",
           "resolved_dR_jets_in_h2",
+          "boosted_m_h1",
+          "boosted_m_h2",
+          "boosted_m_hh",
+          "boosted_dR_jets_in_h1",
+          "boosted_dR_jets_in_h2",
       });
 
       // set defaults in h_cand_vars dictionary
diff --git a/HH4bAnalysis/src/tools/kLargestJets.cxx b/HH4bAnalysis/src/tools/kLargestJets.cxx
index 06a7dcb84..b2d21cddd 100644
--- a/HH4bAnalysis/src/tools/kLargestJets.cxx
+++ b/HH4bAnalysis/src/tools/kLargestJets.cxx
@@ -2,7 +2,7 @@
 #include "xAODJet/JetContainer.h"
 
 // efficient algorithm to find k largest elements in size n vector with
-// efficienvy O(n log k)
+// efficiency O(n log k)
 // see https://stackoverflow.com/a/38391603
 
 // returns jet indices in descending order of the largest k found pt's
-- 
GitLab


From ee510fe844502d965ec4a3815ef664fc7d91b56a Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Mon, 8 Aug 2022 08:22:48 +0200
Subject: [PATCH 07/33] saving

---
 HH4bAnalysis/src/BoostedAnalysis.cxx   | 25 ++++++++++++++++++++++---
 HH4bAnalysis/src/VariableDumperAlg.cxx |  3 ++-
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/HH4bAnalysis/src/BoostedAnalysis.cxx b/HH4bAnalysis/src/BoostedAnalysis.cxx
index 3ed325d2c..4ca76d571 100644
--- a/HH4bAnalysis/src/BoostedAnalysis.cxx
+++ b/HH4bAnalysis/src/BoostedAnalysis.cxx
@@ -3,8 +3,11 @@
 #include "string"
 #include "tools/kLargestJets.h"
 #include "xAODJet/JetContainer.h"
+#include <AsgMessaging/MessageCheck.h>
 #include <AthContainers/ConstDataVector.h>
 
+using namespace asg::msgUserCode;
+
 // struct higgs_cand
 // {
 //   int largeRjetIndex;
@@ -61,13 +64,29 @@ getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
     const std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
         m_acc_VRTrackJets(*thisJet_untrimmed);
     // get the btagged VR trackjets per large R jet
+    int counter = 0;
     for (ElementLink<xAOD::IParticleContainer> VRjet : VRTrackjets)
     {
-      if (isBtag(**VRjet))
+      auto &test = VRjet;
+      // check if VRjet link is valid
+      // should we handle this differently?
+      if (!test.isValid())
+      {
+        // doing this gives a lot of warnings, wonder why
+        // ANA_MSG_WARNING("Invalid track link found!");
+        std::cout << "size " << VRTrackjets.size() << "count " << counter + 1;
+        continue;
+      }
+      // some (very little) of the VR jets are not btagged, this means the
+      // VRtrack ftag sequence does not tag some of them
+      if (!isBtag.isAvailable(**VRjet))
       {
-        // (i is the large R jet index not a counter)
-        btagged_VRTrackjets[i].emplace_back(VRjet);
+        ANA_MSG_WARNING("Skipped non B-tagged VR jet");
+        continue;
       }
+
+      // (i is the large R jet index not a counter)
+      btagged_VRTrackjets[i].emplace_back(VRjet);
     }
   }
 
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index d4476ac56..9d55c1a98 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -57,7 +57,8 @@ namespace HH4B
       ATH_CHECK(m_systematicsList.service().makeSystematicsName(sysname,
                                                                 "%SYS%", sys));
 
-      ATH_MSG_INFO("Will apply sysname \"" << sysname << "\" for event");
+      // ATH_MSG_INFO("Will apply sysname \"" << sysname << "\" for event");
+      ATH_MSG_WARNING("Invalid track link found!");
 
       // Do something with Eventinfo
       SG::ReadHandle<xAOD::EventInfo> eventInfo(m_EventInfoKey);
-- 
GitLab


From e45a85765f214cf7c92142aae20ced9bb06c0c28 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Wed, 10 Aug 2022 08:57:49 +0200
Subject: [PATCH 08/33] make object oriented

---
 HH4bAnalysis/share/VariableDumperConfig.py |   2 +-
 HH4bAnalysis/src/BoostedAnalysis.cxx       |   5 -
 HH4bAnalysis/src/DiHiggsAnalysis.cxx       | 136 +++++++++++++++++++++
 HH4bAnalysis/src/DiHiggsAnalysis.h         |  44 +++++++
 HH4bAnalysis/src/VariableDumperAlg.cxx     |  46 ++-----
 5 files changed, 188 insertions(+), 45 deletions(-)
 create mode 100644 HH4bAnalysis/src/DiHiggsAnalysis.cxx
 create mode 100644 HH4bAnalysis/src/DiHiggsAnalysis.h

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index b1b9a94cc..392fdb43a 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -379,7 +379,7 @@ def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
         "EventInfo.eventNumber   -> eventNumber",
         # we currently don't have any pileup calib files setup
         # 'EventInfo.PileupWeight_%SYS% -> pileupWeight_%SYS%',
-        "EventInfo.mcEventWeights   -> mcEventWeights",
+        # "EventInfo.mcEventWeights   -> mcEventWeights",
         "AnalysisElectrons_%SYS%.pt  -> el_%SYS%_pt",
         "AnalysisElectrons_%SYS%.eta -> el_%SYS%_eta",
         "AnalysisElectrons_%SYS%.phi -> el_%SYS%_phi",
diff --git a/HH4bAnalysis/src/BoostedAnalysis.cxx b/HH4bAnalysis/src/BoostedAnalysis.cxx
index 4ca76d571..75ad5a28c 100644
--- a/HH4bAnalysis/src/BoostedAnalysis.cxx
+++ b/HH4bAnalysis/src/BoostedAnalysis.cxx
@@ -8,11 +8,6 @@
 
 using namespace asg::msgUserCode;
 
-// struct higgs_cand
-// {
-//   int largeRjetIndex;
-// }
-
 std::map<std::string, double>
 getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
                           std::map<std::string, double> h_cand_vars)
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
new file mode 100644
index 000000000..84d4bdc06
--- /dev/null
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -0,0 +1,136 @@
+
+#include "DiHiggsAnalysis.h"
+#include "tools/kLargestJets.h"
+#include "xAODJet/JetContainer.h"
+#include <AsgMessaging/MessageCheck.h>
+#include <AthContainers/ConstDataVector.h>
+
+// wollen vars immer rausschreiben
+
+namespace HH4B
+{
+
+  DiHiggsAnalysis::DiHiggsAnalysis()
+  {
+    // set defaults in h_cand_vars dictionary on construction
+    for (std::string var : h_cand_vars_list)
+    {
+      h_cand_vars[var] = -1;
+    }
+  };
+
+  using namespace asg::msgUserCode;
+
+  void
+  DiHiggsAnalysis::makeBoostedAnalysis(const xAOD::JetContainer *largeRjets)
+  {
+    // TODO: list
+
+    // cuts
+    // recommended by ftag : Remove the event if any of your signal jets have
+    // relativeDeltaRToVRJet < 1.0.
+    // least pt of large R's 250
+    // largest at least 450
+    // eta < 2.0
+
+    // delta eta between large r jets
+    // make btagging configurable
+
+    // check if we have at least 2 large R jets
+    if (largeRjets->size() < 2)
+    {
+      return;
+    }
+    // leadding higgs candidate
+    HiggsCandidate h1;
+    // subleading higgs candidate
+    HiggsCandidate h2;
+    std::vector<HiggsCandidate> h_candidates{h1, h2};
+    std::vector<int> twoLeadingPtLargeRjetsIndices =
+        kLargestJets(largeRjets, 2);
+    h1.largeRjetIndex = twoLeadingPtLargeRjetsIndices[0];
+    h2.largeRjetIndex = twoLeadingPtLargeRjetsIndices[1];
+
+    // ghost associated track jets are only on the untrimmed 1.0 jets
+    SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
+        m_acc_largeR_untrimmed("Parent");
+    SG::AuxElement::ConstAccessor<
+        std::vector<ElementLink<xAOD::IParticleContainer>>>
+        m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
+    SG::AuxElement::ConstAccessor<char> isBtag(
+        "ftag_select_DL1r_FixedCutBEff_77");
+
+    // loop over the two large R jets to get the btagged VR jets inside of each
+    for (HiggsCandidate h : h_candidates)
+    {
+      const xAOD::Jet *thisJet = largeRjets->at(h.largeRjetIndex);
+      // get ghost associated VR track jets from untrimmed large R
+      const xAOD::Jet *thisJet_untrimmed = *m_acc_largeR_untrimmed(*thisJet);
+      const std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
+          m_acc_VRTrackJets(*thisJet_untrimmed);
+      // get the btagged VR trackjets per large R jet
+      int counter = 0;
+      for (ElementLink<xAOD::IParticleContainer> VRjet : VRTrackjets)
+      {
+        auto &test = VRjet;
+        // check if VRjet link is valid
+        // should we handle this differently?
+        if (!test.isValid())
+        {
+          // doing this gives a lot of warnings, wonder why
+          // ANA_MSG_WARNING("Invalid track link found!");
+          std::cout << "size " << VRTrackjets.size() << "count "
+                    << counter + 1;
+          continue;
+        }
+        // some (very little) of the VR jets are not btagged, this means the
+        // VRtrack ftag sequence does not tag some of them
+        if (!isBtag.isAvailable(**VRjet))
+        {
+          ANA_MSG_WARNING("Skipped non B-tagged VR jet");
+          continue;
+        }
+        h.btagged_VRTrackjets.push_back(VRjet);
+      }
+    }
+
+    // find the leading vr jets
+    for (HiggsCandidate h : h_candidates)
+    {
+      // check if we have at least 2 per large R jet, otherwise exit
+      // (subject to change)
+      if (h.btagged_VRTrackjets.size() < 2)
+      {
+        return;
+      }
+
+      // cast VRjet to xAOD::jet to use kLargestJets sorting function
+      // we do it this way since we want to make shallow copies
+      ConstDataVector<xAOD::JetContainer> tmpVRjets(SG::VIEW_ELEMENTS);
+      for (auto VRjet : h.btagged_VRTrackjets)
+      {
+        const auto *jet = dynamic_cast<const xAOD::Jet *>(*VRjet);
+        tmpVRjets.push_back(jet);
+      }
+      // write leading and subleading vr jet onto HiggsCandidate objects
+      std::vector<int> twoLeadingVrJetIndices =
+          kLargestJets(tmpVRjets.asDataVector(), 2);
+      h.leadingJet = dynamic_cast<const xAOD::Jet *>(
+          *h.btagged_VRTrackjets[twoLeadingVrJetIndices[0]]);
+      h.subleadingJet = dynamic_cast<const xAOD::Jet *>(
+          *h.btagged_VRTrackjets[twoLeadingVrJetIndices[1]]);
+      // calc variables
+      h.fourVector = h.leadingJet->p4() + h.subleadingJet->p4();
+      h.dRjets = h.leadingJet->p4().DeltaR(h.subleadingJet->p4());
+    }
+
+    // write to dictionary
+    h_cand_vars["boosted_m_h1"] = h1.fourVector.M();
+    h_cand_vars["boosted_m_h2"] = h2.fourVector.M();
+    h_cand_vars["boosted_m_hh"] = (h1.fourVector + h2.fourVector).M();
+    h_cand_vars["boosted_dR_jets_in_h1"] = h1.dRjets;
+    h_cand_vars["boosted_dR_jets_in_h2"] = h2.dRjets;
+    return;
+  };
+
+}
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
new file mode 100644
index 000000000..06c2c8cb8
--- /dev/null
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -0,0 +1,44 @@
+#ifndef HH4B_DIHIGGSANALYSIS
+#define HH4B_DIHIGGSANALYSIS
+
+#include "xAODJet/JetContainer.h"
+
+// wollen vars immer rausschreiben
+
+namespace HH4B
+{
+  // used variables
+  std::vector<std::string> h_cand_vars_list{
+      "resolved_m_h1",          "resolved_m_h2",
+      "resolved_m_hh",          "resolved_dR_jets_in_h1",
+      "resolved_dR_jets_in_h2", "boosted_m_h1",
+      "boosted_m_h2",           "boosted_m_hh",
+      "boosted_dR_jets_in_h1",  "boosted_dR_jets_in_h2",
+  };
+
+  // value dictionary h_cand
+  std::map<std::string, double> h_cand_vars;
+
+  struct HiggsCandidate
+  {
+    // b-jets for h
+    const xAOD::Jet *leadingJet = nullptr;
+    const xAOD::Jet *subleadingJet = nullptr;
+
+    // boosted analysis
+    // bool isBoosted?
+    int largeRjetIndex = -1;
+    // container holding links to btagged vr track jets inside the large R jet
+    std::vector<ElementLink<xAOD::IParticleContainer>> btagged_VRTrackjets;
+    TLorentzVector fourVector;
+    double dRjets = -1;
+  };
+
+  class DiHiggsAnalysis : HiggsCandidate
+  {
+    DiHiggsAnalysis();
+    void makeResolvedAnalysis();
+    void makeBoostedAnalysis(const xAOD::JetContainer *largeRjets);
+  };
+}
+#endif
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 9d55c1a98..611e42d4c 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -57,21 +57,9 @@ namespace HH4B
       ATH_CHECK(m_systematicsList.service().makeSystematicsName(sysname,
                                                                 "%SYS%", sys));
 
-      // ATH_MSG_INFO("Will apply sysname \"" << sysname << "\" for event");
-      ATH_MSG_WARNING("Invalid track link found!");
-
       // Do something with Eventinfo
       SG::ReadHandle<xAOD::EventInfo> eventInfo(m_EventInfoKey);
       ATH_CHECK(eventInfo.isValid());
-      // jet cleaning
-      // if (m_applyJetCleaning)
-      // {
-      //   if (!m_acc_DFCommonJets_eventClean_LooseBad(*eventInfo))
-      //   {
-      //     return StatusCode::SUCCESS; // go to next event
-      //   }
-      // }
-
       const xAOD::ElectronContainer *electrons(nullptr);
       ATH_CHECK(m_electronHandle.retrieve(electrons, sys));
       // do something with electrons
@@ -91,38 +79,18 @@ namespace HH4B
       ATH_CHECK(m_VRtrackjetHandle.retrieve(VRTrackJets, sys));
       // do something with VRTrackJets
 
-      // variable list
-      std::vector<std::string> h_cand_vars_list({
-          "resolved_m_h1",
-          "resolved_m_h2",
-          "resolved_m_hh",
-          "resolved_dR_jets_in_h1",
-          "resolved_dR_jets_in_h2",
-          "boosted_m_h1",
-          "boosted_m_h2",
-          "boosted_m_hh",
-          "boosted_dR_jets_in_h1",
-          "boosted_dR_jets_in_h2",
-      });
-
-      // set defaults in h_cand_vars dictionary
-      std::map<std::string, double> h_cand_vars;
-      for (std::string var : h_cand_vars_list)
-      {
-        h_cand_vars[var] = -1;
-      }
-
       // TODO: make configurable with which btagging WP Higgs candidates are
       // created
       // std::vector<std::string>
-      h_cand_vars = getResolvedHiggsCandidates(antiKt4RecoJets, h_cand_vars);
-      h_cand_vars = getBoostedHiggsCandidates(antiKt10RecoJets, h_cand_vars);
+      // h_cand_vars = getResolvedHiggsCandidates(antiKt4RecoJets,
+      // h_cand_vars); h_cand_vars =
+      // getBoostedHiggsCandidates(antiKt10RecoJets, h_cand_vars);
 
       // decorate eventInfo with Higgs candidates
-      for (std::string var : h_cand_vars_list)
-      {
-        eventInfo->auxdecor<double>(var) = h_cand_vars[var];
-      }
+      // for (std::string var : h_cand_vars_list)
+      // {
+      //   eventInfo->auxdecor<double>(var) = h_cand_vars[var];
+      // }
     }
 
     return StatusCode::SUCCESS;
-- 
GitLab


From 5d0f7d6d5d6813f518c62e2c4e952b91f70de8c5 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Wed, 10 Aug 2022 18:37:53 +0200
Subject: [PATCH 09/33] added decoration

---
 HH4bAnalysis/src/DiHiggsAnalysis.cxx   | 56 ++++++++++++++++----------
 HH4bAnalysis/src/DiHiggsAnalysis.h     | 24 +++++------
 HH4bAnalysis/src/VariableDumperAlg.cxx | 10 +++--
 3 files changed, 51 insertions(+), 39 deletions(-)

diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index 84d4bdc06..3cc96a947 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -4,19 +4,23 @@
 #include "xAODJet/JetContainer.h"
 #include <AsgMessaging/MessageCheck.h>
 #include <AthContainers/ConstDataVector.h>
-
-// wollen vars immer rausschreiben
+#include <SystematicsHandles/SysReadHandle.h>
+#include <xAODEventInfo/EventInfo.h>
 
 namespace HH4B
 {
-
-  DiHiggsAnalysis::DiHiggsAnalysis()
-  {
-    // set defaults in h_cand_vars dictionary on construction
-    for (std::string var : h_cand_vars_list)
-    {
-      h_cand_vars[var] = -1;
-    }
+  int initValue = -1;
+  std::map<std::string, double> h_cand_vars{
+      {"resolved_m_h1", initValue},
+      {"resolved_m_h2", initValue},
+      {"resolved_m_hh", initValue},
+      {"resolved_dR_jets_in_h1", initValue},
+      {"resolved_dR_jets_in_h2", initValue},
+      {"boosted_m_h1", initValue},
+      {"boosted_m_h2", initValue},
+      {"boosted_m_hh", initValue},
+      {"boosted_dR_jets_in_h1", initValue},
+      {"boosted_dR_jets_in_h2", initValue},
   };
 
   using namespace asg::msgUserCode;
@@ -45,7 +49,6 @@ namespace HH4B
     HiggsCandidate h1;
     // subleading higgs candidate
     HiggsCandidate h2;
-    std::vector<HiggsCandidate> h_candidates{h1, h2};
     std::vector<int> twoLeadingPtLargeRjetsIndices =
         kLargestJets(largeRjets, 2);
     h1.largeRjetIndex = twoLeadingPtLargeRjetsIndices[0];
@@ -61,15 +64,16 @@ namespace HH4B
         "ftag_select_DL1r_FixedCutBEff_77");
 
     // loop over the two large R jets to get the btagged VR jets inside of each
-    for (HiggsCandidate h : h_candidates)
+    // need to do std::ref to access the actual objects h1, h2
+    // for (HiggsCandidate h : {h1, h2}) would make copies of h1, h2
+    for (HiggsCandidate &h : {std::ref(h1), std::ref(h2)})
     {
       const xAOD::Jet *thisJet = largeRjets->at(h.largeRjetIndex);
-      // get ghost associated VR track jets from untrimmed large R
+      // get ghost associated VR track jets from untrimmed large R jet
       const xAOD::Jet *thisJet_untrimmed = *m_acc_largeR_untrimmed(*thisJet);
       const std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
           m_acc_VRTrackJets(*thisJet_untrimmed);
       // get the btagged VR trackjets per large R jet
-      int counter = 0;
       for (ElementLink<xAOD::IParticleContainer> VRjet : VRTrackjets)
       {
         auto &test = VRjet;
@@ -77,14 +81,11 @@ namespace HH4B
         // should we handle this differently?
         if (!test.isValid())
         {
-          // doing this gives a lot of warnings, wonder why
-          // ANA_MSG_WARNING("Invalid track link found!");
-          std::cout << "size " << VRTrackjets.size() << "count "
-                    << counter + 1;
+          ANA_MSG_WARNING("Invalid track link found!");
           continue;
         }
-        // some (very little) of the VR jets are not btagged, this means the
-        // VRtrack ftag sequence does not tag some of them
+        // VRtrack ftag sequence does not tag all of them, so take only the
+        // btagged ones
         if (!isBtag.isAvailable(**VRjet))
         {
           ANA_MSG_WARNING("Skipped non B-tagged VR jet");
@@ -95,7 +96,7 @@ namespace HH4B
     }
 
     // find the leading vr jets
-    for (HiggsCandidate h : h_candidates)
+    for (HiggsCandidate &h : {std::ref(h1), std::ref(h2)})
     {
       // check if we have at least 2 per large R jet, otherwise exit
       // (subject to change)
@@ -133,4 +134,17 @@ namespace HH4B
     return;
   };
 
+  std::map<std::string, double> DiHiggsAnalysis::getHiggsVars()
+  {
+    return h_cand_vars;
+  };
+
+  void DiHiggsAnalysis::decorateHiggsVars(const xAOD::EventInfo &eventInfo)
+  {
+    // the range looks weird, but its just a loop over the h_cand_vars map
+    for (const auto &[key, value] : h_cand_vars)
+    {
+      eventInfo.auxdecor<double>(key) = value;
+    }
+  };
 }
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index 06c2c8cb8..cd33d43e3 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -2,23 +2,15 @@
 #define HH4B_DIHIGGSANALYSIS
 
 #include "xAODJet/JetContainer.h"
+#include <SystematicsHandles/SysReadHandle.h>
+#include <xAODEventInfo/EventInfo.h>
 
 // wollen vars immer rausschreiben
 
 namespace HH4B
 {
-  // used variables
-  std::vector<std::string> h_cand_vars_list{
-      "resolved_m_h1",          "resolved_m_h2",
-      "resolved_m_hh",          "resolved_dR_jets_in_h1",
-      "resolved_dR_jets_in_h2", "boosted_m_h1",
-      "boosted_m_h2",           "boosted_m_hh",
-      "boosted_dR_jets_in_h1",  "boosted_dR_jets_in_h2",
-  };
-
-  // value dictionary h_cand
-  std::map<std::string, double> h_cand_vars;
-
+  // dictionary holding the final vars
+  extern std::map<std::string, double> h_cand_vars;
   struct HiggsCandidate
   {
     // b-jets for h
@@ -26,19 +18,21 @@ namespace HH4B
     const xAOD::Jet *subleadingJet = nullptr;
 
     // boosted analysis
-    // bool isBoosted?
     int largeRjetIndex = -1;
-    // container holding links to btagged vr track jets inside the large R jet
+    // btagged vr track jets inside the large R jet
     std::vector<ElementLink<xAOD::IParticleContainer>> btagged_VRTrackjets;
+
     TLorentzVector fourVector;
     double dRjets = -1;
   };
 
   class DiHiggsAnalysis : HiggsCandidate
   {
-    DiHiggsAnalysis();
+public:
     void makeResolvedAnalysis();
     void makeBoostedAnalysis(const xAOD::JetContainer *largeRjets);
+    std::map<std::string, double> getHiggsVars();
+    void decorateHiggsVars(const xAOD::EventInfo &eventInfo);
   };
 }
 #endif
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 611e42d4c..5f4e13f7a 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -7,9 +7,8 @@
 
 // Class definition
 #include "VariableDumperAlg.h"
-#include "BoostedAnalysis.h"
-#include "ResolvedAnalysis.h"
-#include "map"
+#include "DiHiggsAnalysis.h"
+
 //
 // method implementations
 //
@@ -81,6 +80,11 @@ namespace HH4B
 
       // TODO: make configurable with which btagging WP Higgs candidates are
       // created
+
+      DiHiggsAnalysis hh4b_analysis;
+      hh4b_analysis.makeBoostedAnalysis(antiKt10RecoJets);
+      hh4b_analysis.decorateHiggsVars(*eventInfo);
+
       // std::vector<std::string>
       // h_cand_vars = getResolvedHiggsCandidates(antiKt4RecoJets,
       // h_cand_vars); h_cand_vars =
-- 
GitLab


From f2a9a33047a205eb9cd179c2a44fb507e33a3bdf Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 11 Aug 2022 11:00:13 +0200
Subject: [PATCH 10/33] saving

---
 HH4bAnalysis/src/DiHiggsAnalysis.cxx   | 79 +++++++++++++++++++++++++-
 HH4bAnalysis/src/DiHiggsAnalysis.h     | 10 ++--
 HH4bAnalysis/src/VariableDumperAlg.cxx | 12 +---
 3 files changed, 83 insertions(+), 18 deletions(-)

diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index 3cc96a947..63e4733d3 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -6,6 +6,7 @@
 #include <AthContainers/ConstDataVector.h>
 #include <SystematicsHandles/SysReadHandle.h>
 #include <xAODEventInfo/EventInfo.h>
+using namespace asg::msgUserCode;
 
 namespace HH4B
 {
@@ -23,7 +24,81 @@ namespace HH4B
       {"boosted_dR_jets_in_h2", initValue},
   };
 
-  using namespace asg::msgUserCode;
+  void
+  DiHiggsAnalysis::makeResolvedAnalysis(const xAOD::JetContainer *smallRjets)
+  {
+    // check if we have at least 4 jets
+    if (smallRjets->size() < 4)
+    {
+      return;
+    }
+    // leadding higgs candidate
+    HiggsCandidate h1;
+    // subleading higgs candidate
+    HiggsCandidate h2;
+
+    // get indices of 4 largest pt jets
+    // need to do this because sequence filtering destroys order
+    std::vector<int> fourLeadingPtJetsIndices = kLargestJets(smallRjets, 4);
+
+    // get largest pt jet
+    h1.leadingJet = smallRjets->at(fourLeadingPtJetsIndices[0]);
+
+    // calculate dR to other jets to find closest one
+    std::vector<double> dRtoLeadingJet;
+    double minDR = 0;
+    int minDRindex = -1;
+    for (int jetIndex : fourLeadingPtJetsIndices)
+    {
+      const xAOD::Jet *thisJet = smallRjets->at(jetIndex);
+      double thisDRtoLeadingJet = thisJet->p4().DeltaR(h1.leadingJet->p4());
+      dRtoLeadingJet.push_back(thisDRtoLeadingJet);
+      if (minDR > 0 || minDR > thisDRtoLeadingJet)
+      {
+        minDR = thisDRtoLeadingJet;
+        minDRindex = jetIndex;
+      }
+    }
+
+    std::cout << dRtoLeadingJet[0] << ", " << dRtoLeadingJet[1] << ", "
+              << dRtoLeadingJet[2] << ", " << dRtoLeadingJet[3] << std::endl;
+    std::cout << minDRindex << std::endl;
+    h1.subleadingJet = smallRjets->at(minDRindex);
+
+    // get closest jet to leading jet
+    // find index (iterator) of closest jet, skip leading one as dR=0
+    std::vector<double>::iterator dRminPosition =
+        std::min_element(dRtoLeadingJet.begin() + 1, dRtoLeadingJet.end());
+    // get position in fourLeadingPtJetsIndices to access the actual jet
+    int closestToLeadingJetIndex =
+        std::distance(dRtoLeadingJet.begin(), dRminPosition);
+    h1.subleadingJet =
+        smallRjets->at(fourLeadingPtJetsIndices[closestToLeadingJetIndex]);
+
+    // make higgs candidates
+    h1.fourVector = h1.leadingJet->p4() + h1.subleadingJet->p4();
+    h1.dRjets = h1.leadingJet->p4().DeltaR(h1.subleadingJet->p4());
+
+    // make a copy of the indices and delete the ones of the h1 to get the ones
+    // of h2, order matters!
+    std::vector<int> otherJetIndices = fourLeadingPtJetsIndices;
+    otherJetIndices.erase(otherJetIndices.begin() + closestToLeadingJetIndex);
+    otherJetIndices.erase(otherJetIndices.begin());
+
+    h2.leadingJet = smallRjets->at(otherJetIndices[0]);
+    h2.subleadingJet = smallRjets->at(otherJetIndices[1]);
+
+    h2.fourVector = h2.leadingJet->p4() + h2.subleadingJet->p4();
+    h2.dRjets = h2.leadingJet->p4().DeltaR(h2.subleadingJet->p4());
+    // write to dictionary
+    h_cand_vars["resolved_m_h1"] = h1.fourVector.M();
+    h_cand_vars["resolved_m_h2"] = h2.fourVector.M();
+    h_cand_vars["resolved_m_hh"] = (h1.fourVector + h2.fourVector).M();
+    h_cand_vars["resolved_dR_jets_in_h1"] = h1.dRjets;
+    h_cand_vars["resolved_dR_jets_in_h2"] = h2.dRjets;
+
+    return;
+  };
 
   void
   DiHiggsAnalysis::makeBoostedAnalysis(const xAOD::JetContainer *largeRjets)
@@ -65,7 +140,7 @@ namespace HH4B
 
     // loop over the two large R jets to get the btagged VR jets inside of each
     // need to do std::ref to access the actual objects h1, h2
-    // for (HiggsCandidate h : {h1, h2}) would make copies of h1, h2
+    // "for (HiggsCandidate h : {h1, h2})" would make copies of h1, h2
     for (HiggsCandidate &h : {std::ref(h1), std::ref(h2)})
     {
       const xAOD::Jet *thisJet = largeRjets->at(h.largeRjetIndex);
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index cd33d43e3..73fad58f1 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -17,19 +17,19 @@ namespace HH4B
     const xAOD::Jet *leadingJet = nullptr;
     const xAOD::Jet *subleadingJet = nullptr;
 
-    // boosted analysis
+    TLorentzVector fourVector;
+    double dRjets = -1;
+
+    // for boosted analysis
     int largeRjetIndex = -1;
     // btagged vr track jets inside the large R jet
     std::vector<ElementLink<xAOD::IParticleContainer>> btagged_VRTrackjets;
-
-    TLorentzVector fourVector;
-    double dRjets = -1;
   };
 
   class DiHiggsAnalysis : HiggsCandidate
   {
 public:
-    void makeResolvedAnalysis();
+    void makeResolvedAnalysis(const xAOD::JetContainer *smallRjets);
     void makeBoostedAnalysis(const xAOD::JetContainer *largeRjets);
     std::map<std::string, double> getHiggsVars();
     void decorateHiggsVars(const xAOD::EventInfo &eventInfo);
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 5f4e13f7a..c1d145ff1 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -82,19 +82,9 @@ namespace HH4B
       // created
 
       DiHiggsAnalysis hh4b_analysis;
+      hh4b_analysis.makeResolvedAnalysis(antiKt4RecoJets);
       hh4b_analysis.makeBoostedAnalysis(antiKt10RecoJets);
       hh4b_analysis.decorateHiggsVars(*eventInfo);
-
-      // std::vector<std::string>
-      // h_cand_vars = getResolvedHiggsCandidates(antiKt4RecoJets,
-      // h_cand_vars); h_cand_vars =
-      // getBoostedHiggsCandidates(antiKt10RecoJets, h_cand_vars);
-
-      // decorate eventInfo with Higgs candidates
-      // for (std::string var : h_cand_vars_list)
-      // {
-      //   eventInfo->auxdecor<double>(var) = h_cand_vars[var];
-      // }
     }
 
     return StatusCode::SUCCESS;
-- 
GitLab


From 956c8ca844e4e0b2562987b0e861bbf4ddef64bb Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 11 Aug 2022 12:01:54 +0200
Subject: [PATCH 11/33] moved to object orientation

---
 HH4bAnalysis/src/BoostedAnalysis.cxx  | 142 --------------------------
 HH4bAnalysis/src/BoostedAnalysis.h    |  11 --
 HH4bAnalysis/src/DiHiggsAnalysis.cxx  |  47 +++------
 HH4bAnalysis/src/DiHiggsAnalysis.h    |  13 ++-
 HH4bAnalysis/src/ResolvedAnalysis.cxx |  61 -----------
 HH4bAnalysis/src/ResolvedAnalysis.h   |  11 --
 6 files changed, 24 insertions(+), 261 deletions(-)
 delete mode 100644 HH4bAnalysis/src/BoostedAnalysis.cxx
 delete mode 100644 HH4bAnalysis/src/BoostedAnalysis.h
 delete mode 100644 HH4bAnalysis/src/ResolvedAnalysis.cxx
 delete mode 100644 HH4bAnalysis/src/ResolvedAnalysis.h

diff --git a/HH4bAnalysis/src/BoostedAnalysis.cxx b/HH4bAnalysis/src/BoostedAnalysis.cxx
deleted file mode 100644
index 75ad5a28c..000000000
--- a/HH4bAnalysis/src/BoostedAnalysis.cxx
+++ /dev/null
@@ -1,142 +0,0 @@
-#include "BoostedAnalysis.h"
-#include "map"
-#include "string"
-#include "tools/kLargestJets.h"
-#include "xAODJet/JetContainer.h"
-#include <AsgMessaging/MessageCheck.h>
-#include <AthContainers/ConstDataVector.h>
-
-using namespace asg::msgUserCode;
-
-std::map<std::string, double>
-getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
-                          std::map<std::string, double> h_cand_vars)
-{
-  // TODO: list
-
-  // cuts
-  // recommended by ftag : Remove the event if any of your signal jets have
-  // relativeDeltaRToVRJet < 1.0.
-  // least pt of large R's 250
-  // largest at least 450
-  // eta < 2.0
-
-  // delta eta between large r jets
-  // make btagging configurable
-
-  // check if we have at least 2 large R jets
-  if (largeRjets->size() < 2)
-  {
-    return h_cand_vars;
-  }
-  std::vector<int> twoLeadingPtLargeRjetsIndices = kLargestJets(largeRjets, 2);
-
-  // ghost associated track jets are only on the untrimmed 1.0 jets
-  SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
-      m_acc_largeR_untrimmed("Parent");
-  SG::AuxElement::ConstAccessor<
-      std::vector<ElementLink<xAOD::IParticleContainer>>>
-      m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
-  SG::AuxElement::ConstAccessor<char> isBtag(
-      "ftag_select_DL1r_FixedCutBEff_77");
-
-  // need to allocate size of this to work with the
-  // twoLeadingPtLargeRjetsIndices
-  int allocation_size = *max_element(twoLeadingPtLargeRjetsIndices.begin(),
-                                     twoLeadingPtLargeRjetsIndices.end()) +
-                        1;
-  std::vector<std::vector<ElementLink<xAOD::IParticleContainer>>>
-      btagged_VRTrackjets(allocation_size);
-
-  // loop over the two large R jets to get the btagged VR jets inside of each
-  // (i is the large R jet index not a counter)
-  for (int i : twoLeadingPtLargeRjetsIndices)
-  {
-
-    const xAOD::Jet *thisJet = largeRjets->at(i);
-    // get ghost associated VR track jets from untrimmed large R
-    const xAOD::Jet *thisJet_untrimmed = *m_acc_largeR_untrimmed(*thisJet);
-    const std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
-        m_acc_VRTrackJets(*thisJet_untrimmed);
-    // get the btagged VR trackjets per large R jet
-    int counter = 0;
-    for (ElementLink<xAOD::IParticleContainer> VRjet : VRTrackjets)
-    {
-      auto &test = VRjet;
-      // check if VRjet link is valid
-      // should we handle this differently?
-      if (!test.isValid())
-      {
-        // doing this gives a lot of warnings, wonder why
-        // ANA_MSG_WARNING("Invalid track link found!");
-        std::cout << "size " << VRTrackjets.size() << "count " << counter + 1;
-        continue;
-      }
-      // some (very little) of the VR jets are not btagged, this means the
-      // VRtrack ftag sequence does not tag some of them
-      if (!isBtag.isAvailable(**VRjet))
-      {
-        ANA_MSG_WARNING("Skipped non B-tagged VR jet");
-        continue;
-      }
-
-      // (i is the large R jet index not a counter)
-      btagged_VRTrackjets[i].emplace_back(VRjet);
-    }
-  }
-
-  // get leading pt jets of btagged VRtrackJets in largeRjet i
-  // e.g. h_cand_indices[twoLeadingPtLargeRjetsIndices[0]] contains pt-sorted
-  // VRtrackjet indices for the leading (twoLeadingPtLargeRjetsIndices[0])
-  // largeRjet
-
-  std::vector<std::vector<int>> h_cand_indices(allocation_size);
-  for (int i : twoLeadingPtLargeRjetsIndices)
-  {
-    // check if we have at least 2 per large R jet, otherwise exit
-    // (subject to change)
-    if (btagged_VRTrackjets[i].size() < 2)
-    {
-      return h_cand_vars;
-    }
-
-    ConstDataVector<xAOD::JetContainer> tmpVRjets(SG::VIEW_ELEMENTS);
-    // cast VRjet to xAOD::jet to use kLargestJets sorting function
-    // we do it this way since we want to make shallow copies
-    // tmpVRjets is recreated per i
-    for (auto VRjet : btagged_VRTrackjets[i])
-    {
-      const auto *jet = dynamic_cast<const xAOD::Jet *>(*VRjet);
-      tmpVRjets.push_back(jet);
-    }
-
-    h_cand_indices[i] = kLargestJets(tmpVRjets.asDataVector(), 2);
-  }
-
-  // make higgs candidates
-
-  std::vector<TLorentzVector> h_cand(allocation_size);
-  std::vector<double> dR_jets_in_h_cand(allocation_size);
-
-  for (int i : twoLeadingPtLargeRjetsIndices)
-  {
-    auto leadingVR_h_cand = *btagged_VRTrackjets[i][h_cand_indices[i][0]];
-    auto subleadingVR_h_cand = *btagged_VRTrackjets[i][h_cand_indices[i][1]];
-    h_cand[i] = leadingVR_h_cand->p4() + subleadingVR_h_cand->p4();
-    dR_jets_in_h_cand[i] =
-        leadingVR_h_cand->p4().DeltaR(subleadingVR_h_cand->p4());
-  }
-
-  // write to dictionary
-  auto h1_cand = h_cand[twoLeadingPtLargeRjetsIndices[0]];
-  auto h2_cand = h_cand[twoLeadingPtLargeRjetsIndices[1]];
-  h_cand_vars["boosted_m_h1"] = h1_cand.M();
-  h_cand_vars["boosted_m_h2"] = h2_cand.M();
-  h_cand_vars["boosted_m_hh"] = (h1_cand + h2_cand).M();
-  h_cand_vars["boosted_dR_jets_in_h1"] =
-      dR_jets_in_h_cand[twoLeadingPtLargeRjetsIndices[0]];
-  h_cand_vars["boosted_dR_jets_in_h2"] =
-      dR_jets_in_h_cand[twoLeadingPtLargeRjetsIndices[1]];
-
-  return h_cand_vars;
-};
\ No newline at end of file
diff --git a/HH4bAnalysis/src/BoostedAnalysis.h b/HH4bAnalysis/src/BoostedAnalysis.h
deleted file mode 100644
index 2efad7b90..000000000
--- a/HH4bAnalysis/src/BoostedAnalysis.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef HH4BANALYSIS_BOOSTED_ANALYSIS
-#define HH4BANALYSIS_BOOSTED_ANALYSIS
-
-#include "map"
-#include "xAODJet/JetContainer.h"
-
-std::map<std::string, double>
-getBoostedHiggsCandidates(const xAOD::JetContainer *largeRjets,
-                          std::map<std::string, double> h_cand_vars);
-
-#endif
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index 63e4733d3..c137cfcd2 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -1,11 +1,8 @@
 
 #include "DiHiggsAnalysis.h"
 #include "tools/kLargestJets.h"
-#include "xAODJet/JetContainer.h"
 #include <AsgMessaging/MessageCheck.h>
 #include <AthContainers/ConstDataVector.h>
-#include <SystematicsHandles/SysReadHandle.h>
-#include <xAODEventInfo/EventInfo.h>
 using namespace asg::msgUserCode;
 
 namespace HH4B
@@ -37,7 +34,7 @@ namespace HH4B
     // subleading higgs candidate
     HiggsCandidate h2;
 
-    // get indices of 4 largest pt jets
+    // get indices of 4 largest pt jets in descending order
     // need to do this because sequence filtering destroys order
     std::vector<int> fourLeadingPtJetsIndices = kLargestJets(smallRjets, 4);
 
@@ -45,51 +42,37 @@ namespace HH4B
     h1.leadingJet = smallRjets->at(fourLeadingPtJetsIndices[0]);
 
     // calculate dR to other jets to find closest one
-    std::vector<double> dRtoLeadingJet;
-    double minDR = 0;
+    double minDR = -1;
     int minDRindex = -1;
     for (int jetIndex : fourLeadingPtJetsIndices)
     {
       const xAOD::Jet *thisJet = smallRjets->at(jetIndex);
       double thisDRtoLeadingJet = thisJet->p4().DeltaR(h1.leadingJet->p4());
-      dRtoLeadingJet.push_back(thisDRtoLeadingJet);
-      if (minDR > 0 || minDR > thisDRtoLeadingJet)
+      if (thisDRtoLeadingJet > 0 or minDR > thisDRtoLeadingJet)
       {
         minDR = thisDRtoLeadingJet;
         minDRindex = jetIndex;
       }
     }
 
-    std::cout << dRtoLeadingJet[0] << ", " << dRtoLeadingJet[1] << ", "
-              << dRtoLeadingJet[2] << ", " << dRtoLeadingJet[3] << std::endl;
-    std::cout << minDRindex << std::endl;
     h1.subleadingJet = smallRjets->at(minDRindex);
-
-    // get closest jet to leading jet
-    // find index (iterator) of closest jet, skip leading one as dR=0
-    std::vector<double>::iterator dRminPosition =
-        std::min_element(dRtoLeadingJet.begin() + 1, dRtoLeadingJet.end());
-    // get position in fourLeadingPtJetsIndices to access the actual jet
-    int closestToLeadingJetIndex =
-        std::distance(dRtoLeadingJet.begin(), dRminPosition);
-    h1.subleadingJet =
-        smallRjets->at(fourLeadingPtJetsIndices[closestToLeadingJetIndex]);
-
-    // make higgs candidates
+    // calculate higgs candidate four vector and dR between jets
     h1.fourVector = h1.leadingJet->p4() + h1.subleadingJet->p4();
     h1.dRjets = h1.leadingJet->p4().DeltaR(h1.subleadingJet->p4());
 
-    // make a copy of the indices and delete the ones of the h1 to get the ones
-    // of h2, order matters!
-    std::vector<int> otherJetIndices = fourLeadingPtJetsIndices;
-    otherJetIndices.erase(otherJetIndices.begin() + closestToLeadingJetIndex);
-    otherJetIndices.erase(otherJetIndices.begin());
-
-    h2.leadingJet = smallRjets->at(otherJetIndices[0]);
-    h2.subleadingJet = smallRjets->at(otherJetIndices[1]);
+    // get jet indices of subleading higgs candidate h2
+    std::vector<int> h2_indices;
+    for (int jetIndex : fourLeadingPtJetsIndices)
+    {
+      if (jetIndex != fourLeadingPtJetsIndices[0] and jetIndex != minDRindex)
+        h2_indices.push_back(jetIndex);
+    }
 
+    h2.leadingJet = smallRjets->at(h2_indices[0]);
+    h2.subleadingJet = smallRjets->at(h2_indices[1]);
     h2.fourVector = h2.leadingJet->p4() + h2.subleadingJet->p4();
     h2.dRjets = h2.leadingJet->p4().DeltaR(h2.subleadingJet->p4());
+
     // write to dictionary
     h_cand_vars["resolved_m_h1"] = h1.fourVector.M();
     h_cand_vars["resolved_m_h2"] = h2.fourVector.M();
@@ -109,7 +92,7 @@ namespace HH4B
     // recommended by ftag : Remove the event if any of your signal jets have
     // relativeDeltaRToVRJet < 1.0.
     // least pt of large R's 250
-    // largest at least 450
+    // largest pt jet large R at least 450
     // eta < 2.0
 
     // delta eta between large r jets
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index 73fad58f1..9ff5cd839 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -2,7 +2,6 @@
 #define HH4B_DIHIGGSANALYSIS
 
 #include "xAODJet/JetContainer.h"
-#include <SystematicsHandles/SysReadHandle.h>
 #include <xAODEventInfo/EventInfo.h>
 
 // wollen vars immer rausschreiben
@@ -11,27 +10,33 @@ namespace HH4B
 {
   // dictionary holding the final vars
   extern std::map<std::string, double> h_cand_vars;
+
   struct HiggsCandidate
   {
-    // b-jets for h
+    // b-jets for Higgs candidate
     const xAOD::Jet *leadingJet = nullptr;
     const xAOD::Jet *subleadingJet = nullptr;
-
+    // four vector of Higgs candidate
     TLorentzVector fourVector;
+    // dR between leading and subleading jet
     double dRjets = -1;
 
     // for boosted analysis
     int largeRjetIndex = -1;
-    // btagged vr track jets inside the large R jet
+    // btagged ghost associated VR track jets inside the large R jet
     std::vector<ElementLink<xAOD::IParticleContainer>> btagged_VRTrackjets;
   };
 
   class DiHiggsAnalysis : HiggsCandidate
   {
 public:
+    // do resolved Analysis
     void makeResolvedAnalysis(const xAOD::JetContainer *smallRjets);
+    // do boosted Analysis
     void makeBoostedAnalysis(const xAOD::JetContainer *largeRjets);
+    // returns h_cand_vars for other purposes
     std::map<std::string, double> getHiggsVars();
+    // decorates the h_cand_vars to the eventInfo
     void decorateHiggsVars(const xAOD::EventInfo &eventInfo);
   };
 }
diff --git a/HH4bAnalysis/src/ResolvedAnalysis.cxx b/HH4bAnalysis/src/ResolvedAnalysis.cxx
deleted file mode 100644
index b590e8e8e..000000000
--- a/HH4bAnalysis/src/ResolvedAnalysis.cxx
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "ResolvedAnalysis.h"
-#include "map"
-#include "tools/kLargestJets.h"
-#include "xAODJet/JetContainer.h"
-
-std::map<std::string, double>
-getResolvedHiggsCandidates(const xAOD::JetContainer *smallRjets,
-                           std::map<std::string, double> &h_cand_vars)
-{
-  // check if we have at least 4 jets
-  if (smallRjets->size() < 4)
-  {
-    return h_cand_vars;
-  }
-  // get indices of 4 largest pt jets
-  // need to do this because sequence filtering destroys order
-  std::vector<int> fourLeadingPtJetsIndices = kLargestJets(smallRjets, 4);
-  // get largest pt jet
-  const xAOD::Jet *largestPtJet = smallRjets->at(fourLeadingPtJetsIndices[0]);
-
-  // calculate dR to other higgs candidate jets
-  std::vector<double> dRtoLargestPtJet;
-  for (int jetIndex : fourLeadingPtJetsIndices)
-  {
-    const xAOD::Jet *thisJet = smallRjets->at(jetIndex);
-    double thisDRtoLargestPtJet = thisJet->p4().DeltaR(largestPtJet->p4());
-    dRtoLargestPtJet.push_back(thisDRtoLargestPtJet);
-  }
-
-  // get closest jet to leading jet
-  int closestToLeadingJetEntry =
-      std::min_element(dRtoLargestPtJet.begin(), dRtoLargestPtJet.end()) -
-      dRtoLargestPtJet.begin();
-  const xAOD::Jet *closestToLeadingJet =
-      smallRjets->at(fourLeadingPtJetsIndices[closestToLeadingJetEntry]);
-
-  // make higgs candidates
-  TLorentzVector h1_cand = largestPtJet->p4() + closestToLeadingJet->p4();
-  double dR_jets_in_h1 = largestPtJet->p4().DeltaR(closestToLeadingJet->p4());
-
-  // make a copy of the indices and delete the ones of the h1_cand to get the
-  // ones of the h2_cand, order matters!
-  std::vector<int> otherJetIndices = fourLeadingPtJetsIndices;
-  otherJetIndices.erase(otherJetIndices.begin() + closestToLeadingJetEntry);
-  otherJetIndices.erase(otherJetIndices.begin());
-
-  const xAOD::Jet *otherJet1 = smallRjets->at(otherJetIndices[0]);
-  const xAOD::Jet *otherJet2 = smallRjets->at(otherJetIndices[1]);
-
-  TLorentzVector h2_cand = otherJet1->p4() + otherJet2->p4();
-  double dR_jets_in_h2 = otherJet1->p4().DeltaR(otherJet2->p4());
-
-  // write to dictionary
-  h_cand_vars["resolved_m_h1"] = h1_cand.M();
-  h_cand_vars["resolved_m_h2"] = h2_cand.M();
-  h_cand_vars["resolved_m_hh"] = (h1_cand + h2_cand).M();
-  h_cand_vars["resolved_dR_jets_in_h1"] = dR_jets_in_h1;
-  h_cand_vars["resolved_dR_jets_in_h2"] = dR_jets_in_h2;
-
-  return h_cand_vars;
-};
\ No newline at end of file
diff --git a/HH4bAnalysis/src/ResolvedAnalysis.h b/HH4bAnalysis/src/ResolvedAnalysis.h
deleted file mode 100644
index d9d38b545..000000000
--- a/HH4bAnalysis/src/ResolvedAnalysis.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef HH4BANALYSIS_RESOLVED_ANALYSIS
-#define HH4BANALYSIS_RESOLVED_ANALYSIS
-
-#include "map"
-#include "xAODJet/JetContainer.h"
-
-std::map<std::string, double>
-getResolvedHiggsCandidates(const xAOD::JetContainer *smallRjets,
-                           std::map<std::string, double> &h_cand_vars);
-
-#endif
-- 
GitLab


From db01f983156a2e6e2dc2e5b9129cb0c8e4dd2078 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 11 Aug 2022 13:36:43 +0200
Subject: [PATCH 12/33] adapt to new master

---
 HH4bAnalysis/share/VariableDumperConfig.py    | 850 +++++++++---------
 .../share/utils/containerNameHelper.py        |   3 -
 2 files changed, 412 insertions(+), 441 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 392fdb43a..41fc6ee40 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -1,440 +1,421 @@
 #!/bin/env python
-################################################################################
+
+#
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+#
+
+#
 # VariableDumperConfig.py
 # A simple CA file to create a tree of variables
 #
-# Author: Victor Ruelas
 
-# Basic setup
 import sys
+from pathlib import Path
 
-from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence
-from AnaAlgorithm.DualUseConfig import createAlgorithm
 from AthenaCommon import Logging
+from AthenaConfiguration.AutoConfigFlags import GetFileMD
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
-from utils.argsHelper import checkArgs
-from utils.containerNameHelper import getContainerName
-from utils.convertOldConfigHelper import convertSequenceAndGetAlgs
+from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Event import (
+    EventSelectionAnalysisSequenceCfg,
+    GeneratorAnalysisSequenceCfg,
+    PileupAnalysisSequenceCfg,
+    TriggerAnalysisSequenceCfg,
+)
+from HH4bAnalysis.Algs.Jets import (
+    FatJetAnalysisSequenceCfg,
+    JetAnalysisSequenceCfg,
+    VRJetAnalysisSequenceCfg,
+)
+from HH4bAnalysis.Algs.Muons import MuonAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Photons import PhotonAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Postprocessing import OverlapAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Tree import AnalysisTreeAlgCfg
+from HH4bAnalysis.Config.Base import cache_metadata, pileupConfigFiles, update_metadata
+from HH4bAnalysis.utils.containerNameHelper import getContainerName
+
+log = Logging.logging.getLogger("VariableDumperConfig")
+
+
+def defineArgs(ConfigFlags):
+    # Generate a parser and add an output file argument, then retrieve the args
+    parser = ConfigFlags.getArgumentParser()
+    parser.add_argument(
+        "--outFile",
+        type=str,
+        default="analysis-variables.root",
+        help="Output file name",
+    )
+    parser.add_argument(
+        "--btag-wps",
+        type=str,
+        nargs="*",
+        default=[
+            "DL1dv00_FixedCutBEff_77",
+            "DL1dv00_FixedCutBEff_85",
+        ],
+        help="Btag working points default %(default)s",
+    )
+    parser.add_argument(
+        "--vr-btag-wps",
+        type=str,
+        nargs="*",
+        default=[
+            # "DL1r_FixedCutBEff_77",
+            # "DL1r_FixedCutBEff_85",
+        ],
+        help="VR Jets btag working points default %(default)s",
+    )
+    parser.add_argument(
+        "--trigger-list",
+        type=str,
+        default="Run3",
+        help="Trigger list to use, default: %(default)s",
+    )
+    parser.add_argument(
+        "-c",
+        "--meta-cache",
+        type=Path,
+        default=None,
+        nargs="?",
+        const=Path("metadata.json"),
+        help="use metadata cache file, defaults to %(const)s",
+    )
+    parser.add_argument(
+        "-o",
+        "--loose",
+        action="store_true",
+        help="use loose event cleaning (to get something to pass)",
+    )
+    return parser
+
 
-variabledumperlog = Logging.logging.getLogger("VariableDumperConfig")
+def _is_physlite(flags):
+    fileMD = GetFileMD(flags.Input.Files[0])
+    return fileMD.get("processingTags", []) == ["StreamDAOD_PHYSLITE"]
 
 
-def pileupConfigFiles(dataType):
-    """Return the PRW (Pileup ReWeighting) config files and lumicalc files"""
-    if dataType == "data":
-        prwFiles = []
-        lumicalcFiles = []
+def _is_mc_phys(flags):
+    return flags.Input.isMC and not _is_physlite(flags)
+
+
+def _get_container_names(flags):
+    is_daod_physlite = _is_physlite(flags)
+    inputs = dict(
+        reco4Jet=getContainerName("Reco4PFlowJets", is_daod_physlite),
+        reco10Jet=getContainerName("Reco10PFlowJets", is_daod_physlite),
+        vrJet=getContainerName("VRJets", is_daod_physlite),
+        muons=getContainerName("Muons", is_daod_physlite),
+        electrons=getContainerName("Electrons", is_daod_physlite),
+        photons=getContainerName("Photons", is_daod_physlite),
+    )
+    outputs = dict(
+        reco4Jet=f"Analysis{inputs['reco4Jet']}_%SYS%",
+        muons=f"Analysis{inputs['muons']}_%SYS%",
+        electrons=f"Analysis{inputs['electrons']}_%SYS%",
+        photons=f"Analysis{inputs['photons']}_%SYS%",
+    )
+    if inputs["reco10Jet"]:
+        outputs["reco10Jet"] = f"Analysis{inputs['reco10Jet']}_%SYS%"
     else:
-        lumicalcFiles = [
-            # These need to be updated for release 22 data
-            # "GoodRunsLists/data15_13TeV/20170619/PHYS_StandardGRL_All_Good_25ns_276262-284484_OflLumi-13TeV-008.root",
-            # "GoodRunsLists/data16_13TeV/20180129/PHYS_StandardGRL_All_Good_25ns_297730-311481_OflLumi-13TeV-009.root",
-            # "GoodRunsLists/data17_13TeV/20180619/physics_25ns_Triggerno17e33prim.lumicalc.OflLumi-13TeV-010.root",
-            # "GoodRunsLists/data18_13TeV/20190318/ilumicalc_histograms_None_348885-364292_OflLumi-13TeV-010.root",
-        ]
-        if dataType == "mc":
-            prwFiles = [
-                # Need to be updated and are job specific?
-                # "/cvmfs/atlas.cern.ch/repo/sw/database/GroupData/dev/PileupReweighting/share/DSID364xxx/pileup_mc20d_dsid364701_FS.root"
-            ]
-        else:
-            # We don't have a PRW file that works properly for the AFII file
-            # so we don't apply it in this case
-            prwFiles = []
-    return prwFiles, lumicalcFiles
+        outputs["reco10Jet"] = ""
+    if inputs["vrJet"]:
+        outputs["vrJet"] = f"Analysis{inputs['vrJet']}_%SYS%"
+    else:
+        outputs["vrJet"] = ""
+    return {"inputs": inputs, "outputs": outputs}
 
 
 # Generate the algorithm to do the dumping.
 # AthAlgSequence does not respect filter decisions,
 # so we will need to add a new sequence to the CA
-def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
+def AnalysisAlgsCfg(
+    flags,
+    btag_wps,
+    vr_btag_wps,
+    trigger_chains=[],
+    do_muons=True,
+    metadata_cache=None,
+    do_loose=False,
+):
+    fileMD = GetFileMD(flags.Input.Files[0])
+    if metadata_cache:
+        update_metadata(metadata_cache)
     dataType = "mc" if flags.Input.isMC else "data"
+    is_daod_physlite = _is_physlite(flags)
+    log.info(
+        f"Self-configured: dataType: '{dataType}', is PHYSLITE? {is_daod_physlite}"
+    )
 
-    reco4JetContainerName = getContainerName("Reco4PFlowJets", is_daod_physlite)
-    reco10JetContainerName = getContainerName("Reco10PFlowJets", is_daod_physlite)
-    recoVRJetContainerName = getContainerName("RecoVRTrackJets", is_daod_physlite)
-    muonsContainerName = getContainerName("Muons", is_daod_physlite)
-    electronsContainerName = getContainerName("Electrons", is_daod_physlite)
-    photonsContainerName = getContainerName("Photons", is_daod_physlite)
+    log.debug(f"Containers available in dataset: {flags.Input.Collections}")
+
+    # TODO: no DL1d branches in PHYSLITE yet
+    if is_daod_physlite:
+        btag_wps = [wp.replace("DL1dv00", "DL1r") for wp in btag_wps]
 
     cfg = ComponentAccumulator()
 
     # Every CA should include all its dependencies, apart from the global ones
     # included in the main function.
     #
-    # Add an instance of THistSvc, to create the output file and associated stream.
-    # This is needed so that the alg can register its output TTree.
-    # The syntax for the output is:
-    #   Stream name: "ANALYSIS" (default assumed by AthHistogramAlgorithm)
-    #   Output file name: specified by setting "DATAFILE"
-    #   File I/O option: specified by setting "OPT" and passed to the TFile constructor
-    #      "RECREATE" will (over)write the specified file name with a new file
-    cfg.addService(
-        CompFactory.THistSvc(Output=[f"ANALYSIS DATAFILE='{outfname}', OPT='RECREATE'"])
-    )
     # Create SystematicsSvc explicitly:
-    cfg.addService(CompFactory.getComp("CP::SystematicsSvc")("SystematicsSvc"))
-
-    # Include, and then set up the pileup analysis sequence:
-    prwFiles, lumicalcFiles = pileupConfigFiles(dataType)
-
-    # Create a pile-up analysis sequence
-    from AsgAnalysisAlgorithms.PileupAnalysisSequence import makePileupAnalysisSequence
-
-    pileupSequence = makePileupAnalysisSequence(
-        dataType,
-        userPileupConfigs=prwFiles,
-        userLumicalcFiles=lumicalcFiles,
-        autoConfig=False,
-    )
-    pileupSequence.configure(inputName={}, outputName={})
-    # print(pileupSequence)  # For debugging
-    # Convert to new configurables
-    pileupSequenceCnv, algsCnv = convertSequenceAndGetAlgs(CompFactory, pileupSequence)
-    cfg.addSequence(pileupSequenceCnv)
-    for alg in algsCnv:
-        cfg.addEventAlgo(alg, pileupSequenceCnv.getName())
-
-    # Include, and then set up the electron analysis sequence:
-    from EgammaAnalysisAlgorithms.ElectronAnalysisSequence import (
-        makeElectronAnalysisSequence,
+    systematicsSvc = CompFactory.getComp("CP::SystematicsSvc")("SystematicsSvc")
+    cfg.addService(systematicsSvc)
+
+    log.info("Adding trigger analysis algs")
+    # Removes events failing trigger and adds variable to EventInfo
+    # if trigger passed or not, for example:
+    # EventInfo.trigger_name
+    cfg.merge(TriggerAnalysisSequenceCfg(flags, dataType, trigger_chains))
+
+    log.info("Add DQ event filter sequence")
+    # Remove events failing DQ criteria
+    cfg.merge(
+        EventSelectionAnalysisSequenceCfg(flags, dataType, grlFiles=[], loose=do_loose)
     )
 
-    electronSequence = makeElectronAnalysisSequence(
-        dataType,
-        workingPoint="LooseLHElectron.NonIso",
-        postfix="loose",
-        deepCopyOutput=False,
-        shallowViewOutput=True,
-        recomputeLikelihood=False,
-        chargeIDSelection=False,
-        isolationCorrection=False,
-        crackVeto=False,
-        ptSelectionOutput=False,
-        enableCutflow=False,
-        enableKinematicHistograms=False,
-    )
-    electronSequence.configure(
-        inputName=electronsContainerName, outputName="AnalysisElectrons_%SYS%"
-    )
-    # print(electronSequence)  # For debugging
-    # Convert to new configurables
-    electronSequenceCnv, electronAlgsCnv = convertSequenceAndGetAlgs(
-        CompFactory, electronSequence
+    doPRW = _is_mc_phys(flags)
+    log.info(
+        f"Do PRW is {doPRW}. {'Add' if doPRW else 'Skip'} pileup re-weight sequence"
     )
-    cfg.addSequence(electronSequenceCnv)
-    for electronAlg in electronAlgsCnv:
-        cfg.addEventAlgo(electronAlg, electronSequenceCnv.getName())
+    if doPRW:
+        try:
+            prwFiles, lumicalcFiles = pileupConfigFiles(fileMD)
+            # Adds variable to EventInfo if for pileup weight, for example:
+            # EventInfo.PileWeight_%SYS$
+            cfg.merge(
+                PileupAnalysisSequenceCfg(
+                    flags,
+                    dataType=dataType,
+                    prwFiles=prwFiles,
+                    lumicalcFiles=lumicalcFiles,
+                )
+            )
 
-    # Include, and then set up the photon analysis sequence:
-    from EgammaAnalysisAlgorithms.PhotonAnalysisSequence import (
-        makePhotonAnalysisSequence,
+            log.info("Adding generator analysis sequence")
+            runNumbers = fileMD.get("runNumbers", [])
+            # Adds variable to EventInfo if for generator weight, for example:
+            # EventInfo.generatorWeight_%SYS%
+            cfg.merge(GeneratorAnalysisSequenceCfg(flags, dataType, runNumbers[0]))
+
+        except LookupError as err:
+            log.error(err)
+            doPRW = False
+
+    containers = _get_container_names(flags)
+
+    log.info("Add electron seq")
+    cfg.merge(
+        ElectronAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputContainerName=containers["inputs"]["electrons"],
+            outputContainerName=containers["outputs"]["electrons"],
+        )
     )
 
-    photonSequence = makePhotonAnalysisSequence(
-        dataType,
-        workingPoint="Loose.Undefined",
-        postfix="loose",
-        deepCopyOutput=False,
-        shallowViewOutput=True,
-        crackVeto=False,
-        enableCleaning=True,
-        cleaningAllowLate=False,
-        recomputeIsEM=False,
-        ptSelectionOutput=False,
-        enableCutflow=False,
-        enableKinematicHistograms=False,
-    )
-    photonSequence.configure(
-        inputName=photonsContainerName, outputName="AnalysisPhotons_%SYS%"
-    )
-    # print(photonSequence)  # For debugging
-    # Convert to new configurables
-    photonSequenceCnv, photonAlgsCnv = convertSequenceAndGetAlgs(
-        CompFactory, photonSequence
-    )
-    cfg.addSequence(photonSequenceCnv)
-    for photonAlg in photonAlgsCnv:
-        cfg.addEventAlgo(photonAlg, photonSequenceCnv.getName())
-
-    # Include, and then set up the muon analysis algorithm sequence:
-    from MuonAnalysisAlgorithms.MuonAnalysisSequence import makeMuonAnalysisSequence
-
-    muonSequence = makeMuonAnalysisSequence(
-        dataType,
-        workingPoint="Loose.NonIso",
-        postfix="loose",
-        deepCopyOutput=False,
-        shallowViewOutput=True,
-        ptSelectionOutput=False,
-        qualitySelectionOutput=True,
-        enableCutflow=False,
-        enableKinematicHistograms=False,
-    )
-    muonSequence.configure(
-        inputName=muonsContainerName, outputName="AnalysisMuons_%SYS%"
-    )
-    # print(muonLooseSequence)  # For debugging
-    # Convert to new configurables
-    muonSequenceCnv, muonAlgsCnv = convertSequenceAndGetAlgs(CompFactory, muonSequence)
-    cfg.addSequence(muonSequenceCnv)
-    for muonAlg in muonAlgsCnv:
-        cfg.addEventAlgo(muonAlg, muonSequenceCnv.getName())
-
-    from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
-
-    jetSequence = makeJetAnalysisSequence(
-        dataType,
-        jetCollection=reco4JetContainerName,
-        postfix="smallR",
-        deepCopyOutput=False,
-        shallowViewOutput=True,
-        runGhostMuonAssociation=True,
-        enableCutflow=False,
-        enableKinematicHistograms=False,
-        runFJvtUpdate=False,
-        runFJvtSelection=False,
-        runJvtSelection=False,
+    log.info("Add photon seq")
+    cfg.merge(
+        PhotonAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputContainerName=containers["inputs"]["photons"],
+            outputContainerName=containers["outputs"]["photons"],
+        )
     )
 
-    from FTagAnalysisAlgorithms.FTagAnalysisSequence import makeFTagAnalysisSequence
+    if do_muons:
+        log.info("Add muon seq")
+        cfg.merge(
+            MuonAnalysisSequenceCfg(
+                flags,
+                dataType=dataType,
+                inputContainerName=containers["inputs"]["muons"],
+                outputContainerName=containers["outputs"]["muons"],
+            )
+        )
 
-    bTagCalibFile = (
-        "xAODBTaggingEfficiency/13TeV/2021-22-13TeV-MC16-CDI-2021-12-02_v2.root"
-    )
-    for tagger_wp in btag_wps:
-        tagger, btag_wp = tagger_wp.split("_", 1)
-        ftagSeq = makeFTagAnalysisSequence(
-            jetSequence,
-            dataType,
-            jetCollection=reco4JetContainerName,
-            btagWP=btag_wp,
-            btagger=tagger,
-            generator="Pythia8",
-            minPt=20000,
-            postfix="",
-            preselection=None,
-            kinematicSelection=False,
-            noEfficiency=False,
-            legacyRecommendations=False,
-            enableCutflow=False,
+    log.info("Add jet seq")
+    cfg.merge(
+        JetAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputContainerName=containers["inputs"]["reco4Jet"],
+            outputContainerName=containers["outputs"]["reco4Jet"],
+            workingPoints=btag_wps,
+            is_daod_physlite=is_daod_physlite,
         )
-        # Hack until this is merged:
-        # https://gitlab.cern.ch/atlas/athena/-/merge_requests/54939]
-        for ftagAlg in ftagSeq:
-            if "FTagSelectionAlg" in ftagAlg.getName():
-                ftagAlg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile
-            if "FTagEfficiencyScaleFactorAlg" in ftagAlg.getName():
-                ftagAlg.efficiencyTool.ScaleFactorFileName = bTagCalibFile
-
-    jetSequence.configure(
-        inputName=reco4JetContainerName,
-        outputName="AnalysisJets_%SYS%",
-    )
-    print(jetSequence)  # For debugging
-    # Convert to new configurables
-    jetSequenceCnv, jetAlgsCnv = convertSequenceAndGetAlgs(CompFactory, jetSequence)
-    cfg.addSequence(jetSequenceCnv)
-    for jetAlg in jetAlgsCnv:
-        cfg.addEventAlgo(jetAlg, jetSequenceCnv.getName())
-
-    # Variable Radius jets Ftag sqeuence
-    VRSequence = AnaAlgSequence("VRTrackFTagAnalysisSequence")
-    # the following lines make a shallow copy,
-    # this isn't needed anymore with this MR
-    # https://gitlab.cern.ch/atlas/athena/-/merge_requests/54929
-    alg = createAlgorithm("CP::AsgViewFromSelectionAlg", "VRJetSelectionAlg")
-    VRSequence.append(
-        alg,
-        inputPropName="input",
-        outputPropName="output",
-        stageName="selection",
-        dynConfig={},
-    )
-    VRftagSequence = makeFTagAnalysisSequence(
-        VRSequence,
-        dataType,
-        "AntiKtVR30Rmax4Rmin02TrackJets",
-        btagWP="FixedCutBEff_77",
-        btagger="DL1r",
-        postfix="VR",
-        preselection=None,
-        kinematicSelection=True,
-        noEfficiency=False,
-        legacyRecommendations=False,
-        enableCutflow=False,
-        minPt=20000,
     )
 
-    for ftagAlg in VRftagSequence:
-        if "FTagSelectionAlg" in ftagAlg.getName():
-            ftagAlg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile
-        if "FTagEfficiencyScaleFactorAlg" in ftagAlg.getName():
-            ftagAlg.efficiencyTool.ScaleFactorFileName = bTagCalibFile
+    if is_daod_physlite:
+        log.warning("On PHYSLITE, skip large-R jet sequence for now")
+    else:
+        log.info("Add large-R jet seq")
+        cfg.merge(
+            FatJetAnalysisSequenceCfg(
+                flags,
+                dataType=dataType,
+                inputContainerName=containers["inputs"]["reco10Jet"],
+                outputContainerName=containers["outputs"]["reco10Jet"],
+            )
+        )
 
-    VRSequence.configure(
-        inputName=recoVRJetContainerName, outputName="VRTrackJetsBTAG_%SYS%"
-    )
+    if is_daod_physlite:
+        log.warning("On PHYSLITE, skip VR jet sequence for now")
+    else:
+        log.info("Add VR jet seq")
+        cfg.merge(
+            VRJetAnalysisSequenceCfg(
+                flags,
+                dataType=dataType,
+                inputContainerName=containers["inputs"]["vrJet"],
+                outputContainerName=containers["outputs"]["vrJet"],
+                workingPoints=vr_btag_wps,
+            )
+        )
 
-    VRjetSequenceCnv, VRjetAlgsCnv = convertSequenceAndGetAlgs(CompFactory, VRSequence)
-    cfg.addSequence(VRjetSequenceCnv)
-    for VRjetAlg in VRjetAlgsCnv:
-        cfg.addEventAlgo(VRjetAlg, VRjetSequenceCnv.getName())
-
-    largeRrecojetSequence = makeJetAnalysisSequence(
-        dataType,
-        reco10JetContainerName,
-        postfix="largeR",
-        deepCopyOutput=False,
-        shallowViewOutput=True,
-        runGhostMuonAssociation=False,
-        enableCutflow=False,
-        enableKinematicHistograms=False,
-        largeRMass="Comb",
-    )
-    largeRrecojetSequence.configure(
-        inputName=reco10JetContainerName, outputName="AnalysisLargeRRecoJets_%SYS%"
-    )
-    # print(largeRrecojetSequence)  # For debugging
-    # Convert to new configurables
-    largeRrecojetSequenceCnv, largeJetAlgsCnv = convertSequenceAndGetAlgs(
-        CompFactory, largeRrecojetSequence
+    ########################################################################
+    # Begin postprocessing
+    ########################################################################
+
+    log.info("Add Overlap Removal sequence")
+    overlapInputNames = {
+        "electrons": containers["outputs"]["electrons"],
+        "photons": containers["outputs"]["photons"],
+        "jets": containers["outputs"]["reco4Jet"],
+    }
+    if do_muons:
+        overlapInputNames["muons"] = containers["outputs"]["muons"]
+
+    if not is_daod_physlite:
+        overlapInputNames["fatJets"] = containers["outputs"]["reco10Jet"]
+
+    overlapOutputNames = {k: f"{v}_OR" for k, v in overlapInputNames.items()}
+
+    cfg.merge(
+        OverlapAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputNames=overlapInputNames,
+            outputNames=overlapOutputNames,
+            doFatJets=not is_daod_physlite,
+            doMuons=do_muons,
+        )
     )
-    cfg.addSequence(largeRrecojetSequenceCnv)
-    for largeJetAlg in largeJetAlgsCnv:
-        cfg.addEventAlgo(largeJetAlg, largeRrecojetSequenceCnv.getName())
 
-    # Include, and then set up the overlap analysis algorithm sequence:
-    from AsgAnalysisAlgorithms.OverlapAnalysisSequence import (
-        makeOverlapAnalysisSequence,
-    )
+    if metadata_cache:
+        cache_metadata(metadata_cache)
 
-    overlapSequence = makeOverlapAnalysisSequence(
-        dataType,
-        inputLabel="",
-        outputLabel="passesOR",
-        linkOverlapObjects=False,
-        doEleEleOR=False,
-        doMuPFJetOR=True,
-        doTaus=False,
-        doElectrons=True,
-        doMuons=True,
-        doJets=True,
-        doPhotons=True,
-        doFatJets=True,
-        enableUserPriority=False,
-        bJetLabel="",
-        boostedLeptons=False,
-        postfix="",
-        shallowViewOutput=True,
-        enableCutflow=False,
-    )
-    overlapSequence.configure(
-        inputName={
-            "electrons": "AnalysisElectrons_%SYS%",
-            "photons": "AnalysisPhotons_%SYS%",
-            "muons": "AnalysisMuons_%SYS%",
-            "jets": "AnalysisJets_%SYS%",
-            "fatJets": "AnalysisLargeRRecoJets_%SYS%",
-            # 'taus'      : 'AnalysisTauJets_%SYS%'
-        },
-        outputName={
-            "electrons": "AnalysisElectronsOR_%SYS%",
-            "photons": "AnalysisPhotonsOR_%SYS%",
-            "muons": "AnalysisMuonsOR_%SYS%",
-            "jets": "AnalysisJetsOR_%SYS%",
-            "fatJets": "AnalysisLargeRRecoJetsOR_%SYS%",
-            # 'taus'      : 'AnalysisTauJetsOR_%SYS%'
-        },
-    )
-    # print(overlapSequence)  # For debugging
-    # Convert to new configurables
-    overlapSequenceCnv, overlapAlgsCnv = convertSequenceAndGetAlgs(
-        CompFactory, overlapSequence
-    )
-    cfg.addSequence(overlapSequenceCnv)
-    for overlapAlg in overlapAlgsCnv:
-        cfg.addEventAlgo(overlapAlg, overlapSequenceCnv.getName())
-
-    cfg.addEventAlgo(
-        CompFactory.HH4B.VariableDumperAlg(
-            "VariableDumper",
-            EventInfoKey="EventInfo",
-            RootStreamName="ANALYSIS",
-            # btag_wps=btag_wps,
-        )
-    )
+    return cfg
+
+
+def MiniTupleCfg(
+    flags,
+    outfname,
+    trigger_chains,
+    working_points,
+    do_muons=True,
+):
+    cfg = ComponentAccumulator()
+    is_daod_physlite = _is_physlite(flags)
+    doPRW = _is_mc_phys(flags)
+    containers = _get_container_names(flags)["outputs"]
 
+    log.debug(f"Containers requested in dataset: {containers}")
+
+    ########################################################################
     # Create analysis mini-ntuple
-    treeMaker = CompFactory.getComp("CP::TreeMakerAlg")("TreeMaker")
-    treeMaker.TreeName = "AnalysisMiniTree"
-
-    # Add event info
-    cfg.addEventAlgo(treeMaker)
-    ntupleMaker = CompFactory.getComp("CP::AsgxAODNTupleMakerAlg")("NTupleMaker")
-    ntupleMaker.TreeName = "AnalysisMiniTree"
-    ntupleMaker.Branches = [
+    ########################################################################
+
+    # Add an instance of THistSvc, to create the output file and associated stream.
+    # This is needed so that the alg can register its output TTree.
+    # The syntax for the output is:
+    #   Stream name: "ANALYSIS" (default assumed by AthHistogramAlgorithm)
+    #   Output file name: specified by setting "DATAFILE"
+    #   File I/O option: specified by setting "OPT" and passed to the TFile constructor
+    #      "RECREATE" will (over)write the specified file name with a new file
+    cfg.addService(
+        CompFactory.THistSvc(Output=[f"ANALYSIS DATAFILE='{outfname}', OPT='RECREATE'"])
+    )
+
+    def getFourMomBranches(container, alias, doOR=False):
+        ORstr = "_OR" if doOR else ""
+
+        branches = []
+        vars = ["pt", "eta", "phi"]
+        if "Jets" in container:
+            vars.append("m")
+        for var in vars:
+            branches += [
+                f"{container}{ORstr}.{var}  -> {alias}{ORstr}_%SYS%_{var}",
+            ]
+        return branches
+
+    analysisTreeBranches = [
         "EventInfo.runNumber     -> runNumber",
         "EventInfo.eventNumber   -> eventNumber",
-        # we currently don't have any pileup calib files setup
-        # 'EventInfo.PileupWeight_%SYS% -> pileupWeight_%SYS%',
-        # "EventInfo.mcEventWeights   -> mcEventWeights",
-        "AnalysisElectrons_%SYS%.pt  -> el_%SYS%_pt",
-        "AnalysisElectrons_%SYS%.eta -> el_%SYS%_eta",
-        "AnalysisElectrons_%SYS%.phi -> el_%SYS%_phi",
-        "AnalysisElectronsOR_%SYS%.eta -> el_OR_%SYS%_eta",
-        "AnalysisElectronsOR_%SYS%.phi -> el_OR_%SYS%_phi",
-        "AnalysisElectronsOR_%SYS%.pt  -> el_OR_%SYS%_pt",
-        "AnalysisPhotons_%SYS%.pt  -> ph_%SYS%_pt",
-        "AnalysisPhotons_%SYS%.eta -> ph_%SYS%_eta",
-        "AnalysisPhotons_%SYS%.phi -> ph_%SYS%_phi",
-        "AnalysisPhotonsOR_%SYS%.eta -> ph_OR_%SYS%_eta",
-        "AnalysisPhotonsOR_%SYS%.phi -> ph_OR_%SYS%_phi",
-        "AnalysisPhotonsOR_%SYS%.pt  -> ph_OR_%SYS%_pt",
-        "AnalysisMuons_%SYS%.pt  -> mu_%SYS%_pt",
-        "AnalysisMuons_%SYS%.eta -> mu_%SYS%_eta",
-        "AnalysisMuons_%SYS%.phi -> mu_%SYS%_phi",
-        "AnalysisMuonsOR_%SYS%.eta -> mu_OR_%SYS%_eta",
-        "AnalysisMuonsOR_%SYS%.phi -> mu_OR_%SYS%_phi",
-        "AnalysisMuonsOR_%SYS%.pt  -> mu_OR_%SYS%_pt",
-        "AnalysisJets_%SYS%.m  -> recojet_antikt4_%SYS%_m",
-        "AnalysisJets_%SYS%.pt  -> recojet_antikt4_%SYS%_pt",
-        "AnalysisJets_%SYS%.eta -> recojet_antikt4_%SYS%_eta",
-        "AnalysisJets_%SYS%.phi -> recojet_antikt4_%SYS%_phi",
-        "AnalysisJetsOR_%SYS%.m  -> recojet_antikt4_OR_%SYS%_m",
-        "AnalysisJetsOR_%SYS%.pt  -> recojet_antikt4_OR_%SYS%_pt",
-        "AnalysisJetsOR_%SYS%.eta -> recojet_antikt4_OR_%SYS%_eta",
-        "AnalysisJetsOR_%SYS%.phi -> recojet_antikt4_OR_%SYS%_phi",
-        "AnalysisLargeRRecoJets_%SYS%.m  -> recojet_antikt10_%SYS%_m",
-        "AnalysisLargeRRecoJets_%SYS%.pt  -> recojet_antikt10_%SYS%_pt",
-        "AnalysisLargeRRecoJets_%SYS%.eta -> recojet_antikt10_%SYS%_eta",
-        "AnalysisLargeRRecoJets_%SYS%.phi -> recojet_antikt10_%SYS%_phi",
-        "AnalysisLargeRRecoJetsOR_%SYS%.m  -> recojet_antikt10_OR_%SYS%_m",
-        "AnalysisLargeRRecoJetsOR_%SYS%.pt  -> recojet_antikt10_OR_%SYS%_pt",
-        "AnalysisLargeRRecoJetsOR_%SYS%.eta -> recojet_antikt10_OR_%SYS%_eta",
-        "AnalysisLargeRRecoJetsOR_%SYS%.phi -> recojet_antikt10_OR_%SYS%_phi",
-        "EventInfo.resolved_m_h1   -> resolved_m_h1",
-        "EventInfo.resolved_m_h2   -> resolved_m_h2",
-        "EventInfo.resolved_m_hh   -> resolved_m_hh",
-        "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
-        "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
-        "EventInfo.boosted_m_h1   -> boosted_m_h1",
-        "EventInfo.boosted_m_h2   -> boosted_m_h2",
-        "EventInfo.boosted_m_hh   -> boosted_m_hh",
-        "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
-        "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
+        "EventInfo.mcEventWeights   -> mcEventWeights",
+        "EventInfo.averageInteractionsPerCrossing -> averageInteractionsPerCrossing",
     ]
-    ntupleMaker.Branches += [
-        f"AnalysisJets_%SYS%.ftag_select_{btag_wp} -> recojet_antikt4_%SYS%_{btag_wp}"
-        for btag_wp in btag_wps
+
+    for trig_chain in trigger_chains:
+        cleaned = trig_chain.replace("-", "_")
+        if "." in trig_chain:
+            continue
+        analysisTreeBranches.append(
+            f"EventInfo.trigPassed_{cleaned} -> trigPassed_{cleaned}"
+        )
+
+    if doPRW:
+        analysisTreeBranches += [
+            "EventInfo.PileupWeight_%SYS% -> pileupWeight_%SYS%",
+            "EventInfo.generatorWeight_%SYS% -> generatorWeight_%SYS%",
+        ]
+    else:
+        analysisTreeBranches += [
+            "EventInfo.mcEventWeights -> pileupWeight_NOSYS",
+        ]
+
+    objectpairs = {
+        containers["electrons"]: "el",
+        containers["photons"]: "ph",
+        containers["reco4Jet"]: "recojet_antikt4",
+    }
+    if do_muons:
+        containers["muons"] = "mu"
+
+    for cont, alias in objectpairs.items():
+        analysisTreeBranches += getFourMomBranches(cont, alias)
+        analysisTreeBranches += getFourMomBranches(cont, alias, doOR=True)
+
+    # B-jet WPs
+    analysisTreeBranches += [
+        f"{containers['reco4Jet']}.ftag_select_{btag_wp}"
+        f" -> recojet_antikt4_%SYS%_{btag_wp}"
+        for btag_wp in working_points["ak4"]
+    ]
+    analysisTreeBranches += [
+        f"{containers['reco4Jet']}_OR.ftag_select_{btag_wp}"
+        f" -> recojet_antikt4_OR_%SYS%_{btag_wp}"
+        for btag_wp in working_points["ak4"]
     ]
-    cfg.addEventAlgo(ntupleMaker)
 
-    # Fill tree
-    treeFiller = CompFactory.getComp("CP::TreeFillerAlg")("TreeFiller")
-    treeFiller.TreeName = "AnalysisMiniTree"
-    cfg.addEventAlgo(treeFiller)
+    if not is_daod_physlite:
+        analysisTreeBranches += getFourMomBranches(
+            containers["reco10Jet"], "recojet_antikt10"
+        )
+        analysisTreeBranches += getFourMomBranches(
+            containers["reco10Jet"], "recojet_antikt10", doOR=True
+        )
+        analysisTreeBranches += getFourMomBranches(containers["vrJet"], "vrjet")
+        analysisTreeBranches += [
+            f"{containers['vrJet']}.ftag_select_{btag_wp} -> vrjet_%SYS%_{btag_wp}"
+            for btag_wp in working_points["vr"]
+        ]
+
+    log.info("Add tree seq")
+    cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
 
     return cfg
 
@@ -443,55 +424,31 @@ def VariableDumperCfg(flags, outfname, is_daod_physlite, btag_wps):
 # We define a "main function" that will run a test job if the module
 # is executed rather than imported.
 def main():
+    # Import the job configuration flags, some of which will be autoconfigured.
+    # These are used for steering the job, and include e.g. the input file (list).
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+
+    # Get the arguments, defined at the top for easy browsing
+    parser = defineArgs(ConfigFlags)
+    args = ConfigFlags.fillFromArgs([], parser)
+    # Lock the flags so that the configuration of job subcomponents cannot
+    # modify them silently/unpredictably.
+    # Workaround for buggy glob, needed prior
+    # to https://gitlab.cern.ch/atlas/athena/-/merge_requests/55561
+    if ConfigFlags.Input.Files[0] == "_ATHENA_GENERIC_INPUTFILE_NAME_":
+        ConfigFlags.Input.Files = ConfigFlags.Input.Files[1:]
+    log.info(f"Operating on input files {ConfigFlags.Input.Files}")
+    ConfigFlags.lock()
+
+    # Get a ComponentAccumulator setting up the standard components
+    # needed to run an Athena job.
     # Setting temporarily needed for Run 3 code, to generate python
     # Configurable objects for deduplication
     from AthenaCommon.Configurable import ConfigurableRun3Behavior
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
 
     with ConfigurableRun3Behavior():
 
-        # Import the job configuration flags, some of which will be autoconfigured.
-        # These are used for steering the job, and include e.g. the input file (list).
-        from AthenaConfiguration.AllConfigFlags import ConfigFlags
-
-        # Generate a parser and add an output file argument, then retrieve the args
-        parser = ConfigFlags.getArgumentParser()
-        parser.add_argument(
-            "--outFile",
-            type=str,
-            default="analysis-variables.root",
-            help="Output file name",
-        )
-        parser.add_argument(
-            "--mc",
-            action="store_true",
-            help="Input is Monte Carlo",
-        )
-        parser.add_argument(
-            "--daod-physlite",
-            action="store_true",
-            help="Input is DAOD_PHYSLITE",
-        )
-        parser.add_argument(
-            "--btag-wps",
-            type=str,
-            nargs="+",
-            default=[
-                "DL1dv00_FixedCutBEff_77",
-                "DL1dv00_FixedCutBEff_85",
-            ],
-            help="btag working points default %(default)s",
-        )
-        args = ConfigFlags.fillFromArgs([], parser)
-        # Lock the flags so that the configuration of job subcomponents cannot
-        # modify them silently/unpredictably.
-        ConfigFlags.lock()
-
-        checkArgs(ConfigFlags, args, parser)
-
-        # Get a ComponentAccumulator setting up the standard components
-        # needed to run an Athena job.
-        from AthenaConfiguration.MainServicesConfig import MainServicesCfg
-
         cfg = MainServicesCfg(ConfigFlags)
         # Adjust the loop manager to announce the event number less frequently.
         # Makes a big difference if running over many events
@@ -502,25 +459,42 @@ def main():
         else:
             cfg.addService(CompFactory.AthenaEventLoopMgr(EventPrintoutInterval=500))
 
-        # Add the components for reading in POOL files -- this is a specialised
-        # ROOT format storing structured objects like the
-        # ATLAS physics objects (jets etc)
-        from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+        from HH4bAnalysis.Config.xAODEventSelectorConfig import xAODReadCfg
 
-        cfg.merge(PoolReadCfg(ConfigFlags))
+        cfg.merge(xAODReadCfg(ConfigFlags))
 
         # Add our VariableDumper CA, calling the function defined above.
+        from HH4bAnalysis.Config.TriggerLists import TriggerLists
+
+        trigger_chains = TriggerLists[args.trigger_list]
+        do_muons = not args.meta_cache
+
+        cfg.addSequence(CompFactory.AthSequencer("HH4bSeq"), "AthAlgSeq")
         cfg.merge(
-            VariableDumperCfg(
+            AnalysisAlgsCfg(
                 ConfigFlags,
-                outfname=args.outFile,
-                is_daod_physlite=args.daod_physlite,
                 btag_wps=args.btag_wps,
-            )
+                vr_btag_wps=args.vr_btag_wps,
+                trigger_chains=trigger_chains,
+                metadata_cache=args.meta_cache,
+                do_muons=do_muons,
+                do_loose=args.loose,
+            ),
+            "HH4bSeq",
+        )
+        cfg.merge(
+            MiniTupleCfg(
+                ConfigFlags,
+                outfname=args.outFile,
+                trigger_chains=trigger_chains,
+                working_points={"ak4": args.btag_wps, "vr": args.vr_btag_wps},
+                do_muons=do_muons,
+            ),
+            "HH4bSeq",
         )
 
         # Print the full job configuration
-        cfg.printConfig()
+        cfg.printConfig(summariseProps=False)
 
     # Execute the job defined in the ComponentAccumulator.
     # The number of events is specified by `args.evtMax`
diff --git a/HH4bAnalysis/share/utils/containerNameHelper.py b/HH4bAnalysis/share/utils/containerNameHelper.py
index 359a74d88..121a76bde 100644
--- a/HH4bAnalysis/share/utils/containerNameHelper.py
+++ b/HH4bAnalysis/share/utils/containerNameHelper.py
@@ -3,7 +3,6 @@
 # custom container names used in this framework
 RECO_4_PFLOW_JETS_KEY = "Reco4PFlowJets"
 RECO_10_PFLOW_JETS_KEY = "Reco10PFlowJets"
-RECO_VR_TRACK_JETS_KEY = "RecoVRTrackJets"
 TRUTH_4_JETS_KEY = "Truth4Jets"
 TRUTH_10_JETS_KEY = "Truth10Jets"
 MUONS_KEY = "Muons"
@@ -14,7 +13,6 @@ container_map = {
     "DAOD_PHYS": {
         RECO_4_PFLOW_JETS_KEY: "AntiKt4EMPFlowJets",
         RECO_10_PFLOW_JETS_KEY: "AntiKt10LCTopoTrimmedPtFrac5SmallR20Jets",
-        RECO_VR_TRACK_JETS_KEY: "AntiKtVR30Rmax4Rmin02PV0TrackJets",
         TRUTH_4_JETS_KEY: "AntiKt4TruthDressedWZJets",
         TRUTH_10_JETS_KEY: "AntiKt10TruthTrimmedPtFrac5SmallR20Jets",
         MUONS_KEY: "Muons",
@@ -24,7 +22,6 @@ container_map = {
     "DAOD_PHYSLITE": {
         RECO_4_PFLOW_JETS_KEY: "AnalysisJets",
         RECO_10_PFLOW_JETS_KEY: "?",
-        RECO_VR_TRACK_JETS_KEY: "?",
         TRUTH_4_JETS_KEY: "AntiKt4TruthDressedWZJets",
         TRUTH_10_JETS_KEY: "?",
         MUONS_KEY: "AnalysisMuons",
-- 
GitLab


From e197017d6e30b7660c0cae7361ec9ccc7526e91a Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 11 Aug 2022 13:40:34 +0200
Subject: [PATCH 13/33] adapt to new master

---
 HH4bAnalysis/python/Algs/Electrons.py         |  38 ++++
 HH4bAnalysis/python/Algs/Event.py             |  83 ++++++++
 HH4bAnalysis/python/Algs/Jets.py              | 162 ++++++++++++++++
 HH4bAnalysis/python/Algs/Muons.py             |  29 +++
 HH4bAnalysis/python/Algs/Photons.py           |  33 ++++
 HH4bAnalysis/python/Algs/Postprocessing.py    |  48 +++++
 HH4bAnalysis/python/Algs/Tree.py              |  23 +++
 HH4bAnalysis/python/Algs/__init__.py          |   0
 HH4bAnalysis/python/Config/Base.py            | 100 ++++++++++
 HH4bAnalysis/python/Config/TriggerLists.py    |  45 +++++
 HH4bAnalysis/python/Config/__init__.py        |   0
 .../python/Config/xAODEventSelectorConfig.py  | 114 +++++++++++
 HH4bAnalysis/python/__init__.py               |   0
 HH4bAnalysis/python/utils/__init__.py         |   0
 HH4bAnalysis/python/utils/argsHelper.py       |  25 +++
 .../python/utils/containerNameHelper.py       |  37 ++++
 HH4bAnalysis/share/VariableDumperConfig.py    |  23 +--
 HH4bAnalysis/share/grid_submit.py             | 182 ++++++++++++++++++
 HH4bAnalysis/share/hh4b-test                  | 117 +++++++++++
 19 files changed, 1048 insertions(+), 11 deletions(-)
 create mode 100644 HH4bAnalysis/python/Algs/Electrons.py
 create mode 100644 HH4bAnalysis/python/Algs/Event.py
 create mode 100644 HH4bAnalysis/python/Algs/Jets.py
 create mode 100644 HH4bAnalysis/python/Algs/Muons.py
 create mode 100644 HH4bAnalysis/python/Algs/Photons.py
 create mode 100644 HH4bAnalysis/python/Algs/Postprocessing.py
 create mode 100644 HH4bAnalysis/python/Algs/Tree.py
 create mode 100644 HH4bAnalysis/python/Algs/__init__.py
 create mode 100644 HH4bAnalysis/python/Config/Base.py
 create mode 100644 HH4bAnalysis/python/Config/TriggerLists.py
 create mode 100644 HH4bAnalysis/python/Config/__init__.py
 create mode 100644 HH4bAnalysis/python/Config/xAODEventSelectorConfig.py
 create mode 100644 HH4bAnalysis/python/__init__.py
 create mode 100644 HH4bAnalysis/python/utils/__init__.py
 create mode 100644 HH4bAnalysis/python/utils/argsHelper.py
 create mode 100644 HH4bAnalysis/python/utils/containerNameHelper.py
 create mode 100755 HH4bAnalysis/share/grid_submit.py
 create mode 100755 HH4bAnalysis/share/hh4b-test

diff --git a/HH4bAnalysis/python/Algs/Electrons.py b/HH4bAnalysis/python/Algs/Electrons.py
new file mode 100644
index 000000000..473f7b119
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/Electrons.py
@@ -0,0 +1,38 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+# Include, and then set up the electron analysis sequence:
+from EgammaAnalysisAlgorithms.ElectronAnalysisSequence import (
+    makeElectronAnalysisSequence,
+)
+
+
+def ElectronAnalysisSequenceCfg(
+    flags, dataType, inputContainerName, outputContainerName
+):
+    cfg = ComponentAccumulator()
+
+    # with ConfigurableRun3Behavior(False):
+    electronSequence = makeElectronAnalysisSequence(
+        dataType,
+        workingPoint="LooseLHElectron.NonIso",
+        postfix="loose",
+        deepCopyOutput=False,
+        shallowViewOutput=True,
+        recomputeLikelihood=False,
+        chargeIDSelection=False,
+        isolationCorrection=False,
+        crackVeto=False,
+        ptSelectionOutput=False,
+        enableCutflow=False,
+        enableKinematicHistograms=False,
+    )
+    electronSequence.configure(
+        inputName=inputContainerName, outputName=outputContainerName
+    )
+
+    cfg.addSequence(CompFactory.AthSequencer(electronSequence.getName()))
+    for alg in electronSequence.getGaudiConfig2Components():
+        cfg.addEventAlgo(alg, electronSequence.getName())
+
+    return cfg
diff --git a/HH4bAnalysis/python/Algs/Event.py b/HH4bAnalysis/python/Algs/Event.py
new file mode 100644
index 000000000..282c73892
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/Event.py
@@ -0,0 +1,83 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def EventSelectionAnalysisSequenceCfg(flags, dataType, grlFiles=[], loose=False):
+    cfg = ComponentAccumulator()
+    from AsgAnalysisAlgorithms.EventSelectionAnalysisSequence import (
+        makeEventSelectionAnalysisSequence,
+    )
+
+    eventSelectionSequence = makeEventSelectionAnalysisSequence(
+        dataType, userGRLFiles=grlFiles, runEventCleaning=True
+    )
+
+    cfg.addSequence(CompFactory.AthSequencer(eventSelectionSequence.getName()))
+    for alg in eventSelectionSequence.getGaudiConfig2Components():
+        if "PrimaryVertexSelectorAlg" in alg.getName():
+            alg.MinTracks = 2
+        if "EventFlagSelectorAlg" in alg.getName():
+            selectionFlags = ["DFCommonJets_eventClean_LooseBad"]
+            selectionFlags += ["DFCommonJets_isBadBatman"] if not loose else []
+            alg.FilterDescription = (
+                f"selecting events passing {', '.join(selectionFlags)}"
+            )
+            alg.selectionFlags = [f"{flag},as_char" for flag in selectionFlags]
+
+        cfg.addEventAlgo(alg, eventSelectionSequence.getName())
+
+    return cfg
+
+
+def TriggerAnalysisSequenceCfg(flags, dataType, triggerChains):
+    cfg = ComponentAccumulator()
+    from TriggerAnalysisAlgorithms.TriggerAnalysisSequence import (
+        makeTriggerAnalysisSequence,
+    )
+
+    triggerSequence = makeTriggerAnalysisSequence(dataType, triggerChains=triggerChains)
+
+    cfg.addSequence(CompFactory.AthSequencer(triggerSequence.getName()))
+    for alg in triggerSequence.getGaudiConfig2Components():
+        cfg.addEventAlgo(alg, triggerSequence.getName())
+
+    return cfg
+
+
+def PileupAnalysisSequenceCfg(flags, dataType, prwFiles, lumicalcFiles):
+    cfg = ComponentAccumulator()
+    from AsgAnalysisAlgorithms.PileupAnalysisSequence import makePileupAnalysisSequence
+
+    pileupSequence = makePileupAnalysisSequence(
+        dataType,
+        userPileupConfigs=prwFiles,
+        userLumicalcFiles=lumicalcFiles,
+        autoConfig=False,
+    )
+    pileupSequence.configure(inputName={}, outputName={})
+
+    cfg.addSequence(CompFactory.AthSequencer(pileupSequence.getName()))
+    for alg in pileupSequence.getGaudiConfig2Components():
+        cfg.addEventAlgo(alg, pileupSequence.getName())
+
+    return cfg
+
+
+def GeneratorAnalysisSequenceCfg(flags, dataType, runNumber):
+    cfg = ComponentAccumulator()
+    from AsgAnalysisAlgorithms.GeneratorAnalysisSequence import (
+        makeGeneratorAnalysisSequence,
+    )
+
+    generatorSequence = makeGeneratorAnalysisSequence(
+        dataType,
+        saveCutBookkeepers=True,
+        runNumber=runNumber,
+        cutBookkeepersSystematics=True,
+    )
+
+    cfg.addSequence(CompFactory.AthSequencer(generatorSequence.getName()))
+    for alg in generatorSequence.getGaudiConfig2Components():
+        cfg.addEventAlgo(alg, generatorSequence.getName())
+
+    return cfg
diff --git a/HH4bAnalysis/python/Algs/Jets.py b/HH4bAnalysis/python/Algs/Jets.py
new file mode 100644
index 000000000..be56fec30
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/Jets.py
@@ -0,0 +1,162 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
+from FTagAnalysisAlgorithms.FTagAnalysisSequence import makeFTagAnalysisSequence
+
+
+def JetAnalysisSequenceCfg(
+    flags,
+    dataType,
+    inputContainerName,
+    outputContainerName,
+    workingPoints,
+    is_daod_physlite,
+):
+    cfg = ComponentAccumulator()
+    jetSequence = makeJetAnalysisSequence(
+        dataType,
+        jetCollection=inputContainerName,
+        postfix="smallR",
+        deepCopyOutput=False,
+        shallowViewOutput=True,
+        runGhostMuonAssociation=not is_daod_physlite,
+        enableCutflow=False,
+        enableKinematicHistograms=False,
+        runJvtUpdate=False,
+        runJvtSelection=True,
+    )
+
+    bTagCalibFile = (
+        "xAODBTaggingEfficiency/13TeV/2022-22-13TeV-MC20-CDI-2022-07-28_v1.root"
+    )
+    # This is the container name that is available in the CDI aboce
+    jetBTagContaienrName = "AntiKt4EMPFlowJets"
+
+    for tagger_wp in workingPoints:
+        tagger, btag_wp = tagger_wp.split("_", 1)
+        makeFTagAnalysisSequence(
+            jetSequence,
+            dataType,
+            jetCollection=jetBTagContaienrName,
+            btagWP=btag_wp,
+            btagger=tagger,
+            generator="Pythia8",
+            minPt=20000,
+            postfix="",
+            preselection=None,
+            kinematicSelection=False,
+            noEfficiency=False,
+            legacyRecommendations=False,
+            enableCutflow=False,
+        )
+
+    jetSequence.configure(
+        inputName=inputContainerName,
+        outputName=outputContainerName,
+    )
+
+    cfg.addSequence(CompFactory.AthSequencer(jetSequence.getName()))
+    # Hack until this is merged:
+    # https://gitlab.cern.ch/atlas/athena/-/merge_requests/54939]
+    for alg in jetSequence.getGaudiConfig2Components():
+        if "FTagSelectionAlg" in alg.getName():
+            alg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile
+        if "FTagEfficiencyScaleFactorAlg" in alg.getName():
+            alg.efficiencyTool.ScaleFactorFileName = bTagCalibFile
+
+        cfg.addEventAlgo(alg, jetSequence.getName())
+
+    return cfg
+
+
+def FatJetAnalysisSequenceCfg(flags, dataType, inputContainerName, outputContainerName):
+    cfg = ComponentAccumulator()
+    # with ConfigurableRun3Behavior(False):
+    largeRrecojetSequence = makeJetAnalysisSequence(
+        dataType,
+        jetCollection=inputContainerName,
+        postfix="largeR",
+        deepCopyOutput=False,
+        shallowViewOutput=True,
+        runGhostMuonAssociation=False,
+        enableCutflow=False,
+        enableKinematicHistograms=False,
+        largeRMass="Comb",
+    )
+
+    largeRrecojetSequence.configure(
+        inputName=inputContainerName, outputName=outputContainerName
+    )
+
+    cfg.addSequence(CompFactory.AthSequencer(largeRrecojetSequence.getName()))
+    for alg in largeRrecojetSequence.getGaudiConfig2Components():
+        cfg.addEventAlgo(alg, largeRrecojetSequence.getName())
+
+    return cfg
+
+
+def VRJetAnalysisSequenceCfg(
+    flags, dataType, inputContainerName, outputContainerName, workingPoints
+):
+    cfg = ComponentAccumulator()
+
+    def createVRJetSequence():
+        from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence
+        from AnaAlgorithm.DualUseConfig import createAlgorithm
+
+        postfix = "VR"
+        seq = AnaAlgSequence("JetAnalysisSequence" + postfix)
+        # Set up an algorithm that makes a view container
+        alg = createAlgorithm(
+            "CP::AsgViewFromSelectionAlg", "VRJetSelectionAlg" + postfix
+        )
+        seq.append(
+            alg,
+            inputPropName="input",
+            outputPropName="output",
+            stageName="selection",
+            dynConfig={},
+        )
+        return seq
+
+    vrJetSequence = createVRJetSequence()
+
+    bTagCalibFile = (
+        "xAODBTaggingEfficiency/13TeV/2021-22-13TeV-MC16-CDI-2021-12-02_v2.root"
+    )
+    # This is the container name that is available in the CDI aboce
+    vrJetBTagContaienrName = "AntiKtVR30Rmax4Rmin02TrackJets"
+    for tagger_wp in workingPoints:
+        tagger, btag_wp = tagger_wp.split("_", 1)
+        makeFTagAnalysisSequence(
+            vrJetSequence,
+            dataType,
+            jetCollection=vrJetBTagContaienrName,
+            btagWP=btag_wp,
+            btagger=tagger,
+            generator="Pythia8",
+            minPt=10e3,
+            postfix="",
+            preselection=None,
+            noEfficiency=False,
+            legacyRecommendations=False,
+            enableCutflow=False,
+        )
+
+    vrJetSequence.configure(
+        inputName=inputContainerName,
+        outputName=outputContainerName,
+    )
+
+    cfg.addSequence(CompFactory.AthSequencer(vrJetSequence.getName()))
+    # Hack until this is merged:
+    # https://gitlab.cern.ch/atlas/athena/-/merge_requests/54939]
+    for alg in vrJetSequence.getGaudiConfig2Components():
+        if "FTagSelectionAlg" in alg.getName():
+            alg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile
+        if "FTagEfficiencyScaleFactorAlg" in alg.getName():
+            alg.efficiencyTool.ScaleFactorFileName = bTagCalibFile
+
+        cfg.addEventAlgo(alg, vrJetSequence.getName())
+
+    return cfg
diff --git a/HH4bAnalysis/python/Algs/Muons.py b/HH4bAnalysis/python/Algs/Muons.py
new file mode 100644
index 000000000..c9c4c85f3
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/Muons.py
@@ -0,0 +1,29 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def MuonAnalysisSequenceCfg(flags, dataType, inputContainerName, outputContainerName):
+    cfg = ComponentAccumulator()
+    from MuonAnalysisAlgorithms.MuonAnalysisSequence import makeMuonAnalysisSequence
+
+    muonSequence = makeMuonAnalysisSequence(
+        dataType,
+        workingPoint="Loose.NonIso",
+        postfix="loose",
+        deepCopyOutput=False,
+        shallowViewOutput=True,
+        ptSelectionOutput=False,
+        qualitySelectionOutput=True,
+        enableCutflow=False,
+        enableKinematicHistograms=False,
+    )
+    muonSequence.configure(inputName=inputContainerName, outputName=outputContainerName)
+    # print(muonSequence)  # For debugging
+
+    cfg.addSequence(CompFactory.AthSequencer(muonSequence.getName()))
+    for alg in muonSequence.getGaudiConfig2Components():
+        if "MuonSelectionAlg" in alg.getName():
+            alg.selectionTool.IsRun3Geo = min(flags.Input.RunNumber) > 400000
+        cfg.addEventAlgo(alg, muonSequence.getName())
+
+    return cfg
diff --git a/HH4bAnalysis/python/Algs/Photons.py b/HH4bAnalysis/python/Algs/Photons.py
new file mode 100644
index 000000000..fae5c91a6
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/Photons.py
@@ -0,0 +1,33 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def PhotonAnalysisSequenceCfg(flags, dataType, inputContainerName, outputContainerName):
+    cfg = ComponentAccumulator()
+    from EgammaAnalysisAlgorithms.PhotonAnalysisSequence import (
+        makePhotonAnalysisSequence,
+    )
+
+    photonSequence = makePhotonAnalysisSequence(
+        dataType,
+        workingPoint="Loose.Undefined",
+        postfix="loose",
+        deepCopyOutput=False,
+        shallowViewOutput=True,
+        crackVeto=False,
+        enableCleaning=True,
+        cleaningAllowLate=False,
+        recomputeIsEM=False,
+        ptSelectionOutput=False,
+        enableCutflow=False,
+        enableKinematicHistograms=False,
+    )
+    photonSequence.configure(
+        inputName=inputContainerName, outputName=outputContainerName
+    )
+
+    cfg.addSequence(CompFactory.AthSequencer(photonSequence.getName()))
+    for alg in photonSequence.getGaudiConfig2Components():
+        cfg.addEventAlgo(alg, photonSequence.getName())
+
+    return cfg
diff --git a/HH4bAnalysis/python/Algs/Postprocessing.py b/HH4bAnalysis/python/Algs/Postprocessing.py
new file mode 100644
index 000000000..b32f369bf
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/Postprocessing.py
@@ -0,0 +1,48 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def OverlapAnalysisSequenceCfg(
+    flags,
+    dataType,
+    inputNames,
+    outputNames,
+    doFatJets=True,
+    doMuons=True,
+):
+    cfg = ComponentAccumulator()
+    from AsgAnalysisAlgorithms.OverlapAnalysisSequence import (
+        makeOverlapAnalysisSequence,
+    )
+
+    overlapSequence = makeOverlapAnalysisSequence(
+        dataType,
+        inputLabel="",
+        outputLabel="passesOR",
+        linkOverlapObjects=False,
+        doEleEleOR=False,
+        doMuPFJetOR=False,
+        doTaus=False,
+        doElectrons=True,
+        doMuons=doMuons,
+        doJets=True,
+        doPhotons=True,
+        doFatJets=doFatJets,
+        enableUserPriority=False,
+        bJetLabel="",
+        boostedLeptons=False,
+        postfix="",
+        shallowViewOutput=True,
+        enableCutflow=False,
+    )
+    overlapSequence.configure(
+        inputName=inputNames,
+        outputName=outputNames,
+    )
+    # print(overlapSequence)  # For debugging
+
+    cfg.addSequence(CompFactory.AthSequencer(overlapSequence.getName()))
+    for alg in overlapSequence.getGaudiConfig2Components():
+        cfg.addEventAlgo(alg, overlapSequence.getName())
+
+    return cfg
diff --git a/HH4bAnalysis/python/Algs/Tree.py b/HH4bAnalysis/python/Algs/Tree.py
new file mode 100644
index 000000000..611e4fd83
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/Tree.py
@@ -0,0 +1,23 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def AnalysisTreeAlgCfg(flags, branches):
+    cfg = ComponentAccumulator()
+    # Create analysis mini-ntuple
+    treeMaker = CompFactory.getComp("CP::TreeMakerAlg")("TreeMaker")
+    treeMaker.TreeName = "AnalysisMiniTree"
+    cfg.addEventAlgo(treeMaker)
+
+    # Add branches
+    ntupleMaker = CompFactory.getComp("CP::AsgxAODNTupleMakerAlg")("NTupleMaker")
+    ntupleMaker.TreeName = "AnalysisMiniTree"
+    ntupleMaker.Branches = branches
+    cfg.addEventAlgo(ntupleMaker)
+
+    # Fill tree
+    treeFiller = CompFactory.getComp("CP::TreeFillerAlg")("TreeFiller")
+    treeFiller.TreeName = "AnalysisMiniTree"
+    cfg.addEventAlgo(treeFiller)
+
+    return cfg
diff --git a/HH4bAnalysis/python/Algs/__init__.py b/HH4bAnalysis/python/Algs/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/HH4bAnalysis/python/Config/Base.py b/HH4bAnalysis/python/Config/Base.py
new file mode 100644
index 000000000..55b41d28d
--- /dev/null
+++ b/HH4bAnalysis/python/Config/Base.py
@@ -0,0 +1,100 @@
+from enum import Enum
+import json
+
+
+class SampleTypes(Enum):
+    mc20a = "r13167"
+    mc20d = "r13144"
+    mc20e = "r13145"
+
+
+def cache_metadata(path):
+    from AthenaConfiguration.AutoConfigFlags import _fileMetaData
+
+    all_md = {}
+    for f, m in _fileMetaData.items():
+        all_md[f] = {
+            "metadata": m.metadata,
+            "level": m.metAccessLevel,
+        }
+    with open(path, "w") as cached:
+        json.dump(all_md, cached)
+
+
+def update_metadata(path):
+    from AthenaConfiguration.AutoConfigFlags import _fileMetaData
+
+    if not path.exists():
+        return
+    with open(path) as cached_file:
+        all_cached = json.load(cached_file)
+    for f, m in _fileMetaData.items():
+        cached = all_cached.get(f)
+        if cached:
+            md = _fileMetaData[f]
+            md.metadata.update(cached["metadata"])
+            md.filename = f
+            md.metAccessLevel = cached["level"]
+
+
+def pileupConfigFiles(fileMD):
+    """Return the PRW (Pileup ReWeighting) config files and lumicalc files"""
+    tags = fileMD["AMITag"]
+    dsid = fileMD["mc_channel_number"]
+    split_tags = tags.split("_")
+    # Figure out which MC we are using
+    if SampleTypes.mc20a.value in split_tags:
+        subcampaign = SampleTypes.mc20a
+    elif SampleTypes.mc20d.value in split_tags:
+        subcampaign = SampleTypes.mc20d
+    elif SampleTypes.mc20e.value in split_tags:
+        subcampaign = SampleTypes.mc20e
+    else:
+        raise LookupError(f"Cannot determine subcampaign for DSID {dsid}")
+
+    lumicalc_files = getLumicalcFiles(subcampaign)
+    prw_files = getPrwFiles(dsid, subcampaign, tags)
+
+    return prw_files, lumicalc_files
+
+
+def getLumicalcFiles(subcampaign):
+    list = []
+    if subcampaign == SampleTypes.mc20a:
+        list.extend(
+            (
+                "GoodRunsLists/data15_13TeV/20170619/PHYS_StandardGRL_All_Good_25ns_276262-284484_OflLumi-13TeV-008.root",  # noqa
+                "GoodRunsLists/data16_13TeV/20180129/PHYS_StandardGRL_All_Good_25ns_297730-311481_OflLumi-13TeV-009.root",  # noqa
+            )
+        )
+    if subcampaign == SampleTypes.mc20d:
+        list.append(
+            "GoodRunsLists/data17_13TeV/20180619/physics_25ns_Triggerno17e33prim.lumicalc.OflLumi-13TeV-010.root",  # noqa
+        )
+    if subcampaign == SampleTypes.mc20e:
+        list.append(
+            "GoodRunsLists/data18_13TeV/20190318/ilumicalc_histograms_None_348885-364292_OflLumi-13TeV-010.root"  # noqa
+        )
+
+    return list
+
+
+def getPrwFiles(dsid, subcampaign, tags):
+    actual_mu = []
+    prw_files = []
+    if subcampaign == SampleTypes.mc20d:
+        actual_mu.append(
+            "GoodRunsLists/data17_13TeV/20180619/physics_25ns_Triggerno17e33prim.actualMu.OflLumi-13TeV-010.root"  # noqa
+        )
+    if subcampaign == SampleTypes.mc20e:
+        actual_mu.append(
+            "GoodRunsLists/data18_13TeV/20190318/physics_25ns_Triggerno17e33prim.actualMu.OflLumi-13TeV-010.root"  # noqa
+        )
+
+    if dsid:
+        dsid_as_str = str(dsid)
+        prw_files.append(
+            f"dev/PileupReweighting/share/DSID{dsid_as_str[:3]}xxx/pileup_{subcampaign.name}_dsid{dsid_as_str}_{'AFII' if 'a' in tags else 'FS'}.root"  # noqa
+        )
+
+    return prw_files + actual_mu
diff --git a/HH4bAnalysis/python/Config/TriggerLists.py b/HH4bAnalysis/python/Config/TriggerLists.py
new file mode 100644
index 000000000..38d2fa279
--- /dev/null
+++ b/HH4bAnalysis/python/Config/TriggerLists.py
@@ -0,0 +1,45 @@
+TriggerLists = {
+    "Run3": [
+        "HLT_j80c_020jvt_j55c_020jvt_j28c_020jvt_j20c_020jvt_SHARED_3j20c_020jvt_bdl1d82_pf_ftf_presel2c20XX2c20b85_L1J45p0ETA21_3J15p0ETA25",  # noqa
+        "HLT_j80c_020jvt_j55c_020jvt_j28c_020jvt_j20c_020jvt_SHARED_3j20c_020jvt_bdl1r85_pf_ftf_presel2c20XX2c20b85_L1J45p0ETA21_3J15p0ETA25",  # noqa
+        "HLT_j80c_020jvt_j55c_020jvt_j28c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bdl1d77_pf_ftf_presel2c20XX2c20b85_L1J45p0ETA21_3J15p0ETA25",  # noqa
+        "HLT_j80c_020jvt_j55c_020jvt_j28c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bdl1r77_pf_ftf_presel2c20XX2c20b85_L1J45p0ETA21_3J15p0ETA25",  # noqa
+        "HLT_j80c_020jvt_j55c_020jvt_j28c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bdl1d77_pf_ftf_presel2c20XX2c20b85_L1MU8F_2J15_J20",  # noqa
+        "HLT_j80c_020jvt_j55c_020jvt_j28c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bdl1r77_pf_ftf_presel2c20XX2c20b85_L1MU8F_2J15_J20",  # noqa
+        "HLT_2j35c_020jvt_bdl1d60_2j35c_020jvt_pf_ftf_presel2j25XX2j25b85_L14J15p0ETA25",  # noqa
+        "HLT_2j35c_020jvt_bdl1r60_2j35c_020jvt_pf_ftf_presel2j25XX2j25b85_L14J15p0ETA25",  # noqa
+        "HLT_j150_2j55_0eta290_020jvt_bdl1d70_pf_ftf_preselj80XX2j45b90_L1J85_3J30",  # noqa
+        "HLT_j150_2j55_0eta290_020jvt_bdl1r70_pf_ftf_preselj80XX2j45b90_L1J85_3J30",  # noqa
+    ],
+    "Run2": [
+        # 2015 (not used in the resolved analysis):
+        "HLT_2j35_btight_2j35_L13J25.0ETA23",
+        "HLT_j100_2j55_bmedium",
+        "HLT_j225_bloose",
+        "HLT_j360_a10_lcw_sub_L1J100",
+        # 2016:
+        "HLT_j175_bmv2c2040_split",
+        "HLT_j225_bmv2c2060_split",
+        "HLT_2j35_bmv2c2060_split_2j35_L14J15.0ETA25",
+        "HLT_2j55_bmv2c2060_split_ht300_L14J15",
+        "HLT_j100_2j55_bmv2c2060_split",
+        "HLT_j150_bmv2c2060_split_j50_bmv2c2060_split",
+        "HLT_j420_a10_lcw_L1J100",
+        # 2017:
+        "HLT_j175_gsc225_bmv2c1040_split",  # also 2018
+        "HLT_j225_gsc275_bmv2c1060_split",
+        "HLT_j150_gsc175_bmv2c1060_split_j45_gsc60_bmv2c1060_split",  # and 2018
+        "HLT_j110_gsc150_boffperf_split_2j35_gsc55_bmv2c1070_split_L1J85_3J30",
+        "HLT_2j15_gsc35_bmv2c1040_split_2j15_gsc35_boffperf_split_L14J15.0ETA25",
+        "HLT_2j35_gsc55_bmv2c1050_split_ht300_L1HT190-J15s5.ETA21",
+        "HLT_2j35_gsc55_bmv2c1060_split_ht300_L1HT190-J15s5.ETA21",  # (below 1.5e34)
+        "HLT_j420_a10t_lcw_jes_40smcINF_L1J100",
+        "HLT_j390_a10t_lcw_jes_30smcINF_L1J100",  # also 2018
+        # 2018:
+        "HLT_j225_gsc275_bhmv2c1060_split",
+        "HLT_j110_gsc150_boffperf_split_2j45_gsc55_bmv2c1070_split_L1J85_3J30",
+        "HLT_2j35_bmv2c1060_split_2j35_L14J15.0ETA25",
+        "HLT_2j45_gsc55_bmv2c1050_split_ht300_L1HT190-J15s5.ETA21",
+        "HLT_j420_a10t_lcw_jes_35smcINF_L1J100",
+    ],
+}
diff --git a/HH4bAnalysis/python/Config/__init__.py b/HH4bAnalysis/python/Config/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/HH4bAnalysis/python/Config/xAODEventSelectorConfig.py b/HH4bAnalysis/python/Config/xAODEventSelectorConfig.py
new file mode 100644
index 000000000..3822828a4
--- /dev/null
+++ b/HH4bAnalysis/python/Config/xAODEventSelectorConfig.py
@@ -0,0 +1,114 @@
+# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+
+# @file xAODHybridSelectorConfig
+# @purpose make the Athena framework read a set of xAOD files to emulate the
+#          usual TEvent event loop ... BUT READ METADATA WITH POOL!
+#          Converted from ReadAthenaxAODHybrid.py
+# @author Teng Jian Khoo
+#
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from AthenaCommon import Logging
+from AthenaCommon import Constants
+
+# suppress the event loop heartbeat as it is somewhat I/O hungry for
+# no real gain in n-tuple reading/writing scenarii
+# if not hasattr(svcMgr, theApp.EventLoop):
+#     svcMgr += getattr(CfgMgr, theApp.EventLoop)()
+# evtloop = getattr(svcMgr, theApp.EventLoop)
+# try:
+#     evtloop.EventPrintoutInterval = 10000
+# except Exception:
+#     msg.info('disabling event loop heartbeat... [failed]')
+#     msg.info('performances might be sub-par... sorry.')
+#     pass
+
+from enum import IntEnum
+
+
+# Duplicate here because it's probably more efficient than importing from ROOT
+class xAODAccessMode(IntEnum):
+    BRANCH_ACCESS = 0
+    CLASS_ACCESS = 1
+    ATHENA_ACCESS = 2
+
+
+# Default to the most efficient access method
+def xAODReadCfg(configFlags, AccessMode=xAODAccessMode.CLASS_ACCESS):
+    """
+    Creates a ComponentAccumulator instance containing the
+    athena services required for xAOD file reading
+    """
+
+    msg = Logging.logging.getLogger("ReadAthenaxAODHybrid")
+    msg.debug(
+        "Configuring Athena for reading xAOD files"
+        + " (via TEvent, with POOL for Metadata)..."
+    )
+
+    result = ComponentAccumulator()
+
+    result.addService(
+        CompFactory.EvtPersistencySvc(
+            "EventPersistencySvc",
+        )
+    )
+    result.addService(
+        CompFactory.MetaDataSvc("MetaDataSvc", MetaDataContainer="MetaDataHdr")
+    )
+    result.addService(CompFactory.StoreGateSvc("MetaDataStore"))
+    # Suppress some uninformative messages
+    result.addService(CompFactory.PoolSvc("PoolSvc", OutputLevel=Constants.WARNING))
+
+    # result.addService(CompFactory.THistSvc())
+    result.addService(CompFactory.Athena.xAODCnvSvc())
+    result.addService(
+        CompFactory.ProxyProviderSvc("ProxyProviderSvc", ProviderNames=["MetaDataSvc"])
+    )
+    result.addService(
+        CompFactory.Athena.xAODEventSelector(
+            "EventSelector",
+            InputCollections=configFlags.Input.Files,
+            SkipEvents=configFlags.Exec.SkipEvents,
+            AccessMode=AccessMode,
+            ReadMetaDataWithPool=True,
+        )
+    )
+    evSel = result.getService("EventSelector")
+
+    result.setAppProperty("EvtSel", evSel.getFullJobOptName())
+
+    msg.debug(
+        "Configuring Athena for reading ROOT files"
+        + " (via TEvent, with POOL for Metadata)... [OK]"
+    )
+
+    return result
+
+
+if __name__ == "__main__":
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+    import os
+
+    asg_test_file_mc = os.environ["ASG_TEST_FILE_MC"]
+    ConfigFlags.Input.Files = [asg_test_file_mc]
+
+    import sys
+
+    if len(sys.argv) > 1:
+        ConfigFlags.Input.Files = [sys.argv[1]]
+    ConfigFlags.lock()
+
+    AccessMode = xAODAccessMode.CLASS_ACCESS
+    if len(sys.argv) > 2:
+        AccessMode = xAODAccessMode(int(sys.argv[2]))
+
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+    from AthenaCommon.Configurable import ConfigurableRun3Behavior
+
+    with ConfigurableRun3Behavior():
+        cfg = MainServicesCfg(ConfigFlags)
+        cfg.merge(xAODReadCfg(ConfigFlags, AccessMode))
+
+    cfg.run(10)
diff --git a/HH4bAnalysis/python/__init__.py b/HH4bAnalysis/python/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/HH4bAnalysis/python/utils/__init__.py b/HH4bAnalysis/python/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/HH4bAnalysis/python/utils/argsHelper.py b/HH4bAnalysis/python/utils/argsHelper.py
new file mode 100644
index 000000000..a93eb3ef9
--- /dev/null
+++ b/HH4bAnalysis/python/utils/argsHelper.py
@@ -0,0 +1,25 @@
+import sys
+
+
+def checkArgs(flags, args, parser):
+    if "StreamDAOD_PHYSLITE" in flags.Input.ProcessingTags:
+        input_stream_format = "DAOD_PHYSLITE"
+    elif "StreamDAOD_PHYS" in flags.Input.ProcessingTags:
+        input_stream_format = "DAOD_PHYS"
+    else:
+        input_stream_format = "other"
+
+    if args.daod_physlite and input_stream_format != "DAOD_PHYSLITE":
+        print(
+            f"Input file is {input_stream_format} but --daod-physlite flag was "
+            f"{'given' if args.daod_physlite else 'not given'}. Usage: {parser.prog} -h"
+        )
+        sys.exit(-1)
+
+    is_input_mc = flags.Input.isMC
+    if args.mc is not is_input_mc:
+        print(
+            f"Input file is {'MC' if is_input_mc else 'Data'} but --mc flag was "
+            f"{'given' if args.mc else 'not given'}. Usage: {parser.prog} -h"
+        )
+        sys.exit(-1)
diff --git a/HH4bAnalysis/python/utils/containerNameHelper.py b/HH4bAnalysis/python/utils/containerNameHelper.py
new file mode 100644
index 000000000..08f2cc10a
--- /dev/null
+++ b/HH4bAnalysis/python/utils/containerNameHelper.py
@@ -0,0 +1,37 @@
+# custom container names used in this framework
+RECO_4_PFLOW_JETS_KEY = "Reco4PFlowJets"
+RECO_10_PFLOW_JETS_KEY = "Reco10PFlowJets"
+VR_JETS_KEY = "VRJets"
+TRUTH_4_JETS_KEY = "Truth4Jets"
+TRUTH_10_JETS_KEY = "Truth10Jets"
+MUONS_KEY = "Muons"
+ELECTRONS_KEY = "Electrons"
+PHOTONS_KEY = "Photons"
+
+container_map = {
+    "DAOD_PHYS": {
+        RECO_4_PFLOW_JETS_KEY: "AntiKt4EMPFlowJets",
+        RECO_10_PFLOW_JETS_KEY: "AntiKt10LCTopoTrimmedPtFrac5SmallR20Jets",
+        VR_JETS_KEY: "AntiKtVR30Rmax4Rmin02PV0TrackJets",
+        TRUTH_4_JETS_KEY: "AntiKt4TruthDressedWZJets",
+        TRUTH_10_JETS_KEY: "AntiKt10TruthTrimmedPtFrac5SmallR20Jets",
+        MUONS_KEY: "Muons",
+        ELECTRONS_KEY: "Electrons",
+        PHOTONS_KEY: "Photons",
+    },
+    "DAOD_PHYSLITE": {
+        RECO_4_PFLOW_JETS_KEY: "AnalysisJets",
+        RECO_10_PFLOW_JETS_KEY: "",
+        VR_JETS_KEY: "",
+        TRUTH_4_JETS_KEY: "AntiKt4TruthDressedWZJets",
+        TRUTH_10_JETS_KEY: "",
+        MUONS_KEY: "AnalysisMuons",
+        ELECTRONS_KEY: "AnalysisElectrons",
+        PHOTONS_KEY: "AnalysisPhotons",
+    },
+}
+
+
+def getContainerName(qualitycontainerdesc, daodphyslite=False):
+    format_key = "DAOD_PHYSLITE" if daodphyslite else "DAOD_PHYS"
+    return container_map[format_key][qualitycontainerdesc]
diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 41fc6ee40..4e1f81263 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -13,26 +13,26 @@ import sys
 from pathlib import Path
 
 from AthenaCommon import Logging
-from AthenaConfiguration.AutoConfigFlags import GetFileMD
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
-from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
+from AthenaConfiguration.AutoConfigFlags import GetFileMD
+from HH4bAnalysis.Config.Base import pileupConfigFiles, cache_metadata, update_metadata
 from HH4bAnalysis.Algs.Event import (
-    EventSelectionAnalysisSequenceCfg,
     GeneratorAnalysisSequenceCfg,
-    PileupAnalysisSequenceCfg,
     TriggerAnalysisSequenceCfg,
+    PileupAnalysisSequenceCfg,
+    EventSelectionAnalysisSequenceCfg,
 )
+from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Photons import PhotonAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Muons import MuonAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Jets import (
-    FatJetAnalysisSequenceCfg,
     JetAnalysisSequenceCfg,
+    FatJetAnalysisSequenceCfg,
     VRJetAnalysisSequenceCfg,
 )
-from HH4bAnalysis.Algs.Muons import MuonAnalysisSequenceCfg
-from HH4bAnalysis.Algs.Photons import PhotonAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Postprocessing import OverlapAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Tree import AnalysisTreeAlgCfg
-from HH4bAnalysis.Config.Base import cache_metadata, pileupConfigFiles, update_metadata
 from HH4bAnalysis.utils.containerNameHelper import getContainerName
 
 log = Logging.logging.getLogger("VariableDumperConfig")
@@ -177,7 +177,7 @@ def AnalysisAlgsCfg(
 
     doPRW = _is_mc_phys(flags)
     log.info(
-        f"Do PRW is {doPRW}. {'Add' if doPRW else 'Skip'} pileup re-weight sequence"
+        f"Do PRW is {doPRW}. " f"{'Add' if doPRW else 'Skip'} pileup re-weight sequence"
     )
     if doPRW:
         try:
@@ -410,7 +410,7 @@ def MiniTupleCfg(
         )
         analysisTreeBranches += getFourMomBranches(containers["vrJet"], "vrjet")
         analysisTreeBranches += [
-            f"{containers['vrJet']}.ftag_select_{btag_wp} -> vrjet_%SYS%_{btag_wp}"
+            f"{containers['vrJet']}.ftag_select_{btag_wp}" f" -> vrjet_%SYS%_{btag_wp}"
             for btag_wp in working_points["vr"]
         ]
 
@@ -442,10 +442,11 @@ def main():
 
     # Get a ComponentAccumulator setting up the standard components
     # needed to run an Athena job.
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+
     # Setting temporarily needed for Run 3 code, to generate python
     # Configurable objects for deduplication
     from AthenaCommon.Configurable import ConfigurableRun3Behavior
-    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
 
     with ConfigurableRun3Behavior():
 
diff --git a/HH4bAnalysis/share/grid_submit.py b/HH4bAnalysis/share/grid_submit.py
new file mode 100755
index 000000000..00c70736b
--- /dev/null
+++ b/HH4bAnalysis/share/grid_submit.py
@@ -0,0 +1,182 @@
+#!/bin/env python
+
+import os
+import argparse
+import datetime
+import subprocess
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--mc-list", help="Text file containing MC datasets")
+    parser.add_argument("--data-list", help="Text file containing data datasets")
+    parser.add_argument(
+        "--campaign",
+        default="HH4b.%Y_%m_%d",
+        help=(
+            "The name of the campaign. Will be prepended to the output dataset"
+            " name. Can include datetime.strftime replacement fields"
+        ),
+    )
+    parser.add_argument(
+        "--asetup",
+        help="The asetup command, in case it cannot be read from the environment",
+    )
+    # parser.add_argument("--dest-se", default="DESY-ZN_LOCALGROUPDISK",
+    # help="An RSE to duplicate the results to")
+    parser.add_argument("--excluded-site", help="Any sites to exclude when running")
+    parser.add_argument("--nGBperJob", default="2", help="How many GB required per job")
+    # parser.add_argument("--resubmit", action="store_true",
+    # help="Run in 'resubmission' mode. This reads in information
+    # from an existing task and resubmits the dead tasks.
+    # For this mode you don't need the mc and data lists")
+
+    args = parser.parse_args()
+
+    # Prepare some of the prun options here
+    submit_opts = {
+        "mergeOutput": True,
+        "outputs": "TREE:output-hh4b.root",
+        "writeInputToTxt": "IN:in.txt",
+        "useAthenaPackages": True,
+        # "noSubmit": True,  # only creates tarball but doesn't submit
+    }
+
+    # if args.dest-se is not None:
+    # submit_opts["destSE"] = args.dest-se
+    # if args.excluded-site is not None:
+    # submit_opts["excludedSite"] = args.excluded-Site
+    # if args.nGBperJob is not None:
+    # submit_opts["nGBPerJob"] = args.nGBperJob
+
+    if args.asetup is None:
+        atlas_project = os.environ["AtlasProject"]
+
+        project_dir = os.environ["{0}_DIR".format(atlas_project)]
+        project_version = os.environ["{0}_VERSION".format(atlas_project)]
+
+        if project_dir.startswith("/cvmfs/atlas-nightlies.cern.ch"):
+            raise ValueError(
+                "Cannot deduce the asetup command for a nightly!"
+                + " Use the --asetup option"
+            )
+        submit_opts["athenaTag"] = ",".join([atlas_project, project_version])
+    else:
+        submit_opts["athenaTag"] = args.asetup
+
+    nickname = getGridNickname()
+    if not nickname:
+        raise OSError(
+            1,
+            "Could not find proxy information."
+            + ' Try typing "voms-proxy-init -voms atlas" and try again',
+        )
+
+    proc = subprocess.Popen(
+        [
+            "prun",
+            "--outDS",
+            "user.{0}.NONE".format(nickname),
+            "--exec",
+            "NONE",
+            "--noSubmit",
+            "--useAthenaPackages",
+            "--outTarBall",
+            "code.tar.gz",
+        ]
+    )
+
+    if proc.wait() != 0:
+        raise OSError(proc.returncode, "Failed to create tarball")
+
+    submit_opts["inTarBall"] = "code.tar.gz"
+    # submit_opts["allowTaskDuplication"] = True
+
+    campaign = datetime.datetime.now().strftime(args.campaign)
+
+    io_list = []
+    if args.mc_list is not None:
+        with open(args.mc_list) as fp:
+            mc_list = fp.readlines()
+        for line in mc_list:
+            line = line.strip()
+            if line.startswith("*"):
+                continue
+            if not line:
+                continue
+            ds_name = line.rpartition(":")[2]
+            project, dsid, physics_short, prod_step, dtype, tags = ds_name.split(".")
+            io_list.append(
+                {
+                    "inDS": ds_name,
+                    "outDS": "user.{0}.{1}.{2}.{3}.{4}".format(
+                        nickname, campaign, dsid, physics_short, tags
+                    ),
+                }
+            )
+
+    if args.data_list is not None:
+        with open(args.data_list) as fp:
+            data_list = fp.readlines()
+        for line in data_list:
+            line = line.strip()
+            if line.startswith("*"):
+                continue
+            if not line:
+                continue
+            ds_name = line.rpartition(":")[2]
+            split = ds_name.split(".")
+            io_list.append(
+                {
+                    "inDS": ds_name,
+                    "outDS": "user.{0}.{1}.{2}.{3}".format(
+                        nickname, campaign, split[0], split[1]
+                    ),
+                }
+            )
+
+    if not io_list:
+        raise ValueError("No inputs defined")
+
+    for io in io_list:
+        exec_cmd = "VariableDumperConfig.py --filesInput %IN --outFile {0}".format(
+            submit_opts["outputs"].removeprefix("TREE:")
+        )
+        if args.mc_list:
+            exec_cmd = "VariableDumperConfig.py --filesInput %IN --outFile {0}".format(
+                submit_opts["outputs"].removeprefix("TREE:")
+            )
+        cmd = ["prun", "--inDS", io["inDS"], "--outDS", io["outDS"], "--exec", exec_cmd]
+
+        for k, v in submit_opts.items():
+            if isinstance(v, bool):
+                if v:
+                    cmd += ["--{0}".format(k)]
+            else:
+                if isinstance(v, (list, tuple)):
+                    v = ",".join(map(str, v))
+
+                cmd += ["--{0}".format(k), v]
+
+        print(" ".join(cmd))
+        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        out, err = proc.communicate()
+        print(out.decode("utf-8"), err.decode("utf-8"))
+        if proc.returncode != 0:
+            raise OSError(proc.returncode, err)
+
+
+def getGridNickname():
+    try:
+        voms_proxy_info = subprocess.check_output(["voms-proxy-info", "--all"])
+        voms_proxy_info = voms_proxy_info.decode("utf-8")
+        nickname_index = voms_proxy_info.find("nickname")
+        nickname_parts = voms_proxy_info[nickname_index:].split()
+        nickname = nickname_parts[2]
+    except Exception:
+        nickname = ""
+    return nickname
+
+
+if __name__ == "__main__":
+    main()
diff --git a/HH4bAnalysis/share/hh4b-test b/HH4bAnalysis/share/hh4b-test
new file mode 100755
index 000000000..789d18e35
--- /dev/null
+++ b/HH4bAnalysis/share/hh4b-test
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+
+set -Eeu
+
+
+################################################
+# mode-based switches
+################################################
+
+# standard samples
+PHYS_TTBAR=ttbar.410470.PHYS.e6337_s3681_r13167_p5169.pool.root
+declare -A DATAFILES=(
+    [ntuple-fast]=${PHYS_TTBAR}
+    [ntuple]=${PHYS_TTBAR}
+)
+
+declare -A TESTS=(
+    [ntuple-fast]=ntuple-dump-fast
+    [ntuple]=ntuple-dump
+)
+
+ntuple-dump() {
+    VariableDumperConfig.py -o --filesInput $1 --trigger-list "Run2"
+}
+ntuple-dump-fast() {
+    VariableDumperConfig.py -oc --filesInput $1 --trigger-list "Run2"
+}
+
+################################################
+# parse arguments
+################################################
+
+ALL_MODES=${!TESTS[*]}
+
+print-usage() {
+    echo "usage: ${0##*/} [-h] [-d <dir>] (${ALL_MODES[*]// /|})" 1>&2
+}
+
+usage() {
+    print-usage
+    exit 1;
+}
+
+help() {
+    print-usage
+    cat <<EOF
+
+The ${0##*/} utility will download a test DAOD file and run it.
+
+Options:
+ -d <dir>: specify directory to run in
+ -h: print help
+
+If no -d argument is given we'll create one in /tmp and work there.
+
+EOF
+    exit 1
+}
+
+DIRECTORY=""
+DATA_URL=https://gitlab.cern.ch/dguest/hh4b-test-files/-/raw/master/
+
+while getopts ":d:h" o; do
+    case "${o}" in
+        d) DIRECTORY=${OPTARG} ;;
+        h) help ;;
+        *) usage ;;
+    esac
+done
+shift $((OPTIND-1))
+
+if (( $# != 1 )) ; then
+    usage
+fi
+
+MODE=$1
+
+
+############################################
+# Check that all the modes / paths exist
+############################################
+#
+if [[ ! ${DATAFILES[$MODE]+x} ]]; then usage; fi
+DOWNLOAD_PATH=${DATAFILES[$MODE]}
+FILE=${DOWNLOAD_PATH##*/}
+
+if [[ ! ${TESTS[$MODE]+x} ]]; then usage; fi
+RUN=${TESTS[$MODE]}
+
+
+#############################################
+# now start doing stuff
+#############################################
+#
+if [[ -z ${DIRECTORY} ]] ; then
+    DIRECTORY=$(mktemp -d)
+    echo "running in ${DIRECTORY}" >&2
+fi
+
+if [[ ! -d ${DIRECTORY} ]]; then
+    if [[ -e ${DIRECTORY} ]] ; then
+        echo "${DIRECTORY} is not a directory" >&2
+        exit 1
+    fi
+    mkdir ${DIRECTORY}
+fi
+cd $DIRECTORY
+
+# get files
+if [[ ! -f ${FILE} ]] ; then
+    echo "getting file ${FILE}" >&2
+    curl -s ${DATA_URL}/${DOWNLOAD_PATH} > ${FILE}
+fi
+
+# now run the test
+$RUN $FILE
+
-- 
GitLab


From 6cf961046cec25a9efb86f70668e3e3296b3284e Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 11 Aug 2022 14:49:00 +0200
Subject: [PATCH 14/33] progress

---
 HH4bAnalysis/CMakeLists.txt            |  6 ++++--
 HH4bAnalysis/src/VariableDumperAlg.cxx | 10 ++++++----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/HH4bAnalysis/CMakeLists.txt b/HH4bAnalysis/CMakeLists.txt
index b78c7427c..7ff765547 100644
--- a/HH4bAnalysis/CMakeLists.txt
+++ b/HH4bAnalysis/CMakeLists.txt
@@ -17,7 +17,9 @@ atlas_add_library(HH4bAnalysisLib
 # Build the Athena component library
 atlas_add_component(HH4bAnalysis
   src/VariableDumperAlg.cxx
+  src/DiHiggsAnalysis.cxx
   src/tools/NTrkVertexCounter.cxx
+  src/tools/kLargestJets.cxx
   src/components/*.cxx
   LINK_LIBRARIES
   GaudiKernel
@@ -38,12 +40,12 @@ atlas_install_scripts(
   share/VariableDumperConfig.py
   share/grid_submit.py
   share/hh4b-test
-  )
+)
 atlas_install_python_modules(
   python/Algs
   python/Config
   python/utils
-  )
+)
 
 # atlas_install_data( data/* )
 # You can access your data from code using path resolver, e.g.
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 55ae24769..d92ee14d0 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -52,10 +52,10 @@ namespace HH4B
                                                                 "%SYS%", sys));
 
       ATH_MSG_VERBOSE("Will apply sysname \"" << sysname << "\" for event");
-      // Do something with Eventinfo
+
+      // get the xAOD objects
       SG::ReadHandle<xAOD::EventInfo> eventInfo(m_EventInfoKey);
       ATH_CHECK(eventInfo.isValid());
-
       const xAOD::ElectronContainer *electrons(nullptr);
       ATH_CHECK(m_electronHandle.retrieve(electrons, sys));
       const xAOD::PhotonContainer *photons(nullptr);
@@ -64,13 +64,14 @@ namespace HH4B
       ATH_CHECK(m_muonHandle.retrieve(muons, sys));
       const xAOD::JetContainer *antiKt4RecoJets(nullptr);
       ATH_CHECK(m_jetsmallRHandle.retrieve(antiKt4RecoJets, sys));
+      const xAOD::JetContainer *antiKt10RecoJets(nullptr);
       if (!m_jetlargeRHandle.empty())
       {
-        const xAOD::JetContainer *antiKt10RecoJets(nullptr);
         ATH_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
       }
       const xAOD::JetContainer *VRTrackJets(nullptr);
       ATH_CHECK(m_VRtrackjetHandle.retrieve(VRTrackJets, sys));
+
       for (auto jet : *antiKt4RecoJets)
       {
         const xAOD::BTagging *bjet =
@@ -97,10 +98,11 @@ namespace HH4B
       // TODO: make configurable with which btagging WP Higgs candidates are
       // created
 
+      // create the analysis object
       DiHiggsAnalysis hh4b_analysis;
       hh4b_analysis.makeResolvedAnalysis(antiKt4RecoJets);
       hh4b_analysis.makeBoostedAnalysis(antiKt10RecoJets);
-      hh4b_analysis.decorateHiggsVars(*eventInfo);
+      hh4b_analysis.decorateHiggsVars(*eventInfo)
     }
 
     return StatusCode::SUCCESS;
-- 
GitLab


From 0ff77215d474e6a81cc47650f6057fd97aa752eb Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Fri, 12 Aug 2022 11:06:15 +0200
Subject: [PATCH 15/33] bug on untrimmed large R

---
 HH4bAnalysis/python/Algs/Jets.py              |  14 +-
 HH4bAnalysis/share/VariableDumperAlgConfig.py | 520 ++++++++++++++++++
 HH4bAnalysis/share/VariableDumperConfig.py    |  56 +-
 HH4bAnalysis/src/VariableDumperAlg.cxx        |  25 +-
 HH4bAnalysis/src/VariableDumperAlg.h          |   4 +-
 5 files changed, 570 insertions(+), 49 deletions(-)
 create mode 100755 HH4bAnalysis/share/VariableDumperAlgConfig.py

diff --git a/HH4bAnalysis/python/Algs/Jets.py b/HH4bAnalysis/python/Algs/Jets.py
index be56fec30..6ff8ee601 100644
--- a/HH4bAnalysis/python/Algs/Jets.py
+++ b/HH4bAnalysis/python/Algs/Jets.py
@@ -1,7 +1,7 @@
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
-from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
 from FTagAnalysisAlgorithms.FTagAnalysisSequence import makeFTagAnalysisSequence
+from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
 
 
 def JetAnalysisSequenceCfg(
@@ -30,14 +30,14 @@ def JetAnalysisSequenceCfg(
         "xAODBTaggingEfficiency/13TeV/2022-22-13TeV-MC20-CDI-2022-07-28_v1.root"
     )
     # This is the container name that is available in the CDI aboce
-    jetBTagContaienrName = "AntiKt4EMPFlowJets"
+    jetBTagContainerName = "AntiKt4EMPFlowJets"
 
     for tagger_wp in workingPoints:
         tagger, btag_wp = tagger_wp.split("_", 1)
         makeFTagAnalysisSequence(
             jetSequence,
             dataType,
-            jetCollection=jetBTagContaienrName,
+            jetCollection=jetBTagContainerName,
             btagWP=btag_wp,
             btagger=tagger,
             generator="Pythia8",
@@ -125,19 +125,19 @@ def VRJetAnalysisSequenceCfg(
         "xAODBTaggingEfficiency/13TeV/2021-22-13TeV-MC16-CDI-2021-12-02_v2.root"
     )
     # This is the container name that is available in the CDI aboce
-    vrJetBTagContaienrName = "AntiKtVR30Rmax4Rmin02TrackJets"
+    vrJetBTagContainerName = "AntiKtVR30Rmax4Rmin02TrackJets"
     for tagger_wp in workingPoints:
         tagger, btag_wp = tagger_wp.split("_", 1)
         makeFTagAnalysisSequence(
             vrJetSequence,
             dataType,
-            jetCollection=vrJetBTagContaienrName,
+            jetCollection=vrJetBTagContainerName,
             btagWP=btag_wp,
             btagger=tagger,
-            generator="Pythia8",
             minPt=10e3,
-            postfix="",
+            postfix=btag_wp,
             preselection=None,
+            kinematicSelection=True,
             noEfficiency=False,
             legacyRecommendations=False,
             enableCutflow=False,
diff --git a/HH4bAnalysis/share/VariableDumperAlgConfig.py b/HH4bAnalysis/share/VariableDumperAlgConfig.py
new file mode 100755
index 000000000..43e64e9cb
--- /dev/null
+++ b/HH4bAnalysis/share/VariableDumperAlgConfig.py
@@ -0,0 +1,520 @@
+#!/bin/env python
+
+#
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+#
+
+#
+# VariableDumperConfig.py
+# A simple CA file to create a tree of variables
+#
+
+import sys
+from pathlib import Path
+
+from AthenaCommon import Logging
+from AthenaConfiguration.AutoConfigFlags import GetFileMD
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Event import (
+    EventSelectionAnalysisSequenceCfg,
+    GeneratorAnalysisSequenceCfg,
+    PileupAnalysisSequenceCfg,
+    TriggerAnalysisSequenceCfg,
+)
+from HH4bAnalysis.Algs.Jets import (
+    FatJetAnalysisSequenceCfg,
+    JetAnalysisSequenceCfg,
+    VRJetAnalysisSequenceCfg,
+)
+from HH4bAnalysis.Algs.Muons import MuonAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Photons import PhotonAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Postprocessing import OverlapAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Tree import AnalysisTreeAlgCfg
+from HH4bAnalysis.Config.Base import cache_metadata, pileupConfigFiles, update_metadata
+from HH4bAnalysis.utils.containerNameHelper import getContainerName
+
+log = Logging.logging.getLogger("VariableDumperConfig")
+
+
+def defineArgs(ConfigFlags):
+    # Generate a parser and add an output file argument, then retrieve the args
+    parser = ConfigFlags.getArgumentParser()
+    parser.add_argument(
+        "--outFile",
+        type=str,
+        default="analysis-variables.root",
+        help="Output file name",
+    )
+    parser.add_argument(
+        "--btag-wps",
+        type=str,
+        nargs="*",
+        default=[
+            "DL1dv00_FixedCutBEff_77",
+            "DL1dv00_FixedCutBEff_85",
+        ],
+        help="Btag working points default %(default)s",
+    )
+    parser.add_argument(
+        "--vr-btag-wps",
+        type=str,
+        nargs="*",
+        default=[
+            "DL1r_FixedCutBEff_77",
+            "DL1r_FixedCutBEff_85",
+        ],
+        help="VR Jets btag working points default %(default)s",
+    )
+    parser.add_argument(
+        "--trigger-list",
+        type=str,
+        default="Run3",
+        help="Trigger list to use, default: %(default)s",
+    )
+    parser.add_argument(
+        "-c",
+        "--meta-cache",
+        type=Path,
+        default=None,
+        nargs="?",
+        const=Path("metadata.json"),
+        help="use metadata cache file, defaults to %(const)s",
+    )
+    parser.add_argument(
+        "-o",
+        "--loose",
+        action="store_true",
+        help="use loose event cleaning (to get something to pass)",
+    )
+    return parser
+
+
+def _is_physlite(flags):
+    return flags.Input.ProcessingTags == ["StreamDAOD_PHYSLITE"]
+
+
+def _is_mc_phys(flags):
+    return flags.Input.isMC and not _is_physlite(flags)
+
+
+def _get_container_names(flags):
+    is_daod_physlite = _is_physlite(flags)
+    inputs = dict(
+        reco4Jet=getContainerName("Reco4PFlowJets", is_daod_physlite),
+        reco10Jet=getContainerName("Reco10PFlowJets", is_daod_physlite),
+        vrJet=getContainerName("VRJets", is_daod_physlite),
+        muons=getContainerName("Muons", is_daod_physlite),
+        electrons=getContainerName("Electrons", is_daod_physlite),
+        photons=getContainerName("Photons", is_daod_physlite),
+    )
+    outputs = dict(
+        reco4Jet=f"Analysis{inputs['reco4Jet']}_%SYS%",
+        muons=f"Analysis{inputs['muons']}_%SYS%",
+        electrons=f"Analysis{inputs['electrons']}_%SYS%",
+        photons=f"Analysis{inputs['photons']}_%SYS%",
+    )
+    if inputs["reco10Jet"]:
+        outputs["reco10Jet"] = f"Analysis{inputs['reco10Jet']}_%SYS%"
+    else:
+        outputs["reco10Jet"] = ""
+    if inputs["vrJet"]:
+        outputs["vrJet"] = f"Analysis{inputs['vrJet']}_%SYS%"
+    else:
+        outputs["vrJet"] = ""
+    return {"inputs": inputs, "outputs": outputs}
+
+
+# Generate the algorithm to do the dumping.
+# AthAlgSequence does not respect filter decisions,
+# so we will need to add a new sequence to the CA
+def AnalysisAlgsCfg(
+    flags,
+    btag_wps,
+    vr_btag_wps,
+    trigger_chains=[],
+    do_muons=True,
+    metadata_cache=None,
+    do_loose=False,
+):
+    fileMD = GetFileMD(flags.Input.Files[0])
+    if metadata_cache:
+        update_metadata(metadata_cache)
+    dataType = "mc" if flags.Input.isMC else "data"
+    is_daod_physlite = _is_physlite(flags)
+    log.info(
+        f"Self-configured: dataType: '{dataType}', is PHYSLITE? {is_daod_physlite}"
+    )
+
+    log.debug(f"Containers available in dataset: {flags.Input.Collections}")
+
+    # TODO: no DL1d branches in PHYSLITE yet
+    if is_daod_physlite:
+        btag_wps = [wp.replace("DL1dv00", "DL1r") for wp in btag_wps]
+
+    cfg = ComponentAccumulator()
+
+    # Create SystematicsSvc explicitly:
+    cfg.addService(CompFactory.getComp("CP::SystematicsSvc")("SystematicsSvc"))
+
+    log.info("Adding trigger analysis algs")
+    # Removes events failing trigger and adds variable to EventInfo
+    # if trigger passed or not, for example:
+    # EventInfo.trigger_name
+    cfg.merge(TriggerAnalysisSequenceCfg(flags, dataType, trigger_chains))
+
+    log.info("Add DQ event filter sequence")
+    # Remove events failing DQ criteria
+    cfg.merge(
+        EventSelectionAnalysisSequenceCfg(flags, dataType, grlFiles=[], loose=do_loose)
+    )
+
+    doPRW = _is_mc_phys(flags)
+    log.info(
+        f"Do PRW is {doPRW}. {'Add' if doPRW else 'Skip'} pileup re-weight sequence"
+    )
+    if doPRW:
+        try:
+            prwFiles, lumicalcFiles = pileupConfigFiles(fileMD)
+            # Adds variable to EventInfo if for pileup weight, for example:
+            # EventInfo.PileWeight_%SYS$
+            cfg.merge(
+                PileupAnalysisSequenceCfg(
+                    flags,
+                    dataType=dataType,
+                    prwFiles=prwFiles,
+                    lumicalcFiles=lumicalcFiles,
+                )
+            )
+
+            log.info("Adding generator analysis sequence")
+            # Adds variable to EventInfo if for generator weight, for example:
+            # EventInfo.generatorWeight_%SYS%
+            cfg.merge(GeneratorAnalysisSequenceCfg(flags, dataType))
+
+        except LookupError as err:
+            log.error(err)
+            doPRW = False
+
+    containers = _get_container_names(flags)
+
+    log.info("Add electron seq")
+    cfg.merge(
+        ElectronAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputContainerName=containers["inputs"]["electrons"],
+            outputContainerName=containers["outputs"]["electrons"],
+        )
+    )
+
+    log.info("Add photon seq")
+    cfg.merge(
+        PhotonAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputContainerName=containers["inputs"]["photons"],
+            outputContainerName=containers["outputs"]["photons"],
+        )
+    )
+
+    if do_muons:
+        log.info("Add muon seq")
+        cfg.merge(
+            MuonAnalysisSequenceCfg(
+                flags,
+                dataType=dataType,
+                inputContainerName=containers["inputs"]["muons"],
+                outputContainerName=containers["outputs"]["muons"],
+            )
+        )
+
+    log.info("Add jet seq")
+    cfg.merge(
+        JetAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputContainerName=containers["inputs"]["reco4Jet"],
+            outputContainerName=containers["outputs"]["reco4Jet"],
+            workingPoints=btag_wps,
+            is_daod_physlite=is_daod_physlite,
+        )
+    )
+
+    if is_daod_physlite:
+        log.warning("On PHYSLITE, skip large-R jet sequence for now")
+    else:
+        log.info("Add large-R jet seq")
+        cfg.merge(
+            FatJetAnalysisSequenceCfg(
+                flags,
+                dataType=dataType,
+                inputContainerName=containers["inputs"]["reco10Jet"],
+                outputContainerName=containers["outputs"]["reco10Jet"],
+            )
+        )
+
+    if is_daod_physlite:
+        log.warning("On PHYSLITE, skip VR jet sequence for now")
+    else:
+        log.info("Add VR jet seq")
+        cfg.merge(
+            VRJetAnalysisSequenceCfg(
+                flags,
+                dataType=dataType,
+                inputContainerName=containers["inputs"]["vrJet"],
+                outputContainerName=containers["outputs"]["vrJet"],
+                workingPoints=vr_btag_wps,
+            )
+        )
+
+    ########################################################################
+    # Begin postprocessing
+    ########################################################################
+
+    log.info("Add Overlap Removal sequence")
+    overlapInputNames = {
+        "electrons": containers["outputs"]["electrons"],
+        "photons": containers["outputs"]["photons"],
+        "jets": containers["outputs"]["reco4Jet"],
+    }
+    if do_muons:
+        overlapInputNames["muons"] = containers["outputs"]["muons"]
+
+    if not is_daod_physlite:
+        overlapInputNames["fatJets"] = containers["outputs"]["reco10Jet"]
+
+    overlapOutputNames = {k: f"{v}_OR" for k, v in overlapInputNames.items()}
+
+    cfg.merge(
+        OverlapAnalysisSequenceCfg(
+            flags,
+            dataType=dataType,
+            inputNames=overlapInputNames,
+            outputNames=overlapOutputNames,
+            doFatJets=not is_daod_physlite,
+            doMuons=do_muons,
+        )
+    )
+
+    if metadata_cache:
+        cache_metadata(metadata_cache)
+
+    cfg.addEventAlgo(
+        CompFactory.HH4B.VariableDumperAlg(
+            "VariableDumper",
+            EventInfoKey="EventInfo",
+            RootStreamName="ANALYSIS",
+        )
+    )
+
+    return cfg
+
+
+def MiniTupleCfg(
+    flags,
+    outfname,
+    trigger_chains,
+    working_points,
+    do_muons=True,
+):
+    cfg = ComponentAccumulator()
+    is_daod_physlite = _is_physlite(flags)
+    doPRW = _is_mc_phys(flags)
+    containers = _get_container_names(flags)["outputs"]
+
+    log.debug(f"Containers requested in dataset: {containers}")
+
+    ########################################################################
+    # Create analysis mini-ntuple
+    ########################################################################
+
+    # Add an instance of THistSvc, to create the output file and associated stream.
+    # This is needed so that the alg can register its output TTree.
+    # The syntax for the output is:
+    #   Stream name: "ANALYSIS" (default assumed by AthHistogramAlgorithm)
+    #   Output file name: specified by setting "DATAFILE"
+    #   File I/O option: specified by setting "OPT" and passed to the TFile constructor
+    #      "RECREATE" will (over)write the specified file name with a new file
+    cfg.addService(
+        CompFactory.THistSvc(Output=[f"ANALYSIS DATAFILE='{outfname}', OPT='RECREATE'"])
+    )
+
+    def getFourMomBranches(container, alias, doOR=False):
+        ORstr = "_OR" if doOR else ""
+
+        branches = []
+        vars = ["pt", "eta", "phi"]
+        if "Jets" in container:
+            vars.append("m")
+        for var in vars:
+            branches += [
+                f"{container}{ORstr}.{var}  -> {alias}{ORstr}_%SYS%_{var}",
+            ]
+        return branches
+
+    analysisTreeBranches = [
+        "EventInfo.runNumber     -> runNumber",
+        "EventInfo.eventNumber   -> eventNumber",
+        "EventInfo.mcEventWeights   -> mcEventWeights",
+        "EventInfo.averageInteractionsPerCrossing -> averageInteractionsPerCrossing",
+    ]
+
+    for trig_chain in trigger_chains:
+        cleaned = trig_chain.replace("-", "_")
+        if "." in trig_chain:
+            continue
+        analysisTreeBranches.append(
+            f"EventInfo.trigPassed_{cleaned} -> trigPassed_{cleaned}"
+        )
+
+    if doPRW:
+        analysisTreeBranches += [
+            "EventInfo.PileupWeight_%SYS% -> pileupWeight_%SYS%",
+            "EventInfo.generatorWeight_%SYS% -> generatorWeight_%SYS%",
+        ]
+    else:
+        analysisTreeBranches += [
+            "EventInfo.mcEventWeights -> pileupWeight_NOSYS",
+        ]
+
+    objectpairs = {
+        containers["electrons"]: "el",
+        containers["photons"]: "ph",
+        containers["reco4Jet"]: "recojet_antikt4",
+    }
+    if do_muons:
+        containers["muons"] = "mu"
+
+    for cont, alias in objectpairs.items():
+        analysisTreeBranches += getFourMomBranches(cont, alias)
+        analysisTreeBranches += getFourMomBranches(cont, alias, doOR=True)
+
+    # B-jet WPs
+    analysisTreeBranches += [
+        f"{containers['reco4Jet']}.ftag_select_{btag_wp}"
+        f" -> recojet_antikt4_%SYS%_{btag_wp}"
+        for btag_wp in working_points["ak4"]
+    ]
+    analysisTreeBranches += [
+        f"{containers['reco4Jet']}_OR.ftag_select_{btag_wp}"
+        f" -> recojet_antikt4_OR_%SYS%_{btag_wp}"
+        for btag_wp in working_points["ak4"]
+    ]
+
+    if not is_daod_physlite:
+        analysisTreeBranches += getFourMomBranches(
+            containers["reco10Jet"], "recojet_antikt10"
+        )
+        analysisTreeBranches += getFourMomBranches(
+            containers["reco10Jet"], "recojet_antikt10", doOR=True
+        )
+        analysisTreeBranches += getFourMomBranches(containers["vrJet"], "vrjet")
+        analysisTreeBranches += [
+            f"{containers['vrJet']}.ftag_select_{btag_wp} -> vrjet_%SYS%_{btag_wp}"
+            for btag_wp in working_points["vr"]
+        ]
+
+    log.info("Add tree seq")
+    cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
+
+    return cfg
+
+
+# CA modules are intended to be executable, to facilitate easy testing.
+# We define a "main function" that will run a test job if the module
+# is executed rather than imported.
+def main():
+    # Import the job configuration flags, some of which will be autoconfigured.
+    # These are used for steering the job, and include e.g. the input file (list).
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+
+    # Get the arguments, defined at the top for easy browsing
+    parser = defineArgs(ConfigFlags)
+    args = ConfigFlags.fillFromArgs([], parser)
+    # Lock the flags so that the configuration of job subcomponents cannot
+    # modify them silently/unpredictably.
+    # Workaround for buggy glob, needed prior
+    # to https://gitlab.cern.ch/atlas/athena/-/merge_requests/55561
+    if ConfigFlags.Input.Files[0] == "_ATHENA_GENERIC_INPUTFILE_NAME_":
+        ConfigFlags.Input.Files = ConfigFlags.Input.Files[1:]
+    log.info(f"Operating on input files {ConfigFlags.Input.Files}")
+    ConfigFlags.lock()
+
+    # Get a ComponentAccumulator setting up the standard components
+    # needed to run an Athena job.
+    # Setting temporarily needed for Run 3 code, to generate python
+    # Configurable objects for deduplication
+    from AthenaCommon.Configurable import ConfigurableRun3Behavior
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+
+    with ConfigurableRun3Behavior():
+
+        cfg = MainServicesCfg(ConfigFlags)
+
+        from EventBookkeeperTools.EventBookkeeperToolsConfig import (
+            BookkeeperToolCfg,
+            CutFlowSvcCfg,
+        )
+
+        # Create CutFlowSvc otherwise the default CutFlowSvc that has only
+        # one CutflowBookkeeper object, and can't deal with multiple weights
+        cfg.merge(CutFlowSvcCfg(ConfigFlags))
+        cfg.merge(BookkeeperToolCfg(ConfigFlags))
+
+        # Adjust the loop manager to announce the event number less frequently.
+        # Makes a big difference if running over many events
+        if ConfigFlags.Concurrency.NumThreads > 0:
+            cfg.addService(
+                CompFactory.AthenaHiveEventLoopMgr(EventPrintoutInterval=500)
+            )
+        else:
+            cfg.addService(CompFactory.AthenaEventLoopMgr(EventPrintoutInterval=500))
+
+        from HH4bAnalysis.Config.xAODEventSelectorConfig import xAODReadCfg
+
+        cfg.merge(xAODReadCfg(ConfigFlags))
+
+        # Add our VariableDumper CA, calling the function defined above.
+        from HH4bAnalysis.Config.TriggerLists import TriggerLists
+
+        trigger_chains = TriggerLists[args.trigger_list]
+        do_muons = not args.meta_cache
+
+        cfg.addSequence(CompFactory.AthSequencer("HH4bSeq"), "AthAlgSeq")
+        cfg.merge(
+            AnalysisAlgsCfg(
+                ConfigFlags,
+                btag_wps=args.btag_wps,
+                vr_btag_wps=args.vr_btag_wps,
+                trigger_chains=trigger_chains,
+                metadata_cache=args.meta_cache,
+                do_muons=do_muons,
+                do_loose=args.loose,
+            ),
+            "HH4bSeq",
+        )
+        cfg.merge(
+            MiniTupleCfg(
+                ConfigFlags,
+                outfname=args.outFile,
+                trigger_chains=trigger_chains,
+                working_points={"ak4": args.btag_wps, "vr": args.vr_btag_wps},
+                do_muons=do_muons,
+            ),
+            "HH4bSeq",
+        )
+
+        # Print the full job configuration
+        cfg.printConfig(summariseProps=False)
+
+    # Execute the job defined in the ComponentAccumulator.
+    # The number of events is specified by `args.evtMax`
+    return cfg.run(args.evtMax)
+
+
+# Execute the main function if this file was executed as a script
+if __name__ == "__main__":
+    code = main()
+    sys.exit(0 if code.isSuccess() else 1)
diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 10ee35a09..ea6380b39 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -13,26 +13,26 @@ import sys
 from pathlib import Path
 
 from AthenaCommon import Logging
+from AthenaConfiguration.AutoConfigFlags import GetFileMD
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
-from AthenaConfiguration.AutoConfigFlags import GetFileMD
-from HH4bAnalysis.Config.Base import pileupConfigFiles, cache_metadata, update_metadata
+from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Event import (
+    EventSelectionAnalysisSequenceCfg,
     GeneratorAnalysisSequenceCfg,
-    TriggerAnalysisSequenceCfg,
     PileupAnalysisSequenceCfg,
-    EventSelectionAnalysisSequenceCfg,
+    TriggerAnalysisSequenceCfg,
 )
-from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
-from HH4bAnalysis.Algs.Photons import PhotonAnalysisSequenceCfg
-from HH4bAnalysis.Algs.Muons import MuonAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Jets import (
-    JetAnalysisSequenceCfg,
     FatJetAnalysisSequenceCfg,
+    JetAnalysisSequenceCfg,
     VRJetAnalysisSequenceCfg,
 )
+from HH4bAnalysis.Algs.Muons import MuonAnalysisSequenceCfg
+from HH4bAnalysis.Algs.Photons import PhotonAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Postprocessing import OverlapAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Tree import AnalysisTreeAlgCfg
+from HH4bAnalysis.Config.Base import cache_metadata, pileupConfigFiles, update_metadata
 from HH4bAnalysis.utils.containerNameHelper import getContainerName
 
 log = Logging.logging.getLogger("VariableDumperConfig")
@@ -62,8 +62,8 @@ def defineArgs(ConfigFlags):
         type=str,
         nargs="*",
         default=[
-            # "DL1r_FixedCutBEff_77",
-            # "DL1r_FixedCutBEff_85",
+            "DL1r_FixedCutBEff_77",
+            "DL1r_FixedCutBEff_85",
         ],
         help="VR Jets btag working points default %(default)s",
     )
@@ -172,7 +172,7 @@ def AnalysisAlgsCfg(
 
     doPRW = _is_mc_phys(flags)
     log.info(
-        f"Do PRW is {doPRW}. " f"{'Add' if doPRW else 'Skip'} pileup re-weight sequence"
+        f"Do PRW is {doPRW}. {'Add' if doPRW else 'Skip'} pileup re-weight sequence"
     )
     if doPRW:
         try:
@@ -301,6 +301,20 @@ def AnalysisAlgsCfg(
     if metadata_cache:
         cache_metadata(metadata_cache)
 
+    cfg.addEventAlgo(
+        CompFactory.HH4B.VariableDumperAlg(
+            "VariableDumper",
+            RootStreamName="ANALYSIS",
+            EventInfoKey="EventInfo",
+            ElectronsKey=containers["outputs"]["electrons"],
+            PhotonsKey=containers["outputs"]["photons"],
+            MuonsKey=containers["inputs"]["muons"],
+            SmallJetKey=containers["outputs"]["reco4Jet"],
+            LargeJetKey=containers["inputs"]["reco10Jet"],
+            VRtrackjets=containers["outputs"]["vrJet"],
+        )
+    )
+
     return cfg
 
 
@@ -404,10 +418,21 @@ def MiniTupleCfg(
         )
         analysisTreeBranches += getFourMomBranches(containers["vrJet"], "vrjet")
         analysisTreeBranches += [
-            f"{containers['vrJet']}.ftag_select_{btag_wp}" f" -> vrjet_%SYS%_{btag_wp}"
+            f"{containers['vrJet']}.ftag_select_{btag_wp} -> vrjet_%SYS%_{btag_wp}"
             for btag_wp in working_points["vr"]
         ]
-
+    # analysisTreeBranches = [
+    #     "EventInfo.resolved_m_h1   -> resolved_m_h1",
+    #     "EventInfo.resolved_m_h2   -> resolved_m_h2",
+    #     "EventInfo.resolved_m_hh   -> resolved_m_hh",
+    #     "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
+    #     "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
+    #     "EventInfo.boosted_m_h1   -> boosted_m_h1",
+    #     "EventInfo.boosted_m_h2   -> boosted_m_h2",
+    #     "EventInfo.boosted_m_hh   -> boosted_m_hh",
+    #     "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
+    #     "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
+    # ]
     log.info("Add tree seq")
     cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
 
@@ -436,19 +461,18 @@ def main():
 
     # Get a ComponentAccumulator setting up the standard components
     # needed to run an Athena job.
-    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
-
     # Setting temporarily needed for Run 3 code, to generate python
     # Configurable objects for deduplication
     from AthenaCommon.Configurable import ConfigurableRun3Behavior
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
 
     with ConfigurableRun3Behavior():
 
         cfg = MainServicesCfg(ConfigFlags)
 
         from EventBookkeeperTools.EventBookkeeperToolsConfig import (
-            CutFlowSvcCfg,
             BookkeeperToolCfg,
+            CutFlowSvcCfg,
         )
 
         # Create CutFlowSvc otherwise the default CutFlowSvc that has only
diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index d92ee14d0..8b282dfd1 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -72,29 +72,6 @@ namespace HH4B
       const xAOD::JetContainer *VRTrackJets(nullptr);
       ATH_CHECK(m_VRtrackjetHandle.retrieve(VRTrackJets, sys));
 
-      for (auto jet : *antiKt4RecoJets)
-      {
-        const xAOD::BTagging *bjet =
-            xAOD::BTaggingUtilities::getBTagging(*jet);
-
-        if (!bjet)
-        {
-          ATH_MSG_WARNING("btagging information not available");
-          continue;
-        }
-
-        double DL1dv00_pb = -1;
-        double DL1dv00_pc = -1;
-        double DL1dv00_pu = -1;
-        bjet->pb("DL1dv00", DL1dv00_pb);
-        bjet->pc("DL1dv00", DL1dv00_pc);
-        bjet->pu("DL1dv00", DL1dv00_pu);
-        ATH_MSG_WARNING("DL1dv00_pb \"" << DL1dv00_pb << "\" for jet");
-        ATH_MSG_WARNING("DL1dv00_pc \"" << DL1dv00_pc << "\" for jet");
-        ATH_MSG_WARNING("DL1dv00_pu \"" << DL1dv00_pu << "\" for jet");
-        jet->auxdecor<double>("DL1dv00_pb") = DL1dv00_pb;
-      }
-
       // TODO: make configurable with which btagging WP Higgs candidates are
       // created
 
@@ -102,7 +79,7 @@ namespace HH4B
       DiHiggsAnalysis hh4b_analysis;
       hh4b_analysis.makeResolvedAnalysis(antiKt4RecoJets);
       hh4b_analysis.makeBoostedAnalysis(antiKt10RecoJets);
-      hh4b_analysis.decorateHiggsVars(*eventInfo)
+      hh4b_analysis.decorateHiggsVars(*eventInfo);
     }
 
     return StatusCode::SUCCESS;
diff --git a/HH4bAnalysis/src/VariableDumperAlg.h b/HH4bAnalysis/src/VariableDumperAlg.h
index ba146105b..cdb0b9f87 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.h
+++ b/HH4bAnalysis/src/VariableDumperAlg.h
@@ -60,7 +60,7 @@ private:
         "the electron collection to run on"};
 
     CP::SysReadHandle<xAOD::PhotonContainer> m_photonHandle{
-        this, "PhotosKey", "AnalysisPhotons_%SYS%",
+        this, "PhotonsKey", "AnalysisPhotons_%SYS%",
         "the photon collection to run on"};
 
     CP::SysReadHandle<xAOD::MuonContainer> m_muonHandle{
@@ -76,7 +76,7 @@ private:
         "the large-R jet collection to run on"};
 
     CP::SysReadHandle<xAOD::JetContainer> m_VRtrackjetHandle{
-        this, "VRtrackjets", "VRTrackJetsBTAG_%SYS%",
+        this, "VRtrackjets", "VRTrackJets_%SYS%",
         "the VR track jet collection to run on"};
   };
 }
-- 
GitLab


From 367b9cef6527acc1a207ae723106b124dbbe93b6 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Fri, 12 Aug 2022 11:08:45 +0200
Subject: [PATCH 16/33] remove wrong file

---
 HH4bAnalysis/share/VariableDumperAlgConfig.py | 520 ------------------
 1 file changed, 520 deletions(-)
 delete mode 100755 HH4bAnalysis/share/VariableDumperAlgConfig.py

diff --git a/HH4bAnalysis/share/VariableDumperAlgConfig.py b/HH4bAnalysis/share/VariableDumperAlgConfig.py
deleted file mode 100755
index 43e64e9cb..000000000
--- a/HH4bAnalysis/share/VariableDumperAlgConfig.py
+++ /dev/null
@@ -1,520 +0,0 @@
-#!/bin/env python
-
-#
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-#
-
-#
-# VariableDumperConfig.py
-# A simple CA file to create a tree of variables
-#
-
-import sys
-from pathlib import Path
-
-from AthenaCommon import Logging
-from AthenaConfiguration.AutoConfigFlags import GetFileMD
-from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
-from AthenaConfiguration.ComponentFactory import CompFactory
-from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
-from HH4bAnalysis.Algs.Event import (
-    EventSelectionAnalysisSequenceCfg,
-    GeneratorAnalysisSequenceCfg,
-    PileupAnalysisSequenceCfg,
-    TriggerAnalysisSequenceCfg,
-)
-from HH4bAnalysis.Algs.Jets import (
-    FatJetAnalysisSequenceCfg,
-    JetAnalysisSequenceCfg,
-    VRJetAnalysisSequenceCfg,
-)
-from HH4bAnalysis.Algs.Muons import MuonAnalysisSequenceCfg
-from HH4bAnalysis.Algs.Photons import PhotonAnalysisSequenceCfg
-from HH4bAnalysis.Algs.Postprocessing import OverlapAnalysisSequenceCfg
-from HH4bAnalysis.Algs.Tree import AnalysisTreeAlgCfg
-from HH4bAnalysis.Config.Base import cache_metadata, pileupConfigFiles, update_metadata
-from HH4bAnalysis.utils.containerNameHelper import getContainerName
-
-log = Logging.logging.getLogger("VariableDumperConfig")
-
-
-def defineArgs(ConfigFlags):
-    # Generate a parser and add an output file argument, then retrieve the args
-    parser = ConfigFlags.getArgumentParser()
-    parser.add_argument(
-        "--outFile",
-        type=str,
-        default="analysis-variables.root",
-        help="Output file name",
-    )
-    parser.add_argument(
-        "--btag-wps",
-        type=str,
-        nargs="*",
-        default=[
-            "DL1dv00_FixedCutBEff_77",
-            "DL1dv00_FixedCutBEff_85",
-        ],
-        help="Btag working points default %(default)s",
-    )
-    parser.add_argument(
-        "--vr-btag-wps",
-        type=str,
-        nargs="*",
-        default=[
-            "DL1r_FixedCutBEff_77",
-            "DL1r_FixedCutBEff_85",
-        ],
-        help="VR Jets btag working points default %(default)s",
-    )
-    parser.add_argument(
-        "--trigger-list",
-        type=str,
-        default="Run3",
-        help="Trigger list to use, default: %(default)s",
-    )
-    parser.add_argument(
-        "-c",
-        "--meta-cache",
-        type=Path,
-        default=None,
-        nargs="?",
-        const=Path("metadata.json"),
-        help="use metadata cache file, defaults to %(const)s",
-    )
-    parser.add_argument(
-        "-o",
-        "--loose",
-        action="store_true",
-        help="use loose event cleaning (to get something to pass)",
-    )
-    return parser
-
-
-def _is_physlite(flags):
-    return flags.Input.ProcessingTags == ["StreamDAOD_PHYSLITE"]
-
-
-def _is_mc_phys(flags):
-    return flags.Input.isMC and not _is_physlite(flags)
-
-
-def _get_container_names(flags):
-    is_daod_physlite = _is_physlite(flags)
-    inputs = dict(
-        reco4Jet=getContainerName("Reco4PFlowJets", is_daod_physlite),
-        reco10Jet=getContainerName("Reco10PFlowJets", is_daod_physlite),
-        vrJet=getContainerName("VRJets", is_daod_physlite),
-        muons=getContainerName("Muons", is_daod_physlite),
-        electrons=getContainerName("Electrons", is_daod_physlite),
-        photons=getContainerName("Photons", is_daod_physlite),
-    )
-    outputs = dict(
-        reco4Jet=f"Analysis{inputs['reco4Jet']}_%SYS%",
-        muons=f"Analysis{inputs['muons']}_%SYS%",
-        electrons=f"Analysis{inputs['electrons']}_%SYS%",
-        photons=f"Analysis{inputs['photons']}_%SYS%",
-    )
-    if inputs["reco10Jet"]:
-        outputs["reco10Jet"] = f"Analysis{inputs['reco10Jet']}_%SYS%"
-    else:
-        outputs["reco10Jet"] = ""
-    if inputs["vrJet"]:
-        outputs["vrJet"] = f"Analysis{inputs['vrJet']}_%SYS%"
-    else:
-        outputs["vrJet"] = ""
-    return {"inputs": inputs, "outputs": outputs}
-
-
-# Generate the algorithm to do the dumping.
-# AthAlgSequence does not respect filter decisions,
-# so we will need to add a new sequence to the CA
-def AnalysisAlgsCfg(
-    flags,
-    btag_wps,
-    vr_btag_wps,
-    trigger_chains=[],
-    do_muons=True,
-    metadata_cache=None,
-    do_loose=False,
-):
-    fileMD = GetFileMD(flags.Input.Files[0])
-    if metadata_cache:
-        update_metadata(metadata_cache)
-    dataType = "mc" if flags.Input.isMC else "data"
-    is_daod_physlite = _is_physlite(flags)
-    log.info(
-        f"Self-configured: dataType: '{dataType}', is PHYSLITE? {is_daod_physlite}"
-    )
-
-    log.debug(f"Containers available in dataset: {flags.Input.Collections}")
-
-    # TODO: no DL1d branches in PHYSLITE yet
-    if is_daod_physlite:
-        btag_wps = [wp.replace("DL1dv00", "DL1r") for wp in btag_wps]
-
-    cfg = ComponentAccumulator()
-
-    # Create SystematicsSvc explicitly:
-    cfg.addService(CompFactory.getComp("CP::SystematicsSvc")("SystematicsSvc"))
-
-    log.info("Adding trigger analysis algs")
-    # Removes events failing trigger and adds variable to EventInfo
-    # if trigger passed or not, for example:
-    # EventInfo.trigger_name
-    cfg.merge(TriggerAnalysisSequenceCfg(flags, dataType, trigger_chains))
-
-    log.info("Add DQ event filter sequence")
-    # Remove events failing DQ criteria
-    cfg.merge(
-        EventSelectionAnalysisSequenceCfg(flags, dataType, grlFiles=[], loose=do_loose)
-    )
-
-    doPRW = _is_mc_phys(flags)
-    log.info(
-        f"Do PRW is {doPRW}. {'Add' if doPRW else 'Skip'} pileup re-weight sequence"
-    )
-    if doPRW:
-        try:
-            prwFiles, lumicalcFiles = pileupConfigFiles(fileMD)
-            # Adds variable to EventInfo if for pileup weight, for example:
-            # EventInfo.PileWeight_%SYS$
-            cfg.merge(
-                PileupAnalysisSequenceCfg(
-                    flags,
-                    dataType=dataType,
-                    prwFiles=prwFiles,
-                    lumicalcFiles=lumicalcFiles,
-                )
-            )
-
-            log.info("Adding generator analysis sequence")
-            # Adds variable to EventInfo if for generator weight, for example:
-            # EventInfo.generatorWeight_%SYS%
-            cfg.merge(GeneratorAnalysisSequenceCfg(flags, dataType))
-
-        except LookupError as err:
-            log.error(err)
-            doPRW = False
-
-    containers = _get_container_names(flags)
-
-    log.info("Add electron seq")
-    cfg.merge(
-        ElectronAnalysisSequenceCfg(
-            flags,
-            dataType=dataType,
-            inputContainerName=containers["inputs"]["electrons"],
-            outputContainerName=containers["outputs"]["electrons"],
-        )
-    )
-
-    log.info("Add photon seq")
-    cfg.merge(
-        PhotonAnalysisSequenceCfg(
-            flags,
-            dataType=dataType,
-            inputContainerName=containers["inputs"]["photons"],
-            outputContainerName=containers["outputs"]["photons"],
-        )
-    )
-
-    if do_muons:
-        log.info("Add muon seq")
-        cfg.merge(
-            MuonAnalysisSequenceCfg(
-                flags,
-                dataType=dataType,
-                inputContainerName=containers["inputs"]["muons"],
-                outputContainerName=containers["outputs"]["muons"],
-            )
-        )
-
-    log.info("Add jet seq")
-    cfg.merge(
-        JetAnalysisSequenceCfg(
-            flags,
-            dataType=dataType,
-            inputContainerName=containers["inputs"]["reco4Jet"],
-            outputContainerName=containers["outputs"]["reco4Jet"],
-            workingPoints=btag_wps,
-            is_daod_physlite=is_daod_physlite,
-        )
-    )
-
-    if is_daod_physlite:
-        log.warning("On PHYSLITE, skip large-R jet sequence for now")
-    else:
-        log.info("Add large-R jet seq")
-        cfg.merge(
-            FatJetAnalysisSequenceCfg(
-                flags,
-                dataType=dataType,
-                inputContainerName=containers["inputs"]["reco10Jet"],
-                outputContainerName=containers["outputs"]["reco10Jet"],
-            )
-        )
-
-    if is_daod_physlite:
-        log.warning("On PHYSLITE, skip VR jet sequence for now")
-    else:
-        log.info("Add VR jet seq")
-        cfg.merge(
-            VRJetAnalysisSequenceCfg(
-                flags,
-                dataType=dataType,
-                inputContainerName=containers["inputs"]["vrJet"],
-                outputContainerName=containers["outputs"]["vrJet"],
-                workingPoints=vr_btag_wps,
-            )
-        )
-
-    ########################################################################
-    # Begin postprocessing
-    ########################################################################
-
-    log.info("Add Overlap Removal sequence")
-    overlapInputNames = {
-        "electrons": containers["outputs"]["electrons"],
-        "photons": containers["outputs"]["photons"],
-        "jets": containers["outputs"]["reco4Jet"],
-    }
-    if do_muons:
-        overlapInputNames["muons"] = containers["outputs"]["muons"]
-
-    if not is_daod_physlite:
-        overlapInputNames["fatJets"] = containers["outputs"]["reco10Jet"]
-
-    overlapOutputNames = {k: f"{v}_OR" for k, v in overlapInputNames.items()}
-
-    cfg.merge(
-        OverlapAnalysisSequenceCfg(
-            flags,
-            dataType=dataType,
-            inputNames=overlapInputNames,
-            outputNames=overlapOutputNames,
-            doFatJets=not is_daod_physlite,
-            doMuons=do_muons,
-        )
-    )
-
-    if metadata_cache:
-        cache_metadata(metadata_cache)
-
-    cfg.addEventAlgo(
-        CompFactory.HH4B.VariableDumperAlg(
-            "VariableDumper",
-            EventInfoKey="EventInfo",
-            RootStreamName="ANALYSIS",
-        )
-    )
-
-    return cfg
-
-
-def MiniTupleCfg(
-    flags,
-    outfname,
-    trigger_chains,
-    working_points,
-    do_muons=True,
-):
-    cfg = ComponentAccumulator()
-    is_daod_physlite = _is_physlite(flags)
-    doPRW = _is_mc_phys(flags)
-    containers = _get_container_names(flags)["outputs"]
-
-    log.debug(f"Containers requested in dataset: {containers}")
-
-    ########################################################################
-    # Create analysis mini-ntuple
-    ########################################################################
-
-    # Add an instance of THistSvc, to create the output file and associated stream.
-    # This is needed so that the alg can register its output TTree.
-    # The syntax for the output is:
-    #   Stream name: "ANALYSIS" (default assumed by AthHistogramAlgorithm)
-    #   Output file name: specified by setting "DATAFILE"
-    #   File I/O option: specified by setting "OPT" and passed to the TFile constructor
-    #      "RECREATE" will (over)write the specified file name with a new file
-    cfg.addService(
-        CompFactory.THistSvc(Output=[f"ANALYSIS DATAFILE='{outfname}', OPT='RECREATE'"])
-    )
-
-    def getFourMomBranches(container, alias, doOR=False):
-        ORstr = "_OR" if doOR else ""
-
-        branches = []
-        vars = ["pt", "eta", "phi"]
-        if "Jets" in container:
-            vars.append("m")
-        for var in vars:
-            branches += [
-                f"{container}{ORstr}.{var}  -> {alias}{ORstr}_%SYS%_{var}",
-            ]
-        return branches
-
-    analysisTreeBranches = [
-        "EventInfo.runNumber     -> runNumber",
-        "EventInfo.eventNumber   -> eventNumber",
-        "EventInfo.mcEventWeights   -> mcEventWeights",
-        "EventInfo.averageInteractionsPerCrossing -> averageInteractionsPerCrossing",
-    ]
-
-    for trig_chain in trigger_chains:
-        cleaned = trig_chain.replace("-", "_")
-        if "." in trig_chain:
-            continue
-        analysisTreeBranches.append(
-            f"EventInfo.trigPassed_{cleaned} -> trigPassed_{cleaned}"
-        )
-
-    if doPRW:
-        analysisTreeBranches += [
-            "EventInfo.PileupWeight_%SYS% -> pileupWeight_%SYS%",
-            "EventInfo.generatorWeight_%SYS% -> generatorWeight_%SYS%",
-        ]
-    else:
-        analysisTreeBranches += [
-            "EventInfo.mcEventWeights -> pileupWeight_NOSYS",
-        ]
-
-    objectpairs = {
-        containers["electrons"]: "el",
-        containers["photons"]: "ph",
-        containers["reco4Jet"]: "recojet_antikt4",
-    }
-    if do_muons:
-        containers["muons"] = "mu"
-
-    for cont, alias in objectpairs.items():
-        analysisTreeBranches += getFourMomBranches(cont, alias)
-        analysisTreeBranches += getFourMomBranches(cont, alias, doOR=True)
-
-    # B-jet WPs
-    analysisTreeBranches += [
-        f"{containers['reco4Jet']}.ftag_select_{btag_wp}"
-        f" -> recojet_antikt4_%SYS%_{btag_wp}"
-        for btag_wp in working_points["ak4"]
-    ]
-    analysisTreeBranches += [
-        f"{containers['reco4Jet']}_OR.ftag_select_{btag_wp}"
-        f" -> recojet_antikt4_OR_%SYS%_{btag_wp}"
-        for btag_wp in working_points["ak4"]
-    ]
-
-    if not is_daod_physlite:
-        analysisTreeBranches += getFourMomBranches(
-            containers["reco10Jet"], "recojet_antikt10"
-        )
-        analysisTreeBranches += getFourMomBranches(
-            containers["reco10Jet"], "recojet_antikt10", doOR=True
-        )
-        analysisTreeBranches += getFourMomBranches(containers["vrJet"], "vrjet")
-        analysisTreeBranches += [
-            f"{containers['vrJet']}.ftag_select_{btag_wp} -> vrjet_%SYS%_{btag_wp}"
-            for btag_wp in working_points["vr"]
-        ]
-
-    log.info("Add tree seq")
-    cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
-
-    return cfg
-
-
-# CA modules are intended to be executable, to facilitate easy testing.
-# We define a "main function" that will run a test job if the module
-# is executed rather than imported.
-def main():
-    # Import the job configuration flags, some of which will be autoconfigured.
-    # These are used for steering the job, and include e.g. the input file (list).
-    from AthenaConfiguration.AllConfigFlags import ConfigFlags
-
-    # Get the arguments, defined at the top for easy browsing
-    parser = defineArgs(ConfigFlags)
-    args = ConfigFlags.fillFromArgs([], parser)
-    # Lock the flags so that the configuration of job subcomponents cannot
-    # modify them silently/unpredictably.
-    # Workaround for buggy glob, needed prior
-    # to https://gitlab.cern.ch/atlas/athena/-/merge_requests/55561
-    if ConfigFlags.Input.Files[0] == "_ATHENA_GENERIC_INPUTFILE_NAME_":
-        ConfigFlags.Input.Files = ConfigFlags.Input.Files[1:]
-    log.info(f"Operating on input files {ConfigFlags.Input.Files}")
-    ConfigFlags.lock()
-
-    # Get a ComponentAccumulator setting up the standard components
-    # needed to run an Athena job.
-    # Setting temporarily needed for Run 3 code, to generate python
-    # Configurable objects for deduplication
-    from AthenaCommon.Configurable import ConfigurableRun3Behavior
-    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
-
-    with ConfigurableRun3Behavior():
-
-        cfg = MainServicesCfg(ConfigFlags)
-
-        from EventBookkeeperTools.EventBookkeeperToolsConfig import (
-            BookkeeperToolCfg,
-            CutFlowSvcCfg,
-        )
-
-        # Create CutFlowSvc otherwise the default CutFlowSvc that has only
-        # one CutflowBookkeeper object, and can't deal with multiple weights
-        cfg.merge(CutFlowSvcCfg(ConfigFlags))
-        cfg.merge(BookkeeperToolCfg(ConfigFlags))
-
-        # Adjust the loop manager to announce the event number less frequently.
-        # Makes a big difference if running over many events
-        if ConfigFlags.Concurrency.NumThreads > 0:
-            cfg.addService(
-                CompFactory.AthenaHiveEventLoopMgr(EventPrintoutInterval=500)
-            )
-        else:
-            cfg.addService(CompFactory.AthenaEventLoopMgr(EventPrintoutInterval=500))
-
-        from HH4bAnalysis.Config.xAODEventSelectorConfig import xAODReadCfg
-
-        cfg.merge(xAODReadCfg(ConfigFlags))
-
-        # Add our VariableDumper CA, calling the function defined above.
-        from HH4bAnalysis.Config.TriggerLists import TriggerLists
-
-        trigger_chains = TriggerLists[args.trigger_list]
-        do_muons = not args.meta_cache
-
-        cfg.addSequence(CompFactory.AthSequencer("HH4bSeq"), "AthAlgSeq")
-        cfg.merge(
-            AnalysisAlgsCfg(
-                ConfigFlags,
-                btag_wps=args.btag_wps,
-                vr_btag_wps=args.vr_btag_wps,
-                trigger_chains=trigger_chains,
-                metadata_cache=args.meta_cache,
-                do_muons=do_muons,
-                do_loose=args.loose,
-            ),
-            "HH4bSeq",
-        )
-        cfg.merge(
-            MiniTupleCfg(
-                ConfigFlags,
-                outfname=args.outFile,
-                trigger_chains=trigger_chains,
-                working_points={"ak4": args.btag_wps, "vr": args.vr_btag_wps},
-                do_muons=do_muons,
-            ),
-            "HH4bSeq",
-        )
-
-        # Print the full job configuration
-        cfg.printConfig(summariseProps=False)
-
-    # Execute the job defined in the ComponentAccumulator.
-    # The number of events is specified by `args.evtMax`
-    return cfg.run(args.evtMax)
-
-
-# Execute the main function if this file was executed as a script
-if __name__ == "__main__":
-    code = main()
-    sys.exit(0 if code.isSuccess() else 1)
-- 
GitLab


From a88a634e3f9bc57002533c380c20cd0561ae45cf Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Fri, 12 Aug 2022 18:33:46 +0200
Subject: [PATCH 17/33] adapted to new master

---
 HH4bAnalysis/share/VariableDumperConfig.py | 28 +++++++++++-----------
 HH4bAnalysis/src/DiHiggsAnalysis.cxx       | 10 ++++----
 HH4bAnalysis/src/VariableDumperAlg.h       |  1 -
 3 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index ea6380b39..cc042536b 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -308,9 +308,9 @@ def AnalysisAlgsCfg(
             EventInfoKey="EventInfo",
             ElectronsKey=containers["outputs"]["electrons"],
             PhotonsKey=containers["outputs"]["photons"],
-            MuonsKey=containers["inputs"]["muons"],
+            MuonsKey=containers["outputs"]["muons"],
             SmallJetKey=containers["outputs"]["reco4Jet"],
-            LargeJetKey=containers["inputs"]["reco10Jet"],
+            LargeJetKey=containers["outputs"]["reco10Jet"],
             VRtrackjets=containers["outputs"]["vrJet"],
         )
     )
@@ -421,18 +421,18 @@ def MiniTupleCfg(
             f"{containers['vrJet']}.ftag_select_{btag_wp} -> vrjet_%SYS%_{btag_wp}"
             for btag_wp in working_points["vr"]
         ]
-    # analysisTreeBranches = [
-    #     "EventInfo.resolved_m_h1   -> resolved_m_h1",
-    #     "EventInfo.resolved_m_h2   -> resolved_m_h2",
-    #     "EventInfo.resolved_m_hh   -> resolved_m_hh",
-    #     "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
-    #     "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
-    #     "EventInfo.boosted_m_h1   -> boosted_m_h1",
-    #     "EventInfo.boosted_m_h2   -> boosted_m_h2",
-    #     "EventInfo.boosted_m_hh   -> boosted_m_hh",
-    #     "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
-    #     "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
-    # ]
+    analysisTreeBranches = [
+        "EventInfo.resolved_m_h1   -> resolved_m_h1",
+        "EventInfo.resolved_m_h2   -> resolved_m_h2",
+        "EventInfo.resolved_m_hh   -> resolved_m_hh",
+        "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
+        "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
+        "EventInfo.boosted_m_h1   -> boosted_m_h1",
+        "EventInfo.boosted_m_h2   -> boosted_m_h2",
+        "EventInfo.boosted_m_hh   -> boosted_m_hh",
+        "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
+        "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
+    ]
     log.info("Add tree seq")
     cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
 
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index c137cfcd2..41aebebfb 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -3,6 +3,8 @@
 #include "tools/kLargestJets.h"
 #include <AsgMessaging/MessageCheck.h>
 #include <AthContainers/ConstDataVector.h>
+#include <TLorentzVector.h>
+
 using namespace asg::msgUserCode;
 
 namespace HH4B
@@ -113,12 +115,12 @@ namespace HH4B
     h2.largeRjetIndex = twoLeadingPtLargeRjetsIndices[1];
 
     // ghost associated track jets are only on the untrimmed 1.0 jets
-    SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
+    static const SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
         m_acc_largeR_untrimmed("Parent");
-    SG::AuxElement::ConstAccessor<
+    static const SG::AuxElement::ConstAccessor<
         std::vector<ElementLink<xAOD::IParticleContainer>>>
         m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
-    SG::AuxElement::ConstAccessor<char> isBtag(
+    static const SG::AuxElement::ConstAccessor<char> isBtag(
         "ftag_select_DL1r_FixedCutBEff_77");
 
     // loop over the two large R jets to get the btagged VR jets inside of each
@@ -129,7 +131,7 @@ namespace HH4B
       const xAOD::Jet *thisJet = largeRjets->at(h.largeRjetIndex);
       // get ghost associated VR track jets from untrimmed large R jet
       const xAOD::Jet *thisJet_untrimmed = *m_acc_largeR_untrimmed(*thisJet);
-      const std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
+      std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
           m_acc_VRTrackJets(*thisJet_untrimmed);
       // get the btagged VR trackjets per large R jet
       for (ElementLink<xAOD::IParticleContainer> VRjet : VRTrackjets)
diff --git a/HH4bAnalysis/src/VariableDumperAlg.h b/HH4bAnalysis/src/VariableDumperAlg.h
index cdb0b9f87..623342990 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.h
+++ b/HH4bAnalysis/src/VariableDumperAlg.h
@@ -20,7 +20,6 @@
 #include <AthContainers/AuxElement.h>
 #include <SystematicsHandles/SysListHandle.h>
 #include <SystematicsHandles/SysReadHandle.h>
-#include <TLorentzVector.h>
 #include <xAODEgamma/ElectronContainer.h>
 #include <xAODEgamma/PhotonContainer.h>
 #include <xAODEventInfo/EventInfo.h>
-- 
GitLab


From 3ad7449ea9d548d41d8daed4c2ea6aad73a4d597 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Mon, 15 Aug 2022 18:32:14 +0200
Subject: [PATCH 18/33] moved to std::partial_sort for resolved

---
 HH4bAnalysis/src/DiHiggsAnalysis.cxx | 78 ++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 23 deletions(-)

diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index 41aebebfb..c7a45bd7d 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -40,38 +40,70 @@ namespace HH4B
     // need to do this because sequence filtering destroys order
     std::vector<int> fourLeadingPtJetsIndices = kLargestJets(smallRjets, 4);
 
-    // get largest pt jet
-    h1.leadingJet = smallRjets->at(fourLeadingPtJetsIndices[0]);
-
-    // calculate dR to other jets to find closest one
-    double minDR = -1;
-    int minDRindex = -1;
-    for (int jetIndex : fourLeadingPtJetsIndices)
+    // taken from TJ's tutorial
+    // https://gitlab.cern.ch/khoo/athanalysistutorial/-/blob/r22/MySecondAthAnalysis/src/DileptonFinderAlg.cxx
+    ConstDataVector<xAOD::JetContainer> ptSortedJets(
+        smallRjets->begin(), smallRjets->end(), SG::VIEW_ELEMENTS);
+    std::partial_sort(
+        ptSortedJets.begin(),     // Iterator from which to start sorting
+        ptSortedJets.begin() + 4, // Use begin + N to sort first N
+        ptSortedJets.end(), // Iterator marking the end of the range to sort
+        [](const xAOD::IParticle *left, const xAOD::IParticle *right)
+        { return left->pt() > right->pt(); });
+
+    // get the leading b-jet for the leading Higgs candidate
+    h1.leadingJet = ptSortedJets[0];
+
+    // calculate dR to the next three leading jets and decorate jet
+    static const SG::AuxElement::Decorator<float> dRtoLeadingJet_dec(
+        "dRtoLeadingJet");
+    static const SG::AuxElement::ConstAccessor<float> dRtoLeadingJet_acc(
+        "dRtoLeadingJet");
+
+    // keep only the four leading ones
+    ptSortedJets.erase(ptSortedJets.begin() + 4, ptSortedJets.end());
+
+    // decorate dR(jet,leading jet) to each jet
+    bool firstJet = true;
+    for (const xAOD::Jet *jet : ptSortedJets)
     {
-      const xAOD::Jet *thisJet = smallRjets->at(jetIndex);
-      double thisDRtoLeadingJet = thisJet->p4().DeltaR(h1.leadingJet->p4());
-      if (thisDRtoLeadingJet > 0 or minDR > thisDRtoLeadingJet)
+      // easier to read than done with iterators
+      if (firstJet)
       {
-        minDR = thisDRtoLeadingJet;
-        minDRindex = jetIndex;
+        dRtoLeadingJet_dec(*jet) = 0;
+        firstJet = false;
+        continue;
       }
+      dRtoLeadingJet_dec(*jet) = jet->p4().DeltaR(h1.leadingJet->p4());
     }
 
-    h1.subleadingJet = smallRjets->at(minDRindex);
-    // calculate higgs candidate four vector and dR between jets
-    h1.fourVector = h1.leadingJet->p4() + h1.subleadingJet->p4();
-    h1.dRjets = h1.leadingJet->p4().DeltaR(h1.subleadingJet->p4());
+    ConstDataVector<xAOD::JetContainer> dRsortedJets = ptSortedJets;
+    // find the closest one
+    std::partial_sort(
+        dRsortedJets.begin(),     // Iterator from which to start sorting
+        dRsortedJets.begin() + 4, // Use begin + N to sort first N
+        dRsortedJets.end(), // Iterator marking the end of the range to sort
+        [](const xAOD::IParticle *left, const xAOD::IParticle *right)
+        { return dRtoLeadingJet_acc(*left) > dRtoLeadingJet_acc(*right); });
+
+    h1.subleadingJet = dRsortedJets[1];
 
-    // get jet indices of subleading higgs candidate h2
-    std::vector<int> h2_indices;
-    for (int jetIndex : fourLeadingPtJetsIndices)
+    // get the jets for h2
+    if (dRsortedJets[2]->pt() > dRsortedJets[3]->pt())
     {
-      if (jetIndex != fourLeadingPtJetsIndices[0] and jetIndex != minDRindex)
-        h2_indices.push_back(jetIndex);
+      h2.leadingJet = dRsortedJets[2];
+      h2.subleadingJet = dRsortedJets[3];
+    }
+    else
+    {
+      h2.leadingJet = dRsortedJets[3];
+      h2.subleadingJet = dRsortedJets[2];
     }
 
-    h2.leadingJet = smallRjets->at(h2_indices[0]);
-    h2.subleadingJet = smallRjets->at(h2_indices[1]);
+    // calculate higgs candidate four vector and dR between jets in Higgs
+    // candidate
+    h1.fourVector = h1.leadingJet->p4() + h1.subleadingJet->p4();
+    h1.dRjets = dRtoLeadingJet_acc(*h1.subleadingJet);
     h2.fourVector = h2.leadingJet->p4() + h2.subleadingJet->p4();
     h2.dRjets = h2.leadingJet->p4().DeltaR(h2.subleadingJet->p4());
 
-- 
GitLab


From 82c2fa0b75ccd180a10e6dbdf9f7786fc049de41 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Wed, 17 Aug 2022 10:03:30 +0200
Subject: [PATCH 19/33] moved to std::partial_sort

---
 HH4bAnalysis/CMakeLists.txt             |   1 -
 HH4bAnalysis/src/DiHiggsAnalysis.cxx    | 171 +++++++++++++-----------
 HH4bAnalysis/src/DiHiggsAnalysis.h      |  13 +-
 HH4bAnalysis/src/tools/kLargestJets.cxx |  49 -------
 HH4bAnalysis/src/tools/kLargestJets.h   |  18 ---
 5 files changed, 95 insertions(+), 157 deletions(-)
 delete mode 100644 HH4bAnalysis/src/tools/kLargestJets.cxx
 delete mode 100644 HH4bAnalysis/src/tools/kLargestJets.h

diff --git a/HH4bAnalysis/CMakeLists.txt b/HH4bAnalysis/CMakeLists.txt
index 7ff765547..6e1c3cf1e 100644
--- a/HH4bAnalysis/CMakeLists.txt
+++ b/HH4bAnalysis/CMakeLists.txt
@@ -19,7 +19,6 @@ atlas_add_component(HH4bAnalysis
   src/VariableDumperAlg.cxx
   src/DiHiggsAnalysis.cxx
   src/tools/NTrkVertexCounter.cxx
-  src/tools/kLargestJets.cxx
   src/components/*.cxx
   LINK_LIBRARIES
   GaudiKernel
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index c7a45bd7d..79148dc32 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -1,6 +1,6 @@
 
 #include "DiHiggsAnalysis.h"
-#include "tools/kLargestJets.h"
+#include "AthenaBaseComps/AthCommonMsg.h"
 #include <AsgMessaging/MessageCheck.h>
 #include <AthContainers/ConstDataVector.h>
 #include <TLorentzVector.h>
@@ -36,23 +36,25 @@ namespace HH4B
     // subleading higgs candidate
     HiggsCandidate h2;
 
-    // get indices of 4 largest pt jets in descending order
-    // need to do this because sequence filtering destroys order
-    std::vector<int> fourLeadingPtJetsIndices = kLargestJets(smallRjets, 4);
-
     // taken from TJ's tutorial
     // https://gitlab.cern.ch/khoo/athanalysistutorial/-/blob/r22/MySecondAthAnalysis/src/DileptonFinderAlg.cxx
+    //
+    // this is a shallow copy container
     ConstDataVector<xAOD::JetContainer> ptSortedJets(
         smallRjets->begin(), smallRjets->end(), SG::VIEW_ELEMENTS);
+    // with std::partial_sort you only have to sort an N-sized container
+    // instead of sorting a ptSortedJets.size() container
     std::partial_sort(
         ptSortedJets.begin(),     // Iterator from which to start sorting
         ptSortedJets.begin() + 4, // Use begin + N to sort first N
         ptSortedJets.end(), // Iterator marking the end of the range to sort
         [](const xAOD::IParticle *left, const xAOD::IParticle *right)
-        { return left->pt() > right->pt(); });
+        {
+          return left->pt() > right->pt();
+        }); // lambda function here just handy, could also be another function
 
     // get the leading b-jet for the leading Higgs candidate
-    h1.leadingJet = ptSortedJets[0];
+    h1.m_leadingJet = ptSortedJets[0];
 
     // calculate dR to the next three leading jets and decorate jet
     static const SG::AuxElement::Decorator<float> dRtoLeadingJet_dec(
@@ -67,18 +69,18 @@ namespace HH4B
     bool firstJet = true;
     for (const xAOD::Jet *jet : ptSortedJets)
     {
-      // easier to read than done with iterators
+      // more instructive as done with iterators
       if (firstJet)
       {
         dRtoLeadingJet_dec(*jet) = 0;
         firstJet = false;
         continue;
       }
-      dRtoLeadingJet_dec(*jet) = jet->p4().DeltaR(h1.leadingJet->p4());
+      dRtoLeadingJet_dec(*jet) = jet->p4().DeltaR(h1.m_leadingJet->p4());
     }
 
+    // now find the closest one
     ConstDataVector<xAOD::JetContainer> dRsortedJets = ptSortedJets;
-    // find the closest one
     std::partial_sort(
         dRsortedJets.begin(),     // Iterator from which to start sorting
         dRsortedJets.begin() + 4, // Use begin + N to sort first N
@@ -86,33 +88,34 @@ namespace HH4B
         [](const xAOD::IParticle *left, const xAOD::IParticle *right)
         { return dRtoLeadingJet_acc(*left) > dRtoLeadingJet_acc(*right); });
 
-    h1.subleadingJet = dRsortedJets[1];
+    // first one is dr to the leading itself, therefore second one
+    h1.m_subleadingJet = dRsortedJets[1];
 
     // get the jets for h2
     if (dRsortedJets[2]->pt() > dRsortedJets[3]->pt())
     {
-      h2.leadingJet = dRsortedJets[2];
-      h2.subleadingJet = dRsortedJets[3];
+      h2.m_leadingJet = dRsortedJets[2];
+      h2.m_subleadingJet = dRsortedJets[3];
     }
     else
     {
-      h2.leadingJet = dRsortedJets[3];
-      h2.subleadingJet = dRsortedJets[2];
+      h2.m_leadingJet = dRsortedJets[3];
+      h2.m_subleadingJet = dRsortedJets[2];
     }
 
     // calculate higgs candidate four vector and dR between jets in Higgs
     // candidate
-    h1.fourVector = h1.leadingJet->p4() + h1.subleadingJet->p4();
-    h1.dRjets = dRtoLeadingJet_acc(*h1.subleadingJet);
-    h2.fourVector = h2.leadingJet->p4() + h2.subleadingJet->p4();
-    h2.dRjets = h2.leadingJet->p4().DeltaR(h2.subleadingJet->p4());
+    h1.m_fourVector = h1.m_leadingJet->p4() + h1.m_subleadingJet->p4();
+    h1.m_dRjets = dRtoLeadingJet_acc(*h1.m_subleadingJet);
+    h2.m_fourVector = h2.m_leadingJet->p4() + h2.m_subleadingJet->p4();
+    h2.m_dRjets = h2.m_leadingJet->p4().DeltaR(h2.m_subleadingJet->p4());
 
     // write to dictionary
-    h_cand_vars["resolved_m_h1"] = h1.fourVector.M();
-    h_cand_vars["resolved_m_h2"] = h2.fourVector.M();
-    h_cand_vars["resolved_m_hh"] = (h1.fourVector + h2.fourVector).M();
-    h_cand_vars["resolved_dR_jets_in_h1"] = h1.dRjets;
-    h_cand_vars["resolved_dR_jets_in_h2"] = h2.dRjets;
+    h_cand_vars["resolved_m_h1"] = h1.m_fourVector.M();
+    h_cand_vars["resolved_m_h2"] = h2.m_fourVector.M();
+    h_cand_vars["resolved_m_hh"] = (h1.m_fourVector + h2.m_fourVector).M();
+    h_cand_vars["resolved_dR_jets_in_h1"] = h1.m_dRjets;
+    h_cand_vars["resolved_dR_jets_in_h2"] = h2.m_dRjets;
 
     return;
   };
@@ -141,12 +144,21 @@ namespace HH4B
     HiggsCandidate h1;
     // subleading higgs candidate
     HiggsCandidate h2;
-    std::vector<int> twoLeadingPtLargeRjetsIndices =
-        kLargestJets(largeRjets, 2);
-    h1.largeRjetIndex = twoLeadingPtLargeRjetsIndices[0];
-    h2.largeRjetIndex = twoLeadingPtLargeRjetsIndices[1];
 
-    // ghost associated track jets are only on the untrimmed 1.0 jets
+    // get the leading large R, see resvoled analysis for details
+    ConstDataVector<xAOD::JetContainer> ptSortedLargeRJets(
+        largeRjets->begin(), largeRjets->end(), SG::VIEW_ELEMENTS);
+    std::partial_sort(
+        ptSortedLargeRJets.begin(),     // Iterator from which to start sorting
+        ptSortedLargeRJets.begin() + 2, // Use begin + N to sort first N
+        ptSortedLargeRJets.end(),       // iterator to end
+        [](const xAOD::IParticle *left, const xAOD::IParticle *right)
+        { return left->pt() > right->pt(); });
+
+    h1.m_largeRJet = ptSortedLargeRJets[0];
+    h2.m_largeRJet = ptSortedLargeRJets[1];
+
+    // ghost associated VR track jets are only on the untrimmed 1.0 jets
     static const SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
         m_acc_largeR_untrimmed("Parent");
     static const SG::AuxElement::ConstAccessor<
@@ -155,74 +167,69 @@ namespace HH4B
     static const SG::AuxElement::ConstAccessor<char> isBtag(
         "ftag_select_DL1r_FixedCutBEff_77");
 
-    // loop over the two large R jets to get the btagged VR jets inside of each
-    // need to do std::ref to access the actual objects h1, h2
+    // loop over the Higgs Candidate large R jets to get the btagged VR jets
+    // inside of each, need to do std::ref to access the actual objects h1, h2
     // "for (HiggsCandidate h : {h1, h2})" would make copies of h1, h2
     for (HiggsCandidate &h : {std::ref(h1), std::ref(h2)})
     {
-      const xAOD::Jet *thisJet = largeRjets->at(h.largeRjetIndex);
       // get ghost associated VR track jets from untrimmed large R jet
-      const xAOD::Jet *thisJet_untrimmed = *m_acc_largeR_untrimmed(*thisJet);
+      const xAOD::Jet *untrimmedLargeR =
+          *m_acc_largeR_untrimmed(*h.m_largeRJet);
       std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
-          m_acc_VRTrackJets(*thisJet_untrimmed);
+          m_acc_VRTrackJets(*untrimmedLargeR);
+
       // get the btagged VR trackjets per large R jet
-      for (ElementLink<xAOD::IParticleContainer> VRjet : VRTrackjets)
-      {
-        auto &test = VRjet;
-        // check if VRjet link is valid
-        // should we handle this differently?
-        if (!test.isValid())
-        {
-          ANA_MSG_WARNING("Invalid track link found!");
-          continue;
-        }
-        // VRtrack ftag sequence does not tag all of them, so take only the
-        // btagged ones
-        if (!isBtag.isAvailable(**VRjet))
-        {
-          ANA_MSG_WARNING("Skipped non B-tagged VR jet");
-          continue;
-        }
-        h.btagged_VRTrackjets.push_back(VRjet);
-      }
-    }
+      // remove VRjets with invalid elementlinks and non-btagged ones
+      // should we handle this differently?
+      // can't just remove in for loop, get in trouble with iterator, could do
+      // with while loop but std::remove_if is more efficient
+      VRTrackjets.erase(
+          std::remove_if(VRTrackjets.begin(), VRTrackjets.end(),
+                         [](ElementLink<xAOD::IParticleContainer> &VRjet)
+                         {
+                           if (!VRjet.isValid())
+                           {
+                             ANA_MSG_WARNING("Skipped invalid VR jet link!");
+                             return true;
+                           }
+                           if (!isBtag.isAvailable(**VRjet))
+                           {
+                             ANA_MSG_DEBUG("Skipped non B-tagged VR jet");
+                             return true;
+                           }
+                           return false;
+                         }),
+          VRTrackjets.end());
 
-    // find the leading vr jets
-    for (HiggsCandidate &h : {std::ref(h1), std::ref(h2)})
-    {
       // check if we have at least 2 per large R jet, otherwise exit
-      // (subject to change)
-      if (h.btagged_VRTrackjets.size() < 2)
+      if (VRTrackjets.size() < 2)
       {
         return;
       }
 
-      // cast VRjet to xAOD::jet to use kLargestJets sorting function
-      // we do it this way since we want to make shallow copies
-      ConstDataVector<xAOD::JetContainer> tmpVRjets(SG::VIEW_ELEMENTS);
-      for (auto VRjet : h.btagged_VRTrackjets)
-      {
-        const auto *jet = dynamic_cast<const xAOD::Jet *>(*VRjet);
-        tmpVRjets.push_back(jet);
-      }
-      // write leading and subleading vr jet onto HiggsCandidate objects
-      std::vector<int> twoLeadingVrJetIndices =
-          kLargestJets(tmpVRjets.asDataVector(), 2);
-      h.leadingJet = dynamic_cast<const xAOD::Jet *>(
-          *h.btagged_VRTrackjets[twoLeadingVrJetIndices[0]]);
-      h.subleadingJet = dynamic_cast<const xAOD::Jet *>(
-          *h.btagged_VRTrackjets[twoLeadingVrJetIndices[1]]);
+      // find the leading vr jets
+      std::partial_sort(
+          VRTrackjets.begin(),     // Iterator from which to start sorting
+          VRTrackjets.begin() + 2, // Use begin + N to sort first N
+          VRTrackjets.end(),       // iterator to end
+          [](ElementLink<xAOD::IParticleContainer> &left,
+             ElementLink<xAOD::IParticleContainer> &right)
+          { return (*left)->pt() > (*right)->pt(); });
+
+      h.m_leadingJet = dynamic_cast<const xAOD::Jet *>(*VRTrackjets[0]);
+      h.m_subleadingJet = dynamic_cast<const xAOD::Jet *>(*VRTrackjets[1]);
+
       // calc variables
-      h.fourVector = h.leadingJet->p4() + h.subleadingJet->p4();
-      h.dRjets = h.leadingJet->p4().DeltaR(h.subleadingJet->p4());
+      h.m_fourVector = h.m_leadingJet->p4() + h.m_subleadingJet->p4();
+      h.m_dRjets = h.m_leadingJet->p4().DeltaR(h.m_subleadingJet->p4());
     }
 
     // write to dictionary
-    h_cand_vars["boosted_m_h1"] = h1.fourVector.M();
-    h_cand_vars["boosted_m_h2"] = h2.fourVector.M();
-    h_cand_vars["boosted_m_hh"] = (h1.fourVector + h2.fourVector).M();
-    h_cand_vars["boosted_dR_jets_in_h1"] = h1.dRjets;
-    h_cand_vars["boosted_dR_jets_in_h2"] = h2.dRjets;
+    h_cand_vars["boosted_m_h1"] = h1.m_fourVector.M();
+    h_cand_vars["boosted_m_h2"] = h2.m_fourVector.M();
+    h_cand_vars["boosted_m_hh"] = (h1.m_fourVector + h2.m_fourVector).M();
+    h_cand_vars["boosted_dR_jets_in_h1"] = h1.m_dRjets;
+    h_cand_vars["boosted_dR_jets_in_h2"] = h2.m_dRjets;
     return;
   };
 
@@ -233,6 +240,8 @@ namespace HH4B
 
   void DiHiggsAnalysis::decorateHiggsVars(const xAOD::EventInfo &eventInfo)
   {
+    // static const SG::AuxElement::Decorator<float> HiggsVars_dec(
+    // "dRtoLeadingJet");
     // the range looks weird, but its just a loop over the h_cand_vars map
     for (const auto &[key, value] : h_cand_vars)
     {
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index 9ff5cd839..d28bc0bdb 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -14,17 +14,14 @@ namespace HH4B
   struct HiggsCandidate
   {
     // b-jets for Higgs candidate
-    const xAOD::Jet *leadingJet = nullptr;
-    const xAOD::Jet *subleadingJet = nullptr;
+    const xAOD::Jet *m_leadingJet = nullptr;
+    const xAOD::Jet *m_subleadingJet = nullptr;
     // four vector of Higgs candidate
-    TLorentzVector fourVector;
+    TLorentzVector m_fourVector;
     // dR between leading and subleading jet
-    double dRjets = -1;
-
+    double m_dRjets = -1;
     // for boosted analysis
-    int largeRjetIndex = -1;
-    // btagged ghost associated VR track jets inside the large R jet
-    std::vector<ElementLink<xAOD::IParticleContainer>> btagged_VRTrackjets;
+    const xAOD::Jet *m_largeRJet = nullptr;
   };
 
   class DiHiggsAnalysis : HiggsCandidate
diff --git a/HH4bAnalysis/src/tools/kLargestJets.cxx b/HH4bAnalysis/src/tools/kLargestJets.cxx
deleted file mode 100644
index b2d21cddd..000000000
--- a/HH4bAnalysis/src/tools/kLargestJets.cxx
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "queue"
-#include "xAODJet/JetContainer.h"
-
-// efficient algorithm to find k largest elements in size n vector with
-// efficiency O(n log k)
-// see https://stackoverflow.com/a/38391603
-
-// returns jet indices in descending order of the largest k found pt's
-std::vector<int> kLargestJets(const xAOD::JetContainer *jets, int k_)
-{
-  // Priority queues are a type of container adaptors, specifically designed
-  // such that its first element is always the greatest of the elements it
-  // contains. Using std::greater<T> causes the smallest element to appear as
-  // the top().
-  std::priority_queue<std::pair<double, int>,
-                      std::vector<std::pair<double, int>>,
-                      std::greater<std::pair<double, int>>>
-      queue;
-  long unsigned int k = k_; // number of indices we need
-
-  // loop over jets
-  const xAOD::Jet *thisJet;
-  double thisJetPt;
-  for (long unsigned int i = 0; i < jets->size(); i++)
-  {
-    thisJet = jets->at(i);
-    thisJetPt = thisJet->pt();
-    // fill queue with first k values
-    if (queue.size() < k)
-      // push	inserts element into queue and sorts it
-      queue.push(std::pair<double, int>(thisJetPt, i));
-    // if smallest element in queue is smaller than thisJetPt, replace
-    else if (queue.top().first < thisJetPt)
-    {
-      queue.pop();
-      queue.push(std::pair<double, int>(thisJetPt, i));
-    }
-  }
-
-  // return vector indices in descending order of the largest k found elements
-  k = queue.size();
-  std::vector<int> res(k);
-  for (long unsigned int i = 0; i < k; ++i)
-  {
-    res[k - i - 1] = queue.top().second;
-    queue.pop();
-  }
-  return res;
-}
diff --git a/HH4bAnalysis/src/tools/kLargestJets.h b/HH4bAnalysis/src/tools/kLargestJets.h
deleted file mode 100644
index a5e004508..000000000
--- a/HH4bAnalysis/src/tools/kLargestJets.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef HH4BANALYSIS_K_LARGEST_JETS
-#define HH4BANALYSIS_K_LARGEST_JETS
-
-#include "vector"
-#include "xAODJet/JetContainer.h"
-
-// efficient algorithm to find k largest elements in size n vector with
-// efficienvy O(n log k). see https://stackoverflow.com/a/38391603
-
-// it works something like this :
-// jet_with_pt's {2, 8, 7, 5, 9, 3, 6, 1, 10, 4};
-// kLargestJets(jets,5) returns
-// [8,4,1,2,6]
-
-// returns jet indices in descending order of the largest k found pt's
-std::vector<int> kLargestJets(const xAOD::JetContainer *jets, int k_);
-
-#endif
\ No newline at end of file
-- 
GitLab


From 2b4a80d82fc11a52d0548a005efd6af44c4379c7 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 18 Aug 2022 09:53:32 +0200
Subject: [PATCH 20/33] moved to std::unordered_map

---
 HH4bAnalysis/share/VariableDumperConfig.py |  2 +-
 HH4bAnalysis/src/DiHiggsAnalysis.cxx       | 24 ++++++++++++++--------
 HH4bAnalysis/src/DiHiggsAnalysis.h         |  8 +++++---
 3 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index cc042536b..8de653f2b 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -505,7 +505,7 @@ def main():
                 ConfigFlags,
                 btag_wps=args.btag_wps,
                 vr_btag_wps=args.vr_btag_wps,
-                trigger_chains=trigger_chains,
+                trigger_chains=[trigger_chains],
                 metadata_cache=args.meta_cache,
                 do_muons=do_muons,
                 do_loose=args.loose,
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index 79148dc32..df4719059 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -4,13 +4,13 @@
 #include <AsgMessaging/MessageCheck.h>
 #include <AthContainers/ConstDataVector.h>
 #include <TLorentzVector.h>
-
+// for ANA_MSG_BLAH
 using namespace asg::msgUserCode;
 
 namespace HH4B
 {
   int initValue = -1;
-  std::map<std::string, double> h_cand_vars{
+  std::unordered_map<std::string, float> h_cand_vars{
       {"resolved_m_h1", initValue},
       {"resolved_m_h2", initValue},
       {"resolved_m_hh", initValue},
@@ -233,19 +233,25 @@ namespace HH4B
     return;
   };
 
-  std::map<std::string, double> DiHiggsAnalysis::getHiggsVars()
+  std::unordered_map<std::string, float> DiHiggsAnalysis::getHiggsVars()
   {
     return h_cand_vars;
   };
 
   void DiHiggsAnalysis::decorateHiggsVars(const xAOD::EventInfo &eventInfo)
   {
-    // static const SG::AuxElement::Decorator<float> HiggsVars_dec(
-    // "dRtoLeadingJet");
+    // static const SG::AuxElement::Decorator<float> HiggsVars_dec;
+
     // the range looks weird, but its just a loop over the h_cand_vars map
+
+    // 1)
     for (const auto &[key, value] : h_cand_vars)
     {
-      eventInfo.auxdecor<double>(key) = value;
-    }
-  };
-}
+      SG::AuxElement::Decorator<float> HiggsVars_dec(key);
+      HiggsVars_dec(eventInfo) = value;
+    };
+
+    // 2)
+    // eventInfo.auxdecor<float>(key) = value;
+  }
+};
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index d28bc0bdb..a619838b1 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -9,7 +9,9 @@
 namespace HH4B
 {
   // dictionary holding the final vars
-  extern std::map<std::string, double> h_cand_vars;
+  // unordered_map is faster than map as it does the lookup with a hash and not
+  // by string comparison
+  extern std::unordered_map<std::string, float> h_cand_vars;
 
   struct HiggsCandidate
   {
@@ -19,7 +21,7 @@ namespace HH4B
     // four vector of Higgs candidate
     TLorentzVector m_fourVector;
     // dR between leading and subleading jet
-    double m_dRjets = -1;
+    float m_dRjets = -1;
     // for boosted analysis
     const xAOD::Jet *m_largeRJet = nullptr;
   };
@@ -32,7 +34,7 @@ public:
     // do boosted Analysis
     void makeBoostedAnalysis(const xAOD::JetContainer *largeRjets);
     // returns h_cand_vars for other purposes
-    std::map<std::string, double> getHiggsVars();
+    std::unordered_map<std::string, float> getHiggsVars();
     // decorates the h_cand_vars to the eventInfo
     void decorateHiggsVars(const xAOD::EventInfo &eventInfo);
   };
-- 
GitLab


From 03c9d664504e778707a2dec700b6ecbe643495e3 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 18 Aug 2022 11:43:14 +0200
Subject: [PATCH 21/33] remove inheritance

---
 HH4bAnalysis/src/DiHiggsAnalysis.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index a619838b1..2df509332 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -26,7 +26,7 @@ namespace HH4B
     const xAOD::Jet *m_largeRJet = nullptr;
   };
 
-  class DiHiggsAnalysis : HiggsCandidate
+  class DiHiggsAnalysis
   {
 public:
     // do resolved Analysis
-- 
GitLab


From 6eea6f46ff26f35556b88391bea8e6f8a0cf30f2 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 18 Aug 2022 15:42:29 +0200
Subject: [PATCH 22/33] move to Math/Vector4D.h

---
 HH4bAnalysis/src/DiHiggsAnalysis.cxx | 17 ++++++++++-------
 HH4bAnalysis/src/DiHiggsAnalysis.h   | 16 +++++++++-------
 2 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index f399f66ce..07c31e5c7 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -1,9 +1,9 @@
 
 #include "DiHiggsAnalysis.h"
 #include "AthenaBaseComps/AthCommonMsg.h"
+#include "Math/GenVector/VectorUtil.h"
 #include <AsgMessaging/MessageCheck.h>
 #include <AthContainers/ConstDataVector.h>
-#include <TLorentzVector.h>
 // for ANA_MSG_BLAH
 using namespace asg::msgUserCode;
 
@@ -76,7 +76,8 @@ namespace HH4B
         firstJet = false;
         continue;
       }
-      dRtoLeadingJet_dec(*jet) = jet->p4().DeltaR(h1.m_leadingJet->p4());
+      dRtoLeadingJet_dec(*jet) = ROOT::Math::VectorUtil::DeltaR(
+          jet->jetP4(), h1.m_leadingJet->jetP4());
     }
 
     // now find the closest one
@@ -105,10 +106,11 @@ namespace HH4B
 
     // calculate higgs candidate four vector and dR between jets in Higgs
     // candidate
-    h1.m_fourVector = h1.m_leadingJet->p4() + h1.m_subleadingJet->p4();
+    h1.m_fourVector = h1.m_leadingJet->jetP4() + h1.m_subleadingJet->jetP4();
     h1.m_dRjets = dRtoLeadingJet_acc(*h1.m_subleadingJet);
-    h2.m_fourVector = h2.m_leadingJet->p4() + h2.m_subleadingJet->p4();
-    h2.m_dRjets = h2.m_leadingJet->p4().DeltaR(h2.m_subleadingJet->p4());
+    h2.m_fourVector = h2.m_leadingJet->jetP4() + h2.m_subleadingJet->jetP4();
+    h2.m_dRjets = ROOT::Math::VectorUtil::DeltaR(h2.m_leadingJet->jetP4(),
+                                                 h2.m_subleadingJet->jetP4());
 
     // write to dictionary
     m_diHiggs_vars["resolved_m_h1"] = h1.m_fourVector.M();
@@ -220,8 +222,9 @@ namespace HH4B
       h.m_subleadingJet = dynamic_cast<const xAOD::Jet *>(*VRTrackjets[1]);
 
       // calc variables
-      h.m_fourVector = h.m_leadingJet->p4() + h.m_subleadingJet->p4();
-      h.m_dRjets = h.m_leadingJet->p4().DeltaR(h.m_subleadingJet->p4());
+      h.m_fourVector = h.m_leadingJet->jetP4() + h.m_subleadingJet->jetP4();
+      h.m_dRjets = ROOT::Math::VectorUtil::DeltaR(h.m_leadingJet->jetP4(),
+                                                  h.m_subleadingJet->jetP4());
     }
 
     // write to dictionary
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index 0636c22d7..d3b966f8e 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -2,17 +2,23 @@
 #define HH4B_DIHIGGSANALYSIS
 
 #include "xAODJet/JetContainer.h"
+#include <Math/Vector4D.h>
 #include <xAODEventInfo/EventInfo.h>
 
 namespace HH4B
 {
+  // dictionary holding the final vars
+  // unordered_map is faster than map as it does the lookup with a hash and not
+  // by string comparison
+  extern std::unordered_map<std::string, float> m_diHiggs_vars;
+
   struct HiggsCandidate
   {
     // b-jets for Higgs candidate
     const xAOD::Jet *m_leadingJet = nullptr;
     const xAOD::Jet *m_subleadingJet = nullptr;
     // four vector of Higgs candidate
-    TLorentzVector m_fourVector;
+    ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<float>> m_fourVector;
     // dR between leading and subleading jet
     float m_dRjets = -1;
     // for boosted analysis
@@ -26,14 +32,10 @@ public:
     void makeResolvedAnalysis(const xAOD::JetContainer &smallRjets);
     // do boosted Analysis
     void makeBoostedAnalysis(const xAOD::JetContainer &largeRjets);
-    // returns m_diHiggs_vars for other purposes
+    // returns h_cand_vars for other purposes
     std::unordered_map<std::string, float> getHiggsVars();
-    // decorates the m_diHiggs_vars to the eventInfo
+    // decorates the h_cand_vars to the eventInfo
     void decorateHiggsVars(const xAOD::EventInfo &eventInfo);
-    // dictionary holding the final vars
-    // unordered_map is faster than map as it does the lookup with a hash and
-    // not by string comparison
-    extern std::unordered_map<std::string, float> m_diHiggs_vars;
   };
 }
 #endif
-- 
GitLab


From 7c279d4bcd9676b6e3102a4ed5845b38bc22731e Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 18 Aug 2022 16:50:40 +0200
Subject: [PATCH 23/33] move to own di-higgs alg

---
 HH4bAnalysis/share/VariableDumperConfig.py    | 13 ++++------
 HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx       | 24 ++++++++++++-------
 HH4bAnalysis/src/DiHiggsAnalysisAlg.h         |  6 ++---
 .../src/components/HH4bAnalysis_entries.cxx   |  2 ++
 4 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 7cb827f22..8579d87a3 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -318,16 +318,11 @@ def AnalysisAlgsCfg(
         cache_metadata(metadata_cache)
 
     cfg.addEventAlgo(
-        CompFactory.HH4B.VariableDumperAlg(
-            "VariableDumper",
-            RootStreamName="ANALYSIS",
+        CompFactory.HH4B.DiHiggsAnalysisAlg(
+            "DiHiggsAnalysis",
             EventInfoKey="EventInfo",
-            ElectronsKey=containers["outputs"]["electrons"],
-            PhotonsKey=containers["outputs"]["photons"],
-            MuonsKey=containers["outputs"]["muons"],
-            SmallJetKey=containers["outputs"]["reco4Jet"],
-            LargeJetKey=containers["outputs"]["reco10Jet"],
-            VRtrackjets=containers["outputs"]["vrJet"],
+            SmallJetKey=containers["outputs"]["reco4Jet"].replace("%SYS%", "NOSYS"),
+            LargeJetKey=containers["outputs"]["reco10Jet"].replace("%SYS%", "NOSYS"),
         )
     )
 
diff --git a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
index 9f0aac71e..c5a1abf9a 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
@@ -20,20 +20,29 @@ namespace HH4B
                                           ISvcLocator *pSvcLocator)
       : AthHistogramAlgorithm(name, pSvcLocator)
   {
-    declareProperty("doBoostedAnalysis", m_doBoostedAnalysis);
     declareProperty("doResolvedAnalysis", m_doResolvedAnalysis);
+    declareProperty("doBoostedAnalysis", m_doBoostedAnalysis);
   }
 
   StatusCode DiHiggsAnalysisAlg ::initialize()
   {
     ATH_MSG_DEBUG("Initialising " << name());
 
-    DiHiggsAnalysis getVarsObject;
-    getVarsObject.getHiggsVars();
+    DiHiggsAnalysis hh4b_analysis;
+    hh4b_analysis.getHiggsVars();
+
+    // std::unordered_map<std::string, SG::AuxElement::Decorator<float>>
+    // m_diHiggs_decos;
+    for (const auto &[key, value] : hh4b_analysis.getHiggsVars())
+    {
+      // SG::AuxElement::Decorator<float> HiggsVars_dec(key);
+      // m_diHiggs_decos[key] = HiggsVars_dec;
+      std::cout << key;
+    };
 
     ATH_CHECK(m_EventInfoKey.initialize());
-    ATH_CHECK(m_smallJetKey.initialize());
-    ATH_CHECK(m_largeJetKey.initialize());
+    ATH_CHECK(m_SmallJetKey.initialize());
+    ATH_CHECK(m_LargeJetKey.initialize());
 
     return StatusCode::SUCCESS;
   }
@@ -43,10 +52,9 @@ namespace HH4B
     ATH_MSG_DEBUG("Executing " << name());
 
     // get the xAOD objects
-
     SG::ReadHandle<xAOD::EventInfo> eventInfo(m_EventInfoKey);
-    SG::ReadHandle<xAOD::JetContainer> antiKt4RecoJets(m_smallJetKey);
-    SG::ReadHandle<xAOD::JetContainer> antiKt10RecoJets(m_largeJetKey);
+    SG::ReadHandle<xAOD::JetContainer> antiKt4RecoJets(m_SmallJetKey);
+    SG::ReadHandle<xAOD::JetContainer> antiKt10RecoJets(m_LargeJetKey);
     ATH_CHECK(eventInfo.isValid());
     ATH_CHECK(antiKt4RecoJets.isValid());
     ATH_CHECK(antiKt10RecoJets.isValid());
diff --git a/HH4bAnalysis/src/DiHiggsAnalysisAlg.h b/HH4bAnalysis/src/DiHiggsAnalysisAlg.h
index b9817dc51..fd047aab4 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysisAlg.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysisAlg.h
@@ -44,15 +44,15 @@ private:
 
     // decorators for the Higgs variables
     std::unordered_map<std::string, SG::AuxElement::Decorator<float>>
-        m_hhDecors;
+        m_diHiggs_decos;
     // Member variables for configuration
     SG::ReadHandleKey<xAOD::EventInfo> m_EventInfoKey{
         this, "EventInfoKey", "EventInfo", "EventInfo container to dump"};
 
-    SG::ReadHandleKey<xAOD::JetContainer> m_smallJetKey{
+    SG::ReadHandleKey<xAOD::JetContainer> m_SmallJetKey{
         this, "SmallJetKey", "", "the small-R jet collection to run on"};
 
-    SG::ReadHandleKey<xAOD::JetContainer> m_largeJetKey{
+    SG::ReadHandleKey<xAOD::JetContainer> m_LargeJetKey{
         this, "LargeJetKey", "", "the large-R jet collection to run on"};
 
     bool m_doResolvedAnalysis;
diff --git a/HH4bAnalysis/src/components/HH4bAnalysis_entries.cxx b/HH4bAnalysis/src/components/HH4bAnalysis_entries.cxx
index 69411715b..8b6e9279f 100644
--- a/HH4bAnalysis/src/components/HH4bAnalysis_entries.cxx
+++ b/HH4bAnalysis/src/components/HH4bAnalysis_entries.cxx
@@ -1,7 +1,9 @@
+#include "../DiHiggsAnalysisAlg.h"
 #include "../VariableDumperAlg.h"
 #include "../tools/NTrkVertexCounter.h"
 
 using namespace HH4B;
 
+DECLARE_COMPONENT(DiHiggsAnalysisAlg)
 DECLARE_COMPONENT(NTrkVertexCounter)
 DECLARE_COMPONENT(VariableDumperAlg)
-- 
GitLab


From 4f82cc13f6a50d4d28e5913961aac594da1464d5 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Fri, 19 Aug 2022 10:17:46 +0200
Subject: [PATCH 24/33] create decorators at init

---
 HH4bAnalysis/src/DiHiggsAnalysis.cxx    | 24 +-------------------
 HH4bAnalysis/src/DiHiggsAnalysis.h      | 22 ++++++++++++++-----
 HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx | 29 ++++++++++---------------
 3 files changed, 30 insertions(+), 45 deletions(-)

diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index 07c31e5c7..b4c1c3e60 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -9,19 +9,6 @@ using namespace asg::msgUserCode;
 
 namespace HH4B
 {
-  float initValue = -1;
-  std::unordered_map<std::string, float> m_diHiggs_vars{
-      {"resolved_m_h1", initValue},
-      {"resolved_m_h2", initValue},
-      {"resolved_m_hh", initValue},
-      {"resolved_dR_jets_in_h1", initValue},
-      {"resolved_dR_jets_in_h2", initValue},
-      {"boosted_m_h1", initValue},
-      {"boosted_m_h2", initValue},
-      {"boosted_m_hh", initValue},
-      {"boosted_dR_jets_in_h1", initValue},
-      {"boosted_dR_jets_in_h2", initValue},
-  };
 
   void
   DiHiggsAnalysis::makeResolvedAnalysis(const xAOD::JetContainer &smallRjets)
@@ -243,18 +230,9 @@ namespace HH4B
 
   void DiHiggsAnalysis::decorateHiggsVars(const xAOD::EventInfo &eventInfo)
   {
-    // static const SG::AuxElement::Decorator<float> HiggsVars_dec;
-
-    // the range looks weird, but its just a loop over the m_diHiggs_vars map
-
-    // 1)
     for (const auto &[key, value] : m_diHiggs_vars)
     {
-      SG::AuxElement::Decorator<float> HiggsVars_dec(key);
-      HiggsVars_dec(eventInfo) = value;
+      eventInfo.auxdecor<float>(key) = value;
     };
-
-    // 2)
-    // eventInfo.auxdecor<float>(key) = value;
   }
 };
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index d3b966f8e..280582e62 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -7,11 +7,6 @@
 
 namespace HH4B
 {
-  // dictionary holding the final vars
-  // unordered_map is faster than map as it does the lookup with a hash and not
-  // by string comparison
-  extern std::unordered_map<std::string, float> m_diHiggs_vars;
-
   struct HiggsCandidate
   {
     // b-jets for Higgs candidate
@@ -36,6 +31,23 @@ public:
     std::unordered_map<std::string, float> getHiggsVars();
     // decorates the h_cand_vars to the eventInfo
     void decorateHiggsVars(const xAOD::EventInfo &eventInfo);
+    // DiHiggs variables init value
+    float m_initValue = -1;
+    // map holding the final vars
+    // unordered_map is faster than map as it does the lookup with a hash and
+    // not by string comparison
+    std::unordered_map<std::string, float> m_diHiggs_vars{
+        {"resolved_m_h1", m_initValue},
+        {"resolved_m_h2", m_initValue},
+        {"resolved_m_hh", m_initValue},
+        {"resolved_dR_jets_in_h1", m_initValue},
+        {"resolved_dR_jets_in_h2", m_initValue},
+        {"boosted_m_h1", m_initValue},
+        {"boosted_m_h2", m_initValue},
+        {"boosted_m_hh", m_initValue},
+        {"boosted_dR_jets_in_h1", m_initValue},
+        {"boosted_dR_jets_in_h2", m_initValue},
+    };
   };
 }
 #endif
diff --git a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
index c5a1abf9a..0ba1386dd 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
@@ -2,18 +2,11 @@
   Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
 */
 
-/// @author Victor Ruelas
-
-//
-// includes
-//
+/// @author Frederic Renner
 
 #include "DiHiggsAnalysisAlg.h"
 #include "DiHiggsAnalysis.h"
 
-//
-// method implementations
-//
 namespace HH4B
 {
   DiHiggsAnalysisAlg ::DiHiggsAnalysisAlg(const std::string &name,
@@ -28,16 +21,13 @@ namespace HH4B
   {
     ATH_MSG_DEBUG("Initialising " << name());
 
-    DiHiggsAnalysis hh4b_analysis;
-    hh4b_analysis.getHiggsVars();
+    DiHiggsAnalysis analysisObject;
 
-    // std::unordered_map<std::string, SG::AuxElement::Decorator<float>>
-    // m_diHiggs_decos;
-    for (const auto &[key, value] : hh4b_analysis.getHiggsVars())
+    // create the decorators here once for the whole alg
+    for (const auto &[key, value] : analysisObject.m_diHiggs_vars)
     {
-      // SG::AuxElement::Decorator<float> HiggsVars_dec(key);
-      // m_diHiggs_decos[key] = HiggsVars_dec;
-      std::cout << key;
+      SG::AuxElement::Decorator<float> HiggsVars_dec(key);
+      m_diHiggs_decos.emplace(key, HiggsVars_dec);
     };
 
     ATH_CHECK(m_EventInfoKey.initialize());
@@ -66,7 +56,12 @@ namespace HH4B
     DiHiggsAnalysis hh4b_analysis;
     hh4b_analysis.makeResolvedAnalysis(*antiKt4RecoJets);
     hh4b_analysis.makeBoostedAnalysis(*antiKt10RecoJets);
-    hh4b_analysis.decorateHiggsVars(*eventInfo);
+
+    for (const auto &[key, value] : hh4b_analysis.getHiggsVars())
+    {
+      SG::AuxElement::Decorator<float> HiggsVars_dec = m_diHiggs_decos.at(key);
+      HiggsVars_dec(*eventInfo) = value;
+    };
 
     return StatusCode::SUCCESS;
   }
-- 
GitLab


From 8a5d60bb3e0bff6fd6d12b3ab7771ddf149d6329 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Mon, 22 Aug 2022 10:32:17 +0200
Subject: [PATCH 25/33] added analysis peer btagging working point

---
 HH4bAnalysis/share/VariableDumperConfig.py |  37 +++--
 HH4bAnalysis/src/DiHiggsAnalysis.cxx       | 155 +++++++++++++++------
 HH4bAnalysis/src/DiHiggsAnalysis.h         |  38 +++--
 HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx    |  49 +++++--
 HH4bAnalysis/src/DiHiggsAnalysisAlg.h      |   8 +-
 5 files changed, 199 insertions(+), 88 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 8579d87a3..aef94be08 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -323,6 +323,10 @@ def AnalysisAlgsCfg(
             EventInfoKey="EventInfo",
             SmallJetKey=containers["outputs"]["reco4Jet"].replace("%SYS%", "NOSYS"),
             LargeJetKey=containers["outputs"]["reco10Jet"].replace("%SYS%", "NOSYS"),
+            doResolvedAnalysis=True,
+            doBoostedAnalysis=True,
+            btag_wps=btag_wps,
+            vr_btag_wps=vr_btag_wps,
         )
     )
 
@@ -432,18 +436,29 @@ def MiniTupleCfg(
             f"{containers['vrJet']}.ftag_select_{btag_wp} -> vrjet_%SYS%_{btag_wp}"
             for btag_wp in working_points["vr"]
         ]
-    analysisTreeBranches = [
-        "EventInfo.resolved_m_h1   -> resolved_m_h1",
-        "EventInfo.resolved_m_h2   -> resolved_m_h2",
-        "EventInfo.resolved_m_hh   -> resolved_m_hh",
-        "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
-        "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
-        "EventInfo.boosted_m_h1   -> boosted_m_h1",
-        "EventInfo.boosted_m_h2   -> boosted_m_h2",
-        "EventInfo.boosted_m_hh   -> boosted_m_hh",
-        "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
-        "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
+
+    # Di-Higgs Variables
+    analysisTreeBranches += [
+        f"EventInfo.resolved_m_h1_{btag_wp} -> resolved_m_h1_{btag_wp}"
+        for btag_wp in working_points["ak4"]
     ]
+    analysisTreeBranches += [
+        f"EventInfo.boosted_m_h1_{btag_wp} -> boosted_m_h1_{btag_wp}"
+        for btag_wp in working_points["vr"]
+    ]
+
+    # analysisTreeBranches = [
+    #     "EventInfo.resolved_m_h1   -> resolved_m_h1",
+    #     "EventInfo.resolved_m_h2   -> resolved_m_h2",
+    #     "EventInfo.resolved_m_hh   -> resolved_m_hh",
+    #     "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
+    #     "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
+    #     "EventInfo.boosted_m_h1   -> boosted_m_h1",
+    #     "EventInfo.boosted_m_h2   -> boosted_m_h2",
+    #     "EventInfo.boosted_m_hh   -> boosted_m_hh",
+    #     "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
+    #     "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
+    # ]
     log.info("Add tree seq")
     cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
 
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index b4c1c3e60..eced91fd6 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -8,10 +8,46 @@
 using namespace asg::msgUserCode;
 
 namespace HH4B
+
 {
 
+  std::vector<std::string>
+  getHiggsVarsNames(std::vector<std::string> &btag_wps,
+                    std::vector<std::string> &vr_btag_wps)
+  {
+    std::vector<std::string> vars;
+    for (std::string wp : btag_wps)
+    {
+      vars.push_back("resolved_m_h1_" + wp);
+      vars.push_back("resolved_m_h2_" + wp);
+      vars.push_back("resolved_m_hh_" + wp);
+      vars.push_back("resolved_dR_jets_in_h1_" + wp);
+      vars.push_back("resolved_dR_jets_in_h2_" + wp);
+    }
+    for (std::string wp : vr_btag_wps)
+    {
+      vars.push_back("boosted_m_h1_" + wp);
+      vars.push_back("boosted_m_h2_" + wp);
+      vars.push_back("boosted_m_hh_" + wp);
+      vars.push_back("boosted_dR_jets_in_h1_" + wp);
+      vars.push_back("boosted_dR_jets_in_h2_" + wp);
+    }
+    return vars;
+  }
+
+  void DiHiggsAnalysis::initHiggsVarsMap(std::vector<std::string> &higgsVars)
+  {
+    float initValue = -1;
+    for (std::string var : higgsVars)
+    {
+      m_higgsVarsMap.insert_or_assign(var, initValue);
+    }
+    return;
+  }
+
   void
-  DiHiggsAnalysis::makeResolvedAnalysis(const xAOD::JetContainer &smallRjets)
+  DiHiggsAnalysis::makeResolvedAnalysis(const xAOD::JetContainer &smallRjets,
+                                        std::string wp)
   {
     // check if we have at least 4 jets
     if (smallRjets.size() < 4)
@@ -23,25 +59,54 @@ namespace HH4B
     // subleading higgs candidate
     HiggsCandidate h2;
 
+    // this is a shallow copy container
+    ConstDataVector<xAOD::JetContainer> bTaggedJets(SG::VIEW_ELEMENTS);
+
+    static const SG::AuxElement::ConstAccessor<char> isBtag("ftag_select_" +
+                                                            wp);
+    // remove non-btagged jets of designated wp
+    // (fancy std::remove_if from boosted analysis only works with vectors)
+    for (const xAOD::Jet *jet : smallRjets)
+    {
+      // the ftag sequence does not tag all of them
+      if (!isBtag.isAvailable(*jet))
+      {
+        ANA_MSG_DEBUG("Skipped non B-tagged jet");
+        continue;
+      }
+      // keep only btagged jets with a designated wp
+      if (isBtag(*jet))
+      {
+        bTaggedJets.push_back(jet);
+      }
+    }
+
+    // check if we have at least 4 btagged jets
+    if (bTaggedJets.size() < 4)
+    {
+      return;
+    }
+
+    ConstDataVector<xAOD::JetContainer> ptSortedBtaggedJets(
+        bTaggedJets.begin(), bTaggedJets.end(), SG::VIEW_ELEMENTS);
+
     // taken from TJ's tutorial
     // https://gitlab.cern.ch/khoo/athanalysistutorial/-/blob/r22/MySecondAthAnalysis/src/DileptonFinderAlg.cxx
     //
-    // this is a shallow copy container
-    ConstDataVector<xAOD::JetContainer> ptSortedJets(
-        smallRjets.begin(), smallRjets.end(), SG::VIEW_ELEMENTS);
     // with std::partial_sort you only have to sort an N-sized container
-    // instead of sorting a ptSortedJets.size() container
+    // instead of sorting a ptSortedBtaggedJets.size() container
     std::partial_sort(
-        ptSortedJets.begin(),     // Iterator from which to start sorting
-        ptSortedJets.begin() + 4, // Use begin + N to sort first N
-        ptSortedJets.end(), // Iterator marking the end of the range to sort
+        ptSortedBtaggedJets.begin(), // Iterator from which to start sorting
+        ptSortedBtaggedJets.begin() + 4, // Use begin + N to sort first N
+        ptSortedBtaggedJets.end(), // Iterator marking the end of range to sort
         [](const xAOD::IParticle *left, const xAOD::IParticle *right)
         {
           return left->pt() > right->pt();
-        }); // lambda function here just handy, could also be another function
+        }); // lambda function here just handy, could also be another
+            // function that returns bool
 
     // get the leading b-jet for the leading Higgs candidate
-    h1.m_leadingJet = ptSortedJets[0];
+    h1.m_leadingJet = ptSortedBtaggedJets[0];
 
     // calculate dR to the next three leading jets and decorate jet
     static const SG::AuxElement::Decorator<float> dRtoLeadingJet_dec(
@@ -50,13 +115,14 @@ namespace HH4B
         "dRtoLeadingJet");
 
     // keep only the four leading ones
-    ptSortedJets.erase(ptSortedJets.begin() + 4, ptSortedJets.end());
+    ptSortedBtaggedJets.erase(ptSortedBtaggedJets.begin() + 4,
+                              ptSortedBtaggedJets.end());
 
     // decorate dR(jet,leading jet) to each jet
     bool firstJet = true;
-    for (const xAOD::Jet *jet : ptSortedJets)
+    for (const xAOD::Jet *jet : ptSortedBtaggedJets)
     {
-      // more instructive as done with iterators
+      // more instructive than done with iterators
       if (firstJet)
       {
         dRtoLeadingJet_dec(*jet) = 0;
@@ -68,7 +134,7 @@ namespace HH4B
     }
 
     // now find the closest one
-    ConstDataVector<xAOD::JetContainer> dRsortedJets = ptSortedJets;
+    ConstDataVector<xAOD::JetContainer> dRsortedJets = ptSortedBtaggedJets;
     std::partial_sort(
         dRsortedJets.begin(),     // Iterator from which to start sorting
         dRsortedJets.begin() + 4, // Use begin + N to sort first N
@@ -99,18 +165,20 @@ namespace HH4B
     h2.m_dRjets = ROOT::Math::VectorUtil::DeltaR(h2.m_leadingJet->jetP4(),
                                                  h2.m_subleadingJet->jetP4());
 
-    // write to dictionary
-    m_diHiggs_vars["resolved_m_h1"] = h1.m_fourVector.M();
-    m_diHiggs_vars["resolved_m_h2"] = h2.m_fourVector.M();
-    m_diHiggs_vars["resolved_m_hh"] = (h1.m_fourVector + h2.m_fourVector).M();
-    m_diHiggs_vars["resolved_dR_jets_in_h1"] = h1.m_dRjets;
-    m_diHiggs_vars["resolved_dR_jets_in_h2"] = h2.m_dRjets;
+    // write to map
+    m_higgsVarsMap["resolved_m_h1_" + wp] = h1.m_fourVector.M();
+    m_higgsVarsMap["resolved_m_h2_" + wp] = h2.m_fourVector.M();
+    m_higgsVarsMap["resolved_m_hh_" + wp] =
+        (h1.m_fourVector + h2.m_fourVector).M();
+    m_higgsVarsMap["resolved_dR_jets_in_h1_" + wp] = h1.m_dRjets;
+    m_higgsVarsMap["resolved_dR_jets_in_h2_" + wp] = h2.m_dRjets;
 
     return;
   };
 
   void
-  DiHiggsAnalysis::makeBoostedAnalysis(const xAOD::JetContainer &largeRjets)
+  DiHiggsAnalysis::makeBoostedAnalysis(const xAOD::JetContainer &largeRjets,
+                                       std::string wp)
   {
     // TODO: list
 
@@ -134,9 +202,10 @@ namespace HH4B
     // subleading higgs candidate
     HiggsCandidate h2;
 
-    // get the leading large R, see resvoled analysis for details
+    // get the leading large R in a shallow copy container
     ConstDataVector<xAOD::JetContainer> ptSortedLargeRJets(
         largeRjets.begin(), largeRjets.end(), SG::VIEW_ELEMENTS);
+    // for details on sorting see resolved
     std::partial_sort(
         ptSortedLargeRJets.begin(),     // Iterator from which to start sorting
         ptSortedLargeRJets.begin() + 2, // Use begin + N to sort first N
@@ -153,12 +222,12 @@ namespace HH4B
     static const SG::AuxElement::ConstAccessor<
         std::vector<ElementLink<xAOD::IParticleContainer>>>
         m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
-    static const SG::AuxElement::ConstAccessor<char> isBtag(
-        "ftag_select_DL1r_FixedCutBEff_77");
+    static const SG::AuxElement::ConstAccessor<char> isBtag("ftag_select_" +
+                                                            wp);
 
-    // loop over the Higgs Candidate large R jets to get the btagged VR jets
-    // inside of each, need to do std::ref to access the actual objects h1, h2
-    // "for (HiggsCandidate h : {h1, h2})" would make copies of h1, h2
+    // loop over the Higgs Candidate large R jets, get the btagged VR jets
+    // inside of each, need to do std::ref to access the actual objects h1,
+    // h2. "for (HiggsCandidate h : {h1, h2})" would make copies of h1, h2
     for (HiggsCandidate &h : {std::ref(h1), std::ref(h2)})
     {
       // get ghost associated VR track jets from untrimmed large R jet
@@ -170,8 +239,6 @@ namespace HH4B
       // get the btagged VR trackjets per large R jet
       // remove VRjets with invalid elementlinks and non-btagged ones
       // should we handle this differently?
-      // can't just remove in for loop, get in trouble with iterator, could do
-      // with while loop but std::remove_if is more efficient
       VRTrackjets.erase(
           std::remove_if(VRTrackjets.begin(), VRTrackjets.end(),
                          [](ElementLink<xAOD::IParticleContainer> &VRjet)
@@ -181,11 +248,17 @@ namespace HH4B
                              ANA_MSG_WARNING("Skipped invalid VR jet link!");
                              return true;
                            }
+                           // the ftag sequence does not tag all of them
                            if (!isBtag.isAvailable(**VRjet))
                            {
                              ANA_MSG_DEBUG("Skipped non B-tagged VR jet");
                              return true;
                            }
+                           // keep only btagged jets with a designated wp
+                           if (!isBtag(**VRjet))
+                           {
+                             return true;
+                           }
                            return false;
                          }),
           VRTrackjets.end());
@@ -214,25 +287,19 @@ namespace HH4B
                                                   h.m_subleadingJet->jetP4());
     }
 
-    // write to dictionary
-    m_diHiggs_vars["boosted_m_h1"] = h1.m_fourVector.M();
-    m_diHiggs_vars["boosted_m_h2"] = h2.m_fourVector.M();
-    m_diHiggs_vars["boosted_m_hh"] = (h1.m_fourVector + h2.m_fourVector).M();
-    m_diHiggs_vars["boosted_dR_jets_in_h1"] = h1.m_dRjets;
-    m_diHiggs_vars["boosted_dR_jets_in_h2"] = h2.m_dRjets;
+    // write to map
+    m_higgsVarsMap["boosted_m_h1_" + wp] = h1.m_fourVector.M();
+    m_higgsVarsMap["boosted_m_h2_" + wp] = h2.m_fourVector.M();
+    m_higgsVarsMap["boosted_m_hh_" + wp] =
+        (h1.m_fourVector + h2.m_fourVector).M();
+    m_higgsVarsMap["boosted_dR_jets_in_h1_" + wp] = h1.m_dRjets;
+    m_higgsVarsMap["boosted_dR_jets_in_h2_" + wp] = h2.m_dRjets;
     return;
   };
 
-  std::unordered_map<std::string, float> DiHiggsAnalysis::getHiggsVars()
+  std::unordered_map<std::string, float> DiHiggsAnalysis::getHiggsVarsMap()
   {
-    return m_diHiggs_vars;
+    return m_higgsVarsMap;
   };
 
-  void DiHiggsAnalysis::decorateHiggsVars(const xAOD::EventInfo &eventInfo)
-  {
-    for (const auto &[key, value] : m_diHiggs_vars)
-    {
-      eventInfo.auxdecor<float>(key) = value;
-    };
-  }
 };
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index 280582e62..55596aec4 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -7,12 +7,18 @@
 
 namespace HH4B
 {
+
+  // make Higgs vars names list with attached btagging working points
+  std::vector<std::string>
+  getHiggsVarsNames(std::vector<std::string> &btag_wps,
+                    std::vector<std::string> &vr_btag_wps);
+
   struct HiggsCandidate
   {
     // b-jets for Higgs candidate
     const xAOD::Jet *m_leadingJet = nullptr;
     const xAOD::Jet *m_subleadingJet = nullptr;
-    // four vector of Higgs candidate
+    // four vector of Higgs candidate, (this is faster than TLorentzVector)
     ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<float>> m_fourVector;
     // dR between leading and subleading jet
     float m_dRjets = -1;
@@ -23,31 +29,21 @@ namespace HH4B
   class DiHiggsAnalysis
   {
 public:
+    // initialize vars in m_higgsVarsMap
+    void initHiggsVarsMap(std::vector<std::string> &higgsVars);
     // do resolved Analysis
-    void makeResolvedAnalysis(const xAOD::JetContainer &smallRjets);
+    void makeResolvedAnalysis(const xAOD::JetContainer &smallRjets,
+                              std::string wp);
     // do boosted Analysis
-    void makeBoostedAnalysis(const xAOD::JetContainer &largeRjets);
+    void makeBoostedAnalysis(const xAOD::JetContainer &largeRjets,
+                             std::string wp);
     // returns h_cand_vars for other purposes
-    std::unordered_map<std::string, float> getHiggsVars();
-    // decorates the h_cand_vars to the eventInfo
-    void decorateHiggsVars(const xAOD::EventInfo &eventInfo);
-    // DiHiggs variables init value
-    float m_initValue = -1;
-    // map holding the final vars
+    std::unordered_map<std::string, float> getHiggsVarsMap();
+    // map holding the final vars (like dict in python)
+    // access/write like : m_diHiggs_vars[var];
     // unordered_map is faster than map as it does the lookup with a hash and
     // not by string comparison
-    std::unordered_map<std::string, float> m_diHiggs_vars{
-        {"resolved_m_h1", m_initValue},
-        {"resolved_m_h2", m_initValue},
-        {"resolved_m_hh", m_initValue},
-        {"resolved_dR_jets_in_h1", m_initValue},
-        {"resolved_dR_jets_in_h2", m_initValue},
-        {"boosted_m_h1", m_initValue},
-        {"boosted_m_h2", m_initValue},
-        {"boosted_m_hh", m_initValue},
-        {"boosted_dR_jets_in_h1", m_initValue},
-        {"boosted_dR_jets_in_h2", m_initValue},
-    };
+    std::unordered_map<std::string, float> m_higgsVarsMap;
   };
 }
 #endif
diff --git a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
index 0ba1386dd..3ab13395e 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
@@ -15,19 +15,21 @@ namespace HH4B
   {
     declareProperty("doResolvedAnalysis", m_doResolvedAnalysis);
     declareProperty("doBoostedAnalysis", m_doBoostedAnalysis);
+    declareProperty("btag_wps", m_btag_wps);
+    declareProperty("vr_btag_wps", m_vr_btag_wps);
   }
 
   StatusCode DiHiggsAnalysisAlg ::initialize()
   {
     ATH_MSG_DEBUG("Initialising " << name());
 
-    DiHiggsAnalysis analysisObject;
-
-    // create the decorators here once for the whole alg
-    for (const auto &[key, value] : analysisObject.m_diHiggs_vars)
+    // get to be used Higgs vars to create the final decorators here so they
+    // are created once per alg and not per event
+    m_higgsVars = getHiggsVarsNames(m_btag_wps, m_vr_btag_wps);
+    for (std::string var : m_higgsVars)
     {
-      SG::AuxElement::Decorator<float> HiggsVars_dec(key);
-      m_diHiggs_decos.emplace(key, HiggsVars_dec);
+      SG::AuxElement::Decorator<float> HiggsVars_dec(var);
+      m_diHiggs_decos.emplace(var, HiggsVars_dec);
     };
 
     ATH_CHECK(m_EventInfoKey.initialize());
@@ -39,6 +41,11 @@ namespace HH4B
 
   StatusCode DiHiggsAnalysisAlg ::execute()
   {
+    // jump out if no analysis is selected
+    if (!m_doResolvedAnalysis or !m_doResolvedAnalysis)
+    {
+      return StatusCode::SUCCESS;
+    }
     ATH_MSG_DEBUG("Executing " << name());
 
     // get the xAOD objects
@@ -54,15 +61,35 @@ namespace HH4B
 
     // create the analysis object
     DiHiggsAnalysis hh4b_analysis;
-    hh4b_analysis.makeResolvedAnalysis(*antiKt4RecoJets);
-    hh4b_analysis.makeBoostedAnalysis(*antiKt10RecoJets);
+    // write defaults (-1) into the Higgs variable map
+    hh4b_analysis.initHiggsVarsMap(m_higgsVars);
+
+    // which analyses to do
+    if (m_doResolvedAnalysis)
+    {
+      for (std::string wp : m_btag_wps)
+      {
+        hh4b_analysis.makeResolvedAnalysis(*antiKt4RecoJets, wp);
+      }
+    }
+    if (m_doBoostedAnalysis)
+    {
+      for (std::string wp : m_vr_btag_wps)
+      {
+        hh4b_analysis.makeBoostedAnalysis(*antiKt10RecoJets, wp);
+      }
+    }
 
-    for (const auto &[key, value] : hh4b_analysis.getHiggsVars())
+    // get higgs vars map (behaves like dict in python)
+    std::unordered_map<std::string, float> higgsVarsMap =
+        hh4b_analysis.getHiggsVarsMap();
+    // loop over decorators
+    for (const auto &[var, value] : higgsVarsMap)
     {
-      SG::AuxElement::Decorator<float> HiggsVars_dec = m_diHiggs_decos.at(key);
+      SG::AuxElement::Decorator<float> HiggsVars_dec = m_diHiggs_decos.at(var);
       HiggsVars_dec(*eventInfo) = value;
     };
 
     return StatusCode::SUCCESS;
   }
-}
\ No newline at end of file
+}
diff --git a/HH4bAnalysis/src/DiHiggsAnalysisAlg.h b/HH4bAnalysis/src/DiHiggsAnalysisAlg.h
index fd047aab4..bd204fe36 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysisAlg.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysisAlg.h
@@ -55,10 +55,16 @@ private:
     SG::ReadHandleKey<xAOD::JetContainer> m_LargeJetKey{
         this, "LargeJetKey", "", "the large-R jet collection to run on"};
 
+    // whether the algorithm should do one of the following analyses
     bool m_doResolvedAnalysis;
     bool m_doBoostedAnalysis;
+    // btagging working points for 0.4 jets
+    std::vector<std::string> m_btag_wps;
+    // btagging working points for the variable radius track jets in 1.0 jets
+    std::vector<std::string> m_vr_btag_wps;
+    // list of to be used Higgs vars
+    std::vector<std::string> m_higgsVars;
   };
-
 }
 
 #endif
-- 
GitLab


From 99f7d9240ecc70ccdae2b157c4456e47825a5ad6 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Mon, 22 Aug 2022 17:37:39 +0200
Subject: [PATCH 26/33] added config, some boosted cuts

---
 HH4bAnalysis/python/Algs/DiHiggsAnalysis.py | 49 ++++++++++++++++
 HH4bAnalysis/share/VariableDumperConfig.py  | 58 +++++++++----------
 HH4bAnalysis/src/DiHiggsAnalysis.cxx        | 64 ++++++++++++++-------
 3 files changed, 118 insertions(+), 53 deletions(-)
 create mode 100644 HH4bAnalysis/python/Algs/DiHiggsAnalysis.py

diff --git a/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
new file mode 100644
index 000000000..1c9c72296
--- /dev/null
+++ b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
@@ -0,0 +1,49 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+
+def DiHiggsAnalysisAlgCfg(
+    SmallJetKey,
+    LargeJetKey,
+    btag_wps,
+    vr_btag_wps,
+):
+
+    cfg = ComponentAccumulator()
+    cfg.addEventAlgo(
+        CompFactory.HH4B.DiHiggsAnalysisAlg(
+            "DiHiggsAnalysis",
+            EventInfoKey="EventInfo",
+            SmallJetKey=SmallJetKey,
+            LargeJetKey=LargeJetKey,
+            doResolvedAnalysis=True,
+            doBoostedAnalysis=True,
+            btag_wps=btag_wps,
+            vr_btag_wps=vr_btag_wps,
+        )
+    )
+    return cfg
+
+
+def DiHiggsAnalysisAddBranches(working_points):
+    analysisTreeBranches = []
+    vars = [
+        "m_h1",
+        "m_h2",
+        "m_hh",
+        "dR_jets_in_h1",
+        "dR_jets_in_h2",
+    ]
+    # looks like resolved_DL1r_FixedCutBEff_77_m_hh
+    for btag_wp in working_points["ak4"]:
+        for var in vars:
+            analysisTreeBranches += [
+                f"EventInfo.resolved_{var}_{btag_wp}   -> resolved_{btag_wp}_{var}"
+            ]
+    # actually needs if, if boosted will be configurable
+    for btag_wp in working_points["vr"]:
+        for var in vars:
+            analysisTreeBranches += [
+                f"EventInfo.boosted_{var}_{btag_wp}   -> boosted_{btag_wp}_{var}"
+            ]
+    return analysisTreeBranches
diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index aef94be08..58f4a074d 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -16,6 +16,10 @@ from AthenaCommon import Logging
 from AthenaConfiguration.AutoConfigFlags import GetFileMD
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
+from HH4bAnalysis.Algs.DiHiggsAnalysis import (
+    DiHiggsAnalysisAddBranches,
+    DiHiggsAnalysisAlgCfg,
+)
 from HH4bAnalysis.Algs.Electrons import ElectronAnalysisSequenceCfg
 from HH4bAnalysis.Algs.Event import (
     EventSelectionAnalysisSequenceCfg,
@@ -91,6 +95,11 @@ def defineArgs(ConfigFlags):
         action="store_true",
         help="use loose event cleaning (to get something to pass)",
     )
+    parser.add_argument(
+        "--do_dihiggs_analysis",
+        action="store_true",
+        help="use loose event cleaning (to get something to pass)",
+    )
     return parser
 
 
@@ -161,6 +170,7 @@ def AnalysisAlgsCfg(
     do_PRW=False,
     prw_files=[],
     lumicalc_files=[],
+    do_dihiggs_analysis=False,
 ):
     if metadata_cache:
         update_metadata(metadata_cache)
@@ -317,18 +327,18 @@ def AnalysisAlgsCfg(
     if metadata_cache:
         cache_metadata(metadata_cache)
 
-    cfg.addEventAlgo(
-        CompFactory.HH4B.DiHiggsAnalysisAlg(
-            "DiHiggsAnalysis",
-            EventInfoKey="EventInfo",
-            SmallJetKey=containers["outputs"]["reco4Jet"].replace("%SYS%", "NOSYS"),
-            LargeJetKey=containers["outputs"]["reco10Jet"].replace("%SYS%", "NOSYS"),
-            doResolvedAnalysis=True,
-            doBoostedAnalysis=True,
-            btag_wps=btag_wps,
-            vr_btag_wps=vr_btag_wps,
+    if do_dihiggs_analysis:
+        cfg.merge(
+            DiHiggsAnalysisAlgCfg(
+                SmallJetKey=containers["outputs"]["reco4Jet"].replace("%SYS%", "NOSYS"),
+                LargeJetKey=containers["outputs"]["reco10Jet"].replace(
+                    "%SYS%",
+                    "NOSYS",
+                ),
+                btag_wps=btag_wps,
+                vr_btag_wps=vr_btag_wps,
+            )
         )
-    )
 
     return cfg
 
@@ -340,6 +350,7 @@ def MiniTupleCfg(
     working_points,
     do_muons=True,
     do_PRW=False,
+    do_dihiggs_analysis=False,
 ):
     cfg = ComponentAccumulator()
     is_daod_physlite = _is_physlite(flags)
@@ -437,28 +448,9 @@ def MiniTupleCfg(
             for btag_wp in working_points["vr"]
         ]
 
-    # Di-Higgs Variables
-    analysisTreeBranches += [
-        f"EventInfo.resolved_m_h1_{btag_wp} -> resolved_m_h1_{btag_wp}"
-        for btag_wp in working_points["ak4"]
-    ]
-    analysisTreeBranches += [
-        f"EventInfo.boosted_m_h1_{btag_wp} -> boosted_m_h1_{btag_wp}"
-        for btag_wp in working_points["vr"]
-    ]
+    if do_dihiggs_analysis:
+        analysisTreeBranches += DiHiggsAnalysisAddBranches(working_points)
 
-    # analysisTreeBranches = [
-    #     "EventInfo.resolved_m_h1   -> resolved_m_h1",
-    #     "EventInfo.resolved_m_h2   -> resolved_m_h2",
-    #     "EventInfo.resolved_m_hh   -> resolved_m_hh",
-    #     "EventInfo.resolved_dR_jets_in_h1   -> resolved_dR_jets_in_h1",
-    #     "EventInfo.resolved_dR_jets_in_h2   -> resolved_dR_jets_in_h2",
-    #     "EventInfo.boosted_m_h1   -> boosted_m_h1",
-    #     "EventInfo.boosted_m_h2   -> boosted_m_h2",
-    #     "EventInfo.boosted_m_hh   -> boosted_m_hh",
-    #     "EventInfo.boosted_dR_jets_in_h1   -> boosted_dR_jets_in_h1",
-    #     "EventInfo.boosted_dR_jets_in_h2   -> boosted_dR_jets_in_h2",
-    # ]
     log.info("Add tree seq")
     cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
 
@@ -574,6 +566,7 @@ def main():
                 do_PRW=do_PRW,
                 prw_files=prw_files,
                 lumicalc_files=lumicalc_files,
+                do_dihiggs_analysis=args.do_dihiggs_analysis,
             ),
             "HH4bSeq",
         )
@@ -585,6 +578,7 @@ def main():
                 working_points={"ak4": args.btag_wps, "vr": args.vr_btag_wps},
                 do_muons=do_muons,
                 do_PRW=do_PRW,
+                do_dihiggs_analysis=args.do_dihiggs_analysis,
             ),
             "HH4bSeq",
         )
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index eced91fd6..62edba6b1 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -37,7 +37,7 @@ namespace HH4B
 
   void DiHiggsAnalysis::initHiggsVarsMap(std::vector<std::string> &higgsVars)
   {
-    float initValue = -1;
+    float initValue = -1.;
     for (std::string var : higgsVars)
     {
       m_higgsVarsMap.insert_or_assign(var, initValue);
@@ -61,7 +61,7 @@ namespace HH4B
 
     // this is a shallow copy container
     ConstDataVector<xAOD::JetContainer> bTaggedJets(SG::VIEW_ELEMENTS);
-
+    // accessor for the btagging info on the jet
     static const SG::AuxElement::ConstAccessor<char> isBtag("ftag_select_" +
                                                             wp);
     // remove non-btagged jets of designated wp
@@ -180,18 +180,6 @@ namespace HH4B
   DiHiggsAnalysis::makeBoostedAnalysis(const xAOD::JetContainer &largeRjets,
                                        std::string wp)
   {
-    // TODO: list
-
-    // cuts
-    // recommended by ftag : Remove the event if any of your signal jets have
-    // relativeDeltaRToVRJet < 1.0.
-    // least pt of large R's 250
-    // largest pt jet large R at least 450
-    // eta < 2.0
-
-    // delta eta between large r jets
-    // make btagging configurable
-
     // check if we have at least 2 large R jets
     if (largeRjets.size() < 2)
     {
@@ -213,6 +201,21 @@ namespace HH4B
         [](const xAOD::IParticle *left, const xAOD::IParticle *right)
         { return left->pt() > right->pt(); });
 
+    // cuts from
+    // https://cds.cern.ch/record/2708599/files/ATL-COM-PHYS-2020-083.pdf don't
+    // use "or" here as the || operator is short-circuited in c++, which means
+    // in the OR checking case it stops checking conditions once one becomes
+    // true
+    if (ptSortedLargeRJets[0]->pt() < 450. ||
+        ptSortedLargeRJets[1]->pt() < 250. ||
+        ptSortedLargeRJets[0]->eta() > 2.0 ||
+        ptSortedLargeRJets[0]->m() < 50. || ptSortedLargeRJets[1]->m() < 50. ||
+        std::abs(ptSortedLargeRJets[0]->eta() - ptSortedLargeRJets[0]->eta()) >
+            1.3)
+    {
+      return;
+    }
+
     h1.m_largeRJet = ptSortedLargeRJets[0];
     h2.m_largeRJet = ptSortedLargeRJets[1];
 
@@ -222,8 +225,13 @@ namespace HH4B
     static const SG::AuxElement::ConstAccessor<
         std::vector<ElementLink<xAOD::IParticleContainer>>>
         m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
-    static const SG::AuxElement::ConstAccessor<char> isBtag("ftag_select_" +
-                                                            wp);
+    // accessor for the btagging info on the jet
+    const SG::AuxElement::ConstAccessor<char> isBtag("ftag_select_" + wp);
+    // recommended by ftag : Remove the event if any of your signal jets have
+    // relativeDeltaRToVRJet < 1.0.
+    const SG::AuxElement::ConstAccessor<float> relativeDeltaRToVRJet(
+        "relativeDeltaRToVRJet");
+    bool isRelativeDeltaRToVRJet = false;
 
     // loop over the Higgs Candidate large R jets, get the btagged VR jets
     // inside of each, need to do std::ref to access the actual objects h1,
@@ -237,11 +245,16 @@ namespace HH4B
           m_acc_VRTrackJets(*untrimmedLargeR);
 
       // get the btagged VR trackjets per large R jet
-      // remove VRjets with invalid elementlinks and non-btagged ones
-      // should we handle this differently?
+      // remove_if is efficient, because you don't have to copy things
+      // somewhere else
+      // remove VRjets with invalid ElementLinks and non-btagged
+      // ones, should we handle this differently?
       VRTrackjets.erase(
           std::remove_if(VRTrackjets.begin(), VRTrackjets.end(),
-                         [](ElementLink<xAOD::IParticleContainer> &VRjet)
+                         [&isRelativeDeltaRToVRJet, &relativeDeltaRToVRJet,
+                          &isBtag] // need to "capture" external variables for
+                                   // the lambda function
+                         (ElementLink<xAOD::IParticleContainer> & VRjet)
                          {
                            if (!VRjet.isValid())
                            {
@@ -259,12 +272,21 @@ namespace HH4B
                            {
                              return true;
                            }
+                           // recommended by ftag : Remove the event if any of
+                           // your signal jets have
+                           // relativeDeltaRToVRJet < 1.0.
+                           if (relativeDeltaRToVRJet(**VRjet) < 1.0)
+                           {
+                             isRelativeDeltaRToVRJet = true;
+                           }
+
                            return false;
                          }),
           VRTrackjets.end());
 
-      // check if we have at least 2 per large R jet, otherwise exit
-      if (VRTrackjets.size() < 2)
+      // check if we have at least 2 per large R jet and no
+      // isRelativeDeltaRToVRJet
+      if (VRTrackjets.size() < 2 || isRelativeDeltaRToVRJet)
       {
         return;
       }
-- 
GitLab


From 3075fc21cc317220e701ff27ea30544eedf21abb Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Mon, 22 Aug 2022 17:47:19 +0200
Subject: [PATCH 27/33] fixing pipeline

---
 HH4bAnalysis/share/VariableDumperConfig.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 58f4a074d..9dcd59a37 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -559,7 +559,7 @@ def main():
                 ConfigFlags,
                 btag_wps=args.btag_wps,
                 vr_btag_wps=args.vr_btag_wps,
-                trigger_chains=[trigger_chains],
+                trigger_chains=trigger_chains,
                 metadata_cache=args.meta_cache,
                 do_muons=do_muons,
                 do_loose=args.loose,
@@ -574,7 +574,7 @@ def main():
             MiniTupleCfg(
                 ConfigFlags,
                 outfname=args.outFile,
-                trigger_chains=[trigger_chains],
+                trigger_chains=trigger_chains,
                 working_points={"ak4": args.btag_wps, "vr": args.vr_btag_wps},
                 do_muons=do_muons,
                 do_PRW=do_PRW,
-- 
GitLab


From 2686e2e7454732d64b82b09dadbbedc658308efa Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Wed, 24 Aug 2022 11:28:33 +0200
Subject: [PATCH 28/33] improve config

---
 HH4bAnalysis/python/Algs/DiHiggsAnalysis.py   | 36 +++++++++++--------
 .../python/Config/AnalysisAlgsConfig.py       |  2 ++
 HH4bAnalysis/share/VariableDumperConfig.py    |  1 +
 HH4bAnalysis/src/DiHiggsAnalysis.cxx          |  8 ++---
 4 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
index 1c9c72296..19bbf1680 100644
--- a/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
+++ b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
@@ -5,10 +5,11 @@ from AthenaConfiguration.ComponentFactory import CompFactory
 def DiHiggsAnalysisAlgCfg(
     SmallJetKey,
     LargeJetKey,
+    doResolvedAnalysis,
+    doBoostedAnalysis,
     btag_wps,
     vr_btag_wps,
 ):
-
     cfg = ComponentAccumulator()
     cfg.addEventAlgo(
         CompFactory.HH4B.DiHiggsAnalysisAlg(
@@ -16,12 +17,18 @@ def DiHiggsAnalysisAlgCfg(
             EventInfoKey="EventInfo",
             SmallJetKey=SmallJetKey,
             LargeJetKey=LargeJetKey,
-            doResolvedAnalysis=True,
-            doBoostedAnalysis=True,
+            doResolvedAnalysis=doResolvedAnalysis,
+            doBoostedAnalysis=doBoostedAnalysis,
             btag_wps=btag_wps,
             vr_btag_wps=vr_btag_wps,
         )
     )
+    # make them global to use them in the tree config
+    global globDoResolvedAnalysis
+    globDoResolvedAnalysis = doResolvedAnalysis
+    global globDoBoostedAnalysis
+    globDoBoostedAnalysis = doBoostedAnalysis
+
     return cfg
 
 
@@ -35,15 +42,16 @@ def DiHiggsAnalysisAddBranches(working_points):
         "dR_jets_in_h2",
     ]
     # looks like resolved_DL1r_FixedCutBEff_77_m_hh
-    for btag_wp in working_points["ak4"]:
-        for var in vars:
-            analysisTreeBranches += [
-                f"EventInfo.resolved_{var}_{btag_wp}   -> resolved_{btag_wp}_{var}"
-            ]
-    # actually needs if, if boosted will be configurable
-    for btag_wp in working_points["vr"]:
-        for var in vars:
-            analysisTreeBranches += [
-                f"EventInfo.boosted_{var}_{btag_wp}   -> boosted_{btag_wp}_{var}"
-            ]
+    if globDoResolvedAnalysis:
+        for btag_wp in working_points["ak4"]:
+            for var in vars:
+                analysisTreeBranches += [
+                    f"EventInfo.resolved_{var}_{btag_wp}   -> resolved_{btag_wp}_{var}"
+                ]
+    if globDoBoostedAnalysis:
+        for btag_wp in working_points["vr"]:
+            for var in vars:
+                analysisTreeBranches += [
+                    f"EventInfo.boosted_{var}_{btag_wp}   -> boosted_{btag_wp}_{var}"
+                ]
     return analysisTreeBranches
diff --git a/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py b/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
index 68f743893..b2c61cc9d 100644
--- a/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
+++ b/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
@@ -198,6 +198,8 @@ def AnalysisAlgsCfg(
                     "%SYS%",
                     "NOSYS",
                 ),
+                doResolvedAnalysis=True,
+                doBoostedAnalysis=True,
                 btag_wps=btag_wps,
                 vr_btag_wps=vr_btag_wps,
             )
diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 5654b7533..69478dbe3 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -35,6 +35,7 @@ def defineArgs(ConfigFlags):
         type=str,
         nargs="*",
         default=[
+            "DL1dv00_FixedCutBEff_70",
             "DL1dv00_FixedCutBEff_77",
             "DL1dv00_FixedCutBEff_85",
         ],
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index 62edba6b1..c26d40d29 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -202,10 +202,10 @@ namespace HH4B
         { return left->pt() > right->pt(); });
 
     // cuts from
-    // https://cds.cern.ch/record/2708599/files/ATL-COM-PHYS-2020-083.pdf don't
-    // use "or" here as the || operator is short-circuited in c++, which means
-    // in the OR checking case it stops checking conditions once one becomes
-    // true
+    // https://cds.cern.ch/record/2708599/files/ATL-COM-PHYS-2020-083.pdf
+    // don't use "or" here as the || operator is short-circuited in c++, which
+    // means in the OR checking case it stops checking conditions once one
+    // becomes true
     if (ptSortedLargeRJets[0]->pt() < 450. ||
         ptSortedLargeRJets[1]->pt() < 250. ||
         ptSortedLargeRJets[0]->eta() > 2.0 ||
-- 
GitLab


From f67fbd182dca2b8dc9ee82265ab6d630b439a088 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 25 Aug 2022 10:06:50 +0200
Subject: [PATCH 29/33] added vr jet counters

---
 HH4bAnalysis/python/Algs/DiHiggsAnalysis.py   |   9 +-
 .../python/Config/AnalysisAlgsConfig.py       |   3 +-
 HH4bAnalysis/src/DiHiggsAnalysis.cxx          | 179 +++++++++++-------
 HH4bAnalysis/src/DiHiggsAnalysis.h            |   9 +-
 HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx       |   8 -
 5 files changed, 124 insertions(+), 84 deletions(-)

diff --git a/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
index 19bbf1680..f99f1824f 100644
--- a/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
+++ b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
@@ -41,7 +41,7 @@ def DiHiggsAnalysisAddBranches(working_points):
         "dR_jets_in_h1",
         "dR_jets_in_h2",
     ]
-    # looks like resolved_DL1r_FixedCutBEff_77_m_hh
+
     if globDoResolvedAnalysis:
         for btag_wp in working_points["ak4"]:
             for var in vars:
@@ -49,9 +49,16 @@ def DiHiggsAnalysisAddBranches(working_points):
                     f"EventInfo.resolved_{var}_{btag_wp}   -> resolved_{btag_wp}_{var}"
                 ]
     if globDoBoostedAnalysis:
+        vars += [
+            "h1_nGhostAssocVrJets",
+            "h1_nBtaggedGhostAssocVrTrackJets",
+            "h2_nGhostAssocVrJets",
+            "h2_nBtaggedGhostAssocVrTrackJets",
+        ]
         for btag_wp in working_points["vr"]:
             for var in vars:
                 analysisTreeBranches += [
                     f"EventInfo.boosted_{var}_{btag_wp}   -> boosted_{btag_wp}_{var}"
                 ]
+
     return analysisTreeBranches
diff --git a/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py b/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
index b2c61cc9d..d9c3ef979 100644
--- a/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
+++ b/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
@@ -195,8 +195,7 @@ def AnalysisAlgsCfg(
             DiHiggsAnalysisAlgCfg(
                 SmallJetKey=containers["outputs"]["reco4Jet"].replace("%SYS%", "NOSYS"),
                 LargeJetKey=containers["outputs"]["reco10Jet"].replace(
-                    "%SYS%",
-                    "NOSYS",
+                    "%SYS%", "NOSYS"
                 ),
                 doResolvedAnalysis=True,
                 doBoostedAnalysis=True,
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.cxx b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
index c26d40d29..408cf6d7e 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.cxx
@@ -31,6 +31,10 @@ namespace HH4B
       vars.push_back("boosted_m_hh_" + wp);
       vars.push_back("boosted_dR_jets_in_h1_" + wp);
       vars.push_back("boosted_dR_jets_in_h2_" + wp);
+      vars.push_back("boosted_h1_nGhostAssocVrJets_" + wp);
+      vars.push_back("boosted_h1_nBtaggedGhostAssocVrTrackJets_" + wp);
+      vars.push_back("boosted_h2_nGhostAssocVrJets_" + wp);
+      vars.push_back("boosted_h2_nBtaggedGhostAssocVrTrackJets_" + wp);
     }
     return vars;
   }
@@ -166,13 +170,13 @@ namespace HH4B
                                                  h2.m_subleadingJet->jetP4());
 
     // write to map
+    // clang-format off
     m_higgsVarsMap["resolved_m_h1_" + wp] = h1.m_fourVector.M();
     m_higgsVarsMap["resolved_m_h2_" + wp] = h2.m_fourVector.M();
-    m_higgsVarsMap["resolved_m_hh_" + wp] =
-        (h1.m_fourVector + h2.m_fourVector).M();
+    m_higgsVarsMap["resolved_m_hh_" + wp] = (h1.m_fourVector + h2.m_fourVector).M(); 
     m_higgsVarsMap["resolved_dR_jets_in_h1_" + wp] = h1.m_dRjets;
     m_higgsVarsMap["resolved_dR_jets_in_h2_" + wp] = h2.m_dRjets;
-
+    // clang-format on
     return;
   };
 
@@ -206,12 +210,15 @@ namespace HH4B
     // don't use "or" here as the || operator is short-circuited in c++, which
     // means in the OR checking case it stops checking conditions once one
     // becomes true
-    if (ptSortedLargeRJets[0]->pt() < 450. ||
-        ptSortedLargeRJets[1]->pt() < 250. ||
+    if (ptSortedLargeRJets[0]->pt() < 250. || //
+        ptSortedLargeRJets[1]->pt() < 250. || //
         ptSortedLargeRJets[0]->eta() > 2.0 ||
-        ptSortedLargeRJets[0]->m() < 50. || ptSortedLargeRJets[1]->m() < 50. ||
-        std::abs(ptSortedLargeRJets[0]->eta() - ptSortedLargeRJets[0]->eta()) >
-            1.3)
+        ptSortedLargeRJets[1]->eta() > 2.0
+        // || ptSortedLargeRJets[0]->m() < 50.
+        // || ptSortedLargeRJets[1]->m() < 50.
+        // || std::abs(ptSortedLargeRJets[0]->eta() -
+        //          ptSortedLargeRJets[0]->eta()) > 1.3
+    )
     {
       return;
     }
@@ -219,17 +226,20 @@ namespace HH4B
     h1.m_largeRJet = ptSortedLargeRJets[0];
     h2.m_largeRJet = ptSortedLargeRJets[1];
 
+    // @note create needed accessors
     // ghost associated VR track jets are only on the untrimmed 1.0 jets
     static const SG::AuxElement::ConstAccessor<ElementLink<xAOD::JetContainer>>
         m_acc_largeR_untrimmed("Parent");
     static const SG::AuxElement::ConstAccessor<
         std::vector<ElementLink<xAOD::IParticleContainer>>>
         m_acc_VRTrackJets("GhostAntiKtVR30Rmax4Rmin02PV0TrackJets");
-    // accessor for the btagging info on the jet
-    const SG::AuxElement::ConstAccessor<char> isBtag("ftag_select_" + wp);
+    // accessor for the btagging info on the jet, no static because forwarded
+    // to function
+    static const SG::AuxElement::ConstAccessor<char> isBtag("ftag_select_" +
+                                                            wp);
     // recommended by ftag : Remove the event if any of your signal jets have
     // relativeDeltaRToVRJet < 1.0.
-    const SG::AuxElement::ConstAccessor<float> relativeDeltaRToVRJet(
+    static const SG::AuxElement::ConstAccessor<float> relativeDeltaRToVRJet(
         "relativeDeltaRToVRJet");
     bool isRelativeDeltaRToVRJet = false;
 
@@ -244,78 +254,104 @@ namespace HH4B
       std::vector<ElementLink<xAOD::IParticleContainer>> VRTrackjets =
           m_acc_VRTrackJets(*untrimmedLargeR);
 
-      // get the btagged VR trackjets per large R jet
+      // filter VR jets
       // remove_if is efficient, because you don't have to copy things
       // somewhere else
-      // remove VRjets with invalid ElementLinks and non-btagged
-      // ones, should we handle this differently?
+      int nGhostAssocVrJets = 0;
       VRTrackjets.erase(
-          std::remove_if(VRTrackjets.begin(), VRTrackjets.end(),
-                         [&isRelativeDeltaRToVRJet, &relativeDeltaRToVRJet,
-                          &isBtag] // need to "capture" external variables for
-                                   // the lambda function
-                         (ElementLink<xAOD::IParticleContainer> & VRjet)
-                         {
-                           if (!VRjet.isValid())
-                           {
-                             ANA_MSG_WARNING("Skipped invalid VR jet link!");
-                             return true;
-                           }
-                           // the ftag sequence does not tag all of them
-                           if (!isBtag.isAvailable(**VRjet))
-                           {
-                             ANA_MSG_DEBUG("Skipped non B-tagged VR jet");
-                             return true;
-                           }
-                           // keep only btagged jets with a designated wp
-                           if (!isBtag(**VRjet))
-                           {
-                             return true;
-                           }
-                           // recommended by ftag : Remove the event if any of
-                           // your signal jets have
-                           // relativeDeltaRToVRJet < 1.0.
-                           if (relativeDeltaRToVRJet(**VRjet) < 1.0)
-                           {
-                             isRelativeDeltaRToVRJet = true;
-                           }
-
-                           return false;
-                         }),
+          std::remove_if(
+              VRTrackjets.begin(), VRTrackjets.end(),
+              [&nGhostAssocVrJets,
+               &isRelativeDeltaRToVRJet] // need to "capture" external
+                                         // variables for the lambda function
+              (ElementLink<xAOD::IParticleContainer> & VRjet)
+              {
+                // count only the ftagged ones
+                if ((*VRjet)->pt() > 10.)
+                {
+                  nGhostAssocVrJets += 1;
+                }
+                if (!VRjet.isValid())
+                {
+                  ANA_MSG_WARNING("Skipped invalid VR jet link!");
+                  return true;
+                }
+                // the ftag sequence does not tag all of them
+                if (!isBtag.isAvailable(**VRjet))
+                {
+                  ANA_MSG_DEBUG("Skipped non B-tagged VR jet");
+                  return true;
+                }
+                // keep only btagged jets with a designated wp
+                // (the ftag sequence also cuts on 10GeV)
+                if (!isBtag(**VRjet))
+                {
+                  return true;
+                }
+                // recommended by ftag : Remove the event if any of
+                // your signal jets have
+                // relativeDeltaRToVRJet < 1.0.
+                if (relativeDeltaRToVRJet(**VRjet) < 1.0)
+                {
+                  isRelativeDeltaRToVRJet = true;
+                }
+
+                return false;
+              }),
           VRTrackjets.end());
 
+      h.m_nGhostAssocVrJets = nGhostAssocVrJets;
+      h.m_nBtaggedGhostAssocVrJets = VRTrackjets.size();
+
       // check if we have at least 2 per large R jet and no
-      // isRelativeDeltaRToVRJet
+      // isRelativeDeltaRToVRJet < 1.0
       if (VRTrackjets.size() < 2 || isRelativeDeltaRToVRJet)
       {
-        return;
+        h.m_doDecorate = false;
+      }
+      else
+      {
+        // find the leading vr jets
+        std::partial_sort(
+            VRTrackjets.begin(),     // Iterator from which to start sorting
+            VRTrackjets.begin() + 2, // Use begin + N to sort first N
+            VRTrackjets.end(),       // iterator to end
+            [](ElementLink<xAOD::IParticleContainer> &left,
+               ElementLink<xAOD::IParticleContainer> &right)
+            { return (*left)->pt() > (*right)->pt(); });
+
+        h.m_leadingJet = dynamic_cast<const xAOD::Jet *>(*VRTrackjets[0]);
+        h.m_subleadingJet = dynamic_cast<const xAOD::Jet *>(*VRTrackjets[1]);
+
+        // calc variables
+        h.m_fourVector = h.m_leadingJet->jetP4() + h.m_subleadingJet->jetP4();
+        h.m_dRjets = ROOT::Math::VectorUtil::DeltaR(
+            h.m_leadingJet->jetP4(), h.m_subleadingJet->jetP4());
       }
-
-      // find the leading vr jets
-      std::partial_sort(
-          VRTrackjets.begin(),     // Iterator from which to start sorting
-          VRTrackjets.begin() + 2, // Use begin + N to sort first N
-          VRTrackjets.end(),       // iterator to end
-          [](ElementLink<xAOD::IParticleContainer> &left,
-             ElementLink<xAOD::IParticleContainer> &right)
-          { return (*left)->pt() > (*right)->pt(); });
-
-      h.m_leadingJet = dynamic_cast<const xAOD::Jet *>(*VRTrackjets[0]);
-      h.m_subleadingJet = dynamic_cast<const xAOD::Jet *>(*VRTrackjets[1]);
-
-      // calc variables
-      h.m_fourVector = h.m_leadingJet->jetP4() + h.m_subleadingJet->jetP4();
-      h.m_dRjets = ROOT::Math::VectorUtil::DeltaR(h.m_leadingJet->jetP4(),
-                                                  h.m_subleadingJet->jetP4());
     }
 
     // write to map
-    m_higgsVarsMap["boosted_m_h1_" + wp] = h1.m_fourVector.M();
-    m_higgsVarsMap["boosted_m_h2_" + wp] = h2.m_fourVector.M();
-    m_higgsVarsMap["boosted_m_hh_" + wp] =
-        (h1.m_fourVector + h2.m_fourVector).M();
-    m_higgsVarsMap["boosted_dR_jets_in_h1_" + wp] = h1.m_dRjets;
-    m_higgsVarsMap["boosted_dR_jets_in_h2_" + wp] = h2.m_dRjets;
+    if (h1.m_doDecorate)
+    {
+      m_higgsVarsMap["boosted_m_h1_" + wp] = h1.m_fourVector.M();
+      m_higgsVarsMap["boosted_dR_jets_in_h1_" + wp] = h1.m_dRjets;
+    }
+    if (h2.m_doDecorate)
+    {
+      m_higgsVarsMap["boosted_m_h2_" + wp] = h2.m_fourVector.M();
+      m_higgsVarsMap["boosted_dR_jets_in_h2_" + wp] = h2.m_dRjets;
+    }
+    if (h1.m_doDecorate && h2.m_doDecorate)
+    {
+      m_higgsVarsMap["boosted_m_hh_" + wp] =
+          (h1.m_fourVector + h2.m_fourVector).M();
+    }
+    // clang-format off
+    m_higgsVarsMap["boosted_h1_nGhostAssocVrJets_" + wp] = h1.m_nGhostAssocVrJets; 
+    m_higgsVarsMap["boosted_h1_nBtaggedGhostAssocVrTrackJets_" + wp] = h1.m_nBtaggedGhostAssocVrJets; 
+    m_higgsVarsMap["boosted_h2_nGhostAssocVrJets_" + wp] = h2.m_nGhostAssocVrJets; 
+    m_higgsVarsMap["boosted_h2_nBtaggedGhostAssocVrTrackJets_" + wp] = h2.m_nBtaggedGhostAssocVrJets;
+    // clang-format on
     return;
   };
 
@@ -323,5 +359,4 @@ namespace HH4B
   {
     return m_higgsVarsMap;
   };
-
 };
diff --git a/HH4bAnalysis/src/DiHiggsAnalysis.h b/HH4bAnalysis/src/DiHiggsAnalysis.h
index 55596aec4..8d21acdc4 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysis.h
+++ b/HH4bAnalysis/src/DiHiggsAnalysis.h
@@ -22,8 +22,15 @@ namespace HH4B
     ROOT::Math::LorentzVector<ROOT::Math::PtEtaPhiM4D<float>> m_fourVector;
     // dR between leading and subleading jet
     float m_dRjets = -1;
+
     // for boosted analysis
     const xAOD::Jet *m_largeRJet = nullptr;
+    // Nr of ghost associated Vr Jets
+    int m_nGhostAssocVrJets = -1;
+    // Nr of btagged ghost associated Vr Jets
+    int m_nBtaggedGhostAssocVrJets = -1;
+    // don't decorate if requirements are not met
+    bool m_doDecorate = true;
   };
 
   class DiHiggsAnalysis
@@ -37,7 +44,7 @@ public:
     // do boosted Analysis
     void makeBoostedAnalysis(const xAOD::JetContainer &largeRjets,
                              std::string wp);
-    // returns h_cand_vars for other purposes
+    // returns m_higgsVarsMap for other purposes
     std::unordered_map<std::string, float> getHiggsVarsMap();
     // map holding the final vars (like dict in python)
     // access/write like : m_diHiggs_vars[var];
diff --git a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
index 3ab13395e..2d87230a8 100644
--- a/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
+++ b/HH4bAnalysis/src/DiHiggsAnalysisAlg.cxx
@@ -41,11 +41,6 @@ namespace HH4B
 
   StatusCode DiHiggsAnalysisAlg ::execute()
   {
-    // jump out if no analysis is selected
-    if (!m_doResolvedAnalysis or !m_doResolvedAnalysis)
-    {
-      return StatusCode::SUCCESS;
-    }
     ATH_MSG_DEBUG("Executing " << name());
 
     // get the xAOD objects
@@ -56,9 +51,6 @@ namespace HH4B
     ATH_CHECK(antiKt4RecoJets.isValid());
     ATH_CHECK(antiKt10RecoJets.isValid());
 
-    // TODO: make configurable with which btagging WP Higgs candidates are
-    // created
-
     // create the analysis object
     DiHiggsAnalysis hh4b_analysis;
     // write defaults (-1) into the Higgs variable map
-- 
GitLab


From 6ed3d25b1572e88417e5b3e8535eff63ebcae9f9 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 25 Aug 2022 10:25:38 +0200
Subject: [PATCH 30/33] Update HH4bAnalysis/src/VariableDumperAlg.cxx

---
 HH4bAnalysis/src/VariableDumperAlg.cxx | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index 067117406..de1a0e8f1 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -51,7 +51,6 @@ namespace HH4B
       std::string sysname;
       ATH_CHECK(m_systematicsList.service().makeSystematicsName(sysname,
                                                                 "%SYS%", sys));
-
       ATH_MSG_VERBOSE("Will apply sysname \"" << sysname << "\" for event");
 
       // get the xAOD objects
@@ -65,8 +64,6 @@ namespace HH4B
       ATH_CHECK(m_muonHandle.retrieve(muons, sys));
       const xAOD::JetContainer *antiKt4RecoJets(nullptr);
       ATH_CHECK(m_jetsmallRHandle.retrieve(antiKt4RecoJets, sys));
-      const xAOD::JetContainer *antiKt10RecoJets(nullptr);
-
       if (!m_jetlargeRHandle.empty())
       {
         ATH_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
-- 
GitLab


From 44c1f978218f48cdb6a092721645f3ab7e1693a8 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 25 Aug 2022 10:26:42 +0200
Subject: [PATCH 31/33] Deleted .asetup.save

---
 .asetup.save | 79 ----------------------------------------------------
 1 file changed, 79 deletions(-)
 delete mode 100644 .asetup.save

diff --git a/.asetup.save b/.asetup.save
deleted file mode 100644
index 530699c42..000000000
--- a/.asetup.save
+++ /dev/null
@@ -1,79 +0,0 @@
-#Release cmake
-
-export LANG="C"
-export LC_ALL="C"
-export COOL_ORA_ENABLE_ADAPTIVE_OPT="Y"
-export ASETUP_PRINTLEVEL="0"
-export BINARY_TAG="x86_64-centos7-gcc11-opt"
-export CMTCONFIG="x86_64-centos7-gcc11-opt"
-export ASETUP_SYSBIN=`mktemp -d /tmp/freder/.asetup-sysbin-XXXXXX_$$`
-source $AtlasSetup/scripts/sys_exe-alias.sh ''
-if [ -n "${MAKEFLAGS:+x}" ]; then
-    asetup_flags=`echo ${MAKEFLAGS} | \grep ' -l'`
-    if [ -z "${asetup_flags}" ]; then
-        export MAKEFLAGS="${MAKEFLAGS} -l32"
-    fi
-else
-    export MAKEFLAGS="-j32 -l32"
-fi
-source /cvmfs/sft.cern.ch/lcg/releases/gcc/11.2.0-8a51a/x86_64-centos7/setup.sh
-export CC=`\env which gcc 2>/dev/null`
-[[ -z $CC ]] && unset CC
-export CXX=`\env which g++ 2>/dev/null`
-[[ -z $CXX ]] && unset CXX
-export FC=`\env which gfortran 2>/dev/null`
-[[ -z $FC ]] && unset FC
-export CMAKE_NO_VERBOSE="1"
-type lsetup >/dev/null 2>/dev/null
-if [ $? -ne 0 ]; then
-   source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh --quiet
-fi
-source $ATLAS_LOCAL_ROOT_BASE/packageSetups/localSetup.sh --quiet "cmake 3.21.3"
-if [ -z "${AtlasSetup:+x}" ]; then
-    export AtlasSetup="/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/AtlasSetup/V02-00-44/AtlasSetup"
-    export AtlasSetupVersion="AtlasSetup-02-00-44"
-fi
-export FRONTIER_LOG_LEVEL="warning"
-export ATLAS_POOLCOND_PATH="/cvmfs/atlas-condb.cern.ch/repo/conditions"
-export ATLAS_DB_AREA="/cvmfs/atlas.cern.ch/repo/sw/database"
-export DBRELEASE_OVERRIDE="current"
-export AtlasBaseDir="/cvmfs/atlas.cern.ch/repo/sw/software/22.2"
-export LCG_RELEASE_BASE="/cvmfs/atlas.cern.ch/repo/sw/software/22.2/sw/lcg/releases"
-export AtlasBuildStamp="2022-07-29T0001"
-export AtlasReleaseType="stable"
-export AtlasBuildBranch="22.2"
-export AtlasProject="AthAnalysis"
-export TDAQ_RELEASE_BASE="/cvmfs/atlas.cern.ch/repo/sw/tdaq/offline"
-export ATLAS_RELEASE_BASE="/cvmfs/atlas.cern.ch/repo/sw/software/22.2"
-export AtlasArea="/cvmfs/atlas.cern.ch/repo/sw/software/22.2/AthAnalysis/22.2.84"
-export AtlasVersion="22.2.84"
-source /cvmfs/atlas.cern.ch/repo/sw/software/22.2/AthAnalysis/22.2.84/InstallArea/x86_64-centos7-gcc11-opt/setup.sh
-asetup_status=$?
-if [ ${asetup_status} -ne 0 ]; then
-    \echo "AtlasSetup(ERROR): sourcing release setup script (/cvmfs/atlas.cern.ch/repo/sw/software/22.2/AthAnalysis/22.2.84/InstallArea/x86_64-centos7-gcc11-opt/setup.sh) failed"
-fi
-export TestArea="/lustre/fs22/group/atlas/freder/hh/hh4b-analysis"
-alias_sys_exe emacs
-echo $LD_LIBRARY_PATH | egrep "LCG_[^/:]*/curl/" >/dev/null
-if [ $? -eq 0 ]; then
-    alias_sys_exe_envU git
-fi
-\expr 1 \* 1 + 1 >/dev/null 2>&1
-if [ $? -ne 0 ]; then
-    echo -e '\nMaking workaround-alias for expr on this *OLD* machine'; alias_sys_exe expr
-fi
-export PATH="${ASETUP_SYSBIN}:${PATH}"
-
-#Release Summary as follows:
-#Release base=/cvmfs/atlas.cern.ch/repo/sw/software/22.2
-#Release project=AthAnalysis
-#Release releaseNum=22.2.84
-#Release asconfig=x86_64-centos7-gcc11-opt
-
-# Execute user-specified epilog
-
-source /cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/swConfig/asetup/asetupEpilog.sh
-script_status=$?
-if [ ${script_status} -ne 0 ]; then
-    \echo "AtlasSetup(ERROR): User-specified epilog (source /cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/swConfig/asetup/asetupEpilog.sh) reported failure (error ${script_status})"
-fi
-- 
GitLab


From b75942c65b15f12bb77d71de55c57c7f5d979a20 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 25 Aug 2022 10:30:56 +0200
Subject: [PATCH 32/33] fix pipeline

---
 HH4bAnalysis/src/VariableDumperAlg.cxx | 1 +
 1 file changed, 1 insertion(+)

diff --git a/HH4bAnalysis/src/VariableDumperAlg.cxx b/HH4bAnalysis/src/VariableDumperAlg.cxx
index de1a0e8f1..6297167c6 100644
--- a/HH4bAnalysis/src/VariableDumperAlg.cxx
+++ b/HH4bAnalysis/src/VariableDumperAlg.cxx
@@ -64,6 +64,7 @@ namespace HH4B
       ATH_CHECK(m_muonHandle.retrieve(muons, sys));
       const xAOD::JetContainer *antiKt4RecoJets(nullptr);
       ATH_CHECK(m_jetsmallRHandle.retrieve(antiKt4RecoJets, sys));
+      const xAOD::JetContainer *antiKt10RecoJets(nullptr);
       if (!m_jetlargeRHandle.empty())
       {
         ATH_CHECK(m_jetlargeRHandle.retrieve(antiKt10RecoJets, sys));
-- 
GitLab


From 4c2f1ddc004ef79104cb9f70842b4766ce18c471 Mon Sep 17 00:00:00 2001
From: Frederic Renner <frederic.renner@cern.ch>
Date: Thu, 25 Aug 2022 12:32:22 +0200
Subject: [PATCH 33/33] put analaysis config onto ConfigFlags

---
 HH4bAnalysis/python/Algs/DiHiggsAnalysis.py   | 18 ++++++------------
 .../python/Config/AnalysisAlgsConfig.py       |  3 +--
 HH4bAnalysis/python/Config/MiniTupleConfig.py |  2 +-
 HH4bAnalysis/share/VariableDumperConfig.py    | 19 +++++++++++++++++--
 4 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
index f99f1824f..32c38b549 100644
--- a/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
+++ b/HH4bAnalysis/python/Algs/DiHiggsAnalysis.py
@@ -3,10 +3,9 @@ from AthenaConfiguration.ComponentFactory import CompFactory
 
 
 def DiHiggsAnalysisAlgCfg(
+    flags,
     SmallJetKey,
     LargeJetKey,
-    doResolvedAnalysis,
-    doBoostedAnalysis,
     btag_wps,
     vr_btag_wps,
 ):
@@ -17,22 +16,17 @@ def DiHiggsAnalysisAlgCfg(
             EventInfoKey="EventInfo",
             SmallJetKey=SmallJetKey,
             LargeJetKey=LargeJetKey,
-            doResolvedAnalysis=doResolvedAnalysis,
-            doBoostedAnalysis=doBoostedAnalysis,
+            doResolvedAnalysis=flags.do_resolved_analysis,
+            doBoostedAnalysis=flags.do_boosted_analysis,
             btag_wps=btag_wps,
             vr_btag_wps=vr_btag_wps,
         )
     )
-    # make them global to use them in the tree config
-    global globDoResolvedAnalysis
-    globDoResolvedAnalysis = doResolvedAnalysis
-    global globDoBoostedAnalysis
-    globDoBoostedAnalysis = doBoostedAnalysis
 
     return cfg
 
 
-def DiHiggsAnalysisAddBranches(working_points):
+def DiHiggsAnalysisAddBranches(flags, working_points):
     analysisTreeBranches = []
     vars = [
         "m_h1",
@@ -42,13 +36,13 @@ def DiHiggsAnalysisAddBranches(working_points):
         "dR_jets_in_h2",
     ]
 
-    if globDoResolvedAnalysis:
+    if flags.do_resolved_analysis:
         for btag_wp in working_points["ak4"]:
             for var in vars:
                 analysisTreeBranches += [
                     f"EventInfo.resolved_{var}_{btag_wp}   -> resolved_{btag_wp}_{var}"
                 ]
-    if globDoBoostedAnalysis:
+    if flags.do_boosted_analysis:
         vars += [
             "h1_nGhostAssocVrJets",
             "h1_nBtaggedGhostAssocVrTrackJets",
diff --git a/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py b/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
index d9c3ef979..1f2d2bc4e 100644
--- a/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
+++ b/HH4bAnalysis/python/Config/AnalysisAlgsConfig.py
@@ -193,12 +193,11 @@ def AnalysisAlgsCfg(
     if do_dihiggs_analysis:
         cfg.merge(
             DiHiggsAnalysisAlgCfg(
+                flags,
                 SmallJetKey=containers["outputs"]["reco4Jet"].replace("%SYS%", "NOSYS"),
                 LargeJetKey=containers["outputs"]["reco10Jet"].replace(
                     "%SYS%", "NOSYS"
                 ),
-                doResolvedAnalysis=True,
-                doBoostedAnalysis=True,
                 btag_wps=btag_wps,
                 vr_btag_wps=vr_btag_wps,
             )
diff --git a/HH4bAnalysis/python/Config/MiniTupleConfig.py b/HH4bAnalysis/python/Config/MiniTupleConfig.py
index f7db7866d..608cc6f58 100644
--- a/HH4bAnalysis/python/Config/MiniTupleConfig.py
+++ b/HH4bAnalysis/python/Config/MiniTupleConfig.py
@@ -113,7 +113,7 @@ def MiniTupleCfg(
         ]
 
     if do_dihiggs_analysis:
-        analysisTreeBranches += DiHiggsAnalysisAddBranches(working_points)
+        analysisTreeBranches += DiHiggsAnalysisAddBranches(flags, working_points)
 
     log.info("Add tree seq")
     cfg.merge(AnalysisTreeAlgCfg(flags, branches=analysisTreeBranches))
diff --git a/HH4bAnalysis/share/VariableDumperConfig.py b/HH4bAnalysis/share/VariableDumperConfig.py
index 69478dbe3..63228893f 100755
--- a/HH4bAnalysis/share/VariableDumperConfig.py
+++ b/HH4bAnalysis/share/VariableDumperConfig.py
@@ -1,7 +1,7 @@
 #!/bin/env python
 
 #
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
 #
 
 #
@@ -78,8 +78,21 @@ def defineArgs(ConfigFlags):
     parser.add_argument(
         "--do_dihiggs_analysis",
         action="store_true",
-        help="use loose event cleaning (to get something to pass)",
+        help="run DiHiggs anaylysis",
+    )
+    parser.add_argument(
+        "--do_resolved_analysis",
+        action="store_true",
+        default=True,
+        help="activate resolved analysis",
     )
+    parser.add_argument(
+        "--do_boosted_analysis",
+        action="store_true",
+        default=True,
+        help="activate boosted",
+    )
+
     return parser
 
 
@@ -126,6 +139,8 @@ def main():
 
     fileMD = GetFileMD(ConfigFlags.Input.Files[0])
     ConfigFlags.addFlag("Input.AMITag", fileMD.get("AMITag", ""))
+    ConfigFlags.addFlag("do_resolved_analysis", args.do_resolved_analysis)
+    ConfigFlags.addFlag("do_boosted_analysis", args.do_boosted_analysis)
 
     ConfigFlags.lock()
 
-- 
GitLab