Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions pybop/analysis/sensitivity_analysis.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from typing import TYPE_CHECKING

import numpy as np
from SALib.analyze import sobol
from SALib.sample.sobol import sample

if TYPE_CHECKING:
from pybop.problems.problem import Problem


def sensitivity_analysis(
def get_sobol_sensitivities(
problem: "Problem", n_samples: int = 256, calc_second_order: bool = False
) -> dict:
"""
Expand Down Expand Up @@ -36,9 +37,13 @@ def sensitivity_analysis(
Sensitivities : dict
"""

bounds_array = problem.parameters.get_bounds_array()
if not np.isfinite(bounds_array).all():
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not np.isfinite(bounds_array).all():
if np.any(~np.isfinite(bounds_array)):

nit: minor optimisation where we short-circuit as soon as it hits the first True

raise ValueError("SOBOL analysis requires finite bounds.")

salib_dict = {
"names": problem.parameters.names,
"bounds": problem.parameters.get_bounds_array(),
"bounds": bounds_array,
"num_vars": len(problem.parameters),
}

Expand Down
6 changes: 3 additions & 3 deletions pybop/problems/problem.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np

from pybop.analysis.sensitivity_analysis import sensitivity_analysis
from pybop.analysis.sensitivity_analysis import get_sobol_sensitivities
from pybop.costs.base_cost import BaseCost
from pybop.costs.evaluation import Evaluation
from pybop.parameters.parameter import Inputs, Parameters
Expand Down Expand Up @@ -260,7 +260,7 @@ def get_finite_initial_cost(self):
raise ValueError("The initial parameter values return an infinite cost.")
return cost0

def sensitivity_analysis(
def get_sobol_sensitivities(
self, n_samples: int = 256, calc_second_order: bool = False
) -> dict:
"""
Expand All @@ -275,7 +275,7 @@ def sensitivity_analysis(
calc_second_order : bool, optional
Whether to calculate second-order sensitivities.
"""
return sensitivity_analysis(
return get_sobol_sensitivities(
problem=self, n_samples=n_samples, calc_second_order=calc_second_order
)

Expand Down
20 changes: 9 additions & 11 deletions tests/unit/test_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,10 @@ def model(self):
def parameters(self):
return {
"Negative particle radius [m]": pybop.Parameter(
distribution=pybop.Gaussian(
2e-05,
0.1e-5,
truncated_at=[1e-6, 5e-5],
)
distribution=pybop.Gaussian(2e-05, 0.1e-5, truncated_at=[1e-6, 5e-5])
),
"Positive particle radius [m]": pybop.Parameter(
distribution=pybop.Gaussian(
0.5e-05,
0.1e-5,
truncated_at=[1e-6, 5e-5],
)
distribution=pybop.Gaussian(0.5e-05, 0.1e-5, truncated_at=[1e-6, 5e-5])
),
}

Expand Down Expand Up @@ -239,7 +231,7 @@ def test_parameter_sensitivities(self, simulator, dataset):
cost = pybop.MeanAbsoluteError(dataset)
problem = pybop.Problem(simulator, cost)
n_params = len(problem.parameters)
result = problem.sensitivity_analysis(4, calc_second_order=True)
result = problem.get_sobol_sensitivities(4, calc_second_order=True)

# Assertions
assert isinstance(result, dict)
Expand All @@ -253,3 +245,9 @@ def test_parameter_sensitivities(self, simulator, dataset):
assert isinstance(result["S2_conf"], np.ndarray)
assert result["S1"].shape == (n_params,)
assert result["ST"].shape == (n_params,)

problem.parameters["Negative particle radius [m]"] = pybop.Parameter(
distribution=pybop.Gaussian(2e-05, 0.1e-5) # unbounded
)
with pytest.raises(ValueError, match="SOBOL analysis requires finite bounds."):
problem.get_sobol_sensitivities(4, calc_second_order=True)
Loading