diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.cpp
index 184913d185d6a6aaabc579fbe514b417932b3158..79d6550dccdf1347d0e3901b60b52160e752f9c4 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.cpp
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.cpp
@@ -28,11 +28,12 @@ CaloFutureCorrectionBase::CaloFutureCorrectionBase( const std::string& type, con
   m_cmLoc = LHCb::CaloFutureAlgUtils::CaloFutureIdLocation( "ClusterMatch" );
 
   // allocate memory for m_params. params[area][type]
-  CaloFutureCorrection::ParamVector             vect;
-  CaloFutureCorrection::Parameters              typePar_pair = std::make_pair( CaloFutureCorrection::Empty, vect );
-  std::vector<CaloFutureCorrection::Parameters> vect_pair( CaloFutureCorrection::nT, typePar_pair );
+  CaloFutureCorrection::ParamVector         vect;
+  CaloFutureCorrection::PrecalculatedParams precalculated;
+  CaloFutureCorrection::CachedParameters    typePar_tuple = {CaloFutureCorrection::Empty, vect, precalculated};
+  std::vector<CaloFutureCorrection::CachedParameters> vect_tuple( CaloFutureCorrection::nT, typePar_tuple );
   m_params.reserve( area_size ); // area_size=3 (outer, middle, inner)
-  for ( auto area = 0; area < area_size; ++area ) m_params.push_back( vect_pair );
+  for ( auto area = 0; area < area_size; ++area ) m_params.push_back( vect_tuple );
 }
 
 StatusCode CaloFutureCorrectionBase::initialize() {
@@ -84,10 +85,10 @@ StatusCode CaloFutureCorrectionBase::finalize() {
 
   for ( auto area = 0; area < 3; ++area ) {
     for ( auto itype = 0; itype < static_cast<int>( CaloFutureCorrection::nT ); ++itype ) {
-      int func = m_params[area][itype].first;
+      int func = m_params[area][itype].function;
       if ( func == CaloFutureCorrection::Empty ) continue;
       const auto& type = CaloFutureCorrection::typeName[itype];
-      const auto& vec  = m_params[area][itype].second;
+      const auto& vec  = m_params[area][itype].values;
 
       if ( !vec.empty() ) {
 
@@ -178,55 +179,70 @@ void CaloFutureCorrectionBase::Params( const std::string& paramName, const CaloF
       continue;
     }
 
-    m_params[area][type].first = static_cast<CaloFutureCorrection::Function>( func );
+    m_params[area][type].function = static_cast<CaloFutureCorrection::Function>( func );
 
-    m_params[area][type].second.clear();
-    m_params[area][type].second.reserve( dim );
+    m_params[area][type].values.clear();
+    m_params[area][type].values.reserve( dim );
     for ( int i = 0; i < dim; ++i ) {
-      m_params[area][type].second.push_back( params[pos] );
+      m_params[area][type].values.push_back( params[pos] );
       pos += step;
     }
+    // precalculated exponent, sinh and cosh values: see 'polynomial functions' and 'Sshape function' in
+    // CaloFutureCorrectionBase::getCorrection and CaloFutureCorrectionBase::getCorrectionDerivative
+    if ( !m_params[area][type].values.empty() ) {
+      const auto&      b                        = m_params[area][type].values[0];
+      constexpr double delta                    = 0.5;
+      m_params[area][type].precalculated.myexp  = myexp( b );
+      auto sinh_val                             = ( b != 0 ) ? mysinh( delta / b ) : INFINITY;
+      m_params[area][type].precalculated.mysinh = sinh_val;
+      m_params[area][type].precalculated.mycosh = sqrt( 1. + sinh_val * sinh_val );
+    }
   }
 }
 
-const CaloFutureCorrection::Parameters& CaloFutureCorrectionBase::getParams( const CaloFutureCorrection::Type type,
-                                                                             const LHCb::CaloCellID id ) const {
+const CaloFutureCorrection::CachedParameters&
+CaloFutureCorrectionBase::getParams( const CaloFutureCorrection::Type type, const LHCb::CaloCellID id ) const {
   auto area = id.area();
 
   return m_params[area][type];
 }
 
-double CaloFutureCorrectionBase::getCorrection( const CaloFutureCorrection::Type type, const LHCb::CaloCellID id,
-                                                double var, double def ) const {
+std::optional<double> CaloFutureCorrectionBase::getCorrectionImpl( const CaloFutureCorrection::Type type,
+                                                                   const LHCb::CaloCellID id, const double var,
+                                                                   double* derivative ) const {
+  bool   doDerivative = ( derivative != nullptr );
+  double cor          = 0.;
 
   const auto& pars = getParams( type, id );
   if ( UNLIKELY( msgLevel( MSG::DEBUG ) ) ) {
     const auto& name = CaloFutureCorrection::typeName[type];
     debug() << "Correction type " << name << " to be applied on cluster (seed = " << id << ") is a '"
-            << CaloFutureCorrection::funcName[pars.first] << "' function with params = " << pars.second << endmsg;
+            << CaloFutureCorrection::funcName[pars.function] << "' function with params = " << pars.values << endmsg;
   }
 
   // compute correction
-  if ( pars.first == CaloFutureCorrection::Unknown || pars.second.empty() ) return def;
+  if ( pars.function == CaloFutureCorrection::Unknown || pars.values.empty() ) return std::nullopt;
 
   // list accessor - not correction :
-  if ( pars.first == CaloFutureCorrection::ParamList || pars.first == CaloFutureCorrection::GlobalParamList ) {
+  if ( pars.function == CaloFutureCorrection::ParamList || pars.function == CaloFutureCorrection::GlobalParamList ) {
     warning() << " Param accessor is a fake function - no correction to be applied - return default value" << endmsg;
-    return def;
+    return std::nullopt;
   }
 
-  double cor = def;
   // polynomial correction
-  const auto& temp = pars.second;
+  const auto& temp = pars.values;
+  // and precalculated exponents of some of these values
+  auto& temp_precalc = pars.precalculated;
 
   // polynomial functions
-  if ( pars.first == CaloFutureCorrection::Polynomial || pars.first == CaloFutureCorrection::InversPolynomial ||
-       pars.first == CaloFutureCorrection::ExpPolynomial || pars.first == CaloFutureCorrection::ReciprocalPolynomial ) {
+  if ( pars.function == CaloFutureCorrection::Polynomial || pars.function == CaloFutureCorrection::InversPolynomial ||
+       pars.function == CaloFutureCorrection::ExpPolynomial ||
+       pars.function == CaloFutureCorrection::ReciprocalPolynomial ) {
     double v = 1.;
     cor      = 0.;
     for ( auto i = temp.begin(); i != temp.end(); ++i ) {
       cor += ( *i ) * v;
-      if ( pars.first == CaloFutureCorrection::ReciprocalPolynomial )
+      if ( pars.function == CaloFutureCorrection::ReciprocalPolynomial )
         v = ( var == 0 ) ? 0. : v / var;
       else
         v *= var;
@@ -235,36 +251,79 @@ double CaloFutureCorrectionBase::getCorrection( const CaloFutureCorrection::Type
       if ( UNLIKELY( msgLevel( MSG::VERBOSE ) ) ) verbose() << "cor = " << cor << endmsg;
 #endif
     }
-    if ( pars.first == CaloFutureCorrection::InversPolynomial ) cor = ( cor == 0 ) ? def : 1. / cor;
-    if ( pars.first == CaloFutureCorrection::ExpPolynomial ) cor = ( cor == 0 ) ? def : myexp( cor );
+    if ( pars.function == CaloFutureCorrection::InversPolynomial )
+      if ( cor != 0 ) cor = 1. / cor;
+    if ( pars.function == CaloFutureCorrection::ExpPolynomial ) {
+      if ( cor != 0 ) {
+        if ( var == 0.0 )
+          // if var == 0.0 then cor == temp[0]
+          cor = temp_precalc.myexp;
+        else
+          cor = myexp( cor );
+      }
+    }
+
+    if ( doDerivative ) {
+      if ( pars.function == CaloFutureCorrection::Polynomial ||
+           pars.function == CaloFutureCorrection::InversPolynomial ||
+           pars.function == CaloFutureCorrection::ExpPolynomial ) {
+        *derivative = 0.;
+        double v    = 1.;
+        int    cnt  = 0;
+        auto   i    = temp.begin();
+        for ( ++i, cnt++; i != temp.end(); ++i, cnt++ ) {
+          *derivative += ( *i ) * cnt * v;
+          v *= var;
+        }
+        if ( pars.function == CaloFutureCorrection::InversPolynomial ) *derivative = -( *derivative ) * cor * cor;
+        if ( pars.function == CaloFutureCorrection::ExpPolynomial ) *derivative = ( *derivative ) * cor;
+      } else if ( pars.function == CaloFutureCorrection::ReciprocalPolynomial ) {
+        *derivative = 0.;
+        if ( var != 0 ) {
+          auto v   = 1. / ( var * var );
+          int  cnt = 0;
+          auto i   = temp.begin();
+          for ( ++i, cnt++; i != temp.end(); ++i, cnt++ ) {
+            *derivative -= ( *i ) * cnt * v;
+            v /= var;
+          }
+        }
+      }
+    }
   }
 
   // sigmoid function
-  else if ( pars.first == CaloFutureCorrection::Sigmoid ) {
+  else if ( pars.function == CaloFutureCorrection::Sigmoid ) {
     if ( temp.size() == 4 ) {
-      const auto& a = temp[0];
-      const auto& b = temp[1];
-      const auto& c = temp[2];
-      const auto& d = temp[3];
-      cor           = a + b * mytanh( c * ( var + d ) );
+      const auto& a          = temp[0];
+      const auto& b          = temp[1];
+      const auto& c          = temp[2];
+      const auto& d          = temp[3];
+      auto        mytanh_val = mytanh( c * ( var + d ) );
+      cor                    = a + b * mytanh_val;
+      if ( doDerivative ) *derivative = b * c * ( 1. - mytanh_val * mytanh_val );
     } else {
       Warning( "The power sigmoid function must have 4 parameters" ).ignore();
     }
   }
 
   // Sshape function
-  else if ( pars.first == CaloFutureCorrection::Sshape || pars.first == CaloFutureCorrection::SshapeMod ) {
+  else if ( pars.function == CaloFutureCorrection::Sshape || pars.function == CaloFutureCorrection::SshapeMod ) {
     if ( temp.size() == 1 ) {
       const auto&      b     = temp[0];
       constexpr double delta = 0.5;
       if ( b > 0 ) {
         double arg = var / delta;
-        if ( pars.first == CaloFutureCorrection::SshapeMod ) {
-          arg *= mysinh( delta / b );
-        } else if ( pars.first == CaloFutureCorrection::Sshape ) {
-          arg *= mycosh( delta / b );
+        double csh = 1.;
+        if ( pars.function == CaloFutureCorrection::SshapeMod ) {
+          arg *= temp_precalc.mysinh;
+          csh = temp_precalc.mysinh;
+        } else if ( pars.function == CaloFutureCorrection::Sshape ) {
+          arg *= temp_precalc.mycosh;
+          csh = temp_precalc.mycosh;
         }
         cor = b * mylog( arg + std::sqrt( arg * arg + 1.0 ) );
+        if ( doDerivative ) *derivative = b / delta * csh / std::sqrt( arg * arg + 1. );
       }
     } else {
       Warning( "The Sshape function must have 1 parameter" ).ignore();
@@ -272,16 +331,30 @@ double CaloFutureCorrectionBase::getCorrection( const CaloFutureCorrection::Type
   }
 
   // Shower profile function
-  else if ( pars.first == CaloFutureCorrection::ShowerProfile ) {
+  else if ( pars.function == CaloFutureCorrection::ShowerProfile ) {
     if ( temp.size() == 10 ) {
       if ( var > 0.5 ) {
-        cor = temp[0] * myexp( -temp[1] * var );
-        cor += temp[2] * myexp( -temp[3] * var );
-        cor += temp[4] * myexp( -temp[5] * var );
+        auto tmp1 = temp[0] * myexp( -temp[1] * var );
+        auto tmp2 = temp[2] * myexp( -temp[3] * var );
+        auto tmp3 = temp[4] * myexp( -temp[5] * var );
+        cor       = tmp1;
+        cor += tmp2;
+        cor += tmp3;
+        if ( doDerivative ) {
+          *derivative = -temp[1] * tmp1;
+          *derivative += -temp[3] * tmp2;
+          *derivative += -temp[5] * tmp3;
+        }
       } else {
-        cor = 2.;
-        cor -= temp[6] * myexp( -temp[7] * var );
-        cor -= temp[8] * myexp( -temp[9] * var );
+        cor       = 2.;
+        auto tmp1 = temp[6] * myexp( -temp[7] * var );
+        auto tmp2 = temp[8] * myexp( -temp[9] * var );
+        cor -= tmp1;
+        cor -= tmp2;
+        if ( doDerivative ) {
+          *derivative += temp[7] * tmp1;
+          *derivative += temp[9] * tmp2;
+        }
       }
     } else {
       Warning( "The ShowerProfile function must have 10 parameters" ).ignore();
@@ -289,10 +362,13 @@ double CaloFutureCorrectionBase::getCorrection( const CaloFutureCorrection::Type
   }
 
   // Sinusoidal function
-  else if ( pars.first == CaloFutureCorrection::Sinusoidal ) {
+  else if ( pars.function == CaloFutureCorrection::Sinusoidal ) {
     if ( temp.size() == 1 ) {
-      const double& A = temp[0];
-      cor             = A * mysin( 2 * M_PI * var );
+      const double&    A       = temp[0];
+      constexpr double twopi   = 2. * M_PI;
+      const auto       sin_val = mysin( twopi * var );
+      cor                      = A * sin_val;
+      if ( doDerivative ) *derivative = A * twopi * sqrt( 1. - sin_val * sin_val );
     } else {
       Warning( "The Sinusoidal function must have 1 parameter" ).ignore();
     }
@@ -310,10 +386,10 @@ void CaloFutureCorrectionBase::checkParams() {
     }
 
     for ( int itype = 0; itype < static_cast<int>( CaloFutureCorrection::nT ); ++itype ) {
-      int  func = m_params[area][itype].first;
+      int  func = m_params[area][itype].function;
       bool ok   = true;
       if ( func != CaloFutureCorrection::Empty ) {
-        if ( m_params[area][itype].second.size() == 0 ) {
+        if ( m_params[area][itype].values.size() == 0 ) {
           warning() << "Empty parameter vector of type " << CaloFutureCorrection::typeName[itype] << " of function "
                     << CaloFutureCorrection::funcName[func] << endmsg;
           ok = false;
@@ -326,163 +402,12 @@ void CaloFutureCorrectionBase::checkParams() {
       }
       if ( UNLIKELY( msgLevel( MSG::DEBUG ) && ok ) )
         debug() << " o Will apply correction '" << CaloFutureCorrection::funcName[itype] << "' as a '"
-                << CaloFutureCorrection::funcName[func] << "' function of " << m_params[area][itype].second.size()
+                << CaloFutureCorrection::funcName[func] << "' function of " << m_params[area][itype].values.size()
                 << " parameters" << endmsg;
       if ( !ok ) {
-        m_params[area][itype].second.clear();
-        m_params[area][itype].first = CaloFutureCorrection::Empty;
+        m_params[area][itype].values.clear();
+        m_params[area][itype].function = CaloFutureCorrection::Empty;
       }
     }
   }
 }
-
-double CaloFutureCorrectionBase::getCorrectionDerivative( const CaloFutureCorrection::Type type,
-                                                          const LHCb::CaloCellID id, double var, double def ) const {
-  const auto& pars = getParams( type, id );
-
-  if ( msgLevel( MSG::DEBUG ) ) {
-    const auto name = CaloFutureCorrection::typeName[type];
-    debug() << "Derivative for Correction type " << name << " to be calculated for cluster (seed = " << id << ") is a '"
-            << CaloFutureCorrection::funcName[pars.first] << "' function with params = " << pars.second << endmsg;
-  }
-
-  // compute correction
-  double cor = def;
-  if ( pars.first == CaloFutureCorrection::Unknown || pars.second.empty() ) return cor;
-
-  // polynomial correction
-  const auto& temp = pars.second;
-
-  // polynomial functions
-  double ds = 0.;
-  if ( pars.first == CaloFutureCorrection::Polynomial ) {
-    ds         = 0.;
-    double v   = 1.;
-    int    cnt = 0;
-    auto   i   = temp.begin();
-    for ( ++i, cnt++; i != temp.end(); ++i, cnt++ ) {
-      ds += ( *i ) * cnt * v;
-      v *= var;
-    }
-  }
-
-  else if ( pars.first == CaloFutureCorrection::InversPolynomial ) {
-    double v = 1.;
-    cor      = 0.;
-    for ( auto i = temp.begin(); i != temp.end(); ++i ) {
-      cor += ( *i ) * v;
-      v *= var;
-    }
-    cor = ( cor == 0 ) ? def : 1. / cor;
-
-    v        = 1.;
-    ds       = 0.;
-    int  cnt = 0;
-    auto i   = temp.begin();
-    for ( ++i, cnt++; i != temp.end(); ++i, cnt++ ) {
-      ds += ( *i ) * cnt * v;
-      v *= var;
-    }
-    ds *= -cor * cor;
-  }
-
-  else if ( pars.first == CaloFutureCorrection::ExpPolynomial ) {
-    double v = 1.;
-    cor      = 0.;
-    for ( auto i = temp.begin(); i != temp.end(); ++i ) {
-      cor += ( *i ) * v;
-      v *= var;
-    }
-    cor = ( cor == 0 ) ? def : myexp( cor );
-
-    ds       = 0.;
-    v        = 1.;
-    int  cnt = 0;
-    auto i   = temp.begin();
-    for ( ++i, cnt++; i != temp.end(); ++i, cnt++ ) {
-      ds += ( *i ) * cnt * v;
-      v *= var;
-    }
-
-    ds *= cor;
-  }
-
-  else if ( pars.first == CaloFutureCorrection::ReciprocalPolynomial ) {
-    ds = 0.;
-    if ( var != 0 ) {
-      auto v   = 1. / ( var * var );
-      int  cnt = 0;
-      auto i   = temp.begin();
-      for ( ++i, cnt++; i != temp.end(); ++i, cnt++ ) {
-        ds -= ( *i ) * cnt * v;
-        v /= var;
-      }
-    }
-  }
-
-  // sigmoid function
-  else if ( pars.first == CaloFutureCorrection::Sigmoid ) {
-    ds = 0.;
-    if ( temp.size() == 4 ) {
-      // double a = temp[0];
-      const auto& b = temp[1];
-      const auto& c = temp[2];
-      const auto& d = temp[3];
-      ds            = b * c * ( 1. - std::pow( mytanh( c * ( var + d ) ), 2 ) );
-    } else {
-      Warning( "The power sigmoid function must have 4 parameters" ).ignore();
-    }
-  }
-
-  // Sshape function
-  else if ( pars.first == CaloFutureCorrection::Sshape || pars.first == CaloFutureCorrection::SshapeMod ) {
-    ds = 0.;
-    if ( temp.size() == 1 ) {
-      const auto& b     = temp[0];
-      double      delta = 0.5;
-      if ( b > 0 ) {
-        double csh = 1.;
-        if ( pars.first == CaloFutureCorrection::SshapeMod ) {
-          csh = mysinh( delta / b );
-        } else if ( pars.first == CaloFutureCorrection::Sshape ) {
-          csh = mycosh( delta / b );
-        }
-        const auto arg = var / delta * csh;
-        ds             = b / delta * csh / std::sqrt( arg * arg + 1. );
-      }
-    } else {
-      Warning( "The Sshape function must have 1 parameter" ).ignore();
-    }
-  }
-
-  // Shower profile function
-  else if ( pars.first == CaloFutureCorrection::ShowerProfile ) {
-    ds = 0.;
-    if ( temp.size() == 10 ) {
-      if ( var > 0.5 ) {
-        ds = -temp[0] * temp[1] * myexp( -temp[1] * var );
-        ds += -temp[2] * temp[3] * myexp( -temp[3] * var );
-        ds += -temp[4] * temp[5] * myexp( -temp[5] * var );
-      } else {
-        ds = temp[6] * temp[7] * myexp( -temp[7] * var );
-        ds += temp[8] * temp[9] * myexp( -temp[9] * var );
-      }
-    } else {
-      Warning( "The ShowerProfile function must have 10 parameters" ).ignore();
-    }
-  }
-
-  // Sinusoidal function
-  else if ( pars.first == CaloFutureCorrection::Sinusoidal ) {
-    ds = 0.;
-    if ( temp.size() == 1 ) {
-      const auto&      A     = temp[0];
-      constexpr double twopi = 2. * M_PI;
-      ds                     = A * twopi * mycos( twopi * var );
-    } else {
-      Warning( "The Sinusoidal function must have 1 parameter" ).ignore();
-    }
-  }
-
-  return ds;
-}
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.h b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.h
index d1a8e36f4ca0ca62bd36d488aff45edf48a3be32..7ac485a32a45c62bec5d75b49aff0957d6089cf5 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.h
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureCorrectionBase.h
@@ -72,8 +72,21 @@ namespace CaloFutureCorrection {
     Empty,                     // for empty preallocated places in m_params
     Unknown                    // type of correction from DB that is unspecified here. MUST be the last item.
   };
+
   using ParamVector = std::vector<double>;
-  using Parameters  = std::pair<CaloFutureCorrection::Function, ParamVector>;
+
+  struct PrecalculatedParams {
+    double myexp;
+    double mysinh;
+    double mycosh;
+  };
+
+  struct CachedParameters {
+    CaloFutureCorrection::Function function;
+    ParamVector                    values;
+    PrecalculatedParams            precalculated;
+  };
+
   enum Type {
     // NB: numbering is not continuous due to removed PRS and SPD/Converted_photons -related parameters for Run 1-2
     // CondDB compatibility
@@ -156,8 +169,6 @@ namespace CaloFutureCorrection {
   inline const std::string funcName[nF] = {"InversPolynomial", "Polynomial", "ExpPolynomial",   "ReciprocalPolynomial",
                                            "Sigmoid",          "Sshape",     "ShowerProfile",   "SshapeMod",
                                            "Sinusoidal",       "ParamList",  "GlobalParamList", "Unknown"};
-  using NewVector = std::vector<std::vector<std::pair<CaloFutureCorrection::Function, ParamVector>>>;
-
 } // namespace CaloFutureCorrection
 
 class CaloFutureCorrectionBase : public GaudiTool {
@@ -197,27 +208,37 @@ public:
   }
 
   // accessors
-  const CaloFutureCorrection::Parameters&  getParams( const CaloFutureCorrection::Type type,
-                                                      const LHCb::CaloCellID           id = LHCb::CaloCellID() ) const;
-  inline CaloFutureCorrection::ParamVector getParamVector( const CaloFutureCorrection::Type type,
-                                                           const LHCb::CaloCellID id = LHCb::CaloCellID() ) const {
-    return getParams( type, id ).second;
+  const CaloFutureCorrection::CachedParameters& getParams( const CaloFutureCorrection::Type type,
+                                                           const LHCb::CaloCellID id = LHCb::CaloCellID() ) const;
+  inline CaloFutureCorrection::ParamVector      getParamVector( const CaloFutureCorrection::Type type,
+                                                                const LHCb::CaloCellID id = LHCb::CaloCellID() ) const {
+    return getParams( type, id ).values;
   }
   double getParameter( CaloFutureCorrection::Type type, unsigned int i, const LHCb::CaloCellID id = LHCb::CaloCellID(),
                        double def = 0. ) const {
     const auto& params = getParams( type, id );
-    const auto& data   = params.second;
+    const auto& data   = params.values;
     return ( i < data.size() ) ? data[i] : def;
   }
-  /// calculate analytic derivative for a given function type in cell id at a given point var with default value def
-  double getCorrectionDerivative( const CaloFutureCorrection::Type type, const LHCb::CaloCellID id, double var = 0.,
-                                  double def = 0. ) const;
-  /// propagate cov.m. cov0 according to Jacobian jac: cov1 = (jac * cov * jac^T), see comments in
-  /// CaloFutureECorrection.cpp and CaloFutureSCorrection.cpp
-  // void recalculate_cov(const TMatrixD &jac, const TMatrixDSym &cov0, TMatrixDSym &cov1) const;
 
-  double getCorrection( const CaloFutureCorrection::Type type, const LHCb::CaloCellID id, double var = 0.,
-                        double def = 1. ) const;
+  std::optional<double> getCorrection( const CaloFutureCorrection::Type type, LHCb::CaloCellID id,
+                                       double var = 0. ) const {
+    return getCorrectionImpl( type, id, var, nullptr );
+  }
+
+  struct CorrectionResult {
+    double value;
+    double derivative;
+    CorrectionResult( double _value, double _derivative ) : value( _value ), derivative( _derivative ) {}
+  };
+
+  std::optional<CorrectionResult> getCorrectionAndDerivative( const CaloFutureCorrection::Type type,
+                                                              const LHCb::CaloCellID id, const double var = 0. ) const {
+    double d{0};
+    auto   r = getCorrectionImpl( type, id, var, &d );
+    if ( !r ) return std::nullopt;
+    return std::optional<CorrectionResult>( {*r, d} );
+  }
 
 protected:
   Gaudi::Property<std::string>              m_conditionName{this, "ConditionName", "none"};
@@ -333,10 +354,12 @@ private:
     return *( a->second );
   }
 
+  std::optional<double> getCorrectionImpl( const CaloFutureCorrection::Type type, const LHCb::CaloCellID id,
+                                           const double var, double* derivative ) const;
+
 private:
-  typedef std::vector<std::vector<std::pair<CaloFutureCorrection::Function, CaloFutureCorrection::ParamVector>>>
-                                                              NewVector;
-  NewVector                                                   m_params;
+  typedef std::vector<std::vector<CaloFutureCorrection::CachedParameters>> NewVector;
+  NewVector                                                                m_params;
   const int                                                   area_size = 3; // size of m_params (outer, middle, inner)
   Gaudi::Property<std::map<std::string, std::vector<double>>> m_optParams{this, "Parameters"};
 
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.cpp
index df6e3c3748bac62aedaf7b34ec5218660d4b58d0..9bb7f1aaa16fa03c855009509eac1bc01abd37f3 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.cpp
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureECorrection.cpp
@@ -300,29 +300,37 @@ CaloFutureECorrection::calcECorrection( const struct ECorrInputParams& _params )
   // are useful for debugging in case of changes in the correction function code
   //
   //// aG = const(X,Y,E), no need to calculate derivatives
-  double aG = getCorrection( CaloFutureCorrection::alphaG, cellID ); // global Ecal factor
+  double aG = getCorrection( CaloFutureCorrection::alphaG, cellID ).value_or( 1. ); // global Ecal factor
   //// aE = alphaE(eEcal)
-  double aE = getCorrection( CaloFutureCorrection::alphaE, cellID, eEcal ); // longitudinal leakage
-  double aB = getCorrection( CaloFutureCorrection::alphaB, cellID, bDist ); // lateral leakage
+  const auto aECorDer = getCorrectionAndDerivative( CaloFutureCorrection::alphaE, cellID, eEcal )
+                            .value_or( CorrectionResult{1., 0.} ); // longitudinal leakage
+  const auto aE       = aECorDer.value;
+  const auto aBCorDer = getCorrectionAndDerivative( CaloFutureCorrection::alphaB, cellID, bDist )
+                            .value_or( CorrectionResult{1., 0.} ); // lateral leakage
+  const auto aB = aBCorDer.value;
   //// aX = alphaX(Asx1)
-  double aX = getCorrection( CaloFutureCorrection::alphaX, cellID, Asx ); // module frame dead material X-direction
+  const auto aXCorDer = getCorrectionAndDerivative( CaloFutureCorrection::alphaX, cellID, Asx )
+                            .value_or( CorrectionResult{1., 0.} ); // module frame dead material X-direction
+  const auto aX = aXCorDer.value;
   //// aY = alphaY(Asy1)
-  double aY = getCorrection( CaloFutureCorrection::alphaY, cellID, Asy ); // module frame dead material Y-direction
+  const auto aYCorDer = getCorrectionAndDerivative( CaloFutureCorrection::alphaY, cellID, Asy )
+                            .value_or( CorrectionResult{1., 0.} ); // module frame dead material Y-direction
+  const auto aY = aYCorDer.value;
   if ( m_correctCovariance ) {
-    DaE = getCorrectionDerivative( CaloFutureCorrection::alphaE, cellID, eEcal );
-    DaB = getCorrectionDerivative( CaloFutureCorrection::alphaB, cellID, bDist );
-    DaX = getCorrectionDerivative( CaloFutureCorrection::alphaX, cellID, Asx );
-    DaY = getCorrectionDerivative( CaloFutureCorrection::alphaY, cellID, Asy );
+    DaE = aECorDer.derivative;
+    DaB = aBCorDer.derivative;
+    DaX = aXCorDer.derivative;
+    DaY = aYCorDer.derivative;
   }
 
   // angular correction
   // assume dtheta to be independent of X,Y,E, although it may still be implicitly a bit dependent on X,Y
-  double gT = getCorrection( CaloFutureCorrection::globalT, cellID, dtheta );     // incidence angle (delta)
-  double dT = getCorrection( CaloFutureCorrection::offsetT, cellID, dtheta, 0. ); // incidence angle (delta)
+  double gT = getCorrection( CaloFutureCorrection::globalT, cellID, dtheta ).value_or( 1. ); // incidence angle (delta)
+  double dT = getCorrection( CaloFutureCorrection::offsetT, cellID, dtheta ).value_or( 0. ); // incidence angle (delta)
 
   // Energy offset
   double sinT   = m_det->cellSine( cellID );
-  double offset = getCorrection( CaloFutureCorrection::offset, cellID, sinT, 0. );
+  double offset = getCorrection( CaloFutureCorrection::offset, cellID, sinT ).value_or( 0. );
 
   // Apply Ecal leakage corrections
   double alpha = aG * aE * aB * aX * aY;
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.cpp
index d2d0043d20e59d4b1dae52b91e0c2af562fa8452..b9c25e0a7b51bde43b25187ed60891b11ecc9eed 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.cpp
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.cpp
@@ -103,13 +103,13 @@ StatusCode CaloFutureLCorrection::process( LHCb::span<LHCb::CaloHypo* const> hyp
 
     // Corrected angle
 
-    double gamma0 = getCorrection( CaloFutureCorrection::gamma0, cellID );
-    double delta0 = getCorrection( CaloFutureCorrection::delta0, cellID );
+    double gamma0 = getCorrection( CaloFutureCorrection::gamma0, cellID ).value_or( 1. );
+    double delta0 = getCorrection( CaloFutureCorrection::delta0, cellID ).value_or( 1. );
 
     // NB: gammaP(ePrs = 0) != 0, deltaP(ePrs = 0) != 0 and depend on cellID.area()
     // get gammaP and deltaP parameters (depending on cellID.area() for each cluster
-    double gammaP = getCorrection( CaloFutureCorrection::gammaP, cellID, 0. );
-    double deltaP = getCorrection( CaloFutureCorrection::deltaP, cellID, 0. );
+    double gammaP = getCorrection( CaloFutureCorrection::gammaP, cellID, 0. ).value_or( 1. );
+    double deltaP = getCorrection( CaloFutureCorrection::deltaP, cellID, 0. ).value_or( 1. );
     double g      = gamma0 - gammaP;
     double d      = delta0 + deltaP;
 
@@ -118,7 +118,7 @@ StatusCode CaloFutureLCorrection::process( LHCb::span<LHCb::CaloHypo* const> hyp
     cos_theta         = temp / std::sqrt( tan_theta * tan_theta + temp * temp );
     const auto dz_fps = cos_theta * tg_fps;
 
-    updateCounters( area, dz_fps, g, d );
+    if ( m_counterFlag.value() ) updateCounters( area, dz_fps, g, d );
 
     // Recompute Z position and fill CaloFuturePosition
     const auto zCor = z0 + dz_fps;
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.h b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.h
index d6ef1c76671cca696ffddbaa0f9dcae510df2621..e7803568ba8e570ade9434525a348fce686d0553 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.h
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureLCorrection.h
@@ -60,6 +60,8 @@ private:
   mutable std::vector<SCounter> m_counterPerCaloFutureAreaGamma;
   mutable std::vector<SCounter> m_counterPerCaloFutureAreaDelta;
 
+  Gaudi::Property<bool> m_counterFlag{this, "EnableCounters", true, "Enable collection of counter-based statistics."};
+
   bool isHypoNotValid( const LHCb::CaloHypo* hypo ) const;
 
   bool isEnergyNegative( const LHCb::CaloHypo* hypo ) const;
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.cpp
index 08607200e5a40148a76ea30d8b4a5ab122fa970e..79a00247bbe50d9ca7033e0cd1e67e566d74b77d 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.cpp
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.cpp
@@ -65,7 +65,7 @@ StatusCode CaloFutureSCorrection::process( LHCb::span<LHCb::CaloHypo* const> hyp
     if ( m_hypos.end() == h ) return Error( "Invalid hypothesis!", StatusCode::SUCCESS );
 
     if ( hypo->e() < 0. ) {
-      ++m_counterSkipNegativeEnergyCorrection;
+      if ( m_counterFlag.value() ) ++m_counterSkipNegativeEnergyCorrection;
       continue;
     }
 
@@ -131,8 +131,10 @@ StatusCode CaloFutureSCorrection::process( LHCb::span<LHCb::CaloHypo* const> hyp
     if ( UNLIKELY( msgLevel( MSG::DEBUG ) ) ) { printDebugInfo( hypo, params, xBar, yBar, xCor, yCor ); }
 
     updatePosition( xCor, yCor, hypo );
-    m_counterDeltaX += xCor - xBar;
-    m_counterDeltaY += yCor - yBar;
+    if ( m_counterFlag.value() ) {
+      m_counterDeltaX += xCor - xBar;
+      m_counterDeltaY += yCor - yBar;
+    }
 
     if ( m_correctCovariance ) { updateCovariance( dXhy_dXcl, dYhy_dYcl, hypo ); }
   }
@@ -210,57 +212,61 @@ CaloFutureSCorrection::calculateSCorrections( const struct SCorrInputParams& par
   double Asx      = -( xBar - seedPos.x() ) / CellSize;
   double Asy      = -( yBar - seedPos.y() ) / CellSize;
 
-  // cache intermediate values
-  const double Asx0 = Asx;
-  const double Asy0 = Asy;
-
   // Sshape correction :
-  Asx = getCorrection( CaloFutureCorrection::shapeX, cellID, Asx, Asx ); // Asx1
-  Asy = getCorrection( CaloFutureCorrection::shapeY, cellID, Asy, Asy ); // Asy1
-
-  // // cache intermediate values: necessary for debugging by calculating numeric derivatives dn_shapeX, dn_shapeY below
-  // const double Asx1 = Asx;
-  // const double Asy1 = Asy;
+  auto AsxCorDer =
+      getCorrectionAndDerivative( CaloFutureCorrection::shapeX, cellID, Asx ).value_or( CorrectionResult{Asx, 1.} );
+  Asx                = AsxCorDer.value; // Asx1
+  const auto DshapeX = AsxCorDer.derivative;
+  auto       AsyCorDer =
+      getCorrectionAndDerivative( CaloFutureCorrection::shapeY, cellID, Asy ).value_or( CorrectionResult{Asy, 1.} );
+  Asy                = AsyCorDer.value; // Asy1
+  const auto DshapeY = AsyCorDer.derivative;
 
   // Angular correction (if any) [ NEW  - inserted between Sshape and residual correction ]
   const double xs  = seedPos.x() - Asx * CellSize; // xscor
   const double ys  = seedPos.y() - Asy * CellSize; // yscor
   const double thx = myatan2( xs, z );
   const double thy = myatan2( ys, z );
-  const double daX = getCorrection( CaloFutureCorrection::angularX, cellID, thx, 0. );
-  const double daY = getCorrection( CaloFutureCorrection::angularY, cellID, thy, 0. );
+  const auto [daX, DangularX] =
+      getCorrectionAndDerivative( CaloFutureCorrection::angularX, cellID, thx ).value_or( CorrectionResult{0., 0.} );
+  const auto [daY, DangularY] =
+      getCorrectionAndDerivative( CaloFutureCorrection::angularY, cellID, thy ).value_or( CorrectionResult{0., 0.} );
   Asx -= daX;
   Asy -= daY;
 
-  // cache intermediate values
-  const double Asx2 = Asx;
-  const double Asy2 = Asy;
-
   // residual correction (if any):
-  bool   residualX_flag = false;
-  double dcX            = getCorrection( CaloFutureCorrection::residual, cellID, Asx, 0. );
+  auto dcXCorDer =
+      getCorrectionAndDerivative( CaloFutureCorrection::residual, cellID, Asx ).value_or( CorrectionResult{0., 0.} );
+  auto dcX = dcXCorDer.value;
   if ( dcX == 0. ) {
-    dcX            = getCorrection( CaloFutureCorrection::residualX, cellID, Asx, 0. ); // check X-specific correction
-    residualX_flag = true;
+    // check X-specific correction
+    dcXCorDer =
+        getCorrectionAndDerivative( CaloFutureCorrection::residualX, cellID, Asx ).value_or( CorrectionResult{0., 0.} );
+    dcX = dcXCorDer.value;
   }
-  bool   residualY_flag = false;
-  double dcY            = getCorrection( CaloFutureCorrection::residual, cellID, Asy, 0. );
+  const auto DresidualX = dcXCorDer.derivative;
+  auto       dcYCorDer =
+      getCorrectionAndDerivative( CaloFutureCorrection::residual, cellID, Asy ).value_or( CorrectionResult{0., 0.} );
+  auto dcY = dcYCorDer.value;
   if ( dcY == 0. ) {
-    dcY            = getCorrection( CaloFutureCorrection::residualY, cellID, Asy, 0. ); // check Y-specific correction
-    residualY_flag = true;
+    // check Y-specific correction
+    dcYCorDer =
+        getCorrectionAndDerivative( CaloFutureCorrection::residualY, cellID, Asy ).value_or( CorrectionResult{0., 0.} );
+    dcY = dcYCorDer.value;
   }
+  const auto DresidualY = dcYCorDer.derivative;
   Asx -= dcX;
   Asy -= dcY;
 
-  // cache intermediate values
-  const double Asx3 = Asx;
-  const double Asy3 = Asy;
-
   // left/right - up/down asymmetries correction (if any) :
-  double ddcX = ( xBar < 0 ) ? getCorrection( CaloFutureCorrection::asymM, cellID, Asx, 0. )
-                             : getCorrection( CaloFutureCorrection::asymP, cellID, Asx, 0. );
-  double ddcY = ( yBar < 0 ) ? getCorrection( CaloFutureCorrection::asymM, cellID, Asy, 0. )
-                             : getCorrection( CaloFutureCorrection::asymP, cellID, Asy, 0. );
+  const auto [ddcX, DasymX] =
+      getCorrectionAndDerivative( ( xBar < 0 ) ? CaloFutureCorrection::asymM : CaloFutureCorrection::asymP, cellID,
+                                  Asx )
+          .value_or( CorrectionResult{0., 0.} );
+  const auto [ddcY, DasymY] =
+      getCorrectionAndDerivative( ( yBar < 0 ) ? CaloFutureCorrection::asymM : CaloFutureCorrection::asymP, cellID,
+                                  Asy )
+          .value_or( CorrectionResult{0., 0.} );
   Asx += ddcX; // Asx4
   Asy += ddcY; // Asy4
 
@@ -297,29 +303,12 @@ CaloFutureSCorrection::calculateSCorrections( const struct SCorrInputParams& par
    */
 
   if ( m_correctCovariance ) {
-
     // calculation of the analytic derivatives:
     // NB: printouts comparing analytic calculations with numeric derivatives which are commented-out below
     // are useful for debugging in case of changes in the correction function code
     if ( UNLIKELY( msgLevel( MSG::DEBUG ) ) )
       debug() << "---------- analytic derivatives of individual S-correction functions ---------------" << endmsg;
 
-    double DshapeX = getCorrectionDerivative( CaloFutureCorrection::shapeX, cellID, Asx0, 1. );
-    double DshapeY = getCorrectionDerivative( CaloFutureCorrection::shapeY, cellID, Asy0, 1. );
-
-    double DangularX = getCorrectionDerivative( CaloFutureCorrection::angularX, cellID, thx, 0. );
-    double DangularY = getCorrectionDerivative( CaloFutureCorrection::angularY, cellID, thy, 0. );
-
-    double DresidualX = getCorrectionDerivative(
-        ( residualX_flag ? CaloFutureCorrection::residualX : CaloFutureCorrection::residual ), cellID, Asx2, 0. );
-    double DresidualY = getCorrectionDerivative(
-        ( residualY_flag ? CaloFutureCorrection::residualY : CaloFutureCorrection::residual ), cellID, Asy2, 0. );
-
-    double DasymX = ( xBar < 0 ) ? getCorrectionDerivative( CaloFutureCorrection::asymM, cellID, Asx3, 0. )
-                                 : getCorrectionDerivative( CaloFutureCorrection::asymP, cellID, Asx3, 0. );
-    double DasymY = ( yBar < 0 ) ? getCorrectionDerivative( CaloFutureCorrection::asymM, cellID, Asy3, 0. )
-                                 : getCorrectionDerivative( CaloFutureCorrection::asymP, cellID, Asy3, 0. );
-
     double tx = xs / z;
     double ty = ys / z;
 
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.h b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.h
index 66c6ff179666a9fb8bd72a673b51d4cb87718600..2cb08e03cfa0efe81d9dad7cd84e8755e6655132 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.h
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureSCorrection.h
@@ -72,6 +72,8 @@ private:
   mutable IncCounter m_counterSkipNegativeEnergyCorrection{this, "Skip negative energy correction"};
   mutable SCounter   m_counterDeltaX{this, "Delta(X)"};
   mutable SCounter   m_counterDeltaY{this, "Delta(Y)"};
+
+  Gaudi::Property<bool> m_counterFlag{this, "EnableCounters", true, "Enable collection of counter-based statistics."};
 };
 // ============================================================================
 #endif // CALOFUTURERECO_CALOFUTURESCORRECTION_H
diff --git a/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.cpp b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.cpp
index 815e255da21cfab229f0023429c715cd54632a74..08bdee56f76bb2e0ca01db380657d11d54a7c98f 100644
--- a/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.cpp
+++ b/CaloFuture/CaloFutureReco/src/CaloFutureShowerOverlapTool.cpp
@@ -81,7 +81,7 @@ namespace LHCb::Calo::Tools {
 
     double showerFraction( const CaloFutureCorrectionBase& shape, const double d3d, const unsigned int area ) {
       CaloCellID cellID( CaloCellCode::CaloIndex::EcalCalo, area, 0, 0 ); // fake cell
-      return std::clamp( shape.getCorrection( CaloFutureCorrection::profile, cellID, d3d, 0. ), 0., 1. );
+      return std::clamp( shape.getCorrection( CaloFutureCorrection::profile, cellID, d3d ).value_or( 0. ), 0., 1. );
     }
 
     double fraction( const CaloFutureCorrectionBase& shape, const DeCalorimeter& det, const CaloCluster& cluster,