From cf25d50b00c48d260ce6859254629a5e749f82f6 Mon Sep 17 00:00:00 2001 From: "Patrick L.S. Connor" <connorpa@mail.desy.de> Date: Mon, 13 Jan 2025 18:01:44 +0100 Subject: [PATCH 1/7] using single-threaded EDAnalyzer (fix https://gitlab.cern.ch/cms-analysis/general/DasAnalysisSystem/Core/-/issues/71) --- Ntupliser/plugins/Ntupliser.cc | 11 +---------- Ntupliser/plugins/Ntupliser.h | 7 ++----- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Ntupliser/plugins/Ntupliser.cc b/Ntupliser/plugins/Ntupliser.cc index 44de6c95..f7646594 100644 --- a/Ntupliser/plugins/Ntupliser.cc +++ b/Ntupliser/plugins/Ntupliser.cc @@ -286,15 +286,6 @@ void Ntupliser::beginJob() void Ntupliser::endJob() { metainfo.Set<bool>("git", "complete", true); - cout << __FILE__ << ':' << __func__ << endl; -} -void Ntupliser::beginRun(edm::Run const& iRun, edm::EventSetup const& iSetup) -{ - cout << __FILE__ << ':' << __func__ << endl; -} -void Ntupliser::endRun(edm::Run const& iRun, edm::EventSetup const& iSetup) -{ - cout << __FILE__ << ':' << __func__ << endl; } #endif @@ -680,4 +671,4 @@ Ntupliser::~Ntupliser() } #endif -DEFINE_FWK_MODULE(Ntupliser); \ No newline at end of file +DEFINE_FWK_MODULE(Ntupliser); diff --git a/Ntupliser/plugins/Ntupliser.h b/Ntupliser/plugins/Ntupliser.h index 5ffde872..a1d7683f 100644 --- a/Ntupliser/plugins/Ntupliser.h +++ b/Ntupliser/plugins/Ntupliser.h @@ -1,6 +1,6 @@ #pragma once -#include "FWCore/Framework/interface/EDAnalyzer.h" +#include "FWCore/Framework/interface/one/EDAnalyzer.h" #include "FWCore/Framework/interface/EventSetup.h" #include "FWCore/Framework/interface/ESHandle.h" #include "FWCore/ServiceRegistry/interface/Service.h" @@ -24,16 +24,13 @@ #include <boost/property_tree/ptree.hpp> -class Ntupliser : public edm::EDAnalyzer -{ +class Ntupliser : public edm::one::EDAnalyzer<edm::one::SharedResources> { public: typedef reco::Particle::LorentzVector LorentzVector; // default method in EDAnalyzer explicit Ntupliser(edm::ParameterSet const& cfg); virtual void beginJob() override; - virtual void beginRun(edm::Run const& iRun, edm::EventSetup const& iSetup) override; - virtual void endRun(edm::Run const& iRun, edm::EventSetup const& iSetup) override; virtual void analyze(edm::Event const& iEvent, edm::EventSetup const& iSetup) override; virtual void endJob() override; virtual ~Ntupliser() override; -- GitLab From 65740f65c3262f19b8d44fee80ca8b112e789171 Mon Sep 17 00:00:00 2001 From: "Patrick L.S. Connor" <connorpa@mail.desy.de> Date: Tue, 14 Jan 2025 18:15:26 +0100 Subject: [PATCH 2/7] adapting framework to 2024 data --- Ntupliser/plugins/BuildFile.xml | 3 +- Ntupliser/plugins/Ntupliser.cc | 21 ++-- Ntupliser/plugins/Parameters.cc | 3 + Ntupliser/plugins/Parameters.h | 3 +- Ntupliser/plugins/helper.cc | 183 ++++++++---------------------- Ntupliser/plugins/helper.h | 4 +- Ntupliser/python/Ntupliser_cfg.py | 54 ++++++--- Ntupliser/scripts/mkNtuples | 15 +-- 8 files changed, 113 insertions(+), 173 deletions(-) diff --git a/Ntupliser/plugins/BuildFile.xml b/Ntupliser/plugins/BuildFile.xml index 0c2531ac..9ecd1bf0 100644 --- a/Ntupliser/plugins/BuildFile.xml +++ b/Ntupliser/plugins/BuildFile.xml @@ -14,6 +14,7 @@ <use name="SimDataFormats/GeneratorProducts" /> <use name="SimDataFormats/PileupSummaryInfo" /> <use name="Core/Objects" /> - <flags CXXFLAGS="-g -DDEBUG -std=c++17" EDM_PLUGIN="1"/> + <flags CXXFLAGS="-g" EDM_PLUGIN="1"/> + <flags CPPDEFINES="DEBUG"/> </library> diff --git a/Ntupliser/plugins/Ntupliser.cc b/Ntupliser/plugins/Ntupliser.cc index f7646594..58748184 100644 --- a/Ntupliser/plugins/Ntupliser.cc +++ b/Ntupliser/plugins/Ntupliser.cc @@ -21,6 +21,7 @@ namespace pt = boost::property_tree; using namespace std; namespace fs = filesystem; +namespace /* anonymous */ { // sort by decreasing pt template<typename DAStype> void Sort (vector<DAStype>*& collection) { @@ -32,6 +33,7 @@ template<> void Sort (vector<DAS::FourVector>*& collection) sort(collection->begin(), collection->end(), [](DAS::FourVector &a, DAS::FourVector &b) { return a.Pt() > b.Pt(); } ); } +} // end of anonymous namespace //////////////////////////////////////////////////////////////////////////////// /// Constructor, only initialising the members. @@ -210,7 +212,7 @@ void Ntupliser::getRecJets () DAS::RecJet recjet = h.GetRecJet(*itJet); // we keep all jets and give set the weight to 0 for jets not fullfiling the quality criterion - if (!h.TightLepVetoID(*itJet)) recjet.weights.front() = 0.; + if (!h.JetID(*itJet)) recjet.weights.front() = 0.; // we keep only jet with pt > 20 GeV and in the tracker acceptance //if (recjet.p4.Pt() < 10 /* GeV */ || abs(recjet.p4.Eta()) > 5.0) continue; @@ -282,12 +284,11 @@ void Ntupliser::beginJob() } } -#ifndef DOXYGEN_SHOULD_SKIP_THIS void Ntupliser::endJob() { + cout << __FILE__ << ':' << __func__ << endl; metainfo.Set<bool>("git", "complete", true); } -#endif void Ntupliser::analyze(edm::Event const& iEvent, edm::EventSetup const& iSetup) { @@ -429,14 +430,14 @@ void Ntupliser::initialise (edm::Event const& iEvent) iEvent.getByToken(p.metResultsToken, metResults); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS +namespace /* anonymous */ { string DelLastDigits (string n) { while (isdigit(n.back())) n.pop_back(); return n; } -#endif +} // end of anonymous namespace ////////////////////////////////////////////////////////////////////////////////////////// /// Finds the bits corresponding to the HLT jet pt triggers. @@ -458,9 +459,16 @@ bool Ntupliser::trigger (edm::Event const& iEvent) if (name != p.triggerNames_[k]) continue; bit = triggerResults->accept(itrig); + // indirect way of testing the CMSSW version is to check the GCC version +#if __GNUC__ < 12 // Run 2 (CMSSW_12, GCC 10) preHLT = triggerPrescales->getPrescaleForIndex(itrig); preL1min = triggerPrescalesl1min->getPrescaleForIndex(itrig); preL1max = triggerPrescalesl1max->getPrescaleForIndex(itrig); +#else // Run 3 (CMSSW_13, GCC 12) + preHLT = triggerPrescales->getPrescaleForIndex<double>(itrig); + preL1min = triggerPrescalesl1min->getPrescaleForIndex<double>(itrig); + preL1max = triggerPrescalesl1max->getPrescaleForIndex<double>(itrig); +#endif break; } //--- if at least one monitored trigger has fired passTrigger becomes true @@ -665,10 +673,9 @@ void Ntupliser::getEventVariables (edm::Event const& iEvent) // https://twiki.cern.ch/twiki/bin/view/CMS/MissingETUncertaintyPrescription } -#ifndef DOXYGEN_SHOULD_SKIP_THIS Ntupliser::~Ntupliser() { + cout << __FILE__ << ':' << __func__ << endl; } -#endif DEFINE_FWK_MODULE(Ntupliser); diff --git a/Ntupliser/plugins/Parameters.cc b/Ntupliser/plugins/Parameters.cc index 1246ed9c..a06f1d36 100644 --- a/Ntupliser/plugins/Parameters.cc +++ b/Ntupliser/plugins/Parameters.cc @@ -48,6 +48,9 @@ DAS::Parameters::Parameters(ParameterSet const& cfg, sandbox(gP<bool>("sandbox")), config(ReadJSON(gP<string>("config"), sandbox)), options(config.get_child("flags.options")), + labels (config.get_child("flags.labels")), + CHS (find_by_value(labels, "CHS")), + PUPPI (find_by_value(labels, "PUPPI")), jets (find_by_value(options, "jets" )), PUjetID (gP<bool>("PUjetID")), flavour (find_by_value(options, "flavour" )), diff --git a/Ntupliser/plugins/Parameters.h b/Ntupliser/plugins/Parameters.h index 2c807b91..5e0e41ad 100644 --- a/Ntupliser/plugins/Parameters.h +++ b/Ntupliser/plugins/Parameters.h @@ -58,7 +58,8 @@ struct Parameters { const bool sandbox; //!< flag for CRAB sandbox static boost::property_tree::ptree ReadJSON (std::filesystem::path, bool = false); boost::property_tree::ptree config; //!< input JSON config - const boost::property_tree::ptree& options; //!< booleans to steer branch filling + const boost::property_tree::ptree& options, labels; //!< booleans to steer branch filling + const bool CHS, PUPPI; edm::EDGetTokenT<GenEventInfoProduct> genEvtInfoToken; edm::EDGetTokenT<reco::GenParticleCollection> genParticlesToken; diff --git a/Ntupliser/plugins/helper.cc b/Ntupliser/plugins/helper.cc index 25689611..cabae7dd 100644 --- a/Ntupliser/plugins/helper.cc +++ b/Ntupliser/plugins/helper.cc @@ -14,7 +14,7 @@ using namespace std; DAS::Helper::Helper (DAS::Parameters& parameters) : p(parameters) {} //////////////////////////////////////////////////////////////////////////////// -/// Helper to get `DAS::GenJet` from MiniAOD without flavour +/// \brief Helper to get `DAS::GenJet` from MiniAOD without flavour DAS::GenJet DAS::Helper::GetGenJet (const reco::Jet &ijet) { DAS::GenJet jjet; @@ -26,7 +26,7 @@ DAS::GenJet DAS::Helper::GetGenJet (const reco::Jet &ijet) } //////////////////////////////////////////////////////////////////////////////// -/// Helper to get `DAS::GenJet` from MiniAOD with flavour +/// \brief Helper to get `DAS::GenJet` from MiniAOD with flavour DAS::GenJet DAS::Helper::GetGenJet (const reco::JetFlavourInfoMatching & ijet) { const reco::Jet& Jet = *(ijet.first.get()); @@ -45,7 +45,7 @@ DAS::GenJet DAS::Helper::GetGenJet (const reco::JetFlavourInfoMatching & ijet) } //////////////////////////////////////////////////////////////////////////////// -/// Helper to get `DAS::RecJet` from MiniAOD +/// \brief Helper to get `DAS::RecJet` from MiniAOD /// /// [General instructions](https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideBtagValidation) /// [DeepJet](https://twiki.cern.ch/twiki/bin/view/CMS/DeepJet#94X_installation_recipe_X_10) @@ -88,158 +88,67 @@ DAS::RecJet DAS::Helper::GetRecJet (const pat::Jet &ijet) } //////////////////////////////////////////////////////////////////////////////// -/// Testing loose ID definition for jets (official from JetMET) +/// \brief Testing tight ID lepton veto definition for jets (official from JetMET) /// -/// see https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetID +/// The values for Run 2 correspond to UL and are not expected to change. +/// Instead, the values for Run 3 are only preliminary and are subject to changes. /// -/// /!\ these values are intended for 2016 only!! -bool DAS::Helper::LooseID (const pat::Jet &jet) +/// \note The formulae in blue from the +/// [original TWiki](https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetID) +/// have been copied and their format adapted. +bool DAS::Helper::JetID (const pat::Jet &jet) { - assert(p.year == 2016); // LooseID is only defined for 2016 + const auto eta = jet.eta(); - const auto abseta = abs(jet.eta()); - - auto NHF = jet.neutralHadronEnergyFraction(); - auto NEMF = jet.photonEnergyFraction(); - auto NumConst = jet.neutralMultiplicity() + jet.chargedMultiplicity(); - - auto CHF = jet.chargedHadronEnergyFraction(); - auto CHM = jet.chargedHadronMultiplicity(); - auto CEMF = jet.chargedEmEnergyFraction(); - - if (abseta <= 2.7) - return (NHF<0.99 && NEMF<0.99 && NumConst>1) - && ((abseta<=2.4 && CHF>0 && CHM>0 && CEMF<0.99) || abseta>2.4); - - auto NumNeutralParticle = jet.neutralMultiplicity(); - - if (abseta <= 3.0) - return NHF<0.98 && NEMF>0.01 && NumNeutralParticle>2; - - return NEMF<0.90 && NumNeutralParticle>10; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Testing tight ID definition for jets (official from JetMET) -/// -/// see https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetID -bool DAS::Helper::TightID (const pat::Jet &jet) -{ - const auto abseta = abs(jet.eta()); - - auto NHF = jet.neutralHadronEnergyFraction(); + auto NHF = jet.neutralHadronEnergyFraction(); auto NEMF = jet.photonEnergyFraction(); + auto MUF = jet.muonEnergyFraction(); auto NumConst = jet.neutralMultiplicity() + jet.chargedMultiplicity(); - auto CHF = jet.chargedHadronEnergyFraction(); - auto CHM = jet.chargedHadronMultiplicity(); + auto CHF = jet.chargedHadronEnergyFraction(); + auto CHM = jet.chargedHadronMultiplicity(); auto CEMF = jet.chargedEmEnergyFraction(); - if (abseta <= 2.7) - switch (p.year) { - case 2016: - return (NHF<0.90 && NEMF<0.90 && NumConst>1) - && ((abseta<=2.4 && CHF>0 && CHM>0 && CEMF<0.99) || abseta>2.4); - case 2017: - return (NHF<0.90 && NEMF<0.90 && NumConst>1) - && ((abseta<=2.4 && CHF>0 && CHM>0 ) || abseta>2.4); - case 2018: - return (abseta<=2.6 && CHM>0 && CHF>0 && NumConst>1 && NEMF<0.9 && NHF < 0.9 ) - || (CHM>0 && NEMF<0.99 && NHF < 0.9); - default: - cerr << "Only 2016, 2017 or 2018 is possible\n"; - exit(EXIT_FAILURE); - } - auto NumNeutralParticle = jet.neutralMultiplicity(); - if (abseta <= 3.0) - switch (p.year) { - case 2016: - return NHF<0.98 && NEMF>0.01 && NumNeutralParticle>2; - case 2017: - case 2018: - return NEMF>0.02 && NEMF<0.99 && NumNeutralParticle>2; - default: - cerr << "Only 2016, 2017 or 2018 is possible\n"; - exit(EXIT_FAILURE); - } - switch (p.year) { case 2016: - return NEMF<0.90 && NumNeutralParticle>10; - case 2017: - return NEMF<0.90 && NHF>0.02 && NumNeutralParticle>10; - case 2018: - return NEMF<0.90 && NHF>0.2 && NumNeutralParticle>10; - default: - cerr << "Only 2016, 2017 or 2018 is possible\n"; - exit(EXIT_FAILURE); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Testing tight ID definition for jets (official from JetMET) -/// -/// see https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetID -bool DAS::Helper::TightLepVetoID (const pat::Jet &jet) -{ - const auto abseta = abs(jet.eta()); - - auto NHF = jet.neutralHadronEnergyFraction(); - auto NEMF = jet.photonEnergyFraction(); - auto NumConst = jet.neutralMultiplicity() + jet.chargedMultiplicity(); - - auto CHF = jet.chargedHadronEnergyFraction(); - auto CHM = jet.chargedHadronMultiplicity(); - auto CEMF = jet.chargedEmEnergyFraction(); - auto MUF = jet.muonEnergyFraction(); - - if (abseta <= 2.7) - switch (p.year) { - case 2016: - return (NHF<0.90 && NEMF<0.90 && NumConst>1 && MUF<0.80) - && ((abseta<=2.4 && CHF>0 && CHM>0 && CEMF<0.90) || abseta>2.4); - case 2017: - return (NHF<0.90 && NEMF<0.90 && NumConst>1 && MUF<0.80) - && ((abseta<=2.4 && CHF>0 && CHM>0 && CEMF<0.80) || abseta>2.4); - case 2018: - return (abseta<=2.6 && MUF<0.80 && CEMF<0.80 && CHM>0 && NHF<0.9 && NEMF<0.90 && CHF>0 && NumConst>1) - || (MUF<0.80 && CEMF<0.80 && CHM>0 && NHF<0.9 && NEMF<0.99); - default: - cerr << "Only 2016, 2017 or 2018 is possible\n"; - exit(EXIT_FAILURE); - } + return (abs(eta)<=2.4 && CEMF<0.8 && CHM>0 && CHF>0 && NumConst>1 && NEMF<0.9 && MUF <0.8 && NHF < 0.9) + || (p.CHS && abs(eta)>2.4 && abs(eta)<=2.7 && NEMF<0.99 && NHF < 0.9) + || (p.CHS && NEMF>0.0 && NEMF<0.99 && NHF<0.9 && NumNeutralParticle>1 && abs(eta)>2.7 && abs(eta)<=3.0) + || (p.CHS && NEMF<0.90 && NHF>0.2 && NumNeutralParticle>10 && abs(eta)>3.0) + || (p.PUPPI && abs(eta)>2.4 && abs(eta)<=2.7 && NEMF<0.99 && NHF < 0.98) + || (p.PUPPI && NumNeutralParticle>=1 && abs(eta)>2.7 && abs(eta)<=3.0) + || (p.PUPPI && NEMF<0.90 && NumNeutralParticle>2 && abs(eta)>3.0); - auto NumNeutralParticle = jet.neutralMultiplicity(); - - if (abseta <= 3.0) - switch (p.year) { - case 2016: - return NHF<0.98 && NEMF>0.01 && NumNeutralParticle>2; - case 2017: - case 2018: - return NEMF>0.02 && NEMF<0.99 && NumNeutralParticle>2; - default: - cerr << "Only 2016, 2017 or 2018 is possible\n"; - exit(EXIT_FAILURE); - } - - switch (p.year) { - case 2016: - return NEMF<0.90 && NumNeutralParticle>10; case 2017: - return NEMF<0.90 && NHF>0.02 && NumNeutralParticle>10; case 2018: - return NEMF<0.90 && NHF>0.2 && NumNeutralParticle>10; + return (abs(eta)<=2.6 && CEMF<0.8 && CHM>0 && CHF>0 && NumConst>1 && NEMF<0.9 && MUF <0.8 && NHF < 0.9) + || (p.CHS && abs(eta)>2.6 && abs(eta)<=2.7 && CEMF<0.8 && CHM>0 && NEMF<0.99 && MUF <0.8 && NHF < 0.9) + || (p.CHS && NEMF>0.01 && NEMF<0.99 && NumNeutralParticle>1 && abs(eta)>2.7 && abs(eta)<=3.0) + || (p.CHS && NEMF<0.90 && NHF>0.2 && NumNeutralParticle>10 && abs(eta)>3.0) + || (p.PUPPI && abs(eta)>2.6 && abs(eta)<=2.7 && CEMF<0.8 && NEMF<0.99 && MUF <0.8 && NHF < 0.9) + || (p.PUPPI && NHF<0.9999 && abs(eta)>2.7 && abs(eta)<=3.0) + || (p.PUPPI && NEMF<0.90 && NumNeutralParticle>2 && abs(eta)>3.0); + case 2022: + case 2023: + case 2024: + return (abs(eta)<=2.6 && CEMF<0.8 && CHM>0 && CHF>0.01 && NumConst>1 && NEMF<0.9 && MUF <0.8 && NHF < 0.99) + || (p.PUPPI && abs(eta)>2.6 && abs(eta)<=2.7 && CEMF<0.8 && NEMF<0.99 && MUF <0.8 && NHF < 0.9) + || (p.PUPPI && NHF<0.99 && abs(eta)>2.7 && abs(eta)<=3.0) + || (p.PUPPI &&NEMF<0.40 && NumNeutralParticle>=2 && abs(eta)>3.0) + || (p.CHS && abs(eta)>2.6 && abs(eta)<=2.7 && CEMF<0.8 && CHM>0 && NEMF<0.99 && MUF <0.8 && NHF < 0.9) + || (p.CHS && NEMF<0.99 && NHF<0.99 && NumNeutralParticle>1 && abs(eta)>2.7 && abs(eta)<=3.0) + || (p.CHS && NEMF<0.40 && NumNeutralParticle>10 && abs(eta)>3.0); default: - cerr << "Only 2016, 2017 or 2018 is possible\n"; - exit(EXIT_FAILURE); + auto err_msg = "\x1B[31m\x1B[1mThe JetID has not yet been imlemented in DAS for "s + + to_string(p.year) + "\x1B[0m"s; + throw cms::Exception("Ntupliser") << err_msg; } } //////////////////////////////////////////////////////////////////////////////// -/// Helper to get `DAS::GenMuon` from MiniAOD +/// \brief Helper to get `DAS::GenMuon` from MiniAOD DAS::GenMuon DAS::Helper::GetGenMu (const reco::Candidate &mu) { DAS::GenMuon Mu; @@ -253,7 +162,7 @@ DAS::GenMuon DAS::Helper::GetGenMu (const reco::Candidate &mu) } //////////////////////////////////////////////////////////////////////////////// -/// Helper to get `DAS::RecMuon` from MiniAOD +/// \brief Helper to get `DAS::RecMuon` from MiniAOD DAS::RecMuon DAS::Helper::GetRecMu (const pat::Muon &mu) { DAS::RecMuon Mu; @@ -274,7 +183,7 @@ DAS::RecMuon DAS::Helper::GetRecMu (const pat::Muon &mu) } //////////////////////////////////////////////////////////////////////////////// -/// Helper to get `DAS::GenPhoton` from MiniAOD +/// \brief Helper to get `DAS::GenPhoton` from MiniAOD DAS::GenPhoton DAS::Helper::GetGenPhoton (const reco::GenParticle &photon, bool zAncestor) { DAS::GenPhoton dasPhoton; @@ -288,7 +197,7 @@ DAS::GenPhoton DAS::Helper::GetGenPhoton (const reco::GenParticle &photon, bool } //////////////////////////////////////////////////////////////////////////////// -/// Helper to get `DAS::RecLep` from MiniAOD +/// \brief Helper to get `DAS::RecLep` from MiniAOD DAS::RecPhoton DAS::Helper::GetRecPhoton (const pat::Photon &photon) { DAS::RecPhoton dasPhoton; diff --git a/Ntupliser/plugins/helper.h b/Ntupliser/plugins/helper.h index 5b1cea4e..d51e30ab 100644 --- a/Ntupliser/plugins/helper.h +++ b/Ntupliser/plugins/helper.h @@ -33,9 +33,7 @@ struct Helper { DAS::GenJet GetGenJet (const reco::Jet &ijet); DAS::RecJet GetRecJet (const pat::Jet &ijet); - bool LooseID (const pat::Jet &jet); - bool TightID (const pat::Jet &jet); - bool TightLepVetoID (const pat::Jet &jet); + bool JetID (const pat::Jet &jet); DAS::GenMuon GetGenMu (const reco::Candidate &mu); DAS::RecMuon GetRecMu (const pat::Muon &mu); diff --git a/Ntupliser/python/Ntupliser_cfg.py b/Ntupliser/python/Ntupliser_cfg.py index 44a356f3..b4a00905 100644 --- a/Ntupliser/python/Ntupliser_cfg.py +++ b/Ntupliser/python/Ntupliser_cfg.py @@ -65,10 +65,15 @@ elif any(x in inputFiles[0] for x in ['2017UL','UL17','UL2017']): year = 2017 elif any(x in inputFiles[0] for x in ['2018UL','UL18','UL2018']): year = 2018 + # \todo 2022 and 2023 +elif any(x in inputFiles[0] for x in ['Run2024', 'mcRun3_2024']): + year = 2024 else: raise ValueError("Year is not recognised") flags["year"] = year +run = 2 if year < 2019 else 3 + # definition of the process (note: the name is used when reclustering) process = cms.Process('Darwin') @@ -126,10 +131,19 @@ if isMC: GT = '106X_mc2017_realistic_v10' elif year == 2018: GT = '106X_upgrade2018_realistic_v16_L1v1' + # \todo 2022 and 2023 + elif year == 2024: + GT = '133X_mcRun3_2024_realistic_v10' # \todo TBC else: raise RuntimeError("No GT could be determined") else: - GT = '106X_dataRun2_v37' + if year > 2015 and year < 2019: + GT = '106X_dataRun2_v37' + # \todo 2022 and 2023 + elif year == 2024: + GT = '141X_dataRun3_Prompt_v4' # \todo TBC + else: + raise RuntimeError("No GT could be determined") print(GT) @@ -145,23 +159,29 @@ if year == 2017 or year ==2018: print("Size MET names: "+str(len(metNames))) genJetCollection = 'slimmedGenJets' +# determine the PU method hasPUPPI = 'PUPPI' in labels hasCHS = 'CHS' in labels + +if hasPUPPI and hasCHS: + raise ValueError("PUPPI xor CHS") + +if not hasPUPPI and not hasCHS: + if year < 2019: + hasCHS = True + labels += ['CHS'] + else: + hasPUPPI = True + labels += ['PUPPI'] + if hasPUPPI: + PUmethod = 'PUPPI' JetCollection = 'slimmedJetsPuppi' -else: +elif hasCHS: + PUmethod = 'CHS' JetCollection = 'slimmedJets' if jets: - # determine the PU method - if hasPUPPI and hasCHS: - raise ValueError("PUPPI xor CHS") - elif hasPUPPI: - PUmethod = 'PUPPI' - else: - PUmethod = 'CHS' # default - if not hasCHS: - labels += ['CHS'] if radius == 0.8: ## reclustering: @@ -282,15 +302,15 @@ process.ntupliser = cms.EDAnalyzer('Ntupliser', recphotons = cms.InputTag('slimmedPhotons'), # trigger triggerNames = cms.vstring(triggerNames), - triggerPrescales = cms.InputTag('patTrigger'), - triggerPrescalesl1min = cms.InputTag('patTrigger', 'l1min'), - triggerPrescalesl1max = cms.InputTag('patTrigger', 'l1max'), + triggerPrescales = cms.InputTag('patTrigger', '' , 'PAT' if run == 2 else 'RECO'), + triggerPrescalesl1min = cms.InputTag('patTrigger', 'l1min', 'PAT' if run == 2 else 'RECO'), + triggerPrescalesl1max = cms.InputTag('patTrigger', 'l1max', 'PAT' if run == 2 else 'RECO'), triggerResults = cms.InputTag('TriggerResults','','HLT'), - triggerObjects = cms.InputTag('slimmedPatTrigger'), + triggerObjects = cms.InputTag('slimmedPatTrigger', '', 'PAT' if run == 2 else 'RECO'), # MET met = cms.InputTag('slimmedMETs'), - metNames = cms.vstring(metNames), - metResults = cms.InputTag('TriggerResults','', 'PAT'), + metNames = cms.vstring(metNames), + metResults = cms.InputTag('TriggerResults','', 'PAT' if run == 2 else 'RECO'), ) if dump: diff --git a/Ntupliser/scripts/mkNtuples b/Ntupliser/scripts/mkNtuples index 67c6d93b..36060a3b 100755 --- a/Ntupliser/scripts/mkNtuples +++ b/Ntupliser/scripts/mkNtuples @@ -11,6 +11,7 @@ parser.add_argument('-t', '--test', help="run locally (for test)", action="store parser.add_argument('-l', '--local', help="run on local HTCondor (only if data sets on local T2)", action="store_true") parser.add_argument('-c', '--crab', help="run remotely (for production)", action="store_true") parser.add_argument('-d', '--dryrun', help="do not actually submit or start the n-tupliser", action="store_true") +parser.add_argument('-i', '--image', help="cc7, el8, el9", default="el8") args = parser.parse_args() import os, json @@ -31,11 +32,11 @@ else: # 1. The user runs from EL9 with an elementary config. In that case, `initMetaInfo` may be used to update the input config. The updated config is then used as argument to `mkNtuples` run from an EL8 image with apptainer. # 2. The user has loaded an EL8 image with apptainer on their own (e.g. to develop or to debug). If the git information are missing, it is provided by hand on the fly, otherwise it is taken from the input file. Then the rest of the script is executed directly. -run_from_el9 = which('el8') is not None +run_from_DAS_tools = which('el8') is not None if not 'git' in params: - if run_from_el9: + if run_from_DAS_tools: initMetaInfo = subprocess.check_output(["initMetaInfo", "json"]).decode() metainfo = json.loads(initMetaInfo) params.update(metainfo) @@ -58,11 +59,11 @@ if not 'git' in params: sha = params['git']['commit'] -if args.local and not run_from_el9: - sys.stderr.write("\033[31mLocal jobs (`-l` option) may only be submitted from EL9\033[0m\n") +if args.local and not run_from_DAS_tools: + sys.stderr.write("\033[31mLocal jobs (`-l` option) may only be submitted from DAS (not from CMSSW)\033[0m\n") sys.exit(1) -if run_from_el9 and not args.local: +if run_from_DAS_tools and not args.local: from pathlib import Path p = Path(args.configFile) @@ -70,7 +71,7 @@ if run_from_el9 and not args.local: with open(params_output, 'w') as f: json.dump(params, f, indent = 4) - cmd = ['das-cmssw', 'el8', 'mkNtuples'] + cmd = ['das-cmssw', args.image, 'mkNtuples'] if args.test: cmd += ['-t'] if args.crab: @@ -84,7 +85,7 @@ if run_from_el9 and not args.local: name = (params['name'] + '_') if 'name' in params else '' datasets = params['datasets'] maxEvents = params['maxEvents'] if 'maxEvents' in params else -1 -psetName = f"{os.environ['CORE_BASE']}/Ntupliser/python/Ntupliser_cfg.py" +psetName = f"{os.environ['CMSSW_BASE']}/src/Core/Ntupliser/python/Ntupliser_cfg.py" if 'luminosity' in params: for key, value in params['luminosity'].items(): -- GitLab From 869b10d10872d88a1c6a2b04c5ce39de16b55050 Mon Sep 17 00:00:00 2001 From: "Patrick L.S. Connor" <connorpa@mail.desy.de> Date: Wed, 15 Jan 2025 16:33:27 +0100 Subject: [PATCH 3/7] changing auto_ptr to unique_ptr --- BTagging/src/BTagCalibration.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BTagging/src/BTagCalibration.cc b/BTagging/src/BTagCalibration.cc index 71a913eb..d9cdb393 100644 --- a/BTagging/src/BTagCalibration.cc +++ b/BTagging/src/BTagCalibration.cc @@ -431,7 +431,7 @@ std::cerr << "ERROR in BTagCalibration: " << ost; throw std::exception(); } - otherSysTypeReaders_[ost] = std::auto_ptr<BTagCalibrationReaderImpl>( + otherSysTypeReaders_[ost] = std::unique_ptr<BTagCalibrationReaderImpl>( new BTagCalibrationReaderImpl(op, ost) ); } -- GitLab From 995ba2a82f5bdc3deb490c1897085ec751eda941 Mon Sep 17 00:00:00 2001 From: "Patrick L.S. Connor" <connorpa@mail.desy.de> Date: Wed, 15 Jan 2025 17:17:51 +0100 Subject: [PATCH 4/7] redesigning MET filter application --- CommonTools/bin/mergeNtuples.cc | 18 ++++-- MET/bin/applyMETfilters.cc | 70 ++++++++++++-------- MET/interface/Filters.h | 103 +++++++++++++----------------- Ntupliser/python/Ntupliser_cfg.py | 49 ++++++++------ Ntupliser/test/CI.json | 3 + Ntupliser/test/ak8.json | 3 + Ntupliser/test/runAnalysis.sh | 8 +-- 7 files changed, 141 insertions(+), 113 deletions(-) diff --git a/CommonTools/bin/mergeNtuples.cc b/CommonTools/bin/mergeNtuples.cc index 67580b20..834c1230 100644 --- a/CommonTools/bin/mergeNtuples.cc +++ b/CommonTools/bin/mergeNtuples.cc @@ -76,12 +76,19 @@ void mergeNtuples // MET filter business auto met = flow.GetBranchReadOnly<MET>("met"); + fs::path p_METfilters = config.get<fs::path>("corrections.METfilters"); optional<MissingET::Filters> metfilters; - if (config.get<bool>("corrections.METfilters")) - metfilters = make_optional<MissingET::Filters>(year); + if (p_METfilters != "/dev/null") { + if (!metainfo.Find("corrections", "METfilters")) + BOOST_THROW_EXCEPTION( DE::BadInput("No MET filters in this tree", tOut) ); + if (metainfo.Get<fs::path>("corrections", "METfilters") != p_METfilters) { + cerr << orange << "You are now using a different list of MET filters w.r.t. n-tuplisation.\n" << def; + metainfo.Set<bool>("git", "reproducible", false); + } + metfilters = make_optional<MissingET::Filters>(p_METfilters); + } else cout << orange << "No MET filters will be applied." << def << endl; - metainfo.Set<bool>("corrections", "METfilters", (bool) metfilters); for (DT::Looper looper(tIn); looper(); ++looper) { [[ maybe_unused ]] @@ -99,7 +106,7 @@ void mergeNtuples for (auto& recJet: *recJets) (*jetveto)(recJet); - if (metfilters) (*metfilters)(met, recEvt); + if (metfilters) (*metfilters)(*met, *recEvt); if (steering & DT::fill) tOut->Fill(); } @@ -130,7 +137,8 @@ int main (int argc, char * argv[]) .output("output", &output, "output ROOT file" ) .arg<fs::path>("jetvetomap", "corrections.jetvetomap.filename", "ROOT file containing jet vet maps" "(`/dev/null` to deactivate)") - .arg<bool> ("METfilters", "corrections.METfilters", "activation boolean flag" ); + .arg<fs::path>("METfilters", "corrections.METfilters", "2-column file containing the MET filters" + "(`/dev/null` to deactivate)"); const auto& config = options(argc, argv); const auto& slice = options.slice(); diff --git a/MET/bin/applyMETfilters.cc b/MET/bin/applyMETfilters.cc index 41e4b55d..4eeadeaa 100644 --- a/MET/bin/applyMETfilters.cc +++ b/MET/bin/applyMETfilters.cc @@ -17,6 +17,14 @@ #include <darwin.h> +using namespace std; + +namespace pt = boost::property_tree; +namespace fs = filesystem; + +namespace DE = Darwin::Exceptions; +namespace DT = Darwin::Tools; + namespace DAS::MissingET { struct FractionCut { @@ -61,16 +69,17 @@ struct FractionCut { void Write (TDirectory * d) { + cout << "Writing MET plots for " << name << endl; d->cd(); TDirectory * dd = d->mkdir(name); dd->cd(); for (TH1 * h: {Et.get(), SumEt.get(), Fraction.get(), Pt.get(), Phi.get()}) { - h->SetDirectory(d); + h->SetDirectory(dd); TString n = h->GetName(); n.ReplaceAll(name,""); h->Write(n); } - pt_y->SetDirectory(d); + pt_y->SetDirectory(dd); TString n = pt_y->GetName(); n.ReplaceAll(name,""); pt_y->Write(n); @@ -84,6 +93,7 @@ struct FractionCut { void applyMETfilters (const vector<fs::path>& inputs, //!< input ROOT file (n-tuple) const fs::path& output, //!< output ROOT file (n-tuple) + const pt::ptree& config, //!< config handled with `Darwin::Tools::options` const int steering, //!< parameters obtained from explicit options const DT::Slice slice = {1,0} //!< number and index of slice ) @@ -103,8 +113,15 @@ void applyMETfilters auto met = flow.GetBranchReadOnly<MET >("met" ); auto recJets = flow.GetBranchReadOnly<vector<RecJet>>("recJets"); - metainfo.Set<bool>("corrections", "METfilters", true); - MissingET::Filters metfilters(year); + if (!metainfo.Find("corrections", "METfilters")) + BOOST_THROW_EXCEPTION( DE::BadInput("No MET filters in this tree", tOut) ); + + fs::path p_METfilters = config.get<fs::path>("corrections.METfilters"); + if (metainfo.Get<fs::path>("corrections", "METfilters") != p_METfilters) { + cerr << orange << "You are now using a different list of MET filters w.r.t. n-tuplisation.\n" << def; + metainfo.Set<bool>("git", "reproducible", false); + } + MissingET::Filters metfilters(p_METfilters); /**** declaring a few histograms to control effect of filters ****/ @@ -117,8 +134,8 @@ void applyMETfilters METafterAllMETfiltersAndMETfraction("METafterAllMETfiltersAndMETfraction"); vector<ControlPlots> METfilters; - for (TString METname: metfilters.METnames) - METfilters.push_back(ControlPlots(METname)); + for (const string& METname: metfilters.names) + METfilters.emplace_back(METname); auto totRecWgt = [&](size_t i) { return (isMC ? gEv->weights.front().v : 1) * rEv->weights.at(i).v; @@ -136,17 +153,10 @@ void applyMETfilters METafterMETfraction(*recJets, totRecWgt(0)); } - for (size_t ibit = 0; ibit < metfilters.METbitsToApply.size(); ++ibit) { - bool bit = met->Bit.at(ibit); - if (!bit) continue; - METfilters.at(ibit)(*recJets, totRecWgt(0)); - } - - // IMPORTANT NOTE: - // in case the MET fraction based cut would be used, - // the description of the MET class should be changed!! + /// \note In case the MET fraction based cut would be used, + /// the description of the MET class should be changed!! - metfilters(met, rEv); + metfilters(*met, *rEv); METafterAllMETfilters(*recJets, totRecWgt(0)); @@ -156,15 +166,22 @@ void applyMETfilters if (steering & DT::fill) tOut->Fill(); } - beforeCut.Write(fOut); - afterCut.Write(fOut); - METbefore.Write(fOut); - METafterMETfraction.Write(fOut); - METafterAllMETfilters.Write(fOut); - METafterAllMETfiltersAndMETfraction.Write(fOut); + cout << "Saving MET variables before and after the MET fraction cut" << endl; + auto dMETcut = fOut->mkdir("METfraction"); + beforeCut.Write(dMETcut); + afterCut.Write(dMETcut); + + cout << "Saving control observables before and after the MET fraction cut and/or MET filters" << endl; + auto dCP = fOut->mkdir("controlplots"); + METbefore.Write(dCP); + METafterMETfraction.Write(dCP); + METafterAllMETfilters.Write(dCP); + METafterAllMETfiltersAndMETfraction.Write(dCP); + cout << "Saving control observables for each MET filter individually" << endl; + auto dMETfilters = fOut->mkdir("METfilters"); for (auto& filt: METfilters) - filt.Write(fOut); + filt.Write(dMETfilters); metainfo.Set<bool>("git", "complete", true); @@ -187,13 +204,14 @@ int main (int argc, char * argv[]) DT::split | DT::Friend); options.inputs("inputs", &inputs, "input ROOT file(s) or directory") - .output("output", &output, "output ROOT file" ); + .output("output", &output, "output ROOT file" ) + .arg<fs::path>("METfilters", "corrections.METfilters", "2-column file containing the MET filters"); - options(argc,argv); + const auto& config = options(argc,argv); const auto& slice = options.slice(); const int steering = options.steering(); - DAS::MissingET::applyMETfilters(inputs, output, steering, slice); + DAS::MissingET::applyMETfilters(inputs, output, config, steering, slice); } catch (boost::exception& e) { DE::Diagnostic(e); diff --git a/MET/interface/Filters.h b/MET/interface/Filters.h index e5bde6c5..e3daeb87 100644 --- a/MET/interface/Filters.h +++ b/MET/interface/Filters.h @@ -1,85 +1,68 @@ -#include <vector> -#include <system_error> #include <iostream> -#include <TString.h> +#include <string> +#include <system_error> +#include <vector> #include "Core/CommonTools/interface/binnings.h" #include "Core/Objects/interface/Event.h" #include "Core/Objects/interface/Jet.h" -#include <darwin.h> - -using namespace std; +#include <boost/property_tree/info_parser.hpp> -namespace pt = boost::property_tree; -namespace fs = filesystem; - -namespace DE = Darwin::Exceptions; -namespace DT = Darwin::Tools; +#include <darwin.h> namespace DAS::MissingET { +//////////////////////////////////////////////////////////////////////////////// +/// MET / noise event filters +/// +/// More info at https://indico.cern.ch/event/1305273/#12-status-update-from-hamburg struct Filters { - vector<TString> METnames; - vector<int> METbitsToApply; - //For more info look at https://indico.cern.ch/event/1305273/#12-status-update-from-hamburg, contribution by V. Guglielmi + std::vector<std::string> names; //!< full name of MET filter + std::vector<size_t> bitsToTest; //!< indices of the bits to test in DAS::MET::Bit - // NOTE: this is taken from the python config file, check that the name - // still make sense..... - Filters (int year) + Filters (const std::filesystem::path& file //!< expecting a 2-column file (see $DARWIN_TABLES/MET) + ) { - switch (year) { - case 2016: - METnames = {"goodVertices", "globalSuperTightHalo2016Filter", "HBHENoiseFilter", - "HBHENoiseIsoFilter", "EcalDeadCellTriggerPrimitiveFilter", - "BadPFMuonFilter", /*this one destroys Herwig16, for some reason*/ - "BadPFMuonDzFilter", //always return null value, to be better studied - "BadChargedCandidateFilter", /*this one too, but anyway, it is no longer recommended for any */ - "eeBadScFilter" /*this one is useless*/}; + using namespace std; + namespace pt = boost::property_tree; + namespace fs = filesystem; - METbitsToApply = {0, 1, 2, 3, 4, 5, 6, /*7,*/ 8}; /// \todo Check list of filters for 2016 - break; - case 2017: - case 2018: - // filters 6 and 9 always null, to be better investigated!!! filters 7 and 8 not recommended - METnames = {"goodVertices", "globalSuperTightHalo2016Filter", "HBHENoiseFilter", - "HBHENoiseIsoFilter", "EcalDeadCellTriggerPrimitiveFilter", - "BadPFMuonFilter", /*this one destroys Herwig16, for some reason*/ - "BadPFMuonDzFilter", - "BadChargedCandidateFilter", - "eeBadScFilter", - "hfNoisyHitsFilter", - "ecalBadCalibFilter"}; - METbitsToApply = {0, 1, 2, 3, 4, 5, 6, /*7,*/ 8, /*9,*/ 10}; /// \todo Check list of filters for 2017 and 18 - break; - default: - BOOST_THROW_EXCEPTION( invalid_argument(Form("%d is not (currently) not handled.", year)) ); - } + if (!fs::exists(file)) + BOOST_THROW_EXCEPTION(fs::filesystem_error("Bad MET filter list", file, + make_error_code(errc::no_such_file_or_directory))); - cout << "MET bits:"; - for (auto bit: METbitsToApply) - cout << ' ' << bit; - cout << endl; - } + pt::ptree tree; + pt::read_info(file, tree); - void operator() (MET * met, RecEvent * event) - { - // testing MET filters - bool passFilters = true; - // BadChargedCandidateFilter is no longer recommended - for (size_t ibit = 0; ibit < METnames.size(); ++ibit) { + cout << "MET / noise filters:"; + size_t ibit = 0; + for (auto& [name, child]: tree) { + auto bit = child.get_value<bool>(); - bool bit = met->Bit.at(ibit); + // printout + cout << (bit ? green : red) << ' ' << name; - if (find(METbitsToApply.begin(), METbitsToApply.end(), ibit) != METbitsToApply.end()) - passFilters = passFilters && bit; + // save + names.push_back(name); + if (bit) bitsToTest.push_back(ibit); + ++ibit; } - - if (!passFilters) - event->weights *= 0; + cout << def << endl; } + void operator() (const MET& met, RecEvent& event) + { + if (met.Bit.size() != names.size()) + BOOST_THROW_EXCEPTION( std::runtime_error("Inconsistent lengths of MET bits between file and event") ); + + for (size_t ibit: bitsToTest) { + if (met.Bit.at(ibit)) continue; + event.weights *= 0; + return; + } + } }; } diff --git a/Ntupliser/python/Ntupliser_cfg.py b/Ntupliser/python/Ntupliser_cfg.py index b4a00905..672989c8 100644 --- a/Ntupliser/python/Ntupliser_cfg.py +++ b/Ntupliser/python/Ntupliser_cfg.py @@ -103,13 +103,7 @@ process.MessageLogger = cms.Service("MessageLogger", ) ) -# definition of jets - -from RecoJets.JetProducers.GenJetParameters_cfi import * - -# gen particles are used both for muons and for flavours -# (so not relevant for analyses working with all-flavour inclusive jets) -genParticleCollection = 'prunedGenParticles' +### GT ### ## \todo clarify how much it matters... (in the n-tuples, we take the # uncorrected, but what about DeepJet for instance??) @@ -149,14 +143,30 @@ print(GT) process.GlobalTag = GlobalTag(process.GlobalTag, GT, '') -## \todo add forward triggers for 2017 and 2018 -# \todo clarify if there are efficient triggers in 2016 for forward region +### MET ### + +from pathlib import Path +METfilters = Path() +metNames = [] +if "corrections" in params and "METfilters" in params["corrections"]: + METfilters = Path(os.path.expandvars(params["corrections"]["METfilters"])) + # expecting a 2-column file (see $DARWIN_TABLES/MET) + with open(METfilters, 'r') as data: + for line in data: + p = line.split() + metNames.append(str(p[0])) + ## \note The MET filters are not applied but only saved to the n-tuples + print("MET filters: " + " ".join(metNames)) +else: + print("\x1B[33mNo MET filters\x1B[0m") -triggerNames = [] -metNames=['Flag_goodVertices','Flag_globalSuperTightHalo2016Filter','Flag_HBHENoiseFilter','Flag_HBHENoiseIsoFilter','Flag_EcalDeadCellTriggerPrimitiveFilter','Flag_BadPFMuonFilter', 'Flag_BadPFMuonDzFilter', 'Flag_BadChargedCandidateFilter','Flag_eeBadScFilter'] -if year == 2017 or year ==2018: - metNames+=['Flag_hfNoisyHitsFilter','Flag_ecalBadCalibFilter'] -print("Size MET names: "+str(len(metNames))) +### JETS ### + +from RecoJets.JetProducers.GenJetParameters_cfi import * + +# gen particles are used both for muons and for flavours +# (so not relevant for analyses working with all-flavour inclusive jets) +genParticleCollection = 'prunedGenParticles' genJetCollection = 'slimmedGenJets' # determine the PU method @@ -181,6 +191,8 @@ elif hasCHS: PUmethod = 'CHS' JetCollection = 'slimmedJets' +## \todo add forward triggers for 2017 and 2018 +triggerNames = [] if jets: if radius == 0.8: @@ -227,7 +239,8 @@ if muons and triggers: if (not isMC) and ('ZeroBias' in inputFiles[0]): triggerNames = ['HLT_ZeroBias_v'] -# get flavour at gen level +### FLAVOURS ### + if jets and flavour: if isMC: @@ -238,9 +251,7 @@ if jets and flavour: ) process.ak4genJetFlavourInfos = ak4JetFlavourInfos.clone( jets = genJetCollection, - hadronFlavourHasPriority = cms.bool(True), # only affect the parton flavour, actually - #relPtTolerance = cms.double(1.), # not sure that we should touch any of these - #ghostRescaling_ = cms.double(1e-24) # default is 1e-18 + hadronFlavourHasPriority = cms.bool(True) # only affect the parton flavour, actually ) process.load('Configuration.Geometry.GeometryRecoDB_cff') @@ -268,6 +279,8 @@ if jets and flavour: ) JetCollection = 'selectedUpdatedPatJetsRetrained' +### MISC ### + if not 'preseed' in params: import random params['preseed'] = random.randrange(0,2e8) diff --git a/Ntupliser/test/CI.json b/Ntupliser/test/CI.json index fbeb4c1d..33383e5b 100644 --- a/Ntupliser/test/CI.json +++ b/Ntupliser/test/CI.json @@ -16,5 +16,8 @@ "repo": "$CORE_BASE", "reproducible": false, "complete": false + }, + "corrections": { + "METfilters": "${DARWIN_TABLES}/MET/2018.info" } } diff --git a/Ntupliser/test/ak8.json b/Ntupliser/test/ak8.json index a7663935..48d11561 100644 --- a/Ntupliser/test/ak8.json +++ b/Ntupliser/test/ak8.json @@ -18,5 +18,8 @@ }, "datasets": { "/JetHT/Run2018D-UL2018_MiniAODv2_GT36-v1/MINIAOD": {} + }, + "corrections": { + "METfilters": "${DARWIN_TABLES}/MET/2018.info" } } diff --git a/Ntupliser/test/runAnalysis.sh b/Ntupliser/test/runAnalysis.sh index e995ce18..51f8f4c1 100755 --- a/Ntupliser/test/runAnalysis.sh +++ b/Ntupliser/test/runAnalysis.sh @@ -9,11 +9,11 @@ isMC="$3" mkdir -p "$folder" cd "$folder" -mergeNtuples "${input_file}" mergeNtuples.root /dev/null false -f +mergeNtuples "${input_file}" mergeNtuples.root /dev/null /dev/null -f # MET -applyMETfilters mergeNtuples.root applyMETfilters.root -mergeNtuples ntuple.root mergeNtuples.root /dev/null true -f +applyMETfilters mergeNtuples.root applyMETfilters.root $DARWIN_TABLES/MET/2018.info +mergeNtuples ntuple.root mergeNtuples.root /dev/null $DARWIN_TABLES/MET/2018.info -f ## \todo getMETfraction # jet veto maps @@ -23,7 +23,7 @@ if [[ ! -f $vetomap ]]; then (cd $DARWIN_TABLES/jetvetomaps && ./getULRun2Maps) fi applyConservativeVetoMap mergeNtuples.root applyConservativeVetoMap.root $vetomap -mergeNtuples ntuple.root mergeNtuples.root $vetomap true -f +mergeNtuples ntuple.root mergeNtuples.root $vetomap $DARWIN_TABLES/MET/2018.info -f previous_file=mergeNtuples.root -- GitLab From 874a2ca0393b80fdf499391511614ae527731f24 Mon Sep 17 00:00:00 2001 From: "Patrick L.S. Connor" <connorpa@mail.desy.de> Date: Wed, 15 Jan 2025 18:02:10 +0100 Subject: [PATCH 5/7] partially adapting muons selectors for Run 3 --- Muons/bin/applyMuonSelection.cc | 77 ++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/Muons/bin/applyMuonSelection.cc b/Muons/bin/applyMuonSelection.cc index 3f3d3740..426c6eb5 100644 --- a/Muons/bin/applyMuonSelection.cc +++ b/Muons/bin/applyMuonSelection.cc @@ -35,31 +35,45 @@ namespace DT = Darwin::Tools; namespace DAS::Muon { //////////////////////////////////////////////////////////////////////////////// -/// Adapted from [CMSSW](https://github.com/cms-sw/cmssw/blob/CMSSW_9_4_X/DataFormats/MuonReco/interface/Muon.h#L185-L212) +/// Adapted from [CMSSW](https://github.com/cms-sw/cmssw/blob/CMSSW_13_3_X/DataFormats/MuonReco/interface/Muon.h#L202-239) enum Selector { - None = 0u, // added - CutBasedIdLoose = 1u<< 0, - CutBasedIdMedium = 1u<< 1, - CutBasedIdMediumPrompt = 1u<< 2, // medium with IP cuts - CutBasedIdTight = 1u<< 3, - CutBasedIdGlobalHighPt = 1u<< 4, // high pt muon for Z',W' (better momentum resolution) - CutBasedIdTrkHighPt = 1u<< 5, // high pt muon for boosted Z (better efficiency) - PFIsoVeryLoose = 1u<< 6, // reliso<0.40 - PFIsoLoose = 1u<< 7, // reliso<0.25 - PFIsoMedium = 1u<< 8, // reliso<0.20 - PFIsoTight = 1u<< 9, // reliso<0.15 - PFIsoVeryTight = 1u<<10, // reliso<0.10 - TkIsoLoose = 1u<<11, // reliso<0.10 - TkIsoTight = 1u<<12, // reliso<0.05 - SoftCutBasedId = 1u<<13, - SoftMvaId = 1u<<14, - MvaLoose = 1u<<15, - MvaMedium = 1u<<16, - MvaTight = 1u<<17, - MiniIsoLoose = 1u<<18, // reliso<0.40 - MiniIsoMedium = 1u<<19, // reliso<0.20 - MiniIsoTight = 1u<<20, // reliso<0.10 - MiniIsoVeryTight = 1u<<21 // reliso<0.05 + None = 0ul, // added + CutBasedIdLoose = 1ul<< 0, + CutBasedIdMedium = 1ul<< 1, + CutBasedIdMediumPrompt = 1ul<< 2, // medium with IP cuts + CutBasedIdTight = 1ul<< 3, + CutBasedIdGlobalHighPt = 1ul<< 4, // high pt muon for Z',W' (better momentum resolution) + CutBasedIdTrkHighPt = 1ul<< 5, // high pt muon for boosted Z (better efficiency) + PFIsoVeryLoose = 1ul<< 6, // reliso<0.40 + PFIsoLoose = 1ul<< 7, // reliso<0.25 + PFIsoMedium = 1ul<< 8, // reliso<0.20 + PFIsoTight = 1ul<< 9, // reliso<0.15 + PFIsoVeryTight = 1ul<<10, // reliso<0.10 + TkIsoLoose = 1ul<<11, // reliso<0.10 + TkIsoTight = 1ul<<12, // reliso<0.05 + SoftCutBasedId = 1ul<<13, + SoftMvaId = 1ul<<14, + MvaLoose = 1ul<<15, + MvaMedium = 1ul<<16, + MvaTight = 1ul<<17, + MiniIsoLoose = 1ul<<18, // reliso<0.40 + MiniIsoMedium = 1ul<<19, // reliso<0.20 + MiniIsoTight = 1ul<<20, // reliso<0.10 + MiniIsoVeryTight = 1ul<<21, // reliso<0.05 + TriggerIdLoose = 1ul<<22, // robust selector for HLT + InTimeMuon = 1ul<<23, + PFIsoVeryVeryTight = 1ul<<24, // reliso<0.05 + MultiIsoLoose = 1ul<<25, // miniIso with ptRatio and ptRel + MultiIsoMedium = 1ul<<26, // miniIso with ptRatio and ptRel + PuppiIsoLoose = 1ul<<27, + PuppiIsoMedium = 1ul<<28, + PuppiIsoTight = 1ul<<29, + MvaVTight = 1ul<<30, + MvaVVTight = 1ul<<31, + LowPtMvaLoose = 1ul<<32, + LowPtMvaMedium = 1ul<<33, + MvaIDwpMedium = 1ul<<34, + MvaIDwpTight = 1ul<<35, }; //////////////////////////////////////////////////////////////////////////////// @@ -93,13 +107,14 @@ private: if (s == "TrkHighPtID") return Selector::CutBasedIdTrkHighPt ; // andIPCut? // Muon ISO - if (s == "VeryLooseRelIso") return Selector::PFIsoVeryLoose; - if (s == "LooseRelIso") return Selector::PFIsoLoose ; - if (s == "MediumRelIso") return Selector::PFIsoMedium ; - if (s == "TightRelIso") return Selector::PFIsoTight ; - if (s == "VeryTightRelIso") return Selector::PFIsoVeryTight; - if (s == "LooseRelTkIso") return Selector::TkIsoLoose ; - if (s == "TightRelTkIso") return Selector::TkIsoTight ; + if (s == "VeryLooseRelIso") return Selector::PFIsoVeryLoose ; + if (s == "LooseRelIso") return Selector::PFIsoLoose ; + if (s == "MediumRelIso") return Selector::PFIsoMedium ; + if (s == "TightRelIso") return Selector::PFIsoTight ; + if (s == "VeryTightRelIso") return Selector::PFIsoVeryTight ; + if (s == "VeryVeryTightRelIso") return Selector::PFIsoVeryVeryTight; + if (s == "LooseRelTkIso") return Selector::TkIsoLoose ; + if (s == "TightRelTkIso") return Selector::TkIsoTight ; BOOST_THROW_EXCEPTION( invalid_argument(s + " is not recognised.") ); } -- GitLab From c7e9b53257dc4eeebd301e234f7eec492e97add1 Mon Sep 17 00:00:00 2001 From: "Patrick L.S. Connor" <patrick.connor@cern.ch> Date: Wed, 29 Jan 2025 15:53:54 +0100 Subject: [PATCH 6/7] adding a command-line option to applyPUcleaning for the 3rd (and most ad-hoc) criterion --- CommonTools/doc/example.info | 1 + Ntupliser/test/runAnalysis.sh | 2 +- PUstaubSauger/bin/applyPUcleaning.cc | 13 +++++++++---- PUstaubSauger/bin/applyPUcleaningHT.cc | 13 +++++++++---- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CommonTools/doc/example.info b/CommonTools/doc/example.info index 14ef6db3..8612bf52 100644 --- a/CommonTools/doc/example.info +++ b/CommonTools/doc/example.info @@ -38,6 +38,7 @@ corrections ; for event-by-event corrections { MBmaxgenpt ${DARWIN_TABLES}/PUstaub/Pythia16.txt MBmaxgenht ${DARWIN_TABLES}/PUstaub/Pythia16.txt + artifacts_minpt 156 minpt 10 minht 10 } diff --git a/Ntupliser/test/runAnalysis.sh b/Ntupliser/test/runAnalysis.sh index 51f8f4c1..8f0a1b67 100755 --- a/Ntupliser/test/runAnalysis.sh +++ b/Ntupliser/test/runAnalysis.sh @@ -33,7 +33,7 @@ if [ "$isMC" = "yes" ]; then applyMClumi mergeNtuples.root getSumWeights.root applyMClumi.root 1 -f # PU staub - applyPUcleaning applyMClumi.root applyPUcleaning.root /dev/null -f + applyPUcleaning applyMClumi.root applyPUcleaning.root /dev/null 0 -f # jet energy scale corrections JEC_TABLES=$DARWIN_TABLES/jsonpog-integration/POG/JME/2018_UL/jet_jerc.json.gz diff --git a/PUstaubSauger/bin/applyPUcleaning.cc b/PUstaubSauger/bin/applyPUcleaning.cc index db651d25..a116ccb8 100644 --- a/PUstaubSauger/bin/applyPUcleaning.cc +++ b/PUstaubSauger/bin/applyPUcleaning.cc @@ -90,6 +90,9 @@ void applyPUcleaning const auto& maxgenpts = GetMaxGenPts(fMBmaxgenpt); metainfo.Set<fs::path>("corrections", "PUcleaning", "MBmaxgenpt", fMBmaxgenpt); + auto artifacts_minpt = config.get<float>("corrections.PUcleaning.artifacts_minpt"); + metainfo.Set<float>("corrections", "PUcleaning", "artifacts_minpt", artifacts_minpt); + // branches auto genEvt = flow.GetBranchReadOnly<GenEvent>("genEvent"); auto recEvt = flow.GetBranchReadWrite<RecEvent>("recEvent"); @@ -135,15 +138,14 @@ void applyPUcleaning } // 3- removal of reconstruction artefacts happening at excessively high pt - if (recJets->size() > 0) { + if (recJets->size() > 0 && artifacts_minpt > 0) { const auto& recjet = recJets->begin(); bool matched = false; for (const auto& genjet: *genJets) matched |= DeltaR(genjet.p4, recjet->p4) < maxDR; float maxgenpt = genJets->size() > 0 ? genJets->front().p4.Pt() : genEvt->hard_scale; - static const float m = 156; /// \todo Hard-coded cut currently tuned for Pythia UL18 - if (recjet->p4.Pt() > max(2*maxgenpt, m)) + if (recjet->p4.Pt() > max(2*maxgenpt, artifacts_minpt)) recJets->erase(recjet); } @@ -194,7 +196,10 @@ int main (int argc, char * argv[]) options.inputs("inputs", &inputs, "input ROOT file(s) or directory") .output("output", &output, "output ROOT file") .arg<fs::path>("MBmaxgenpt", "corrections.PUcleaning.MBmaxgenpt", - "2-column file with MB event ID and max gen pt"); + "2-column file with MB event ID and max gen pt") + .arg<float>("artifacts_minpt", "corrections.PUcleaning.artifacts_minpt", + "Partily arbitrary value to cut of overweighted reconstruction " + "artifacts (0 to deactivate)"); /// \note 156 GeV for Pythia UL18 const auto& config = options(argc, argv); const auto& slice = options.slice(); diff --git a/PUstaubSauger/bin/applyPUcleaningHT.cc b/PUstaubSauger/bin/applyPUcleaningHT.cc index 7c5aea1f..e482bfe6 100644 --- a/PUstaubSauger/bin/applyPUcleaningHT.cc +++ b/PUstaubSauger/bin/applyPUcleaningHT.cc @@ -90,6 +90,9 @@ void applyPUcleaningHT const auto& maxgenhts = GetMaxGenHts(fMBmaxgenht); metainfo.Set<fs::path>("corrections", "PUcleaning", "MBmaxgenht", fMBmaxgenht); + auto artifacts_minpt = config.get<float>("corrections.PUcleaning.artifacts_minpt"); + metainfo.Set<float>("corrections", "PUcleaning", "artifacts_minpt", artifacts_minpt); + // branches auto genEvt = flow.GetBranchReadOnly<GenEvent>("genEvent"); auto recEvt = flow.GetBranchReadWrite<RecEvent>("recEvent"); @@ -134,15 +137,14 @@ void applyPUcleaningHT } // 3- removal of reconstruction artefacts happening at excessively high pt - if (recJets->size() > 0) { + if (recJets->size() > 0 && artifacts_minpt > 0) { const auto& recjet = recJets->begin(); bool matched = false; for (const auto& genjet: *genJets) matched |= DeltaR(genjet.p4, recjet->p4) < maxDR; float maxgenpt = genJets->size() > 0 ? genJets->front().p4.Pt() : genEvt->hard_scale; - static const float m = 156; /// \todo Hard-coded cut currently tuned for Pythia UL18 - if (recjet->p4.Pt() > max(2*maxgenpt, m)) + if (recjet->p4.Pt() > max(2*maxgenpt, artifacts_minpt)) genEvt->weights.front() = 0; } @@ -193,7 +195,10 @@ int main (int argc, char * argv[]) options.inputs("inputs", &inputs, "input ROOT file(s) or directory") .output("output", &output, "output ROOT file") .arg<fs::path>("MBmaxgenht", "corrections.PUcleaning.MBmaxgenht", - "2-column file with MB event ID and max gen ht"); + "2-column file with MB event ID and max gen ht") + .arg<float>("artifacts_minpt", "corrections.PUcleaning.artifacts_minpt", + "Partily arbitrary value to cut of overweighted reconstruction " + "artifacts (0 to deactivate)"); /// \note 156 GeV for Pythia UL18 const auto& config = options(argc, argv); const auto& slice = options.slice(); -- GitLab From edb0590c271f6c6a82881cf7179f808fe51ce938 Mon Sep 17 00:00:00 2001 From: "Patrick L.S. Connor" <patrick.connor@cern.ch> Date: Sat, 1 Feb 2025 14:23:12 +0100 Subject: [PATCH 7/7] improve logic when input data set is not found by mkNtuples --- Ntupliser/scripts/mkNtuples | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Ntupliser/scripts/mkNtuples b/Ntupliser/scripts/mkNtuples index 36060a3b..972b32e6 100755 --- a/Ntupliser/scripts/mkNtuples +++ b/Ntupliser/scripts/mkNtuples @@ -15,18 +15,20 @@ parser.add_argument('-i', '--image', help="cc7, el8, el9", default="el8") args = parser.parse_args() import os, json -if os.path.exists(args.configFile): - print("Opening " + args.configFile) - with open(args.configFile, "r") as f: - params = json.load(f) -else: - print("Warning: no config file given in argument. The script will be run with a default data set. This probably only makes sense for testing.") +if args.configFile == "": + print("\x1B[33mWarning: no config file given in argument. The script will be run with a default data set. This probably only makes sense for testing.\x1B[0m") params = { 'name': 'test', 'flags': { 'options' : ['jets'] }, 'datasets': {'/QCD_Pt-15to7000_TuneCP5_Flat2018_13TeV_pythia8/RunIISummer20UL16MiniAODAPVv2-106X_mcRun2_asymptotic_preVFP_v11-v1/MINIAODSIM': {'splitting': 'FileBased'}} } args.configFile = "test.json" +elif os.path.exists(args.configFile): + print("Opening " + args.configFile) + with open(args.configFile, "r") as f: + params = json.load(f) +else: + raise ValueError("Input config file could not be found") # Expected scenarios: # 1. The user runs from EL9 with an elementary config. In that case, `initMetaInfo` may be used to update the input config. The updated config is then used as argument to `mkNtuples` run from an EL8 image with apptainer. @@ -49,7 +51,7 @@ if not 'git' in params: params['git'] = { 'repo': str(origin), 'commit': str(sha), - 'reproducible': False, # TODO: or include software versions + 'reproducible': False, ## \todo or include software versions 'complete': False } -- GitLab