Exemplo n.º 1
0
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
Exemplo n.º 2
0
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()
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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