def test_exponential_1D(self):
     a = 1
     b = 2
     print("\n\nTesting 1D quadrature on exponential function")
     for Nq in range(1, 5):
         print(f"I_{Nq} error:",
               quadrature1D(a, b, Nq, np.exp) - np.exp(b) + np.exp(a))
         self.assertAlmostEqual(quadrature1D(a, b, Nq, np.exp),
                                np.exp(b) - np.exp(a),
                                delta=1)
    def test_constant_1D_sub_2D(self):

        p1 = np.array([1, 0])
        p2 = np.array([3, 1])
        p3 = np.array([3, 2])

        for a in [p1, p2, p3]:
            for b in [p1, p2, p3]:
                for z in [p1, p2, p3]:
                    for Nq in range(1, 5):
                        f = get_one_form(z)
                        self.assertAlmostEqual(
                            quadrature1D(a, b, Nq, f),
                            0.5 * f(b + a) * np.linalg.norm(b - a))
Пример #3
0
def get_A_F(p,
            tri,
            dirichlet_edges,
            f,
            g=None,
            neumann_edges=np.empty(0),
            Nq=4,
            finite_element=IsoparametricLinearTriangle,
            tri_u=None):
    # find the shape functions for the reference triangle
    if tri_u is None:
        tri_u = tri
    ref_element_geom = finite_element.geometry.ref_element
    sf_geom = finite_element.geometry.shape_fun
    sf_geom_jac = finite_element.geometry.shape_fun_jacobian
    sf_u = finite_element.displacement.shape_fun
    sf_u_jac = finite_element.displacement.shape_fun_jacobian
    n_bar = len(np.unique(tri_u))
    A = np.zeros((n_bar, n_bar))
    F = np.zeros(n_bar)

    for element, element_u in zip(tri, tri_u):
        # find expression for the dual basis for the reference element
        X = p[element].T

        def left_integrand(ksi):
            left = sf_u_jac(ksi) @ np.linalg.inv(X @ sf_geom_jac(ksi))
            jacobian_det = np.linalg.det(X @ sf_geom_jac(ksi))
            return left @ left.T * jacobian_det

        def right_integrand(ksi):
            jacobian_det = np.linalg.det(X @ sf_geom_jac(ksi))
            return f(X @ sf_geom(ksi)) * sf_u(ksi) * jacobian_det

        # For linear geometry and solution shape functions we can calculate this integral only once, then scale it.
        # integrate over reference element
        A[np.ix_(element_u, element_u)] += qd.quadrature2D(*ref_element_geom,
                                                           Nq=1,
                                                           g=left_integrand)

        # Add load to F vector
        # integrate over reference element
        F[element_u] += qd.quadrature2D(*ref_element_geom, Nq, right_integrand)

        # apply neumann conditions if applicable
        for alpha in range(len(element)):
            for beta in range(len(element)):
                if [element[alpha], element[beta]] in neumann_edges.tolist():
                    vertex1, vertex2 = ref_element_geom[[alpha, beta]]

                    def right_integrand_neumann(ksi):
                        coor_change = np.linalg.norm(
                            X @ sf_geom_jac(ksi) @ (vertex2 - vertex1)
                        ) / np.linalg.norm(vertex1 - vertex2)
                        return sf_u(ksi) * g(X @ sf_geom(ksi)) * coor_change

                    F[element_u] += qd.quadrature1D(vertex1,
                                                    vertex2,
                                                    Nq,
                                                    g=right_integrand_neumann)

    # Applying dirichlet boundary conditions
    epsilon = 1e-100
    dirichlet_vertecis = np.unique(dirichlet_edges)
    for i in dirichlet_vertecis:
        A[i, i] = 1 / epsilon
        F[i] = 0

    return A, F
 def test_linear_1D(self):
     for a in range(-10, 10):
         for b in range(a, 10):
             for Nq in range(1, 5):
                 self.assertAlmostEqual(quadrature1D(a, b, Nq, identity),
                                        0.5 * (b**2 - a**2))
Пример #5
0
def get_elasticity_A_F(p,
                       tri,
                       dirichlet_edges,
                       C,
                       f,
                       g=None,
                       neumann_edges=np.empty(0),
                       Nq=4,
                       finite_element=IsoparametricLinearTriangle,
                       tri_u=None):
    """
    # Function generates the system Au = F for the linear elasticity equation
    :param p: location of nodes in mesh
    :param tri: list of indexes in p for the nodes of each triangle. For  geometry definition
    :param dirichlet_edges: list of par indexes defining the edge nodes with dirichlet boundary conditions
    :param C: sigma_hat = C epsilon_hat
    :param f: force pear area
    :param g: neumann boundary conditions if applicable
    :param neumann_edges: edges to neumann
    :param Nq: Number of quadrature points used for integration
    :param finite_element: class with shape functions for geometry and displacement.
    :param tri_u: list of indexes in p for the nodes of each triangle. For displacement definition
    :return: A, F
    """
    if tri_u is None:
        tri_u = tri

    # Define shape functions
    ref_element_geom = finite_element.geometry.ref_element
    sf_geom = finite_element.geometry.shape_fun
    sf_geom_jac = finite_element.geometry.shape_fun_jacobian
    sf_u = finite_element.displacement.shape_fun
    sf_u_jac = finite_element.displacement.shape_fun_jacobian

    # set up system
    n_bar = len(np.unique(tri_u))
    degrees = 2 * n_bar
    A = np.zeros((degrees, degrees))
    F = np.zeros(degrees)

    for element, element_u in zip(tri, tri_u):
        X = p[element].T
        index_u_2d = np.concatenate((index(element_u, 0), index(element_u, 1)))

        def right_integrand(ksi):
            jacobian_det = np.linalg.det(X @ sf_geom_jac(ksi))
            return np.kron(f(X @ sf_geom(ksi)), sf_u(ksi)) * jacobian_det

        # find coefficients for basis functions
        XY = np.append(np.ones((3, 1)), p[element], axis=1)
        B = np.linalg.solve(XY, np.identity(3))

        # coordinates of the nodes of the element
        p1, p2, p3 = p[element[0]], p[element[1]], p[element[2]]

        # integrate right integrand over refrence triangle
        F[index_u_2d] += qd.quadrature2D(*ref_element_geom, Nq,
                                         right_integrand)

        for da in [0, 1]:
            for db in [0, 1]:

                def left_integrand(ksi):
                    left = sf_u_jac(ksi) @ np.linalg.inv(X @ sf_geom_jac(ksi))
                    inner = (Epsilon[da] @ left.T).T @ C @ Epsilon[db] @ left.T
                    jacobian_det = np.linalg.det(X @ sf_geom_jac(ksi))
                    return inner * jacobian_det

                # integrate integrand over refrence triangle
                A[np.ix_(index(element_u, da),
                         index(element_u, db))] += qd.quadrature2D(
                             *ref_element_geom, 1, left_integrand)
        # apply neumann conditions as in solver.py
        for alpha in range(3):
            for da in [0, 1]:
                for beta in range(3):
                    for db in [0, 1]:
                        # apply neumann conditions if applicable
                        if [element[alpha],
                                element[beta]] in neumann_edges.tolist():
                            vertex1, vertex2 = p[element[alpha]], p[
                                element[beta]]
                            Ha = lambda x: (B[0, alpha] + B[1:3, alpha] @ x)
                            Hb = lambda x: B[0, beta] + B[1:3, beta] @ x

                            F[index(element[alpha], da)] += qd.quadrature1D(
                                vertex1, vertex2, Nq,
                                function_multiply(Ha, proj(g, da)))
                            F[index(element[beta], db)] += qd.quadrature1D(
                                vertex1, vertex2, Nq,
                                function_multiply(Hb, proj(g, db)))

    # Applying dirichlet boundary conditions
    epsilon = 1e-100
    dirichlet_vertecis = np.unique(dirichlet_edges)
    for node in dirichlet_vertecis:
        for d in [0, 1]:
            A[index(node, d), index(node, d)] = 1 / epsilon
            F[index(node, d)] = 0

    return A, F