def test_public_functions(self):
        param = pybamm.LithiumIonParameters()

        a_n = pybamm.FullBroadcast(pybamm.Scalar(0), "negative electrode",
                                   {"secondary": "current collector"})
        a_p = pybamm.FullBroadcast(pybamm.Scalar(0), "positive electrode",
                                   {"secondary": "current collector"})

        variables = {
            "Negative electrode interfacial current density": a_n,
            "Negative electrode temperature": a_n,
            "Negative electrode active material volume fraction": a_n,
            "Negative electrode surface area to volume ratio": a_n,
            "Negative particle radius": a_n,
        }

        submodel = pybamm.particle.PolynomialManyParticles(
            param, "Negative", "uniform profile")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        submodel = pybamm.particle.PolynomialManyParticles(
            param, "Negative", "quadratic profile")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        submodel = pybamm.particle.PolynomialManyParticles(
            param, "Negative", "quartic profile")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        variables = {
            "Positive electrode interfacial current density": a_p,
            "Positive electrode temperature": a_p,
            "Positive electrode active material volume fraction": a_p,
            "Positive electrode surface area to volume ratio": a_p,
            "Positive particle radius": a_p,
        }

        submodel = pybamm.particle.PolynomialManyParticles(
            param, "Positive", "uniform profile")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        submodel = pybamm.particle.PolynomialManyParticles(
            param, "Positive", "quadratic profile")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()

        submodel = pybamm.particle.PolynomialManyParticles(
            param, "Positive", "quartic profile")
        std_tests = tests.StandardSubModelTests(submodel, variables)
        std_tests.test_all()
    def get_fundamental_variables(self):
        c_ox_av = pybamm.Variable("X-averaged oxygen concentration")
        c_ox_n = pybamm.FullBroadcast(
            c_ox_av, ["negative electrode"], "current collector"
        )
        c_ox_s = pybamm.FullBroadcast(c_ox_av, ["separator"], "current collector")
        c_ox_p = pybamm.FullBroadcast(
            c_ox_av, ["positive electrode"], "current collector"
        )
        c_ox = pybamm.Concatenation(c_ox_n, c_ox_s, c_ox_p)

        return self._get_standard_concentration_variables(c_ox)
    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
        tor_s_0_av = variables["Leading-order x-averaged separator tortuosity"]
        tor_p_0_av = variables[
            "Leading-order x-averaged positive electrolyte tortuosity"
        ]

        # Diffusivities
        D_ox_s = tor_s_0_av * param.curlyD_ox
        D_ox_p = tor_p_0_av * 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 = sj_ox_p * (x_p - 1)

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

        # 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
Exemple #4
0
    def test_symbol_visualise(self):

        param = pybamm.standard_parameters_lithium_ion

        one_n = pybamm.FullBroadcast(1, ["negative electrode"],
                                     "current collector")
        one_p = pybamm.FullBroadcast(1, ["positive electrode"],
                                     "current collector")

        zero_n = pybamm.FullBroadcast(0, ["negative electrode"],
                                      "current collector")
        zero_s = pybamm.FullBroadcast(0, ["separator"], "current collector")
        zero_p = pybamm.FullBroadcast(0, ["positive electrode"],
                                      "current collector")

        deps_dt = pybamm.Concatenation(zero_n, zero_s, zero_p)

        v_box = pybamm.Scalar(0)

        variables = {
            "Porosity": param.epsilon,
            "Porosity change": deps_dt,
            "Volume-averaged velocity": v_box,
            "Negative electrode interfacial current density": one_n,
            "Positive electrode interfacial current density": one_p,
            "Cell temperature": pybamm.Concatenation(zero_n, zero_s, zero_p),
        }
        icd = " interfacial current density"
        reactions = {
            "main": {
                "Negative": {
                    "s": 1,
                    "aj": "Negative electrode" + icd
                },
                "Positive": {
                    "s": 1,
                    "aj": "Positive electrode" + icd
                },
            }
        }
        model = pybamm.electrolyte.stefan_maxwell.diffusion.Full(
            param, reactions)
        variables.update(model.get_fundamental_variables())
        variables.update(model.get_coupled_variables(variables))

        model.set_rhs(variables)

        c_e = pybamm.standard_variables.c_e
        rhs = model.rhs[c_e]
        rhs.visualise("StefanMaxwell_test.png")
        self.assertTrue(os.path.exists("StefanMaxwell_test.png"))
        with self.assertRaises(ValueError):
            rhs.visualise("StefanMaxwell_test")
Exemple #5
0
    def test_symbol_visualise(self):

        param = pybamm.LithiumIonParameters()

        zero_n = pybamm.FullBroadcast(0, ["negative electrode"],
                                      "current collector")
        zero_s = pybamm.FullBroadcast(0, ["separator"], "current collector")
        zero_p = pybamm.FullBroadcast(0, ["positive electrode"],
                                      "current collector")

        zero_nsp = pybamm.concatenation(zero_n, zero_s, zero_p)

        v_box = pybamm.Scalar(0)

        variables = {
            "Porosity":
            param.epsilon,
            "Negative electrode porosity":
            param.epsilon_n,
            "Separator porosity":
            param.epsilon_s,
            "Positive electrode porosity":
            param.epsilon_p,
            "Electrolyte tortuosity":
            param.epsilon**1.5,
            "Porosity change":
            zero_nsp,
            "Electrolyte current density":
            zero_nsp,
            "Volume-averaged velocity":
            v_box,
            "Interfacial current density":
            zero_nsp,
            "Oxygen interfacial current density":
            zero_nsp,
            "Cell temperature":
            pybamm.concatenation(zero_n, zero_s, zero_p),
            "Transverse volume-averaged acceleration":
            pybamm.concatenation(zero_n, zero_s, zero_p),
            "Sum of electrolyte reaction source terms":
            zero_nsp,
        }
        model = pybamm.electrolyte_diffusion.Full(param)
        variables.update(model.get_fundamental_variables())
        variables.update(model.get_coupled_variables(variables))

        model.set_rhs(variables)

        rhs = list(model.rhs.values())[0]
        rhs.visualise("StefanMaxwell_test.png")
        self.assertTrue(os.path.exists("StefanMaxwell_test.png"))
        with self.assertRaises(ValueError):
            rhs.visualise("StefanMaxwell_test")
Exemple #6
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
def simplified_concatenation(*children):
    """ Perform simplifications on a concatenation """
    # Create Concatenation to easily read domains
    concat = Concatenation(*children)
    # Simplify concatenation of broadcasts all with the same child to a single
    # broadcast across all domains
    if len(children) == 0:
        raise ValueError("Cannot create empty concatenation")
    elif len(children) == 1:
        return children[0]
    else:
        if all(
            isinstance(child, pybamm.Broadcast)
            and child.child.id == children[0].child.id
            for child in children
        ):
            unique_child = children[0].orphans[0]
            if isinstance(children[0], pybamm.PrimaryBroadcast):
                return pybamm.PrimaryBroadcast(unique_child, concat.domain)
            else:
                return pybamm.FullBroadcast(
                    unique_child, concat.domain, concat.auxiliary_domains
                )
        elif all(isinstance(child, pybamm.Variable) for child in children):
            return pybamm.ConcatenationVariable(*children)
    return concat
Exemple #8
0
    def set_rhs(self, variables):

        param = self.param

        eps = variables["Porosity"]
        deps_dt = variables["Porosity change"]
        c_e = variables["Electrolyte concentration"]
        N_e = variables["Electrolyte flux"]
        # i_e = variables["Electrolyte current density"]

        # source_term = ((param.s - param.t_plus) / param.gamma_e) * pybamm.div(i_e)
        # source_term = pybamm.div(i_e) / param.gamma_e  # lithium-ion
        source_terms = sum(
            pybamm.Concatenation(
                reaction["Negative"]["s"] *
                variables[reaction["Negative"]["aj"]],
                pybamm.FullBroadcast(0, "separator", "current collector"),
                reaction["Positive"]["s"] *
                variables[reaction["Positive"]["aj"]],
            ) / param.gamma_e for reaction in self.reactions.values())

        self.rhs = {
            c_e: (1 / eps) *
            (-pybamm.div(N_e) / param.C_e + source_terms - c_e * deps_dt)
        }
Exemple #9
0
    def process_dict(self, var_eqn_dict):
        """Discretise a dictionary of {variable: equation}, broadcasting if necessary
        (can be model.rhs, model.algebraic, model.initial_conditions or
        model.variables).

        Parameters
        ----------
        var_eqn_dict : dict
            Equations ({variable: equation} dict) to dicretise
            (can be model.rhs, model.algebraic, model.initial_conditions or
            model.variables)

        Returns
        -------
        new_var_eqn_dict : dict
            Discretised equations

        """
        new_var_eqn_dict = {}
        for eqn_key, eqn in var_eqn_dict.items():
            # Broadcast if the equation evaluates to a number(e.g. Scalar)
            if eqn.evaluates_to_number() and not isinstance(eqn_key, str):
                eqn = pybamm.FullBroadcast(eqn, eqn_key.domain,
                                           eqn_key.auxiliary_domains)

            # note we are sending in the key.id here so we don't have to
            # keep calling .id
            pybamm.logger.debug("Discretise {!r}".format(eqn_key))

            processed_eqn = self.process_symbol(eqn)

            new_var_eqn_dict[eqn_key] = processed_eqn

        return new_var_eqn_dict
Exemple #10
0
def r_average(symbol):
    """convenience function for creating an average in the r-direction

    Parameters
    ----------
    symbol : :class:`pybamm.Symbol`
        The function to be averaged

    Returns
    -------
    :class:`Symbol`
        the new averaged symbol
    """
    # Can't take average if the symbol evaluates on edges
    if symbol.evaluates_on_edges("primary"):
        raise ValueError(
            "Can't take the r-average of a symbol that evaluates on edges")
    # If symbol doesn't have a particle domain, its r-averaged value is itself
    if symbol.domain not in [["positive particle"], ["negative particle"]]:
        new_symbol = symbol.new_copy()
        new_symbol.parent = None
        return new_symbol
    # If symbol is a Broadcast, its average value is its child
    elif isinstance(symbol, pybamm.Broadcast):
        return symbol.orphans[0]
    else:
        r = pybamm.SpatialVariable("r", symbol.domain)
        v = pybamm.FullBroadcast(pybamm.Scalar(1), symbol.domain,
                                 symbol.auxiliary_domains)
        return Integral(symbol, r) / Integral(v, r)
    def set_rhs(self, variables):
        "Composite reaction-diffusion with source terms from leading order"

        param = self.param

        eps_0 = separator_and_positive_only(
            variables["Leading-order porosity"])
        deps_0_dt = separator_and_positive_only(
            variables["Leading-order porosity change"])
        c_ox = variables[
            "Separator and positive electrode oxygen concentration"]
        N_ox = variables["Oxygen flux"].orphans[1]

        if self.extended is False:
            j_ox_0 = variables[
                "Leading-order positive electrode oxygen interfacial current density"]
            pos_reactions = param.s_ox_Ox * j_ox_0
        else:
            j_ox_0 = variables[
                "Positive electrode oxygen interfacial current density"]
            pos_reactions = param.s_ox_Ox * j_ox_0
        sep_reactions = pybamm.FullBroadcast(0, "separator",
                                             "current collector")
        source_terms_0 = (pybamm.Concatenation(sep_reactions, pos_reactions) /
                          param.gamma_e)

        self.rhs = {
            c_ox: (1 / eps_0) *
            (-pybamm.div(N_ox) / param.C_e + source_terms_0 - c_ox * deps_0_dt)
        }
Exemple #12
0
    def get_coupled_variables(self, variables):

        # Simple formula for velocity in the separator
        v_box_s = pybamm.FullBroadcast(0, "separator", "current collector")
        div_v_box_s = pybamm.FullBroadcast(0, "separator", "current collector")

        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
    def set_rhs(self, variables):
        "Composite reaction-diffusion with source terms from leading order"

        param = self.param

        eps_0 = separator_and_positive_only(variables["Leading-order porosity"])
        deps_0_dt = separator_and_positive_only(
            variables["Leading-order porosity change"]
        )
        c_ox = variables["Separator and positive electrode oxygen concentration"]
        N_ox = variables["Oxygen flux"].orphans[1]

        if self.extended is False:
            pos_reactions = sum(
                reaction["Positive"]["s_ox"]
                * variables["Leading-order " + reaction["Positive"]["aj"].lower()]
                for reaction in self.reactions.values()
            )
        else:
            pos_reactions = sum(
                reaction["Positive"]["s_ox"] * variables[reaction["Positive"]["aj"]]
                for reaction in self.reactions.values()
            )
        sep_reactions = pybamm.FullBroadcast(0, "separator", "current collector")
        source_terms_0 = (
            pybamm.Concatenation(sep_reactions, pos_reactions) / param.gamma_e
        )

        self.rhs = {
            c_ox: (1 / eps_0)
            * (-pybamm.div(N_ox) / param.C_e + source_terms_0 - c_ox * deps_0_dt)
        }
Exemple #14
0
    def get_coupled_variables(self, variables):
        param = self.param

        if self.phase == "Electrolyte":
            eps_n = variables["Negative electrode porosity"]
            eps_s = variables["Separator porosity"]
            eps_p = variables["Positive electrode porosity"]

            tor_n = eps_n**param.b_e_n
            tor_s = eps_s**param.b_e_s
            tor_p = eps_p**param.b_e_p
        elif self.phase == "Electrode":
            eps_n = variables[
                "Negative electrode active material volume fraction"]
            eps_p = variables[
                "Positive electrode active material volume fraction"]

            tor_n = eps_n**param.b_e_n
            tor_s = pybamm.FullBroadcast(0, "separator", "current collector")
            tor_p = eps_p**param.b_e_p

        variables.update(
            self._get_standard_tortuosity_variables(tor_n, tor_s, tor_p,
                                                    self.set_leading_order))

        return variables
Exemple #15
0
 def get_fundamental_variables(self):
     zero = pybamm.FullBroadcast(pybamm.Scalar(0),
                                 self.domain.lower() + " electrode",
                                 "current collector")
     variables = self._get_standard_concentration_variables(zero)
     variables.update(self._get_standard_reaction_variables(zero))
     return variables
Exemple #16
0
    def _get_standard_interfacial_current_variables(self, j):

        i_typ = self.param.i_typ
        L_x = self.param.L_x
        if self.domain == "Negative":
            j_scale = i_typ / (self.param.a_n_dim * L_x)
        elif self.domain == "Positive":
            j_scale = i_typ / (self.param.a_p_dim * L_x)

        # Average, and broadcast if necessary
        j_av = pybamm.x_average(j)
        if j.domain == []:
            j = pybamm.FullBroadcast(j, self.domain_for_broadcast,
                                     "current collector")
        elif j.domain == ["current collector"]:
            j = pybamm.PrimaryBroadcast(j, self.domain_for_broadcast)

        variables = {
            self.domain + " electrode" + self.reaction_name + " interfacial current density":
            j,
            "X-averaged " + self.domain.lower() + " electrode" + self.reaction_name + " interfacial current density":
            j_av,
            self.domain + " electrode" + self.reaction_name + " interfacial current density [A.m-2]":
            j_scale * j,
            "X-averaged " + self.domain.lower() + " electrode" + self.reaction_name + " interfacial current density [A.m-2]":
            j_scale * j_av,
            self.domain + " electrode" + self.reaction_name + " interfacial current density per volume [A.m-3]":
            i_typ / L_x * j,
            "X-averaged " + self.domain.lower() + " electrode" + self.reaction_name + " interfacial current density per volume [A.m-3]":
            i_typ / L_x * j_av,
        }

        return variables
Exemple #17
0
    def set_rhs(self, variables):

        param = self.param

        eps_s = variables["Separator porosity"]
        eps_p = variables["Positive electrode porosity"]
        eps = pybamm.concatenation(eps_s, eps_p)

        deps_dt_s = variables["Separator porosity change"]
        deps_dt_p = variables["Positive electrode porosity change"]
        deps_dt = pybamm.concatenation(deps_dt_s, deps_dt_p)

        c_ox = variables["Separator and positive electrode oxygen concentration"]
        N_ox = variables["Oxygen flux"].orphans[1]

        j_ox = variables["Positive electrode oxygen interfacial current density"]
        source_terms = pybamm.concatenation(
            pybamm.FullBroadcast(0, "separator", "current collector"),
            param.s_ox_Ox * j_ox,
        )

        self.rhs = {
            c_ox: (1 / eps)
            * (-pybamm.div(N_ox) / param.C_e + source_terms - c_ox * deps_dt)
        }
    def get_fundamental_variables(self):
        c_e_n = pybamm.FullBroadcast(1, "negative electrode", "current collector")
        c_e_s = pybamm.FullBroadcast(1, "separator", "current collector")
        c_e_p = pybamm.FullBroadcast(1, "positive electrode", "current collector")

        variables = self._get_standard_concentration_variables(c_e_n, c_e_s, c_e_p)

        N_e = pybamm.FullBroadcastToEdges(
            0,
            ["negative electrode", "separator", "positive electrode"],
            "current collector",
        )

        variables.update(self._get_standard_flux_variables(N_e))

        return variables
 def test_public_functions(self):
     param = pybamm.LithiumIonParameters()
     a = pybamm.Scalar(1)
     full = pybamm.FullBroadcast(
         a,
         ["negative electrode", "separator", "positive electrode"],
         "current collector",
     )
     variables = {
         "Porosity": a,
         "Negative electrode porosity": a,
         "Separator porosity": a,
         "Positive electrode porosity": a,
         "Electrolyte tortuosity": a,
         "Porosity change": a,
         "Volume-averaged velocity": a,
         "Electrolyte concentration": a,
         "Electrolyte current density": full,
         "Sum of electrolyte reaction source terms": full,
         "Cell temperature": full,
         "Transverse volume-averaged acceleration": full,
     }
     submodel = pybamm.electrolyte_diffusion.Full(param)
     std_tests = tests.StandardSubModelTests(submodel, variables)
     std_tests.test_all()
Exemple #20
0
    def _get_standard_sei_film_overpotential_variables(self, eta_sei):

        pot_scale = self.param.potential_scale
        # Average, and broadcast if necessary
        eta_sei_av = pybamm.x_average(eta_sei)
        if eta_sei.domain == []:
            eta_sei = pybamm.FullBroadcast(eta_sei, self.domain_for_broadcast,
                                           "current collector")
        elif eta_sei.domain == ["current collector"]:
            eta_sei = pybamm.PrimaryBroadcast(eta_sei,
                                              self.domain_for_broadcast)

        domain = self.domain.lower() + " electrode"
        variables = {
            self.domain + " electrode sei film overpotential":
            eta_sei,
            "X-averaged " + domain + " sei film overpotential":
            eta_sei_av,
            self.domain + " electrode sei film overpotential [V]":
            eta_sei * pot_scale,
            "X-averaged " + domain + " sei film overpotential [V]":
            eta_sei_av * pot_scale,
        }

        return variables
Exemple #21
0
    def get_coupled_variables(self, variables):

        j_n = variables["Negative electrode interfacial current density"]
        j_p = variables["Positive electrode interfacial current density"]
        deps_n_dt = -self.param.beta_surf_n * j_n

        if self.options["SEI porosity change"] == "true":

            j_sei_n = variables[
                "Negative electrode SEI interfacial current density"]
            beta_sei_n = self.param.beta_sei_n
            deps_n_dt += beta_sei_n * j_sei_n

        if self.options["lithium plating porosity change"] == "true":

            j_plating = variables[
                "Negative electrode lithium plating interfacial current density"]
            beta_plating = self.param.beta_plating

            deps_n_dt += beta_plating * j_plating

        deps_s_dt = pybamm.FullBroadcast(
            0,
            "separator",
            auxiliary_domains={"secondary": "current collector"})

        deps_p_dt = -self.param.beta_surf_p * j_p

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

        return variables
Exemple #22
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)
        }
Exemple #23
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
Exemple #24
0
 def test_full_broadcast(self):
     a = pybamm.Symbol("a")
     broad_a = pybamm.FullBroadcast(a, ["negative electrode"],
                                    "current collector")
     self.assertEqual(broad_a.domain, ["negative electrode"])
     self.assertEqual(broad_a.auxiliary_domains["secondary"],
                      ["current collector"])
Exemple #25
0
    def _get_standard_ocp_variables(self, ocp, dUdT):
        """
        A private function to obtain the open circuit potential and
        related standard variables.

        Parameters
        ----------
        ocp : :class:`pybamm.Symbol`
            The open-circuit potential
        dUdT : :class:`pybamm.Symbol`
            The entropic change in ocp

        Returns
        -------
        variables : dict
            The variables dictionary including the open circuit potentials
            and related standard variables.
        """

        # Average, and broadcast if necessary
        ocp_av = pybamm.x_average(ocp)
        if ocp.domain == []:
            ocp = pybamm.FullBroadcast(
                ocp, self.domain_for_broadcast, "current collector"
            )
        elif ocp.domain == ["current collector"]:
            ocp = pybamm.PrimaryBroadcast(ocp, self.domain_for_broadcast)
        dUdT_av = pybamm.x_average(dUdT)

        if self.domain == "Negative":
            ocp_dim = self.param.U_n_ref + self.param.potential_scale * ocp
            ocp_av_dim = self.param.U_n_ref + self.param.potential_scale * ocp_av
        elif self.domain == "Positive":
            ocp_dim = self.param.U_p_ref + self.param.potential_scale * ocp
            ocp_av_dim = self.param.U_p_ref + self.param.potential_scale * ocp_av

        variables = {
            self.domain
            + " electrode"
            + self.reaction_name
            + " open circuit potential": ocp,
            self.domain
            + " electrode"
            + self.reaction_name
            + " open circuit potential [V]": ocp_dim,
            "X-averaged "
            + self.domain.lower()
            + " electrode"
            + self.reaction_name
            + " open circuit potential": ocp_av,
            "X-averaged "
            + self.domain.lower()
            + " electrode"
            + self.reaction_name
            + " open circuit potential [V]": ocp_av_dim,
            self.domain + " electrode entropic change": dUdT,
            "X-averaged " + self.domain.lower() + " electrode entropic change": dUdT_av,
        }

        return variables
Exemple #26
0
    def _get_standard_surface_potential_difference_variables(self, delta_phi):

        if self.domain == "Negative":
            ocp_ref = self.param.U_n_ref
        elif self.domain == "Positive":
            ocp_ref = self.param.U_p_ref
        pot_scale = self.param.potential_scale

        # Average, and broadcast if necessary
        delta_phi_av = pybamm.x_average(delta_phi)
        if delta_phi.domain == []:
            delta_phi = pybamm.FullBroadcast(
                delta_phi, self.domain_for_broadcast, "current collector"
            )
        elif delta_phi.domain == ["current collector"]:
            delta_phi = pybamm.PrimaryBroadcast(delta_phi, self.domain_for_broadcast)

        variables = {
            self.domain + " electrode surface potential difference": delta_phi,
            "X-averaged "
            + self.domain.lower()
            + " electrode surface potential difference": delta_phi_av,
            self.domain
            + " electrode surface potential difference [V]": ocp_ref
            + delta_phi * pot_scale,
            "X-averaged "
            + self.domain.lower()
            + " electrode surface potential difference [V]": ocp_ref
            + delta_phi_av * pot_scale,
        }

        return variables
Exemple #27
0
    def _get_standard_overpotential_variables(self, eta_r):

        pot_scale = self.param.potential_scale
        # Average, and broadcast if necessary
        eta_r_av = pybamm.x_average(eta_r)
        if eta_r.domain == []:
            eta_r = pybamm.FullBroadcast(
                eta_r, self.domain_for_broadcast, "current collector"
            )
        elif eta_r.domain == ["current collector"]:
            eta_r = pybamm.PrimaryBroadcast(eta_r, self.domain_for_broadcast)

        variables = {
            self.domain
            + " electrode"
            + self.reaction_name
            + " reaction overpotential": eta_r,
            "X-averaged "
            + self.domain.lower()
            + " electrode"
            + self.reaction_name
            + " reaction overpotential": eta_r_av,
            self.domain
            + " electrode"
            + self.reaction_name
            + " reaction overpotential [V]": eta_r * pot_scale,
            "X-averaged "
            + self.domain.lower()
            + " electrode"
            + self.reaction_name
            + " reaction overpotential [V]": eta_r_av * pot_scale,
        }

        return variables
Exemple #28
0
    def _get_standard_whole_cell_exchange_current_variables(self, variables):

        i_typ = self.param.i_typ
        L_x = self.param.L_x
        j_n_scale = i_typ / (self.param.a_n_dim * L_x)
        j_p_scale = i_typ / (self.param.a_p_dim * L_x)

        j0_n = variables[
            "Negative electrode" + self.reaction_name + " exchange current density"
        ]
        j0_s = pybamm.FullBroadcast(0, "separator", "current collector")
        j0_p = variables[
            "Positive electrode" + self.reaction_name + " exchange current density"
        ]
        j0 = pybamm.Concatenation(j0_n, j0_s, j0_p)
        j0_dim = pybamm.Concatenation(j_n_scale * j0_n, j0_s, j_p_scale * j0_p)

        if self.reaction_name == "":
            variables = {
                "Exchange current density": j0,
                "Exchange current density [A.m-2]": j0_dim,
                "Exchange current density per volume [A.m-3]": i_typ / L_x * j0,
            }
        else:
            reaction_name = self.reaction_name[1:].capitalize()
            variables = {
                reaction_name + " exchange current density": j0,
                reaction_name + " exchange current density [A.m-2]": j0_dim,
                reaction_name
                + " exchange current density per volume [A.m-3]": i_typ / L_x * j0,
            }

        return variables
Exemple #29
0
 def _flux_law(self, T):
     """Fast heat diffusion (temperature has no spatial dependence)"""
     q = pybamm.FullBroadcast(
         pybamm.Scalar(0),
         ["negative electrode", "separator", "positive electrode"],
         "current collector",
     )
     return q
Exemple #30
0
 def epsilon_s_p(self, x):
     """
     Positive electrode active material volume fraction, specified for compatibility
     with lithium-ion submodels. Note that this does not change even though porosity
     changes, since the material being created is inactive.
     """
     return pybamm.FullBroadcast(1 - self.eps_p_max, "positive electrode",
                                 "current collector")