diff --git a/UB4/UB4.py b/UB4/UB4.py index 1d81dfccd2463fdb96a4d70c2fdc2629f144456c..a31f962baf1f002d6ca1d110c83097550a9d30c3 100644 --- a/UB4/UB4.py +++ b/UB4/UB4.py @@ -1,6 +1,8 @@ import numpy as np import matplotlib.pyplot as plt from tqdm import trange +from typing import Callable + # Ex1: Numerical integrators @@ -17,12 +19,12 @@ def implicit_euler(f, y0: np.ndarray, t: float, dt: float, eps = 1e-5, **kwargs) y[0] = y0 for i in trange(1, no_of_steps): - y_0 = y[i-1] + dt * f(y[i-1]) # predicted state obtained through EE - y_1 = y[i-1] + dt * f(y_0) + y_0 = y[i-1] + dt * f(y[i-1], **kwargs) # predicted state obtained through EE + y_1 = y[i-1] + dt * f(y_0, **kwargs) - while abs(y_1 - y_0) > eps: + while np.linalg.norm(y_1 - y_0) > eps: y_0 = y_1 - y_1 = y[i-1] + dt * f(y_0) + y_1 = y[i-1] + dt * f(y_0, **kwargs) y[i] = y_1 return y @@ -58,7 +60,7 @@ def implicit_midpoint(f, y0: np.ndarray, t: float, dt: float, eps = 1e-5, **kwar y_0 = y[i-1] + dt * f(y[i-1] + dt/2 * f(y[i-1], **kwargs), **kwargs) # predicted state obtained through IM y_1 = y[i-1] + dt * f( 1/2 * (y[i-1] + y_0) ,**kwargs) - while abs(y_1 - y_0) > eps: + while np.linalg.norm(y_1 - y_0) > eps: y_0 = y_1 y_1 = y[i-1] + dt * f( 1/2 * (y[i-1] + y_0) ,**kwargs) y[i] = y_1 @@ -102,17 +104,17 @@ exact_solution = lambda t : np.exp(lamda * t) * y0 ### t = 10, dt = 1e-2 <-- Strange behaviour ! # They all behave similarly. They do not decay as rapidly as ES. -for i in range(len(dt)): - plt.figure() - y_implicit_euler = implicit_euler(f, y0, t[1], dt[i]) - plt.plot(implicit_euler(f, y0, t[1], dt[i]), '--', label = "implicit euler (IE)") - plt.plot(explicit_euler(f, y0, t[1], dt[i]), 'x', label = "explicit euler (EE)") - plt.plot(implicit_midpoint(f, y0, t[1], dt[i]), '>', label = "implicit midpoint (IM)") - time = np.arange(int(t[1] // dt[i])) - plt.plot(exact_solution(time), '3', label="exact solution (ES)") - plt.legend() - plt.title(f't={t[1]}, dt={dt[i]}') - plt.show() +# for i in range(len(dt)): +# plt.figure() +# y_implicit_euler = implicit_euler(f, y0, t[1], dt[i]) +# plt.plot(implicit_euler(f, y0, t[1], dt[i]), '--', label = "implicit euler (IE)") +# plt.plot(explicit_euler(f, y0, t[1], dt[i]), 'x', label = "explicit euler (EE)") +# plt.plot(implicit_midpoint(f, y0, t[1], dt[i]), '>', label = "implicit midpoint (IM)") +# time = np.arange(int(t[1] // dt[i])) +# plt.plot(exact_solution(time), '3', label="exact solution (ES)") +# plt.legend() +# plt.title(f't={t[1]}, dt={dt[i]}') +# plt.show() #### Observation ### t = 100, dt = 0.9 <-- Strange behaviour ! @@ -124,50 +126,212 @@ for i in range(len(dt)): # Ex3: -# def f(y: np.ndarray, k: float) -> np.ndarray: -# assert y.shape[0] == 3, 'y has the wrong dimension. It should be 3' +def f(y: np.ndarray, k: float) -> np.ndarray: + assert y.shape[0] == 3, 'y has the wrong dimension. It should be 3' -# A = np.array([[-1, 1, 0], -# [1, -1-k, k], -# [0, k, -k]]) + A = np.array([[-1, 1, 0], # S1 -> S2 + [1, -1-k, k], # S2 -> S1, S2 -> S3 + [0, k, -k]]) # S3 -> S2 -# return np.dot(A, y) + return np.dot(A, y) + +dt = [0.5, 1e-1, 1e-2] +t = 10 +y0 = np.array([1,0,0]) + +### short time +# fig = plt.figure() +# for dt_i in dt: +# y = implicit_euler(f, y0, t, dt_i, k=1) +# plt.plot(y[:,0], '--',label = 'State 1') +# plt.plot(y[:,1], 'x', label = 'State 2') +# plt.plot(y[:,2], '>', label = 'State 3') +# plt.legend() +# plt.title(f"IE, dt = {dt_i}") +# plt.show() + + +# fig = plt.figure() +# for dt_i in dt: +# y = explicit_euler(f, y0, t, dt_i, k=1) +# plt.plot(y[:,0], '--', label = 'State 1') +# plt.plot(y[:,1], 'x', label = 'State 2') +# plt.plot(y[:,2], '>', label = 'State 3') +# plt.legend() +# plt.title(f"EE, dt = {dt_i}") +# plt.show() + + +# fig = plt.figure() +# for dt_i in dt: +# y = implicit_midpoint(f, y0, t, dt_i, k=1) +# plt.plot(y[:,0], '--', label = 'State 1') +# plt.plot(y[:,1], 'x', label = 'State 2') +# plt.plot(y[:,2], '>', label = 'State 3') +# plt.legend() +# plt.title(f"IM, dt = {dt_i}") +# plt.show() + -# dt = [1, 1e-1, 1e-2, 1e-3] -# t = [10,100] -# y0 = np.array([1,0,0]) +#### Observation +# Diverging behaviour for dt in [0.9, 0.7] for EE +# Funny behaviour fot dt in [0.9, 0.45] for IE (only 1 point) +# Funny behaviour for dt in [0.9, 0.7] for IM (only 1 point) -# # short time +### k = 1e-3 # fig = plt.figure() # for dt_i in dt: -# y = implicit_euler(f, y0, t[0], dt_i, k=1) +# y = implicit_euler(f, y0, t, dt_i, k=1e-3) # plt.plot(y[:,0], '--',label = 'State 1') # plt.plot(y[:,1], 'x', label = 'State 2') # plt.plot(y[:,2], '>', label = 'State 3') # plt.legend() -# plt.title(f'{integrators[0]}, dt = {dt_i}') +# plt.title(f"IE, dt = {dt_i}") # plt.show() # fig = plt.figure() # for dt_i in dt: -# y = explicit_euler(f, y0, t[0], dt_i, k=1) +# y = explicit_euler(f, y0, t, dt_i, k=1e-3) # plt.plot(y[:,0], '--', label = 'State 1') # plt.plot(y[:,1], 'x', label = 'State 2') # plt.plot(y[:,2], '>', label = 'State 3') # plt.legend() -# plt.title(f'{integrators[1]}, dt = {dt_i}') +# plt.title(f"EE, dt = {dt_i}") # plt.show() # fig = plt.figure() # for dt_i in dt: -# y = implicit_midpoint(f, y0, t[0], dt_i, k=1) +# y = implicit_midpoint(f, y0, t, dt_i, k=1e-3) # plt.plot(y[:,0], '--', label = 'State 1') # plt.plot(y[:,1], 'x', label = 'State 2') # plt.plot(y[:,2], '>', label = 'State 3') # plt.legend() -# plt.title(f'{integrators[2]}, dt = {dt_i}') +# plt.title(f"IM, dt = {dt_i}") # plt.show() +### different init cond +y0 = np.array([0.5,0.2,0.3]) + +### k = 1e-3 +# fig = plt.figure() +# for dt_i in dt: +# y = implicit_euler(f, y0, t, dt_i, k=1e-3) +# plt.plot(y[:,0], '--',label = 'State 1') +# plt.plot(y[:,1], 'x', label = 'State 2') +# plt.plot(y[:,2], '>', label = 'State 3') +# plt.legend() +# plt.title(f"IE, dt = {dt_i}") +# plt.show() + + +# fig = plt.figure() +# for dt_i in dt: +# y = explicit_euler(f, y0, t, dt_i, k=1e-3) +# plt.plot(y[:,0], '--', label = 'State 1') +# plt.plot(y[:,1], 'x', label = 'State 2') +# plt.plot(y[:,2], '>', label = 'State 3') +# plt.legend() +# plt.title(f"EE, dt = {dt_i}") +# plt.show() + + +# fig = plt.figure() +# for dt_i in dt: +# y = implicit_midpoint(f, y0, t, dt_i, k=1e-3) +# plt.plot(y[:,0], '--', label = 'State 1') +# plt.plot(y[:,1], 'x', label = 'State 2') +# plt.plot(y[:,2], '>', label = 'State 3') +# plt.legend() +# plt.title(f"IM, dt = {dt_i}") +# plt.show() + + +# Ex4: HO +## A. Integrator +# p_dot = - partial H / partial q = -q +# q_dot = partial H / partial p = p + +p_0 = np.array([0]) +q_0 = np.array([1]) +t = 100 +dt = 0.001 + +def HO_IE(p_0: np.ndarray, q_0: np.ndarray, t: float, dt: float): + """ + Integrator = implicit Euler + p_dot = - partial H / partial q = -q + q_dot = partial H / partial p = p + """ + no_of_steps = int(t // dt) + p = np.zeros((no_of_steps, *p_0.shape)) + q = np.zeros((no_of_steps, *q_0.shape)) + p[0] = p_0 + q[0] = q_0 + + for i in trange(1, no_of_steps): + p[i] = 1/(1 + dt**2) * (p[i-1] - dt * q[i-1]) + q[i] = 1/(1 + dt**2) * (q[i-1] + dt * p[i-1]) + + return p, q + +def HO_EE(p_0: np.ndarray, q_0: np.ndarray, t: float, dt: float): + """ + Integrator = explicit Euler + p_dot = - partial H / partial q = -q + q_dot = partial H / partial p = p + """ + no_of_steps = int(t // dt) + p = np.zeros((no_of_steps, *p_0.shape)) + q = np.zeros((no_of_steps, *q_0.shape)) + p[0] = p_0 + q[0] = q_0 + + for i in trange(1, no_of_steps): + p[i] = p[i-1] + dt * -q[i-1] + q[i] = q[i-1] + dt * p[i-1] + + return p, q + +def HO_IM(p_0: np.ndarray, q_0: np.ndarray, t: float, dt: float): + """ + Integrator = implicit midpoint + p_dot = - partial H / partial q = -q + q_dot = partial H / partial p = p + """ + no_of_steps = int(t // dt) + p = np.zeros((no_of_steps, *p_0.shape)) + q = np.zeros((no_of_steps, *q_0.shape)) + p[0] = p_0 + q[0] = q_0 + + for i in trange(1, no_of_steps): + q[i] = (q[i-1] + dt*(p[i-1] - dt/4 * q[i-1])) / (1 + dt**2 / 4) + p[i] = (p[i-1] - dt*(q[i-1] - dt/4 * p[i-1])) / (1 + dt**2 / 4) + + return p, q + +p, q = HO_IE(p_0, q_0, t, dt) +plt.figure() +plt.plot(p, q) +plt.title("Implicit Euler") +plt.show() +### Observation -> Could see that phase space volume increases + +p, q = HO_EE(p_0, q_0, t, dt) +plt.figure() +plt.plot(p, q) +plt.title("Explicit Euler") +plt.show() + +p, q = HO_IM(p_0, q_0, t, dt) +plt.figure() +plt.plot(p, q) +plt.title("Implicit midpoint") +plt.show() +### Observation -> Conserve phase space volume better than the other 2 methods + + +