def test_model_solver_dae_inputs_in_initial_conditions(self): # Create model model = pybamm.BaseModel() var1 = pybamm.Variable("var1") var2 = pybamm.Variable("var2") model.rhs = {var1: pybamm.InputParameter("rate") * var1} model.algebraic = {var2: var1 - var2} model.initial_conditions = { var1: pybamm.InputParameter("ic 1"), var2: pybamm.InputParameter("ic 2"), } # Solve solver = pybamm.ScikitsDaeSolver(rtol=1e-8, atol=1e-8) t_eval = np.linspace(0, 5, 100) solution = solver.solve(model, t_eval, inputs={ "rate": -1, "ic 1": 0.1, "ic 2": 2 }) np.testing.assert_array_almost_equal(solution.y[0], 0.1 * np.exp(-solution.t), decimal=5) np.testing.assert_array_almost_equal(solution.y[-1], 0.1 * np.exp(-solution.t), decimal=5) # Solve again with different initial conditions solution = solver.solve(model, t_eval, inputs={ "rate": -0.1, "ic 1": 1, "ic 2": 3 }) np.testing.assert_array_almost_equal(solution.y[0], 1 * np.exp(-0.1 * solution.t), decimal=5) np.testing.assert_array_almost_equal(solution.y[-1], 1 * np.exp(-0.1 * solution.t), decimal=5)
def test_diff_c_e_lead_acid(self): # With intercalation param = pybamm.standard_parameters_lead_acid model_n = pybamm.interface.ButlerVolmer(param, "Negative", "lead-acid main") model_p = pybamm.interface.ButlerVolmer(param, "Positive", "lead-acid main") parameter_values = pybamm.lead_acid.BaseModel( ).default_parameter_values def j_n(c_e): variables = { **self.variables, "Negative electrode surface potential difference": 1, "Negative electrolyte concentration": c_e, } return model_n.get_coupled_variables(variables)[ "Negative electrode interfacial current density"].orphans[0] def j_p(c_e): variables = { **self.variables, "Positive electrode surface potential difference": 1, "Positive electrolyte concentration": c_e, } return model_p.get_coupled_variables(variables)[ "Positive electrode interfacial current density"].orphans[0] c_e = pybamm.InputParameter("c_e") h = pybamm.Scalar(0.00001) # Analytical j_n_diff = parameter_values.process_symbol(j_n(c_e).diff(c_e)) j_p_diff = parameter_values.process_symbol(j_p(c_e).diff(c_e)) # Numerical j_n_FD = parameter_values.process_symbol( (j_n(c_e + h) - j_n(c_e - h)) / (2 * h)) self.assertAlmostEqual( j_n_diff.evaluate(inputs={"c_e": 0.5}), j_n_FD.evaluate(inputs={"c_e": 0.5}), places=5, ) j_p_FD = parameter_values.process_symbol( (j_p(c_e + h) - j_p(c_e - h)) / (2 * h)) self.assertAlmostEqual( j_p_diff.evaluate(inputs={"c_e": 0.5}), j_p_FD.evaluate(inputs={"c_e": 0.5}), places=5, )
def __init__(self, working_electrode, name="Electrode-specific SOH model"): self.working_electrode = working_electrode pybamm.citations.register("Mohtat2019") super().__init__(name) param = pybamm.LithiumIonParameters( {"working electrode": working_electrode}) x_100 = pybamm.Variable("x_100", bounds=(0, 1)) C = pybamm.Variable("C", bounds=(0, np.inf)) Cw = pybamm.InputParameter("C_w") T_ref = param.T_ref if working_electrode == "negative": # pragma: no cover raise NotImplementedError elif working_electrode == "positive": Uw = param.U_p_dimensional x_0 = x_100 + C / Cw V_max = pybamm.InputParameter("V_max") V_min = pybamm.InputParameter("V_min") self.algebraic = { x_100: Uw(x_100, T_ref) - V_max, C: Uw(x_0, T_ref) - V_min, } # initial guess must be chosen such that 0 < x_0, x_100 < 1 # First guess for x_100 x_100_init = 0.85 # Make sure x_0 = x_100 - C/C_w > 0 C_init = param.Q C_init = pybamm.minimum(Cw * x_100_init - 0.1, C_init) self.initial_conditions = {x_100: x_100_init, C: C_init} self.variables = { "x_100": x_100, "C": C, "x_0": x_0, "Uw(x_100)": Uw(x_100, T_ref), "Uw(x_0)": Uw(x_0, T_ref), "C_w": Cw, "C_w * (x_100 - x_0)": Cw * (x_100 - x_0), }
def test_generate_casadi(self): model = pybamm.BaseModel() t = pybamm.t a = pybamm.Variable("a") b = pybamm.Variable("b") p = pybamm.InputParameter("p") q = pybamm.InputParameter("q") model.rhs = {a: -a * p} model.algebraic = {b: a - b} model.initial_conditions = {a: q, b: 1} model.variables = {"a+b": a + b - t} # Generate C code model.generate("test.c", ["a+b"]) # Compile subprocess.run(["gcc", "-fPIC", "-shared", "-o", "test.so", "test.c"]) # nosec # Read the generated functions x0_fn = casadi.external("x0", "./test.so") z0_fn = casadi.external("z0", "./test.so") rhs_fn = casadi.external("rhs_", "./test.so") alg_fn = casadi.external("alg_", "./test.so") jac_rhs_fn = casadi.external("jac_rhs", "./test.so") jac_alg_fn = casadi.external("jac_alg", "./test.so") var_fn = casadi.external("variables", "./test.so") # Test that function values are as expected self.assertEqual(x0_fn([0, 5]), 5) self.assertEqual(z0_fn([0, 0]), 1) self.assertEqual(rhs_fn(0, 3, 2, [7, 2]), -21) self.assertEqual(alg_fn(0, 3, 2, [7, 2]), 1) np.testing.assert_array_equal(np.array(jac_rhs_fn(5, 6, 7, [8, 9])), [[-8, 0]]) np.testing.assert_array_equal(np.array(jac_alg_fn(5, 6, 7, [8, 9])), [[1, -1]]) self.assertEqual(var_fn(6, 3, 2, [7, 2]), -1) # Remove generated files. os.remove("test.c") os.remove("test.so")
def test_block_symbolic_inputs(self): solver = pybamm.BaseSolver(rtol=1e-2, atol=1e-4) model = pybamm.BaseModel() a = pybamm.Scalar(0) p = pybamm.InputParameter("p") model.rhs = {a: a * p} with self.assertRaisesRegex( pybamm.SolverError, "Only CasadiSolver and CasadiAlgebraicSolver can have symbolic inputs", ): solver.solve(model, np.array([1, 2, 3]))
def test_tanh(self): a = pybamm.InputParameter("a") fun = pybamm.tanh(a) self.assertEqual(fun.evaluate(inputs={"a": 3}), np.tanh(3)) h = 0.0000001 self.assertAlmostEqual( fun.diff(a).evaluate(inputs={"a": 3}), (pybamm.tanh(pybamm.Scalar(3 + h)).evaluate() - fun.evaluate(inputs={"a": 3})) / h, places=5, )
def test_timescale_input_fail(self): # Make sure timescale can't depend on inputs model = pybamm.BaseModel() v = pybamm.Variable("v") model.rhs = {v: -1} model.initial_conditions = {v: 1} a = pybamm.InputParameter("a") model.timescale = a solver = pybamm.BaseSolver() with self.assertRaisesRegex(pybamm.SolverError, "The model timescale"): solver.set_up(model, inputs={"a": 10})
def test_unary_operator(self): a = pybamm.Symbol("a", domain=["test"]) un = pybamm.UnaryOperator("unary test", a) self.assertEqual(un.children[0].name, a.name) self.assertEqual(un.domain, a.domain) # with number a = pybamm.InputParameter("a") absval = pybamm.AbsoluteValue(-a) self.assertEqual(absval.evaluate(inputs={"a": 10}), 10) self.assertEqual(absval.evaluate(inputs={"a": 10}, known_evals={})[0], 10)
def test_model_solver_dae_inputs_events(self): # Create model for form in ["python", "casadi"]: model = pybamm.BaseModel() model.convert_to_format = form whole_cell = [ "negative electrode", "separator", "positive electrode" ] var1 = pybamm.Variable("var1", domain=whole_cell) var2 = pybamm.Variable("var2", domain=whole_cell) model.rhs = {var1: pybamm.InputParameter("rate 1") * var1} model.algebraic = { var2: pybamm.InputParameter("rate 2") * var1 - var2 } model.initial_conditions = {var1: 1, var2: 2} model.events = [ pybamm.Event("var1 = 1.5", pybamm.min(var1 - 1.5)), pybamm.Event("var2 = 2.5", pybamm.min(var2 - 2.5)), ] disc = get_discretisation_for_testing() disc.process_model(model) # Solve if form == "python": solver = pybamm.ScikitsDaeSolver(rtol=1e-8, atol=1e-8, root_method="lm") else: solver = pybamm.ScikitsDaeSolver(rtol=1e-8, atol=1e-8) t_eval = np.linspace(0, 5, 100) solution = solver.solve(model, t_eval, inputs={ "rate 1": 0.1, "rate 2": 2 }) np.testing.assert_array_less(solution.y[0], 1.5) np.testing.assert_array_less(solution.y[-1], 2.5) np.testing.assert_allclose(solution.y[0], np.exp(0.1 * solution.t)) np.testing.assert_allclose(solution.y[-1], 2 * np.exp(0.1 * solution.t))
def test_symbol_new_copy(self): a = pybamm.Parameter("a") b = pybamm.Parameter("b") v_n = pybamm.Variable("v", "negative electrode") x_n = pybamm.standard_spatial_vars.x_n v_s = pybamm.Variable("v", "separator") vec = pybamm.Vector([1, 2, 3, 4, 5]) mat = pybamm.Matrix([[1, 2], [3, 4]]) mesh = get_mesh_for_testing() for symbol in [ a + b, a - b, a * b, a / b, a**b, -a, abs(a), pybamm.Function(np.sin, a), pybamm.FunctionParameter("function", {"a": a}), pybamm.grad(v_n), pybamm.div(pybamm.grad(v_n)), pybamm.upwind(v_n), pybamm.IndefiniteIntegral(v_n, x_n), pybamm.BackwardIndefiniteIntegral(v_n, x_n), pybamm.BoundaryValue(v_n, "right"), pybamm.BoundaryGradient(v_n, "right"), pybamm.PrimaryBroadcast(a, "domain"), pybamm.SecondaryBroadcast(v_n, "current collector"), pybamm.FullBroadcast(a, "domain", {"secondary": "other domain"}), pybamm.concatenation(v_n, v_s), pybamm.NumpyConcatenation(a, b, v_s), pybamm.DomainConcatenation([v_n, v_s], mesh), pybamm.Parameter("param"), pybamm.InputParameter("param"), pybamm.StateVector(slice(0, 56)), pybamm.Matrix(np.ones((50, 40))), pybamm.SpatialVariable("x", ["negative electrode"]), pybamm.t, pybamm.Index(vec, 1), pybamm.NotConstant(a), pybamm.ExternalVariable( "external variable", 20, domain="test", auxiliary_domains={"secondary": "test2"}, ), pybamm.minimum(a, b), pybamm.maximum(a, b), pybamm.SparseStack(mat, mat), ]: self.assertEqual(symbol.id, symbol.new_copy().id)
def set_events(self, variables): # add current and voltage events to the model # current events both negative and positive to catch specification n_cells = self.param.n_cells self.events.extend([ pybamm.Event( "Current cut-off (positive) [A] [experiment]", variables["Current [A]"] - abs(pybamm.InputParameter("Current cut-off [A]")), ), pybamm.Event( "Current cut-off (negative) [A] [experiment]", variables["Current [A]"] + abs(pybamm.InputParameter("Current cut-off [A]")), ), pybamm.Event( "Voltage cut-off [V] [experiment]", variables["Terminal voltage [V]"] - pybamm.InputParameter("Voltage cut-off [V]") / n_cells, ), ])
def test_sqrt(self): a = pybamm.InputParameter("a") fun = pybamm.sqrt(a) self.assertIsInstance(fun, pybamm.Sqrt) self.assertEqual(fun.evaluate(inputs={"a": 3}), np.sqrt(3)) h = 0.0000001 self.assertAlmostEqual( fun.diff(a).evaluate(inputs={"a": 3}), (pybamm.sqrt(pybamm.Scalar(3 + h)).evaluate() - fun.evaluate(inputs={"a": 3})) / h, places=5, )
def test_processed_variable_0D_some_inputs(self): # with some symbolic inputs and some non-symbolic inputs y = pybamm.StateVector(slice(0, 1)) p = pybamm.InputParameter("p") q = pybamm.InputParameter("q") var = p * y - q var.mesh = None t_sol = np.linspace(0, 1) y_sol = np.array([np.linspace(0, 5)]) solution = pybamm.Solution(t_sol, y_sol) solution.inputs = {"p": casadi.MX.sym("p"), "q": 2} processed_var = pybamm.ProcessedSymbolicVariable(var, solution) np.testing.assert_array_equal( processed_var.value({ "p": 3 }).full(), 3 * y_sol - 2) np.testing.assert_array_equal( processed_var.sensitivity({ "p": 3 }).full(), y_sol.T)
def test_set_expected_size(self): a = pybamm.InputParameter("a") a.set_expected_size(10) self.assertEqual(a._expected_size, 10) y = np.linspace(0, 1, 10) np.testing.assert_array_equal(a.evaluate(inputs={"a": y}), y) with self.assertRaisesRegex( ValueError, "Input parameter 'a' was given an object of size '1' but was expecting an " "object of size '10'", ): a.evaluate(inputs={"a": 5})
def test_processed_variable_0D_with_inputs(self): # with symbolic inputs y = pybamm.StateVector(slice(0, 1)) p = pybamm.InputParameter("p") q = pybamm.InputParameter("q") var = p * y + q var.mesh = None t_sol = np.linspace(0, 1) y_sol = np.array([np.linspace(0, 5)]) solution = pybamm.Solution(t_sol, y_sol) solution.inputs = {"p": casadi.MX.sym("p"), "q": casadi.MX.sym("q")} processed_var = pybamm.ProcessedSymbolicVariable(var, solution) np.testing.assert_array_equal( processed_var.value({ "p": 3, "q": 4 }).full(), 3 * y_sol + 4) np.testing.assert_array_equal( processed_var.sensitivity({ "p": 3, "q": 4 }).full(), np.c_[y_sol.T, np.ones_like(y_sol).T], ) # via value_and_sensitivity val, sens = processed_var.value_and_sensitivity({"p": 3, "q": 4}) np.testing.assert_array_equal(val.full(), 3 * y_sol + 4) np.testing.assert_array_equal(sens.full(), np.c_[y_sol.T, np.ones_like(y_sol).T]) # Test bad inputs with self.assertRaisesRegex(TypeError, "inputs should be 'dict'"): processed_var.value(1) with self.assertRaisesRegex(ValueError, "Inconsistent input keys"): processed_var.value({"not p": 3}) with self.assertRaisesRegex(ValueError, "Inconsistent input keys"): processed_var.value({"q": 3, "p": 2})
def test_read_input_parameters(self): # Read input parameters from different parts of the model model = pybamm.BaseModel() a = pybamm.InputParameter("a") b = pybamm.InputParameter("b") c = pybamm.InputParameter("c") d = pybamm.InputParameter("d") e = pybamm.InputParameter("e") f = pybamm.InputParameter("f") u = pybamm.Variable("u") v = pybamm.Variable("v") model.rhs = {u: -u * a} model.algebraic = {v: v - b} model.initial_conditions = {u: c, v: d} model.events = [pybamm.Event("u=e", u - e)] model.variables = {"v+f": v + f} self.assertEqual( set([x.name for x in model.input_parameters]), set([x.name for x in [a, b, c, d, e, f]]), ) self.assertTrue( all( isinstance(x, pybamm.InputParameter) for x in model.input_parameters))
def test_erfc(self): a = pybamm.InputParameter("a") fun = pybamm.erfc(a) self.assertAlmostEqual(fun.evaluate(inputs={"a": 3}), special.erfc(3), places=15) h = 0.0000001 self.assertAlmostEqual( fun.diff(a).evaluate(inputs={"a": 3}), (pybamm.erfc(pybamm.Scalar(3 + h)).evaluate() - fun.evaluate(inputs={"a": 3})) / h, places=5, )
def test_sinh(self): a = pybamm.InputParameter("a") fun = pybamm.sinh(a) self.assertIsInstance(fun, pybamm.Sinh) self.assertEqual(fun.children[0].id, a.id) self.assertEqual(fun.evaluate(inputs={"a": 3}), np.sinh(3)) h = 0.0000001 self.assertAlmostEqual( fun.diff(a).evaluate(inputs={"a": 3}), (pybamm.sinh(pybamm.Scalar(3 + h)).evaluate() - fun.evaluate(inputs={"a": 3})) / h, places=5, )
def test_solve_with_input(self): # Simple system: a single algebraic equation var = pybamm.Variable("var") model = pybamm.BaseModel() model.algebraic = {var: var + pybamm.InputParameter("value")} model.initial_conditions = {var: 2} # create discretisation disc = pybamm.Discretisation() disc.process_model(model) # Solve solver = pybamm.AlgebraicSolver() solution = solver.solve(model, np.linspace(0, 1, 10), inputs={"value": 7}) np.testing.assert_array_equal(solution.y, -7)
def test_model_solver_multiple_inputs_initial_conditions_error(self): # Create model model = pybamm.BaseModel() model.convert_to_format = "casadi" domain = ["negative electrode", "separator", "positive electrode"] var = pybamm.Variable("var", domain=domain) model.rhs = {var: -pybamm.InputParameter("rate") * var} model.initial_conditions = {var: 2 * pybamm.InputParameter("rate")} # create discretisation mesh = get_mesh_for_testing() spatial_methods = {"macroscale": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) disc.process_model(model) solver = pybamm.ScipySolver(rtol=1e-8, atol=1e-8, method="RK45") t_eval = np.linspace(0, 10, 100) ninputs = 8 inputs_list = [{"rate": 0.01 * (i + 1)} for i in range(ninputs)] with self.assertRaisesRegex( pybamm.SolverError, ("Input parameters cannot appear in expression " "for initial conditions."), ): solver.solve(model, t_eval, inputs=inputs_list, nproc=2)
def constant_current_constant_voltage_constant_power(variables): I = variables["Current [A]"] V = variables["Terminal voltage [V]"] s_I = pybamm.InputParameter("Current switch") s_V = pybamm.InputParameter("Voltage switch") s_P = pybamm.InputParameter("Power switch") n_cells = pybamm.electrical_parameters.n_cells return (s_I * (I - pybamm.InputParameter("Current input [A]")) + s_V * (V - pybamm.InputParameter("Voltage input [V]") / n_cells) + s_P * (V * I - pybamm.InputParameter("Power input [W]") / n_cells))
def test_process_inline_function_parameters(self): def D(c): return c**2 parameter_values = pybamm.ParameterValues({"Diffusivity": D}) a = pybamm.InputParameter("a") func = pybamm.FunctionParameter("Diffusivity", {"a": a}) processed_func = parameter_values.process_symbol(func) self.assertEqual(processed_func.evaluate(inputs={"a": 3}), 9) # process differentiated function parameter diff_func = func.diff(a) processed_diff_func = parameter_values.process_symbol(diff_func) self.assertEqual(processed_diff_func.evaluate(inputs={"a": 3}), 6)
def constant_current_constant_voltage_constant_power(variables): I = variables["Current [A]"] V = variables["Terminal voltage [V]"] s_I = pybamm.InputParameter("Current switch") s_V = pybamm.InputParameter("Voltage switch") s_P = pybamm.InputParameter("Power switch") n_cells = pybamm.Parameter( "Number of cells connected in series to make a battery") return (s_I * (I - pybamm.InputParameter("Current input [A]")) + s_V * (V - pybamm.InputParameter("Voltage input [V]") / n_cells) + s_P * (V * I - pybamm.InputParameter("Power input [W]") / n_cells))
def test_solver_sensitivities(self): # Create model model = pybamm.BaseModel() model.convert_to_format = "jax" domain = ["negative electrode", "separator", "positive electrode"] var = pybamm.Variable("var", domain=domain) model.rhs = {var: -pybamm.InputParameter("rate") * var} model.initial_conditions = {var: 1} # create discretisation mesh = get_mesh_for_testing(xpts=10) spatial_methods = {"macroscale": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) disc.process_model(model) # Solve t_eval = np.linspace(0, 10, 4) y0 = model.concatenated_initial_conditions.evaluate().reshape(-1) rhs = pybamm.EvaluatorJax(model.concatenated_rhs) def fun(y, t, inputs): return rhs.evaluate(t=t, y=y, inputs=inputs).reshape(-1) h = 0.0001 rate = 0.1 # create a dummy "model" where we calculate the sum of the time series @jax.jit def solve_bdf(rate): return jax.numpy.sum( pybamm.jax_bdf_integrate(fun, y0, t_eval, {'rate': rate}, rtol=1e-9, atol=1e-9)) # check answers with finite difference eval_plus = solve_bdf(rate + h) eval_neg = solve_bdf(rate - h) grad_num = (eval_plus - eval_neg) / (2 * h) grad_solve_bdf = jax.jit(jax.grad(solve_bdf)) grad_bdf = grad_solve_bdf(rate) self.assertAlmostEqual(grad_bdf, grad_num, places=3)
def test_cos(self): a = pybamm.InputParameter("a") fun = pybamm.cos(a) self.assertIsInstance(fun, pybamm.Cos) self.assertEqual(fun.children[0].id, a.id) self.assertEqual(fun.evaluate(inputs={"a": 3}), np.cos(3)) h = 0.0000001 self.assertAlmostEqual( fun.diff(a).evaluate(inputs={"a": 3}), (pybamm.cos(pybamm.Scalar(3 + h)).evaluate() - fun.evaluate(inputs={"a": 3})) / h, places=5, ) # test simplify y = pybamm.StateVector(slice(0, 1)) fun = pybamm.cos(y) self.assertEqual(fun.id, fun.simplify().id)
def test_get_solve(self): # Create model model = pybamm.BaseModel() model.convert_to_format = "jax" domain = ["negative electrode", "separator", "positive electrode"] var = pybamm.Variable("var", domain=domain) model.rhs = {var: -pybamm.InputParameter("rate") * var} model.initial_conditions = {var: 1} # No need to set parameters; can use base discretisation (no spatial # operators) # create discretisation mesh = get_mesh_for_testing() spatial_methods = {"macroscale": pybamm.FiniteVolume()} disc = pybamm.Discretisation(mesh, spatial_methods) disc.process_model(model) # test that another method string gives error with self.assertRaises(ValueError): solver = pybamm.JaxSolver(method="not_real") # Solve solver = pybamm.JaxSolver(rtol=1e-8, atol=1e-8) t_eval = np.linspace(0, 5, 80) with self.assertRaisesRegex(RuntimeError, "Model is not set up for solving"): solver.get_solve(model, t_eval) solver.solve(model, t_eval, inputs={"rate": 0.1}) solver = solver.get_solve(model, t_eval) y = solver({"rate": 0.1}) np.testing.assert_allclose(y[0], np.exp(-0.1 * t_eval), rtol=1e-6, atol=1e-6) y = solver({"rate": 0.2}) np.testing.assert_allclose(y[0], np.exp(-0.2 * t_eval), rtol=1e-6, atol=1e-6)
def test_solve_with_symbolic_input_1D_vector_input(self): var = pybamm.Variable("var", "negative electrode") model = pybamm.BaseModel() param = pybamm.InputParameter("param", "negative electrode") model.rhs = {var: -param * var} model.initial_conditions = {var: 2} model.variables = {"var": var} # create discretisation disc = get_discretisation_for_testing() disc.process_model(model) # Solve - scalar input solver = pybamm.CasadiSolver() solution = solver.solve(model, np.linspace(0, 1)) n = disc.mesh["negative electrode"].npts solver = pybamm.CasadiSolver() t_eval = np.linspace(0, 1) solution = solver.solve(model, t_eval) p = np.linspace(0, 1, n)[:, np.newaxis] np.testing.assert_array_almost_equal( solution["var"].value({"param": 3 * np.ones(n)}), np.repeat(2 * np.exp(-3 * t_eval), 40)[:, np.newaxis], decimal=4, ) np.testing.assert_array_almost_equal( solution["var"].value({"param": 2 * p}), 2 * np.exp(-2 * p * t_eval).T.reshape(-1, 1), decimal=4, ) np.testing.assert_array_almost_equal( solution["var"].sensitivity({"param": 3 * np.ones(n)}), np.kron(-2 * t_eval * np.exp(-3 * t_eval), np.eye(40)).T, decimal=4, ) sens = solution["var"].sensitivity({"param": p}).full() for idx, t in enumerate(t_eval): np.testing.assert_array_almost_equal( sens[40 * idx:40 * (idx + 1), :], -2 * t * np.exp(-p * t) * np.eye(40), decimal=4, )
def __init__(self, e_class): self.dim_dict=e_class.dim_dict self.nd_dict=e_class.nd_param.nd_param_dict self.model=pybamm.BaseModel() self.parameter_dict={} self.pybam_val_dict={} self.simulation_options=e_class.simulation_options self.dim_keys=self.nd_dict.keys() self.time=e_class.time_vec for key in self.dim_keys: self.parameter_dict[key]=pybamm.InputParameter(key) self.pybam_val_dict[key]=None self.current=pybamm.Variable("current") self.theta=pybamm.Variable("theta") if self.simulation_options["method"]=="dcv": Edc_forward = pybamm.t Edc_backwards = -(pybamm.t - 2*self.parameter_dict["tr"]) E_t = self.parameter_dict["E_start"]+ \ (pybamm.t <= self.parameter_dict["tr"]) * Edc_forward + \ (pybamm.t > self.parameter_dict["tr"]) * Edc_backwards elif self.simulation_options["method"]=="sinusoidal": E_t=self.parameter_dict["E_start"]+self.parameter_dict["d_E"]+(self.parameter_dict["d_E"]*pybamm.sin((self.parameter_dict["nd_omega"]*pybamm.t)+self.parameter_dict["phase"])) elif self.simulation_options["method"]=="ramped": Edc_forward = pybamm.t Edc_backwards = -(pybamm.t - 2*self.parameter_dict["tr"]) E_t = self.parameter_dict["E_start"]+ \ (pybamm.t <= self.parameter_dict["tr"]) * Edc_forward + \ (pybamm.t > self.parameter_dict["tr"]) * Edc_backwards+\ (self.parameter_dict["d_E"]*pybamm.sin((self.parameter_dict["nd_omega"]*pybamm.t)+self.parameter_dict["phase"])) Er=E_t-(self.parameter_dict["Ru"]*self.current) ErE0=Er-self.parameter_dict["E_0"] alpha=self.parameter_dict["alpha"] if "Cdlinv" not in e_class.optim_list: Cdlp=self.parameter_dict["Cdl"]*(1+self.parameter_dict["CdlE1"]*Er+self.parameter_dict["CdlE2"]*(Er**2)+self.parameter_dict["CdlE3"]*(Er**3)) else: Cdlp=(pybamm.t <= self.parameter_dict["tr"]) *(self.parameter_dict["Cdl"]*(1+self.parameter_dict["CdlE1"]*Er+self.parameter_dict["CdlE2"]*(Er**2)+self.parameter_dict["CdlE3"]*(Er**3)))+\ (pybamm.t > self.parameter_dict["tr"]) *(self.parameter_dict["Cdlinv"]*(1+self.parameter_dict["CdlE1inv"]*Er+self.parameter_dict["CdlE2inv"]*(Er**2)+self.parameter_dict["CdlE3inv"]*(Er**3))) self.model.variables={"current":self.current, "theta":self.theta} d_thetadt=((1-self.theta)*self.parameter_dict["k_0"]*pybamm.exp((1-alpha)*ErE0))-(self.theta*self.parameter_dict["k_0"]*pybamm.exp((-alpha)*ErE0)) dIdt=(E_t.diff(pybamm.t)-(self.current/Cdlp)+self.parameter_dict["gamma"]*d_thetadt*(1/Cdlp))/self.parameter_dict["Ru"] self.model.rhs={self.current:dIdt, self.theta:d_thetadt} self.disc=pybamm.Discretisation() self.model.initial_conditions={self.theta:pybamm.Scalar(1), self.current:pybamm.Scalar(0)} self.disc.process_model(self.model)
def test_solve_with_symbolic_input_1D_scalar_input(self): var = pybamm.Variable("var", "negative electrode") model = pybamm.BaseModel() param = pybamm.InputParameter("param") model.algebraic = {var: var + param} model.initial_conditions = {var: 2} model.variables = {"var": var} # create discretisation disc = tests.get_discretisation_for_testing() disc.process_model(model) # Solve - scalar input solver = pybamm.CasadiAlgebraicSolver() solution = solver.solve(model, [0]) np.testing.assert_array_equal(solution["var"].value({"param": 7}), -7) np.testing.assert_array_equal(solution["var"].value({"param": 3}), -3) np.testing.assert_array_equal( solution["var"].sensitivity({"param": 3}), -1)
def test_solve_with_symbolic_input_in_initial_conditions(self): # Simple system: a single algebraic equation var = pybamm.Variable("var") model = pybamm.BaseModel() model.algebraic = {var: var + 2} model.initial_conditions = {var: pybamm.InputParameter("param")} model.variables = {"var": var} # create discretisation disc = pybamm.Discretisation() disc.process_model(model) # Solve solver = pybamm.CasadiAlgebraicSolver() solution = solver.solve(model, [0]) np.testing.assert_array_equal(solution["var"].value({"param": 7}), -2) np.testing.assert_array_equal(solution["var"].value({"param": 3}), -2) np.testing.assert_array_equal( solution["var"].sensitivity({"param": 3}), 0)