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;