Example #1
0
def div(symbol):
    """
    convenience function for creating a :class:`Divergence`

    Parameters
    ----------

    symbol : :class:`Symbol`
        the divergence will be performed on this sub-symbol

    Returns
    -------

    :class:`Divergence`
        the divergence of ``symbol``
    """
    # Divergence of a broadcast is zero
    if isinstance(symbol, pybamm.PrimaryBroadcastToEdges):
        new_child = pybamm.PrimaryBroadcast(0, symbol.child.domain)
        return pybamm.PrimaryBroadcast(new_child, symbol.domain)
    # Divergence commutes with Negate operator
    if isinstance(symbol, pybamm.Negate):
        return -div(symbol.orphans[0])
    else:
        return Divergence(symbol)
    def _get_coupled_variables_from_potential(self, variables, phi_e_av):
        i_boundary_cc = variables["Current collector current density"]

        param = self.param
        l_n = param.l_n
        l_p = param.l_p
        x_n = pybamm.standard_spatial_vars.x_n
        x_p = pybamm.standard_spatial_vars.x_p

        phi_e_n = pybamm.PrimaryBroadcast(phi_e_av, ["negative electrode"])
        phi_e_s = pybamm.PrimaryBroadcast(phi_e_av, ["separator"])
        phi_e_p = pybamm.PrimaryBroadcast(phi_e_av, ["positive electrode"])
        phi_e = pybamm.Concatenation(phi_e_n, phi_e_s, phi_e_p)

        i_e_n = pybamm.outer(i_boundary_cc, x_n / l_n)
        i_e_s = pybamm.PrimaryBroadcast(i_boundary_cc, ["separator"])
        i_e_p = pybamm.outer(i_boundary_cc, (1 - x_p) / l_p)
        i_e = pybamm.Concatenation(i_e_n, i_e_s, i_e_p)

        variables.update(self._get_standard_potential_variables(phi_e, phi_e_av))
        variables.update(self._get_standard_current_variables(i_e))

        eta_c_av = pybamm.Scalar(0)  # concentration overpotential
        delta_phi_e_av = pybamm.Scalar(0)  # ohmic losses
        variables.update(self._get_split_overpotential(eta_c_av, delta_phi_e_av))

        return variables
    def test_concatenation_simplify(self):
        # Primary broadcast
        var = pybamm.Variable("var", "current collector")
        a = pybamm.PrimaryBroadcast(var, "negative electrode")
        b = pybamm.PrimaryBroadcast(var, "separator")
        c = pybamm.PrimaryBroadcast(var, "positive electrode")

        concat = pybamm.concatenation(a, b, c)
        self.assertIsInstance(concat, pybamm.PrimaryBroadcast)
        self.assertEqual(concat.orphans[0], var)
        self.assertEqual(
            concat.domain,
            ["negative electrode", "separator", "positive electrode"])

        # Full broadcast
        a = pybamm.FullBroadcast(0, "negative electrode", "current collector")
        b = pybamm.FullBroadcast(0, "separator", "current collector")
        c = pybamm.FullBroadcast(0, "positive electrode", "current collector")

        concat = pybamm.concatenation(a, b, c)
        self.assertIsInstance(concat, pybamm.FullBroadcast)
        self.assertEqual(concat.orphans[0].id, pybamm.Scalar(0).id)
        self.assertEqual(
            concat.domain,
            ["negative electrode", "separator", "positive electrode"])
        self.assertEqual(concat.auxiliary_domains,
                         {"secondary": ["current collector"]})
    def nasty_hack_to_get_phi_s(self, variables):
        "This restates what is already in the electrode submodel which we should not do"

        param = self.param

        x_n = pybamm.standard_spatial_vars.x_n
        x_p = pybamm.standard_spatial_vars.x_p
        eps = variables[self.domain + " electrode porosity"]
        i_boundary_cc = variables["Current collector current density"]
        i_e = variables[self.domain + " electrolyte current density"]

        i_s = pybamm.PrimaryBroadcast(i_boundary_cc, self.domain_for_broadcast) - i_e

        if self.domain == "Negative":
            conductivity = param.sigma_n * (1 - eps) ** param.b_n
            phi_s = -pybamm.IndefiniteIntegral(i_s / conductivity, x_n)

        elif self.domain == "Positive":

            phi_e_s = variables["Separator electrolyte potential"]
            delta_phi_p = variables["Positive electrode surface potential difference"]

            conductivity = param.sigma_p * (1 - eps) ** param.b_p

            phi_s = -pybamm.IndefiniteIntegral(
                i_s / conductivity, x_p
            ) + pybamm.PrimaryBroadcast(
                pybamm.boundary_value(phi_e_s, "right")
                + pybamm.boundary_value(delta_phi_p, "left"),
                "positive electrode",
            )

        return phi_s
Example #5
0
    def format(self, left, right):
        "Format children left and right into compatible form"
        # Turn numbers into scalars
        if isinstance(left, numbers.Number):
            left = pybamm.Scalar(left)
        if isinstance(right, numbers.Number):
            right = pybamm.Scalar(right)

        # Check both left and right are pybamm Symbols
        if not (isinstance(left, pybamm.Symbol) and isinstance(right, pybamm.Symbol)):
            raise NotImplementedError(
                """'{}' not implemented for symbols of type {} and {}""".format(
                    self.__class__.__name__, type(left), type(right)
                )
            )

        # Do some broadcasting in special cases, to avoid having to do this manually
        if left.domain != [] and right.domain != []:
            if (
                left.domain != right.domain
                and "secondary" in right.auxiliary_domains
                and left.domain == right.auxiliary_domains["secondary"]
            ):
                left = pybamm.PrimaryBroadcast(left, right.domain)
            if (
                right.domain != left.domain
                and "secondary" in left.auxiliary_domains
                and right.domain == left.auxiliary_domains["secondary"]
            ):
                right = pybamm.PrimaryBroadcast(right, left.domain)

        return left, right
Example #6
0
    def set_rhs(self, variables):
        "Composite reaction-diffusion with source terms from leading order"

        param = self.param

        eps_0 = variables["Leading-order porosity"]
        deps_0_dt = variables["Leading-order porosity change"]
        c_e = variables["Electrolyte concentration"]
        N_e = variables["Electrolyte flux"]
        if self.extended is False:
            sum_s_j = variables[
                "Leading-order sum of electrolyte reaction source terms"
            ]
        elif self.extended == "distributed":
            sum_s_j = variables["Sum of electrolyte reaction source terms"]
        elif self.extended == "average":
            sum_s_j_n_av = variables[
                "Sum of x-averaged negative electrode electrolyte reaction source terms"
            ]
            sum_s_j_p_av = variables[
                "Sum of x-averaged positive electrode electrolyte reaction source terms"
            ]
            sum_s_j = pybamm.Concatenation(
                pybamm.PrimaryBroadcast(sum_s_j_n_av, "negative electrode"),
                pybamm.FullBroadcast(0, "separator", "current collector"),
                pybamm.PrimaryBroadcast(sum_s_j_p_av, "positive electrode"),
            )
        source_terms = sum_s_j / self.param.gamma_e

        self.rhs = {
            c_e: (1 / eps_0)
            * (-pybamm.div(N_e) / param.C_e + source_terms - c_e * deps_0_dt)
        }
Example #7
0
    def test_public_functions(self):
        param = pybamm.standard_parameters_lead_acid

        a = pybamm.Scalar(0)
        a_n = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["negative electrode"])
        a_p = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["positive electrode"])
        variables = {
            "Current collector current density": a,
            "Negative electrode potential": a_n,
            "Negative electrolyte potential": a_n,
            "Negative electrode open circuit potential": a_n,
            "Negative electrolyte concentration": a_n,
            "Negative electrode temperature": a_n,
        }
        submodel = pybamm.interface.ButlerVolmer(param, "Negative",
                                                 "lead-acid main")
        std_tests = tests.StandardSubModelTests(submodel, variables)

        std_tests.test_all()

        variables = {
            "Current collector current density": a,
            "Positive electrode potential": a_p,
            "Positive electrolyte potential": a_p,
            "Positive electrode open circuit potential": a_p,
            "Positive electrolyte concentration": a_p,
            "Positive electrode temperature": a_p,
            "Negative electrode interfacial current density": a_n,
            "Negative electrode exchange current density": a_n,
        }
        submodel = pybamm.interface.ButlerVolmer(param, "Positive",
                                                 "lead-acid main")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()
    def get_fundamental_variables(self):
        c_e_av = pybamm.standard_variables.c_e_av
        c_e_n = pybamm.PrimaryBroadcast(c_e_av, ["negative electrode"])
        c_e_s = pybamm.PrimaryBroadcast(c_e_av, ["separator"])
        c_e_p = pybamm.PrimaryBroadcast(c_e_av, ["positive electrode"])

        return self._get_standard_concentration_variables(c_e_n, c_e_s, c_e_p)
Example #9
0
    def test_public_functions(self):
        param = pybamm.standard_parameters_lead_acid

        a = pybamm.Scalar(0)
        variables = {
            "Current collector current density":
            a,
            "Negative electrolyte current density":
            pybamm.PrimaryBroadcast(a, ["negative electrode"]),
            "Positive electrolyte current density":
            pybamm.PrimaryBroadcast(a, ["positive electrode"]),
            "Negative electrode porosity":
            a,
            "Positive electrode porosity":
            a,
            "Separator electrolyte potential":
            a,
            "Positive electrode surface potential difference":
            a,
        }
        submodel = pybamm.electrode.ohm.SurfaceForm(param, "Negative")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        submodel = pybamm.electrode.ohm.SurfaceForm(param, "Positive")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()
Example #10
0
    def get_coupled_variables(self, variables):

        j_n = variables[
            "X-averaged negative electrode interfacial current density"]
        j_p = variables[
            "X-averaged positive electrode interfacial current density"]
        j_sei_n = variables[
            "X-averaged negative electrode sei interfacial current density"]
        beta_sei_n = self.param.beta_sei_n

        deps_n_dt = pybamm.PrimaryBroadcast(
            -self.param.beta_surf_n * j_n + beta_sei_n * j_sei_n,
            ["negative electrode"])
        deps_s_dt = pybamm.FullBroadcast(
            0,
            "separator",
            auxiliary_domains={"secondary": "current collector"})
        deps_p_dt = pybamm.PrimaryBroadcast(-self.param.beta_surf_p * j_p,
                                            ["positive electrode"])

        variables.update(
            self._get_standard_porosity_change_variables(
                deps_n_dt, deps_s_dt, deps_p_dt))

        return variables
Example #11
0
    def test_shape_and_size_for_testing(self):
        scal = pybamm.Scalar(1)
        self.assertEqual(scal.shape_for_testing, scal.shape)
        self.assertEqual(scal.size_for_testing, scal.size)

        state = pybamm.StateVector(slice(10, 25), domain="test")
        state2 = pybamm.StateVector(slice(10, 25), domain="test 2")
        self.assertEqual(state.shape_for_testing, state.shape)

        param = pybamm.Parameter("a")
        self.assertEqual(param.shape_for_testing, ())

        func = pybamm.FunctionParameter("func", {"state": state})
        self.assertEqual(func.shape_for_testing, state.shape_for_testing)

        concat = pybamm.concatenation(state, state2)
        self.assertEqual(concat.shape_for_testing, (30, 1))
        self.assertEqual(concat.size_for_testing, 30)

        var = pybamm.Variable("var", domain="negative electrode")
        broadcast = pybamm.PrimaryBroadcast(0, "negative electrode")
        self.assertEqual(var.shape_for_testing, broadcast.shape_for_testing)
        self.assertEqual((var + broadcast).shape_for_testing,
                         broadcast.shape_for_testing)

        var = pybamm.Variable("var", domain=["random domain", "other domain"])
        broadcast = pybamm.PrimaryBroadcast(0,
                                            ["random domain", "other domain"])
        self.assertEqual(var.shape_for_testing, broadcast.shape_for_testing)
        self.assertEqual((var + broadcast).shape_for_testing,
                         broadcast.shape_for_testing)

        sym = pybamm.Symbol("sym")
        with self.assertRaises(NotImplementedError):
            sym.shape_for_testing
Example #12
0
    def test_jac_of_domain_concatenation(self):
        # create mesh
        disc = get_1p1d_discretisation_for_testing()
        mesh = disc.mesh
        y = pybamm.StateVector(slice(0, 1500))

        # Jacobian of a DomainConcatenation of constants is a zero matrix of the
        # appropriate size
        a_dom = ["negative electrode"]
        b_dom = ["separator"]
        c_dom = ["positive electrode"]
        cc_npts = mesh["current collector"][0].npts
        curr_coll_vector = pybamm.Vector(np.ones(cc_npts), domain="current collector")
        a = 2 * pybamm.PrimaryBroadcast(curr_coll_vector, a_dom)
        b = pybamm.PrimaryBroadcast(curr_coll_vector, b_dom)
        c = 3 * pybamm.PrimaryBroadcast(curr_coll_vector, c_dom)

        conc = pybamm.Concatenation(a, b, c)
        disc.set_variable_slices([conc])
        conc_disc = disc.process_symbol(conc)
        jac = conc_disc.jac(y).evaluate().toarray()
        np.testing.assert_array_equal(jac, np.zeros((1500, 1500)))

        # Jacobian of a DomainConcatenation of StateVectors
        a = pybamm.Variable("a", domain=a_dom)
        b = pybamm.Variable("b", domain=b_dom)
        c = pybamm.Variable("c", domain=c_dom)
        conc = pybamm.Concatenation(a, b, c)
        disc.set_variable_slices([conc])
        conc_disc = disc.process_symbol(conc)
        y0 = np.ones(1500)
        jac = conc_disc.jac(y).evaluate(y=y0).toarray()
        np.testing.assert_array_equal(jac, np.eye(1500))
Example #13
0
def preprocess_binary(left, right):
    if isinstance(left, numbers.Number):
        left = pybamm.Scalar(left)
    if isinstance(right, numbers.Number):
        right = pybamm.Scalar(right)

    # Check both left and right are pybamm Symbols
    if not (isinstance(left, pybamm.Symbol)
            and isinstance(right, pybamm.Symbol)):
        raise NotImplementedError(
            """BinaryOperator not implemented for symbols of type {} and {}""".
            format(type(left), type(right)))

    # Do some broadcasting in special cases, to avoid having to do this manually
    if left.domain != [] and right.domain != []:
        if (left.domain != right.domain
                and "secondary" in right.auxiliary_domains
                and left.domain == right.auxiliary_domains["secondary"]):
            left = pybamm.PrimaryBroadcast(left, right.domain)
        if (right.domain != left.domain
                and "secondary" in left.auxiliary_domains
                and right.domain == left.auxiliary_domains["secondary"]):
            right = pybamm.PrimaryBroadcast(right, left.domain)

    return left, right
Example #14
0
    def test_public_function(self):
        param = pybamm.standard_parameters_lead_acid

        a_n = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["negative electrode"])
        a_s = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["separator"])
        a = pybamm.Scalar(0)
        variables = {
            "Current collector current density": a,
            "Negative electrode potential": a_n,
            "Negative electrolyte potential": a_n,
            "Negative electrolyte concentration": a_n,
            "Negative electrode temperature": a_n,
            "X-averaged positive electrode oxygen interfacial current density": a,
            "Separator tortuosity": a_s,
            "Separator oxygen concentration": a_s,
            "Leading-order negative electrode oxygen interfacial current density": a,
        }
        submodel = pybamm.interface.DiffusionLimited(
            param, "Negative", "lead-acid oxygen", "leading"
        )
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        submodel = pybamm.interface.DiffusionLimited(
            param, "Negative", "lead-acid oxygen", "composite"
        )
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        submodel = pybamm.interface.DiffusionLimited(
            param, "Negative", "lead-acid oxygen", "full"
        )
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()
Example #15
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)
    def get_fundamental_variables(self):
        c_ox_av = pybamm.Variable(
            "X-averaged oxygen concentration", domain="current collector"
        )
        c_ox_n = pybamm.PrimaryBroadcast(c_ox_av, "negative electrode")
        c_ox_s = pybamm.PrimaryBroadcast(c_ox_av, "separator")
        c_ox_p = pybamm.PrimaryBroadcast(c_ox_av, "positive electrode")

        return self._get_standard_concentration_variables(c_ox_n, c_ox_s, c_ox_p)
Example #17
0
    def get_coupled_variables(self, variables):

        # Set up
        param = self.param
        l_n = param.l_n
        x_n = pybamm.standard_spatial_vars.x_n
        x_s = pybamm.standard_spatial_vars.x_s
        x_p = pybamm.standard_spatial_vars.x_p

        p_s = variables["X-averaged separator pressure"]
        j_n_av = variables["X-averaged negative electrode interfacial current density"]
        j_p_av = variables["X-averaged positive electrode interfacial current density"]

        p_n = param.beta_n * j_n_av * (-(x_n ** 2) + param.l_n ** 2) / 2 + p_s
        p_p = param.beta_n * j_n_av * ((x_p - 1) ** 2 - param.l_p ** 2) / 2 + p_s
        variables.update(self._get_standard_neg_pos_pressure_variables(p_n, p_p))

        # Volume-averaged velocity
        v_box_n = param.beta_n * j_n_av * x_n
        v_box_p = param.beta_p * j_p_av * (x_p - 1)
        variables.update(
            self._get_standard_neg_pos_velocity_variables(v_box_n, v_box_p)
        )

        div_v_box_n = pybamm.PrimaryBroadcast(
            param.beta_n * j_n_av, "negative electrode"
        )
        div_v_box_p = pybamm.PrimaryBroadcast(
            param.beta_p * j_p_av, "positive electrode"
        )
        variables.update(
            self._get_standard_neg_pos_acceleration_variables(div_v_box_n, div_v_box_p)
        )

        # Transverse velocity in the separator determines through-cell velocity
        div_Vbox_s = variables[
            "X-averaged separator transverse volume-averaged acceleration"
        ]
        i_boundary_cc = variables["Current collector current density"]
        v_box_n_right = param.beta_n * i_boundary_cc
        div_v_box_s_av = -div_Vbox_s
        div_v_box_s = pybamm.PrimaryBroadcast(div_v_box_s_av, "separator")

        # Simple formula for velocity in the separator
        v_box_s = div_v_box_s_av * (x_s - l_n) + v_box_n_right

        variables.update(
            self._get_standard_sep_velocity_variables(v_box_s, div_v_box_s)
        )
        variables.update(self._get_standard_whole_cell_velocity_variables(variables))
        variables.update(
            self._get_standard_whole_cell_acceleration_variables(variables)
        )
        variables.update(self._get_standard_whole_cell_pressure_variables(variables))

        return variables
Example #18
0
 def test_public_functions(self):
     param = pybamm.standard_parameters_lead_acid
     a_n = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["negative electrode"])
     a_p = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["positive electrode"])
     variables = {
         "Negative electrode interfacial current density": a_n,
         "Positive electrode interfacial current density": a_p,
     }
     submodel = pybamm.porosity.Full(param)
     std_tests = tests.StandardSubModelTests(submodel, variables)
     std_tests.test_all()
Example #19
0
    def test_public_functions(self):
        param = pybamm.standard_parameters_lithium_ion
        a = pybamm.Scalar(0)
        a_n = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["negative electrode"])
        a_s = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["separator"])
        a_p = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["positive electrode"])
        variables = {
            "Current collector current density": a,
            "Negative electrode porosity": a_n,
            "Negative electrolyte concentration": a_n,
            "Negative electrode interfacial current density": a_n,
            "X-averaged negative electrode interfacial current density": a,
            "X-averaged negative electrode total interfacial current density":
            a,
        }
        icd = " interfacial current density"
        reactions = {
            "main": {
                "Negative": {
                    "s": 1,
                    "aj": "Negative electrode" + icd
                },
                "Positive": {
                    "s": 1,
                    "aj": "Positive electrode" + icd
                },
            }
        }
        spf = pybamm.electrolyte.stefan_maxwell.conductivity.surface_potential_form
        submodel = spf.LeadingOrderAlgebraic(param, "Negative", reactions)
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()
        submodel = spf.LeadingOrderDifferential(param, "Negative", reactions)
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        variables = {
            "Current collector current density": a,
            "Negative electrolyte potential": a_n,
            "Negative electrolyte current density": a_n,
            "Separator electrolyte potential": a_s,
            "Separator electrolyte current density": a_s,
            "Positive electrode porosity": a_p,
            "Positive electrolyte concentration": a_p,
            "X-averaged positive electrode interfacial current density": a,
            "X-averaged positive electrode total interfacial current density":
            a,
        }
        submodel = spf.LeadingOrderAlgebraic(param, "Positive", reactions)
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()
        submodel = spf.LeadingOrderDifferential(param, "Positive", reactions)
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()
Example #20
0
    def get_fundamental_variables(self):

        eps_n_pc = pybamm.standard_variables.eps_n_pc
        eps_s_pc = pybamm.standard_variables.eps_s_pc
        eps_p_pc = pybamm.standard_variables.eps_p_pc

        eps_n = pybamm.PrimaryBroadcast(eps_n_pc, "negative electrode")
        eps_s = pybamm.PrimaryBroadcast(eps_s_pc, "separator")
        eps_p = pybamm.PrimaryBroadcast(eps_p_pc, "positive electrode")

        variables = self._get_standard_porosity_variables(eps_n, eps_s, eps_p)
        return variables
Example #21
0
    def get_fundamental_variables(self):
        if self.domain == "Negative":
            c_s_xav = pybamm.standard_variables.c_s_n_xav
            c_s = pybamm.PrimaryBroadcast(c_s_xav, ["negative electrode"])

        elif self.domain == "Positive":
            c_s_xav = pybamm.standard_variables.c_s_p_xav
            c_s = pybamm.PrimaryBroadcast(c_s_xav, ["positive electrode"])

        variables = self._get_standard_concentration_variables(c_s, c_s_xav)

        return variables
Example #22
0
    def test_x_average(self):
        a = pybamm.Scalar(1)
        average_a = pybamm.x_average(a)
        self.assertEqual(average_a.id, a.id)

        average_broad_a = pybamm.x_average(
            pybamm.PrimaryBroadcast(a, ["negative electrode"]))
        self.assertEqual(average_broad_a.evaluate(), np.array([1]))

        conc_broad = pybamm.Concatenation(
            pybamm.PrimaryBroadcast(1, ["negative electrode"]),
            pybamm.PrimaryBroadcast(2, ["separator"]),
            pybamm.PrimaryBroadcast(3, ["positive electrode"]),
        )
        average_conc_broad = pybamm.x_average(conc_broad)
        self.assertIsInstance(average_conc_broad, pybamm.Division)

        for domain in [
            ["negative electrode"],
            ["separator"],
            ["positive electrode"],
            ["negative electrode", "separator", "positive electrode"],
        ]:
            a = pybamm.Symbol("a", domain=domain)
            x = pybamm.SpatialVariable("x", domain)
            av_a = pybamm.x_average(a)
            self.assertIsInstance(av_a, pybamm.Division)
            self.assertIsInstance(av_a.children[0], pybamm.Integral)
            self.assertEqual(av_a.children[0].integration_variable[0].domain,
                             x.domain)
            self.assertEqual(av_a.domain, [])

        a = pybamm.Symbol("a", domain="new domain")
        av_a = pybamm.x_average(a)
        self.assertEqual(av_a.domain, [])
        self.assertIsInstance(av_a, pybamm.Division)
        self.assertIsInstance(av_a.children[0], pybamm.Integral)
        self.assertEqual(av_a.children[0].integration_variable[0].domain,
                         a.domain)
        self.assertIsInstance(av_a.children[1], pybamm.Integral)
        self.assertEqual(av_a.children[1].integration_variable[0].domain,
                         a.domain)
        self.assertEqual(av_a.children[1].children[0].id,
                         pybamm.ones_like(a).id)

        # x-average of symbol that evaluates on edges raises error
        symbol_on_edges = pybamm.PrimaryBroadcastToEdges(1, "domain")
        with self.assertRaisesRegex(
                ValueError,
                "Can't take the x-average of a symbol that evaluates on edges"
        ):
            pybamm.x_average(symbol_on_edges)
Example #23
0
    def get_fundamental_variables(self):

        T_x_av = pybamm.standard_variables.T_av
        T_n = pybamm.PrimaryBroadcast(T_x_av, "negative electrode")
        T_s = pybamm.PrimaryBroadcast(T_x_av, "separator")
        T_p = pybamm.PrimaryBroadcast(T_x_av, "positive electrode")
        T = pybamm.Concatenation(T_n, T_s, T_p)

        T_cn = T_x_av
        T_cp = T_x_av

        variables = self._get_standard_fundamental_variables(T, T_cn, T_cp)
        return variables
Example #24
0
    def get_fundamental_variables(self):
        T_amb = self.param.T_amb(pybamm.t * self.param.timescale)
        T_x_av = pybamm.PrimaryBroadcast(T_amb, "current collector")
        T_vol_av = pybamm.PrimaryBroadcast(T_amb, "current collector")
        T_cn = T_x_av
        T_n = pybamm.PrimaryBroadcast(T_x_av, "negative electrode")
        T_s = pybamm.PrimaryBroadcast(T_x_av, "separator")
        T_p = pybamm.PrimaryBroadcast(T_x_av, "positive electrode")
        T_cp = T_x_av

        variables = self._get_standard_fundamental_variables(
            T_cn, T_n, T_s, T_p, T_cp, T_x_av, T_vol_av)

        return variables
Example #25
0
    def set_initial_conditions(self, variables):
        c_s = variables[self.domain + " particle concentration"]

        if self.domain == "Negative":
            x_n = pybamm.PrimaryBroadcast(pybamm.standard_spatial_vars.x_n,
                                          "negative particle")
            c_init = self.param.c_n_init(x_n)

        elif self.domain == "Positive":
            x_p = pybamm.PrimaryBroadcast(pybamm.standard_spatial_vars.x_p,
                                          "positive particle")
            c_init = self.param.c_p_init(x_p)

        self.initial_conditions = {c_s: c_init}
Example #26
0
    def get_coupled_variables(self, variables):

        param = self.param
        l_n = param.l_n
        l_s = param.l_s
        l_p = param.l_p
        x_s = pybamm.standard_spatial_vars.x_s
        x_p = pybamm.standard_spatial_vars.x_p

        # Unpack
        eps_s_0_av = variables["Leading-order x-averaged separator porosity"]
        eps_p_0_av = variables[
            "Leading-order x-averaged positive electrode porosity"]

        # Diffusivities
        D_ox_s = (eps_s_0_av**param.b_s) * param.curlyD_ox
        D_ox_p = (eps_p_0_av**param.b_p) * param.curlyD_ox

        # Reactions
        sj_ox_p = sum(reaction["Positive"]["s_ox"] *
                      variables["Leading-order x-averaged " +
                                reaction["Positive"]["aj"].lower()]
                      for reaction in self.reactions.values())

        # Fluxes
        N_ox_n_1 = pybamm.FullBroadcast(0, "negative electrode",
                                        "current collector")
        N_ox_s_1 = -pybamm.PrimaryBroadcast(sj_ox_p * l_p, "separator")
        N_ox_p_1 = pybamm.outer(sj_ox_p, x_p - 1)

        # Concentrations
        c_ox_n_1 = pybamm.FullBroadcast(0, "negative electrode",
                                        "current collector")
        c_ox_s_1 = pybamm.outer(sj_ox_p * l_p / D_ox_s, x_s - l_n)
        c_ox_p_1 = pybamm.outer(
            -sj_ox_p / (2 * D_ox_p),
            (x_p - 1)**2 - l_p**2) + pybamm.PrimaryBroadcast(
                sj_ox_p * l_p * l_s / D_ox_s, "positive electrode")

        # Update variables
        c_ox = pybamm.Concatenation(param.C_e * c_ox_n_1, param.C_e * c_ox_s_1,
                                    param.C_e * c_ox_p_1)
        variables.update(self._get_standard_concentration_variables(c_ox))

        N_ox = pybamm.Concatenation(param.C_e * N_ox_n_1, param.C_e * N_ox_s_1,
                                    param.C_e * N_ox_p_1)
        variables.update(self._get_standard_flux_variables(N_ox))

        return variables
    def get_fundamental_variables(self):

        T_x_av = pybamm.standard_variables.T_av
        T_vol_av = self._yz_average(T_x_av)

        T_cn = T_x_av
        T_n = pybamm.PrimaryBroadcast(T_x_av, "negative electrode")
        T_s = pybamm.PrimaryBroadcast(T_x_av, "separator")
        T_p = pybamm.PrimaryBroadcast(T_x_av, "positive electrode")
        T_cp = T_x_av

        variables = self._get_standard_fundamental_variables(
            T_cn, T_n, T_s, T_p, T_cp, T_x_av, T_vol_av)

        return variables
    def test_public_functions(self):
        param = pybamm.standard_parameters_lithium_ion
        phi_s_cn = pybamm.PrimaryBroadcast(pybamm.Scalar(0), ["current collector"])
        phi_s_cp = pybamm.PrimaryBroadcast(pybamm.Scalar(3), ["current collector"])

        coupled_variables.update(
            {
                "Negative current collector potential": phi_s_cn,
                "Positive current collector potential": phi_s_cp,
            }
        )

        submodel = pybamm.thermal.x_lumped.SetTemperature1D(param)
        std_tests = tests.StandardSubModelTests(submodel, coupled_variables)
        std_tests.test_all()
    def get_coupled_variables(self, variables):
        # Unpack
        c_e_0 = variables["Leading-order " + self.domain.lower() +
                          " electrolyte concentration"]
        c_e = variables[self.domain + " electrolyte concentration"]
        c_e_1 = (c_e - c_e_0) / self.param.C_e

        dj_dc_0 = self._get_dj_dc(variables)
        dj_ddeltaphi_0 = self._get_dj_ddeltaphi(variables)

        # Update delta_phi with new phi_e and phi_s
        variables = self._get_delta_phi(variables)

        delta_phi_0 = variables["Leading-order " + self.domain.lower() +
                                " electrode surface potential difference"]
        delta_phi = variables[self.domain +
                              " electrode surface potential difference"]
        delta_phi_1 = (delta_phi - delta_phi_0) / self.param.C_e

        j_0 = variables["Leading-order " + self.domain.lower() + " electrode" +
                        self.reaction_name + " interfacial current density"]
        j_1 = (pybamm.PrimaryBroadcast(dj_dc_0, self.domain_for_broadcast) *
               c_e_1 + pybamm.PrimaryBroadcast(
                   dj_ddeltaphi_0, self.domain_for_broadcast) * delta_phi_1)
        j = j_0 + self.param.C_e * j_1
        # Get exchange-current density
        j0 = self._get_exchange_current_density(variables)
        # Get open-circuit potential variables and reaction overpotential
        ocp, dUdT = self._get_open_circuit_potential(variables)
        eta_r = delta_phi - ocp

        variables.update(self._get_standard_interfacial_current_variables(j))
        variables.update(self._get_standard_exchange_current_variables(j0))
        variables.update(self._get_standard_overpotential_variables(eta_r))
        variables.update(self._get_standard_ocp_variables(ocp, dUdT))

        if ("Negative electrode" + self.reaction_name +
                " interfacial current density" in variables
                and "Positive electrode" + self.reaction_name +
                " interfacial current density" in variables):
            variables.update(
                self._get_standard_whole_cell_interfacial_current_variables(
                    variables))
            variables.update(
                self._get_standard_whole_cell_exchange_current_variables(
                    variables))

        return variables
Example #30
0
    def _separator_velocity(self, variables):
        """
        A private method to calculate x- and z-components of velocity in the separator

        Parameters
        ----------
        variables : dict
            Dictionary of variables in the whole model.

        Returns
        -------
        v_box_s : :class:`pybamm.Symbol`
            The x-component of velocity in the separator
        dVbox_dz : :class:`pybamm.Symbol`
            The z-component of velocity in the separator
        """
        # Set up
        param = self.param
        l_n = pybamm.geometric_parameters.l_n
        l_s = pybamm.geometric_parameters.l_s
        x_s = pybamm.standard_spatial_vars.x_s

        # Difference in negative and positive electrode velocities determines the
        # velocity in the separator
        i_boundary_cc = variables["Current collector current density"]
        v_box_n_right = param.beta_n * i_boundary_cc
        v_box_p_left = param.beta_p * i_boundary_cc
        d_vbox_s__dx = (v_box_p_left - v_box_n_right) / l_s

        # Simple formula for velocity in the separator
        dVbox_dz = pybamm.Concatenation(
            pybamm.FullBroadcast(
                0,
                "negative electrode",
                auxiliary_domains={"secondary": "current collector"},
            ),
            pybamm.PrimaryBroadcast(-d_vbox_s__dx, "separator"),
            pybamm.FullBroadcast(
                0,
                "positive electrode",
                auxiliary_domains={"secondary": "current collector"},
            ),
        )
        v_box_s = pybamm.outer(d_vbox_s__dx,
                               (x_s - l_n)) + pybamm.PrimaryBroadcast(
                                   v_box_n_right, "separator")

        return v_box_s, dVbox_dz