import matplotlib.pyplot as plt import numpy as np import numpy.linalg as lin import scipy.sparse as sp from scipy.sparse.linalg import spsolve def kappa_integral(x,y): # todo 3 a) return 0.5 * (y**2 - x**2) + y -x def build_massMatrix(N): # todo 3 b) M = np.identity(N) return M def build_rigidityMatrix(N): # todo 3 b) # Be careful with the indices! # kappa_integral could be helpful here M = np.zeros((N,N)) h = 1/(N+1) # The case of i=j for i in range(N): M[i,i] = kappa_integral((h-1)*i, h*i) \ + kappa_integral(h*i, (h+1)*i) # to be filled # The case of i-j=1 for i in range(1,N): M[i, i-1] = - kappa_integral(h*i, h*(i+1))# to be filled # The case of j-i=1 for i in range(N-1): M[i, i+1] = - kappa_integral(h*(i-1),h*i)# to be filled return M def f(t,x): # todo 3 c) return ((x + 1) * np.pi **2 - 1) * np.exp(-t) * np.sin(np.pi * x) - np.pi * np.exp(-t) * np.cos(np.pi * x) def initial_value(x): # todo 3 c) return np.sin(np.pi * x) def exact_solution_at_1(x): # todo 3 c) return np.exp(-1) * np.sin(np.pi * x) def build_F(t,N): # todo 3 d) h = 1/(N+1) x = np.linspace(0,1,N+1) return h/3 * (f(t, x - h/2) + f(t,x) + f(t, x + h/2)) def FEM_theta(N,M,theta): # todo 3 e) h = 1/(N+1) k = 1/(M+1) u = initial_value(np.linspace(0,1,N+1)) M_matrix = build_massMatrix(N) B = theta * M_matrix C = (1 - theta) * M_matrix - k * build_rigidityMatrix(N) F = build_F(0,N) for m in range(M): if (theta != 0): u = np.linalg.solve(B, C @ u + F) elif (theta == 0): u = C @ u + F F = build_F(m*k,N) return u #### error analysis #### nb_samples = 5 exponents = np.arange(2,7) N = np.pow(2,exponents) - 1 # fill in this line for f)-g) M = np.pow(2, exponents) # fill in this line for f)-g) theta= .3# fill in this line for f)-g) #### Do not change any code below! #### l2error = np.zeros(nb_samples) k = 1 / M try: for i in range(nb_samples): l2error[i] = (1 / (N[i]+1)) ** (1 / 2) * lin.norm(exact_solution_at_1((1/(N[i]+1))*(np.arange(N[i])+1)) - FEM_theta(N[i], M[i],theta), ord=2) if np.isnan(l2error[i])==True: raise Exception("Error unbounded. Plots not shown.") conv_rate = np.polyfit(np.log(k), np.log(l2error), deg=1) if conv_rate[0]<0: raise Exception("Error unbounded. Plots not shown.") print(f"FEM method with theta={theta} converges: Convergence rate in discrete $L^2$ norm with respect to time step $k$: {conv_rate[0]}") plt.figure(figsize=[10, 6]) plt.loglog(k, l2error, '-x', label='error') plt.loglog(k, k, '--', label='$O(k)$') plt.loglog(k, k**2, '--', label='$O(k^2)$') plt.title('$L^2$ convergence rate', fontsize=13) plt.xlabel('$k$', fontsize=13) plt.ylabel('error', fontsize=13) plt.legend() plt.plot() plt.show() except Exception as e: print(e)