def h_finder(N_list, ifprint=True): h_vec = [] for N in N_list: p, tri, edge = getPlate(N+1) # p Nodal points, (x,y)-coordinates for point i given in row i. # tri Elements. Index to the three corners of element i given in row i. # edge Edge lines. Index list to the two corners of edge line i given in row i. h_list = [] for nk in tri: # nk : node-numbers for the k'th triangle # the points of the triangle p1 = p[nk[0], :] p2 = p[nk[1], :] p3 = p[nk[2], :] # find distance between the nodes h1 = np.linalg.norm(p1 - p2) h2 = np.linalg.norm(p1 - p3) h3 = np.linalg.norm(p2 - p3) # append h_list.append(h1) h_list.append(h2) h_list.append(h3) # let h be the max h = np.max(h_list) h_vec.append(h) if ifprint: print("N =", N, "gives h =", h) if not ifprint: h_vec = np.asarray(h_vec) return h_vec
def meshplot_v2(N_list, nCols=4, save=False): """ Function to make plots of meshes for N in N_list Parameters ---------- N_list : list A list containing N's to plot a mesh for. N : int Number of nodal edges on the x-axis. nCols : int, optional Number of columns in the final plot, meaning subplots per row. The default is 4. save : bool, optional Will the plot be saved in the plot folder. The default is False. Note: the plot folder must exist! Returns ------- None. """ # if N_list is just an int if isinstance(N_list, int): N_list = [N_list] # create a figure numPlots = len(N_list) nRows = numPlots // nCols + numPlots % nCols # make N_list's length to nRows*nCols by appending -1 while len(N_list) < nRows * nCols: N_list.append(-1) # reshape N_list N_list = np.array(N_list).reshape((nRows, nCols)) # create the main figure and the axs as the subplots, # the figsize (21, 6) is good for nRows = 1 # but figsize (21, 7 * nRows) is better for nRows = 2, 3, ... if nRows == 1: c = 6 else: c = 7 * nRows fig, axs = plt.subplots(nRows, nCols, figsize=(21, c)) if nCols == 1: axs = np.array([ axs, ]) if nRows == 1: axs = np.array([ axs, ]) for i in range(nRows): for j in range(nCols): N = N_list[i, j] if N == -1: # don't show plot axs[i, j].set_axis_off() else: ax = axs[i, j] # get the nodes, elements and edge lines p, tri, edge = getPlate(N + 1) # plot them with triplot ax.triplot(p[:, 0], p[:, 1], tri) # label the axes ax.set_xlabel('$x$') ax.set_ylabel('$y$') # give the plot a title ax.set_title('Mesh for $N=' + str(N) + '$') # adjust plt.subplots_adjust(hspace=0.3, wspace=0.4) # save the plot? if save: plt.savefig("plot\Mesh_for_Ns.pdf") plt.show()
def contourplot_Heat2D(N, u_hdict, save_name, save=False): """ Function to make contourplots of the three first entry's in u_hdict Parameters ---------- N : int Number of nodal edges on the x-axis. u_hdict : dictionary Dictionary with at least three entries, the entry's are u_h at a time stamp t. save_name : string The name of the plot for saving. save : bool, optional Will the plot be saved in the plot folder. The default is False. Note: the plot folder must exist! Returns ------- None. """ # get the nodes, elements and edge lines p, tri, edge = getPlate(N + 1) u_h0, t0 = u_hdict[0] u_h1, t1 = u_hdict[1] u_h2, t2 = u_hdict[2] # x and y coordinates x = p[:, 0] y = p[:, 1] # restrict color coding to (-1, 1), levels = np.linspace(-1, 1, 9) plt.figure(figsize=(21, 6)) # Create plot of numerical solution plt.subplot(1, 3, 1) plt.gca().set_aspect('equal') plt.tricontourf(x, y, tri, u_h0, levels=levels, extend='both') plt.colorbar() plt.title("$u_h(t, x,y)$ at $t=" + "{:.2f}".format(t0) + "$ \nfor $N=" + str(N) + "$") # Create plot of analytical solution plt.subplot(1, 3, 2) plt.gca().set_aspect('equal') plt.tricontourf(x, y, tri, u_h1, levels=levels, extend='both') plt.colorbar() plt.title("$u_h(t, x,y)$ at $t=" + "{:.2f}".format(t1) + "$ \nfor $N=" + str(N) + "$") # Create plot of absolute difference between the two solutions plt.subplot(1, 3, 3) plt.gca().set_aspect('equal') plt.tricontourf(x, y, tri, u_h2, levels=levels, extend='both') plt.colorbar() plt.title("$u_h(t, x,y)$ at $t=" + "{:.2f}".format(t2) + "$ \nfor $N=" + str(N) + "$") # adjust plt.subplots_adjust(wspace=0.4) # save the plot? if save: plt.savefig("plot/" + save_name + ".pdf") plt.show()
def Error_Estimate_G(N, u_hdict): """ Function find the Error estimate for the three first entry's in u_hdict using the Gradient Recovery Operator Parameters ---------- N : int Number of nodal edges on the x-axis. u_hdict : dictionary dictionary of three (u_h, t_i)-values, where t_i is the time stamp for when u_h is. Returns ------- eta2_vec : numpy.array estimates error for the three time stamps """ # get u_h and time stamps u_h0, t0 = u_hdict[0] u_h1, t1 = u_hdict[1] u_h2, t2 = u_hdict[2] p, tri, edge = getPlate(N+1) # p Nodal points, (x,y)-coordinates for point i given in row i. # tri Elements. Index to the three corners of element i given in row i. # edge Edge lines. Index list to the two corners of edge line i given in row i. # initialize error estimate eta2_vec = np.zeros(3) for nk in tri: # nk : node-numbers for the k'th triangle # the points of the triangle p1 = p[nk[0], :] p2 = p[nk[1], :] p3 = p[nk[2], :] # array for grad u_h, # columns ph1, phi2, phi3 # rows: t0, t1, t1 gradu_hx = np.zeros((3, 3)) gradu_hy = np.zeros((3, 3)) # get alpha alpha_dict = get_alpha(u_h0, u_h1, u_h2, nk, p, tri) alpha1 = alpha_dict[1] alpha2 = alpha_dict[2] alpha3 = alpha_dict[3] # calculate basis functions. # compute the gradient of u_h the element # note the gradient is constant on the element by the choice of basis # row_k: [1, x_k, y_k] Bk = np.asarray([p_vec(*p[nk[0]]), p_vec(*p[nk[1]]), p_vec(*p[nk[2]])]) Ck = np.linalg.inv(Bk) # here faster than solving Mk @ Ck = I_3 # x - comp of grad phi, is constant Ckx = Ck[1, :] # y - comp of grad phi, is constant Cky = Ck[2, :] # the x-component on the element gradu_hx[:, 0] = Ckx * u_h0[nk] gradu_hx[:, 1] = Ckx * u_h1[nk] gradu_hx[:, 2] = Ckx * u_h2[nk] # the y-component on the element gradu_hy[:, 0] = Cky * u_h0[nk] gradu_hy[:, 1] = Cky * u_h1[nk] gradu_hy[:, 2] = Cky * u_h2[nk] # the basis functions # phi_1 = [1, x, y] @ Ck[:,0] # phi_2 = [1, x, y] @ Ck[:,1] # phi_3 = [1, x, y] @ Ck[:,2] phi = lambda x, y: [1, x, y] @ Ck # The function to integrate # the x-comp Fx = lambda x, y, i: p_vec(*p1) @ alpha1[0][:, i] * phi(x, y)[0] - gradu_hx[0, i] \ + p_vec(*p2) @ alpha2[0][:, i] * phi(x, y)[1] - gradu_hx[1, i]\ + p_vec(*p3) @ alpha3[0][:, i] * phi(x, y)[2] - gradu_hx[2, i] # the y-comp Fy = lambda x, y, i: p_vec(*p1) @ alpha1[1][:, i] * phi(x, y)[0] - gradu_hy[0, i] \ + p_vec(*p2) @ alpha2[1][:, i] * phi(x, y)[1] - gradu_hy[1, i] \ + p_vec(*p3) @ alpha3[1][:, i] * phi(x, y)[2] - gradu_hy[2, i] # the function of i Fi = lambda x, y, i: Fx(x, y, i) ** 2 + Fy(x, y, i) ** 2 # now do the integration for i in range(3): # the function F = lambda x, y: Fi(x, y, i) eta2_vec[i] += quadrature2D(p1, p2, p3, 4, F) return eta2_vec
def ThetaMethod_Heat2D(N, Nt, alpha, beta, f, uD, duDdt, u0, theta=0.5, T=1, Rg_indep_t=True, f_indep_t=False): """ Function solve the Heat equartion in 2D using the theta methoid and to get u_h values for three different time stamps (1/3, 2/3, 1) * T Note: function is faster given that Rg_indep_t=True and f_indep_t=True, meaning we assume that the boundary function and the source function are independent of t. Parameters ---------- N : int Number of nodal edges on the x-axis. Nt : int Number of time steps. alpha : float parameter alpha of the equation. beta : float parameter beta of the source function f : function pointer The source function. uD : function pointer Value of u_h on the boundary. duDdt : function pointer Derivative of u_h on the boundary, derivative of uD. u0 : function pointer initial function for t=0. theta : float, optional parameter for the time itegration method. 0: Forward Euler 0.5: Implicit Trapes 1: Backward Euler The default is 0.5. T : float, optional The end time of the interval [0, T]. The default is 1. Rg_indep_t : bool, optional Is the boundary function independent of t. The default is True. f_indep_t : bool, optional Is the source function independent of t. The default is False. Returns ------- u_hdict : dictionary dictionary of three (u_h, t_i)-values, where t_i is the time stamp for when u_h is. """ p, tri, edge = getPlate(N + 1) # p Nodal points, (x,y)-coordinates for point i given in row i. # tri Elements. Index to the three corners of element i given in row i. # edge Index list of all nodal points on the outer edge (r=1). # get lists of unique interior and edge point indices in_index, edge_index = get_in_and_edge_index(tri, edge) # number of interior nodes N_in = in_index.shape[0] # x and y on the edge xvec_edge = p[edge_index][:, 0] yvec_edge = p[edge_index][:, 1] # x and y on the interior xvec_in = p[in_index][:, 0] yvec_in = p[in_index][:, 1] # the time-step k = T / Nt ktheta = k * theta # thetabar kthetabar = k * (1 - theta) # get the base Stiffness Matrix, Mass matrix, F(t=0), contribution Matrices to F. A, M, F0, Ba, Bm = base_Heat2D(N, p, tri, N_in, in_index, edge_index, f, alpha, beta) # initial setup # u_h1(t=0), (homogenous Dirichlet) u_h1_current = u0(xvec_in, yvec_in) # The lifting function and its t derivative at t=0 Rg_current = uD(xvec_edge, yvec_edge, t=0) dRgdt_current = duDdt(xvec_edge, yvec_edge, t=0) # The t=0 load vector with BC contributions F_current = F0 - Bm @ dRgdt_current - Ba @ Rg_current # dictionary to save to u_hdict = dict() savecount = 0 # do iterations of theta-method for j in range(1, Nt + 1): # the time tk = j * k # the left-hand side matrix lhs = (M + ktheta * A).tocsr() # The lifting function and its t derivative at t=tk if Rg_indep_t: # independent of t # next == current Rg_next = Rg_current dRgdt_next = dRgdt_current else: # dependent on t Rg_next = uD(xvec_edge, yvec_edge, t=tk) dRgdt_next = duDdt(xvec_edge, yvec_edge, t=tk) # the next load vector if f_indep_t: # independent of t # next == current F_next = F_current else: # dependent on t F_next = build_Ft( N_in, p, tri, in_index, edge_index, f, beta, t=tk) - Bm @ dRgdt_next - Ba @ Rg_next # the right-hand side vector rhs = (M - kthetabar * A) @ u_h1_current + ktheta * F_next + kthetabar * F_current # solve(lhs, rhs) u_h1_next = spsolve(lhs, rhs) # save time-picture, we have choosen to save three. if j in (int(Nt / 3), int(2 * Nt / 3), Nt): u_hdict[savecount] = [ get_u_h(N, u_h1_next, Rg_next, in_index, edge_index), tk ] savecount += 1 # update u_h1_current = u_h1_next Rg_current = Rg_next F_current = F_next # return return u_hdict