diff --git a/examples/scripts/compare_comsol/compare_comsol_DFN.py b/examples/scripts/compare_comsol/compare_comsol_DFN.py index 07081efae9..817f34665a 100644 --- a/examples/scripts/compare_comsol/compare_comsol_DFN.py +++ b/examples/scripts/compare_comsol/compare_comsol_DFN.py @@ -57,7 +57,7 @@ # Make Comsol 'model' for comparison whole_cell = ["negative electrode", "separator", "positive electrode"] comsol_t = comsol_variables["time"] -L_x = param.process_symbol(pybamm.standard_parameters_lithium_ion.L_x).evaluate() +L_x = param.evaluate(pybamm.standard_parameters_lithium_ion.L_x) def get_interp_fun(variable, domain): diff --git a/pybamm/models/submodels/current_collector/effective_resistance_current_collector.py b/pybamm/models/submodels/current_collector/effective_resistance_current_collector.py index 0d3b0a643b..793adeff00 100644 --- a/pybamm/models/submodels/current_collector/effective_resistance_current_collector.py +++ b/pybamm/models/submodels/current_collector/effective_resistance_current_collector.py @@ -123,15 +123,15 @@ def get_processed_potentials(self, solution, mesh, param_values, V_av, I_av): """ # Get required processed parameters param = self.param - l_cn = param_values.process_symbol(param.l_cn).evaluate() - l_cp = param_values.process_symbol(param.l_cp).evaluate() - l_y = param_values.process_symbol(param.l_y).evaluate() - l_z = param_values.process_symbol(param.l_z).evaluate() - sigma_cn_prime = param_values.process_symbol(param.sigma_cn_prime).evaluate() - sigma_cp_prime = param_values.process_symbol(param.sigma_cp_prime).evaluate() - alpha = param_values.process_symbol(param.alpha).evaluate() - pot_scale = param_values.process_symbol(param.potential_scale).evaluate() - U_ref = param_values.process_symbol(param.U_p_ref - param.U_n_ref).evaluate() + l_cn = param_values.evaluate(param.l_cn) + l_cp = param_values.evaluate(param.l_cp) + l_y = param_values.evaluate(param.l_y) + l_z = param_values.evaluate(param.l_z) + sigma_cn_prime = param_values.evaluate(param.sigma_cn_prime) + sigma_cp_prime = param_values.evaluate(param.sigma_cp_prime) + alpha = param_values.evaluate(param.alpha) + pot_scale = param_values.evaluate(param.potential_scale) + U_ref = param_values.evaluate(param.U_p_ref - param.U_n_ref) # Process psi and W, and their (average) values at the negative tab psi = pybamm.ProcessedVariable( diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py index 05f4b883ef..5aff085d3e 100644 --- a/pybamm/parameters/parameter_values.py +++ b/pybamm/parameters/parameter_values.py @@ -502,3 +502,23 @@ def update_scalars(self, symbol): x.function.interpolate() return symbol + + def evaluate(self, symbol): + """ + Process and evaluate a symbol. + + Parameters + ---------- + symbol : :class:`pybamm.Symbol` + Symbol or Expression tree to evaluate + + Returns + ------- + number of array + The evaluated symbol + """ + processed_symbol = self.process_symbol(symbol) + if processed_symbol.is_constant() and processed_symbol.evaluates_to_number(): + return processed_symbol.evaluate() + else: + raise ValueError("symbol must evaluate to a constant scalar") diff --git a/results/2plus1D/compare_lithium_ion_2plus1D.py b/results/2plus1D/compare_lithium_ion_2plus1D.py index fb7c51b316..cce573d2d0 100644 --- a/results/2plus1D/compare_lithium_ion_2plus1D.py +++ b/results/2plus1D/compare_lithium_ion_2plus1D.py @@ -79,8 +79,8 @@ plt.ylabel("Terminal voltage [V]") plt.legend() # add C-rate, delta, and alpha to title -delta = param.process_symbol(pybamm.standard_parameters_lithium_ion.delta).evaluate() -alpha = param.process_symbol(pybamm.standard_parameters_lithium_ion.alpha).evaluate() +delta = param.evaluate(pybamm.standard_parameters_lithium_ion.delta) +alpha = param.evaluate(pybamm.standard_parameters_lithium_ion.alpha) plt.title( r"C-rate = {:3d}, $\alpha$ = {:.6f} , $\delta$ = {:.6f}".format( C_rate, alpha, delta diff --git a/results/2plus1D/compare_spmecc.py b/results/2plus1D/compare_spmecc.py index 68dec71546..2f4cd2f136 100644 --- a/results/2plus1D/compare_spmecc.py +++ b/results/2plus1D/compare_spmecc.py @@ -63,9 +63,7 @@ # add current collector Ohmic losses to average SPMEe to get SPMeCC voltage if model.name == "Average SPMe": current = pybamm.ProcessedVariable(model.variables["Current [A]"], t, y)(t) - delta = param.process_symbol( - pybamm.standard_parameters_lithium_ion.delta - ).evaluate() + delta = param.evaluate(pybamm.standard_parameters_lithium_ion.delta) R_cc = param.process_symbol( cc_model.variables["Effective current collector resistance [Ohm]"] ).evaluate( diff --git a/results/2plus1D/spm_2plus1D_tab_grid.py b/results/2plus1D/spm_2plus1D_tab_grid.py index b4211bb401..88fa3e5ddc 100644 --- a/results/2plus1D/spm_2plus1D_tab_grid.py +++ b/results/2plus1D/spm_2plus1D_tab_grid.py @@ -22,7 +22,7 @@ # adjust current to correspond to a typical current density of 24 [A.m-2] C_rate = 1 param["Typical current [A]"] = ( - C_rate * 24 * param.process_symbol(pybamm.geometric_parameters.A_cc).evaluate() + C_rate * 24 * param.evaluate(pybamm.geometric_parameters.A_cc) ) param.process_model(model) param.process_geometry(geometry) @@ -39,9 +39,7 @@ var.z: 5, } submesh_types = model.default_submesh_types -submesh_types[ - "current collector" -] = pybamm.ScikitExponential2DSubMesh +submesh_types["current collector"] = pybamm.ScikitExponential2DSubMesh # depnding on number of points in y-z plane may need to increase recursion depth... sys.setrecursionlimit(10000) mesh = pybamm.Mesh(geometry, submesh_types, var_pts) diff --git a/results/2plus1D/spmecc.py b/results/2plus1D/spmecc.py index 26776b15c9..89360c571d 100644 --- a/results/2plus1D/spmecc.py +++ b/results/2plus1D/spmecc.py @@ -41,7 +41,7 @@ time = pybamm.ProcessedVariable(cell_model.variables["Time [h]"], t, y)(t) voltage = pybamm.ProcessedVariable(cell_model.variables["Terminal voltage [V]"], t, y) current = pybamm.ProcessedVariable(cell_model.variables["Current [A]"], t, y)(t) -delta = param.process_symbol(pybamm.standard_parameters_lithium_ion.delta).evaluate() +delta = param.evaluate(pybamm.standard_parameters_lithium_ion.delta) R_cc = param.process_symbol( cc_model.variables["Effective current collector resistance [Ohm]"] ).evaluate(t=cc_solution.t, y=cc_solution.y)[0][0] diff --git a/results/2plus1D/user_mesh_spm_1plus1D.py b/results/2plus1D/user_mesh_spm_1plus1D.py index 811ee2f98e..a639500260 100644 --- a/results/2plus1D/user_mesh_spm_1plus1D.py +++ b/results/2plus1D/user_mesh_spm_1plus1D.py @@ -19,7 +19,7 @@ # load parameter values and process model and geometry param = model.default_parameter_values C_rate = 1 -current_1C = 24 * param.process_symbol(pybamm.geometric_parameters.A_cc).evaluate() +current_1C = 24 * param.evaluate(pybamm.geometric_parameters.A_cc) param.update( { "Typical current [A]": C_rate * current_1C, diff --git a/tests/integration/test_models/standard_output_tests.py b/tests/integration/test_models/standard_output_tests.py index 5c100105f5..b019737fc8 100644 --- a/tests/integration/test_models/standard_output_tests.py +++ b/tests/integration/test_models/standard_output_tests.py @@ -90,8 +90,8 @@ def __init__(self, model, param, disc, solution, operating_condition): self.r_p_edge = disc.mesh["positive particle"][0].edges # Useful parameters - self.l_n = param.process_symbol(pybamm.geometric_parameters.l_n).evaluate() - self.l_p = param.process_symbol(pybamm.geometric_parameters.l_p).evaluate() + self.l_n = param.evaluate(pybamm.geometric_parameters.l_n) + self.l_p = param.evaluate(pybamm.geometric_parameters.l_p) if isinstance(self.model, pybamm.lithium_ion.BaseModel): current_param = pybamm.standard_parameters_lithium_ion.current_with_time @@ -635,9 +635,9 @@ def test_velocity_vs_current(self): t, x_n, x_p = self.t, self.x_n, self.x_p beta_n = pybamm.standard_parameters_lead_acid.beta_n - beta_n = self.param.process_symbol(beta_n).evaluate() + beta_n = self.param.evaluate(beta_n) beta_p = pybamm.standard_parameters_lead_acid.beta_p - beta_p = self.param.process_symbol(beta_p).evaluate() + beta_p = self.param.evaluate(beta_p) np.testing.assert_array_almost_equal( self.v_box(t, x_n), beta_n * self.i_e(t, x_n) diff --git a/tests/unit/test_parameters/test_dimensionless_parameter_values_lithium_ion.py b/tests/unit/test_parameters/test_dimensionless_parameter_values_lithium_ion.py index 555da6a437..73ad08911d 100644 --- a/tests/unit/test_parameters/test_dimensionless_parameter_values_lithium_ion.py +++ b/tests/unit/test_parameters/test_dimensionless_parameter_values_lithium_ion.py @@ -21,122 +21,82 @@ def test_lithium_ion(self): "particle geometry" # a_n dimensional np.testing.assert_almost_equal( - values.process_symbol(param.a_n_dim).evaluate(None, None), - 0.18 * 10 ** (6), - 2, + values.evaluate(param.a_n_dim), 0.18 * 10 ** (6), 2 ) # R_n dimensional - np.testing.assert_almost_equal( - values.process_symbol(param.R_n).evaluate(None, None), 1 * 10 ** (-5), 2 - ) + np.testing.assert_almost_equal(values.evaluate(param.R_n), 1 * 10 ** (-5), 2) # a_n - np.testing.assert_almost_equal( - values.process_symbol(param.a_n).evaluate(None, None), 1.8, 2 - ) + np.testing.assert_almost_equal(values.evaluate(param.a_n), 1.8, 2) # a_p dimensional np.testing.assert_almost_equal( - values.process_symbol(param.a_p_dim).evaluate(None, None), - 0.15 * 10 ** (6), - 2, + values.evaluate(param.a_p_dim), 0.15 * 10 ** (6), 2 ) # R_p dimensional - np.testing.assert_almost_equal( - values.process_symbol(param.R_n).evaluate(None, None), 1 * 10 ** (-5), 2 - ) + np.testing.assert_almost_equal(values.evaluate(param.R_n), 1 * 10 ** (-5), 2) # a_p - np.testing.assert_almost_equal( - values.process_symbol(param.a_p).evaluate(None, None), 1.5, 2 - ) + np.testing.assert_almost_equal(values.evaluate(param.a_p), 1.5, 2) "reaction rates" # m_n* np.testing.assert_almost_equal( - values.process_symbol(param.m_n_dimensional(param.T_ref)).evaluate( - None, None - ), - 2 * 10 ** (-5), - 8, + values.evaluate(param.m_n_dimensional(param.T_ref)), 2 * 10 ** (-5), 8 ) np.testing.assert_almost_equal( - values.process_symbol(1 / param.C_r_n * c_rate).evaluate(None, None), - 26.6639, - 3, + values.evaluate(1 / param.C_r_n * c_rate), 26.6639, 3 ) # m_p* np.testing.assert_almost_equal( - values.process_symbol(param.m_p_dimensional(param.T_ref)).evaluate( - None, None - ), - 6 * 10 ** (-7), - 8, + values.evaluate(param.m_p_dimensional(param.T_ref)), 6 * 10 ** (-7), 8 ) # gamma_p / C_r_p np.testing.assert_almost_equal( - values.process_symbol(param.gamma_p / param.C_r_p * c_rate).evaluate( - None, None - ), - 1.366, - 3, + values.evaluate(param.gamma_p / param.C_r_p * c_rate), 1.366, 3 ) "particle dynamics" # neg diffusion coefficient np.testing.assert_almost_equal( - values.process_symbol( - param.D_n_dimensional(param.c_n_init, param.T_ref) - ).evaluate(None, None), + values.evaluate(param.D_n_dimensional(param.c_n_init, param.T_ref)), 3.9 * 10 ** (-14), 2, ) # neg diffusion timescale np.testing.assert_almost_equal( - values.process_symbol(param.tau_diffusion_n).evaluate(None, None), - 2.5641 * 10 ** (3), - 2, + values.evaluate(param.tau_diffusion_n), 2.5641 * 10 ** (3), 2 ) # tau_n / tau_d (1/gamma_n in Scott's transfer) - np.testing.assert_almost_equal( - values.process_symbol(param.C_n / c_rate).evaluate(None, None), 0.11346, 3 - ) + np.testing.assert_almost_equal(values.evaluate(param.C_n / c_rate), 0.11346, 3) # pos diffusion coefficient np.testing.assert_almost_equal( - values.process_symbol( - param.D_p_dimensional(param.c_p_init, param.T_ref) - ).evaluate(None, None), + values.evaluate(param.D_p_dimensional(param.c_p_init, param.T_ref)), 1 * 10 ** (-13), 2, ) # pos diffusion timescale np.testing.assert_almost_equal( - values.process_symbol(param.tau_diffusion_p).evaluate(None, None), - 1 * 10 ** (3), - 2, + values.evaluate(param.tau_diffusion_p), 1 * 10 ** (3), 2 ) # tau_p / tau_d (1/gamma_p in Scott's transfer) - np.testing.assert_almost_equal( - values.process_symbol(param.C_p / c_rate).evaluate(None, None), 0.044249, 3 - ) + np.testing.assert_almost_equal(values.evaluate(param.C_p / c_rate), 0.044249, 3) "electrolyte dynamics" # typical diffusion coefficient (we should change the typ value in paper to # match this one. We take this parameter excluding the exp(-0.65) in the # paper at the moment np.testing.assert_almost_equal( - values.process_symbol( - param.D_e_dimensional(param.c_e_typ, param.T_ref) - ).evaluate(None, None), + values.evaluate(param.D_e_dimensional(param.c_e_typ, param.T_ref)), 5.34 * 10 ** (-10) * np.exp(-0.65), 10, ) @@ -144,21 +104,15 @@ def test_lithium_ion(self): # electrolyte diffusion timescale (accounting for np.exp(-0.65) in # diffusion_typ). Change value in paper to this. np.testing.assert_almost_equal( - values.process_symbol(param.tau_diffusion_e).evaluate(None, None), - 181.599, - 3, + values.evaluate(param.tau_diffusion_e), 181.599, 3 ) # C_e - np.testing.assert_almost_equal( - values.process_symbol(param.C_e / c_rate).evaluate(None, None), 0.008, 3 - ) + np.testing.assert_almost_equal(values.evaluate(param.C_e / c_rate), 0.008, 3) # electrolyte conductivity np.testing.assert_almost_equal( - values.process_symbol( - param.kappa_e_dimensional(param.c_e_typ, param.T_ref) - ).evaluate(None, None), + values.evaluate(param.kappa_e_dimensional(param.c_e_typ, param.T_ref)), 1.1045, 3, ) @@ -167,32 +121,26 @@ def test_lithium_ion(self): # F R / T (should be equal to old 1 / Lambda) old_Lambda = 38 np.testing.assert_almost_equal( - values.process_symbol(param.potential_scale).evaluate(None, None), - 1 / old_Lambda, - 3, + values.evaluate(param.potential_scale), 1 / old_Lambda, 3 ) "electrode conductivities" # neg dimensional - np.testing.assert_almost_equal( - values.process_symbol(param.sigma_n_dim).evaluate(None, None), 100, 3 - ) + np.testing.assert_almost_equal(values.evaluate(param.sigma_n_dim), 100, 3) # neg dimensionless (old sigma_n / old_Lambda ) (this is different to values # in paper so check again, it is close enough though for now) np.testing.assert_almost_equal( - values.process_symbol(param.sigma_n * c_rate).evaluate(None, None), 475.7, 1 + values.evaluate(param.sigma_n * c_rate), 475.7, 1 ) # neg dimensional - np.testing.assert_almost_equal( - values.process_symbol(param.sigma_p_dim).evaluate(None, None), 10, 3 - ) + np.testing.assert_almost_equal(values.evaluate(param.sigma_p_dim), 10, 3) # neg dimensionless (old sigma_n / old_Lambda ) (this is different to values in # paper so check again, it is close enough for now though) np.testing.assert_almost_equal( - values.process_symbol(param.sigma_p * c_rate).evaluate(None, None), 47.57, 1 + values.evaluate(param.sigma_p * c_rate), 47.57, 1 ) def test_thermal_parameters(self): @@ -201,72 +149,48 @@ def test_thermal_parameters(self): c_rate = param.i_typ / 24 # Density - np.testing.assert_almost_equal( - values.process_symbol(param.rho_cn).evaluate(), 1.9019, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.rho_n).evaluate(), 0.6403, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.rho_s).evaluate(), 0.1535, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.rho_p).evaluate(), 1.2605, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.rho_cp).evaluate(), 1.3403, 2 - ) + np.testing.assert_almost_equal(values.evaluate(param.rho_cn), 1.9019, 2) + np.testing.assert_almost_equal(values.evaluate(param.rho_n), 0.6403, 2) + np.testing.assert_almost_equal(values.evaluate(param.rho_s), 0.1535, 2) + np.testing.assert_almost_equal(values.evaluate(param.rho_p), 1.2605, 2) + np.testing.assert_almost_equal(values.evaluate(param.rho_cp), 1.3403, 2) # Thermal conductivity - np.testing.assert_almost_equal( - values.process_symbol(param.lambda_cn).evaluate(), 6.7513, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.lambda_n).evaluate(), 0.0296, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.lambda_s).evaluate(), 0.0027, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.lambda_p).evaluate(), 0.0354, 2 - ) - np.testing.assert_almost_equal( - values.process_symbol(param.lambda_cp).evaluate(), 3.9901, 2 - ) + np.testing.assert_almost_equal(values.evaluate(param.lambda_cn), 6.7513, 2) + np.testing.assert_almost_equal(values.evaluate(param.lambda_n), 0.0296, 2) + np.testing.assert_almost_equal(values.evaluate(param.lambda_s), 0.0027, 2) + np.testing.assert_almost_equal(values.evaluate(param.lambda_p), 0.0354, 2) + np.testing.assert_almost_equal(values.evaluate(param.lambda_cp), 3.9901, 2) # other thermal parameters # note: in paper this is 0.0534 * c_rate which conflicts with this # if we do C_th * c_rate we get 0.0534 so probably error in paper # np.testing.assert_almost_equal( - # values.process_symbol(param.C_th / c_rate).evaluate(), 0.0253, 2 + # values.evaluate(param.C_th / c_rate), 0.0253, 2 # ) - np.testing.assert_almost_equal( - values.process_symbol(param.Theta / c_rate).evaluate(), 0.008, 2 - ) + np.testing.assert_almost_equal(values.evaluate(param.Theta / c_rate), 0.008, 2) - np.testing.assert_almost_equal( - values.process_symbol(param.h).evaluate(), 3.7881 * 10 ** (-5), 7 - ) + np.testing.assert_almost_equal(values.evaluate(param.h), 3.7881 * 10 ** (-5), 7) # np.testing.assert_almost_equal( - # values.process_symbol(param.B / c_rate).evaluate(), 36.216, 2 + # values.evaluate(param.B / c_rate), 36.216, 2 # ) - np.testing.assert_equal(values.process_symbol(param.T_init).evaluate(), 0) + np.testing.assert_equal(values.evaluate(param.T_init), 0) # test timescale # np.testing.assert_almost_equal( - # values.process_symbol(param.tau_th_yz).evaluate(), 1.4762 * 10 ** (3), 2 + # values.evaluate(param.tau_th_yz), 1.4762 * 10 ** (3), 2 # ) # thermal = pybamm.thermal_parameters # np.testing.assert_almost_equal( - # values.process_symbol(thermal.rho_eff_dim).evaluate(), 1.8116 * 10 ** (6), 2 + # values.evaluate(thermal.rho_eff_dim), 1.8116 * 10 ** (6), 2 # ) # np.testing.assert_almost_equal( - # values.process_symbol(thermal.lambda_eff_dim).evaluate(), 59.3964, 2 + # values.evaluate(thermal.lambda_eff_dim), 59.3964, 2 # ) def test_parameter_functions(self): @@ -276,17 +200,17 @@ def test_parameter_functions(self): c_test = pybamm.Scalar(0.5) T_test = pybamm.Scalar(0) - values.process_symbol(param.U_n(c_test, T_test)).evaluate() - values.process_symbol(param.U_p(c_test, T_test)).evaluate() - values.process_symbol(param.dUdT_n(c_test)).evaluate() - values.process_symbol(param.dUdT_p(c_test)).evaluate() + values.evaluate(param.U_n(c_test, T_test)) + values.evaluate(param.U_p(c_test, T_test)) + values.evaluate(param.dUdT_n(c_test)) + values.evaluate(param.dUdT_p(c_test)) - values.process_symbol(param.D_p(c_test, T_test)).evaluate() - values.process_symbol(param.D_n(c_test, T_test)).evaluate() + values.evaluate(param.D_p(c_test, T_test)) + values.evaluate(param.D_n(c_test, T_test)) c_e_test = pybamm.Scalar(1) - values.process_symbol(param.D_e(c_e_test, T_test)).evaluate() - values.process_symbol(param.kappa_e(c_e_test, T_test)).evaluate() + values.evaluate(param.D_e(c_e_test, T_test)) + values.evaluate(param.kappa_e(c_e_test, T_test)) if __name__ == "__main__": diff --git a/tests/unit/test_parameters/test_parameter_values.py b/tests/unit/test_parameters/test_parameter_values.py index db92388f93..fca7caf834 100644 --- a/tests/unit/test_parameters/test_parameter_values.py +++ b/tests/unit/test_parameters/test_parameter_values.py @@ -451,6 +451,21 @@ def test_process_empty_model(self): ): parameter_values.process_model(model) + def test_evaluate(self): + parameter_values = pybamm.ParameterValues({"a": 1, "b": 2, "c": 3}) + a = pybamm.Parameter("a") + b = pybamm.Parameter("b") + c = pybamm.Parameter("c") + self.assertEqual(parameter_values.evaluate(a), 1) + self.assertEqual(parameter_values.evaluate(a + (b * c)), 7) + + y = pybamm.StateVector(slice(0, 1)) + with self.assertRaises(ValueError): + parameter_values.evaluate(y) + array = pybamm.Array(np.array([1, 2, 3])) + with self.assertRaises(ValueError): + parameter_values.evaluate(array) + if __name__ == "__main__": print("Add -v for more debug output")