def test_processed_var_0D_interpolation(self): # without spatial dependence t = pybamm.t y = pybamm.StateVector(slice(0, 1)) var = y eqn = t * y var.mesh = None eqn.mesh = None t_sol = np.linspace(0, 1, 1000) y_sol = np.array([np.linspace(0, 5, 1000)]) processed_var = pybamm.ProcessedVariable(var, pybamm.Solution(t_sol, y_sol)) # vector np.testing.assert_array_equal(processed_var(t_sol), y_sol[0]) # scalar np.testing.assert_array_equal(processed_var(0.5), 2.5) np.testing.assert_array_equal(processed_var(0.7), 3.5) processed_eqn = pybamm.ProcessedVariable(eqn, pybamm.Solution(t_sol, y_sol)) np.testing.assert_array_equal(processed_eqn(t_sol), t_sol * y_sol[0]) np.testing.assert_array_almost_equal(processed_eqn(0.5), 0.5 * 2.5) # Suppress warning for this test pybamm.set_logging_level("ERROR") np.testing.assert_array_equal(processed_eqn(2), np.nan) pybamm.set_logging_level("WARNING")
def test_processed_variable_0D(self): # without space t = pybamm.t y = pybamm.StateVector(slice(0, 1)) var = t * y var.mesh = None t_sol = np.linspace(0, 1) y_sol = np.array([np.linspace(0, 5)]) var_casadi = to_casadi(var, y_sol) processed_var = pybamm.ProcessedVariable( [var], [var_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) np.testing.assert_array_equal(processed_var.entries, t_sol * y_sol[0]) # scalar value var = y var.mesh = None t_sol = np.array([0]) y_sol = np.array([1])[:, np.newaxis] var_casadi = to_casadi(var, y_sol) processed_var = pybamm.ProcessedVariable( [var], [var_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) np.testing.assert_array_equal(processed_var.entries, y_sol[0])
def test_call_failure(self): # x domain var = pybamm.Variable("var x", domain=["negative electrode", "separator"]) x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"]) disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = np.linspace(0, 1) y_sol = x_sol[:, np.newaxis] * np.linspace(0, 5) processed_var = pybamm.ProcessedVariable(var_sol, pybamm.Solution(t_sol, y_sol)) with self.assertRaisesRegex(ValueError, "x cannot be None"): processed_var(0) # r domain var = pybamm.Variable("var r", domain=["negative particle"]) r = pybamm.SpatialVariable("r", domain=["negative particle"]) disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) r_sol = disc.process_symbol(r).entries[:, 0] var_sol = disc.process_symbol(var) y_sol = r_sol[:, np.newaxis] * np.linspace(0, 5) processed_var = pybamm.ProcessedVariable(var_sol, pybamm.Solution(t_sol, y_sol)) with self.assertRaisesRegex(ValueError, "r cannot be None"): processed_var(0) with self.assertRaisesRegex(ValueError, "r cannot be None"): processed_var(0, 1)
def test_processed_var_1D_interpolation(self): t = pybamm.t var = pybamm.Variable("var", domain=["negative electrode", "separator"]) x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"]) eqn = t * var + x disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] var_sol = disc.process_symbol(var) eqn_sol = disc.process_symbol(eqn) t_sol = np.linspace(0, 1) y_sol = x_sol[:, np.newaxis] * np.linspace(0, 5) processed_var = pybamm.ProcessedVariable( var_sol, pybamm.Solution(t_sol, y_sol), warn=False ) # 2 vectors np.testing.assert_array_almost_equal(processed_var(t_sol, x_sol), y_sol) # 1 vector, 1 scalar np.testing.assert_array_almost_equal( processed_var(0.5, x_sol)[:, 0], 2.5 * x_sol ) np.testing.assert_array_equal( processed_var(t_sol, x_sol[-1]), x_sol[-1] * np.linspace(0, 5) ) # 2 scalars np.testing.assert_array_almost_equal( processed_var(0.5, x_sol[-1]), 2.5 * x_sol[-1] ) processed_eqn = pybamm.ProcessedVariable( eqn_sol, pybamm.Solution(t_sol, y_sol), warn=False ) # 2 vectors np.testing.assert_array_almost_equal( processed_eqn(t_sol, x_sol), t_sol * y_sol + x_sol[:, np.newaxis] ) # 1 vector, 1 scalar self.assertEqual(processed_eqn(0.5, x_sol[10:30]).shape, (20, 1)) self.assertEqual(processed_eqn(t_sol[4:9], x_sol[-1]).shape, (5,)) # 2 scalars self.assertEqual(processed_eqn(0.5, x_sol[-1]).shape, (1,)) # test x processed_x = pybamm.ProcessedVariable( disc.process_symbol(x), pybamm.Solution(t_sol, y_sol), warn=False ) np.testing.assert_array_almost_equal(processed_x(x=x_sol), x_sol[:, np.newaxis]) # On microscale r_n = pybamm.Matrix( disc.mesh["negative particle"].nodes, domain="negative particle" ) r_n.mesh = disc.mesh["negative particle"] processed_r_n = pybamm.ProcessedVariable( r_n, pybamm.Solution(t_sol, y_sol), warn=False ) np.testing.assert_array_equal(r_n.entries[:, 0], processed_r_n.entries[:, 0])
def test_processed_var_2D_secondary_broadcast(self): var = pybamm.Variable("var", domain=["negative particle"]) broad_var = pybamm.SecondaryBroadcast(var, "negative electrode") x = pybamm.SpatialVariable("x", domain=["negative electrode"]) r = pybamm.SpatialVariable("r", domain=["negative particle"]) disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] r_sol = disc.process_symbol(r).entries[:, 0] var_sol = disc.process_symbol(broad_var) t_sol = np.linspace(0, 1) y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis] * np.linspace(0, 5) processed_var = pybamm.ProcessedVariable( var_sol, pybamm.Solution(t_sol, y_sol), warn=False ) # 3 vectors np.testing.assert_array_equal( processed_var(t_sol, x_sol, r_sol).shape, (10, 40, 50) ) np.testing.assert_array_equal( processed_var(t_sol, x_sol, r_sol), np.reshape(y_sol, [len(r_sol), len(x_sol), len(t_sol)]), ) # 2 vectors, 1 scalar np.testing.assert_array_equal(processed_var(0.5, x_sol, r_sol).shape, (10, 40)) np.testing.assert_array_equal(processed_var(t_sol, 0.2, r_sol).shape, (10, 50)) np.testing.assert_array_equal(processed_var(t_sol, x_sol, 0.5).shape, (40, 50)) # 1 vectors, 2 scalar np.testing.assert_array_equal(processed_var(0.5, 0.2, r_sol).shape, (10,)) np.testing.assert_array_equal(processed_var(0.5, x_sol, 0.5).shape, (40,)) np.testing.assert_array_equal(processed_var(t_sol, 0.2, 0.5).shape, (50,)) # 3 scalars np.testing.assert_array_equal(processed_var(0.2, 0.2, 0.2).shape, ()) # positive particle var = pybamm.Variable("var", domain=["positive particle"]) broad_var = pybamm.SecondaryBroadcast(var, "positive electrode") x = pybamm.SpatialVariable("x", domain=["positive electrode"]) r = pybamm.SpatialVariable("r", domain=["positive particle"]) disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] r_sol = disc.process_symbol(r).entries[:, 0] var_sol = disc.process_symbol(broad_var) t_sol = np.linspace(0, 1) y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis] * np.linspace(0, 5) processed_var = pybamm.ProcessedVariable( var_sol, pybamm.Solution(t_sol, y_sol), warn=False ) # 3 vectors np.testing.assert_array_equal( processed_var(t_sol, x_sol, r_sol).shape, (10, 35, 50) )
def test_processed_variable_2D_x_z(self): var = pybamm.Variable( "var", domain=["negative electrode", "separator"], auxiliary_domains={"secondary": "current collector"}, ) x = pybamm.SpatialVariable( "x", domain=["negative electrode", "separator"], auxiliary_domains={"secondary": "current collector"}, ) z = pybamm.SpatialVariable("z", domain=["current collector"]) disc = tests.get_1p1d_discretisation_for_testing() disc.set_variable_slices([var]) z_sol = disc.process_symbol(z).entries[:, 0] x_sol = disc.process_symbol(x).entries[:, 0] # Keep only the first iteration of entries x_sol = x_sol[:len(x_sol) // len(z_sol)] var_sol = disc.process_symbol(var) t_sol = np.linspace(0, 1) y_sol = np.ones(len(x_sol) * len(z_sol))[:, np.newaxis] * np.linspace( 0, 5) var_casadi = to_casadi(var_sol, y_sol) processed_var = pybamm.ProcessedVariable( [var_sol], [var_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) np.testing.assert_array_equal( processed_var.entries, np.reshape( y_sol, [len(x_sol), len(z_sol), len(t_sol)]), ) # On edges x_s_edge = pybamm.Matrix( np.tile(disc.mesh["separator"].edges, len(z_sol)), domain="separator", auxiliary_domains={"secondary": "current collector"}, ) x_s_edge.mesh = disc.mesh["separator"] x_s_edge.secondary_mesh = disc.mesh["current collector"] x_s_casadi = to_casadi(x_s_edge, y_sol) processed_x_s_edge = pybamm.ProcessedVariable( [x_s_edge], [x_s_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) np.testing.assert_array_equal( x_s_edge.entries.flatten(), processed_x_s_edge.entries[:, :, 0].T.flatten())
def test_processed_variable_1D(self): t = pybamm.t var = pybamm.Variable("var", domain=["negative electrode", "separator"]) x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"]) eqn = t * var + x # On nodes disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] var_sol = disc.process_symbol(var) eqn_sol = disc.process_symbol(eqn) t_sol = np.linspace(0, 1) y_sol = np.ones_like(x_sol)[:, np.newaxis] * np.linspace(0, 5) processed_var = pybamm.ProcessedVariable( var_sol, pybamm.Solution(t_sol, y_sol), warn=False ) np.testing.assert_array_equal(processed_var.entries, y_sol) np.testing.assert_array_equal(processed_var(t_sol, x_sol), y_sol) processed_eqn = pybamm.ProcessedVariable( eqn_sol, pybamm.Solution(t_sol, y_sol), warn=False ) np.testing.assert_array_equal( processed_eqn(t_sol, x_sol), t_sol * y_sol + x_sol[:, np.newaxis] ) # Test extrapolation np.testing.assert_array_equal(processed_var.entries[0], 2 * y_sol[0] - y_sol[1]) np.testing.assert_array_equal( processed_var.entries[1], 2 * y_sol[-1] - y_sol[-2] ) # On edges x_s_edge = pybamm.Matrix(disc.mesh["separator"].edges, domain="separator") x_s_edge.mesh = disc.mesh["separator"] processed_x_s_edge = pybamm.ProcessedVariable( x_s_edge, pybamm.Solution(t_sol, y_sol), warn=False ) np.testing.assert_array_equal( x_s_edge.entries[:, 0], processed_x_s_edge.entries[:, 0] ) # space only eqn = var + x eqn_sol = disc.process_symbol(eqn) t_sol = np.array([0]) y_sol = np.ones_like(x_sol)[:, np.newaxis] processed_eqn2 = pybamm.ProcessedVariable( eqn_sol, pybamm.Solution(t_sol, y_sol), warn=False ) np.testing.assert_array_equal( processed_eqn2.entries, y_sol + x_sol[:, np.newaxis] )
def test_call_failure(self): # x domain var = pybamm.Variable("var x", domain=["negative electrode", "separator"]) x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"]) disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = np.linspace(0, 1) y_sol = x_sol[:, np.newaxis] * np.linspace(0, 5) var_casadi = to_casadi(var_sol, y_sol) processed_var = pybamm.ProcessedVariable( [var_sol], [var_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) with self.assertRaisesRegex(ValueError, "x cannot be None"): processed_var(0) # r domain var = pybamm.Variable("var r", domain=["negative particle"]) r = pybamm.SpatialVariable( "r", domain=["negative particle"], auxiliary_domains={"secondary": ["negative electrode"]}, ) disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) r_sol = disc.process_symbol(r).entries[:, 0] var_sol = disc.process_symbol(var) y_sol = r_sol[:, np.newaxis] * np.linspace(0, 5) var_casadi = to_casadi(var_sol, y_sol) processed_var = pybamm.ProcessedVariable( [var_sol], [var_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) with self.assertRaisesRegex(ValueError, "r cannot be None"): processed_var(0) with self.assertRaisesRegex(ValueError, "r cannot be None"): processed_var(0, 1) # t is None but len(solution.t) > 1 with self.assertRaisesRegex(ValueError, "t cannot be None"): processed_var()
def test_get_processed_potentials(self): # solve cheap SPM to test processed potentials (think of an alternative test?) models = [ pybamm.current_collector.EffectiveResistance2D(), pybamm.lithium_ion.SPM(), ] var = pybamm.standard_spatial_vars var_pts = { var.x_n: 5, var.x_s: 5, var.x_p: 5, var.r_n: 5, var.r_p: 5, var.y: 5, var.z: 5, } param = models[1].default_parameter_values meshes = [None] * len(models) for i, model in enumerate(models): param.process_model(model) geometry = model.default_geometry param.process_geometry(geometry) meshes[i] = pybamm.Mesh(geometry, model.default_submesh_types, var_pts) disc = pybamm.Discretisation(meshes[i], model.default_spatial_methods) disc.process_model(model) solutions = [None] * len(models) t_eval = np.linspace(0, 0.1, 10) solutions[0] = models[0].default_solver.solve(models[0]) solutions[1] = models[1].default_solver.solve(models[1], t_eval) # Process SPM V and I V = pybamm.ProcessedVariable( models[1].variables["Terminal voltage"], solutions[1].t, solutions[1].y, mesh=meshes[1], ) I = pybamm.ProcessedVariable( models[1].variables["Total current density"], solutions[1].t, solutions[1].y, mesh=meshes[1], ) # Test potential can be constructed and evaluated without raising error potentials = models[0].get_processed_potentials( solutions[0], meshes[0], param, V, I) for var, processed_var in potentials.items(): processed_var(0.05, 0.5, 0.5)
def get_max_error(current): pybamm.logger.info("current = {}".format(current)) # Update current (and hence C_e) in the parameters param = pybamm.ParameterValues( chemistry=pybamm.parameter_sets.Sulzer2019) param.update({"Typical current [A]": current}) param.update_model(leading_order_model, loqs_disc) param.update_model(composite_model, comp_disc) param.update_model(full_model, full_disc) # Solve, make sure times are the same and use tight tolerances t_eval = np.linspace(0, 0.6) solver_loqs = leading_order_model.default_solver solver_loqs.rtol = 1e-8 solver_loqs.atol = 1e-8 solution_loqs = solver_loqs.solve(leading_order_model, t_eval) solver_comp = composite_model.default_solver solver_comp.rtol = 1e-8 solver_comp.atol = 1e-8 solution_comp = solver_comp.solve(composite_model, t_eval) solver_full = full_model.default_solver solver_full.rtol = 1e-8 solver_full.atol = 1e-8 solution_full = solver_full.solve(full_model, t_eval) # Post-process variables t_loqs, y_loqs = solution_loqs.t, solution_loqs.y t_comp, y_comp = solution_comp.t, solution_comp.y t_full, y_full = solution_full.t, solution_full.y voltage_loqs = pybamm.ProcessedVariable( leading_order_model.variables["Terminal voltage"], t_loqs, y_loqs, loqs_disc.mesh, ) voltage_comp = pybamm.ProcessedVariable( composite_model.variables["Terminal voltage"], t_comp, y_comp, comp_disc.mesh, ) voltage_full = pybamm.ProcessedVariable( full_model.variables["Terminal voltage"], t_full, y_full, full_disc.mesh) # Compare t = t_full[:np.min([len(t_loqs), len(t_comp), len(t_full)])] loqs_error = np.max(np.abs(voltage_loqs(t) - voltage_full(t))) comp_error = np.max(np.abs(voltage_comp(t) - voltage_full(t))) return (loqs_error, comp_error)
def test_processed_var_2D_fixed_t_interpolation(self): var = pybamm.Variable( "var", domain=["negative particle"], auxiliary_domains={"secondary": ["negative electrode"]}, ) x = pybamm.SpatialVariable("x", domain=["negative electrode"]) r = pybamm.SpatialVariable( "r", domain=["negative particle"], auxiliary_domains={"secondary": ["negative electrode"]}, ) disc = tests.get_p2d_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] r_sol = disc.process_symbol(r).entries[:, 0] # Keep only the first iteration of entries r_sol = r_sol[: len(r_sol) // len(x_sol)] var_sol = disc.process_symbol(var) t_sol = np.array([0]) y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis] processed_var = pybamm.ProcessedVariable( var_sol, pybamm.Solution(t_sol, y_sol), warn=False ) # 2 vectors np.testing.assert_array_equal(processed_var(x=x_sol, r=r_sol).shape, (10, 40)) # 1 vector, 1 scalar np.testing.assert_array_equal(processed_var(x=0.2, r=r_sol).shape, (10,)) np.testing.assert_array_equal(processed_var(x=x_sol, r=0.5).shape, (40,)) # 2 scalars np.testing.assert_array_equal(processed_var(x=0.2, r=0.2).shape, ())
def test_processed_variable_1D_unknown_domain(self): x = pybamm.SpatialVariable("x", domain="SEI layer", coord_sys="cartesian") geometry = pybamm.Geometry({ "SEI layer": { x: { "min": pybamm.Scalar(0), "max": pybamm.Scalar(1) } } }) submesh_types = {"SEI layer": pybamm.Uniform1DSubMesh} var_pts = {x: 100} mesh = pybamm.Mesh(geometry, submesh_types, var_pts) nt = 100 y_sol = np.zeros((var_pts[x], nt)) solution = pybamm.Solution( np.linspace(0, 1, nt), y_sol, pybamm.BaseModel(), {}, np.linspace(0, 1, 1), np.zeros((var_pts[x])), "test", ) c = pybamm.StateVector(slice(0, var_pts[x]), domain=["SEI layer"]) c.mesh = mesh["SEI layer"] c_casadi = to_casadi(c, y_sol) pybamm.ProcessedVariable([c], [c_casadi], solution, warn=False)
def test_processed_var_2D_fixed_t_scikit_interpolation(self): var = pybamm.Variable("var", domain=["current collector"]) disc = tests.get_2p1d_discretisation_for_testing() disc.set_variable_slices([var]) y_sol = disc.mesh["current collector"].edges["y"] z_sol = disc.mesh["current collector"].edges["z"] var_sol = disc.process_symbol(var) var_sol.mesh = disc.mesh["current collector"] t_sol = np.array([0]) u_sol = np.ones(var_sol.shape[0])[:, np.newaxis] var_casadi = to_casadi(var_sol, u_sol) processed_var = pybamm.ProcessedVariable( [var_sol], [var_casadi], pybamm.Solution(t_sol, u_sol, pybamm.BaseModel(), {}), warn=False, ) # 2 vectors np.testing.assert_array_equal( processed_var(y=y_sol, z=z_sol).shape, (15, 15)) # 1 vector, 1 scalar np.testing.assert_array_equal( processed_var(y=0.2, z=z_sol).shape, (15, )) np.testing.assert_array_equal( processed_var(y=y_sol, z=0.5).shape, (15, )) # 2 scalars np.testing.assert_array_equal( processed_var(t=None, y=0.2, z=0.2).shape, ())
def test_processed_variable_2D_x_r(self): var = pybamm.Variable( "var", domain=["negative particle"], auxiliary_domains={"secondary": ["negative electrode"]}, ) x = pybamm.SpatialVariable("x", domain=["negative electrode"]) r = pybamm.SpatialVariable("r", domain=["negative particle"]) disc = tests.get_p2d_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] r_sol = disc.process_symbol(r).entries[:, 0] # Keep only the first iteration of entries r_sol = r_sol[:len(r_sol) // len(x_sol)] var_sol = disc.process_symbol(var) t_sol = np.linspace(0, 1) y_sol = np.ones(len(x_sol) * len(r_sol))[:, np.newaxis] * np.linspace( 0, 5) processed_var = pybamm.ProcessedVariable(var_sol, pybamm.Solution(t_sol, y_sol)) np.testing.assert_array_equal( processed_var.entries, np.reshape( y_sol, [len(r_sol), len(x_sol), len(t_sol)]), )
def test_processed_var_1D_fixed_t_interpolation(self): var = pybamm.Variable("var", domain=["negative electrode", "separator"]) x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"]) eqn = var + x disc = tests.get_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] eqn_sol = disc.process_symbol(eqn) t_sol = np.array([1]) y_sol = x_sol[:, np.newaxis] eqn_casadi = to_casadi(eqn_sol, y_sol) processed_var = pybamm.ProcessedVariable( [eqn_sol], [eqn_casadi], pybamm.Solution(t_sol, y_sol, pybamm.BaseModel(), {}), warn=False, ) # vector np.testing.assert_array_almost_equal(processed_var(x=x_sol), 2 * x_sol[:, np.newaxis]) # scalar np.testing.assert_array_almost_equal(processed_var(x=0.5), 1)
def test_processed_variable_1D_unknown_domain(self): x = pybamm.SpatialVariable("x", domain="SEI layer", coord_sys="cartesian") geometry = pybamm.Geometry() geometry.add_domain( "SEI layer", { "primary": { x: { "min": pybamm.Scalar(0), "max": pybamm.Scalar(1) } } }, ) submesh_types = {"SEI layer": pybamm.Uniform1DSubMesh} var_pts = {x: 100} mesh = pybamm.Mesh(geometry, submesh_types, var_pts) nt = 100 solution = pybamm.Solution( np.linspace(0, 1, nt), np.zeros((var_pts[x], nt)), np.linspace(0, 1, 1), np.zeros((var_pts[x])), "test", ) c = pybamm.StateVector(slice(0, var_pts[x]), domain=["SEI layer"]) c.mesh = mesh["SEI layer"] pybamm.ProcessedVariable(c, solution)
def test_processed_var_2Dspace_scikit_interpolation(self): var = pybamm.Variable("var", domain=["current collector"]) y = pybamm.SpatialVariable("y", domain=["current collector"]) z = pybamm.SpatialVariable("z", domain=["current collector"]) disc = tests.get_2p1d_discretisation_for_testing() disc.set_variable_slices([var]) y_sol = disc.process_symbol(y).entries[:, 0] z_sol = disc.process_symbol(z).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = np.array([0]) u_sol = np.ones(var_sol.shape[0])[:, np.newaxis] processed_var = pybamm.ProcessedVariable(var_sol, t_sol, u_sol, mesh=disc.mesh) # 2 vectors np.testing.assert_array_equal( processed_var(t=None, y=y_sol, z=z_sol).shape, (15, 15)) # 1 vector, 1 scalar np.testing.assert_array_equal( processed_var(t=None, y=0.2, z=z_sol).shape, (15, 1)) np.testing.assert_array_equal( processed_var(t=None, y=y_sol, z=0.5).shape, (15, )) # 2 scalars np.testing.assert_array_equal( processed_var(t=None, y=0.2, z=0.2).shape, (1, ))
def update(self, variables): """Add ProcessedVariables to the dictionary of variables in the solution""" # Convert single entry to list if isinstance(variables, str): variables = [variables] # Process for key in variables: pybamm.logger.debug("Post-processing {}".format(key)) # If there are symbolic inputs then we need to make a # ProcessedSymbolicVariable if self.has_symbolic_inputs is True: var = pybamm.ProcessedSymbolicVariable( self.model.variables[key], self) # Otherwise a standard ProcessedVariable is ok else: var = pybamm.ProcessedVariable(self.model.variables[key], self, self._known_evals) # Update known_evals in order to process any other variables faster for t in var.known_evals: self._known_evals[t].update(var.known_evals[t]) # Save variable and data self._variables[key] = var self.data[key] = var.data
def test_failure(self): t = np.ones(25) y = np.ones((120, 25)) mat = pybamm.Vector(np.ones(120), domain=["negative particle"]) disc = tests.get_p2d_discretisation_for_testing() with self.assertRaisesRegex( ValueError, "3D variable shape does not match domain shape"): pybamm.ProcessedVariable(mat, t, y, disc.mesh)
def test_update_geometry(self): # test on simple lead-acid model model1 = pybamm.lead_acid.LOQS() modeltest1 = tests.StandardModelTest(model1) t_eval = np.linspace(0, 0.5) modeltest1.test_all(t_eval=t_eval, skip_output_tests=True) T1, Y1 = modeltest1.solution.t, modeltest1.solution.y # trying to update the geometry fails parameter_values_update = pybamm.ParameterValues( chemistry=pybamm.parameter_sets.Sulzer2019 ) parameter_values_update.update( { "Negative electrode thickness [m]": 0.0002, "Separator thickness [m]": 0.0003, "Positive electrode thickness [m]": 0.0004, } ) with self.assertRaisesRegex(ValueError, "geometry has changed"): modeltest1.test_update_parameters(parameter_values_update) # instead we need to make a new model and re-discretise model2 = pybamm.lead_acid.LOQS() # nb: need to be careful make parameters a reasonable size modeltest2 = tests.StandardModelTest(model2) modeltest2.test_all( param=parameter_values_update, t_eval=t_eval, skip_output_tests=True ) T2, Y2 = modeltest2.solution.t, modeltest2.solution.y # results should be different c1 = pybamm.ProcessedVariable( modeltest1.model.variables["Electrolyte concentration"], T1, Y1, mesh=modeltest1.disc.mesh, ).entries c2 = pybamm.ProcessedVariable( modeltest2.model.variables["Electrolyte concentration"], T2, Y2, mesh=modeltest2.disc.mesh, ).entries self.assertNotEqual(np.linalg.norm(c1 - c2), 0) self.assertNotEqual(np.linalg.norm(Y1 - Y2), 0)
def test_processed_variable_1D(self): # without space t = pybamm.t y = pybamm.StateVector(slice(0, 1)) var = t * y t_sol = np.linspace(0, 1) y_sol = np.array([np.linspace(0, 5)]) processed_var = pybamm.ProcessedVariable(var, t_sol, y_sol) np.testing.assert_array_equal(processed_var.entries, t_sol * y_sol[0])
def test_processed_var_1D_interpolation(self): # without spatial dependence t = pybamm.t y = pybamm.StateVector(slice(0, 1)) var = y eqn = t * y t_sol = np.linspace(0, 1, 1000) y_sol = np.array([np.linspace(0, 5, 1000)]) processed_var = pybamm.ProcessedVariable(var, t_sol, y_sol) # vector np.testing.assert_array_equal(processed_var(t_sol), y_sol[0]) # scalar np.testing.assert_array_equal(processed_var(0.5), 2.5) np.testing.assert_array_equal(processed_var(0.7), 3.5) processed_eqn = pybamm.ProcessedVariable(eqn, t_sol, y_sol) np.testing.assert_array_equal(processed_eqn(t_sol), t_sol * y_sol[0]) np.testing.assert_array_almost_equal(processed_eqn(0.5), 0.5 * 2.5)
def update(self, variables): """Add ProcessedVariables to the dictionary of variables in the solution""" # Convert single entry to list if isinstance(variables, str): variables = [variables] # Process for key in variables: pybamm.logger.debug("Post-processing {}".format(key)) # If there are symbolic inputs then we need to make a # ProcessedSymbolicVariable if self.has_symbolic_inputs is True: var = pybamm.ProcessedSymbolicVariable( self.all_models[0].variables[key], self ) # Otherwise a standard ProcessedVariable is ok else: vars_pybamm = [model.variables[key] for model in self.all_models] # Iterate through all models, some may be in the list several times and # therefore only get set up once vars_casadi = [] for model, ys, inputs, var_pybamm in zip( self.all_models, self.all_ys, self.all_inputs, vars_pybamm ): if key in model._variables_casadi: var_casadi = model._variables_casadi[key] else: t_MX = casadi.MX.sym("t") y_MX = casadi.MX.sym("y", ys.shape[0]) symbolic_inputs_dict = { key: casadi.MX.sym("input", value.shape[0]) for key, value in inputs.items() } symbolic_inputs = casadi.vertcat( *[p for p in symbolic_inputs_dict.values()] ) # Convert variable to casadi # Make all inputs symbolic first for converting to casadi var_sym = var_pybamm.to_casadi( t_MX, y_MX, inputs=symbolic_inputs_dict ) var_casadi = casadi.Function( "variable", [t_MX, y_MX, symbolic_inputs], [var_sym] ) model._variables_casadi[key] = var_casadi vars_casadi.append(var_casadi) var = pybamm.ProcessedVariable(vars_pybamm, vars_casadi, self) # Save variable and data self._variables[key] = var self.data[key] = var.data
def test_processed_variable_3D_x_z(self): var = pybamm.Variable( "var", domain=["negative electrode", "separator"], auxiliary_domains={"secondary": "current collector"}, ) x = pybamm.SpatialVariable("x", domain=["negative electrode", "separator"]) z = pybamm.SpatialVariable("z", domain=["current collector"]) disc = tests.get_1p1d_discretisation_for_testing() disc.set_variable_slices([var]) x_sol = disc.process_symbol(x).entries[:, 0] z_sol = disc.process_symbol(z).entries[:, 0] var_sol = disc.process_symbol(var) t_sol = np.linspace(0, 1) y_sol = np.ones(len(x_sol) * len(z_sol))[:, np.newaxis] * np.linspace( 0, 5) processed_var = pybamm.ProcessedVariable(var_sol, t_sol, y_sol, mesh=disc.mesh) np.testing.assert_array_equal( processed_var.entries, np.reshape( y_sol, [len(x_sol), len(z_sol), len(t_sol)]), ) # On edges x_s_edge = pybamm.Matrix( np.repeat(disc.mesh["separator"][0].edges, len(z_sol)), domain="separator", auxiliary_domains={"secondary": "current collector"}, ) processed_x_s_edge = pybamm.ProcessedVariable(x_s_edge, t_sol, y_sol, disc.mesh) np.testing.assert_array_equal( x_s_edge.entries[:, 0], processed_x_s_edge.entries[:, :, 0].reshape(-1, 1)[:, 0], )
def test_solution_too_short(self): t = pybamm.t y = pybamm.StateVector(slice(0, 1)) var = t * y var.mesh = None t_sol = np.array([1]) y_sol = np.array([np.linspace(0, 5)]) with self.assertRaisesRegex( pybamm.SolverError, "Solution time vector must have length > 1"): pybamm.ProcessedVariable(var, pybamm.Solution(t_sol, y_sol))
def test_solution_too_short(self): t = pybamm.t y = pybamm.StateVector(slice(0, 3)) var = t * y disc = tests.get_2p1d_discretisation_for_testing() var.mesh = disc.mesh["current collector"] t_sol = np.array([1]) y_sol = np.linspace(0, 5)[:, np.newaxis] with self.assertRaisesRegex( pybamm.SolverError, "Solution time vector must have length > 1"): pybamm.ProcessedVariable(var, pybamm.Solution(t_sol, y_sol))
def test_processed_var_0D_fixed_t_interpolation(self): y = pybamm.StateVector(slice(0, 1)) var = y eqn = 2 * y var.mesh = None eqn.mesh = None t_sol = np.array([10]) y_sol = np.array([[100]]) processed_var = pybamm.ProcessedVariable( eqn, pybamm.Solution(t_sol, y_sol), warn=False ) np.testing.assert_array_equal(processed_var(), 200)
def test_3D_raises_error(self): var = pybamm.Variable( "var", domain=["negative electrode"], auxiliary_domains={"secondary": ["current collector"]}, ) disc = tests.get_2p1d_discretisation_for_testing() disc.set_variable_slices([var]) var_sol = disc.process_symbol(var) t_sol = np.array([0, 1, 2]) u_sol = np.ones(var_sol.shape[0] * 3)[:, np.newaxis] with self.assertRaisesRegex(NotImplementedError, "Shape not recognized"): pybamm.ProcessedVariable(var_sol, pybamm.Solution(t_sol, u_sol), warn=False)
def test_processed_variable_2D_fixed_t_scikit(self): var = pybamm.Variable("var", domain=["current collector"]) disc = tests.get_2p1d_discretisation_for_testing() disc.set_variable_slices([var]) y = disc.mesh["current collector"][0].edges["y"] z = disc.mesh["current collector"][0].edges["z"] var_sol = disc.process_symbol(var) t_sol = np.array([0]) u_sol = np.ones(var_sol.shape[0])[:, np.newaxis] processed_var = pybamm.ProcessedVariable(var_sol, pybamm.Solution(t_sol, u_sol)) np.testing.assert_array_equal(processed_var.entries, np.reshape(u_sol, [len(y), len(z)]))
def update(self, variables): """Add ProcessedVariables to the dictionary of variables in the solution""" # Convert single entry to list if isinstance(variables, str): variables = [variables] # Process for key in variables: pybamm.logger.debug("Post-processing {}".format(key)) var = pybamm.ProcessedVariable(self.model.variables[key], self, self._known_evals) # Update known_evals in order to process any other variables faster for t in var.known_evals: self._known_evals[t].update(var.known_evals[t]) # Save variable and data self._variables[key] = var self.data[key] = var.data