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)
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)
def __mod__(self, other): """return an :class:`Modulo` object""" return pybamm.simplify_if_constant(pybamm.Modulo(self, other), keep_domains=True)