Ejemplo n.º 1
0
def test_gll():
    m = 5

    # 1D interval
    pts, wts = basix.make_quadrature(basix.QuadratureType.gll, basix.CellType.interval, m+1)
    pts, wts = 2*pts.flatten()-1, 2*wts.flatten()
    ref_pts = np.array([-1., 1., -np.sqrt(3/7), 0.0, np.sqrt(3/7)])
    assert (np.allclose(pts.flatten(), ref_pts))
    ref_wts = np.array([1/10, 1/10, 49/90, 32/45, 49/90])
    assert (np.allclose(wts, ref_wts))
    assert np.isclose(sum(pts * wts), 0)
    assert np.isclose(sum(wts), 2)

    # 2D quad
    pts, wts = basix.make_quadrature(basix.QuadratureType.gll, basix.CellType.quadrilateral, m+1)
    pts, wts = 2*pts-1, 4*wts
    ref_pts2 = np.array([[x, y] for x in ref_pts for y in ref_pts])
    assert (np.allclose(pts, ref_pts2))
    ref_wts2 = np.array([w1*w2 for w1 in ref_wts for w2 in ref_wts])
    assert (np.allclose(wts, ref_wts2))
    assert np.isclose((pts * wts.reshape(-1, 1)).sum(), 0)
    assert np.isclose(sum(wts), 4)

    # 3D hex
    pts, wts = basix.make_quadrature(basix.QuadratureType.gll, basix.CellType.hexahedron, m+1)
    pts, wts = 2*pts-1, 8*wts
    ref_pts3 = np.array([[x, y, z] for x in ref_pts for y in ref_pts for z in ref_pts])
    assert (np.allclose(pts, ref_pts3))
    ref_wts3 = np.array([w1*w2*w3 for w1 in ref_wts for w2 in ref_wts for w3 in ref_wts])
    assert (np.allclose(wts, ref_wts3))
    assert np.isclose((pts * wts.reshape(-1, 1)).sum(), 0)
    assert np.isclose(sum(wts), 8)
Ejemplo n.º 2
0
def test_tensor_product_factorisation_quadrilateral(degree):
    P = degree
    cell_type = basix.CellType.quadrilateral
    element = basix.create_element(basix.ElementFamily.P, cell_type, P,
                                   basix.LagrangeVariant.gll_warped)
    factors = element.get_tensor_product_representation()[0]

    # Quadrature degree
    Q = 2 * P + 2
    points, w = basix.make_quadrature(basix.QuadratureType.Default, cell_type,
                                      Q)
    data = element.tabulate(1, points)
    dphi_x = data[1, :, :, 0]
    dphi_y = data[2, :, :, 0]

    assert points.shape[0] == (P + 2) * (P + 2)

    # FIXME: This test assumes all factors formed by a single element
    perm = factors[1]
    element0 = factors[0][0]
    cell1d = element0.cell_type
    points, w = basix.make_quadrature(basix.QuadratureType.Default, cell1d, Q)
    data = element0.tabulate(1, points)
    phi0 = data[0, :, :, 0]
    dphi0 = data[1, :, :, 0]

    # number of dofs in each direction
    Nd = P + 1
    # number of quadrature points in each direction
    Nq = P + 2

    # Compute derivative of basis function in the x direction
    dphi_tensor = numpy.zeros([Nq, Nq, Nd, Nd])
    for q0 in range(Nq):
        for q1 in range(Nq):
            for i0 in range(Nd):
                for i1 in range(Nd):
                    dphi_tensor[q0, q1, i0, i1] = dphi0[q0, i0] * phi0[q1, i1]
    dphi_tensor = dphi_tensor.reshape([Nq * Nq, Nd * Nd])
    assert numpy.allclose(dphi_x[:, perm], dphi_tensor)

    # Compute derivative of basis function in the y direction
    dphi_tensor = numpy.zeros([Nq, Nq, Nd, Nd])
    for q0 in range(Nq):
        for q1 in range(Nq):
            for i0 in range(Nd):
                for i1 in range(Nd):
                    dphi_tensor[q0, q1, i0, i1] = phi0[q0, i0] * dphi0[q1, i1]

    dphi_tensor = dphi_tensor.reshape([Nq * Nq, Nd * Nd])
    assert numpy.allclose(dphi_y[:, perm], dphi_tensor)
Ejemplo n.º 3
0
def test_qorder_line(m, scheme):
    Qpts, Qwts = basix.make_quadrature(scheme, basix.CellType.interval, m)
    x = sympy.Symbol('x')
    f = x**m
    q = sympy.integrate(f, (x, 0, (1)))
    s = 0.0
    for (pt, wt) in zip(Qpts, Qwts):
        s += wt * f.subs([(x, pt[0])])
    assert(np.isclose(float(q), float(s)))
Ejemplo n.º 4
0
def test_xiao_gimbutas_tri(m, scheme):
    Qpts, Qwts = basix.make_quadrature(scheme, basix.CellType.triangle, m)
    x = sympy.Symbol('x')
    y = sympy.Symbol('y')
    f = x**m + 2 * y**m
    q = sympy.integrate(sympy.integrate(f, (x, 0, 1 - y)), (y, 0, 1))
    s = 0.0
    for (pt, wt) in zip(Qpts, Qwts):
        s += wt * f.subs([(x, pt[0]), (y, pt[1])])
    assert(np.isclose(float(q), float(s)))
Ejemplo n.º 5
0
def test_prism(order):
    Tpts, Twts = basix.make_quadrature(basix.CellType.triangle, 2 * order + 1)
    Lpts, Lwts = basix.make_quadrature(basix.CellType.interval, 2 * order + 1)
    Qwts = []
    Qpts = []
    for p, u in zip(Tpts, Twts):
        for q, v in zip(Lpts, Lwts):
            Qpts.append([p[0], p[1], q[0]])
            Qwts.append(u * v)
    basis = basix._basixcpp.tabulate_polynomial_set(basix.CellType.prism,
                                                    order, 0, Qpts)[0]
    ndofs = basis.shape[1]

    mat = np.zeros((ndofs, ndofs))
    for i in range(ndofs):
        for j in range(ndofs):
            mat[i, j] = sum(basis[:, i] * basis[:, j] * Qwts)

    assert np.allclose(mat, np.eye(ndofs))
Ejemplo n.º 6
0
def test_qorder_tet(m, scheme):
    Qpts, Qwts = basix.make_quadrature(scheme, basix.CellType.tetrahedron, m)
    x = sympy.Symbol('x')
    y = sympy.Symbol('y')
    z = sympy.Symbol('z')
    f = x**m + y**m + z**m
    q = sympy.integrate(sympy.integrate(sympy.integrate(f, (x, 0, (1 - y - z))), (y, 0, 1 - z)), (z, 0, 1))
    s = 0.0
    for (pt, wt) in zip(Qpts, Qwts):
        s += wt * f.subs([(x, pt[0]), (y, pt[1]), (z, pt[2])])
    assert(np.isclose(float(q), float(s)))
Ejemplo n.º 7
0
def test_legendre(cell_type, degree):
    points, weights = basix.make_quadrature(cell_type, 2 * degree)

    polys = basix.tabulate_polynomials(basix.PolynomialType.legendre,
                                       cell_type, degree, points)

    matrix = numpy.empty((polys.shape[1], polys.shape[1]))
    for i, col_i in enumerate(polys.T):
        for j, col_j in enumerate(polys.T):
            matrix[i, j] = sum(col_i * col_j * weights)

    assert numpy.allclose(matrix, numpy.identity(polys.shape[1]))
Ejemplo n.º 8
0
def test_quadrature_function():
    Qpts, Qwts = basix.make_quadrature(basix.CellType.interval, 3)
    # Scale to interval [0.0, 2.0]
    Qpts *= 2.0
    Qwts *= 2.0

    def f(x):
        return x * x

    b = sum([w * f(pt[0]) for pt, w in zip(Qpts, Qwts)])

    assert np.isclose(b, 8.0 / 3.0)
Ejemplo n.º 9
0
def test_cell(cell_type, order):
    Qpts, Qwts = basix.make_quadrature(cell_type, 2 * order + 1)
    basis = basix._basixcpp.tabulate_polynomial_set(cell_type, order, 0,
                                                    Qpts)[0]

    ndofs = basis.shape[1]
    mat = np.zeros((ndofs, ndofs))
    for i in range(ndofs):
        for j in range(ndofs):
            mat[i, j] = sum(basis[:, i] * basis[:, j] * Qwts)

    assert np.allclose(mat, np.eye(ndofs))
Ejemplo n.º 10
0
def create_quadrature(cellname, degree, rule):
    """Create a quadrature rule."""
    if cellname == "vertex":
        return [[]], [1]

    quadrature = basix.make_quadrature(rule,
                                       basix.cell.string_to_type(cellname),
                                       degree)

    # The quadrature degree from UFL can be very high for some
    # integrals.  Print warning if number of quadrature points
    # exceeds 100.
    num_points = quadrature[1].size
    if num_points >= 100:
        warnings.warn(
            f"Number of integration points per cell is: {num_points}. Consider using 'quadrature_degree' "
            "to reduce number.")

    return quadrature
Ejemplo n.º 11
0
def test_pyramid(order):
    Lpts, Lwts = basix.make_quadrature(basix.CellType.interval, 4 * order + 2)
    Qwts = []
    Qpts = []
    for p, u in zip(Lpts, Lwts):
        for q, v in zip(Lpts, Lwts):
            for r, w in zip(Lpts, Lwts):
                sc = (1.0 - r[0])
                Qpts.append([p[0] * sc, q[0] * sc, r[0]])
                Qwts.append(u * v * sc * sc * w)
    basis = basix._basixcpp.tabulate_polynomial_set(basix.CellType.pyramid,
                                                    order, 0, Qpts)[0]
    ndofs = basis.shape[1]

    mat = np.zeros((ndofs, ndofs))
    for i in range(ndofs):
        for j in range(ndofs):
            mat[i, j] = sum(basis[:, i] * basis[:, j] * Qwts)

    assert np.allclose(mat, np.eye(ndofs))
Ejemplo n.º 12
0
def test_assembly_into_quadrature_function():
    """Test assembly into a Quadrature function.

    This test evaluates a UFL Expression into a Quadrature function space by
    evaluating the Expression on all cells of the mesh, and then inserting the
    evaluated values into a PETSc Vector constructed from a matching Quadrature
    function space.

    Concretely, we consider the evaluation of:

        e = B*(K(T)))**2 * grad(T)

    where

        K = 1/(A + B*T)

    where A and B are Constants and T is a Coefficient on a P2 finite element
    space with T = x + 2*y.

    The result is compared with interpolating the analytical expression of e
    directly into the Quadrature space.

    In parallel, each process evaluates the Expression on both local cells and
    ghost cells so that no parallel communication is required after insertion
    into the vector.
    """
    mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 3, 6)

    quadrature_degree = 2
    quadrature_points = basix.make_quadrature(basix.CellType.triangle, quadrature_degree)
    Q_element = ufl.VectorElement("Quadrature", ufl.triangle, quadrature_degree, quad_scheme="default")
    Q = dolfinx.FunctionSpace(mesh, Q_element)

    def T_exact(x):
        return x[0] + 2.0 * x[1]

    P2 = dolfinx.FunctionSpace(mesh, ("P", 2))
    T = dolfinx.Function(P2)
    T.interpolate(T_exact)
    A = dolfinx.Constant(mesh, 1.0)
    B = dolfinx.Constant(mesh, 2.0)

    K = 1.0 / (A + B * T)
    e = B * K**2 * ufl.grad(T)

    e_expr = dolfinx.Expression(e, quadrature_points)

    map_c = mesh.topology.index_map(mesh.topology.dim)
    num_cells = map_c.size_local + map_c.num_ghosts
    cells = np.arange(0, num_cells, dtype=np.int32)

    e_eval = e_expr.eval(cells)

    # Assemble into Function
    e_Q = dolfinx.Function(Q)
    with e_Q.vector.localForm() as e_Q_local:
        e_Q_local.setBlockSize(e_Q.function_space.dofmap.bs)
        e_Q_local.setValuesBlocked(Q.dofmap.list.array, e_eval, addv=PETSc.InsertMode.INSERT)

    def e_exact(x):
        T = x[0] + 2.0 * x[1]
        K = 1.0 / (A.value + B.value * T)

        grad_T = np.zeros((2, x.shape[1]))
        grad_T[0, :] = 1.0
        grad_T[1, :] = 2.0

        e = B.value * K**2 * grad_T
        return e

    e_exact_Q = dolfinx.Function(Q)
    e_exact_Q.interpolate(e_exact)

    assert np.isclose((e_exact_Q.vector - e_Q.vector).norm(), 0.0)
Ejemplo n.º 13
0
import basix
import numpy as np
from basix import ElementFamily, CellType, LagrangeVariant

# To get a quadrature rule on a triangle, we use the function `make_quadrature`.
# This function takes two or three three inputs. We want to use the default
# quadrature, pass in two inputs: a cell type and an order. The order of the rule
# is equal to the degree of the highest degree polynomial that will be exactly
# integrated by this rule. In this example, we use an order 4 rule, so all quartic
# polynomials will be integrated exactly.
#
# `make_quadrature` returns two values: the points and the weights of the
# quadrature rule.

points, weights = basix.make_quadrature(CellType.triangle, 4)

# If we want to control the type of quadrature used, we can pass in three
# inputs to `make_quadrautre`. For example, the following code would force basix
# to use a Gauss-Jacobi quadrature rule:

points, weights = basix.make_quadrature(basix.QuadratureType.gauss_jacobi,
                                        CellType.triangle, 4)

# We now use this quadrature rule to integrate the functions :math:`f(x,y)=x^3y`
# and :math:`g(x,y)=x^3y^2` over the triangle. The exact values of these integrals
# are 1/120 (0.00833333333333...) and 1/420 (0.00238095238095...) respectively.
#
# As :math:`f` is a degree 4 polynomial, we expect our quadrature rule to be able
# to compute its integral exactly (within machine precision). :math:`g` on the
# other hand is a degree 5 polynomial, so its integral will not be computed exactly.
Ejemplo n.º 14
0
# We start by importing Basis and Numpy.

import basix
import numpy as np
from basix import ElementFamily, CellType, LagrangeVariant

# We define a degree 3 Lagrange space on a tetrahedron.

lagrange = basix.create_element(ElementFamily.P, CellType.tetrahedron, 3,
                                LagrangeVariant.equispaced)

# The facets of a tetrahedron are triangular, so we create a quadrature
# rule on a triangle. We use an order 3 rule so that we can integrate the
# basis functions in our space exactly.

points, weights = basix.make_quadrature(CellType.triangle, 3)

# Next, we must map the quadrature points to our facet. We use the function
# `geometry` to get the coordinates of the vertices of the tetrahedron, and
# we use `sub_entity_connectivity` to see which vertices are adjacent to
# our facet. We get the sub-entity connectivity using the indices 2 (facets
# of 3D cells have dimension 2), 0 (vertices have dimension 0), and 0 (the
# index of the facet we chose to use).
#
# Using this information, we can map the quadrature points to the facet.

vertices = basix.geometry(CellType.tetrahedron)
facet = basix.cell.sub_entity_connectivity(CellType.tetrahedron)[2][0][0]
mapped_points = np.array([
    vertices[facet[0]] * (1 - x - y) + vertices[facet[1]] * x +
    vertices[facet[2]] * y for x, y in points
Ejemplo n.º 15
0
def test_cell_quadrature(celltype, order):
    Qpts, Qwts = basix.make_quadrature(celltype[0], order)
    assert(np.isclose(sum(Qwts), celltype[1]))
Ejemplo n.º 16
0
def test_assembly_into_quadrature_function():
    """Test assembly into a Quadrature function.

    This test evaluates a UFL Expression into a Quadrature function space by
    evaluating the Expression on all cells of the mesh, and then inserting the
    evaluated values into a PETSc Vector constructed from a matching Quadrature
    function space.

    Concretely, we consider the evaluation of:

        e = B*(K(T)))**2 * grad(T)

    where

        K = 1/(A + B*T)

    where A and B are Constants and T is a Coefficient on a P2 finite element
    space with T = x + 2*y.

    The result is compared with interpolating the analytical expression of e
    directly into the Quadrature space.

    In parallel, each process evaluates the Expression on both local cells and
    ghost cells so that no parallel communication is required after insertion
    into the vector.
    """
    mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 3, 6)

    quadrature_degree = 2
    quadrature_points, wts = basix.make_quadrature("default",
                                                   basix.CellType.triangle,
                                                   quadrature_degree)
    Q_element = ufl.VectorElement("Quadrature",
                                  ufl.triangle,
                                  quadrature_degree,
                                  quad_scheme="default")
    Q = dolfinx.FunctionSpace(mesh, Q_element)

    def T_exact(x):
        return x[0] + 2.0 * x[1]

    P2 = dolfinx.FunctionSpace(mesh, ("P", 2))
    T = dolfinx.Function(P2)
    T.interpolate(T_exact)
    A = dolfinx.Constant(mesh, 1.0)
    B = dolfinx.Constant(mesh, 2.0)

    K = 1.0 / (A + B * T)
    e = B * K**2 * ufl.grad(T)

    e_expr = dolfinx.Expression(e, quadrature_points)

    map_c = mesh.topology.index_map(mesh.topology.dim)
    num_cells = map_c.size_local + map_c.num_ghosts
    cells = np.arange(0, num_cells, dtype=np.int32)

    e_eval = e_expr.eval(cells)

    # Assemble into Function
    e_Q = dolfinx.Function(Q)
    with e_Q.vector.localForm() as e_Q_local:
        e_Q_local.setBlockSize(e_Q.function_space.dofmap.bs)
        e_Q_local.setValuesBlocked(Q.dofmap.list.array,
                                   e_eval,
                                   addv=PETSc.InsertMode.INSERT)

    def e_exact(x):
        T = x[0] + 2.0 * x[1]
        K = 1.0 / (A.value + B.value * T)

        grad_T = np.zeros((2, x.shape[1]))
        grad_T[0, :] = 1.0
        grad_T[1, :] = 2.0

        e = B.value * K**2 * grad_T
        return e

    # FIXME: Below is only for testing purposes,
    # never to be used in user code!
    #
    # Replace when interpolation into Quadrature element works.
    coord_dofs = mesh.geometry.dofmap
    x_g = mesh.geometry.x
    tdim = mesh.topology.dim
    Q_dofs = Q.dofmap.list.array.reshape(num_cells, quadrature_points.shape[0])
    bs = Q.dofmap.bs

    Q_dofs_unrolled = bs * np.repeat(Q_dofs, bs).reshape(-1,
                                                         bs) + np.arange(bs)
    Q_dofs_unrolled = Q_dofs_unrolled.reshape(
        -1, bs * quadrature_points.shape[0]).astype(Q_dofs.dtype)

    with e_Q.vector.localForm() as local:
        e_exact_eval = np.zeros_like(local.array)

        for cell in range(num_cells):
            xg = x_g[coord_dofs.links(cell), :tdim]
            x = mesh.geometry.cmap.push_forward(quadrature_points, xg)
            e_exact_eval[Q_dofs_unrolled[cell]] = e_exact(x.T).T.flatten()

        assert np.allclose(local.array, e_exact_eval)
Ejemplo n.º 17
0
def create_quadrature(cellname, degree, rule):
    if cellname == "vertex":
        return [[]], [1]
    return basix.make_quadrature(rule, basix_cells[cellname], degree)