Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include PyBaMM solution in OptimizationResult #573

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
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
8 changes: 7 additions & 1 deletion pybop/optimisers/base_optimiser.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ class OptimisationResult:
Number of iterations performed by the optimiser.
scipy_result : scipy.optimize.OptimizeResult, optional
The result obtained from a SciPy optimiser.
pybamm_solution: pybamm.Solution or list[pybamm.Solution], optional
The final solution object(s) obtained from the optimisation.
"""

def __init__(
Expand All @@ -313,6 +315,7 @@ def __init__(
optim: Optional[BaseOptimiser] = None,
time: Optional[float] = None,
scipy_result=None,
pybamm_solution=None,
):
self.x = x
self.cost = cost
Expand All @@ -328,6 +331,8 @@ def __init__(
else:
self.x0 = None

self.pybamm_solution = pybamm_solution

# Check that the parameters produce finite cost, and are physically viable
self._validate_parameters()
self.check_physical_viability(self.x)
Expand Down Expand Up @@ -403,5 +408,6 @@ def __str__(self) -> str:
f" Final cost: {self.final_cost}\n"
f" Optimisation time: {self.time} seconds\n"
f" Number of iterations: {self.n_iterations}\n"
f" SciPy result available: {'Yes' if self.scipy_result else 'No'}"
f" SciPy result available: {'Yes' if self.scipy_result else 'No'}\n"
f" PyBaMM Solution available: {'Yes' if self.pybamm_solution else 'No'}"
)
1 change: 1 addition & 0 deletions pybop/optimisers/base_pints_optimiser.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ def fun(x):
n_iterations=self._iterations,
optim=self,
time=total_time,
pybamm_solution=self.cost.problem.solution,
)

def f_guessed_tracking(self):
Expand Down
9 changes: 6 additions & 3 deletions pybop/optimisers/scipy_optimisers.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,18 @@ def _run(self):
nit = -1

return OptimisationResult(
x=self._transformation.to_model(result.x)
if self._transformation
else result.x,
x=(
self._transformation.to_model(result.x)
if self._transformation
else result.x
),
cost=self.cost,
final_cost=self.cost(result.x, apply_transform=True),
n_iterations=nit,
scipy_result=result,
optim=self,
time=total_time,
pybamm_solution=self.cost.problem.solution,
)


Expand Down
7 changes: 7 additions & 0 deletions pybop/problems/base_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ def __init__(
output_variables=self.output_vars,
)

# to store pybamm solution objects
self._solution = None

def set_initial_state(self, initial_state: Optional[dict] = None):
"""
Set the initial state to be applied to evaluations of the problem.
Expand Down Expand Up @@ -195,3 +198,7 @@ def domain_data(self, domain_data):
@property
def dataset(self):
return self._dataset

@property
def solution(self):
return self._solution
2 changes: 2 additions & 0 deletions pybop/problems/design_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ def evaluate(self, inputs: Inputs):
for signal in [*self.signal, *self.additional_variables]
}

self._solution = sol

return {
signal: sol[signal].data
for signal in self.signal + self.additional_variables
Expand Down
1 change: 1 addition & 0 deletions pybop/problems/fitting_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def evaluate(self, inputs: Inputs) -> dict[str, np.ndarray[np.float64]]:
print(f"Simulation error: {e}")
return {signal: self.failure_output for signal in self.signal}

self._solution = sol
return {
signal: sol[signal].data
for signal in (self.signal + self.additional_variables)
Expand Down
3 changes: 3 additions & 0 deletions pybop/problems/multi_fitting_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,17 @@ def evaluate(self, inputs: Inputs):
self.parameters.update(values=list(inputs.values()))

combined_signal = []
combined_solutions = []

for problem in self.problems:
problem_inputs = problem.parameters.as_dict()
signal_values = problem.evaluate(problem_inputs)
combined_solutions.append(problem.solution)

# Collect signals
for signal in problem.signal:
combined_signal.extend(signal_values[signal])
self._solution = combined_solutions

return {"Combined signal": np.asarray(combined_signal)}

Expand Down
6 changes: 4 additions & 2 deletions tests/unit/test_optimisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,8 @@ def test_halting(self, cost):
f" Final cost: {results.final_cost}\n"
f" Optimisation time: {results.time} seconds\n"
f" Number of iterations: {results.n_iterations}\n"
f" SciPy result available: No"
f" SciPy result available: No\n"
f" PyBaMM Solution available: No"
)

# Test guessed values
Expand Down Expand Up @@ -550,7 +551,8 @@ def test_halting(self, cost):
f" Final cost: {results.final_cost}\n"
f" Optimisation time: {results.time} seconds\n"
f" Number of iterations: {results.n_iterations}\n"
f" SciPy result available: No"
f" SciPy result available: No\n"
f" PyBaMM Solution available: Yes"
)

optim.set_max_unchanged_iterations()
Expand Down
Loading