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
        tor = variables[self.domain + " electrode tortuosity"]
        i_boundary_cc = variables["Current collector current density"]
        i_e = variables[self.domain + " electrolyte current density"]

        i_s = i_boundary_cc - i_e

        if self.domain == "Negative":
            conductivity = param.sigma_n * tor
            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 * tor

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

        return phi_s
Beispiel #2
0
    def get_coupled_variables(self, variables):

        # Set up
        param = self.param
        z = pybamm.standard_spatial_vars.z

        # 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) / param.l_s

        # Simple formula for velocity in the separator
        div_Vbox_s = -d_vbox_s_dx
        variables.update(
            self._get_standard_transverse_velocity_variables(
                div_Vbox_s, "acceleration"))

        Vbox_s = pybamm.IndefiniteIntegral(div_Vbox_s, z)
        variables.update(
            self._get_standard_transverse_velocity_variables(
                Vbox_s, "velocity"))

        return variables
    def get_coupled_variables(self, variables):
        param = self.param

        if self.domain in ["Negative", "Positive"]:

            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, T) / c_e) * pybamm.grad(c_e)
                + pybamm.grad(delta_phi)
                + i_boundary_cc / sigma_eff
            )
            variables.update(self._get_domain_current_variables(i_e))

            phi_s = variables[self.domain + " electrode potential"]
            phi_e = phi_s - delta_phi

            variables.update(self._get_domain_potential_variables(phi_e))

        elif self.domain == "Separator":
            x_s = pybamm.standard_spatial_vars.x_s

            i_boundary_cc = variables["Current collector current density"]
            c_e_s = variables["Separator electrolyte concentration"]
            phi_e_n = variables["Negative electrolyte potential"]
            tor_s = variables["Separator porosity"]
            T = variables["Separator temperature"]

            chi_e_s = param.chi(c_e_s, T)
            kappa_s_eff = param.kappa_e(c_e_s, T) * tor_s

            phi_e_s = pybamm.boundary_value(
                phi_e_n, "right"
            ) + pybamm.IndefiniteIntegral(
                (1 + param.Theta * T) * chi_e_s / c_e_s * pybamm.grad(c_e_s)
                - param.C_e * i_boundary_cc / kappa_s_eff,
                x_s,
            )

            i_e_s = pybamm.PrimaryBroadcast(i_boundary_cc, "separator")

            variables.update(self._get_domain_potential_variables(phi_e_s))
            variables.update(self._get_domain_current_variables(i_e_s))

            # Update boundary conditions (for indefinite integral)
            self.boundary_conditions[c_e_s] = {
                "left": (pybamm.BoundaryGradient(c_e_s, "left"), "Neumann"),
                "right": (pybamm.BoundaryGradient(c_e_s, "right"), "Neumann"),
            }

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

        return variables
Beispiel #4
0
    def get_coupled_variables(self, variables):

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

        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.PrimaryBroadcast(
                phi_s_cn, "negative electrode"
            ) - 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",
            )

        variables.update(self._get_standard_potential_variables(phi_s))
        variables.update(self._get_standard_current_variables(i_s))

        if (
            "Negative electrode current density" in variables
            and "Positive electrode current density" in variables
        ):
            variables.update(self._get_standard_whole_cell_variables(variables))

        return variables
Beispiel #5
0
    def test_symbol_new_copy(self):
        a = pybamm.Parameter("a")
        b = pybamm.Parameter("b")
        v_n = pybamm.Variable("v", "negative electrode")
        x_n = pybamm.standard_spatial_vars.x_n
        v_s = pybamm.Variable("v", "separator")
        vec = pybamm.Vector([1, 2, 3, 4, 5])
        mat = pybamm.Matrix([[1, 2], [3, 4]])
        mesh = get_mesh_for_testing()

        for symbol in [
                a + b,
                a - b,
                a * b,
                a / b,
                a**b,
                -a,
                abs(a),
                pybamm.Function(np.sin, a),
                pybamm.FunctionParameter("function", {"a": a}),
                pybamm.grad(v_n),
                pybamm.div(pybamm.grad(v_n)),
                pybamm.upwind(v_n),
                pybamm.IndefiniteIntegral(v_n, x_n),
                pybamm.BackwardIndefiniteIntegral(v_n, x_n),
                pybamm.BoundaryValue(v_n, "right"),
                pybamm.BoundaryGradient(v_n, "right"),
                pybamm.PrimaryBroadcast(a, "domain"),
                pybamm.SecondaryBroadcast(v_n, "current collector"),
                pybamm.FullBroadcast(a, "domain",
                                     {"secondary": "other domain"}),
                pybamm.concatenation(v_n, v_s),
                pybamm.NumpyConcatenation(a, b, v_s),
                pybamm.DomainConcatenation([v_n, v_s], mesh),
                pybamm.Parameter("param"),
                pybamm.InputParameter("param"),
                pybamm.StateVector(slice(0, 56)),
                pybamm.Matrix(np.ones((50, 40))),
                pybamm.SpatialVariable("x", ["negative electrode"]),
                pybamm.t,
                pybamm.Index(vec, 1),
                pybamm.NotConstant(a),
                pybamm.ExternalVariable(
                    "external variable",
                    20,
                    domain="test",
                    auxiliary_domains={"secondary": "test2"},
                ),
                pybamm.minimum(a, b),
                pybamm.maximum(a, b),
                pybamm.SparseStack(mat, mat),
        ]:
            self.assertEqual(symbol.id, symbol.new_copy().id)
Beispiel #6
0
    def test_symbol_new_copy(self):
        a = pybamm.Scalar(0)
        b = pybamm.Scalar(1)
        v_n = pybamm.Variable("v", "negative electrode")
        x_n = pybamm.standard_spatial_vars.x_n
        v_s = pybamm.Variable("v", "separator")
        vec = pybamm.Vector(np.array([1, 2, 3, 4, 5]))
        mesh = get_mesh_for_testing()

        for symbol in [
                a + b,
                a - b,
                a * b,
                a / b,
                a**b,
                -a,
                abs(a),
                pybamm.Function(np.sin, a),
                pybamm.FunctionParameter("function", {"a": a}),
                pybamm.grad(v_n),
                pybamm.div(pybamm.grad(v_n)),
                pybamm.Integral(a, pybamm.t),
                pybamm.IndefiniteIntegral(v_n, x_n),
                pybamm.BackwardIndefiniteIntegral(v_n, x_n),
                pybamm.BoundaryValue(v_n, "right"),
                pybamm.BoundaryGradient(v_n, "right"),
                pybamm.PrimaryBroadcast(a, "domain"),
                pybamm.SecondaryBroadcast(v_n, "current collector"),
                pybamm.FullBroadcast(a, "domain",
                                     {"secondary": "other domain"}),
                pybamm.Concatenation(v_n, v_s),
                pybamm.NumpyConcatenation(a, b, v_s),
                pybamm.DomainConcatenation([v_n, v_s], mesh),
                pybamm.Parameter("param"),
                pybamm.InputParameter("param"),
                pybamm.StateVector(slice(0, 56)),
                pybamm.Matrix(np.ones((50, 40))),
                pybamm.SpatialVariable("x", ["negative electrode"]),
                pybamm.t,
                pybamm.Index(vec, 1),
        ]:
            self.assertEqual(symbol.id, symbol.new_copy().id)
    def _get_sep_coupled_variables(self, variables):
        """
        A private function to get the coupled variables when the domain is 'Separator'.
        """

        param = self.param
        x_s = pybamm.standard_spatial_vars.x_s

        i_boundary_cc = variables["Current collector current density"]
        c_e_s = variables["Separator electrolyte concentration"]
        phi_e_n = variables["Negative electrolyte potential"]
        eps_s = variables["Separator porosity"]
        T = variables["Separator temperature"]

        chi_e_s = param.chi(c_e_s)
        kappa_s_eff = param.kappa_e(c_e_s, T) * (eps_s ** param.b_s)

        phi_e_s = pybamm.PrimaryBroadcast(
            pybamm.boundary_value(phi_e_n, "right"), "separator"
        ) + pybamm.IndefiniteIntegral(
            chi_e_s / c_e_s * pybamm.grad(c_e_s)
            - param.C_e
            * pybamm.PrimaryBroadcast(i_boundary_cc, self.domain_for_broadcast)
            / kappa_s_eff,
            x_s,
        )

        i_e_s = pybamm.PrimaryBroadcast(i_boundary_cc, "separator")

        variables.update(self._get_domain_potential_variables(phi_e_s))
        variables.update(self._get_domain_current_variables(i_e_s))

        # Update boundary conditions (for indefinite integral)
        self.boundary_conditions[c_e_s] = {
            "left": (pybamm.BoundaryGradient(c_e_s, "left"), "Neumann"),
            "right": (pybamm.BoundaryGradient(c_e_s, "right"), "Neumann"),
        }

        return variables
Beispiel #8
0
    def test_indefinite_integral_on_nodes(self):
        mesh = get_mesh_for_testing()
        spatial_methods = {"macroscale": pybamm.FiniteVolume()}
        disc = pybamm.Discretisation(mesh, spatial_methods)

        # input a phi, take grad, then integrate to recover phi approximation
        # (need to test this way as check evaluated on edges using if has grad
        # and no div)
        phi = pybamm.Variable("phi",
                              domain=["negative electrode", "separator"])

        x = pybamm.SpatialVariable("x", ["negative electrode", "separator"])
        int_phi = pybamm.IndefiniteIntegral(phi, x)
        disc.set_variable_slices([phi])
        # Set boundary conditions (required for shape but don't matter)
        int_phi_disc = disc.process_symbol(int_phi)

        combined_submesh = mesh.combine_submeshes("negative electrode",
                                                  "separator")

        # constant case
        phi_exact = np.ones((combined_submesh[0].npts, 1))
        int_phi_exact = combined_submesh[0].edges
        int_phi_approx = int_phi_disc.evaluate(None, phi_exact)[:, 0]
        np.testing.assert_array_equal(int_phi_exact, int_phi_approx)
        # linear case
        phi_exact = combined_submesh[0].nodes[:, np.newaxis]
        int_phi_exact = combined_submesh[0].edges[:, np.newaxis]**2 / 2
        int_phi_approx = int_phi_disc.evaluate(None, phi_exact)
        np.testing.assert_array_almost_equal(int_phi_exact, int_phi_approx)
        # cos case
        phi_exact = np.cos(combined_submesh[0].nodes[:, np.newaxis])
        int_phi_exact = np.sin(combined_submesh[0].edges[:, np.newaxis])
        int_phi_approx = int_phi_disc.evaluate(None, phi_exact)
        np.testing.assert_array_almost_equal(int_phi_exact,
                                             int_phi_approx,
                                             decimal=5)
Beispiel #9
0
    def test_integral(self):
        # time integral
        a = pybamm.Symbol("a")
        t = pybamm.t
        inta = pybamm.Integral(a, t)
        self.assertEqual(inta.name, "integral dtime")
        # self.assertTrue(inta.definite)
        self.assertEqual(inta.children[0].name, a.name)
        self.assertEqual(inta.integration_variable[0], t)
        self.assertEqual(inta.domain, [])

        # space integral
        a = pybamm.Symbol("a", domain=["negative electrode"])
        x = pybamm.SpatialVariable("x", ["negative electrode"])
        inta = pybamm.Integral(a, x)
        self.assertEqual(inta.name, "integral dx ['negative electrode']")
        self.assertEqual(inta.children[0].name, a.name)
        self.assertEqual(inta.integration_variable[0], x)
        self.assertEqual(inta.domain, [])
        self.assertEqual(inta.auxiliary_domains, {})
        # space integral with secondary domain
        a_sec = pybamm.Symbol(
            "a",
            domain=["negative electrode"],
            auxiliary_domains={"secondary": "current collector"},
        )
        x = pybamm.SpatialVariable("x", ["negative electrode"])
        inta_sec = pybamm.Integral(a_sec, x)
        self.assertEqual(inta_sec.domain, ["current collector"])
        self.assertEqual(inta_sec.auxiliary_domains, {})
        # space integral with secondary domain
        a_tert = pybamm.Symbol(
            "a",
            domain=["negative electrode"],
            auxiliary_domains={
                "secondary": "current collector",
                "tertiary": "some extra domain",
            },
        )
        x = pybamm.SpatialVariable("x", ["negative electrode"])
        inta_tert = pybamm.Integral(a_tert, x)
        self.assertEqual(inta_tert.domain, ["current collector"])
        self.assertEqual(inta_tert.auxiliary_domains,
                         {"secondary": ["some extra domain"]})

        # space integral over two variables
        b = pybamm.Symbol("b", domain=["current collector"])
        y = pybamm.SpatialVariable("y", ["current collector"])
        z = pybamm.SpatialVariable("z", ["current collector"])
        inta = pybamm.Integral(b, [y, z])
        self.assertEqual(inta.name, "integral dy dz ['current collector']")
        self.assertEqual(inta.children[0].name, b.name)
        self.assertEqual(inta.integration_variable[0], y)
        self.assertEqual(inta.integration_variable[1], z)
        self.assertEqual(inta.domain, [])

        # Indefinite
        inta = pybamm.IndefiniteIntegral(a, x)
        self.assertEqual(inta.name,
                         "a integrated w.r.t x on ['negative electrode']")
        self.assertEqual(inta.children[0].name, a.name)
        self.assertEqual(inta.integration_variable[0], x)
        self.assertEqual(inta.domain, ["negative electrode"])
        inta_sec = pybamm.IndefiniteIntegral(a_sec, x)
        self.assertEqual(inta_sec.domain, ["negative electrode"])
        self.assertEqual(inta_sec.auxiliary_domains,
                         {"secondary": ["current collector"]})

        # expected errors
        a = pybamm.Symbol("a", domain=["negative electrode"])
        x = pybamm.SpatialVariable("x", ["separator"])
        y = pybamm.Variable("y")
        z = pybamm.SpatialVariable("z", ["negative electrode"])
        with self.assertRaises(pybamm.DomainError):
            pybamm.Integral(a, x)
        with self.assertRaises(ValueError):
            pybamm.Integral(a, y)
Beispiel #10
0
    def test_integral(self):
        # space integral
        a = pybamm.Symbol("a", domain=["negative electrode"])
        x = pybamm.SpatialVariable("x", ["negative electrode"])
        inta = pybamm.Integral(a, x)
        self.assertEqual(inta.name, "integral dx ['negative electrode']")
        self.assertEqual(inta.children[0].name, a.name)
        self.assertEqual(inta.integration_variable[0], x)
        self.assertEqual(inta.domain, [])
        self.assertEqual(inta.auxiliary_domains, {})
        # space integral with secondary domain
        a_sec = pybamm.Symbol(
            "a",
            domain=["negative electrode"],
            auxiliary_domains={"secondary": "current collector"},
        )
        x = pybamm.SpatialVariable("x", ["negative electrode"])
        inta_sec = pybamm.Integral(a_sec, x)
        self.assertEqual(inta_sec.domain, ["current collector"])
        self.assertEqual(inta_sec.auxiliary_domains, {})
        # space integral with tertiary domain
        a_tert = pybamm.Symbol(
            "a",
            domain=["negative electrode"],
            auxiliary_domains={
                "secondary": "current collector",
                "tertiary": "some extra domain",
            },
        )
        x = pybamm.SpatialVariable("x", ["negative electrode"])
        inta_tert = pybamm.Integral(a_tert, x)
        self.assertEqual(inta_tert.domain, ["current collector"])
        self.assertEqual(inta_tert.auxiliary_domains,
                         {"secondary": ["some extra domain"]})

        # space integral *in* secondary domain
        y = pybamm.SpatialVariable("y", ["current collector"])
        # without a tertiary domain
        inta_sec_y = pybamm.Integral(a_sec, y)
        self.assertEqual(inta_sec_y.domain, ["negative electrode"])
        self.assertEqual(inta_sec_y.auxiliary_domains, {})
        # with a tertiary domain
        inta_tert_y = pybamm.Integral(a_tert, y)
        self.assertEqual(inta_tert_y.domain, ["negative electrode"])
        self.assertEqual(inta_tert_y.auxiliary_domains,
                         {"secondary": ["some extra domain"]})

        # space integral *in* tertiary domain
        z = pybamm.SpatialVariable("z", ["some extra domain"])
        inta_tert_z = pybamm.Integral(a_tert, z)
        self.assertEqual(inta_tert_z.domain, ["negative electrode"])
        self.assertEqual(inta_tert_z.auxiliary_domains,
                         {"secondary": ["current collector"]})

        # space integral over two variables
        b = pybamm.Symbol("b", domain=["current collector"])
        y = pybamm.SpatialVariable("y", ["current collector"])
        z = pybamm.SpatialVariable("z", ["current collector"])
        inta = pybamm.Integral(b, [y, z])
        self.assertEqual(inta.name, "integral dy dz ['current collector']")
        self.assertEqual(inta.children[0].name, b.name)
        self.assertEqual(inta.integration_variable[0], y)
        self.assertEqual(inta.integration_variable[1], z)
        self.assertEqual(inta.domain, [])

        # Indefinite
        inta = pybamm.IndefiniteIntegral(a, x)
        self.assertEqual(inta.name,
                         "a integrated w.r.t x on ['negative electrode']")
        self.assertEqual(inta.children[0].name, a.name)
        self.assertEqual(inta.integration_variable[0], x)
        self.assertEqual(inta.domain, ["negative electrode"])
        inta_sec = pybamm.IndefiniteIntegral(a_sec, x)
        self.assertEqual(inta_sec.domain, ["negative electrode"])
        self.assertEqual(inta_sec.auxiliary_domains,
                         {"secondary": ["current collector"]})
        # backward indefinite integral
        inta = pybamm.BackwardIndefiniteIntegral(a, x)
        self.assertEqual(
            inta.name,
            "a integrated backward w.r.t x on ['negative electrode']")

        # expected errors
        a = pybamm.Symbol("a", domain=["negative electrode"])
        x = pybamm.SpatialVariable("x", ["separator"])
        y = pybamm.Variable("y")
        z = pybamm.SpatialVariable("z", ["negative electrode"])
        with self.assertRaises(pybamm.DomainError):
            pybamm.Integral(a, x)
        with self.assertRaisesRegex(TypeError, "integration_variable must be"):
            pybamm.Integral(a, y)
        with self.assertRaisesRegex(
                NotImplementedError,
                "Indefinite integral only implemeted w.r.t. one variable",
        ):
            pybamm.IndefiniteIntegral(a, [x, y])
Beispiel #11
0
    def get_coupled_variables(self, variables):
        c_e_av = variables["X-averaged electrolyte concentration"]

        i_boundary_cc_0 = variables[
            "Leading-order current collector current density"]
        c_e_n = variables["Negative electrolyte concentration"]
        c_e_s = variables["Separator electrolyte concentration"]
        c_e_p = variables["Positive electrolyte concentration"]
        c_e_n0 = pybamm.boundary_value(c_e_n, "left")

        delta_phi_n_av = variables[
            "X-averaged negative electrode surface potential difference"]
        phi_s_n_av = variables["X-averaged negative electrode potential"]

        tor_n = variables["Negative electrolyte tortuosity"]
        tor_s = variables["Separator tortuosity"]
        tor_p = variables["Positive electrolyte tortuosity"]

        T_av = variables["X-averaged cell temperature"]
        T_av_n = pybamm.PrimaryBroadcast(T_av, "negative electrode")
        T_av_s = pybamm.PrimaryBroadcast(T_av, "separator")
        T_av_p = pybamm.PrimaryBroadcast(T_av, "positive electrode")

        param = self.param
        l_n = param.l_n
        l_p = param.l_p
        x_n = pybamm.standard_spatial_vars.x_n
        x_s = pybamm.standard_spatial_vars.x_s
        x_p = pybamm.standard_spatial_vars.x_p
        x_n_edge = pybamm.standard_spatial_vars.x_n_edge
        x_p_edge = pybamm.standard_spatial_vars.x_p_edge

        chi_av = param.chi(c_e_av, T_av)
        chi_av_n = pybamm.PrimaryBroadcast(chi_av, "negative electrode")
        chi_av_s = pybamm.PrimaryBroadcast(chi_av, "separator")
        chi_av_p = pybamm.PrimaryBroadcast(chi_av, "positive electrode")

        # electrolyte current
        i_e_n = i_boundary_cc_0 * x_n / l_n
        i_e_s = pybamm.PrimaryBroadcast(i_boundary_cc_0, "separator")
        i_e_p = i_boundary_cc_0 * (1 - x_p) / l_p
        i_e = pybamm.Concatenation(i_e_n, i_e_s, i_e_p)

        i_e_n_edge = i_boundary_cc_0 * x_n_edge / l_n
        i_e_s_edge = pybamm.PrimaryBroadcastToEdges(i_boundary_cc_0,
                                                    "separator")
        i_e_p_edge = i_boundary_cc_0 * (1 - x_p_edge) / l_p

        # electrolyte potential
        indef_integral_n = (pybamm.IndefiniteIntegral(
            i_e_n_edge / (param.kappa_e(c_e_n, T_av_n) * tor_n), x_n) *
                            param.C_e / param.gamma_e)
        indef_integral_s = (pybamm.IndefiniteIntegral(
            i_e_s_edge / (param.kappa_e(c_e_s, T_av_s) * tor_s), x_s) *
                            param.C_e / param.gamma_e)
        indef_integral_p = (pybamm.IndefiniteIntegral(
            i_e_p_edge / (param.kappa_e(c_e_p, T_av_p) * tor_p), x_p) *
                            param.C_e / param.gamma_e)

        integral_n = indef_integral_n
        integral_s = indef_integral_s + pybamm.boundary_value(
            integral_n, "right")
        integral_p = indef_integral_p + pybamm.boundary_value(
            integral_s, "right")

        phi_e_const = (
            -delta_phi_n_av + phi_s_n_av -
            (chi_av * (1 + param.Theta * T_av) * pybamm.x_average(
                self._higher_order_macinnes_function(c_e_n / c_e_n0))) +
            pybamm.x_average(integral_n))

        phi_e_n = (phi_e_const +
                   (chi_av_n * (1 + param.Theta * T_av_n) *
                    self._higher_order_macinnes_function(c_e_n / c_e_n0)) -
                   integral_n)

        phi_e_s = (phi_e_const +
                   (chi_av_s * (1 + param.Theta * T_av_s) *
                    self._higher_order_macinnes_function(c_e_s / c_e_n0)) -
                   integral_s)

        phi_e_p = (phi_e_const +
                   (chi_av_p * (1 + param.Theta * T_av_p) *
                    self._higher_order_macinnes_function(c_e_p / c_e_n0)) -
                   integral_p)

        # concentration overpotential
        eta_c_av = (chi_av * (1 + param.Theta * T_av) * (pybamm.x_average(
            self._higher_order_macinnes_function(
                c_e_p / c_e_av)) - pybamm.x_average(
                    self._higher_order_macinnes_function(c_e_n / c_e_av))))

        # average electrolyte ohmic losses
        delta_phi_e_av = -(pybamm.x_average(integral_p) -
                           pybamm.x_average(integral_n))

        variables.update(
            self._get_standard_potential_variables(phi_e_n, phi_e_s, phi_e_p))
        variables.update(self._get_standard_current_variables(i_e))
        variables.update(
            self._get_split_overpotential(eta_c_av, delta_phi_e_av))

        return variables
Beispiel #12
0
    def test_indefinite_integral(self):

        # create discretisation
        mesh = get_mesh_for_testing()
        spatial_methods = {
            "macroscale": pybamm.FiniteVolume(),
            "negative particle": pybamm.FiniteVolume(),
            "positive particle": pybamm.FiniteVolume(),
            "current collector": pybamm.ZeroDimensionalMethod(),
        }
        disc = pybamm.Discretisation(mesh, spatial_methods)

        # input a phi, take grad, then integrate to recover phi approximation
        # (need to test this way as check evaluated on edges using if has grad
        # and no div)
        phi = pybamm.Variable("phi",
                              domain=["negative electrode", "separator"])
        i = pybamm.grad(phi)  # create test current (variable on edges)

        x = pybamm.SpatialVariable("x", ["negative electrode", "separator"])
        int_grad_phi = pybamm.IndefiniteIntegral(i, x)
        disc.set_variable_slices([phi])  # i is not a fundamental variable
        # Set boundary conditions (required for shape but don't matter)
        disc._bcs = {
            phi.id: {
                "left": (pybamm.Scalar(0), "Neumann"),
                "right": (pybamm.Scalar(0), "Neumann"),
            }
        }
        int_grad_phi_disc = disc.process_symbol(int_grad_phi)
        left_boundary_value = pybamm.BoundaryValue(int_grad_phi, "left")
        left_boundary_value_disc = disc.process_symbol(left_boundary_value)

        combined_submesh = mesh.combine_submeshes("negative electrode",
                                                  "separator")

        # constant case
        phi_exact = np.ones((combined_submesh[0].npts, 1))
        phi_approx = int_grad_phi_disc.evaluate(None, phi_exact)
        phi_approx += 1  # add constant of integration
        np.testing.assert_array_equal(phi_exact, phi_approx)
        self.assertEqual(left_boundary_value_disc.evaluate(y=phi_exact), 0)
        # linear case
        phi_exact = combined_submesh[0].nodes[:, np.newaxis]
        phi_approx = int_grad_phi_disc.evaluate(None, phi_exact)
        np.testing.assert_array_almost_equal(phi_exact, phi_approx)
        self.assertEqual(left_boundary_value_disc.evaluate(y=phi_exact), 0)

        # sine case
        phi_exact = np.sin(combined_submesh[0].nodes[:, np.newaxis])
        phi_approx = int_grad_phi_disc.evaluate(None, phi_exact)
        np.testing.assert_array_almost_equal(phi_exact, phi_approx)
        self.assertEqual(left_boundary_value_disc.evaluate(y=phi_exact), 0)

        # --------------------------------------------------------------------
        # region which doesn't start at zero
        phi = pybamm.Variable("phi",
                              domain=["separator", "positive electrode"])
        i = pybamm.grad(phi)  # create test current (variable on edges)
        x = pybamm.SpatialVariable("x", ["separator", "positive electrode"])
        int_grad_phi = pybamm.IndefiniteIntegral(i, x)
        disc.set_variable_slices([phi])  # i is not a fundamental variable
        disc._bcs = {
            phi.id: {
                "left": (pybamm.Scalar(0), "Neumann"),
                "right": (pybamm.Scalar(0), "Neumann"),
            }
        }
        int_grad_phi_disc = disc.process_symbol(int_grad_phi)
        left_boundary_value = pybamm.BoundaryValue(int_grad_phi, "left")
        left_boundary_value_disc = disc.process_symbol(left_boundary_value)
        combined_submesh = mesh.combine_submeshes("separator",
                                                  "positive electrode")

        # constant case
        phi_exact = np.ones((combined_submesh[0].npts, 1))
        phi_approx = int_grad_phi_disc.evaluate(None, phi_exact)
        phi_approx += 1  # add constant of integration
        np.testing.assert_array_equal(phi_exact, phi_approx)
        self.assertEqual(left_boundary_value_disc.evaluate(y=phi_exact), 0)

        # linear case
        phi_exact = (combined_submesh[0].nodes[:, np.newaxis] -
                     combined_submesh[0].edges[0])
        phi_approx = int_grad_phi_disc.evaluate(None, phi_exact)
        np.testing.assert_array_almost_equal(phi_exact, phi_approx)
        np.testing.assert_array_almost_equal(
            left_boundary_value_disc.evaluate(y=phi_exact), 0)

        # sine case
        phi_exact = np.sin(combined_submesh[0].nodes[:, np.newaxis] -
                           combined_submesh[0].edges[0])
        phi_approx = int_grad_phi_disc.evaluate(None, phi_exact)
        np.testing.assert_array_almost_equal(phi_exact, phi_approx)
        np.testing.assert_array_almost_equal(
            left_boundary_value_disc.evaluate(y=phi_exact), 0)

        # --------------------------------------------------------------------
        # micrsoscale case
        c = pybamm.Variable("c", domain=["negative particle"])
        N = pybamm.grad(c)  # create test current (variable on edges)
        r_n = pybamm.SpatialVariable("r_n", ["negative particle"])
        c_integral = pybamm.IndefiniteIntegral(N, r_n)
        disc.set_variable_slices([c])  # N is not a fundamental variable
        disc._bcs = {
            c.id: {
                "left": (pybamm.Scalar(0), "Neumann"),
                "right": (pybamm.Scalar(0), "Neumann"),
            }
        }

        c_integral_disc = disc.process_symbol(c_integral)
        left_boundary_value = pybamm.BoundaryValue(c_integral, "left")
        left_boundary_value_disc = disc.process_symbol(left_boundary_value)
        combined_submesh = mesh["negative particle"]

        # constant case
        c_exact = np.ones((combined_submesh[0].npts, 1))
        c_approx = c_integral_disc.evaluate(None, c_exact)
        c_approx += 1  # add constant of integration
        np.testing.assert_array_equal(c_exact, c_approx)
        self.assertEqual(left_boundary_value_disc.evaluate(y=c_exact), 0)

        # linear case
        c_exact = combined_submesh[0].nodes[:, np.newaxis]
        c_approx = c_integral_disc.evaluate(None, c_exact)
        np.testing.assert_array_almost_equal(c_exact, c_approx)
        np.testing.assert_array_almost_equal(
            left_boundary_value_disc.evaluate(y=c_exact), 0)

        # sine case
        c_exact = np.sin(combined_submesh[0].nodes[:, np.newaxis])
        c_approx = c_integral_disc.evaluate(None, c_exact)
        np.testing.assert_array_almost_equal(c_exact, c_approx, decimal=3)
        np.testing.assert_array_almost_equal(
            left_boundary_value_disc.evaluate(y=c_exact), 0)