def test_convert_scalar_symbols(self):
        a = pybamm.Scalar(0)
        b = pybamm.Scalar(1)
        c = pybamm.Scalar(-1)
        d = pybamm.Scalar(2)
        e = pybamm.Scalar(3)
        g = pybamm.Scalar(3.3)

        self.assertEqual(a.to_casadi(), casadi.MX(0))
        self.assertEqual(d.to_casadi(), casadi.MX(2))

        # negate
        self.assertEqual((-b).to_casadi(), casadi.MX(-1))
        # absolute value
        self.assertEqual(abs(c).to_casadi(), casadi.MX(1))
        # floor
        self.assertEqual(pybamm.Floor(g).to_casadi(), casadi.MX(3))
        # ceiling
        self.assertEqual(pybamm.Ceiling(g).to_casadi(), casadi.MX(4))

        # function
        def square_plus_one(x):
            return x**2 + 1

        f = pybamm.Function(square_plus_one, b)
        self.assertEqual(f.to_casadi(), 2)

        def myfunction(x, y):
            return x + y

        f = pybamm.Function(myfunction, b, d)
        self.assertEqual(f.to_casadi(), casadi.MX(3))

        # use classes to avoid simplification
        # addition
        self.assertEqual((pybamm.Addition(a, b)).to_casadi(), casadi.MX(1))
        # subtraction
        self.assertEqual(pybamm.Subtraction(c, d).to_casadi(), casadi.MX(-3))
        # multiplication
        self.assertEqual(
            pybamm.Multiplication(c, d).to_casadi(), casadi.MX(-2))
        # power
        self.assertEqual(pybamm.Power(c, d).to_casadi(), casadi.MX(1))
        # division
        self.assertEqual(pybamm.Division(b, d).to_casadi(), casadi.MX(1 / 2))

        # modulo
        self.assertEqual(pybamm.Modulo(e, d).to_casadi(), casadi.MX(1))

        # minimum and maximum
        self.assertEqual(pybamm.Minimum(a, b).to_casadi(), casadi.MX(0))
        self.assertEqual(pybamm.Maximum(a, b).to_casadi(), casadi.MX(1))
    def test_model_step_nonsmooth_events(self):
        # Create model
        model = pybamm.BaseModel()
        model.timescale = pybamm.Scalar(1)
        var1 = pybamm.Variable("var1")
        var2 = pybamm.Variable("var2")
        a = 0.6
        discontinuities = (np.arange(3) + 1) * a

        model.rhs = {var1: pybamm.Modulo(pybamm.t * model.timescale, a)}
        model.algebraic = {var2: 2 * var1 - var2}
        model.initial_conditions = {var1: 0, var2: 0}
        model.events = [
            pybamm.Event("var1 = 0.55", pybamm.min(var1 - 0.55)),
            pybamm.Event("var2 = 1.2", pybamm.min(var2 - 1.2)),
        ]
        for discontinuity in discontinuities:
            model.events.append(
                pybamm.Event("nonsmooth rate", pybamm.Scalar(discontinuity)))
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Solve
        step_solver = pybamm.ScikitsDaeSolver(rtol=1e-8, atol=1e-8)
        dt = 0.05
        time = 0
        end_time = 3
        step_solution = None
        while time < end_time:
            step_solution = step_solver.step(step_solution,
                                             model,
                                             dt=dt,
                                             npts=10)
            time += dt
        np.testing.assert_array_less(step_solution.y[0, :-1], 0.55)
        np.testing.assert_array_less(step_solution.y[-1, :-1], 1.2)
        np.testing.assert_equal(step_solution.t_event[0], step_solution.t[-1])
        np.testing.assert_array_equal(step_solution.y_event[:, 0],
                                      step_solution.y[:, -1])
        var1_soln = (step_solution.t %
                     a)**2 / 2 + a**2 / 2 * (step_solution.t // a)
        var2_soln = 2 * var1_soln
        np.testing.assert_array_almost_equal(step_solution.y[0],
                                             var1_soln,
                                             decimal=5)
        np.testing.assert_array_almost_equal(step_solution.y[-1],
                                             var2_soln,
                                             decimal=5)
Exemple #3
0
 def __mod__(self, other):
     """return an :class:`Modulo` object."""
     return pybamm.simplify_if_constant(pybamm.Modulo(self, other))
    def test_model_solver_dae_multiple_nonsmooth_python(self):
        model = pybamm.BaseModel()
        model.convert_to_format = "python"
        whole_cell = ["negative electrode", "separator", "positive electrode"]
        var1 = pybamm.Variable("var1", domain=whole_cell)
        var2 = pybamm.Variable("var2", domain=whole_cell)
        a = 0.6
        discontinuities = (np.arange(3) + 1) * a

        model.rhs = {var1: pybamm.Modulo(pybamm.t, a)}
        model.algebraic = {var2: 2 * var1 - var2}
        model.initial_conditions = {var1: 0, var2: 0}
        model.events = [
            pybamm.Event("var1 = 0.55", pybamm.min(var1 - 0.55)),
            pybamm.Event("var2 = 1.2", pybamm.min(var2 - 1.2)),
        ]
        for discontinuity in discontinuities:
            model.events.append(
                pybamm.Event("nonsmooth rate", pybamm.Scalar(discontinuity)))
        disc = get_discretisation_for_testing()
        disc.process_model(model)

        # Solve
        solver = pybamm.ScikitsDaeSolver(rtol=1e-8,
                                         atol=1e-8,
                                         root_method="lm")

        # create two time series, one without a time point on the discontinuity,
        # and one with
        t_eval1 = np.linspace(0, 2, 10)
        t_eval2 = np.insert(t_eval1, np.searchsorted(t_eval1, discontinuities),
                            discontinuities)
        solution1 = solver.solve(model, t_eval1)
        solution2 = solver.solve(model, t_eval2)

        # check time vectors
        for solution in [solution1, solution2]:
            # time vectors are ordered
            self.assertTrue(np.all(solution.t[:-1] <= solution.t[1:]))

            # time value before and after discontinuity is an epsilon away
            for discontinuity in discontinuities:
                dindex = np.searchsorted(solution.t, discontinuity)
                value_before = solution.t[dindex - 1]
                value_after = solution.t[dindex]
                self.assertEqual(value_before + sys.float_info.epsilon,
                                 discontinuity)
                self.assertEqual(value_after - sys.float_info.epsilon,
                                 discontinuity)

        # both solution time vectors should have same number of points
        self.assertEqual(len(solution1.t), len(solution2.t))

        # check solution
        for solution in [solution1, solution2]:
            np.testing.assert_array_less(solution.y[0, :-1], 0.55)
            np.testing.assert_array_less(solution.y[-1, :-1], 1.2)
            var1_soln = (solution.t % a)**2 / 2 + a**2 / 2 * (solution.t // a)
            var2_soln = 2 * var1_soln
            np.testing.assert_allclose(solution.y[0], var1_soln, rtol=1e-06)
            np.testing.assert_allclose(solution.y[-1], var2_soln, rtol=1e-06)
Exemple #5
0
 def __mod__(self, other):
     """return an :class:`Modulo` object"""
     return pybamm.simplify_if_constant(pybamm.Modulo(self, other),
                                        keep_domains=True)