Exemple #1
0
    def test_symbol_replacements(self):
        a = pybamm.Parameter("a")
        b = pybamm.Parameter("b")
        c = pybamm.Parameter("c")
        d = pybamm.Parameter("d")
        replacer = pybamm.SymbolReplacer({a: b, c: d})

        for symbol_in, symbol_out in [
            (a, b),  # just the symbol
            (a + a, b + b),  # binary operator
            (2 * pybamm.sin(a), 2 * pybamm.sin(b)),  # function
            (3 * b, 3 * b),  # no replacement
            (a + c, b + d),  # two replacements
        ]:
            replaced_symbol = replacer.process_symbol(symbol_in)
            self.assertEqual(replaced_symbol.id, symbol_out.id)

        var1 = pybamm.Variable("var 1", domain="dom 1")
        var2 = pybamm.Variable("var 2", domain="dom 2")
        var3 = pybamm.Variable("var 3", domain="dom 1")
        conc = pybamm.concatenation(var1, var2)

        replacer = pybamm.SymbolReplacer({var1: var3})
        replaced_symbol = replacer.process_symbol(conc)
        self.assertEqual(replaced_symbol.id,
                         pybamm.concatenation(var3, var2).id)
    def test_advanced_functions(self):
        a = pybamm.StateVector(slice(0, 1))
        b = pybamm.StateVector(slice(1, 2))
        y = np.array([5, 3])

        #
        func = a * pybamm.exp(b)
        self.assertAlmostEqual(func.diff(a).evaluate(y=y)[0], np.exp(3))
        func = pybamm.exp(a + 2 * b + a * b) + a * pybamm.exp(b)
        self.assertEqual(
            func.diff(a).evaluate(y=y), (4 * np.exp(3 * 5 + 5 + 2 * 3) + np.exp(3))
        )
        self.assertEqual(
            func.diff(b).evaluate(y=y), np.exp(3) * (7 * np.exp(3 * 5 + 5 + 3) + 5)
        )
        #
        func = pybamm.sin(pybamm.cos(a * 4) / 2) * pybamm.cos(4 * pybamm.exp(b / 3))
        self.assertEqual(
            func.diff(a).evaluate(y=y),
            -2 * np.sin(20) * np.cos(np.cos(20) / 2) * np.cos(4 * np.exp(1)),
        )
        self.assertEqual(
            func.diff(b).evaluate(y=y),
            -4 / 3 * np.exp(1) * np.sin(4 * np.exp(1)) * np.sin(np.cos(20) / 2),
        )
        #
        func = pybamm.sin(a * b)
        self.assertEqual(func.diff(a).evaluate(y=y), 3 * np.cos(15))
Exemple #3
0
    def test_functions(self):
        y = pybamm.StateVector(slice(0, 4))
        u = pybamm.StateVector(slice(0, 2))
        v = pybamm.StateVector(slice(2, 4))
        const = pybamm.Scalar(1)

        y0 = np.array([1.0, 2.0, 3.0, 4.0])

        func = pybamm.sin(u)
        jacobian = np.array([[np.cos(1), 0, 0, 0], [0, np.cos(2), 0, 0]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.cos(v)
        jacobian = np.array([[0, 0, -np.sin(3), 0], [0, 0, 0, -np.sin(4)]])
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.sin(3 * u * v)
        jacobian = np.array(
            [
                [9 * np.cos(9), 0, 3 * np.cos(9), 0],
                [0, 12 * np.cos(24), 0, 6 * np.cos(24)],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.cos(5 * pybamm.exp(u + v))
        jacobian = np.array(
            [
                [
                    -5 * np.exp(4) * np.sin(5 * np.exp(4)),
                    0,
                    -5 * np.exp(4) * np.sin(5 * np.exp(4)),
                    0,
                ],
                [
                    0,
                    -5 * np.exp(6) * np.sin(5 * np.exp(6)),
                    0,
                    -5 * np.exp(6) * np.sin(5 * np.exp(6)),
                ],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        # when child evaluates to number
        func = pybamm.Sin(const)
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(0, dfunc_dy)

        # several children
        func = pybamm.Function(test_multi_var_function, 2 * y, 3 * y)
        jacobian = np.diag(5 * np.ones(4))
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())
Exemple #4
0
    def test_functions(self):
        y = pybamm.StateVector(slice(0, 8))
        u = pybamm.StateVector(slice(0, 2), slice(4, 6))
        v = pybamm.StateVector(slice(2, 4), slice(6, 8))

        y0 = np.arange(1, 9)
        const = pybamm.Scalar(1)

        func = pybamm.sin(u)
        jacobian = np.array(
            [
                [np.cos(1), 0, 0, 0, 0, 0, 0, 0],
                [0, np.cos(2), 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, np.cos(5), 0, 0, 0],
                [0, 0, 0, 0, 0, np.cos(6), 0, 0],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.cos(v)
        jacobian = np.array(
            [
                [0, 0, -np.sin(3), 0, 0, 0, 0, 0],
                [0, 0, 0, -np.sin(4), 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, -np.sin(7), 0],
                [0, 0, 0, 0, 0, 0, 0, -np.sin(8)],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        func = pybamm.sin(3 * u * v)
        jacobian = np.array(
            [
                [9 * np.cos(9), 0, 3 * np.cos(9), 0, 0, 0, 0, 0],
                [0, 12 * np.cos(24), 0, 6 * np.cos(24), 0, 0, 0, 0],
                [0, 0, 0, 0, 21 * np.cos(105), 0, 15 * np.cos(105), 0],
                [0, 0, 0, 0, 0, 24 * np.cos(144), 0, 18 * np.cos(144)],
            ]
        )
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())

        # when child evaluates to number
        func = pybamm.sin(const)
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(0, dfunc_dy)

        # several children
        func = pybamm.Function(test_multi_var_function, 2 * y, 3 * y)
        jacobian = np.diag(5 * np.ones(8))
        dfunc_dy = func.jac(y).evaluate(y=y0)
        np.testing.assert_array_equal(jacobian, dfunc_dy.toarray())
Exemple #5
0
 def test_sin(self):
     a = pybamm.InputParameter("a")
     fun = pybamm.sin(a)
     self.assertIsInstance(fun, pybamm.Sin)
     self.assertEqual(fun.children[0].id, a.id)
     self.assertEqual(fun.evaluate(inputs={"a": 3}), np.sin(3))
     h = 0.0000001
     self.assertAlmostEqual(
         fun.diff(a).evaluate(inputs={"a": 3}),
         (pybamm.sin(pybamm.Scalar(3 + h)).evaluate() -
          fun.evaluate(inputs={"a": 3})) / h,
         places=5,
     )
Exemple #6
0
 def test_sin(self):
     a = pybamm.Scalar(3)
     fun = pybamm.sin(a)
     self.assertIsInstance(fun, pybamm.Sin)
     self.assertEqual(fun.children[0].id, a.id)
     self.assertEqual(fun.evaluate(), np.sin(3))
     self.assertEqual(fun.diff(a).evaluate(), np.cos(3))
Exemple #7
0
    def test_diff(self):
        a = pybamm.StateVector(slice(0, 1))
        b = pybamm.StateVector(slice(1, 2))
        y = np.array([5])
        func = pybamm.Function(test_function, a)
        self.assertEqual(func.diff(a).evaluate(y=y), 2)
        self.assertEqual(func.diff(func).evaluate(), 1)
        func = pybamm.sin(a)
        self.assertEqual(func.evaluate(y=y), np.sin(a.evaluate(y=y)))
        self.assertEqual(func.diff(a).evaluate(y=y), np.cos(a.evaluate(y=y)))
        func = pybamm.exp(a)
        self.assertEqual(func.evaluate(y=y), np.exp(a.evaluate(y=y)))
        self.assertEqual(func.diff(a).evaluate(y=y), np.exp(a.evaluate(y=y)))

        # multiple variables
        func = pybamm.Function(test_multi_var_function, 4 * a, 3 * a)
        self.assertEqual(func.diff(a).evaluate(y=y), 7)
        func = pybamm.Function(test_multi_var_function, 4 * a, 3 * b)
        self.assertEqual(func.diff(a).evaluate(y=np.array([5, 6])), 4)
        self.assertEqual(func.diff(b).evaluate(y=np.array([5, 6])), 3)
        func = pybamm.Function(test_multi_var_function_cube, 4 * a, 3 * b)
        self.assertEqual(func.diff(a).evaluate(y=np.array([5, 6])), 4)
        self.assertEqual(
            func.diff(b).evaluate(y=np.array([5, 6])), 3 * 3 * (3 * 6) ** 2
        )

        # exceptions
        func = pybamm.Function(
            test_multi_var_function_cube, 4 * a, 3 * b, derivative="derivative"
        )
        with self.assertRaises(ValueError):
            func.diff(a)
 def beta(T):
     T_inf = pybamm.FunctionParameter("T_inf", {"x": self.x})
     h = pybamm.Parameter("h")
     eps0 = pybamm.Parameter("eps0")
     return (1e-4 * (1.0 + 5.0 * pybamm.sin(3 * np.pi * T / 200.0) +
                     pybamm.exp(0.02 * T)) / eps0 + h * (T_inf - T) /
             (T_inf**4 - T**4) / eps0)
    def test_model_solver_with_bounds(self):
        # Note: we need a better test case to test this functionality properly
        # Create model
        model = pybamm.BaseModel()
        var1 = pybamm.Variable("var1", bounds=(0, 10))
        model.algebraic = {var1: pybamm.sin(var1) + 1}
        model.initial_conditions = {var1: pybamm.Scalar(3)}
        model.variables = {"var1": var1}

        # Solve
        solver = pybamm.CasadiAlgebraicSolver(tol=1e-12)
        solution = solver.solve(model)
        np.testing.assert_array_almost_equal(solution["var1"].data,
                                             3 * np.pi / 2)
Exemple #10
0
    def test_model_solver_minimize_with_bounds(self):
        # Note: we need a better test case to test this functionality properly
        # Create model
        model = pybamm.BaseModel()
        var1 = pybamm.Variable("var1", bounds=(0, 10))
        model.algebraic = {var1: pybamm.sin(var1) + 1}
        model.initial_conditions = {var1: pybamm.Scalar(3)}
        model.variables = {"var1": var1}

        # Solve
        solver = pybamm.AlgebraicSolver("minimize", tol=1e-16)
        solution = solver.solve(model)
        np.testing.assert_array_almost_equal(
            model.variables["var1"].evaluate(t=None, y=solution.y),
            3 * np.pi / 2,
            decimal=4,
        )
Exemple #11
0
 def __init__(self, e_class):
     self.dim_dict=e_class.dim_dict
     self.nd_dict=e_class.nd_param.nd_param_dict
     self.model=pybamm.BaseModel()
     self.parameter_dict={}
     self.pybam_val_dict={}
     self.simulation_options=e_class.simulation_options
     self.dim_keys=self.nd_dict.keys()
     self.time=e_class.time_vec
     for key in self.dim_keys:
         self.parameter_dict[key]=pybamm.InputParameter(key)
         self.pybam_val_dict[key]=None
     self.current=pybamm.Variable("current")
     self.theta=pybamm.Variable("theta")
     if self.simulation_options["method"]=="dcv":
         Edc_forward = pybamm.t
         Edc_backwards = -(pybamm.t - 2*self.parameter_dict["tr"])
         E_t = self.parameter_dict["E_start"]+ \
         (pybamm.t <= self.parameter_dict["tr"]) * Edc_forward + \
         (pybamm.t > self.parameter_dict["tr"]) * Edc_backwards
     elif self.simulation_options["method"]=="sinusoidal":
         E_t=self.parameter_dict["E_start"]+self.parameter_dict["d_E"]+(self.parameter_dict["d_E"]*pybamm.sin((self.parameter_dict["nd_omega"]*pybamm.t)+self.parameter_dict["phase"]))
     elif self.simulation_options["method"]=="ramped":
         Edc_forward = pybamm.t
         Edc_backwards = -(pybamm.t - 2*self.parameter_dict["tr"])
         E_t = self.parameter_dict["E_start"]+ \
         (pybamm.t <= self.parameter_dict["tr"]) * Edc_forward + \
         (pybamm.t > self.parameter_dict["tr"]) * Edc_backwards+\
         (self.parameter_dict["d_E"]*pybamm.sin((self.parameter_dict["nd_omega"]*pybamm.t)+self.parameter_dict["phase"]))
     Er=E_t-(self.parameter_dict["Ru"]*self.current)
     ErE0=Er-self.parameter_dict["E_0"]
     alpha=self.parameter_dict["alpha"]
     if "Cdlinv" not in e_class.optim_list:
         Cdlp=self.parameter_dict["Cdl"]*(1+self.parameter_dict["CdlE1"]*Er+self.parameter_dict["CdlE2"]*(Er**2)+self.parameter_dict["CdlE3"]*(Er**3))
     else:
         Cdlp=(pybamm.t <= self.parameter_dict["tr"]) *(self.parameter_dict["Cdl"]*(1+self.parameter_dict["CdlE1"]*Er+self.parameter_dict["CdlE2"]*(Er**2)+self.parameter_dict["CdlE3"]*(Er**3)))+\
         (pybamm.t > self.parameter_dict["tr"]) *(self.parameter_dict["Cdlinv"]*(1+self.parameter_dict["CdlE1inv"]*Er+self.parameter_dict["CdlE2inv"]*(Er**2)+self.parameter_dict["CdlE3inv"]*(Er**3)))
     self.model.variables={"current":self.current, "theta":self.theta}
     d_thetadt=((1-self.theta)*self.parameter_dict["k_0"]*pybamm.exp((1-alpha)*ErE0))-(self.theta*self.parameter_dict["k_0"]*pybamm.exp((-alpha)*ErE0))
     dIdt=(E_t.diff(pybamm.t)-(self.current/Cdlp)+self.parameter_dict["gamma"]*d_thetadt*(1/Cdlp))/self.parameter_dict["Ru"]
     self.model.rhs={self.current:dIdt, self.theta:d_thetadt}
     self.disc=pybamm.Discretisation()
     self.model.initial_conditions={self.theta:pybamm.Scalar(1), self.current:pybamm.Scalar(0)}
     self.disc.process_model(self.model)
Exemple #12
0
        def get_error(m):
            # create mesh and discretisation p2d, uniform in x
            mesh = get_p2d_mesh_for_testing(3, m)
            disc = pybamm.Discretisation(mesh, spatial_methods)
            submesh = mesh["negative particle"]
            r = submesh[0].nodes
            r_edge = pybamm.standard_spatial_vars.r_n_edge

            N = r_edge ** 2 * pybamm.sin(r_edge)
            div_eqn = pybamm.div(N)
            # Define exact solutions
            # N = r**2*sin(r) --> div(N) = 4*r*sin(r) - r**2*cos(r)
            div_exact = 4 * r * np.sin(r) + r ** 2 * np.cos(r)
            div_exact = np.kron(np.ones(len(submesh)), div_exact)

            # Discretise and evaluate
            div_eqn_disc = disc.process_symbol(div_eqn)
            div_approx = div_eqn_disc.evaluate()

            return div_approx[:, 0] - div_exact
        def get_error(n):
            # create mesh and discretisation (single particle)
            mesh = get_mesh_for_testing(rpts=n)
            disc = pybamm.Discretisation(mesh, spatial_methods)
            submesh = mesh["negative particle"]
            r = submesh.nodes
            r_edge = pybamm.SpatialVariableEdge("r_n", domain=["negative particle"])

            # Define flux and bcs
            N = r_edge ** 2 * pybamm.sin(r_edge)
            div_eqn = pybamm.div(N)
            # Define exact solutions
            # N = r**3 --> div(N) = 5 * r**2
            div_exact = 4 * r * np.sin(r) + r ** 2 * np.cos(r)

            # Discretise and evaluate
            div_eqn_disc = disc.process_symbol(div_eqn)
            div_approx = div_eqn_disc.evaluate()

            # Return difference between approx and exact
            return div_approx[:, 0] - div_exact
Exemple #14
0
        def get_error(n):
            # create mesh and discretisation (single particle)
            mesh = get_mesh_for_testing(rpts=n)
            disc = pybamm.Discretisation(mesh, spatial_methods)
            submesh = mesh["negative particle"]
            r = submesh[0].nodes
            r_edge = pybamm.standard_spatial_vars.r_n_edge

            # Define flux and bcs
            N = r_edge * pybamm.sin(r_edge)
            div_eqn = pybamm.div(N)
            # Define exact solutions
            # N = r*sin(r) --> div(N) = 3*sin(r) + r*cos(r)
            div_exact = 3 * np.sin(r) + r * np.cos(r)

            # Discretise and evaluate
            div_eqn_disc = disc.process_symbol(div_eqn)
            div_approx = div_eqn_disc.evaluate()

            # Return difference between approx and exact
            return div_approx[:, 0] - div_exact
Exemple #15
0
        def get_error(m):
            # create mesh and discretisation p2d, x-dependent
            mesh = get_p2d_mesh_for_testing(6, m)
            disc = pybamm.Discretisation(mesh, spatial_methods)
            submesh_r = mesh["negative particle"]
            r = submesh_r.nodes
            r_edge = pybamm.standard_spatial_vars.r_n_edge
            x = pybamm.standard_spatial_vars.x_n

            N = pybamm.PrimaryBroadcast(
                x, "negative particle") * (r_edge**2 * pybamm.sin(r_edge))
            div_eqn = pybamm.div(N)
            # Define exact solutions
            # N = r**2*sin(r) --> div(N) = 4*r*sin(r) - r**2*cos(r)
            div_exact = 4 * r * np.sin(r) + r**2 * np.cos(r)
            div_exact = np.kron(mesh["negative electrode"].nodes, div_exact)

            # Discretise and evaluate
            div_eqn_disc = disc.process_symbol(div_eqn)
            div_approx = div_eqn_disc.evaluate()

            return div_approx[:, 0] - div_exact
def my_fun(t, A, omega):
    return A * pybamm.sin(2 * np.pi * omega * t)
Exemple #17
0
    def __init__(self, param=None):
        # Set fixed parameters here
        if param is None:
            param = pybamm.ParameterValues({
                "Far-field concentration of S(soln) [mol cm-3]":
                1e-6,
                "Diffusion Constant [cm2 s-1]":
                7.2e-6,
                "Faraday Constant [C mol-1]":
                96485.3328959,
                "Gas constant [J K-1 mol-1]":
                8.314459848,
                "Electrode Area [cm2]":
                0.07,
                "Temperature [K]":
                273.0,
                "Voltage frequency [rad s-1]":
                9.0152,
                "Voltage start [V]":
                0.4,
                "Voltage reverse [V]":
                -0.4,
                "Voltage amplitude [V]":
                0.0,  # 0.05,
                "Scan Rate [V s-1]":
                0.05,
                "Electrode Coverage [mol cm2]":
                6.5e-12,
            })

        # Create dimensional fixed parameters
        D = pybamm.Parameter("Diffusion Constant [cm2 s-1]")
        F = pybamm.Parameter("Faraday Constant [C mol-1]")
        R = pybamm.Parameter("Gas constant [J K-1 mol-1]")
        a = pybamm.Parameter("Electrode Area [cm2]")
        T = pybamm.Parameter("Temperature [K]")
        omega_d = pybamm.Parameter("Voltage frequency [rad s-1]")
        E_start_d = pybamm.Parameter("Voltage start [V]")
        E_reverse_d = pybamm.Parameter("Voltage reverse [V]")
        deltaE_d = pybamm.Parameter("Voltage amplitude [V]")
        v = pybamm.Parameter("Scan Rate [V s-1]")
        Gamma = pybamm.Parameter("Electrode Coverage [mol cm2]")

        # Create dimensional input parameters
        E0_d = pybamm.InputParameter("Reversible Potential [V]")
        k0_d = pybamm.InputParameter("Redox Rate [s-1]")
        kcat_d = pybamm.InputParameter("Catalytic Rate [cm3 mol-l s-1]")
        alpha = pybamm.InputParameter("Symmetry factor [non-dim]")
        Cdl_d = pybamm.InputParameter("Capacitance [F]")
        Ru_d = pybamm.InputParameter("Uncompensated Resistance [Ohm]")

        # Create scaling factors for non-dimensionalisation
        E_0 = R * T / F
        T_0 = E_0 / v
        I_0 = F * a * Gamma / T
        L_0 = pybamm.sqrt(D * T_0)

        # Non-dimensionalise parameters
        E0 = E0_d / E_0
        k0 = k0_d * T_0
        kcat = kcat_d * Gamma * L_0 / D
        Cdl = Cdl_d * a * E_0 / (I_0 * T_0)
        Ru = Ru_d * I_0 / E_0

        omega = 2 * np.pi * omega_d * T_0
        E_start = E_start_d / E_0
        E_reverse = E_reverse_d / E_0
        t_reverse = E_start - E_reverse
        deltaE = deltaE_d / E_0

        # Input voltage protocol
        Edc_forward = -pybamm.t
        Edc_backwards = pybamm.t - 2 * t_reverse
        Eapp = E_start + \
            (pybamm.t <= t_reverse) * Edc_forward + \
            (pybamm.t > t_reverse) * Edc_backwards + \
            deltaE * pybamm.sin(omega * pybamm.t)

        # create PyBaMM model object
        model = pybamm.BaseModel()

        # Create state variables for model
        theta = pybamm.Variable("O(surf) [non-dim]")
        c = pybamm.Variable("S(soln) [non-dim]", domain="solution")
        i = pybamm.Variable("Current [non-dim]")

        # Effective potential
        Eeff = Eapp - i * Ru

        # Faridaic current (Butler Volmer)
        i_f = k0 * ((1 - theta) * pybamm.exp(
            (1 - alpha) * (Eeff - E0)) - theta * pybamm.exp(-alpha *
                                                            (Eeff - E0)))

        c_at_electrode = pybamm.BoundaryValue(c, "left")

        # Catalytic current
        i_cat = kcat * c_at_electrode * (1 - theta)

        # ODE equations
        model.rhs = {
            theta: i_f + i_cat,
            i: 1 / (Cdl * Ru) * (i_f + Cdl * Eapp.diff(pybamm.t) - i - i_cat),
            c: pybamm.div(pybamm.grad(c)),
        }

        # algebraic equations (none)
        model.algebraic = {}

        # Boundary and initial conditions
        model.boundary_conditions = {
            c: {
                "right": (pybamm.Scalar(1), "Dirichlet"),
                "left": (i_cat, "Neumann"),
            }
        }

        model.initial_conditions = {
            theta: pybamm.Scalar(1),
            i: Cdl * Eapp.diff(pybamm.t),
            c: pybamm.Scalar(1),
        }

        # set spatial variables and solution domain geometry
        x = pybamm.SpatialVariable('x', domain="solution")
        model.geometry = pybamm.Geometry({
            "solution": {
                x: {
                    "min": pybamm.Scalar(0),
                    "max": pybamm.Scalar(20)
                }
            }
        })
        model.var_pts = {x: 100}

        # Using Finite Volume discretisation on an expanding 1D grid
        model.submesh_types = {
            "solution":
            pybamm.MeshGenerator(pybamm.Exponential1DSubMesh, {'side': 'left'})
        }
        model.spatial_methods = {"solution": pybamm.FiniteVolume()}

        # model variables
        model.variables = {
            "Current [non-dim]": i,
            "O(surf) [non-dim]": theta,
            "S(soln) at electrode [non-dim]": c_at_electrode,
            "Applied Voltage [non-dim]": Eapp,
        }
        # --------------------------------

        # Set model parameters
        param.process_model(model)
        geometry = model.geometry
        param.process_geometry(geometry)

        # Create mesh and discretise model
        mesh = pybamm.Mesh(geometry, model.submesh_types, model.var_pts)
        disc = pybamm.Discretisation(mesh, model.spatial_methods)
        disc.process_model(model)

        # Create solver
        model.convert_to_format = 'python'
        solver = pybamm.ScipySolver(method='BDF', rtol=1e-6, atol=1e-6)
        #solver = pybamm.CasadiSolver(mode='fast', rtol=1e-8, atol=1e-10)

        # Store discretised model and solver
        self._model = model
        self._param = param
        self._solver = solver
        self._omega_d = param.process_symbol(omega_d).evaluate()
        self._I_0 = param.process_symbol(I_0).evaluate()
        self._T_0 = param.process_symbol(T_0).evaluate()
Exemple #18
0
    def __init__(self, n=100, max_x=10, param=None):
        # Set fixed parameters here
        if param is None:
            param = pybamm.ParameterValues({
                "Far-field concentration of A [mol cm-3]":
                1e-6,
                "Diffusion Constant [cm2 s-1]":
                7.2e-6,
                "Faraday Constant [C mol-1]":
                96485.3328959,
                "Gas constant [J K-1 mol-1]":
                8.314459848,
                "Electrode Area [cm2]":
                0.07,
                "Temperature [K]":
                297.0,
                "Voltage frequency [rad s-1]":
                9.0152,
                "Voltage start [V]":
                0.5,
                "Voltage reverse [V]":
                -0.1,
                "Voltage amplitude [V]":
                0.08,
                "Scan Rate [V s-1]":
                0.08941,
            })

        # Create dimensional fixed parameters
        c_inf = pybamm.Parameter("Far-field concentration of A [mol cm-3]")
        D = pybamm.Parameter("Diffusion Constant [cm2 s-1]")
        F = pybamm.Parameter("Faraday Constant [C mol-1]")
        R = pybamm.Parameter("Gas constant [J K-1 mol-1]")
        S = pybamm.Parameter("Electrode Area [cm2]")
        T = pybamm.Parameter("Temperature [K]")

        E_start_d = pybamm.Parameter("Voltage start [V]")
        E_reverse_d = pybamm.Parameter("Voltage reverse [V]")
        deltaE_d = pybamm.Parameter("Voltage amplitude [V]")
        v = pybamm.Parameter("Scan Rate [V s-1]")

        # Create dimensional input parameters
        E0 = pybamm.InputParameter("Reversible Potential [non-dim]")
        k0 = pybamm.InputParameter("Reaction Rate [non-dim]")
        alpha = pybamm.InputParameter("Symmetry factor [non-dim]")
        Cdl = pybamm.InputParameter("Capacitance [non-dim]")
        Ru = pybamm.InputParameter("Uncompensated Resistance [non-dim]")
        omega_d = pybamm.InputParameter("Voltage frequency [rad s-1]")

        E0_d = pybamm.InputParameter("Reversible Potential [V]")
        k0_d = pybamm.InputParameter("Reaction Rate [s-1]")
        alpha = pybamm.InputParameter("Symmetry factor [non-dim]")
        Cdl_d = pybamm.InputParameter("Capacitance [F]")
        Ru_d = pybamm.InputParameter("Uncompensated Resistance [Ohm]")

        # Create scaling factors for non-dimensionalisation
        E_0 = R * T / F
        T_0 = E_0 / v
        L_0 = pybamm.sqrt(D * T_0)
        I_0 = D * F * S * c_inf / L_0

        # Non-dimensionalise parameters
        E0 = E0_d / E_0
        k0 = k0_d * L_0 / D
        Cdl = Cdl_d * S * E_0 / (I_0 * T_0)
        Ru = Ru_d * I_0 / E_0
        omega = 2 * np.pi * omega_d * T_0

        E_start = E_start_d / E_0
        E_reverse = E_reverse_d / E_0
        t_reverse = E_start - E_reverse
        deltaE = deltaE_d / E_0

        # Input voltage protocol
        Edc_forward = -pybamm.t
        Edc_backwards = pybamm.t - 2 * t_reverse
        Eapp = E_start + \
            (pybamm.t <= t_reverse) * Edc_forward + \
            (pybamm.t > t_reverse) * Edc_backwards + \
            deltaE * pybamm.sin(omega * pybamm.t)

        # create PyBaMM model object
        model = pybamm.BaseModel()

        # Create state variables for model
        theta = pybamm.Variable("ratio_A", domain="solution")
        i = pybamm.Variable("Current")

        # Effective potential
        Eeff = Eapp - i * Ru

        # Faradaic current
        i_f = pybamm.BoundaryGradient(theta, "left")

        # ODE equations
        model.rhs = {
            theta: pybamm.div(pybamm.grad(theta)),
            i: 1 / (Cdl * Ru) * (-i_f + Cdl * Eapp.diff(pybamm.t) - i),
        }

        # algebraic equations (none)
        model.algebraic = {}

        # Butler-volmer boundary condition at electrode
        theta_at_electrode = pybamm.BoundaryValue(theta, "left")
        butler_volmer = k0 * (theta_at_electrode * pybamm.exp(-alpha *
                                                              (Eeff - E0)) -
                              (1 - theta_at_electrode) * pybamm.exp(
                                  (1 - alpha) * (Eeff - E0)))

        # Boundary and initial conditions
        model.boundary_conditions = {
            theta: {
                "right": (pybamm.Scalar(1), "Dirichlet"),
                "left": (butler_volmer, "Neumann"),
            }
        }

        model.initial_conditions = {
            theta: pybamm.Scalar(1),
            i: Cdl * (-1.0 + deltaE * omega),
        }

        # set spatial variables and solution domain geometry
        x = pybamm.SpatialVariable('x', domain="solution")
        default_geometry = pybamm.Geometry({
            "solution": {
                x: {
                    "min": pybamm.Scalar(0),
                    "max": pybamm.Scalar(max_x)
                }
            }
        })

        default_var_pts = {x: n}

        # Using Finite Volume discretisation on an expanding 1D grid for solution
        default_submesh_types = {
            "solution":
            pybamm.MeshGenerator(pybamm.Exponential1DSubMesh, {'side': 'left'})
        }
        default_spatial_methods = {"solution": pybamm.FiniteVolume()}

        # model variables
        model.variables = {
            "Current [non-dim]": i,
        }

        #--------------------------------

        # Set model parameters
        param.process_model(model)
        geometry = default_geometry
        param.process_geometry(geometry)

        # Create mesh and discretise model
        mesh = pybamm.Mesh(geometry, default_submesh_types, default_var_pts)
        disc = pybamm.Discretisation(mesh, default_spatial_methods)
        disc.process_model(model)

        # Create solver
        solver = pybamm.CasadiSolver(
            mode="fast",
            rtol=1e-9,
            atol=1e-9,
            extra_options_setup={'print_stats': False})
        #model.convert_to_format = 'jax'
        #solver = pybamm.JaxSolver(method='BDF')
        #model.convert_to_format = 'python'
        #solver = pybamm.ScipySolver(method='BDF')

        # Store discretised model and solver
        self._model = model
        self._solver = solver
        self._fast_solver = None
        self._omega_d = param["Voltage frequency [rad s-1]"]

        self._I_0 = param.process_symbol(I_0).evaluate()
        self._T_0 = param.process_symbol(T_0).evaluate()
        self._E_0 = param.process_symbol(E_0).evaluate()
        self._L_0 = param.process_symbol(L_0).evaluate()
        self._S = param.process_symbol(S).evaluate()
        self._D = param.process_symbol(D).evaluate()
        self._default_var_points = default_var_pts