Exemplo n.º 1
0
    def test_extrapolate_on_nonuniform_grid(self):
        geometry = pybamm.Geometry("1D micro")

        submesh_types = {
            "negative particle": pybamm.MeshGenerator(pybamm.Exponential1DSubMesh),
            "positive particle": pybamm.MeshGenerator(pybamm.Exponential1DSubMesh),
        }

        var = pybamm.standard_spatial_vars
        rpts = 10
        var_pts = {var.r_n: rpts, var.r_p: rpts}
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)
        method_options = {"extrapolation": {"order": "linear", "use bcs": False}}
        spatial_methods = {"negative particle": pybamm.FiniteVolume(method_options)}
        disc = pybamm.Discretisation(mesh, spatial_methods)

        var = pybamm.Variable("var", domain="negative particle")
        surf_eqn = pybamm.surf(var)
        disc.set_variable_slices([var])
        surf_eqn_disc = disc.process_symbol(surf_eqn)

        micro_submesh = mesh["negative particle"]

        # check constant extrapolates to constant
        constant_y = np.ones_like(micro_submesh[0].nodes[:, np.newaxis])
        np.testing.assert_array_almost_equal(
            surf_eqn_disc.evaluate(None, constant_y), 1
        )

        # check linear variable extrapolates correctly
        linear_y = micro_submesh[0].nodes
        y_surf = micro_submesh[0].edges[-1]
        np.testing.assert_array_almost_equal(
            surf_eqn_disc.evaluate(None, linear_y), y_surf
        )
Exemplo n.º 2
0
 def default_submesh_types(self):
     if self.options["dimensionality"] == 1:
         return {"current collector": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)}
     elif self.options["dimensionality"] == 2:
         return {
             "current collector": pybamm.MeshGenerator(pybamm.ScikitUniform2DSubMesh)
         }
Exemplo n.º 3
0
    def test_exceptions(self):
        edges = np.array([0, 0.3, 1])
        submesh_params = {"edges": edges}
        mesh = pybamm.MeshGenerator(pybamm.UserSupplied1DSubMesh,
                                    submesh_params)

        x_n = pybamm.standard_spatial_vars.x_n

        # error if npts+1 != len(edges)
        lims = {x_n: {"min": 0, "max": 1}}
        npts = {x_n.id: 10}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # error if lims[0] not equal to edges[0]
        lims = {x_n: {"min": 0.1, "max": 1}}
        npts = {x_n.id: len(edges) - 1}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # error if lims[-1] not equal to edges[-1]
        lims = {x_n: {"min": 0, "max": 10}}
        npts = {x_n.id: len(edges) - 1}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # no user points
        mesh = pybamm.MeshGenerator(pybamm.UserSupplied1DSubMesh)
        with self.assertRaisesRegex(pybamm.GeometryError,
                                    "User mesh requires"):
            mesh(None, None)
Exemplo n.º 4
0
def get_unit_2p1D_mesh_for_testing(ypts=15, zpts=15, include_particles=True):
    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.battery_geometry(
        include_particles=include_particles, current_collector_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_no_parameters(self):
        r = pybamm.SpatialVariable("r",
                                   domain=["negative particle"],
                                   coord_sys="spherical polar")

        geometry = {
            "negative particle": {
                r: {
                    "min": pybamm.Scalar(0),
                    "max": pybamm.Scalar(1)
                }
            }
        }

        edges = np.array([0, 0.3, 1])
        order = 3
        submesh_params = {"edges": edges, "order": order}
        submesh_types = {
            "negative particle":
            pybamm.MeshGenerator(pybamm.SpectralVolume1DSubMesh,
                                 submesh_params)
        }
        var_pts = {r: len(edges) - 1}

        # create mesh
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # check boundary locations
        self.assertEqual(mesh["negative particle"].edges[0], 0)
        self.assertEqual(mesh["negative particle"].edges[-1], 1)

        # check number of edges and nodes
        self.assertEqual(len(mesh["negative particle"].sv_nodes), var_pts[r])
        self.assertEqual(len(mesh["negative particle"].nodes),
                         order * var_pts[r])
        self.assertEqual(
            len(mesh["negative particle"].edges),
            len(mesh["negative particle"].nodes) + 1,
        )

        # check Chebyshev subdivision locations
        for (a, b) in zip(mesh["negative particle"].edges.tolist(),
                          [0, 0.075, 0.225, 0.3, 0.475, 0.825, 1]):
            self.assertAlmostEqual(a, b)

        # test uniform submesh creation
        submesh_params = {"order": order}
        submesh_types = {
            "negative particle":
            pybamm.MeshGenerator(pybamm.SpectralVolume1DSubMesh,
                                 submesh_params)
        }
        var_pts = {r: 2}

        # create mesh
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)
        for (a, b) in zip(mesh["negative particle"].edges.tolist(),
                          [0.0, 0.125, 0.375, 0.5, 0.625, 0.875, 1.0]):
            self.assertAlmostEqual(a, b)
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
    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.battery_geometry(include_particles=False,
                                           current_collector_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.assertRaisesRegex(
                pybamm.DiscretisationError,
                "Parameter values have not yet been set for geometry",
        ):
            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)

        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)

        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)
        var.z.coord_sys = "cartesian"
Exemplo n.º 8
0
    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.battery_geometry(include_particles=False,
                                           current_collector_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}

        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),
        }

        # create mesh
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # check boundary locations
        self.assertEqual(mesh["negative electrode"].edges[0], 0)
        self.assertEqual(mesh["positive electrode"].edges[-1], 1)

        # check internal boundary locations
        self.assertEqual(mesh["negative electrode"].edges[-1],
                         mesh["separator"].edges[0])
        self.assertEqual(mesh["positive electrode"].edges[0],
                         mesh["separator"].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].npts, npts)
            else:
                self.assertEqual(len(mesh[domain].edges),
                                 len(mesh[domain].nodes) + 1)
Exemplo n.º 9
0
    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"
Exemplo n.º 10
0
    def test_mesh_creation_no_parameters(self):
        r = pybamm.SpatialVariable("r",
                                   domain=["negative particle"],
                                   coord_sys="spherical polar")

        geometry = {
            "negative particle": {
                "primary": {
                    r: {
                        "min": pybamm.Scalar(0),
                        "max": pybamm.Scalar(1)
                    }
                }
            }
        }

        submesh_types = {
            "negative particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)
        }
        var_pts = {r: 20}
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # create mesh
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # check boundary locations
        self.assertEqual(mesh["negative particle"][0].edges[0], 0)
        self.assertEqual(mesh["negative particle"][0].edges[-1], 1)

        # check number of edges and nodes
        self.assertEqual(len(mesh["negative particle"][0].nodes), var_pts[r])
        self.assertEqual(
            len(mesh["negative particle"][0].edges),
            len(mesh["negative particle"][0].nodes) + 1,
        )
Exemplo n.º 11
0
def get_1p1d_mesh_for_testing(
    xpts=None, zpts=15, cc_submesh=pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)
):
    geometry = pybamm.battery_geometry(current_collector_dimension=1)
    return get_mesh_for_testing(
        xpts=xpts, zpts=zpts, geometry=geometry, cc_submesh=cc_submesh
    )
Exemplo n.º 12
0
    def test_symmetric_mesh_creation_no_parameters_odd(self):
        r = pybamm.SpatialVariable("r",
                                   domain=["negative particle"],
                                   coord_sys="spherical polar")

        geometry = {
            "negative particle": {
                r: {
                    "min": pybamm.Scalar(0),
                    "max": pybamm.Scalar(1)
                }
            }
        }

        submesh_params = {"side": "symmetric", "stretch": 1.5}
        submesh_types = {
            "negative particle":
            pybamm.MeshGenerator(pybamm.Exponential1DSubMesh, submesh_params)
        }
        var_pts = {r: 21}

        # create mesh
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # check boundary locations
        self.assertEqual(mesh["negative particle"].edges[0], 0)
        self.assertEqual(mesh["negative particle"].edges[-1], 1)

        # check number of edges and nodes
        self.assertEqual(len(mesh["negative particle"].nodes), var_pts[r])
        self.assertEqual(
            len(mesh["negative particle"].edges),
            len(mesh["negative particle"].nodes) + 1,
        )
Exemplo n.º 13
0
    def test_mesh_creation_no_parameters(self):
        r = pybamm.SpatialVariable("r",
                                   domain=["negative particle"],
                                   coord_sys="spherical polar")

        geometry = {
            "negative particle": {
                r: {
                    "min": pybamm.Scalar(0),
                    "max": pybamm.Scalar(1)
                }
            }
        }

        edges = np.array([0, 0.3, 1])
        submesh_params = {"edges": edges}
        submesh_types = {
            "negative particle":
            pybamm.MeshGenerator(pybamm.UserSupplied1DSubMesh, submesh_params)
        }
        var_pts = {r: len(edges) - 1}

        # create mesh
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # check boundary locations
        self.assertEqual(mesh["negative particle"].edges[0], 0)
        self.assertEqual(mesh["negative particle"].edges[-1], 1)

        # check number of edges and nodes
        self.assertEqual(len(mesh["negative particle"].nodes), var_pts[r])
        self.assertEqual(
            len(mesh["negative particle"].edges),
            len(mesh["negative particle"].nodes) + 1,
        )
Exemplo n.º 14
0
def get_1p1d_mesh_for_testing(
    xpts=None, zpts=15, cc_submesh=pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)
):
    geometry = pybamm.Geometry("1+1D macro")
    return get_mesh_for_testing(
        xpts=xpts, zpts=zpts, geometry=geometry, cc_submesh=cc_submesh
    )
Exemplo n.º 15
0
def errors(pts, function, method_options, bcs=None):

    domain = "test"
    x = pybamm.SpatialVariable("x", domain=domain)
    geometry = {
        domain: {"primary": {x: {"min": pybamm.Scalar(0), "max": pybamm.Scalar(1)}}}
    }
    submesh_types = {domain: pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)}
    var_pts = {x: pts}
    mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

    spatial_methods = {"test": pybamm.FiniteVolume(method_options)}
    disc = pybamm.Discretisation(mesh, spatial_methods)

    var = pybamm.Variable("var", domain="test")
    left_extrap = pybamm.BoundaryValue(var, "left")
    right_extrap = pybamm.BoundaryValue(var, "right")

    if bcs:
        model = pybamm.BaseBatteryModel()
        bc_dict = {var: bcs}
        model.boundary_conditions = bc_dict
        disc.bcs = disc.process_boundary_conditions(model)

    submesh = mesh["test"]
    y, l_true, r_true = function(submesh[0].nodes)

    disc.set_variable_slices([var])
    left_extrap_processed = disc.process_symbol(left_extrap)
    right_extrap_processed = disc.process_symbol(right_extrap)

    l_error = np.abs(l_true - left_extrap_processed.evaluate(None, y))
    r_error = np.abs(r_true - right_extrap_processed.evaluate(None, y))

    return l_error, r_error
Exemplo n.º 16
0
    def test_adding_1D_external_variable(self):
        model = pybamm.BaseModel()

        a = pybamm.Variable("a", domain=["test"])
        b = pybamm.Variable("b", domain=["test"])

        model.rhs = {a: a * b}
        model.boundary_conditions = {
            a: {
                "left": (0, "Dirichlet"),
                "right": (0, "Dirichlet")
            }
        }
        model.initial_conditions = {a: 0}
        model.external_variables = [b]
        model.variables = {
            "a": a,
            "b": b,
            "c": a * b,
            "grad b": pybamm.grad(b),
            "div grad b": pybamm.div(pybamm.grad(b)),
        }

        x = pybamm.SpatialVariable("x", domain="test", coord_sys="cartesian")
        geometry = {
            "test": {
                "primary": {
                    x: {
                        "min": pybamm.Scalar(0),
                        "max": pybamm.Scalar(1)
                    }
                }
            }
        }

        submesh_types = {"test": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)}
        var_pts = {x: 10}
        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        spatial_methods = {"test": pybamm.FiniteVolume()}
        disc = pybamm.Discretisation(mesh, spatial_methods)
        disc.process_model(model)

        self.assertEqual(disc.y_slices[a.id][0], slice(0, 10, None))

        self.assertEqual(model.y_slices[a][0], slice(0, 10, None))

        b_test = np.ones((10, 1))
        np.testing.assert_array_equal(
            model.variables["b"].evaluate(inputs={"b": b_test}), b_test)

        # check that b is added to the boundary conditions
        model.bcs[b.id]["left"]
        model.bcs[b.id]["right"]

        # check that grad and div(grad ) produce the correct shapes
        self.assertEqual(model.variables["b"].shape_for_testing, (10, 1))
        self.assertEqual(model.variables["grad b"].shape_for_testing, (11, 1))
        self.assertEqual(model.variables["div grad b"].shape_for_testing,
                         (10, 1))
    def test_exceptions(self):
        edges = np.array([0, 0.3, 1])
        submesh_params = {"edges": edges}
        mesh = pybamm.MeshGenerator(pybamm.SpectralVolume1DSubMesh,
                                    submesh_params)

        x_n = pybamm.standard_spatial_vars.x_n

        # error if npts+1 != len(edges)
        lims = {x_n: {"min": 0, "max": 1}}
        npts = {x_n.id: 10}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # error if lims[0] not equal to edges[0]
        lims = {x_n: {"min": 0.1, "max": 1}}
        npts = {x_n.id: len(edges) - 1}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # error if lims[-1] not equal to edges[-1]
        lims = {x_n: {"min": 0, "max": 10}}
        npts = {x_n.id: len(edges) - 1}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)
Exemplo n.º 18
0
    def test_exceptions(self):
        var = pybamm.standard_spatial_vars
        lims = {var.y: {"min": 0, "max": 1}}
        y_edges = np.array([0, 0.3, 1])
        z_edges = np.array([0, 0.3, 1])
        submesh_params = {"y_edges": y_edges, "z_edges": z_edges}
        mesh = pybamm.MeshGenerator(pybamm.UserSupplied2DSubMesh,
                                    submesh_params)
        # test not enough lims
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, None)
        lims = {var.y: {"min": 0, "max": 1}, var.z: {"min": 0, "max": 1}}

        # error if len(edges) != npts
        npts = {var.y.id: 10, var.z.id: 3}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # error if lims[0] not equal to edges[0]
        lims = {var.y: {"min": 0.1, "max": 1}, var.z: {"min": 0, "max": 1}}
        npts = {var.y.id: 3, var.z.id: 3}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # error if lims[-1] not equal to edges[-1]
        lims = {var.y: {"min": 0, "max": 1}, var.z: {"min": 0, "max": 1.3}}
        npts = {var.y.id: 3, var.z.id: 3}
        with self.assertRaises(pybamm.GeometryError):
            mesh(lims, npts)

        # error if different coordinate system
        lims = {var.y: {"min": 0, "max": 1}, var.r_n: {"min": 0, "max": 1}}
        npts = {var.y.id: 3, var.r_n.id: 3}
        with self.assertRaises(pybamm.DomainError):
            mesh(lims, npts)

        mesh = pybamm.MeshGenerator(pybamm.UserSupplied2DSubMesh)
        with self.assertRaisesRegex(pybamm.GeometryError,
                                    "User mesh requires"):
            mesh(None, None)

        submesh_params = {"y_edges": np.array([0, 0.3, 1])}
        mesh = pybamm.MeshGenerator(pybamm.UserSupplied2DSubMesh,
                                    submesh_params)
        with self.assertRaisesRegex(pybamm.GeometryError,
                                    "User mesh requires"):
            mesh(None, None)
Exemplo n.º 19
0
    def test_multiple_meshes_macro(self):
        param = pybamm.ParameterValues(
            values={
                "Negative electrode thickness [m]": 0.1,
                "Separator thickness [m]": 0.2,
                "Positive electrode thickness [m]": 0.3,
                "Electrode height [m]": 0.4,
                "Negative tab centre z-coordinate [m]": 0.0,
                "Positive tab centre z-coordinate [m]": 0.4,
            })

        geometry = pybamm.Geometry("1+1D macro")
        param.process_geometry(geometry)
        # provide mesh properties

        var = pybamm.standard_spatial_vars
        var_pts = {var.x_n: 10, var.x_s: 15, var.x_p: 20, var.z: 5}
        submesh_types = {
            "negative electrode":
            pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "positive electrode":
            pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "current collector": pybamm.MeshGenerator(pybamm.SubMesh0D),
        }

        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # check types
        self.assertIsInstance(mesh["negative electrode"], list)
        self.assertIsInstance(mesh["separator"], list)
        self.assertIsInstance(mesh["positive electrode"], list)
        self.assertEqual(len(mesh["negative electrode"]), 5)
        self.assertEqual(len(mesh["separator"]), 5)
        self.assertEqual(len(mesh["positive electrode"]), 5)

        for i in range(5):
            self.assertIsInstance(mesh["negative electrode"][i],
                                  pybamm.Uniform1DSubMesh)
            self.assertIsInstance(mesh["separator"][i],
                                  pybamm.Uniform1DSubMesh)
            self.assertIsInstance(mesh["positive electrode"][i],
                                  pybamm.Uniform1DSubMesh)
            self.assertEqual(mesh["negative electrode"][i].npts, 10)
            self.assertEqual(mesh["separator"][i].npts, 15)
            self.assertEqual(mesh["positive electrode"][i].npts, 20)
Exemplo n.º 20
0
def get_2p1d_mesh_for_testing(
    xpts=None,
    ypts=15,
    zpts=15,
    cc_submesh=pybamm.MeshGenerator(pybamm.ScikitUniform2DSubMesh),
):
    geometry = pybamm.Geometry("2+1D macro")
    return get_mesh_for_testing(
        xpts=xpts, zpts=zpts, geometry=geometry, cc_submesh=cc_submesh
    )
Exemplo n.º 21
0
def get_mesh_for_testing(
    xpts=None, rpts=10, ypts=15, zpts=15, geometry=None, cc_submesh=None, order=2
):
    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.0,
            "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,
        }
    )

    if geometry is None:
        geometry = pybamm.battery_geometry()
    param.process_geometry(geometry)

    submesh_types = {
        "negative electrode": pybamm.MeshGenerator(
            pybamm.SpectralVolume1DSubMesh, {"order": order}
        ),
        "separator": pybamm.MeshGenerator(
            pybamm.SpectralVolume1DSubMesh, {"order": order}
        ),
        "positive electrode": pybamm.MeshGenerator(
            pybamm.SpectralVolume1DSubMesh, {"order": order}
        ),
        "negative particle": pybamm.MeshGenerator(
            pybamm.SpectralVolume1DSubMesh, {"order": order}
        ),
        "positive particle": pybamm.MeshGenerator(
            pybamm.SpectralVolume1DSubMesh, {"order": order}
        ),
        "current collector": pybamm.MeshGenerator(pybamm.SubMesh0D),
    }
    if cc_submesh:
        submesh_types["current collector"] = cc_submesh

    if xpts is None:
        xn_pts, xs_pts, xp_pts = 40, 25, 35
    else:
        xn_pts, xs_pts, xp_pts = xpts, xpts, xpts
    var = pybamm.standard_spatial_vars
    var_pts = {
        var.x_n: xn_pts,
        var.x_s: xs_pts,
        var.x_p: xp_pts,
        var.r_n: rpts,
        var.r_p: rpts,
        var.y: ypts,
        var.z: zpts,
    }

    return pybamm.Mesh(geometry, submesh_types, var_pts)
Exemplo n.º 22
0
def get_2p1d_mesh_for_testing(
    xpts=None,
    ypts=15,
    zpts=15,
    include_particles=True,
    cc_submesh=pybamm.MeshGenerator(pybamm.ScikitUniform2DSubMesh),
):
    geometry = pybamm.battery_geometry(
        include_particles=include_particles, current_collector_dimension=2
    )
    return get_mesh_for_testing(
        xpts=xpts, zpts=zpts, geometry=geometry, cc_submesh=cc_submesh
    )
Exemplo n.º 23
0
    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)
Exemplo n.º 24
0
    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")
Exemplo n.º 25
0
    def test_tab_left_right(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),
        }

        # 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.0,
                "Negative tab centre z-coordinate [m]": 0.25,
                "Positive tab centre y-coordinate [m]": 0.4,
                "Positive tab centre z-coordinate [m]": 0.25,
                "Positive tab width [m]": 0.1,
                "Negative electrode thickness [m]": 0.3,
                "Separator thickness [m]": 0.3,
                "Positive electrode thickness [m]": 0.3,
            })

        # check mesh can be built
        geometry = pybamm.battery_geometry(include_particles=False,
                                           current_collector_dimension=2)
        param.process_geometry(geometry)
        pybamm.Mesh(geometry, submesh_types, var_pts)
Exemplo n.º 26
0
    def test_multiple_meshes(self):
        param = pybamm.ParameterValues(
            values={
                "Negative electrode thickness [m]": 0.1,
                "Separator thickness [m]": 0.2,
                "Positive electrode thickness [m]": 0.3,
            })

        geometry = pybamm.Geometry("1+1D micro")
        param.process_geometry(geometry)

        # provide mesh properties

        var = pybamm.standard_spatial_vars
        var_pts = {var.x_n: 10, var.x_p: 10, var.r_n: 5, var.r_p: 6}
        submesh_types = {
            "negative particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "positive particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "current collector": pybamm.MeshGenerator(pybamm.SubMesh0D),
        }

        mesh = pybamm.Mesh(geometry, submesh_types, var_pts)

        # check types
        self.assertIsInstance(mesh["negative particle"], list)
        self.assertIsInstance(mesh["positive particle"], list)
        self.assertEqual(len(mesh["negative particle"]), 10)
        self.assertEqual(len(mesh["positive particle"]), 10)

        for i in range(10):
            self.assertIsInstance(mesh["negative particle"][i],
                                  pybamm.Uniform1DSubMesh)
            self.assertIsInstance(mesh["positive particle"][i],
                                  pybamm.Uniform1DSubMesh)
            self.assertEqual(mesh["negative particle"][i].npts, 5)
            self.assertEqual(mesh["positive particle"][i].npts, 6)
Exemplo n.º 27
0
 def default_submesh_types(self):
     base_submeshes = {
         "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
         "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
         "positive electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
         "negative particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
         "positive particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
     }
     if self.options["dimensionality"] == 0:
         base_submeshes["current collector"] = pybamm.MeshGenerator(pybamm.SubMesh0D)
     elif self.options["dimensionality"] == 1:
         base_submeshes["current collector"] = pybamm.MeshGenerator(
             pybamm.Uniform1DSubMesh
         )
     elif self.options["dimensionality"] == 2:
         base_submeshes["current collector"] = pybamm.MeshGenerator(
             pybamm.ScikitUniform2DSubMesh
         )
     return base_submeshes
Exemplo n.º 28
0
    def test_mesh_sizes(self):
        param = pybamm.ParameterValues(
            values={
                "Negative electrode thickness [m]": 0.1,
                "Separator thickness [m]": 0.2,
                "Positive electrode thickness [m]": 0.3,
            })

        geometry = pybamm.Geometry1DMacro()
        param.process_geometry(geometry)

        # provide mesh properties
        var = pybamm.standard_spatial_vars
        var_pts = {
            var.x_n: 10,
            var.x_s: 10,
            var.x_p: 12,
            var.r_n: 5,
            var.r_p: 6
        }
        submesh_types = {
            "negative electrode":
            pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "positive electrode":
            pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "negative particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "positive particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "current collector": pybamm.MeshGenerator(pybamm.SubMesh0D),
        }

        mesh_type = pybamm.Mesh

        # create mesh
        mesh = mesh_type(geometry, submesh_types, var_pts)

        var_id_pts = {var.id: pts for var, pts in var_pts.items()}

        self.assertEqual(mesh["negative electrode"][0].npts,
                         var_id_pts[var.x_n.id])
        self.assertEqual(mesh["separator"][0].npts, var_id_pts[var.x_s.id])
        self.assertEqual(mesh["positive electrode"][0].npts,
                         var_id_pts[var.x_p.id])

        self.assertEqual(
            len(mesh["negative electrode"][0].edges) - 1,
            var_id_pts[var.x_n.id])
        self.assertEqual(
            len(mesh["separator"][0].edges) - 1, var_id_pts[var.x_s.id])
        self.assertEqual(
            len(mesh["positive electrode"][0].edges) - 1,
            var_id_pts[var.x_p.id])
Exemplo n.º 29
0
 def test_unimplemented_meshes(self):
     var = pybamm.standard_spatial_vars
     var_pts = {var.x_n: 10, var.y: 10}
     geometry = {
         "negative electrode": {
             var.x_n: {
                 "min": 0,
                 "max": 1
             },
             var.y: {
                 "min": 0,
                 "max": 1
             },
         }
     }
     submesh_types = {
         "negative electrode": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh)
     }
     with self.assertRaises(pybamm.GeometryError):
         pybamm.Mesh(geometry, submesh_types, var_pts)
Exemplo n.º 30
0
    def test_mesh_creation(self):
        param = pybamm.ParameterValues(
            values={
                "Negative electrode thickness [m]": 0.1,
                "Separator thickness [m]": 0.2,
                "Positive electrode thickness [m]": 0.3,
            })

        geometry = pybamm.Geometry1DMacro()
        param.process_geometry(geometry)

        var = pybamm.standard_spatial_vars
        var_pts = {
            var.x_n: 10,
            var.x_s: 10,
            var.x_p: 12,
            var.r_n: 5,
            var.r_p: 6
        }

        submesh_types = {
            "negative electrode":
            pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "separator": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "positive electrode":
            pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "negative particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "positive particle": pybamm.MeshGenerator(pybamm.Uniform1DSubMesh),
            "current collector": pybamm.MeshGenerator(pybamm.SubMesh0D),
        }

        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":
                self.assertEqual(len(mesh[domain][0].edges),
                                 len(mesh[domain][0].nodes) + 1)