Esempio n. 1
0
    def _get_standard_porosity_change_variables(self,
                                                deps_n_dt,
                                                deps_s_dt,
                                                deps_p_dt,
                                                set_leading_order=False):

        deps_n_dt_av = pybamm.x_average(deps_n_dt)
        deps_s_dt_av = pybamm.x_average(deps_s_dt)
        deps_p_dt_av = pybamm.x_average(deps_p_dt)
        deps_dt = pybamm.concatenation(deps_n_dt, deps_s_dt, deps_p_dt)

        variables = {
            "Porosity change": deps_dt,
            "Negative electrode porosity change": deps_n_dt,
            "Separator porosity change": deps_s_dt,
            "Positive electrode porosity change": deps_p_dt,
            "X-averaged negative electrode porosity change": deps_n_dt_av,
            "X-averaged separator porosity change": deps_s_dt_av,
            "X-averaged positive electrode porosity change": deps_p_dt_av,
        }

        if set_leading_order is True:
            variables.update({
                "Leading-order x-averaged " + "negative electrode porosity change":
                deps_n_dt_av,
                "Leading-order x-averaged separator porosity change":
                deps_s_dt_av,
                "Leading-order x-averaged " + "positive electrode porosity change":
                deps_p_dt_av,
            })

        return variables
Esempio n. 2
0
    def _get_standard_tortuosity_variables(self,
                                           tor_n,
                                           tor_s,
                                           tor_p,
                                           set_leading_order=False):
        tor = pybamm.concatenation(tor_n, tor_s, tor_p)

        variables = {
            self.phase + " tortuosity":
            tor,
            "Negative " + self.phase.lower() + " tortuosity":
            tor_n,
            "Positive " + self.phase.lower() + " tortuosity":
            tor_p,
            "X-averaged negative " + self.phase.lower() + " tortuosity":
            pybamm.x_average(tor_n),
            "X-averaged positive " + self.phase.lower() + " tortuosity":
            pybamm.x_average(tor_p),
        }
        if self.phase == "Electrolyte":
            variables.update({
                "Separator tortuosity":
                tor_s,
                "X-averaged separator tortuosity":
                pybamm.x_average(tor_s),
            })

        if set_leading_order is True:
            leading_order_variables = {
                "Leading-order " + name.lower(): var
                for name, var in variables.items()
            }
            variables.update(leading_order_variables)

        return variables
Esempio n. 3
0
    def _get_standard_neg_pos_acceleration_variables(self, div_v_box_n,
                                                     div_v_box_p):
        """ Acceleration in the electrodes """

        acc_scale = self.param.velocity_scale / self.param.L_x

        div_v_box_n_av = pybamm.x_average(div_v_box_n)
        div_v_box_p_av = pybamm.x_average(div_v_box_p)

        variables = {
            "Negative electrode volume-averaged acceleration":
            div_v_box_n,
            "Positive electrode volume-averaged acceleration":
            div_v_box_p,
            "Negative electrode volume-averaged acceleration [m.s-1]":
            acc_scale * div_v_box_n,
            "Positive electrode volume-averaged acceleration [m.s-1]":
            acc_scale * div_v_box_p,
            "X-averaged negative electrode volume-averaged acceleration" + "":
            div_v_box_n_av,
            "X-averaged positive electrode volume-averaged acceleration" + "":
            div_v_box_p_av,
            "X-averaged negative electrode volume-averaged acceleration " + "[m.s-1]":
            acc_scale * div_v_box_n_av,
            "X-averaged positive electrode volume-averaged acceleration " + "[m.s-1]":
            acc_scale * div_v_box_p_av,
        }

        return variables
Esempio n. 4
0
    def _get_total_concentration_variables(self, variables):
        c_s_rav = variables[
            "R-averaged " + self.domain.lower() + " particle concentration"
        ]
        eps_s = variables[self.domain + " electrode active material volume fraction"]
        eps_s_av = pybamm.x_average(eps_s)
        c_s_vol_av = pybamm.x_average(eps_s * c_s_rav) / eps_s_av
        if self.domain == "Negative":
            c_scale = self.param.c_n_max
            L = self.param.L_n
        elif self.domain == "Positive":
            c_scale = self.param.c_p_max
            L = self.param.L_p
        A = self.param.A_cc

        variables.update(
            {
                self.domain + " electrode SOC": c_s_vol_av,
                self.domain + " electrode volume-averaged concentration": c_s_vol_av,
                self.domain
                + " electrode "
                + "volume-averaged concentration [mol.m-3]": c_s_vol_av * c_scale,
                "Total lithium in "
                + self.domain.lower()
                + " electrode [mol]": c_s_vol_av * eps_s_av * c_scale * L * A,
            }
        )
        return variables
Esempio n. 5
0
    def _get_standard_porosity_variables(self,
                                         eps_n,
                                         eps_s,
                                         eps_p,
                                         set_leading_order=False):

        eps_n_av = pybamm.x_average(eps_n)
        eps_s_av = pybamm.x_average(eps_s)
        eps_p_av = pybamm.x_average(eps_p)
        eps = pybamm.concatenation(eps_n, eps_s, eps_p)

        variables = {
            "Porosity": eps,
            "Negative electrode porosity": eps_n,
            "Separator porosity": eps_s,
            "Positive electrode porosity": eps_p,
            "X-averaged negative electrode porosity": eps_n_av,
            "X-averaged separator porosity": eps_s_av,
            "X-averaged positive electrode porosity": eps_p_av,
        }

        if set_leading_order is True:
            leading_order_variables = {
                "Leading-order " + name.lower(): var
                for name, var in variables.items()
            }
            variables.update(leading_order_variables)

        return variables
Esempio n. 6
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
Esempio n. 7
0
    def get_coupled_variables(self, variables):
        # Calculate delta_phi_s from phi_s and phi_e if it isn't already known
        if self.domain + " electrode surface potential difference" not in variables:
            variables = self._get_delta_phi(variables)
        delta_phi_s = variables[self.domain +
                                " electrode surface potential difference"]
        # If delta_phi_s was broadcast, take only the orphan
        if isinstance(delta_phi_s, pybamm.Broadcast):
            delta_phi_s = delta_phi_s.orphans[0]

        # 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_s - ocp

        # Get interfacial current densities
        j = self._get_diffusion_limited_current_density(variables)
        j_tot_av = self._get_average_total_interfacial_current_density(
            variables)

        variables.update(self._get_standard_interfacial_current_variables(j))
        variables.update(
            self._get_standard_total_interfacial_current_variables(j_tot_av))
        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))

        # No SEI film resistance in this model
        eta_sei = pybamm.Scalar(0)
        variables.update(
            self._get_standard_sei_film_overpotential_variables(eta_sei))

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

        if self.order == "composite":
            # For the composite model, adds the first-order x-averaged interfacial
            # current density to the dictionary of variables.
            j_0 = variables["Leading-order " + self.domain.lower() +
                            " electrode" + self.reaction_name +
                            " interfacial current density"]
            j_1_bar = (pybamm.x_average(j) -
                       pybamm.x_average(j_0)) / self.param.C_e

            variables.update({
                "First-order x-averaged " + self.domain.lower() + " electrode" + self.reaction_name + " interfacial current density":
                j_1_bar
            })

        return variables
Esempio n. 8
0
    def _get_standard_potential_variables(self, phi_s):
        """
        A private function to obtain the standard variables which
        can be derived from the potential in the electrode.

        Parameters
        ----------
        phi_s : :class:`pybamm.Symbol`
            The potential in the electrode.

        Returns
        -------
        variables : dict
            The variables which can be derived from the potential in the
            electrode.
        """
        param = self.param
        phi_s_av = pybamm.x_average(phi_s)

        if self.domain == "Negative":
            phi_s_dim = param.potential_scale * phi_s
            phi_s_av_dim = param.potential_scale * phi_s_av
            delta_phi_s = phi_s

        elif self.domain == "Positive":
            phi_s_dim = param.U_p_ref - param.U_n_ref + param.potential_scale * phi_s
            phi_s_av_dim = (param.U_p_ref - param.U_n_ref +
                            param.potential_scale * phi_s_av)

            v = pybamm.boundary_value(phi_s, "right")
            delta_phi_s = phi_s - pybamm.PrimaryBroadcast(
                v, ["positive electrode"])
        delta_phi_s_av = pybamm.x_average(delta_phi_s)
        delta_phi_s_dim = delta_phi_s * param.potential_scale
        delta_phi_s_av_dim = delta_phi_s_av * param.potential_scale

        variables = {
            self.domain + " electrode potential":
            phi_s,
            self.domain + " electrode potential [V]":
            phi_s_dim,
            "X-averaged " + self.domain.lower() + " electrode potential":
            phi_s_av,
            "X-averaged " + self.domain.lower() + " electrode potential [V]":
            phi_s_av_dim,
            self.domain + " electrode ohmic losses":
            delta_phi_s,
            self.domain + " electrode ohmic losses [V]":
            delta_phi_s_dim,
            "X-averaged " + self.domain.lower() + " electrode ohmic losses":
            delta_phi_s_av,
            "X-averaged " + self.domain.lower() + " electrode ohmic losses [V]":
            delta_phi_s_av_dim,
            "Gradient of " + self.domain.lower() + " electrode potential":
            pybamm.grad(phi_s),
        }

        return variables
Esempio n. 9
0
    def _get_standard_concentration_variables(self, c_e_n, c_e_s, c_e_p):
        """
        A private function to obtain the standard variables which
        can be derived from the concentration in the electrolyte.

        Parameters
        ----------
        c_e_n : :class:`pybamm.Symbol`
            The electrolyte concentration in the negative electrode.
        c_e_s : :class:`pybamm.Symbol`
            The electrolyte concentration in the separator.
        c_e_p : :class:`pybamm.Symbol`
            The electrolyte concentration in the positive electrode.

        Returns
        -------
        variables : dict
            The variables which can be derived from the concentration in the
            electrolyte.
        """

        c_e_typ = self.param.c_e_typ

        c_e = pybamm.concatenation(c_e_n, c_e_s, c_e_p)
        c_e_av = pybamm.x_average(c_e)
        c_e_n_av = pybamm.x_average(c_e_n)
        c_e_s_av = pybamm.x_average(c_e_s)
        c_e_p_av = pybamm.x_average(c_e_p)

        variables = {
            "Electrolyte concentration": c_e,
            "Electrolyte concentration [mol.m-3]": c_e_typ * c_e,
            "Electrolyte concentration [Molar]": c_e_typ * c_e / 1000,
            "X-averaged electrolyte concentration": c_e_av,
            "X-averaged electrolyte concentration [mol.m-3]": c_e_typ * c_e_av,
            "X-averaged electrolyte concentration [Molar]": c_e_typ * c_e_av / 1000,
            "Negative electrolyte concentration": c_e_n,
            "Negative electrolyte concentration [mol.m-3]": c_e_typ * c_e_n,
            "Negative electrolyte concentration [Molar]": c_e_typ * c_e_n / 1000,
            "Separator electrolyte concentration": c_e_s,
            "Separator electrolyte concentration [mol.m-3]": c_e_typ * c_e_s,
            "Separator electrolyte concentration [Molar]": c_e_typ * c_e_s / 1000,
            "Positive electrolyte concentration": c_e_p,
            "Positive electrolyte concentration [mol.m-3]": c_e_typ * c_e_p,
            "Positive electrolyte concentration [Molar]": c_e_typ * c_e_p / 1000,
            "X-averaged negative electrolyte concentration": c_e_n_av,
            "X-averaged negative electrolyte concentration [mol.m-3]": c_e_typ
            * c_e_n_av,
            "X-averaged separator electrolyte concentration": c_e_s_av,
            "X-averaged separator electrolyte concentration [mol.m-3]": c_e_typ
            * c_e_s_av,
            "X-averaged positive electrolyte concentration": c_e_p_av,
            "X-averaged positive electrolyte concentration [mol.m-3]": c_e_typ
            * c_e_p_av,
        }

        return variables
Esempio n. 10
0
    def _get_standard_neg_pos_pressure_variables(self, p_n, p_p):
        """ Pressure in the electrodes """

        variables = {
            "Negative electrode pressure": p_n,
            "Positive electrode pressure": p_p,
            "X-averaged negative electrode pressure": pybamm.x_average(p_n),
            "X-averaged positive electrode pressure": pybamm.x_average(p_p),
        }

        return variables
Esempio n. 11
0
    def _get_standard_thickness_variables(self, L_inner, L_outer):
        """
        A private function to obtain the standard variables which
        can be derived from the local SEI thickness.

        Parameters
        ----------
        L_inner : :class:`pybamm.Symbol`
            The inner SEI thickness.
        L_outer : :class:`pybamm.Symbol`
            The outer SEI thickness.

        Returns
        -------
        variables : dict
            The variables which can be derived from the SEI thicknesses.
        """
        param = self.param
        domain = self.domain.lower() + " electrode"

        # Set length scale to one for the "no SEI" model so that it is not
        # required by parameter values in general
        if isinstance(self, pybamm.sei.NoSEI):
            L_scale = 1
        else:
            L_scale = param.L_sei_0_dim

        L_inner_av = pybamm.x_average(L_inner)
        L_outer_av = pybamm.x_average(L_outer)

        variables = {
            "Inner " + domain + " sei thickness":
            L_inner,
            "Inner " + domain + " sei thickness [m]":
            L_inner * L_scale,
            "X-averaged inner " + domain + " sei thickness":
            L_inner_av,
            "X-averaged inner " + domain + " sei thickness [m]":
            L_inner_av * L_scale,
            "Outer " + domain + " sei thickness":
            L_outer,
            "Outer " + domain + " sei thickness [m]":
            L_outer * L_scale,
            "X-averaged outer " + domain + " sei thickness":
            L_outer_av,
            "X-averaged outer " + domain + " sei thickness [m]":
            L_outer_av * L_scale,
        }

        # Get variables related to the total thickness
        L_sei = L_inner + L_outer
        variables.update(self._get_standard_total_thickness_variables(L_sei))

        return variables
Esempio n. 12
0
    def _get_standard_concentration_variables(self, c_plated_Li):
        """
        A private function to obtain the standard variables which
        can be derived from the local plated lithium concentration.
        Parameters
        ----------
        c_plated_Li : :class:`pybamm.Symbol`
            The plated lithium concentration.
        Returns
        -------
        variables : dict
            The variables which can be derived from the plated lithium thickness.
        """
        param = self.param

        # Set scales to one for the "no plating" model so that they are not required
        # by parameter values in general
        if isinstance(self, pybamm.lithium_plating.NoPlating):
            c_scale = 1
            L_scale = 1
        else:
            c_scale = param.c_Li_typ
            L_scale = param.V_bar_plated_Li * c_scale / param.a_n_typ

        c_plated_Li_av = pybamm.x_average(c_plated_Li)
        L_plated_Li = c_plated_Li  # plated Li thickness
        L_plated_Li_av = pybamm.x_average(L_plated_Li)
        Q_plated_Li = c_plated_Li_av * param.L_n * param.L_y * param.L_z

        domain = self.domain.lower() + " electrode"
        Domain = domain.capitalize()

        variables = {
            f"{Domain} lithium plating concentration":
            c_plated_Li,
            f"{Domain} lithium plating concentration [mol.m-3]":
            c_plated_Li * c_scale,
            f"X-averaged {domain} lithium plating concentration":
            c_plated_Li_av,
            f"X-averaged {domain} lithium plating concentration"
            " [mol.m-3]":
            c_plated_Li_av * c_scale,
            f"{Domain} lithium plating thickness [m]":
            L_plated_Li * L_scale,
            f"X-averaged {domain} lithium plating thickness [m]":
            L_plated_Li_av * L_scale,
            f"Loss of lithium to {domain} lithium plating [mol]":
            Q_plated_Li * c_scale,
            f"Loss of capacity to {domain} lithium plating [A.h]":
            Q_plated_Li * c_scale * param.F / 3600,
        }

        return variables
Esempio n. 13
0
    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.leading_order_model._get_dj_dc(variables)
        dj_ddeltaphi_0 = self.leading_order_model._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 = dj_dc_0 * c_e_1 + dj_ddeltaphi_0 * 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))

        # Add first-order averages
        j_1_bar = dj_dc_0 * pybamm.x_average(
            c_e_1) + dj_ddeltaphi_0 * pybamm.x_average(delta_phi_1)

        variables.update({
            "First-order x-averaged " + self.domain.lower() + " electrode" + self.reaction_name + " interfacial current density":
            j_1_bar
        })

        if self.domain == "Positive":
            variables.update(
                self._get_standard_whole_cell_interfacial_current_variables(
                    variables))
            variables.update(
                self._get_standard_whole_cell_exchange_current_variables(
                    variables))

        return variables
Esempio n. 14
0
    def get_coupled_variables(self, variables):
        c_s = variables[self.domain + " particle concentration"]
        c_s_rav = variables["R-averaged " + self.domain.lower() +
                            " particle concentration"]
        c_s_surf = variables[self.domain + " particle surface concentration"]
        T = pybamm.PrimaryBroadcast(
            variables[self.domain + " electrode temperature"],
            [self.domain.lower() + " particle"],
        )

        # Set flux depending on polynomial order
        if self.name == "uniform profile":
            # The flux is zero since there is no concentration gradient
            N_s = pybamm.FullBroadcastToEdges(
                0,
                [self.domain.lower() + " particle"],
                auxiliary_domains={
                    "secondary": self.domain.lower() + " electrode",
                    "tertiary": "current collector",
                },
            )
            N_s_xav = pybamm.FullBroadcastToEdges(
                0,
                self.domain.lower() + " particle", "current collector")
        elif self.name == "quadratic profile":
            # The flux may be computed directly from the polynomial for c
            if self.domain == "Negative":
                r = pybamm.standard_spatial_vars.r_n
                N_s = -self.param.D_n(c_s, T) * 5 * (c_s_surf - c_s_rav) * r
            elif self.domain == "Positive":
                r = pybamm.standard_spatial_vars.r_p
                N_s = -self.param.D_p(c_s, T) * 5 * (c_s_surf - c_s_rav) * r
            N_s_xav = pybamm.x_average(N_s)
        elif self.name == "quartic profile":
            q_s_rav = variables["R-averaged " + self.domain.lower() +
                                " particle concentration gradient"]
            # The flux may be computed directly from the polynomial for c
            if self.domain == "Negative":
                r = pybamm.standard_spatial_vars.r_n
                N_s = -self.param.D_n(c_s, T) * (
                    (-70 * c_s_surf + 20 * q_s_rav + 70 * c_s_rav) * r +
                    (105 * c_s_surf - 28 * q_s_rav - 105 * c_s_rav) * r**3)
            elif self.domain == "Positive":
                r = pybamm.standard_spatial_vars.r_p
                N_s = -self.param.D_p(c_s, T) * (
                    (-70 * c_s_surf + 20 * q_s_rav + 70 * c_s_rav) * r +
                    (105 * c_s_surf - 28 * q_s_rav - 105 * c_s_rav) * r**3)
            N_s_xav = pybamm.x_average(N_s)

        variables.update(self._get_standard_flux_variables(N_s, N_s_xav))

        return variables
Esempio n. 15
0
    def _get_standard_reaction_variables(self, j_inner, j_outer):
        """
        A private function to obtain the standard variables which
        can be derived from the SEI interfacial reaction current

        Parameters
        ----------
        j_inner : :class:`pybamm.Symbol`
            The inner SEI interfacial reaction current.
        j_outer : :class:`pybamm.Symbol`
            The outer SEI interfacial reaction current.

        Returns
        -------
        variables : dict
            The variables which can be derived from the SEI thicknesses.
        """
        if self.domain == "Negative":
            j_scale = self.param.j_scale_n
        elif self.domain == "Positive":
            j_scale = self.param.j_scale_p
        j_i_av = pybamm.x_average(j_inner)
        j_o_av = pybamm.x_average(j_outer)

        domain = self.domain.lower() + " electrode"

        variables = {
            "Inner " + domain + " sei interfacial current density": j_inner,
            "Inner "
            + domain
            + " sei interfacial current density [A.m-2]": j_inner * j_scale,
            "X-averaged inner " + domain + " sei interfacial current density": j_i_av,
            "X-averaged inner "
            + domain
            + " sei interfacial current density [A.m-2]": j_i_av * j_scale,
            "Outer " + domain + " sei interfacial current density": j_outer,
            "Outer "
            + domain
            + " sei interfacial current density [A.m-2]": j_outer * j_scale,
            "X-averaged outer " + domain + " sei interfacial current density": j_o_av,
            "X-averaged outer "
            + domain
            + " sei interfacial current density [A.m-2]": j_o_av * j_scale,
        }

        j_sei = j_inner + j_outer
        variables.update(self._get_standard_total_reaction_variables(j_sei))

        return variables
Esempio n. 16
0
    def _get_total_concentration_electrolyte(self, c_e, epsilon):
        """
        A private function to obtain the total ion concentration in the electrolyte.

        Parameters
        ----------
        c_e : :class:`pybamm.Symbol`
            The electrolyte concentration
        epsilon : :class:`pybamm.Symbol`
            The porosity

        Returns
        -------
        variables : dict
            The "Total concentration in electrolyte [mol]" variable.
        """

        c_e_typ = self.param.c_e_typ
        L_x = self.param.L_x
        A = self.param.A_cc

        c_e_total = pybamm.x_average(epsilon * c_e)

        variables = {
            "Total concentration in electrolyte [mol]":
            c_e_typ * L_x * A * c_e_total
        }

        return variables
Esempio n. 17
0
    def get_coupled_variables(self, variables):

        j_sei = variables[self.domain + " electrode sei interfacial current density"]
        L_sei = variables["Total " + self.domain.lower() + " electrode sei thickness"]
        c_scale = self.param.c_ec_0_dim
        # concentration of EC on graphite surface, base case = 1
        if self.domain == "Negative":
            C_ec = self.param.C_ec_n

        c_ec = pybamm.Scalar(1) + j_sei * L_sei * C_ec
        c_ec_av = pybamm.x_average(c_ec)
        variables.update(
            {
                self.domain + " electrode EC surface concentration": c_ec,
                self.domain
                + " electrode EC surface concentration [mol.m-3]": c_ec * c_scale,
                "X-averaged "
                + self.domain.lower()
                + " electrode EC surface concentration": c_ec_av,
                "X-averaged "
                + self.domain.lower()
                + " electrode EC surface concentration": c_ec_av * c_scale,
            }
        )
        # Update whole cell variables, which also updates the "sum of" variables
        if (
            "Negative electrode sei interfacial current density" in variables
            and "Positive electrode sei interfacial current density" in variables
            and "Sei interfacial current density" not in variables
        ):
            variables.update(
                self._get_standard_whole_cell_interfacial_current_variables(variables)
            )

        return variables
Esempio n. 18
0
 def _x_average(self, var, var_cn, var_cp):
     """
     Computes the X-average over the whole cell (including current collectors)
     from the variable in the cell (negative electrode, separator,
     positive electrode), negative current collector, and positive current
     collector. This method is overwritten by models which do not include
     current collector effects, so that the average is just taken over the
     negative electrode, separator and positive electrode.
     Note: we do this as we cannot create a single variable which is
     the concatenation [var_cn, var, var_cp] since var_cn and var_cp share the
     same domian. (In the N+1D formulation the current collector variables are
     assumed independent of x, so we do not make the distinction between negative
     and positive current collectors in the geometry).
     """
     # When averging the temperature for x-lumped or xyz-lumped models, var
     # is a concatenation of broadcasts of the X- or Volume- averaged temperature.
     # In this instance we return the (unmodified) variable corresponding to
     # the correct average to avoid a ModelError (the unmodified variables must
     # be the key in model.rhs)
     if isinstance(var, pybamm.Concatenation) and all(
             isinstance(child, pybamm.Broadcast) for child in var.children):
         # Create list of var.ids
         var_ids = [child.children[0].id for child in var.children]
         var_ids.extend([var_cn.id, var_cp.id])
         # If all var.ids the same, then the variable is uniform in x so can
         # just return one the values (arbitrarily var_cn here)
         if len(set(var_ids)) == 1:
             out = var_cn
     else:
         out = (self.param.l_cn * var_cn + pybamm.x_average(var) +
                self.param.l_cp * var_cp) / self.param.l
     return out
Esempio n. 19
0
    def _get_whole_cell_variables(self, variables):
        """
        A private function to obtain the potential and current concatenated
        across the whole cell. Note: requires 'variables' to contain the potential
        and current in the subdomains: 'negative electrode', 'separator', and
        'positive electrode'.

        Parameters
        ----------
        variables : dict
            The variables that have been set in the rest of the model.

        Returns
        -------
        variables : dict
            The variables including the whole-cell electrolyte potentials
            and currents.
        """

        phi_e_n = variables["Negative electrolyte potential"]
        phi_e_s = variables["Separator electrolyte potential"]
        phi_e_p = variables["Positive electrolyte potential"]
        phi_e = pybamm.Concatenation(phi_e_n, phi_e_s, phi_e_p)
        phi_e_av = pybamm.x_average(phi_e)

        i_e_n = variables["Negative electrolyte current density"]
        i_e_s = variables["Separator electrolyte current density"]
        i_e_p = variables["Positive electrolyte current density"]
        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))

        return variables
Esempio n. 20
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
    def _get_neg_pos_coupled_variables(self, variables):
        """
        A private function to get the coupled variables when the domain is 'Negative'
        or 'Positive'.
        """

        param = self.param

        conductivity, sigma_eff = self._get_conductivities(variables)
        i_boundary_cc = variables["Current collector current density"]
        c_e = variables[self.domain + " electrolyte concentration"]
        delta_phi = variables[self.domain +
                              " electrode surface potential difference"]
        T = variables[self.domain + " electrode temperature"]

        i_e = conductivity * (
            ((1 + param.Theta * T) * param.chi(c_e) / c_e) * pybamm.grad(c_e) +
            pybamm.grad(delta_phi) + i_boundary_cc / sigma_eff)
        variables.update(self._get_domain_current_variables(i_e))

        # TODO: Expression can be written in a form which does not require phi_s and
        # so avoid this hack.
        phi_s = self.nasty_hack_to_get_phi_s(variables)
        phi_e = phi_s - delta_phi

        variables.update(self._get_domain_potential_variables(phi_e))
        variables.update({"test": pybamm.x_average(phi_s)})
        return variables
Esempio n. 22
0
 def get_coupled_variables(self, variables):
     variables.update(self._get_standard_surface_variables(variables))
     variables.update(self._get_mechanical_results(variables))
     T = variables[self.domain + " electrode temperature"]
     if self.domain == "Negative":
         k_cr = self.param.k_cr_n(T)
         m_cr = self.param.m_cr_n
         b_cr = self.param.b_cr_n
     else:
         k_cr = self.param.k_cr_p(T)
         m_cr = self.param.m_cr_p
         b_cr = self.param.b_cr_p
     stress_t_surf = variables[self.domain +
                               " particle surface tangential stress"]
     l_cr = variables[self.domain + " particle crack length"]
     # # compressive stress will not lead to crack propagation
     dK_SIF = stress_t_surf * b_cr * pybamm.Sqrt(
         np.pi * l_cr) * (stress_t_surf >= 0)
     dl_cr = k_cr * pybamm.Power(dK_SIF, m_cr) / self.param.t0_cr
     variables.update({
         self.domain + " particle cracking rate":
         dl_cr,
         "X-averaged " + self.domain.lower() + " particle cracking rate":
         pybamm.x_average(dl_cr),
     })
     return variables
    def _get_domain_potential_variables(self, phi_e, domain=None):
        """
        A private function to obtain the standard variables which
        can be derived from the potential in the electrolyte split
        by domain: 'negative electrode', 'separator' and 'positive electrode'.

        Parameters
        ----------
        phi_e : :class:`pybamm.Symbol`
            The potential in the electrolyte within the domain 'domain'.

        Returns
        -------
        variables : dict
            The variables which can be derived from the potential in the
            electrolyte in domain 'domain'.
        """
        domain = domain or self.domain

        pot_scale = self.param.potential_scale
        phi_e_av = pybamm.x_average(phi_e)

        variables = {
            domain + " electrolyte potential":
            phi_e,
            domain + " electrolyte potential [V]":
            phi_e * pot_scale,
            "X-averaged " + domain.lower() + " electrolyte potential":
            phi_e_av,
            "X-averaged " + domain.lower() + " electrolyte potential [V]":
            phi_e_av * pot_scale,
        }

        return variables
Esempio n. 24
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
Esempio n. 25
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
Esempio n. 26
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
Esempio n. 27
0
    def _get_standard_porosity_change_variables(self,
                                                deps_n_dt,
                                                deps_s_dt,
                                                deps_p_dt,
                                                set_leading_order=False):

        if deps_n_dt.domain == ["current collector"]:
            deps_n_dt_av = deps_n_dt
            deps_s_dt_av = deps_s_dt
            deps_p_dt_av = deps_p_dt
            deps_n_dt = pybamm.PrimaryBroadcast(deps_n_dt_av,
                                                "negative electrode")
            deps_s_dt = pybamm.PrimaryBroadcast(deps_s_dt_av, "separator")
            deps_p_dt = pybamm.PrimaryBroadcast(deps_p_dt_av,
                                                "positive electrode")
        else:
            deps_n_dt_av = pybamm.x_average(deps_n_dt)
            deps_s_dt_av = pybamm.x_average(deps_s_dt)
            deps_p_dt_av = pybamm.x_average(deps_p_dt)
        deps_dt = pybamm.concatenation(deps_n_dt, deps_s_dt, deps_p_dt)

        variables = {
            "Porosity change": deps_dt,
            "Negative electrode porosity change": deps_n_dt,
            "Separator porosity change": deps_s_dt,
            "Positive electrode porosity change": deps_p_dt,
            "X-averaged negative electrode porosity change": deps_n_dt_av,
            "X-averaged separator porosity change": deps_s_dt_av,
            "X-averaged positive electrode porosity change": deps_p_dt_av,
        }

        if set_leading_order is True:
            variables.update({
                "Leading-order x-averaged " + "negative electrode porosity change":
                deps_n_dt_av,
                "Leading-order x-averaged separator porosity change":
                deps_s_dt_av,
                "Leading-order x-averaged " + "positive electrode porosity change":
                deps_p_dt_av,
            })

        return variables
Esempio n. 28
0
    def get_fundamental_variables(self):
        if self.domain == "Negative":
            c_s = pybamm.standard_variables.c_s_n

        elif self.domain == "Positive":
            c_s = pybamm.standard_variables.c_s_p

        c_s_xav = pybamm.x_average(c_s)
        variables = self._get_standard_concentration_variables(c_s, c_s_xav)

        return variables
Esempio n. 29
0
    def get_fundamental_variables(self):
        # The particle concentration is uniform throughout the particle, so we
        # can just use the surface value. This avoids dealing with both
        # x *and* r averaged quantities, which may be confusing.

        if self.domain == "Negative":
            c_s_surf_xav = pybamm.standard_variables.c_s_n_surf_xav
            c_s_xav = pybamm.PrimaryBroadcast(c_s_surf_xav,
                                              ["negative particle"])
            c_s = pybamm.SecondaryBroadcast(c_s_xav, ["negative electrode"])

            N_s = pybamm.FullBroadcast(
                0,
                ["negative particle"],
                auxiliary_domains={
                    "secondary": "negative electrode",
                    "tertiary": "current collector",
                },
            )
            N_s_xav = pybamm.x_average(N_s)

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

            N_s = pybamm.FullBroadcast(
                0,
                ["positive particle"],
                auxiliary_domains={
                    "secondary": "positive electrode",
                    "tertiary": "current collector",
                },
            )
            N_s_xav = pybamm.x_average(N_s)

        variables = self._get_standard_concentration_variables(c_s, c_s_xav)
        variables.update(self._get_standard_flux_variables(N_s, N_s_xav))

        return variables
Esempio n. 30
0
    def _get_standard_porosity_variables(self, eps, set_leading_order=False):

        eps_n, eps_s, eps_p = eps.orphans

        variables = {
            "Porosity": eps,
            "Negative electrode porosity": eps_n,
            "Separator porosity": eps_s,
            "Positive electrode porosity": eps_p,
            "X-averaged negative electrode porosity": pybamm.x_average(eps_n),
            "X-averaged separator porosity": pybamm.x_average(eps_s),
            "X-averaged positive electrode porosity": pybamm.x_average(eps_p),
        }

        if set_leading_order is True:
            variables.update({
                "Leading-order negative electrode porosity":
                eps_n,
                "Leading-order separator porosity":
                eps_s,
                "Leading-order positive electrode porosity":
                eps_p,
                "Leading-order x-averaged " + "negative electrode porosity":
                pybamm.x_average(eps_n),
                "Leading-order x-averaged separator porosity":
                pybamm.x_average(eps_s),
                "Leading-order x-averaged " + "positive electrode porosity":
                pybamm.x_average(eps_p),
            })

        return variables