SENSITIVITY
Overview
The SENSITIVITY function evaluates how a scalar model output responds to changes in its parameters by wrapping CasADi ’s automatic differentiation. For a model with variables and parameters , the sensitivity row vector contains the partial derivatives evaluated at a selected point. This example function is provided as-is without any representation of accuracy.
Usage
In Excel, the function is entered as:
=SENSITIVITY(model, variables, parameters, [variable_names], [parameter_names])model(string, required): Expression defining the model output. CasADi symbols such asca.expare supported.variables(2D list of float, required): Single row of variable values where the sensitivity is evaluated.parameters(2D list of float, required): Single row of parameter values that define the evaluation point.variable_names(2D list of string, optional): Names of the variables in order; defaults tox1,x2, … if omitted.parameter_names(2D list of string, optional): Names of the parameters in order; defaults toa1,a2, … if omitted.
The function returns a 2D list containing one row of partial derivatives with respect to each parameter, or an error message string when validation fails.
Examples
Example 1: Logistic Growth
Inputs:
| model | variables | parameters | variable_names | parameter_names | ||||
|---|---|---|---|---|---|---|---|---|
| K/(1+ca.exp(-r*(t - t0))) | 5 | 100 | 0.1 | 10 | t | K | r | t0 |
Excel formula:
=SENSITIVITY("K/(1+ca.exp(-r*(t - t0)))", {5}, {100,0.1,10}, {"t"}, {"K","r","t0"})Expected output:
| Result | ||
|---|---|---|
| 0.378 | -117.502 | -2.350 |
Example 2: Polynomial with Cross Term
Inputs:
| model | variables | parameters | |
|---|---|---|---|
| x**2 + axy | 1.5 | 2 | 0.8 |
Excel formula:
=SENSITIVITY("x**2 + a*x*y", {1.5,2}, {0.8})Expected output:
| Result |
|---|
| 3.000 |
Example 3: Damped Oscillator Snapshot
Inputs:
| model | variables | parameters | variable_names | parameter_names | ||
|---|---|---|---|---|---|---|
| ca.exp(-z*t)ca.sin(wt) | 0.5 | 0.2 | 4 | t | z | w |
Excel formula:
=SENSITIVITY("ca.exp(-z*t)*ca.sin(w*t)", {0.5}, {0.2,4}, {"t"}, {"z","w"})Expected output:
| Result | |
|---|---|
| -0.345 | 0.416 |
Example 4: Saturation Model
Inputs:
| model | variables | parameters | variable_names | parameter_names | ||
|---|---|---|---|---|---|---|
| (ax)/(1 + bx) | 2 | 3 | 1.5 | x | a | b |
Excel formula:
=SENSITIVITY("(a*x)/(1 + b*x)", {2}, {3,1.5}, {"x"}, {"a","b"})Expected output:
| Result | |
|---|---|
| 0.421 | -1.265 |
Python Code
import casadi as ca
def sensitivity(model, variables, parameters, variable_names=None, parameter_names=None):
"""Compute the sensitivity of a scalar model with respect to its parameters using CasADi.
Wraps CasADi automatic differentiation to return the row vector of partial derivatives
of a scalar expression f(x, a) with respect to parameters `a` evaluated at the provided
point.
Args:
model: String expression representing the model output. The expression may use
CasADi functions via the `ca` namespace (for example `ca.exp`, `ca.sin`).
variables: 2D list or scalar containing the evaluation point for each independent variable.
parameters: 2D list or scalar containing the parameter values at which the sensitivity is evaluated.
variable_names: Optional 2D list of strings specifying the variable names in order.
parameter_names: Optional 2D list of strings specifying the parameter names in order.
Returns:
A 2D list containing a single row of partial derivatives (floats) with respect to each parameter,
or an error message string if validation fails or CasADi encounters an error.
Notes:
This function exposes a minimal wrapper around CasADi. See https://web.casadi.org/ for
CasADi documentation. This example function is provided as-is without any representation of accuracy.
"""
# Helper to normalize values that may be passed as scalars by Excel for single-cell ranges.
def to2d(x):
return [[x]] if not isinstance(x, list) else x
if not isinstance(model, str) or model.strip() == "":
return "Invalid input: model must be a non-empty string."
# Normalize inputs that may be passed as scalars.
variables = to2d(variables)
parameters = to2d(parameters)
try:
variable_values = [float(v) for v in variables[0]]
except Exception:
return "Invalid input: variables must contain numeric values."
try:
parameter_values = [float(p) for p in parameters[0]]
except Exception:
return "Invalid input: parameters must contain numeric values."
if len(variable_values) == 0:
return "Invalid input: variables must include at least one value."
if len(parameter_values) == 0:
return "Invalid input: parameters must include at least one value."
# Validate and normalize names
if variable_names is not None:
variable_names = to2d(variable_names)
variable_names_list = variable_names[0]
if len(variable_names_list) != len(variable_values):
return "Invalid input: number of variable names must match number of variable values."
if not all(isinstance(n, str) and n.strip() for n in variable_names_list):
return "Invalid input: variable_names must contain non-empty strings."
else:
variable_names_list = [f"x{i+1}" for i in range(len(variable_values))]
if parameter_names is not None:
parameter_names = to2d(parameter_names)
parameter_names_list = parameter_names[0]
if len(parameter_names_list) != len(parameter_values):
return "Invalid input: number of parameter names must match number of parameter values."
if not all(isinstance(n, str) and n.strip() for n in parameter_names_list):
return "Invalid input: parameter_names must contain non-empty strings."
else:
parameter_names_list = [f"a{i+1}" for i in range(len(parameter_values))]
# Create CasADi symbols
variable_symbols = [ca.MX.sym(n) for n in variable_names_list]
parameter_symbols = [ca.MX.sym(n) for n in parameter_names_list]
# Build evaluation context for eval() so user can reference variable and parameter names
evaluation_context = {name: variable_symbols[idx] for idx, name in enumerate(variable_names_list)}
evaluation_context.update({name: parameter_symbols[idx] for idx, name in enumerate(parameter_names_list)})
evaluation_context["ca"] = ca
try:
expression = eval(model, evaluation_context)
except Exception as exc:
return f"Invalid model expression: {exc}"
try:
jac = ca.jacobian(expression, ca.vertcat(*parameter_symbols))
sensitivity_fn = ca.Function("sensitivity_fn", variable_symbols + parameter_symbols, [jac])
casadi_result = sensitivity_fn(*(variable_values + parameter_values))
except Exception as exc:
return f"Error during CasADi calculation: {exc}"
# casadi_result is typically a DM; return as nested Python lists
try:
if isinstance(casadi_result, ca.DM):
return casadi_result.full().tolist()
# Some CasADi versions return a list/tuple with one element
if isinstance(casadi_result, (list, tuple)) and len(casadi_result) == 1 and isinstance(casadi_result[0], ca.DM):
return casadi_result[0].full().tolist()
except Exception:
return "Error during CasADi calculation: Unexpected result type."
return "Error during CasADi calculation: Unexpected result type."