xref: /libCEED/python/tests/test-3-basis.py (revision 673160d747a9093c09c5196095b9e3a2083e30dd)
10ef72598Sjeremylt# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
20ef72598Sjeremylt# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
30ef72598Sjeremylt# reserved. See files LICENSE and NOTICE for details.
40ef72598Sjeremylt#
50ef72598Sjeremylt# This file is part of CEED, a collection of benchmarks, miniapps, software
60ef72598Sjeremylt# libraries and APIs for efficient high-order finite element and spectral
70ef72598Sjeremylt# element discretizations for exascale applications. For more information and
80ef72598Sjeremylt# source code availability see http://github.com/ceed.
90ef72598Sjeremylt#
100ef72598Sjeremylt# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
110ef72598Sjeremylt# a collaborative effort of two U.S. Department of Energy organizations (Office
120ef72598Sjeremylt# of Science and the National Nuclear Security Administration) responsible for
130ef72598Sjeremylt# the planning and preparation of a capable exascale ecosystem, including
140ef72598Sjeremylt# software, applications, hardware, advanced system engineering and early
150ef72598Sjeremylt# testbed platforms, in support of the nation's exascale computing imperative.
160ef72598Sjeremylt
170ef72598Sjeremylt# @file
180ef72598Sjeremylt# Test Ceed Basis functionality
190ef72598Sjeremylt
200ef72598Sjeremyltimport os
210ef72598Sjeremyltimport math
220ef72598Sjeremyltimport libceed
230ef72598Sjeremyltimport numpy as np
240ef72598Sjeremyltimport buildmats as bm
250ef72598Sjeremyltimport check
260ef72598Sjeremylt
270ef72598SjeremyltTOL = np.finfo(float).eps * 256
280ef72598Sjeremylt
290ef72598Sjeremylt# -------------------------------------------------------------------------------
300ef72598Sjeremylt# Utilities
310ef72598Sjeremylt# -------------------------------------------------------------------------------
320ef72598Sjeremylt
330ef72598Sjeremylt
340ef72598Sjeremyltdef eval(dim, x):
350ef72598Sjeremylt    result, center = 1, 0.1
360ef72598Sjeremylt    for d in range(dim):
370ef72598Sjeremylt        result *= math.tanh(x[d] - center)
380ef72598Sjeremylt        center += 0.1
390ef72598Sjeremylt    return result
400ef72598Sjeremylt
410ef72598Sjeremylt
420ef72598Sjeremyltdef feval(x1, x2):
430ef72598Sjeremylt    return x1 * x1 + x2 * x2 + x1 * x2 + 1
440ef72598Sjeremylt
450ef72598Sjeremylt
460ef72598Sjeremyltdef dfeval(x1, x2):
470ef72598Sjeremylt    return 2 * x1 + x2
480ef72598Sjeremylt
490ef72598Sjeremylt# -------------------------------------------------------------------------------
500ef72598Sjeremylt# Test creation and distruction of a H1Lagrange basis
510ef72598Sjeremylt# -------------------------------------------------------------------------------
520ef72598Sjeremylt
530ef72598Sjeremylt
540ef72598Sjeremyltdef test_300(ceed_resource, capsys):
550ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
560ef72598Sjeremylt
570ef72598Sjeremylt    b = ceed.BasisTensorH1Lagrange(1, 1, 4, 4, libceed.GAUSS_LOBATTO)
580ef72598Sjeremylt    print(b)
590ef72598Sjeremylt    del b
600ef72598Sjeremylt
610ef72598Sjeremylt    b = ceed.BasisTensorH1Lagrange(1, 1, 4, 4, libceed.GAUSS)
620ef72598Sjeremylt    print(b)
630ef72598Sjeremylt    del b
640ef72598Sjeremylt
650ef72598Sjeremylt    stdout, stderr, ref_stdout = check.output(capsys)
660ef72598Sjeremylt    assert not stderr
670ef72598Sjeremylt    assert stdout == ref_stdout
680ef72598Sjeremylt
690ef72598Sjeremylt# -------------------------------------------------------------------------------
700ef72598Sjeremylt# Test QR factorization
710ef72598Sjeremylt# -------------------------------------------------------------------------------
720ef72598Sjeremylt
730ef72598Sjeremylt
740ef72598Sjeremyltdef test_301(ceed_resource, capsys):
750ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
760ef72598Sjeremylt
770ef72598Sjeremylt    qr = np.array([1, -1, 4, 1, 4, -2, 1, 4, 2, 1, -1, 0], dtype="float64")
780ef72598Sjeremylt    tau = np.empty(3, dtype="float64")
790ef72598Sjeremylt
800ef72598Sjeremylt    qr, tau = ceed.qr_factorization(qr, tau, 4, 3)
810ef72598Sjeremylt
820ef72598Sjeremylt    for i in range(len(qr)):
830ef72598Sjeremylt        if qr[i] <= TOL and qr[i] >= -TOL:
840ef72598Sjeremylt            qr[i] = 0
850ef72598Sjeremylt        print("%12.8f" % qr[i])
860ef72598Sjeremylt
870ef72598Sjeremylt    for i in range(len(tau)):
880ef72598Sjeremylt        if tau[i] <= TOL and tau[i] >= -TOL:
890ef72598Sjeremylt            tau[i] = 0
900ef72598Sjeremylt        print("%12.8f" % tau[i])
910ef72598Sjeremylt
920ef72598Sjeremylt    stdout, stderr, ref_stdout = check.output(capsys)
930ef72598Sjeremylt    assert not stderr
940ef72598Sjeremylt    assert stdout == ref_stdout
950ef72598Sjeremylt
960ef72598Sjeremylt# -------------------------------------------------------------------------------
970ef72598Sjeremylt# Test Symmetric Schur Decomposition
980ef72598Sjeremylt# -------------------------------------------------------------------------------
990ef72598Sjeremylt
1000ef72598Sjeremylt
1010ef72598Sjeremyltdef test_304(ceed_resource, capsys):
1020ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1030ef72598Sjeremylt
104*673160d7Sjeremylt    A = np.array([0.2, 0.0745355993, -0.0745355993, 0.0333333333,
105*673160d7Sjeremylt                  0.0745355993, 1., 0.1666666667, -0.0745355993,
106*673160d7Sjeremylt                  -0.0745355993, 0.1666666667, 1., 0.0745355993,
107*673160d7Sjeremylt                  0.0333333333, -0.0745355993, 0.0745355993, 0.2], dtype="float64")
1080ef72598Sjeremylt
109*673160d7Sjeremylt    Q = A.copy()
1100ef72598Sjeremylt
111*673160d7Sjeremylt    lam = ceed.symmetric_schur_decomposition(Q, 4)
112*673160d7Sjeremylt    Q = Q.reshape(4, 4)
113*673160d7Sjeremylt    lam = np.diag(lam)
1140ef72598Sjeremylt
115*673160d7Sjeremylt    Q_lambda_Qt = np.matmul(np.matmul(Q, lam), Q.T)
116*673160d7Sjeremylt    assert np.max(Q_lambda_Qt - A.reshape(4, 4)) < 1E-14
1170ef72598Sjeremylt
1180ef72598Sjeremylt# -------------------------------------------------------------------------------
1190ef72598Sjeremylt# Test Simultaneous Diagonalization
1200ef72598Sjeremylt# -------------------------------------------------------------------------------
1210ef72598Sjeremylt
1220ef72598Sjeremylt
1230ef72598Sjeremyltdef test_305(ceed_resource, capsys):
1240ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1250ef72598Sjeremylt
126*673160d7Sjeremylt    M = np.array([0.2, 0.0745355993, -0.0745355993, 0.0333333333,
127*673160d7Sjeremylt                  0.0745355993, 1., 0.1666666667, -0.0745355993,
128*673160d7Sjeremylt                  -0.0745355993, 0.1666666667, 1., 0.0745355993,
129*673160d7Sjeremylt                  0.0333333333, -0.0745355993, 0.0745355993, 0.2], dtype="float64")
130*673160d7Sjeremylt    K = np.array([3.0333333333, -3.4148928136, 0.4982261470, -0.1166666667,
131*673160d7Sjeremylt                  -3.4148928136, 5.8333333333, -2.9166666667, 0.4982261470,
132*673160d7Sjeremylt                  0.4982261470, -2.9166666667, 5.8333333333, -3.4148928136,
133*673160d7Sjeremylt                  -0.1166666667, 0.4982261470, -3.4148928136, 3.0333333333], dtype="float64")
1340ef72598Sjeremylt
135*673160d7Sjeremylt    X, lam = ceed.simultaneous_diagonalization(K, M, 4)
136*673160d7Sjeremylt    X = X.reshape(4, 4)
137*673160d7Sjeremylt    np.diag(lam)
1380ef72598Sjeremylt
139*673160d7Sjeremylt    M = M.reshape(4, 4)
140*673160d7Sjeremylt    K = K.reshape(4, 4)
1410ef72598Sjeremylt
142*673160d7Sjeremylt    Xt_M_X = np.matmul(X.T, np.matmul(M, X))
143*673160d7Sjeremylt    assert np.max(Xt_M_X - np.identity(4)) < 1E-14
1440ef72598Sjeremylt
145*673160d7Sjeremylt    Xt_K_X = np.matmul(X.T, np.matmul(K, X))
146*673160d7Sjeremylt    assert np.max(Xt_K_X - lam) < 1E-14
1470ef72598Sjeremylt
1480ef72598Sjeremylt# -------------------------------------------------------------------------------
1490ef72598Sjeremylt# Test GetNumNodes and GetNumQuadraturePoints for basis
1500ef72598Sjeremylt# -------------------------------------------------------------------------------
1510ef72598Sjeremylt
1520ef72598Sjeremylt
1530ef72598Sjeremyltdef test_306(ceed_resource):
1540ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1550ef72598Sjeremylt
1560ef72598Sjeremylt    b = ceed.BasisTensorH1Lagrange(3, 1, 4, 5, libceed.GAUSS_LOBATTO)
1570ef72598Sjeremylt
1580ef72598Sjeremylt    p = b.get_num_nodes()
1590ef72598Sjeremylt    q = b.get_num_quadrature_points()
1600ef72598Sjeremylt
1610ef72598Sjeremylt    assert p == 64
1620ef72598Sjeremylt    assert q == 125
1630ef72598Sjeremylt
1640ef72598Sjeremylt# -------------------------------------------------------------------------------
1650ef72598Sjeremylt# Test interpolation in multiple dimensions
1660ef72598Sjeremylt# -------------------------------------------------------------------------------
1670ef72598Sjeremylt
1680ef72598Sjeremylt
1690ef72598Sjeremyltdef test_313(ceed_resource):
1700ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1710ef72598Sjeremylt
1720ef72598Sjeremylt    for dim in range(1, 4):
1730ef72598Sjeremylt        Q = 10
1740ef72598Sjeremylt        Qdim = Q**dim
1750ef72598Sjeremylt        Xdim = 2**dim
1760ef72598Sjeremylt        x = np.empty(Xdim * dim, dtype="float64")
1770ef72598Sjeremylt        uq = np.empty(Qdim, dtype="float64")
1780ef72598Sjeremylt
1790ef72598Sjeremylt        for d in range(dim):
1800ef72598Sjeremylt            for i in range(Xdim):
1810ef72598Sjeremylt                x[d * Xdim + i] = 1 if (i %
1820ef72598Sjeremylt                                        (2**(dim - d))) // (2**(dim - d - 1)) else -1
1830ef72598Sjeremylt
1840ef72598Sjeremylt        X = ceed.Vector(Xdim * dim)
1850ef72598Sjeremylt        X.set_array(x, cmode=libceed.USE_POINTER)
1860ef72598Sjeremylt        Xq = ceed.Vector(Qdim * dim)
1870ef72598Sjeremylt        Xq.set_value(0)
1880ef72598Sjeremylt        U = ceed.Vector(Qdim)
1890ef72598Sjeremylt        U.set_value(0)
1900ef72598Sjeremylt        Uq = ceed.Vector(Qdim)
1910ef72598Sjeremylt
1920ef72598Sjeremylt        bxl = ceed.BasisTensorH1Lagrange(dim, dim, 2, Q, libceed.GAUSS_LOBATTO)
1930ef72598Sjeremylt        bul = ceed.BasisTensorH1Lagrange(dim, 1, Q, Q, libceed.GAUSS_LOBATTO)
1940ef72598Sjeremylt
1950ef72598Sjeremylt        bxl.apply(1, libceed.EVAL_INTERP, X, Xq)
1960ef72598Sjeremylt
1970ef72598Sjeremylt        with Xq.array_read() as xq:
1980ef72598Sjeremylt            for i in range(Qdim):
1990ef72598Sjeremylt                xx = np.empty(dim, dtype="float64")
2000ef72598Sjeremylt                for d in range(dim):
2010ef72598Sjeremylt                    xx[d] = xq[d * Qdim + i]
2020ef72598Sjeremylt                uq[i] = eval(dim, xx)
2030ef72598Sjeremylt
2040ef72598Sjeremylt        Uq.set_array(uq, cmode=libceed.USE_POINTER)
2050ef72598Sjeremylt
2060ef72598Sjeremylt        # This operation is the identity because the quadrature is collocated
2070ef72598Sjeremylt        bul.T.apply(1, libceed.EVAL_INTERP, Uq, U)
2080ef72598Sjeremylt
2090ef72598Sjeremylt        bxg = ceed.BasisTensorH1Lagrange(dim, dim, 2, Q, libceed.GAUSS)
2100ef72598Sjeremylt        bug = ceed.BasisTensorH1Lagrange(dim, 1, Q, Q, libceed.GAUSS)
2110ef72598Sjeremylt
2120ef72598Sjeremylt        bxg.apply(1, libceed.EVAL_INTERP, X, Xq)
2130ef72598Sjeremylt        bug.apply(1, libceed.EVAL_INTERP, U, Uq)
2140ef72598Sjeremylt
2150ef72598Sjeremylt        with Xq.array_read() as xq, Uq.array_read() as u:
2160ef72598Sjeremylt            for i in range(Qdim):
2170ef72598Sjeremylt                xx = np.empty(dim, dtype="float64")
2180ef72598Sjeremylt                for d in range(dim):
2190ef72598Sjeremylt                    xx[d] = xq[d * Qdim + i]
2200ef72598Sjeremylt                fx = eval(dim, xx)
2210ef72598Sjeremylt                assert math.fabs(u[i] - fx) < 1E-4
2220ef72598Sjeremylt
2230ef72598Sjeremylt# -------------------------------------------------------------------------------
2240ef72598Sjeremylt# Test grad in multiple dimensions
2250ef72598Sjeremylt# -------------------------------------------------------------------------------
2260ef72598Sjeremylt
2270ef72598Sjeremylt
2280ef72598Sjeremyltdef test_314(ceed_resource):
2290ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
2300ef72598Sjeremylt
2310ef72598Sjeremylt    for dim in range(1, 4):
2320ef72598Sjeremylt        P, Q = 8, 10
2330ef72598Sjeremylt        Pdim = P**dim
2340ef72598Sjeremylt        Qdim = Q**dim
2350ef72598Sjeremylt        Xdim = 2**dim
2360ef72598Sjeremylt        sum1 = sum2 = 0
2370ef72598Sjeremylt        x = np.empty(Xdim * dim, dtype="float64")
2380ef72598Sjeremylt        u = np.empty(Pdim, dtype="float64")
2390ef72598Sjeremylt
2400ef72598Sjeremylt        for d in range(dim):
2410ef72598Sjeremylt            for i in range(Xdim):
2420ef72598Sjeremylt                x[d * Xdim + i] = 1 if (i %
2430ef72598Sjeremylt                                        (2**(dim - d))) // (2**(dim - d - 1)) else -1
2440ef72598Sjeremylt
2450ef72598Sjeremylt        X = ceed.Vector(Xdim * dim)
2460ef72598Sjeremylt        X.set_array(x, cmode=libceed.USE_POINTER)
2470ef72598Sjeremylt        Xq = ceed.Vector(Pdim * dim)
2480ef72598Sjeremylt        Xq.set_value(0)
2490ef72598Sjeremylt        U = ceed.Vector(Pdim)
2500ef72598Sjeremylt        Uq = ceed.Vector(Qdim * dim)
2510ef72598Sjeremylt        Uq.set_value(0)
2520ef72598Sjeremylt        Ones = ceed.Vector(Qdim * dim)
2530ef72598Sjeremylt        Ones.set_value(1)
2540ef72598Sjeremylt        Gtposeones = ceed.Vector(Pdim)
2550ef72598Sjeremylt        Gtposeones.set_value(0)
2560ef72598Sjeremylt
2570ef72598Sjeremylt        # Get function values at quadrature points
2580ef72598Sjeremylt        bxl = ceed.BasisTensorH1Lagrange(dim, dim, 2, P, libceed.GAUSS_LOBATTO)
2590ef72598Sjeremylt        bxl.apply(1, libceed.EVAL_INTERP, X, Xq)
2600ef72598Sjeremylt
2610ef72598Sjeremylt        with Xq.array_read() as xq:
2620ef72598Sjeremylt            for i in range(Pdim):
2630ef72598Sjeremylt                xx = np.empty(dim, dtype="float64")
2640ef72598Sjeremylt                for d in range(dim):
2650ef72598Sjeremylt                    xx[d] = xq[d * Pdim + i]
2660ef72598Sjeremylt                u[i] = eval(dim, xx)
2670ef72598Sjeremylt
2680ef72598Sjeremylt        U.set_array(u, cmode=libceed.USE_POINTER)
2690ef72598Sjeremylt
2700ef72598Sjeremylt        # Calculate G u at quadrature points, G' * 1 at dofs
2710ef72598Sjeremylt        bug = ceed.BasisTensorH1Lagrange(dim, 1, P, Q, libceed.GAUSS)
2720ef72598Sjeremylt        bug.apply(1, libceed.EVAL_GRAD, U, Uq)
2730ef72598Sjeremylt        bug.T.apply(1, libceed.EVAL_GRAD, Ones, Gtposeones)
2740ef72598Sjeremylt
2750ef72598Sjeremylt        # Check if 1' * G * u = u' * (G' * 1)
2760ef72598Sjeremylt        with Gtposeones.array_read() as gtposeones, Uq.array_read() as uq:
2770ef72598Sjeremylt            for i in range(Pdim):
2780ef72598Sjeremylt                sum1 += gtposeones[i] * u[i]
2790ef72598Sjeremylt            for i in range(dim * Qdim):
2800ef72598Sjeremylt                sum2 += uq[i]
2810ef72598Sjeremylt
2820ef72598Sjeremylt        assert math.fabs(sum1 - sum2) < 1E-10
2830ef72598Sjeremylt
2840ef72598Sjeremylt# -------------------------------------------------------------------------------
2850ef72598Sjeremylt# Test creation and destruction of a 2D Simplex non-tensor H1 basis
2860ef72598Sjeremylt# -------------------------------------------------------------------------------
2870ef72598Sjeremylt
2880ef72598Sjeremylt
2890ef72598Sjeremyltdef test_320(ceed_resource):
2900ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
2910ef72598Sjeremylt
2920ef72598Sjeremylt    P, Q, dim = 6, 4, 2
2930ef72598Sjeremylt
2940ef72598Sjeremylt    in_array = np.empty(P, dtype="float64")
2950ef72598Sjeremylt    qref = np.empty(dim * Q, dtype="float64")
2960ef72598Sjeremylt    qweight = np.empty(Q, dtype="float64")
2970ef72598Sjeremylt
2980ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
2990ef72598Sjeremylt
3000ef72598Sjeremylt    b = ceed.BasisH1(libceed.TRIANGLE, 1, P, Q, interp, grad, qref, qweight)
3010ef72598Sjeremylt
3020ef72598Sjeremylt    print(b)
3030ef72598Sjeremylt    del b
3040ef72598Sjeremylt
3050ef72598Sjeremylt# -------------------------------------------------------------------------------
3060ef72598Sjeremylt# Test integration with a 2D Simplex non-tensor H1 basis
3070ef72598Sjeremylt# -------------------------------------------------------------------------------
3080ef72598Sjeremylt
3090ef72598Sjeremylt
3100ef72598Sjeremyltdef test_322(ceed_resource):
3110ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
3120ef72598Sjeremylt
3130ef72598Sjeremylt    P, Q, dim = 6, 4, 2
3140ef72598Sjeremylt
3150ef72598Sjeremylt    xr = np.array([0., 0.5, 1., 0., 0.5, 0., 0., 0.,
3160ef72598Sjeremylt                   0., 0.5, 0.5, 1.], dtype="float64")
3170ef72598Sjeremylt    in_array = np.empty(P, dtype="float64")
3180ef72598Sjeremylt    qref = np.empty(dim * Q, dtype="float64")
3190ef72598Sjeremylt    qweight = np.empty(Q, dtype="float64")
3200ef72598Sjeremylt
3210ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
3220ef72598Sjeremylt
3230ef72598Sjeremylt    b = ceed.BasisH1(libceed.TRIANGLE, 1, P, Q, interp, grad, qref, qweight)
3240ef72598Sjeremylt
3250ef72598Sjeremylt    # Interpolate function to quadrature points
3260ef72598Sjeremylt    for i in range(P):
3270ef72598Sjeremylt        in_array[i] = feval(xr[0 * P + i], xr[1 * P + i])
3280ef72598Sjeremylt
3290ef72598Sjeremylt    in_vec = ceed.Vector(P)
3300ef72598Sjeremylt    in_vec.set_array(in_array, cmode=libceed.USE_POINTER)
3310ef72598Sjeremylt    out_vec = ceed.Vector(Q)
3320ef72598Sjeremylt    out_vec.set_value(0)
3330ef72598Sjeremylt    weights_vec = ceed.Vector(Q)
3340ef72598Sjeremylt    weights_vec.set_value(0)
3350ef72598Sjeremylt
3360ef72598Sjeremylt    b.apply(1, libceed.EVAL_INTERP, in_vec, out_vec)
3370ef72598Sjeremylt    b.apply(1, libceed.EVAL_WEIGHT, libceed.VECTOR_NONE, weights_vec)
3380ef72598Sjeremylt
3390ef72598Sjeremylt    # Check values at quadrature points
3400ef72598Sjeremylt    with out_vec.array_read() as out_array, weights_vec.array_read() as weights_array:
3410ef72598Sjeremylt        sum = 0
3420ef72598Sjeremylt        for i in range(Q):
3430ef72598Sjeremylt            sum += out_array[i] * weights_array[i]
3440ef72598Sjeremylt        assert math.fabs(sum - 17. / 24.) < 1E-10
3450ef72598Sjeremylt
3460ef72598Sjeremylt# -------------------------------------------------------------------------------
3470ef72598Sjeremylt# Test grad with a 2D Simplex non-tensor H1 basis
3480ef72598Sjeremylt# -------------------------------------------------------------------------------
3490ef72598Sjeremylt
3500ef72598Sjeremylt
3510ef72598Sjeremyltdef test_323(ceed_resource):
3520ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
3530ef72598Sjeremylt
3540ef72598Sjeremylt    P, Q, dim = 6, 4, 2
3550ef72598Sjeremylt
3560ef72598Sjeremylt    xq = np.array([0.2, 0.6, 1. / 3., 0.2, 0.2, 0.2,
3570ef72598Sjeremylt                   1. / 3., 0.6], dtype="float64")
3580ef72598Sjeremylt    xr = np.array([0., 0.5, 1., 0., 0.5, 0., 0., 0.,
3590ef72598Sjeremylt                   0., 0.5, 0.5, 1.], dtype="float64")
3600ef72598Sjeremylt    in_array = np.empty(P, dtype="float64")
3610ef72598Sjeremylt    qref = np.empty(dim * Q, dtype="float64")
3620ef72598Sjeremylt    qweight = np.empty(Q, dtype="float64")
3630ef72598Sjeremylt
3640ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
3650ef72598Sjeremylt
3660ef72598Sjeremylt    b = ceed.BasisH1(libceed.TRIANGLE, 1, P, Q, interp, grad, qref, qweight)
3670ef72598Sjeremylt
3680ef72598Sjeremylt    # Interpolate function to quadrature points
3690ef72598Sjeremylt    for i in range(P):
3700ef72598Sjeremylt        in_array[i] = feval(xr[0 * P + i], xr[1 * P + i])
3710ef72598Sjeremylt
3720ef72598Sjeremylt    in_vec = ceed.Vector(P)
3730ef72598Sjeremylt    in_vec.set_array(in_array, cmode=libceed.USE_POINTER)
3740ef72598Sjeremylt    out_vec = ceed.Vector(Q * dim)
3750ef72598Sjeremylt    out_vec.set_value(0)
3760ef72598Sjeremylt
3770ef72598Sjeremylt    b.apply(1, libceed.EVAL_GRAD, in_vec, out_vec)
3780ef72598Sjeremylt
3790ef72598Sjeremylt    # Check values at quadrature points
3800ef72598Sjeremylt    with out_vec.array_read() as out_array:
3810ef72598Sjeremylt        for i in range(Q):
3820ef72598Sjeremylt            value = dfeval(xq[0 * Q + i], xq[1 * Q + i])
3830ef72598Sjeremylt            assert math.fabs(out_array[0 * Q + i] - value) < 1E-10
3840ef72598Sjeremylt
3850ef72598Sjeremylt            value = dfeval(xq[1 * Q + i], xq[0 * Q + i])
3860ef72598Sjeremylt            assert math.fabs(out_array[1 * Q + i] - value) < 1E-10
3870ef72598Sjeremylt
3880ef72598Sjeremylt# -------------------------------------------------------------------------------
389