diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetUncertaintiesAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetUncertaintiesAlg.h index 8d522f7c5a82fefb8ce351d4258f824c78040610..eb3cf87fa7c257a2893cf882eed72bef2d9e364d 100644 --- a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetUncertaintiesAlg.h +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetUncertaintiesAlg.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration */ /// @author Nils Krumnack @@ -35,10 +35,14 @@ namespace CP - /// \brief the uncertainties tool + /// \brief the main jet uncertainties tool private: ToolHandle<ICPJetUncertaintiesTool> m_uncertaintiesTool; + /// \brief the secondary jet uncertainties tool, for pseudo-data JER smearing + private: + ToolHandle<ICPJetUncertaintiesTool> m_uncertaintiesToolPD; + /// \brief the systematics list we run private: SysListHandle m_systematicsList {this}; @@ -56,6 +60,15 @@ namespace CP /// \brief the helper for OutOfValidity results private: OutOfValidityHelper m_outOfValidity {this}; + + /// \brief the vector of systematics (for CPU-optimisation) + private: + std::vector<CP::SystematicSet> m_systematicsVector; + + /// \brief the vector of pseudo-data JER systematics (for CPU-optimisation) + private: + std::vector<CP::SystematicSet> m_systematicsVectorOnlyJERPseudoData; + }; } diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetUncertaintiesAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetUncertaintiesAlg.cxx index 776e493ff06bbbb58c3ed790df700a36bf6f4fd6..c75a456da3530d96585c81a42a2a4338165f707f 100644 --- a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetUncertaintiesAlg.cxx +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetUncertaintiesAlg.cxx @@ -22,8 +22,10 @@ namespace CP ISvcLocator* pSvcLocator) : AnaAlgorithm (name, pSvcLocator) , m_uncertaintiesTool ("JetUncertaintiesTool", this) + , m_uncertaintiesToolPD ("", this) { declareProperty ("uncertaintiesTool", m_uncertaintiesTool, "the uncertainties tool we apply"); + declareProperty ("uncertaintiesToolPD", m_uncertaintiesToolPD, "the uncertainties tool we apply specifically for the 'Full'/'All' JER systematic models"); } @@ -35,8 +37,24 @@ namespace CP ANA_CHECK (m_jetHandle.initialize (m_systematicsList)); ANA_CHECK (m_preselection.initialize (m_systematicsList, m_jetHandle, SG::AllowEmpty)); ANA_CHECK (m_systematicsList.addSystematics (*m_uncertaintiesTool)); + if (!m_uncertaintiesToolPD.empty()) { + ANA_CHECK (m_uncertaintiesToolPD.retrieve()); + ANA_CHECK (m_systematicsList.addSystematics (*m_uncertaintiesToolPD)); + } ANA_CHECK (m_systematicsList.initialize()); ANA_CHECK (m_outOfValidity.initialize()); + + // CPU-optimisation: differentiate the systematics for the two tools + // in initialisation rather than execution + for (const auto&sys : m_systematicsList.systematicsVector()) + { + if (sys.name().find("PseudoData") != std::string::npos) { + m_systematicsVectorOnlyJERPseudoData.push_back(sys); + } + else { + m_systematicsVector.push_back(sys); + } + } return StatusCode::SUCCESS; } @@ -45,18 +63,31 @@ namespace CP StatusCode JetUncertaintiesAlg :: execute () { - for (const auto& sys : m_systematicsList.systematicsVector()) + for (const auto& sys : m_systematicsVector) + { + ANA_CHECK (m_uncertaintiesTool->applySystematicVariation (sys)); + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet, sys)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_uncertaintiesTool->applyCorrection (*jet)); + } + } + } + for (const auto& sys : m_systematicsVectorOnlyJERPseudoData) { - ANA_CHECK (m_uncertaintiesTool->applySystematicVariation (sys)); + ANA_CHECK (m_uncertaintiesToolPD->applySystematicVariation (sys)); xAOD::JetContainer *jets = nullptr; ANA_CHECK (m_jetHandle.getCopy (jets, sys)); for (xAOD::Jet *jet : *jets) - { - if (m_preselection.getBool (*jet, sys)) - { - ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_uncertaintiesTool->applyCorrection (*jet)); - } - } + { + if (m_preselection.getBool (*jet, sys)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_uncertaintiesToolPD->applyCorrection (*jet)); + } + } } return StatusCode::SUCCESS; diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py index a5e50ca49a17576f5bdd8602e5887156541d237e..2fd47645c84f916584d7005bb21b7be24be5c5fc 100644 --- a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py @@ -112,6 +112,89 @@ class SmallRJetAnalysisConfig (ConfigBlock) : self.addOption ('uncertToolCalibArea', None, type=str) self.addOption ('uncertToolMCType', None, type=str) + + def getUncertaintyToolSettings(self, config): + + # Retrieve appropriate JES/JER recommendations for the JetUncertaintiesTool. + # We do this separately from the tool declaration, as we may need to set uo + # two such tools, but they have to be private. + + # Config file: + config_file = None + if self.systematicsModelJES == "All" and self.systematicsModelJER == "All": + config_file = "R4_AllNuisanceParameters_AllJERNP.config" + elif "Scenario" in self.systematicsModelJES: + if self.systematicsModelJER != "Simple": + raise ValueError( + "Invalid uncertainty configuration - Scenario* systematicsModelJESs can " + "only be used together with the Simple systematicsModelJER") + config_file = "R4_{0}_SimpleJER.config".format(self.systematicsModelJES) + elif self.systematicsModelJES in ["Global", "Category"] and self.systematicsModelJER in ["Simple", "Full"]: + config_file = "R4_{0}Reduction_{1}JER.config".format(self.systematicsModelJES, self.systematicsModelJER) + else: + raise ValueError( + "Invalid combination of systematicsModelJES and systematicsModelJER settings: " + "systematicsModelJES: {0}, systematicsModelJER: {1}".format(self.systematicsModelJES, self.systematicsModelJER) ) + + # Calibration area: + calib_area = None + if self.uncertToolCalibArea is not None: + calib_area = self.uncertToolCalibArea + + # Expert override for config path: + if self.uncertToolConfigPath is not None: + config_file = self.uncertToolConfigPath + else: + config_file = "rel22/Summer2023_PreRec/" + config_file + + # MC type: + mc_type = None + if self.uncertToolMCType is not None: + mc_type = self.uncertToolMCType + else: + if config.geometry() is LHCPeriod.Run2: + mc_type = "MC20" + else: + mc_type = "MC21" + + return config_file, calib_area, mc_type + + + def createUncertaintyTool(self, jetUncertaintiesAlg, config, jetCollectionName, doPseudoData=False): + + # Create an instance of JetUncertaintiesTool, following JetETmiss recommendations. + # To run Jet Energy Resolution (JER) uncertainties in the "Full" or "All" schemes, + # we need two sets of tools: one configured as normal (MC), the other with the + # exact same settings but pretending to run on data (pseudo-data). + # This is achieved by passing "isPseudoData=True" to the arguments. + + # Retrieve the common configuration settings + configFile, calibArea, mcType = self.getUncertaintyToolSettings(config) + + # The main tool for all JES+JER combinations + config.addPrivateTool( 'uncertaintiesTool', 'JetUncertaintiesTool' ) + jetUncertaintiesAlg.uncertaintiesTool.JetDefinition = jetCollectionName[:-4] + jetUncertaintiesAlg.uncertaintiesTool.ConfigFile = configFile + if calibArea is not None: + jetUncertaintiesAlg.uncertaintiesTool.CalibArea = calibArea + jetUncertaintiesAlg.uncertaintiesTool.MCType = mcType + jetUncertaintiesAlg.uncertaintiesTool.IsData = (config.dataType() is DataType.Data) + jetUncertaintiesAlg.uncertaintiesTool.PseudoDataJERsmearingMode = False + + if doPseudoData: + # The secondary tool for pseudo-data JER smearing + config.addPrivateTool( 'uncertaintiesToolPD', 'JetUncertaintiesTool' ) + jetUncertaintiesAlg.uncertaintiesToolPD.JetDefinition = jetCollectionName[:-4] + jetUncertaintiesAlg.uncertaintiesToolPD.ConfigFile = configFile + if calibArea is not None: + jetUncertaintiesAlg.uncertaintiesToolPD.CalibArea = calibArea + jetUncertaintiesAlg.uncertaintiesToolPD.MCType = mcType + + # This is the part that is different! + jetUncertaintiesAlg.uncertaintiesToolPD.IsData = True + jetUncertaintiesAlg.uncertaintiesToolPD.PseudoDataJERsmearingMode = True + + def makeAlgs (self, config) : postfix = self.postfix @@ -162,40 +245,7 @@ class SmallRJetAnalysisConfig (ConfigBlock) : # Jet uncertainties alg = config.createAlgorithm( 'CP::JetUncertaintiesAlg', 'JetUncertaintiesAlg'+postfix ) - config.addPrivateTool( 'uncertaintiesTool', 'JetUncertaintiesTool' ) - alg.uncertaintiesTool.JetDefinition = jetCollectionName[:-4] - # Prepare the config file - if self.systematicsModelJES == "All" and self.systematicsModelJER == "All": - alg.uncertaintiesTool.ConfigFile = "R4_AllNuisanceParameters_AllJERNP.config" - elif "Scenario" in self.systematicsModelJES: - if self.systematicsModelJER != "Simple": - raise ValueError( - "Invalid uncertainty configuration - Scenario* systematicsModelJESs can " - "only be used together with the Simple systematicsModelJER") - configFile = "R4_{0}_SimpleJER.config".format(self.systematicsModelJES) - elif self.systematicsModelJES in ["Global", "Category"] and self.systematicsModelJER in ["Simple", "Full"]: - configFile = "R4_{0}Reduction_{1}JER.config".format(self.systematicsModelJES, self.systematicsModelJER) - else: - raise ValueError( - "Invalid combination of systematicsModelJES and systematicsModelJER settings: " - "systematicsModelJES: {0}, systematicsModelJER: {1}".format(self.systematicsModelJES, self.systematicsModelJER) ) - # Expert override for calibarea - if self.uncertToolCalibArea is not None: - alg.uncertaintiesTool.CalibArea = self.uncertToolCalibArea - # Expert override for configpath - if self.uncertToolConfigPath is not None: - alg.uncertaintiesTool.ConfigFile = self.uncertToolConfigPath - else: # Default config - alg.uncertaintiesTool.ConfigFile = "rel22/Summer2023_PreRec/"+configFile # Add the correct directory on the front - # Expert override for mctype - if self.uncertToolMCType is not None: - alg.uncertaintiesTool.MCType = self.uncertToolMCType - else: # Default config - if config.geometry() is LHCPeriod.Run2: - alg.uncertaintiesTool.MCType = "MC20" - else: - alg.uncertaintiesTool.MCType = "MC21" - alg.uncertaintiesTool.IsData = (config.dataType() is DataType.Data) + self.createUncertaintyTool(alg, config, jetCollectionName, doPseudoData=( self.systematicsModelJER in ["Full","All"] )) alg.jets = config.readName (self.containerName) alg.jetsOut = config.copyName (self.containerName) alg.preselection = config.getPreselection (self.containerName, '') diff --git a/Reconstruction/Jet/JetUncertainties/JetUncertainties/JetUncertaintiesTool.h b/Reconstruction/Jet/JetUncertainties/JetUncertainties/JetUncertaintiesTool.h index 5708d5c7c8f699c89d42a3dac2f73991d6b6c24e..f5415910ad878b765df383ed3c1637593bba10ad 100644 --- a/Reconstruction/Jet/JetUncertainties/JetUncertainties/JetUncertaintiesTool.h +++ b/Reconstruction/Jet/JetUncertainties/JetUncertainties/JetUncertaintiesTool.h @@ -274,6 +274,9 @@ class ATLAS_NOT_THREAD_SAFE JetUncertaintiesTool : virtual public ICPJetUncertai // Properties for the flavour configuration bool m_absEtaGluonFraction; + + // toggle only the JER uncertainties for pseudo-data smearing + bool m_pseudoDataJERsmearingMode; }; diff --git a/Reconstruction/Jet/JetUncertainties/Root/JetUncertaintiesTool.cxx b/Reconstruction/Jet/JetUncertainties/Root/JetUncertaintiesTool.cxx index 9baca54f1a3afdd309b4ea53017dee1051c9af45..46e02b0e22183b4e809d993f350565034345bcdc 100644 --- a/Reconstruction/Jet/JetUncertainties/Root/JetUncertaintiesTool.cxx +++ b/Reconstruction/Jet/JetUncertainties/Root/JetUncertaintiesTool.cxx @@ -105,6 +105,7 @@ JetUncertaintiesTool::JetUncertaintiesTool(const std::string& name) , m_accEfficiency("temp_efficiency") , m_accTagResult("temp_accept") , m_absEtaGluonFraction(true) + , m_pseudoDataJERsmearingMode(false) { declareProperty("JetDefinition",m_jetDef); declareProperty("MCType",m_mcType); @@ -116,6 +117,7 @@ JetUncertaintiesTool::JetUncertaintiesTool(const std::string& name) declareProperty("VariablesToShift",m_systFilters); declareProperty("IsData",m_isData); declareProperty("AbsEtaGluonFraction",m_absEtaGluonFraction); + declareProperty("PseudoDataJERsmearingMode",m_pseudoDataJERsmearingMode); ATH_MSG_DEBUG("Creating JetUncertaintiesTool named "<<m_name); @@ -168,6 +170,7 @@ JetUncertaintiesTool::JetUncertaintiesTool(const JetUncertaintiesTool& toCopy) , m_accEfficiency(toCopy.m_accEfficiency) , m_accTagResult(toCopy.m_accTagResult) , m_absEtaGluonFraction(toCopy.m_absEtaGluonFraction) + , m_pseudoDataJERsmearingMode(toCopy.m_pseudoDataJERsmearingMode) { ATH_MSG_DEBUG("Creating copy of JetUncertaintiesTool named "<<m_name); @@ -708,6 +711,13 @@ StatusCode JetUncertaintiesTool::initialize() CP::SystematicVariation systVar(m_groups.at(iGroup)->getName().Data(),CP::SystematicVariation::CONTINUOUS); if (addAffectingSystematic(systVar,isRecommended) != StatusCode::SUCCESS) return StatusCode::FAILURE; + if (m_pseudoDataJERsmearingMode) { + if (systVar.basename().find("JER") != std::string::npos) { + CP::SystematicVariation systVarPD(systVar.basename()+"_PseudoData",CP::SystematicVariation::CONTINUOUS); + if (addAffectingSystematic(systVarPD,isRecommended) != StatusCode::SUCCESS) + return StatusCode::FAILURE; + } + } } // Ensure that we have nominal resolutions for any requested resolution uncertainties @@ -1306,11 +1316,24 @@ StatusCode JetUncertaintiesTool::applySystematicVariation(const CP::SystematicSe // ATH_MSG_FATAL("Tool must be initialized before calling applySystematicVariation"); // return StatusCode::FAILURE; //} + CP::SystematicSet filteredSet; + if (m_pseudoDataJERsmearingMode) { + std::string remappedName = systConfig.name(); + size_t found = remappedName.find("_PseudoData"); + if (found != std::string::npos) { + remappedName.erase(found, std::string("_PseudoData").length()); + } + CP::SystematicSet altConfig(remappedName); + // Filter the full set of systematics to the set we care about + if (getFilteredSystematicSet(altConfig,filteredSet) != StatusCode::SUCCESS) + return StatusCode::FAILURE; + } + else { // Filter the full set of systematics to the set we care about - CP::SystematicSet filteredSet; if (getFilteredSystematicSet(systConfig,filteredSet) != StatusCode::SUCCESS) return StatusCode::FAILURE; + } // Get the uncertainty set associated to the filtered systematics set jet::UncertaintySet* uncSet = nullptr;