def get_unit_2p1D_mesh_for_testing(ypts=15, zpts=15): param = pybamm.ParameterValues( values={ "Electrode width [m]": 1, "Electrode height [m]": 1, "Negative tab width [m]": 1, "Negative tab centre y-coordinate [m]": 0.5, "Negative tab centre z-coordinate [m]": 0, "Positive tab width [m]": 1, "Positive tab centre y-coordinate [m]": 0.5, "Positive tab centre z-coordinate [m]": 1, "Negative electrode thickness [m]": 0.3, "Separator thickness [m]": 0.3, "Positive electrode thickness [m]": 0.3, } ) geometry = pybamm.Geometryxp1DMacro(cc_dimension=2) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = {var.x_n: 3, var.x_s: 3, var.x_p: 3, var.y: ypts, var.z: zpts} submesh_types = { "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "positive electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "current collector": pybamm.MeshGenerator(pybamm.ScikitUniform2DSubMesh), } return pybamm.Mesh(geometry, submesh_types, var_pts)
def test_mesh_creation(self): param = pybamm.ParameterValues( values={ "Electrode width [m]": 0.4, "Electrode height [m]": 0.5, "Negative tab width [m]": 0.1, "Negative tab centre y-coordinate [m]": 0.1, "Negative tab centre z-coordinate [m]": 0.5, "Positive tab width [m]": 0.1, "Positive tab centre y-coordinate [m]": 0.3, "Positive tab centre z-coordinate [m]": 0.5, "Negative electrode thickness [m]": 0.3, "Separator thickness [m]": 0.3, "Positive electrode thickness [m]": 0.3, }) geometry = pybamm.Geometryxp1DMacro(cc_dimension=2) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = {var.x_n: 10, var.x_s: 7, var.x_p: 12, var.y: 16, var.z: 24} y_edges = np.linspace(0, 0.8, 16) z_edges = np.linspace(0, 1, 24) submesh_params = {"y_edges": y_edges, "z_edges": z_edges} submesh_types = { "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "positive electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "current collector": pybamm.MeshGenerator(pybamm.UserSupplied2DSubMesh, submesh_params), } mesh_type = pybamm.Mesh # create mesh mesh = mesh_type(geometry, submesh_types, var_pts) # check boundary locations self.assertEqual(mesh["negative electrode"][0].edges[0], 0) self.assertEqual(mesh["positive electrode"][0].edges[-1], 1) # check internal boundary locations self.assertEqual(mesh["negative electrode"][0].edges[-1], mesh["separator"][0].edges[0]) self.assertEqual(mesh["positive electrode"][0].edges[0], mesh["separator"][0].edges[-1]) for domain in mesh: if domain == "current collector": # NOTE: only for degree 1 npts = var_pts[var.y] * var_pts[var.z] self.assertEqual(mesh[domain][0].npts, npts) else: self.assertEqual(len(mesh[domain][0].edges), len(mesh[domain][0].nodes) + 1)
def test_init_failure(self): submesh_types = { "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "positive electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "current collector": pybamm.MeshGenerator(pybamm.ScikitUniform2DSubMesh), } geometry = pybamm.Geometryxp1DMacro(cc_dimension=2) with self.assertRaises(KeyError): pybamm.Mesh(geometry, submesh_types, {}) var = pybamm.standard_spatial_vars var_pts = {var.x_n: 10, var.x_s: 10, var.x_p: 10, var.y: 10, var.z: 10} # there are parameters in the variables that need to be processed with self.assertRaises(NotImplementedError): pybamm.Mesh(geometry, submesh_types, var_pts) lims = {var.x_n: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}} with self.assertRaises(pybamm.GeometryError): pybamm.ScikitUniform2DSubMesh(lims, None, None) lims = { var.x_n: { "min": pybamm.Scalar(0), "max": pybamm.Scalar(1) }, var.x_p: { "min": pybamm.Scalar(0), "max": pybamm.Scalar(1) }, } with self.assertRaises(pybamm.DomainError): pybamm.ScikitUniform2DSubMesh(lims, None, None) lims = { var.y: { "min": pybamm.Scalar(0), "max": pybamm.Scalar(1) }, var.z: { "min": pybamm.Scalar(0), "max": pybamm.Scalar(1) }, } npts = {var.y.id: 10, var.z.id: 10} var.z.coord_sys = "not cartesian" with self.assertRaises(pybamm.DomainError): pybamm.ScikitUniform2DSubMesh(lims, npts, None) var.z.coord_sys = "cartesian"
def test_geometry_keys(self): geometry = pybamm.Geometryxp1DMacro(cc_dimension=1) for key, prim_sec_vars in geometry.items(): self.assertIn("primary", prim_sec_vars.keys()) if key != "current collector": self.assertIn("secondary", prim_sec_vars.keys()) var = pybamm.standard_spatial_vars self.assertEqual( list(prim_sec_vars["secondary"].keys())[0].id, var.z.id) for spatial_vars in prim_sec_vars.values(): all( self.assertIsInstance(spatial_var, pybamm.SpatialVariable) for spatial_var in spatial_vars.keys() if spatial_var not in ["negative", "positive"])
def test_geometry_keys(self): geometry = pybamm.Geometryxp1DMacro(cc_dimension=2) for key, prim_sec_vars in geometry.items(): self.assertIn("primary", prim_sec_vars.keys()) if key != "current collector": self.assertIn("secondary", prim_sec_vars.keys()) var = pybamm.standard_spatial_vars self.assertIn(var.y, prim_sec_vars["secondary"].keys()) self.assertIn(var.z, prim_sec_vars["secondary"].keys()) for spatial_vars in prim_sec_vars.values(): all( self.assertIsInstance(spatial_var, pybamm.SpatialVariable) for spatial_var in spatial_vars.keys() if spatial_var not in ["negative", "positive"]) def test_init_failure(self): with self.assertRaises(pybamm.GeometryError): pybamm.Geometryxp1DMacro(cc_dimension=3)
def test_1plus1D_tabs_right_left(self): param = pybamm.ParameterValues( values={ "Electrode width [m]": 0.4, "Electrode height [m]": 0.5, "Negative tab centre z-coordinate [m]": 0.5, "Positive tab centre z-coordinate [m]": 0.0, "Negative electrode thickness [m]": 0.3, "Separator thickness [m]": 0.3, "Positive electrode thickness [m]": 0.3, }) geometry = pybamm.Geometryxp1DMacro(cc_dimension=1) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = {var.x_n: 10, var.x_s: 7, var.x_p: 12, var.z: 24} submesh_types = { "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "positive electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "current collector": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), } mesh_type = pybamm.Mesh # create mesh mesh = mesh_type(geometry, submesh_types, var_pts) # negative tab should be "right" self.assertEqual(mesh["current collector"][0].tabs["negative tab"], "right") # positive tab should be "left" self.assertEqual(mesh["current collector"][0].tabs["positive tab"], "left")
def test_tab_error(self): # set variables and submesh types var = pybamm.standard_spatial_vars var_pts = {var.x_n: 2, var.x_s: 2, var.x_p: 2, var.y: 64, var.z: 64} submesh_types = { "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "positive electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "current collector": pybamm.MeshGenerator(pybamm.ScikitUniform2DSubMesh), } mesh_type = pybamm.Mesh # set base parameters param = pybamm.ParameterValues( values={ "Electrode width [m]": 0.4, "Electrode height [m]": 0.5, "Negative tab width [m]": 0.1, "Negative tab centre y-coordinate [m]": 0.1, "Negative tab centre z-coordinate [m]": 0.5, "Positive tab centre y-coordinate [m]": 10, "Positive tab centre z-coordinate [m]": 10, "Positive tab width [m]": 0.1, "Negative electrode thickness [m]": 0.3, "Separator thickness [m]": 0.3, "Positive electrode thickness [m]": 0.3, }) # check error raised if tab not on boundary geometry = pybamm.Geometryxp1DMacro(cc_dimension=2) param.process_geometry(geometry) with self.assertRaises(pybamm.GeometryError): mesh_type(geometry, submesh_types, var_pts)
def test_init_failure(self): with self.assertRaises(pybamm.GeometryError): pybamm.Geometryxp1DMacro(cc_dimension=3)
def test_manufactured_solution_exponential_grid(self): param = pybamm.ParameterValues( values={ "Electrode width [m]": 1, "Electrode height [m]": 1, "Negative tab width [m]": 1, "Negative tab centre y-coordinate [m]": 0.5, "Negative tab centre z-coordinate [m]": 0, "Positive tab width [m]": 1, "Positive tab centre y-coordinate [m]": 0.5, "Positive tab centre z-coordinate [m]": 1, "Negative electrode thickness [m]": 0.3, "Separator thickness [m]": 0.3, "Positive electrode thickness [m]": 0.3, }) geometry = pybamm.Geometryxp1DMacro(cc_dimension=2) param.process_geometry(geometry) var = pybamm.standard_spatial_vars var_pts = {var.x_n: 3, var.x_s: 3, var.x_p: 3, var.y: 32, var.z: 32} submesh_types = { "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "positive electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh), "current collector": pybamm.MeshGenerator(pybamm.ScikitExponential2DSubMesh), } mesh = pybamm.Mesh(geometry, submesh_types, var_pts) spatial_methods = { "macroscale": pybamm.FiniteVolume(), "current collector": pybamm.ScikitFiniteElement(), } disc = pybamm.Discretisation(mesh, spatial_methods) # laplace of u = cos(pi*y)*sin(pi*z) var = pybamm.Variable("var", domain="current collector") laplace_eqn = pybamm.laplacian(var) # set boundary conditions ("negative tab" = bottom of unit square, # "positive tab" = top of unit square, elsewhere normal derivative is zero) disc.bcs = { var.id: { "negative tab": (pybamm.Scalar(0), "Dirichlet"), "positive tab": (pybamm.Scalar(0), "Dirichlet"), } } disc.set_variable_slices([var]) laplace_eqn_disc = disc.process_symbol(laplace_eqn) y_vertices = mesh["current collector"][0].coordinates[0, :][:, np.newaxis] z_vertices = mesh["current collector"][0].coordinates[1, :][:, np.newaxis] u = np.cos(np.pi * y_vertices) * np.sin(np.pi * z_vertices) mass = pybamm.Mass(var) mass_disc = disc.process_symbol(mass) soln = -np.pi**2 * u np.testing.assert_array_almost_equal(laplace_eqn_disc.evaluate( None, u), mass_disc.entries @ soln, decimal=1)