def ode_integrate_rk(fun_rk, x0, time_max, time_step): """ Integrate function using Euler method - fun: Function df/dt = f(x, t) to integrate - x0: Initial state - time_tot: Total time to simulate [s] - time_step: Time step [s] For Runge-Kutta, use: solver = ode(fun) solver.set_integrator('dopri5') solver.set_initial_value(x0, time[0]) xi = solver.integrate(ti) Note that solver.integrate(ti) only integrates for one time step at time ti (where ti is the current time), so you will need to use a for loop Make sure to use the Result class similarly to the example_integrate found above (i.e. Result(x, time)) """ time = np.arange(0, time_max, time_step) x = np.zeros([len(time), len(x0)]) solver = ode(fun_rk) solver.set_integrator('dopri5') solver.set_initial_value(x0, time[0]) for i, ti in enumerate(time): x[i] = solver.integrate(ti) return Result(x, time)
def exercise1(clargs): """ Exercise 1 """ # Setup pylog.info("Running exercise 1") # Setup time_max = 5 # Maximum simulation time time_step = 0.2 # Time step for ODE integration in simulation x0 = np.array([1.]) # Initial state # Integration methods (Exercises 1.a - 1.d) pylog.info("Running function integration using different methods") # Example pylog.debug("Running example plot for integration (remove)") example = example_integrate(x0, time_max, time_step) example.plot_state(figure="Example", label="Example", marker=".") # Analytical (1.a) time = np.arange(0, time_max, time_step) # Time vector x_a = analytic_function(time) analytical = Result(x_a, time) if x_a is not None else None # Euler (1.b) euler = euler_integrate(function, x0, time_max, time_step) # ODE (1.c) ode = ode_integrate(function, x0, time_max, time_step) # ODE Runge-Kutta (1.c) ode_rk = ode_integrate_rk(function_rk, x0, time_max, time_step) # Euler with lower time step (1.d) pylog.warning("Euler with smaller ts must be implemented") euler_time_step = None euler_ts_small = (euler_integrate(function, x0, time_max, euler_time_step) if euler_time_step is not None else None) # Plot integration results plot_integration_methods(analytical=analytical, euler=euler, ode=ode, ode_rk=ode_rk, euler_ts_small=euler_ts_small, euler_timestep=time_step, euler_timestep_small=euler_time_step) # Error analysis (Exercise 1.e) pylog.warning("Error analysis must be implemented") # Show plots of all results if not clargs.save_figures: plt.show() return
def ode_integrate(fun, x0, time_max, time_step): """ Integrate function using Euler method - fun: Function df/dt = f(x, t) to integrate - x0: Initial state - time_tot: Total time to simulate [s] - time_step: Time step [s] Use odeint from the scipy library for integration Make sure to then use the Result class similarly to the example_integrate found above (i.e. Result(x, time)) """ time = np.arange(0, time_max, time_step) x = odeint(fun, x0, time) return Result(x, time)
def euler_integrate(fun, x0, time_max, time_step): """ Integrate function using Euler method - fun: Function df/dt = f(x, t) to integrate - x0: Initial state - time_tot: Total time to simulate [s] - time_step: Time step [s] For loop in Python: >>> a = [0, 0, 0] # Same as [0 for _ in range(3)] (List comprehension) >>> for i in range(3): ... a[i] = i >>> print(a) [0, 1, 2] Creating a matrix of zeros in python: >>> state = np.zeros([3, 2]) >>> print(state) [[0. 0.] [0. 0.] [0. 0.]] For loop for a state in python >>> state = np.zeros([3, 2]) >>> state[0, 0], state[0, 1] = 1, 2 >>> for i, time in enumerate([0, 0.1, 0.2]): ... state[i, 0] += time ... state[i, 1] -= time >>> print(state) [[ 1. 2. ] [ 0.1 -0.1] [ 0.2 -0.2]] Make sure to use the Result class similarly to the example_integrate found above (i.e. Result(x, time)) """ time = np.arange(0, time_max, time_step) x = np.zeros([len(time), len(x0)]) x[0] = x0 for i, ti in enumerate(time[:-1]): x[i + 1] = x[i] + fun(x[i], ti) * time_step return Result(x, time)
def example_integrate(x0, time_max, time_step): """ Example to show how to use Python Note that the Result class takes x and time as input, and is used to facilitate the plotting of the results, where x and time are lists or arrays Additionally, using: r = Result(x, t) You can then use r.state or r.time to extract the original x and t You can then plot the state in function of time with: r.plot_state(figure="Name of figure") """ time = np.arange(0, time_max, time_step) x = np.zeros([len(time), len(x0)]) for i, ti in enumerate(time[:-1]): x[i + 1] = x[i] + 1e-2 * ti # for i in range(len(time[:-1])): # Also possible # x[i+1] = x[i] + 0.2 return Result(x, time)
def exercise1(clargs): """ Exercise 1 """ # Setup pylog.info("Running exercise 1") # Setup time_max = 5 # Maximum simulation time time_step = 0.2 # Time step for ODE integration in simulation x0 = np.array([1.]) # Initial state # Integration methods (Exercises 1.a - 1.d) pylog.info("Running function integration using different methods") # Analytical (1.a) time = np.arange(0, time_max, time_step) # Time vector x_a = analytic_function(time) analytical = Result(x_a, time) if x_a is not None else None # Euler (1.b) euler = euler_integrate(function, x0, time_max, time_step) error(euler.state, analytical.state, "Euler") # ODE (1.c) ode = ode_integrate(function, x0, time_max, time_step) error(ode.state, analytical.state, "LSODA") # ODE Runge-Kutta (1.c) ode_rk = ode_integrate_rk(function_rk, x0, time_max, time_step) error(ode_rk.state, analytical.state, "Runge-Kutta") # Euler with lower time step (1.d) euler_time_step = 0.05 time_small = np.arange(0, time_max, euler_time_step) # Time vector x_a = analytic_function(time_small) analytical_ts_small = Result(x_a, time_small) euler_ts_small = (euler_integrate(function, x0, time_max, euler_time_step) if euler_time_step is not None else None) error(euler_ts_small.state, analytical_ts_small.state, "Euler (smaller ts)") # Plot integration results plot_integration_methods(analytical=analytical, euler=euler, ode=ode, ode_rk=ode_rk, euler_ts_small=euler_ts_small, euler_timestep=time_step, euler_timestep_small=euler_time_step) # Error analysis (Exercise 1.e) pylog.info("Studying integration error using different methods") dt_list = np.logspace(-3, 0, 20) # List of timesteps (powers of 10) integration_errors = [["L1", 1], ["L2", 2], ["Linf", 0]] methods = [["Euler", euler_integrate, function], ["Lsoda", ode_integrate, function], ["RK", ode_integrate_rk, function_rk]] for error_name, error_index in integration_errors: for name, integration_function, f in methods: compute_error(f, analytic_function, integration_function, x0, dt_list, time_max=time_max, figure=error_name, label=name, n=error_index) # Show plots of all results if not clargs.save_figures: plt.show() return