Exemple #1
0
    def test_line_integral(self):
        # Define quadrature rule
        rule = GaussRule(2, shape='interval')
        w = rule.weights()
        x_ref = rule.nodes()

        # function f to be integrated over edge e
        f = lambda x, y: x**2 * y
        e = HalfEdge(Vertex((0, 0)), Vertex((1, 1)))

        # Map rule to physical entity
        x_phys, mg = e.reference_map(x_ref, jac_r2p=True)
        jacobian = mg['jac_r2p']

        x_phys = convert_to_array(x_phys, dim=2)
        fvec = f(x_phys[:, 0], x_phys[:, 1])

        jac = np.linalg.norm(jacobian[0])
        self.assertAlmostEqual(np.dot(fvec,w)*jac,np.sqrt(2)/4,places=10,\
                               msg='Failed to integrate x^2y.')
        self.assertAlmostEqual(np.sum(w)*jac, np.sqrt(2), places=10,\
                               msg='Failed to integrate 1.')
Exemple #2
0
    def test_reference_map(self):
        v_sw = Vertex((0, 0))
        v_se = Vertex((3, 1))
        v_ne = Vertex((2, 3))
        v_nw = Vertex((-1, 1))

        h12 = HalfEdge(v_sw, v_se)
        h23 = HalfEdge(v_se, v_ne)
        h34 = HalfEdge(v_ne, v_nw)
        h41 = HalfEdge(v_nw, v_sw)
        cell = QuadCell([h12, h23, h34, h41])

        #
        # Map corner vertices of reference cell to physical vertices
        #
        y_refs = np.array([[0, 0], [1, 0], [1, 1], [0, 1]])
        x = list(convert_to_array(cell.get_vertices()))
        x_phys = cell.reference_map(list(y_refs))

        self.assertTrue(np.allclose(np.array(x),x_phys),\
                        'Mapped vertices should coincide '+\
                        'with physical cell vertices.')

        #
        # Jacobian: Area of cell by integration
        #
        rule_2d = GaussRule(order=4, shape='quadrilateral')
        r = rule_2d.nodes()
        wg = rule_2d.weights()
        dummy, mg = cell.reference_map(list(r), jac_r2p=True)
        jac = mg['jac_r2p']
        area = 0
        for i in range(4):
            j = jac[i]
            w = wg[i]
            area += np.abs(np.linalg.det(j)) * w
        self.assertAlmostEqual(cell.area(), area, 7,\
                               'Area computed via numerical quadrature '+\
                               'not close to actual area')
        #
        # Try different formats
        #
        # Array
        x = np.array(x)
        x_ref = cell.reference_map(x, mapsto='reference')
        self.assertTrue(np.allclose(y_refs, np.array(x_ref)),\
                        'Map array to reference: incorrect output.')
        # Single point
        x = x[0, :]
        x_ref = cell.reference_map(x, mapsto='reference')
        self.assertTrue(np.allclose(x, x_ref))

        #
        # Map corner vertices to reference points
        #
        x = convert_to_array(cell.get_vertices())
        y = cell.reference_map(x, mapsto='reference')
        self.assertTrue(np.allclose(y, y_refs), \
                        'Corner vertices should map '+\
                        'onto (0,0),(1,0),(1,1),(0,1).')

        #
        # Map random points in [0,1]^2 onto cell and back again
        #
        # Generate random points
        t = np.random.rand(5)
        s = np.random.rand(5)
        x = np.array([s, t]).T

        # Map to physical cell
        x_phy = cell.reference_map(x)

        # Check whether points are contained in cell
        in_cell = cell.contains_points(x_phy)
        self.assertTrue(all(in_cell), \
                        'All points mapped from [0,1]^2 '+\
                        'should be contained in the cell.')

        # Map back to reference cell
        x_ref = cell.reference_map(x_phy, mapsto='reference')
        self.assertTrue(np.allclose(np.array(x_ref), np.array(x)),\
                        'Points mapped to physical cell and back should '+\
                        'be unchanged.')

        #
        # Compute the hessian and compare with finite difference approximation
        #
        h = 1e-8
        x = np.array([[0.5, 0.5], [0.5 + h, 0.5], [0.5 - h, 0.5],
                      [0.5, 0.5 + h], [0.5, 0.5 - h]])

        x_ref, mg = cell.reference_map(x,
                                       mapsto='reference',
                                       hess_p2r=True,
                                       jac_p2r=True)
        J = mg['jac_p2r']
        H = mg['hess_p2r']

        # sxx
        sxx_fd = (J[1][0, 0] - J[2][0, 0]) / (2 * h)
        sxx = H[0][0, 0, 0]
        self.assertAlmostEqual(sxx_fd, sxx, 7, \
                               'Hessian calculation not close to '+\
                               'finite difference approximation')

        # syx
        syx_fd = (J[1][0, 1] - J[2][0, 1]) / (2 * h)
        sxy = H[0][0, 1, 0]
        syx = H[0][1, 0, 0]
        self.assertAlmostEqual(sxy, syx, 7, 'Mixed derivatives not equal.')
        self.assertAlmostEqual(syx_fd, sxy, 7, \
                               'Hessian calculation not close to '+\
                               'finite difference approximation')

        # syy
        syy_fd = (J[3][0, 1] - J[4][0, 1]) / (2 * h)
        syy = H[0][1, 1, 0]
        self.assertAlmostEqual(syy_fd, syy, 7, \
                               'Hessian calculation not close to '+\
                               'finite difference approximation')

        # txx
        txx_fd = (J[1][1, 0] - J[2][1, 0]) / (2 * h)
        txx = H[0][0, 0, 1]
        self.assertAlmostEqual(txx_fd, txx, 7, \
                               'Hessian calculation not close to '+\
                               'finite difference approximation')

        # txy
        txy_fd = (J[3][1, 0] - J[4][1, 0]) / (2 * h)
        txy = H[0][0, 1, 1]
        tyx = H[0][1, 0, 1]
        self.assertAlmostEqual(txy, tyx, 7, 'Mixed derivatives not equal.')
        self.assertAlmostEqual(txy_fd, txy, 7, \
                               'Hessian calculation not close to '+\
                               'finite difference approximation')

        # tyy
        tyy_fd = (J[3][1, 1] - J[4][1, 1]) / (2 * h)
        tyy = H[0][1, 1, 1]
        self.assertAlmostEqual(tyy_fd, tyy, 7, \
                               'Hessian calculation not close to '+\
                               'finite difference approximation')
Exemple #3
0
    def test_constructor(self):
        # =====================================================================
        # Test 1D 
        # ===================================================================== 
        
        #
        # Kernel consists of a single explicit Function: 
        # 
        f1 = lambda x: x+2
        f = Explicit(f1, dim=1)
        k = Kernel(f)
        x = np.linspace(0,1,100)
        n_points = len(x)
        
        # Check that it evaluates correctly.
        self.assertTrue(np.allclose(f1(x), k.eval(x).ravel()))
        
        # Check shape of kernel
        self.assertEqual(k.eval(x).shape, (n_points,1))
        
        #
        # Kernel consists of a combination of two explicit functions
        # 
        f1 = Explicit(lambda x: x+2, dim=1)
        f2 = Explicit(lambda x: x**2 + 1, dim=1)
        F = lambda f1, f2: f1**2 + f2
        f_t = lambda x: (x+2)**2 + x**2 + 1
        k = Kernel([f1,f2], F=F)
        
        # Check evaluation
        self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel()))
        
        # Check shape 
        self.assertEqual(k.eval(x).shape, (n_points,1))
        

        #
        # Same thing as above, but with nodal functions
        # 
        mesh = Mesh1D(resolution=(1,))
        Q1 = QuadFE(1,'Q1')
        Q2 = QuadFE(1,'Q2')
        
        dQ1 = DofHandler(mesh,Q1)
        dQ2 = DofHandler(mesh,Q2)
        
        # Distribute dofs
        [dQ.distribute_dofs() for dQ in [dQ1,dQ2]]
        
        # Basis functions
        phi1 = Basis(dQ1,'u')
        phi2 = Basis(dQ2,'u')
        
        f1 = Nodal(lambda x: x+2, basis=phi1)
        f2 = Nodal(lambda x: x**2 + 1, basis=phi2)
        k = Kernel([f1,f2], F=F)
        
        # Check evaluation
        self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel()))
        
        #
        # Replace f2 above with its derivative
        # 
        k = Kernel([f1,f2], derivatives=['f', 'fx'], F=F)
        f_t = lambda x: (x+2)**2 + 2*x
                
        # Check derivative evaluation F = F(f1, df2_dx)
        self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel()))
        
        
        # 
        # Sampling 
        #
        one = Constant(1)
        f1 = Explicit(lambda x: x**2 + 1, dim=1)
        
        # Sampled function
        a = np.linspace(0,1,11)
        n_samples = len(a)
        
        # Define Dofhandler
        dh = DofHandler(mesh, Q2)
        dh.distribute_dofs()
        dh.set_dof_vertices()
        xv = dh.get_dof_vertices()
        n_dofs = dh.n_dofs()
        
        phi = Basis(dh, 'u')
        
        # Evaluate parameterized function at mesh dof vertices
        f2_m  = np.empty((n_dofs, n_samples))
        for i in range(n_samples):
            f2_m[:,i] = xv.ravel() + a[i]*xv.ravel()**2
        f2 = Nodal(data=f2_m, basis=phi)
        
        # Define kernel
        F = lambda f1, f2, one: f1 + f2 + one
        k = Kernel([f1,f2,one], F=F)
        
        # Evaluate on a fine mesh
        x = np.linspace(0,1,100)
        n_points = len(x)
        self.assertEqual(k.eval(x).shape, (n_points, n_samples))    
        for i in range(n_samples):
            # Check evaluation            
            self.assertTrue(np.allclose(k.eval(x)[:,i], f1.eval(x)[:,i] + x + a[i]*x**2+ 1))
            
        
        #
        # Sample multiple constant functions
        # 
        f1 = Constant(data=a)
        f2 = Explicit(lambda x: 1 + x**2, dim=1)
        f3 = Nodal(data=f2_m[:,-1], basis=phi)
        
        F = lambda f1, f2, f3: f1 + f2 + f3
        k = Kernel([f1,f2,f3], F=F)
        
        x = np.linspace(0,1,100)
        for i in range(n_samples):
            self.assertTrue(np.allclose(k.eval(x)[:,i], \
                                        a[i] + f2.eval(x)[:,i] + f3.eval(x)[:,i]))
        
        #
        # Submeshes
        # 
        mesh = Mesh1D(resolution=(1,))
        mesh_labels = Tree(regular=False)
        
        mesh = Mesh1D(resolution=(1,))
        Q1 = QuadFE(1,'Q1')
        Q2 = QuadFE(1,'Q2')
        
        dQ1 = DofHandler(mesh,Q1)
        dQ2 = DofHandler(mesh,Q2)
        
        # Distribute dofs
        [dQ.distribute_dofs() for dQ in [dQ1,dQ2]]
        
        # Basis
        p1 = Basis(dQ1)
        p2 = Basis(dQ2) 
        
        
        f1 = Nodal(lambda x: x, basis=p1)
        f2 = Nodal(lambda x: -2+2*x**2, basis=p2)
        one = Constant(np.array([1,2]))
    
        F = lambda f1, f2, one: 2*f1**2 + f2 + one
        
        I = mesh.cells.get_child(0)
        
        kernel = Kernel([f1,f2, one], F=F)
        
        rule1D = GaussRule(5,shape='interval')
        x = I.reference_map(rule1D.nodes())
Exemple #4
0
    def test_accuracy(self):
        """
        Test the Accuracy of the Gauss rule on the reference cell
        
        1D Rule: (Interval) 
            Number of Nodes: 1,2,3,4,5,6
            Accuracy: 2N-1 
             
        2D Rule (Quadrilateral): 
            Number of Nodes: 1,4,9,16,25,36 
            Accuracy: (2n-1, 2n-1), where n = sqrt(N)
            
        TODO: 2D Rule (Triangle) 
        """
        #
        # 1D Polynomials and exact integrals
        #
        order_1d = [1, 2, 3, 4, 5, 6]
        polynomials_1d = {
            1: lambda x: 2 * np.ones(x.shape),
            2: lambda x: x**3 - 2 * x**2 + x + 1,
            3: lambda x: x**5 - 2 * x**2 + 2,
            4: lambda x: x**7 + 2 * x**6 + 3 * x,
            5: lambda x: x**9 + 3 * x**4 + 1,
            6: lambda x: x**11 - 3 * x**8 + 1
        }

        integrals_1d = {
            1: 2,
            2: 13 / 12,
            3: 3 / 2,
            4: 107 / 56,
            5: 17 / 10,
            6: 3 / 4
        }

        #
        # 2D Polynomials and exact integrals
        #
        order_2d = [1, 4, 9, 16, 25, 36]

        polynomials_2d = {
            1: lambda x, y: np.ones(x.shape),
            4: lambda x, y: x * y + x + y,
            9: lambda x, y: (x**5 - 2 * x**2 + 2) * (y**4 - 2 * y),
            16: lambda x, y: (x**7 + 2 * x**6 + 3 * x) * (y**5 + 2 * y**2),
            25: lambda x, y: (x**9 + 3 * x**4 + 1) * (y**9 + 3 * y**4 + 1),
            36: lambda x, y: (x**11 - 3 * x**8 + 1) * (y**11 + 2 * y)
        }

        integrals_2d = {
            1: 1,
            4: 5 / 4,
            9: -6 / 5,
            16: 535 / 336,
            25: 289 / 100,
            36: 13 / 16
        }

        # Combine information
        order = {1: order_1d, 2: order_2d}
        polynomials = {1: polynomials_1d, 2: polynomials_2d}
        integrals = {1: integrals_1d, 2: integrals_2d}

        #
        # Iterate over dimensions
        #
        for dim in [1, 2]:
            element = QuadFE(dim, 'Q1')
            #
            # Iterate over orders
            #
            for n in order[dim]:

                # Define Gauss Rule
                rule = GaussRule(n, element)
                x = rule.nodes()
                w = rule.weights()

                # Compute approximate integral
                f = polynomials[dim][n]
                if dim == 1:
                    Ia = np.dot(w, f(x))
                elif dim == 2:
                    Ia = np.dot(w, f(x[:, 0], x[:, 1]))

                # Compute exact integral
                Ie = integrals[dim][n]

                # Compare
                self.assertAlmostEqual(Ia, Ie, 10)
Exemple #5
0
    def test_shape(self):
        """
        Test shape functions
        """
        test_functions = {'Q1': (lambda x,y: (x+1)*(y-1), lambda x,y: y-1, \
                                 lambda x,y: x+1),
                          'Q2': (lambda x,y: x**2 -1, lambda x,y: 2*x, \
                                 lambda x,y: 0*x),
                          'Q3': (lambda x,y: x**3 - y**3, lambda x,y: 3*x**2, \
                                 lambda x,y: -3*y**2)}
        #
        # Over reference cell
        #
        cell_integrals = {
            'Q1': [-0.75, -0.5, 1.5],
            'Q2': [-2 / 3., 1.0, 0.0],
            'Q3': [0., 1.0, -1.0]
        }

        derivatives = [(0, ), (1, 0), (1, 1)]
        for etype in ['Q1', 'Q2', 'Q3']:
            element = QuadFE(2, etype)
            n_dofs = element.n_dofs()
            x_ref = element.reference_nodes()
            #
            # Sanity check
            #
            I = np.eye(n_dofs)
            self.assertTrue(np.allclose(element.shape(x_ref),I),\
                            'Shape functions incorrect at reference nodes.')
            y = np.random.rand(5, 2)
            rule2d = GaussRule(9, element=element)
            weights = rule2d.weights()
            x_gauss = rule2d.nodes()
            f_nodes = test_functions[etype][0](x_ref[:, 0], x_ref[:, 1])
            for i in range(3):
                phi = element.shape(y, derivatives=derivatives[i])
                f = test_functions[etype][i]
                #
                # Interpolation
                #
                fvals = f(y[:, 0], y[:, 1])
                self.assertTrue(np.allclose(np.dot(phi,f_nodes),fvals),\
                                'Shape function interpolation failed.')
                #
                # Integration
                #
                phi = element.shape(x_gauss, derivatives=derivatives[i])
                self.assertAlmostEqual(np.dot(weights,np.dot(phi,f_nodes)),\
                                 cell_integrals[etype][i],places=8,\
                                 msg='Incorrect integral.')
        # On Physical cell

        #
        # Non-rectangular quadcell
        #
        test_functions['Q1'] = (lambda x, y: (x + 1) +
                                (y - 1), lambda x, y: np.ones(x.shape),
                                lambda x, y: np.ones(y.shape))

        # Vertices
        v0 = Vertex((0, 0))
        v1 = Vertex((0.5, 0.5))
        v2 = Vertex((0, 2))
        v3 = Vertex((-0.5, 0.5))

        # half_edges
        h01 = HalfEdge(v0, v1)
        h12 = HalfEdge(v1, v2)
        h23 = HalfEdge(v2, v3)
        h30 = HalfEdge(v3, v0)

        # quadcell
        cell = QuadCell([h01, h12, h23, h30])

        for etype in ['Q1', 'Q2', 'Q3']:
            element = QuadFE(2, etype)
            n_dofs = element.n_dofs()
            x_ref = element.reference_nodes()
            x, mg = cell.reference_map(x_ref, jac_p2r=True, hess_p2r=True)
            #
            # Sanity check
            #
            I = np.eye(n_dofs)
            shape = element.shape(x_ref,
                                  cell,
                                  jac_p2r=mg['jac_p2r'],
                                  hess_p2r=mg['hess_p2r'])
            self.assertTrue(np.allclose(shape,I),\
                            'Shape functions incorrect at reference nodes.')

            # Random points in the reference domain
            y_ref = np.random.rand(5, 2)
            y, mg = cell.reference_map(y_ref, jac_p2r=True, hess_p2r=True)

            self.assertTrue(all(cell.contains_points(y)),\
                            'Cell should contain all mapped points')
            f_nodes = test_functions[etype][0](x[:, 0], x[:, 1])

            for i in range(3):
                phi = element.shape(y_ref,
                                    cell=cell,
                                    derivatives=derivatives[i],
                                    jac_p2r=mg['jac_p2r'],
                                    hess_p2r=mg['hess_p2r'])
                f = test_functions[etype][i]
                #
                # Interpolation
                #
                fvals = f(y[:, 0], y[:, 1])
                self.assertTrue(np.allclose(np.dot(phi,f_nodes),fvals),\
                                'Shape function interpolation failed.')
Exemple #6
0
    def test_shape_eval(self):
        """
        Routine evaluates all shape functions on given cell
        """
        #
        # Diamond-shaped region
        #

        # Vertices
        A = Vertex((0, -1))
        B = Vertex((1, 0))
        C = Vertex((0, 1))
        D = Vertex((-1, 0))

        # Half-edges
        AB = HalfEdge(A, B)
        BC = HalfEdge(B, C)
        CD = HalfEdge(C, D)
        DA = HalfEdge(D, A)

        # Cell
        cell = QuadCell([AB, BC, CD, DA])

        # 1D Quadrature Rule
        rule = GaussRule(4, shape='interval')
        xx = rule.nodes()
        ww = rule.weights()

        #
        # Map rule to physical domain (CD)
        #
        xg, mg = CD.reference_map(xx, jac_r2p=True)
        xg = convert_to_array(xg)

        # Modify weights
        jac = mg['jac_r2p']
        wg = ww * np.array(np.linalg.norm(jac[0]))

        # Check length of edge is sqrt(2)
        self.assertTrue(np.allclose(np.sum(wg), np.sqrt(2)))

        # Check Int x^2 y on CD
        f = lambda x, y: x**2 * y
        fx = f(xg[:, 0], xg[:, 1])

        self.assertTrue(np.allclose(np.sum(fx * wg), np.sqrt(2) * (1 / 12)))

        #
        # Use shape functions to evaluate line integral
        #

        #
        # Map 1D rule onto reference cell
        #
        Q = QuadFE(2, 'Q1')
        rcell = Q.reference_cell()

        # Determine equivalent Half-edge on reference element
        i_he = cell.get_half_edges().index(CD)
        ref_he = rcell.get_half_edge(i_he)

        # Get 2D reference nodes
        b, h = convert_to_array(ref_he.get_vertices())
        x_ref = np.array([b[i] + xx * (h[i] - b[i]) for i in range(2)]).T

        # Map 2D reference point to phyisical cell
        xxg, mg = cell.reference_map(x_ref,
                                     jac_r2p=False,
                                     jac_p2r=True,
                                     hess_p2r=True)

        self.assertTrue(np.allclose(xxg, xg))

        # Evaluate the shape functions
        phi = Q.shape(x_ref, cell, [(0, ), (1, 0), (1, 1)], mg['jac_p2r'])

        # x = phi1 - phi3
        self.assertTrue(np.allclose(phi[0][:, 1] - phi[0][:, 3], xg[:, 0]))

        # y = -phi0 + phi2
        self.assertTrue(np.allclose(-phi[0][:, 0] + phi[0][:, 2], xg[:, 1]))

        # g(x,y) = x - y = phi*[1,1,-1-1]
        c = np.array([1, 1, -1, -1])
        g = phi[0].dot(c)

        # Int_CD x-y ds
        self.assertTrue(np.allclose(np.sum(wg * g), -np.sqrt(2)))

        # Integrals involving phi_x, phi_y
        gx = phi[1].dot(c)
        gy = phi[2].dot(c)

        n = CD.unit_normal()

        self.assertTrue(np.allclose(np.sum(wg * (gx * n[0] + gy * n[1])), -2))
Exemple #7
0
]
cell = QuadCell(halfedges)
cell.split()

plot = Plot(quickview=False)
fig, ax = plt.subplots(1, 1)

# Plot cell and children
for c in cell.traverse():
    vertices = [v.coordinates() for v in c.get_vertices()]
    poly = plt.Polygon(vertices, fc=clrs.to_rgba('w'), edgecolor=(0, 0, 0, 1))
    ax.add_patch(poly)

# Define Gauss Rule
child = cell.get_child(0)
gauss = GaussRule(4, shape='quadrilateral')

# Map rule to sw child
xg, wg, mg = gauss.mapped_rule(child, jac_p2r=True, hess_p2r=True)

plt.plot(xg[:, 0], xg[:, 1], '.k')

# Subdivide reference cell with same tree structure
r0, r1, r2, r3 = Vertex((0, 0)), Vertex((1, 0)), Vertex((1, 1)), Vertex((0, 1))
half_edges = [
    HalfEdge(r0, r1),
    HalfEdge(r1, r2),
    HalfEdge(r2, r3),
    HalfEdge(r3, r0)
]