Repository: pybamm-team/PyBaMM

Issue:
Move initial soc out of solve
### Description

It would be nice if it was in its own method, which was then called by either solve or build.

### Motivation

Necessary to get initial soc for Julia solvers

### Possible Implementation

just move it to its own method, then call that method in build/solve

### Additional context

_No response_

Discussion:

Patch:
diff --git a/pybamm/simulation.py b/pybamm/simulation.py
index 25123bb6a..612fb07a9 100644
--- a/pybamm/simulation.py
+++ b/pybamm/simulation.py
@@ -466,7 +466,47 @@ class Simulation:
             self._parameter_values.process_geometry(self._geometry)
         self.model = self._model_with_set_params
 
-    def build(self, check_model=True):
+    def set_initial_soc(self, initial_soc):
+        if self._built_initial_soc != initial_soc:
+            # reset
+            self._model_with_set_params = None
+            self._built_model = None
+            self.op_conds_to_built_models = None
+
+        c_n_init = self.parameter_values[
+            "Initial concentration in negative electrode [mol.m-3]"
+        ]
+        c_p_init = self.parameter_values[
+            "Initial concentration in positive electrode [mol.m-3]"
+        ]
+        param = pybamm.LithiumIonParameters()
+        c_n_max = self.parameter_values.evaluate(param.n.prim.c_max)
+        c_p_max = self.parameter_values.evaluate(param.p.prim.c_max)
+        x, y = pybamm.lithium_ion.get_initial_stoichiometries(
+            initial_soc, self.parameter_values
+        )
+        self.parameter_values.update(
+            {
+                "Initial concentration in negative electrode [mol.m-3]": x * c_n_max,
+                "Initial concentration in positive electrode [mol.m-3]": y * c_p_max,
+            }
+        )
+        # For experiments also update the following
+        if hasattr(self, "op_conds_to_model_and_param"):
+            for key, (model, param) in self.op_conds_to_model_and_param.items():
+                param.update(
+                    {
+                        "Initial concentration in negative electrode [mol.m-3]": x
+                        * c_n_max,
+                        "Initial concentration in positive electrode [mol.m-3]": y
+                        * c_p_max,
+                    }
+                )
+        # Save solved initial SOC in case we need to re-build the model
+        self._built_initial_soc = initial_soc
+        return c_n_init, c_p_init
+
+    def build(self, check_model=True, initial_soc=None):
         """
         A method to build the model into a system of matrices and vectors suitable for
         performing numerical computations. If the model has already been built or
@@ -479,7 +519,13 @@ class Simulation:
         check_model : bool, optional
             If True, model checks are performed after discretisation (see
             :meth:`pybamm.Discretisation.process_model`). Default is True.
+        initial_soc : float, optional
+            Initial State of Charge (SOC) for the simulation. Must be between 0 and 1.
+            If given, overwrites the initial concentrations provided in the parameter
+            set.
         """
+        if initial_soc is not None:
+            self.set_initial_soc(initial_soc)
 
         if self.built_model:
             return
@@ -596,45 +642,7 @@ class Simulation:
         logs = {}
 
         if initial_soc is not None:
-            if self._built_initial_soc != initial_soc:
-                # reset
-                self._model_with_set_params = None
-                self._built_model = None
-                self.op_conds_to_built_models = None
-
-            c_n_init = self.parameter_values[
-                "Initial concentration in negative electrode [mol.m-3]"
-            ]
-            c_p_init = self.parameter_values[
-                "Initial concentration in positive electrode [mol.m-3]"
-            ]
-            param = pybamm.LithiumIonParameters()
-            c_n_max = self.parameter_values.evaluate(param.n.prim.c_max)
-            c_p_max = self.parameter_values.evaluate(param.p.prim.c_max)
-            x, y = pybamm.lithium_ion.get_initial_stoichiometries(
-                initial_soc, self.parameter_values
-            )
-            self.parameter_values.update(
-                {
-                    "Initial concentration in negative electrode [mol.m-3]": x
-                    * c_n_max,
-                    "Initial concentration in positive electrode [mol.m-3]": y
-                    * c_p_max,
-                }
-            )
-            # For experiments also update the following
-            if hasattr(self, "op_conds_to_model_and_param"):
-                for key, (model, param) in self.op_conds_to_model_and_param.items():
-                    param.update(
-                        {
-                            "Initial concentration in negative electrode [mol.m-3]": x
-                            * c_n_max,
-                            "Initial concentration in positive electrode [mol.m-3]": y
-                            * c_p_max,
-                        }
-                    )
-            # Save solved initial SOC in case we need to re-build the model
-            self._built_initial_soc = initial_soc
+            c_n_init, c_p_init = self.set_initial_soc(initial_soc)
 
         if self.operating_mode in ["without experiment", "drive cycle"]:
             self.build(check_model=check_model)


Test patch:
diff --git a/tests/unit/test_simulation.py b/tests/unit/test_simulation.py
index 83f373c8b..bf501ae91 100644
--- a/tests/unit/test_simulation.py
+++ b/tests/unit/test_simulation.py
@@ -244,6 +244,10 @@ class TestSimulation(unittest.TestCase):
         sim.solve(initial_soc=0.8)
         self.assertEqual(sim._built_initial_soc, 0.8)
 
+        sim = pybamm.Simulation(model, parameter_values=param)
+        sim.build(initial_soc=0.8)
+        self.assertEqual(sim._built_initial_soc, 0.8)
+
     def test_solve_with_inputs(self):
         model = pybamm.lithium_ion.SPM()
         param = model.default_parameter_values