Beispiel #1
0
    def test_yz_average(self):
        a = pybamm.Scalar(1)
        z_average_a = pybamm.z_average(a)
        yz_average_a = pybamm.yz_average(a)
        self.assertEqual(z_average_a.id, a.id)
        self.assertEqual(yz_average_a.id, a.id)

        z_average_broad_a = pybamm.z_average(
            pybamm.PrimaryBroadcast(a, ["current collector"]))
        yz_average_broad_a = pybamm.yz_average(
            pybamm.PrimaryBroadcast(a, ["current collector"]))
        self.assertEqual(z_average_broad_a.evaluate(), np.array([1]))
        self.assertEqual(yz_average_broad_a.evaluate(), np.array([1]))

        a = pybamm.Variable("a", domain=["current collector"])
        y = pybamm.SpatialVariable("y", ["current collector"])
        z = pybamm.SpatialVariable("z", ["current collector"])
        z_av_a = pybamm.z_average(a)
        yz_av_a = pybamm.yz_average(a)

        self.assertIsInstance(yz_av_a, pybamm.Division)
        self.assertIsInstance(z_av_a, pybamm.Division)
        self.assertIsInstance(z_av_a.children[0], pybamm.Integral)
        self.assertIsInstance(yz_av_a.children[0], pybamm.Integral)
        self.assertEqual(z_av_a.children[0].integration_variable[0].domain,
                         z.domain)
        self.assertEqual(yz_av_a.children[0].integration_variable[0].domain,
                         y.domain)
        self.assertEqual(yz_av_a.children[0].integration_variable[1].domain,
                         z.domain)
        self.assertIsInstance(z_av_a.children[1], pybamm.Integral)
        self.assertIsInstance(yz_av_a.children[1], pybamm.Integral)
        self.assertEqual(z_av_a.children[1].integration_variable[0].domain,
                         a.domain)
        self.assertEqual(z_av_a.children[1].children[0].id,
                         pybamm.ones_like(a).id)
        self.assertEqual(yz_av_a.children[1].integration_variable[0].domain,
                         y.domain)
        self.assertEqual(yz_av_a.children[1].integration_variable[0].domain,
                         z.domain)
        self.assertEqual(yz_av_a.children[1].children[0].id,
                         pybamm.ones_like(a).id)
        self.assertEqual(z_av_a.domain, [])
        self.assertEqual(yz_av_a.domain, [])

        a = pybamm.Symbol("a", domain="bad domain")
        with self.assertRaises(pybamm.DomainError):
            pybamm.z_average(a)
        with self.assertRaises(pybamm.DomainError):
            pybamm.yz_average(a)

        # average of symbol that evaluates on edges raises error
        symbol_on_edges = pybamm.PrimaryBroadcastToEdges(1, "domain")
        with self.assertRaisesRegex(
                ValueError,
                "Can't take the z-average of a symbol that evaluates on edges"
        ):
            pybamm.z_average(symbol_on_edges)
Beispiel #2
0
    def get_fundamental_variables(self):
        # Get necessary parameters
        param = self.param
        l_cn = param.l_cn
        l_cp = param.l_cp
        sigma_cn_dbl_prime = param.sigma_cn_dbl_prime
        sigma_cp_dbl_prime = param.sigma_cp_dbl_prime
        delta = param.delta  # aspect ratio

        # Set model variables: Note: we solve using a scaled version that is
        # better conditioned
        R_cn_scaled = pybamm.Variable(
            "Scaled negative current collector resistance", domain="current collector"
        )
        R_cp_scaled = pybamm.Variable(
            "Scaled positive current collector resistance", domain="current collector"
        )
        R_cn = delta * R_cn_scaled / (l_cn * sigma_cn_dbl_prime)
        R_cp = delta * R_cp_scaled / (l_cp * sigma_cp_dbl_prime)

        # Define effective current collector resistance
        if self.options["dimensionality"] == 1:
            R_cc_n = -pybamm.z_average(R_cn)
            R_cc_p = -pybamm.z_average(R_cp)
        elif self.options["dimensionality"] == 2:
            R_cc_n = -pybamm.yz_average(R_cn)
            R_cc_p = -pybamm.yz_average(R_cp)
        R_cc = R_cc_n + R_cc_p
        R_scale = param.potential_scale / param.I_typ

        variables = {
            "Scaled negative current collector resistance": R_cn_scaled,
            "Negative current collector resistance": R_cn,
            "Negative current collector resistance [Ohm]": R_cn * R_scale,
            "Scaled positive current collector resistance": R_cp_scaled,
            "Positive current collector resistance": R_cp,
            "Positive current collector resistance [Ohm]": R_cp * R_scale,
            "Effective current collector resistance": R_cc,
            "Effective current collector resistance [Ohm]": R_cc * R_scale,
            "Effective negative current collector resistance": R_cc_n,
            "Effective negative current collector resistance [Ohm]": R_cc_n * R_scale,
            "Effective positive current collector resistance": R_cc_p,
            "Effective positive current collector resistance [Ohm]": R_cc_p * R_scale,
        }

        # Add spatial variables
        var = pybamm.standard_spatial_vars
        L_y = pybamm.geometric_parameters.L_y
        L_z = pybamm.geometric_parameters.L_z
        if self.options["dimensionality"] == 1:
            variables.update({"z": var.z, "z [m]": var.z * L_z})
        elif self.options["dimensionality"] == 2:
            variables.update(
                {"y": var.y, "y [m]": var.y * L_y, "z": var.z, "z [m]": var.z * L_z}
            )

        return variables
Beispiel #3
0
 def _yz_average(self, var):
     "Computes the y-z average"
     # TODO: change the behaviour of z_average and yz_average so the if statement
     # can be removed
     if self.cc_dimension in [0, 1]:
         return pybamm.z_average(var)
     elif self.cc_dimension == 2:
         return pybamm.yz_average(var)
Beispiel #4
0
    def test_yz_average(self):
        a = pybamm.Scalar(1)
        z_average_a = pybamm.z_average(a)
        yz_average_a = pybamm.yz_average(a)
        self.assertEqual(z_average_a.id, a.id)
        self.assertEqual(yz_average_a.id, a.id)

        z_average_broad_a = pybamm.z_average(
            pybamm.Broadcast(a, ["current collector"]))
        yz_average_broad_a = pybamm.yz_average(
            pybamm.Broadcast(a, ["current collector"]))
        self.assertEqual(z_average_broad_a.evaluate(), np.array([1]))
        self.assertEqual(yz_average_broad_a.evaluate(), np.array([1]))

        a = pybamm.Symbol("a", domain=["current collector"])
        y = pybamm.SpatialVariable("y", ["current collector"])
        z = pybamm.SpatialVariable("z", ["current collector"])
        z_av_a = pybamm.z_average(a)
        yz_av_a = pybamm.yz_average(a)

        self.assertIsInstance(z_av_a, pybamm.Division)
        self.assertIsInstance(yz_av_a, pybamm.Division)
        self.assertIsInstance(z_av_a.children[0], pybamm.Integral)
        self.assertIsInstance(yz_av_a.children[0], pybamm.Integral)
        self.assertEqual(z_av_a.children[0].integration_variable[0].domain,
                         z.domain)
        self.assertEqual(yz_av_a.children[0].integration_variable[0].domain,
                         y.domain)
        self.assertEqual(yz_av_a.children[0].integration_variable[1].domain,
                         z.domain)
        self.assertEqual(z_av_a.domain, [])
        self.assertEqual(yz_av_a.domain, [])

        a = pybamm.Symbol("a", domain="bad domain")
        with self.assertRaises(pybamm.DomainError):
            pybamm.z_average(a)
        with self.assertRaises(pybamm.DomainError):
            pybamm.yz_average(a)
 def test_averages(self):
     # create discretisation
     disc = get_discretisation_for_testing(
         cc_method=pybamm.ZeroDimensionalSpatialMethod)
     # create and discretise variable
     var = pybamm.Variable("var", domain="current collector")
     disc.set_variable_slices([var])
     var_disc = disc.process_symbol(var)
     # check average returns the same value
     y = np.array([1])
     for expression in [pybamm.z_average(var), pybamm.yz_average(var)]:
         expr_disc = disc.process_symbol(expression)
         np.testing.assert_array_equal(var_disc.evaluate(y=y),
                                       expr_disc.evaluate(y=y))
Beispiel #6
0
    def __init__(self):
        super().__init__()
        self.name = "Effective resistance in current collector model (2D)"
        self.param = pybamm.standard_parameters_lithium_ion

        # Get necessary parameters
        param = self.param
        l_cn = param.l_cn
        l_cp = param.l_cp
        l_tab_p = param.l_tab_p
        A_tab_p = l_cp * l_tab_p
        sigma_cn_dbl_prime = param.sigma_cn_dbl_prime
        sigma_cp_dbl_prime = param.sigma_cp_dbl_prime
        delta = param.delta

        # Set model variables -- we solve a auxilliary problem in each current collector
        # then relate this to the potentials and resistances later
        f_n = pybamm.Variable("Unit solution in negative current collector",
                              domain="current collector")
        f_p = pybamm.Variable("Unit solution in positive current collector",
                              domain="current collector")

        # Governing equations -- we impose that the average of f_p is zero
        # by introducing a Lagrange multiplier
        c = pybamm.Variable("Lagrange multiplier")

        self.algebraic = {
            f_n:
            pybamm.laplacian(f_n) + pybamm.source(1, f_n),
            c:
            pybamm.laplacian(f_p) - pybamm.source(1, f_p) +
            c * pybamm.DefiniteIntegralVector(f_p, vector_type="column"),
            f_p:
            pybamm.yz_average(f_p) + 0 * c,
        }

        # Boundary conditons
        pos_tab_bc = l_cp / A_tab_p
        self.boundary_conditions = {
            f_n: {
                "negative tab": (0, "Dirichlet"),
                "positive tab": (0, "Neumann")
            },
            f_p: {
                "negative tab": (0, "Neumann"),
                "positive tab": (pos_tab_bc, "Neumann"),
            },
        }

        # "Initial conditions" provides initial guess for solver
        self.initial_conditions = {
            f_n: pybamm.Scalar(0),
            f_p: pybamm.Scalar(0),
            c: pybamm.Scalar(0),
        }

        # Define effective current collector resistance
        R_cc_n = delta * pybamm.yz_average(f_n) / (l_cn * sigma_cn_dbl_prime)
        R_cc_p = (delta * pybamm.BoundaryIntegral(f_p, "positive tab") /
                  (l_cp * sigma_cp_dbl_prime))
        R_cc = R_cc_n + R_cc_p
        R_scale = param.potential_scale / param.I_typ

        self.variables = {
            "Unit solution in negative current collector":
            f_n,
            "Unit solution in positive current collector":
            f_p,
            "Effective current collector resistance":
            R_cc,
            "Effective current collector resistance [Ohm]":
            R_cc * R_scale,
            "Effective negative current collector resistance":
            R_cc_n,
            "Effective negative current collector resistance [Ohm]":
            R_cc_n * R_scale,
            "Effective positive current collector resistance":
            R_cc_p,
            "Effective positive current collector resistance [Ohm]":
            R_cc_p * R_scale,
        }

        # Add spatial variables
        var = pybamm.standard_spatial_vars
        L_y = pybamm.geometric_parameters.L_y
        L_z = pybamm.geometric_parameters.L_z
        self.variables.update({
            "y": var.y,
            "y [m]": var.y * L_y,
            "z": var.z,
            "z [m]": var.z * L_z
        })

        pybamm.citations.register("timms2020")
 def _yz_average(self, var):
     """Computes the y-z average by integration over y and z"""
     return pybamm.yz_average(var)