Repository: pybamm-team/PyBaMM

Issue:
Parameter fitting with simulation class
Trying to do parameter fitting directly with the simulation class doesn't work. It looks like the inputs don't get updated.

Discussion:

Patch:
diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py
index 5a6b992fd..5c782ec34 100644
--- a/pybamm/parameters/parameter_values.py
+++ b/pybamm/parameters/parameter_values.py
@@ -487,9 +487,12 @@ class ParameterValues:
                 # Scalar inherits name (for updating parameters) and domain (for
                 # Broadcast)
                 return pybamm.Scalar(value, name=symbol.name, domain=symbol.domain)
-            elif isinstance(value, pybamm.InputParameter):
-                value.domain = symbol.domain
-                return value
+            elif isinstance(value, pybamm.Symbol):
+                new_value = self.process_symbol(value)
+                new_value.domain = symbol.domain
+                return new_value
+            else:
+                raise TypeError("Cannot process parameter '{}'".format(value))
 
         elif isinstance(symbol, pybamm.FunctionParameter):
             new_children = [self.process_symbol(child) for child in symbol.children]
diff --git a/pybamm/simulation.py b/pybamm/simulation.py
index 9b9f58a08..7d7374ab5 100644
--- a/pybamm/simulation.py
+++ b/pybamm/simulation.py
@@ -422,6 +422,9 @@ class Simulation:
                 pybamm.logger.warning(
                     "Ignoring t_eval as solution times are specified by the experiment"
                 )
+            # Re-initialize solution, e.g. for solving multiple times with different
+            # inputs without having to build the simulation again
+            self._solution = None
             # Step through all experimental conditions
             inputs = inputs or {}
             pybamm.logger.info("Start running experiment")


Test patch:
diff --git a/tests/unit/test_experiments/test_simulation_with_experiment.py b/tests/unit/test_experiments/test_simulation_with_experiment.py
index 511b4c354..1569969a3 100644
--- a/tests/unit/test_experiments/test_simulation_with_experiment.py
+++ b/tests/unit/test_experiments/test_simulation_with_experiment.py
@@ -2,6 +2,7 @@
 # Test setting up a simulation with an experiment
 #
 import pybamm
+import numpy as np
 import unittest
 
 
@@ -93,6 +94,27 @@ class TestSimulationExperiment(unittest.TestCase):
         pybamm.set_logging_level("WARNING")
         self.assertIn("event", sim._solution.termination)
 
+    def test_inputs(self):
+        experiment = pybamm.Experiment(
+            ["Discharge at C/2 for 1 hour", "Rest for 1 hour"]
+        )
+        model = pybamm.lithium_ion.SPM()
+
+        # Change a parameter to an input
+        param = pybamm.ParameterValues(chemistry=pybamm.parameter_sets.Marquis2019)
+        param["Negative electrode diffusivity [m2.s-1]"] = (
+            pybamm.InputParameter("Dsn") * 3.9e-14
+        )
+
+        # Solve a first time
+        sim = pybamm.Simulation(model, experiment=experiment, parameter_values=param)
+        sim.solve(inputs={"Dsn": 1})
+        np.testing.assert_array_equal(sim.solution.inputs["Dsn"], 1)
+
+        # Solve again, input should change
+        sim.solve(inputs={"Dsn": 2})
+        np.testing.assert_array_equal(sim.solution.inputs["Dsn"], 2)
+
 
 if __name__ == "__main__":
     print("Add -v for more debug output")
diff --git a/tests/unit/test_parameters/test_parameter_values.py b/tests/unit/test_parameters/test_parameter_values.py
index aa35fdecb..5c82a57ed 100644
--- a/tests/unit/test_parameters/test_parameter_values.py
+++ b/tests/unit/test_parameters/test_parameter_values.py
@@ -235,8 +235,25 @@ class TestParameterValues(unittest.TestCase):
             x = pybamm.Parameter("x")
             parameter_values.process_symbol(x)
 
+    def test_process_parameter_in_parameter(self):
+        parameter_values = pybamm.ParameterValues(
+            {"a": 2, "2a": pybamm.Parameter("a") * 2, "b": np.array([1, 2, 3])}
+        )
+
+        # process 2a parameter
+        a = pybamm.Parameter("2a")
+        processed_a = parameter_values.process_symbol(a)
+        self.assertEqual(processed_a.evaluate(), 4)
+
+        # case where parameter can't be processed
+        b = pybamm.Parameter("b")
+        with self.assertRaisesRegex(TypeError, "Cannot process parameter"):
+            parameter_values.process_symbol(b)
+
     def test_process_input_parameter(self):
-        parameter_values = pybamm.ParameterValues({"a": "[input]", "b": 3})
+        parameter_values = pybamm.ParameterValues(
+            {"a": "[input]", "b": 3, "c times 2": pybamm.InputParameter("c") * 2}
+        )
         # process input parameter
         a = pybamm.Parameter("a")
         processed_a = parameter_values.process_symbol(a)
@@ -252,6 +269,11 @@ class TestParameterValues(unittest.TestCase):
         self.assertIsInstance(processed_add.children[1], pybamm.Scalar)
         self.assertEqual(processed_add.evaluate(inputs={"a": 4}), 7)
 
+        # process complex input parameter
+        c = pybamm.Parameter("c times 2")
+        processed_c = parameter_values.process_symbol(c)
+        self.assertEqual(processed_c.evaluate(inputs={"c": 5}), 10)
+
     def test_process_function_parameter(self):
         parameter_values = pybamm.ParameterValues(
             {