Пример #1
0
    def test_boundary_integral(self):
        mesh = get_2p1d_mesh_for_testing(include_particles=False)
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "current collector": pybamm.ScikitFiniteElement(),
        }
        disc = pybamm.Discretisation(mesh, spatial_methods)
        var = pybamm.Variable("var", domain="current collector")
        disc.set_variable_slices([var])

        full = pybamm.BoundaryIntegral(var)
        neg = pybamm.BoundaryIntegral(var, region="negative tab")
        pos = pybamm.BoundaryIntegral(var, region="positive tab")

        full_disc = disc.process_symbol(full)
        neg_disc = disc.process_symbol(neg)
        pos_disc = disc.process_symbol(pos)

        # check integrating 1 gives correct *dimensionless* region lengths
        perimeter = 2 * (1 + 0.8)
        l_tab_n = 0.1 / 0.5
        l_tab_p = 0.1 / 0.5
        constant_y = np.ones(mesh["current collector"].npts)
        # Integral around boundary is exact
        np.testing.assert_array_almost_equal(
            full_disc.evaluate(None, constant_y), perimeter
        )
        # Ideally mesh edges should line up with tab edges.... then we would get
        # better agreement between actual and numerical tab width
        np.testing.assert_array_almost_equal(
            neg_disc.evaluate(None, constant_y), l_tab_n, decimal=1
        )
        np.testing.assert_array_almost_equal(
            pos_disc.evaluate(None, constant_y), l_tab_p, decimal=1
        )
Пример #2
0
    def test_mass_matrix_inverse(self):
        # get mesh
        mesh = get_2p1d_mesh_for_testing(ypts=5, zpts=5)
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "current collector": pybamm.ScikitFiniteElement(),
        }
        # create model
        a = pybamm.Variable("a", domain="negative electrode")
        b = pybamm.Variable("b", domain="current collector")
        model = pybamm.BaseModel()
        model.rhs = {a: pybamm.Laplacian(a), b: 4 * pybamm.Laplacian(b)}
        model.initial_conditions = {a: pybamm.Scalar(3), b: pybamm.Scalar(10)}
        model.boundary_conditions = {
            a: {"left": (0, "Neumann"), "right": (0, "Neumann")},
            b: {"negative tab": (0, "Neumann"), "positive tab": (0, "Neumann")},
        }
        model.variables = {"a": a, "b": b}

        # create discretisation
        disc = pybamm.Discretisation(mesh, spatial_methods)
        disc.process_model(model)

        # test that computing mass matrix block-by-block (as is done during
        # discretisation) gives the correct result
        # Note: inverse is more efficient in csc format
        mass_inv = inv(csc_matrix(model.mass_matrix.entries))
        np.testing.assert_equal(
            model.mass_matrix_inv.entries.toarray(), mass_inv.toarray()
        )
Пример #3
0
 def test_not_implemented(self):
     mesh = get_2p1d_mesh_for_testing(include_particles=False)
     spatial_method = pybamm.ScikitFiniteElement()
     spatial_method.build(mesh)
     self.assertEqual(spatial_method.mesh, mesh)
     with self.assertRaises(NotImplementedError):
         spatial_method.divergence(None, None, None)
     with self.assertRaises(NotImplementedError):
         spatial_method.indefinite_integral(None, None)
Пример #4
0
 def test_definite_integral(self):
     mesh = get_2p1d_mesh_for_testing()
     spatial_methods = {
         "macroscale": pybamm.FiniteVolume(),
         "current collector": pybamm.ScikitFiniteElement(),
     }
     disc = pybamm.Discretisation(mesh, spatial_methods)
     var = pybamm.Variable("var", domain="current collector")
     y = pybamm.SpatialVariable("y", ["current collector"])
     z = pybamm.SpatialVariable("z", ["current collector"])
     integral_eqn = pybamm.Integral(var, [y, z])
     disc.set_variable_slices([var])
     integral_eqn_disc = disc.process_symbol(integral_eqn)
     y_test = 6 * np.ones(mesh["current collector"][0].npts)
     fem_mesh = mesh["current collector"][0]
     ly = fem_mesh.coordinates[0, -1]
     lz = fem_mesh.coordinates[1, -1]
     np.testing.assert_array_almost_equal(
         integral_eqn_disc.evaluate(None, y_test), 6 * ly * lz)
Пример #5
0
    def test_neg_pos(self):
        mesh = get_2p1d_mesh_for_testing()
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "current collector": pybamm.ScikitFiniteElement(),
        }
        disc = pybamm.Discretisation(mesh, spatial_methods)
        var = pybamm.Variable("var", domain="current collector")
        disc.set_variable_slices([var])

        extrap_neg = pybamm.BoundaryValue(var, "negative tab")
        extrap_pos = pybamm.BoundaryValue(var, "positive tab")
        extrap_neg_disc = disc.process_symbol(extrap_neg)
        extrap_pos_disc = disc.process_symbol(extrap_pos)
        # check constant returns constant at tab
        constant_y = np.ones(mesh["current collector"][0].npts)[:, np.newaxis]
        np.testing.assert_array_almost_equal(
            extrap_neg_disc.evaluate(None, constant_y), 1)
        np.testing.assert_array_almost_equal(
            extrap_pos_disc.evaluate(None, constant_y), 1)
Пример #6
0
    def test_definite_integral_vector(self):
        mesh = get_2p1d_mesh_for_testing(include_particles=False)
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "current collector": pybamm.ScikitFiniteElement(),
        }
        disc = pybamm.Discretisation(mesh, spatial_methods)
        var = pybamm.Variable("var", domain="current collector")
        disc.set_variable_slices([var])

        # row (default)
        vec = pybamm.DefiniteIntegralVector(var)
        vec_disc = disc.process_symbol(vec)
        self.assertEqual(vec_disc.shape[0], 1)
        self.assertEqual(vec_disc.shape[1], mesh["current collector"].npts)

        # column
        vec = pybamm.DefiniteIntegralVector(var, vector_type="column")
        vec_disc = disc.process_symbol(vec)
        self.assertEqual(vec_disc.shape[0], mesh["current collector"].npts)
        self.assertEqual(vec_disc.shape[1], 1)
Пример #7
0
    def test_discretise_equations(self):
        # get mesh
        mesh = get_2p1d_mesh_for_testing(include_particles=False)
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "current collector": pybamm.ScikitFiniteElement(),
        }
        disc = pybamm.Discretisation(mesh, spatial_methods)
        # discretise some equations
        var = pybamm.Variable("var", domain="current collector")
        y = pybamm.SpatialVariable("y", ["current collector"])
        z = pybamm.SpatialVariable("z", ["current collector"])
        disc.set_variable_slices([var])
        y_test = np.ones(mesh["current collector"].npts)
        unit_source = pybamm.PrimaryBroadcast(1, "current collector")
        disc.bcs = {
            var.id: {
                "negative tab": (pybamm.Scalar(0), "Neumann"),
                "positive tab": (pybamm.Scalar(0), "Neumann"),
            }
        }

        for eqn in [
            pybamm.laplacian(var),
            pybamm.source(unit_source, var),
            pybamm.laplacian(var) - pybamm.source(unit_source, var),
            pybamm.source(var, var),
            pybamm.laplacian(var) - pybamm.source(2 * var, var),
            pybamm.laplacian(var) - pybamm.source(unit_source ** 2 + 1 / var, var),
            pybamm.Integral(var, [y, z]) - 1,
            pybamm.source(var, var, boundary=True),
            pybamm.laplacian(var) - pybamm.source(unit_source, var, boundary=True),
            pybamm.laplacian(var)
            - pybamm.source(unit_source ** 2 + 1 / var, var, boundary=True),
        ]:
            # Check that equation can be evaluated in each case
            # Dirichlet
            disc.bcs = {
                var.id: {
                    "negative tab": (pybamm.Scalar(0), "Dirichlet"),
                    "positive tab": (pybamm.Scalar(1), "Dirichlet"),
                }
            }
            eqn_disc = disc.process_symbol(eqn)
            eqn_disc.evaluate(None, y_test)
            # Neumann
            disc.bcs = {
                var.id: {
                    "negative tab": (pybamm.Scalar(0), "Neumann"),
                    "positive tab": (pybamm.Scalar(1), "Neumann"),
                }
            }
            eqn_disc = disc.process_symbol(eqn)
            eqn_disc.evaluate(None, y_test)
            # One of each
            disc.bcs = {
                var.id: {
                    "negative tab": (pybamm.Scalar(0), "Neumann"),
                    "positive tab": (pybamm.Scalar(1), "Dirichlet"),
                }
            }
            eqn_disc = disc.process_symbol(eqn)
            eqn_disc.evaluate(None, y_test)
            # One of each
            disc.bcs = {
                var.id: {
                    "negative tab": (pybamm.Scalar(0), "Dirichlet"),
                    "positive tab": (pybamm.Scalar(1), "Neumann"),
                }
            }
            eqn_disc = disc.process_symbol(eqn)
            eqn_disc.evaluate(None, y_test)

        # check  ValueError raised for non Dirichlet or Neumann BCs
        eqn = pybamm.laplacian(var) - pybamm.source(unit_source, var)
        disc.bcs = {
            var.id: {
                "negative tab": (pybamm.Scalar(0), "Dirichlet"),
                "positive tab": (pybamm.Scalar(1), "Other BC"),
            }
        }
        with self.assertRaises(ValueError):
            eqn_disc = disc.process_symbol(eqn)
        disc.bcs = {
            var.id: {
                "negative tab": (pybamm.Scalar(0), "Other BC"),
                "positive tab": (pybamm.Scalar(1), "Neumann"),
            }
        }
        with self.assertRaises(ValueError):
            eqn_disc = disc.process_symbol(eqn)

        # raise ModelError if no BCs provided
        new_var = pybamm.Variable("new_var", domain="current collector")
        disc.set_variable_slices([new_var])
        eqn = pybamm.laplacian(new_var)
        with self.assertRaises(pybamm.ModelError):
            eqn_disc = disc.process_symbol(eqn)

        # check GeometryError if using scikit-fem not in y or z
        x = pybamm.SpatialVariable("x", ["current collector"])
        with self.assertRaises(pybamm.GeometryError):
            disc.process_symbol(x)