xref: /libCEED/python/tests/test-3-basis.py (revision 3d8e882215d238700cdceb37404f76ca7fa24eaa)
1*3d8e8822SJeremy L Thompson# Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors
2*3d8e8822SJeremy L Thompson# All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
30ef72598Sjeremylt#
4*3d8e8822SJeremy L Thompson# SPDX-License-Identifier: BSD-2-Clause
50ef72598Sjeremylt#
6*3d8e8822SJeremy L Thompson# This file is part of CEED:  http://github.com/ceed
70ef72598Sjeremylt
80ef72598Sjeremylt# @file
90ef72598Sjeremylt# Test Ceed Basis functionality
100ef72598Sjeremylt
110ef72598Sjeremyltimport os
120ef72598Sjeremyltimport math
130ef72598Sjeremyltimport libceed
140ef72598Sjeremyltimport numpy as np
150ef72598Sjeremyltimport buildmats as bm
160ef72598Sjeremyltimport check
170ef72598Sjeremylt
1880a9ef05SNatalie BeamsTOL = libceed.EPSILON * 256
190ef72598Sjeremylt
200ef72598Sjeremylt# -------------------------------------------------------------------------------
210ef72598Sjeremylt# Utilities
220ef72598Sjeremylt# -------------------------------------------------------------------------------
230ef72598Sjeremylt
240ef72598Sjeremylt
250ef72598Sjeremyltdef eval(dim, x):
260ef72598Sjeremylt    result, center = 1, 0.1
270ef72598Sjeremylt    for d in range(dim):
280ef72598Sjeremylt        result *= math.tanh(x[d] - center)
290ef72598Sjeremylt        center += 0.1
300ef72598Sjeremylt    return result
310ef72598Sjeremylt
320ef72598Sjeremylt
330ef72598Sjeremyltdef feval(x1, x2):
340ef72598Sjeremylt    return x1 * x1 + x2 * x2 + x1 * x2 + 1
350ef72598Sjeremylt
360ef72598Sjeremylt
370ef72598Sjeremyltdef dfeval(x1, x2):
380ef72598Sjeremylt    return 2 * x1 + x2
390ef72598Sjeremylt
400ef72598Sjeremylt# -------------------------------------------------------------------------------
410ef72598Sjeremylt# Test creation and distruction of a H1Lagrange basis
420ef72598Sjeremylt# -------------------------------------------------------------------------------
430ef72598Sjeremylt
440ef72598Sjeremylt
450ef72598Sjeremyltdef test_300(ceed_resource, capsys):
460ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
470ef72598Sjeremylt
480ef72598Sjeremylt    b = ceed.BasisTensorH1Lagrange(1, 1, 4, 4, libceed.GAUSS_LOBATTO)
490ef72598Sjeremylt    print(b)
500ef72598Sjeremylt    del b
510ef72598Sjeremylt
520ef72598Sjeremylt    b = ceed.BasisTensorH1Lagrange(1, 1, 4, 4, libceed.GAUSS)
530ef72598Sjeremylt    print(b)
540ef72598Sjeremylt    del b
550ef72598Sjeremylt
5680a9ef05SNatalie Beams    # Only run this test in double precision
5780a9ef05SNatalie Beams    if libceed.lib.CEED_SCALAR_TYPE == libceed.SCALAR_FP64:
580ef72598Sjeremylt        stdout, stderr, ref_stdout = check.output(capsys)
590ef72598Sjeremylt        assert not stderr
600ef72598Sjeremylt        assert stdout == ref_stdout
610ef72598Sjeremylt
620ef72598Sjeremylt# -------------------------------------------------------------------------------
630ef72598Sjeremylt# Test QR factorization
640ef72598Sjeremylt# -------------------------------------------------------------------------------
650ef72598Sjeremylt
660ef72598Sjeremylt
67c3a5a609SJeremy L Thompsondef test_301(ceed_resource):
680ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
690ef72598Sjeremylt
70c3a5a609SJeremy L Thompson    m = 4
71c3a5a609SJeremy L Thompson    n = 3
7280a9ef05SNatalie Beams    a = np.array([1, -1, 4, 1, 4, -2, 1, 4, 2, 1, -1, 0],
7380a9ef05SNatalie Beams                 dtype=ceed.scalar_type())
7480a9ef05SNatalie Beams    qr = np.array([1, -1, 4, 1, 4, -2, 1, 4, 2, 1, -1, 0],
7580a9ef05SNatalie Beams                  dtype=ceed.scalar_type())
7680a9ef05SNatalie Beams    tau = np.empty(3, dtype=ceed.scalar_type())
770ef72598Sjeremylt
78c3a5a609SJeremy L Thompson    qr, tau = ceed.qr_factorization(qr, tau, m, n)
79c3a5a609SJeremy L Thompson    np_qr, np_tau = np.linalg.qr(a.reshape(m, n), mode="raw")
800ef72598Sjeremylt
81c3a5a609SJeremy L Thompson    for i in range(n):
8280a9ef05SNatalie Beams        assert abs(tau[i] - np_tau[i]) < TOL
830ef72598Sjeremylt
84c3a5a609SJeremy L Thompson    qr = qr.reshape(m, n)
85c3a5a609SJeremy L Thompson    for i in range(m):
86c3a5a609SJeremy L Thompson        for j in range(n):
8780a9ef05SNatalie Beams            assert abs(qr[i, j] - np_qr[j, i]) < TOL
880ef72598Sjeremylt
890ef72598Sjeremylt# -------------------------------------------------------------------------------
900ef72598Sjeremylt# Test Symmetric Schur Decomposition
910ef72598Sjeremylt# -------------------------------------------------------------------------------
920ef72598Sjeremylt
930ef72598Sjeremylt
94c3a5a609SJeremy L Thompsondef test_304(ceed_resource):
950ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
960ef72598Sjeremylt
97673160d7Sjeremylt    A = np.array([0.2, 0.0745355993, -0.0745355993, 0.0333333333,
98673160d7Sjeremylt                  0.0745355993, 1., 0.1666666667, -0.0745355993,
99673160d7Sjeremylt                  -0.0745355993, 0.1666666667, 1., 0.0745355993,
10080a9ef05SNatalie Beams                  0.0333333333, -0.0745355993, 0.0745355993, 0.2],
10180a9ef05SNatalie Beams                 dtype=ceed.scalar_type())
1020ef72598Sjeremylt
103673160d7Sjeremylt    Q = A.copy()
1040ef72598Sjeremylt
105673160d7Sjeremylt    lam = ceed.symmetric_schur_decomposition(Q, 4)
106673160d7Sjeremylt    Q = Q.reshape(4, 4)
107673160d7Sjeremylt    lam = np.diag(lam)
1080ef72598Sjeremylt
109673160d7Sjeremylt    Q_lambda_Qt = np.matmul(np.matmul(Q, lam), Q.T)
11080a9ef05SNatalie Beams    assert np.max(Q_lambda_Qt - A.reshape(4, 4)) < TOL
1110ef72598Sjeremylt
1120ef72598Sjeremylt# -------------------------------------------------------------------------------
1130ef72598Sjeremylt# Test Simultaneous Diagonalization
1140ef72598Sjeremylt# -------------------------------------------------------------------------------
1150ef72598Sjeremylt
1160ef72598Sjeremylt
117c3a5a609SJeremy L Thompsondef test_305(ceed_resource):
1180ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1190ef72598Sjeremylt
120673160d7Sjeremylt    M = np.array([0.2, 0.0745355993, -0.0745355993, 0.0333333333,
121673160d7Sjeremylt                  0.0745355993, 1., 0.1666666667, -0.0745355993,
122673160d7Sjeremylt                  -0.0745355993, 0.1666666667, 1., 0.0745355993,
12380a9ef05SNatalie Beams                  0.0333333333, -0.0745355993, 0.0745355993, 0.2],
12480a9ef05SNatalie Beams                 dtype=ceed.scalar_type())
125673160d7Sjeremylt    K = np.array([3.0333333333, -3.4148928136, 0.4982261470, -0.1166666667,
126673160d7Sjeremylt                  -3.4148928136, 5.8333333333, -2.9166666667, 0.4982261470,
127673160d7Sjeremylt                  0.4982261470, -2.9166666667, 5.8333333333, -3.4148928136,
12880a9ef05SNatalie Beams                  -0.1166666667, 0.4982261470, -3.4148928136, 3.0333333333],
12980a9ef05SNatalie Beams                 dtype=ceed.scalar_type())
1300ef72598Sjeremylt
131673160d7Sjeremylt    X, lam = ceed.simultaneous_diagonalization(K, M, 4)
132673160d7Sjeremylt    X = X.reshape(4, 4)
133673160d7Sjeremylt    np.diag(lam)
1340ef72598Sjeremylt
135673160d7Sjeremylt    M = M.reshape(4, 4)
136673160d7Sjeremylt    K = K.reshape(4, 4)
1370ef72598Sjeremylt
138673160d7Sjeremylt    Xt_M_X = np.matmul(X.T, np.matmul(M, X))
13980a9ef05SNatalie Beams    assert np.max(Xt_M_X - np.identity(4)) < TOL
1400ef72598Sjeremylt
141673160d7Sjeremylt    Xt_K_X = np.matmul(X.T, np.matmul(K, X))
14280a9ef05SNatalie Beams    assert np.max(Xt_K_X - lam) < TOL
1430ef72598Sjeremylt
1440ef72598Sjeremylt# -------------------------------------------------------------------------------
1450ef72598Sjeremylt# Test GetNumNodes and GetNumQuadraturePoints for basis
1460ef72598Sjeremylt# -------------------------------------------------------------------------------
1470ef72598Sjeremylt
1480ef72598Sjeremylt
1490ef72598Sjeremyltdef test_306(ceed_resource):
1500ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1510ef72598Sjeremylt
1520ef72598Sjeremylt    b = ceed.BasisTensorH1Lagrange(3, 1, 4, 5, libceed.GAUSS_LOBATTO)
1530ef72598Sjeremylt
1540ef72598Sjeremylt    p = b.get_num_nodes()
1550ef72598Sjeremylt    q = b.get_num_quadrature_points()
1560ef72598Sjeremylt
1570ef72598Sjeremylt    assert p == 64
1580ef72598Sjeremylt    assert q == 125
1590ef72598Sjeremylt
1600ef72598Sjeremylt# -------------------------------------------------------------------------------
1610ef72598Sjeremylt# Test interpolation in multiple dimensions
1620ef72598Sjeremylt# -------------------------------------------------------------------------------
1630ef72598Sjeremylt
1640ef72598Sjeremylt
1650ef72598Sjeremyltdef test_313(ceed_resource):
1660ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1670ef72598Sjeremylt
1680ef72598Sjeremylt    for dim in range(1, 4):
1690ef72598Sjeremylt        Q = 10
1700ef72598Sjeremylt        Qdim = Q**dim
1710ef72598Sjeremylt        Xdim = 2**dim
17280a9ef05SNatalie Beams        x = np.empty(Xdim * dim, dtype=ceed.scalar_type())
17380a9ef05SNatalie Beams        uq = np.empty(Qdim, dtype=ceed.scalar_type())
1740ef72598Sjeremylt
1750ef72598Sjeremylt        for d in range(dim):
1760ef72598Sjeremylt            for i in range(Xdim):
1770ef72598Sjeremylt                x[d * Xdim + i] = 1 if (i %
1780ef72598Sjeremylt                                        (2**(dim - d))) // (2**(dim - d - 1)) else -1
1790ef72598Sjeremylt
1800ef72598Sjeremylt        X = ceed.Vector(Xdim * dim)
1810ef72598Sjeremylt        X.set_array(x, cmode=libceed.USE_POINTER)
1820ef72598Sjeremylt        Xq = ceed.Vector(Qdim * dim)
1830ef72598Sjeremylt        Xq.set_value(0)
1840ef72598Sjeremylt        U = ceed.Vector(Qdim)
1850ef72598Sjeremylt        U.set_value(0)
1860ef72598Sjeremylt        Uq = ceed.Vector(Qdim)
1870ef72598Sjeremylt
1880ef72598Sjeremylt        bxl = ceed.BasisTensorH1Lagrange(dim, dim, 2, Q, libceed.GAUSS_LOBATTO)
1890ef72598Sjeremylt        bul = ceed.BasisTensorH1Lagrange(dim, 1, Q, Q, libceed.GAUSS_LOBATTO)
1900ef72598Sjeremylt
1910ef72598Sjeremylt        bxl.apply(1, libceed.EVAL_INTERP, X, Xq)
1920ef72598Sjeremylt
1930ef72598Sjeremylt        with Xq.array_read() as xq:
1940ef72598Sjeremylt            for i in range(Qdim):
19580a9ef05SNatalie Beams                xx = np.empty(dim, dtype=ceed.scalar_type())
1960ef72598Sjeremylt                for d in range(dim):
1970ef72598Sjeremylt                    xx[d] = xq[d * Qdim + i]
1980ef72598Sjeremylt                uq[i] = eval(dim, xx)
1990ef72598Sjeremylt
2000ef72598Sjeremylt        Uq.set_array(uq, cmode=libceed.USE_POINTER)
2010ef72598Sjeremylt
2020ef72598Sjeremylt        # This operation is the identity because the quadrature is collocated
2030ef72598Sjeremylt        bul.T.apply(1, libceed.EVAL_INTERP, Uq, U)
2040ef72598Sjeremylt
2050ef72598Sjeremylt        bxg = ceed.BasisTensorH1Lagrange(dim, dim, 2, Q, libceed.GAUSS)
2060ef72598Sjeremylt        bug = ceed.BasisTensorH1Lagrange(dim, 1, Q, Q, libceed.GAUSS)
2070ef72598Sjeremylt
2080ef72598Sjeremylt        bxg.apply(1, libceed.EVAL_INTERP, X, Xq)
2090ef72598Sjeremylt        bug.apply(1, libceed.EVAL_INTERP, U, Uq)
2100ef72598Sjeremylt
2110ef72598Sjeremylt        with Xq.array_read() as xq, Uq.array_read() as u:
2120ef72598Sjeremylt            for i in range(Qdim):
21380a9ef05SNatalie Beams                xx = np.empty(dim, dtype=ceed.scalar_type())
2140ef72598Sjeremylt                for d in range(dim):
2150ef72598Sjeremylt                    xx[d] = xq[d * Qdim + i]
2160ef72598Sjeremylt                fx = eval(dim, xx)
2170ef72598Sjeremylt                assert math.fabs(u[i] - fx) < 1E-4
2180ef72598Sjeremylt
2190ef72598Sjeremylt# -------------------------------------------------------------------------------
2200ef72598Sjeremylt# Test grad in multiple dimensions
2210ef72598Sjeremylt# -------------------------------------------------------------------------------
2220ef72598Sjeremylt
2230ef72598Sjeremylt
2240ef72598Sjeremyltdef test_314(ceed_resource):
2250ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
2260ef72598Sjeremylt
2270ef72598Sjeremylt    for dim in range(1, 4):
2280ef72598Sjeremylt        P, Q = 8, 10
2290ef72598Sjeremylt        Pdim = P**dim
2300ef72598Sjeremylt        Qdim = Q**dim
2310ef72598Sjeremylt        Xdim = 2**dim
2320ef72598Sjeremylt        sum1 = sum2 = 0
23380a9ef05SNatalie Beams        x = np.empty(Xdim * dim, dtype=ceed.scalar_type())
23480a9ef05SNatalie Beams        u = np.empty(Pdim, dtype=ceed.scalar_type())
2350ef72598Sjeremylt
2360ef72598Sjeremylt        for d in range(dim):
2370ef72598Sjeremylt            for i in range(Xdim):
2380ef72598Sjeremylt                x[d * Xdim + i] = 1 if (i %
2390ef72598Sjeremylt                                        (2**(dim - d))) // (2**(dim - d - 1)) else -1
2400ef72598Sjeremylt
2410ef72598Sjeremylt        X = ceed.Vector(Xdim * dim)
2420ef72598Sjeremylt        X.set_array(x, cmode=libceed.USE_POINTER)
2430ef72598Sjeremylt        Xq = ceed.Vector(Pdim * dim)
2440ef72598Sjeremylt        Xq.set_value(0)
2450ef72598Sjeremylt        U = ceed.Vector(Pdim)
2460ef72598Sjeremylt        Uq = ceed.Vector(Qdim * dim)
2470ef72598Sjeremylt        Uq.set_value(0)
2480ef72598Sjeremylt        Ones = ceed.Vector(Qdim * dim)
2490ef72598Sjeremylt        Ones.set_value(1)
2500ef72598Sjeremylt        Gtposeones = ceed.Vector(Pdim)
2510ef72598Sjeremylt        Gtposeones.set_value(0)
2520ef72598Sjeremylt
2530ef72598Sjeremylt        # Get function values at quadrature points
2540ef72598Sjeremylt        bxl = ceed.BasisTensorH1Lagrange(dim, dim, 2, P, libceed.GAUSS_LOBATTO)
2550ef72598Sjeremylt        bxl.apply(1, libceed.EVAL_INTERP, X, Xq)
2560ef72598Sjeremylt
2570ef72598Sjeremylt        with Xq.array_read() as xq:
2580ef72598Sjeremylt            for i in range(Pdim):
25980a9ef05SNatalie Beams                xx = np.empty(dim, dtype=ceed.scalar_type())
2600ef72598Sjeremylt                for d in range(dim):
2610ef72598Sjeremylt                    xx[d] = xq[d * Pdim + i]
2620ef72598Sjeremylt                u[i] = eval(dim, xx)
2630ef72598Sjeremylt
2640ef72598Sjeremylt        U.set_array(u, cmode=libceed.USE_POINTER)
2650ef72598Sjeremylt
2660ef72598Sjeremylt        # Calculate G u at quadrature points, G' * 1 at dofs
2670ef72598Sjeremylt        bug = ceed.BasisTensorH1Lagrange(dim, 1, P, Q, libceed.GAUSS)
2680ef72598Sjeremylt        bug.apply(1, libceed.EVAL_GRAD, U, Uq)
2690ef72598Sjeremylt        bug.T.apply(1, libceed.EVAL_GRAD, Ones, Gtposeones)
2700ef72598Sjeremylt
2710ef72598Sjeremylt        # Check if 1' * G * u = u' * (G' * 1)
2720ef72598Sjeremylt        with Gtposeones.array_read() as gtposeones, Uq.array_read() as uq:
2730ef72598Sjeremylt            for i in range(Pdim):
2740ef72598Sjeremylt                sum1 += gtposeones[i] * u[i]
2750ef72598Sjeremylt            for i in range(dim * Qdim):
2760ef72598Sjeremylt                sum2 += uq[i]
2770ef72598Sjeremylt
27880a9ef05SNatalie Beams        assert math.fabs(sum1 - sum2) < 10. * TOL
2790ef72598Sjeremylt
2800ef72598Sjeremylt# -------------------------------------------------------------------------------
2810ef72598Sjeremylt# Test creation and destruction of a 2D Simplex non-tensor H1 basis
2820ef72598Sjeremylt# -------------------------------------------------------------------------------
2830ef72598Sjeremylt
2840ef72598Sjeremylt
2850ef72598Sjeremyltdef test_320(ceed_resource):
2860ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
2870ef72598Sjeremylt
2880ef72598Sjeremylt    P, Q, dim = 6, 4, 2
2890ef72598Sjeremylt
29080a9ef05SNatalie Beams    in_array = np.empty(P, dtype=ceed.scalar_type())
29180a9ef05SNatalie Beams    qref = np.empty(dim * Q, dtype=ceed.scalar_type())
29280a9ef05SNatalie Beams    qweight = np.empty(Q, dtype=ceed.scalar_type())
2930ef72598Sjeremylt
29480a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
29580a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
2960ef72598Sjeremylt
2970ef72598Sjeremylt    b = ceed.BasisH1(libceed.TRIANGLE, 1, P, Q, interp, grad, qref, qweight)
2980ef72598Sjeremylt
2990ef72598Sjeremylt    print(b)
3000ef72598Sjeremylt    del b
3010ef72598Sjeremylt
3020ef72598Sjeremylt# -------------------------------------------------------------------------------
3030ef72598Sjeremylt# Test integration with a 2D Simplex non-tensor H1 basis
3040ef72598Sjeremylt# -------------------------------------------------------------------------------
3050ef72598Sjeremylt
3060ef72598Sjeremylt
3070ef72598Sjeremyltdef test_322(ceed_resource):
3080ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
3090ef72598Sjeremylt
3100ef72598Sjeremylt    P, Q, dim = 6, 4, 2
3110ef72598Sjeremylt
3120ef72598Sjeremylt    xr = np.array([0., 0.5, 1., 0., 0.5, 0., 0., 0.,
31380a9ef05SNatalie Beams                   0., 0.5, 0.5, 1.], dtype=ceed.scalar_type())
31480a9ef05SNatalie Beams    in_array = np.empty(P, dtype=ceed.scalar_type())
31580a9ef05SNatalie Beams    qref = np.empty(dim * Q, dtype=ceed.scalar_type())
31680a9ef05SNatalie Beams    qweight = np.empty(Q, dtype=ceed.scalar_type())
3170ef72598Sjeremylt
31880a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
31980a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
3200ef72598Sjeremylt
3210ef72598Sjeremylt    b = ceed.BasisH1(libceed.TRIANGLE, 1, P, Q, interp, grad, qref, qweight)
3220ef72598Sjeremylt
3230ef72598Sjeremylt    # Interpolate function to quadrature points
3240ef72598Sjeremylt    for i in range(P):
3250ef72598Sjeremylt        in_array[i] = feval(xr[0 * P + i], xr[1 * P + i])
3260ef72598Sjeremylt
3270ef72598Sjeremylt    in_vec = ceed.Vector(P)
3280ef72598Sjeremylt    in_vec.set_array(in_array, cmode=libceed.USE_POINTER)
3290ef72598Sjeremylt    out_vec = ceed.Vector(Q)
3300ef72598Sjeremylt    out_vec.set_value(0)
3310ef72598Sjeremylt    weights_vec = ceed.Vector(Q)
3320ef72598Sjeremylt    weights_vec.set_value(0)
3330ef72598Sjeremylt
3340ef72598Sjeremylt    b.apply(1, libceed.EVAL_INTERP, in_vec, out_vec)
3350ef72598Sjeremylt    b.apply(1, libceed.EVAL_WEIGHT, libceed.VECTOR_NONE, weights_vec)
3360ef72598Sjeremylt
3370ef72598Sjeremylt    # Check values at quadrature points
3380ef72598Sjeremylt    with out_vec.array_read() as out_array, weights_vec.array_read() as weights_array:
3390ef72598Sjeremylt        sum = 0
3400ef72598Sjeremylt        for i in range(Q):
3410ef72598Sjeremylt            sum += out_array[i] * weights_array[i]
34280a9ef05SNatalie Beams        assert math.fabs(sum - 17. / 24.) < 10. * TOL
3430ef72598Sjeremylt
3440ef72598Sjeremylt# -------------------------------------------------------------------------------
3450ef72598Sjeremylt# Test grad with a 2D Simplex non-tensor H1 basis
3460ef72598Sjeremylt# -------------------------------------------------------------------------------
3470ef72598Sjeremylt
3480ef72598Sjeremylt
3490ef72598Sjeremyltdef test_323(ceed_resource):
3500ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
3510ef72598Sjeremylt
3520ef72598Sjeremylt    P, Q, dim = 6, 4, 2
3530ef72598Sjeremylt
3540ef72598Sjeremylt    xq = np.array([0.2, 0.6, 1. / 3., 0.2, 0.2, 0.2,
35580a9ef05SNatalie Beams                   1. / 3., 0.6], dtype=ceed.scalar_type())
3560ef72598Sjeremylt    xr = np.array([0., 0.5, 1., 0., 0.5, 0., 0., 0.,
35780a9ef05SNatalie Beams                   0., 0.5, 0.5, 1.], dtype=ceed.scalar_type())
35880a9ef05SNatalie Beams    in_array = np.empty(P, dtype=ceed.scalar_type())
35980a9ef05SNatalie Beams    qref = np.empty(dim * Q, dtype=ceed.scalar_type())
36080a9ef05SNatalie Beams    qweight = np.empty(Q, dtype=ceed.scalar_type())
3610ef72598Sjeremylt
36280a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
36380a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
3640ef72598Sjeremylt
3650ef72598Sjeremylt    b = ceed.BasisH1(libceed.TRIANGLE, 1, P, Q, interp, grad, qref, qweight)
3660ef72598Sjeremylt
3670ef72598Sjeremylt    # Interpolate function to quadrature points
3680ef72598Sjeremylt    for i in range(P):
3690ef72598Sjeremylt        in_array[i] = feval(xr[0 * P + i], xr[1 * P + i])
3700ef72598Sjeremylt
3710ef72598Sjeremylt    in_vec = ceed.Vector(P)
3720ef72598Sjeremylt    in_vec.set_array(in_array, cmode=libceed.USE_POINTER)
3730ef72598Sjeremylt    out_vec = ceed.Vector(Q * dim)
3740ef72598Sjeremylt    out_vec.set_value(0)
3750ef72598Sjeremylt
3760ef72598Sjeremylt    b.apply(1, libceed.EVAL_GRAD, in_vec, out_vec)
3770ef72598Sjeremylt
3780ef72598Sjeremylt    # Check values at quadrature points
3790ef72598Sjeremylt    with out_vec.array_read() as out_array:
3800ef72598Sjeremylt        for i in range(Q):
3810ef72598Sjeremylt            value = dfeval(xq[0 * Q + i], xq[1 * Q + i])
38280a9ef05SNatalie Beams            assert math.fabs(out_array[0 * Q + i] - value) < 10. * TOL
3830ef72598Sjeremylt
3840ef72598Sjeremylt            value = dfeval(xq[1 * Q + i], xq[0 * Q + i])
38580a9ef05SNatalie Beams            assert math.fabs(out_array[1 * Q + i] - value) < 10. * TOL
3860ef72598Sjeremylt
3870ef72598Sjeremylt# -------------------------------------------------------------------------------
388