xref: /libCEED/python/tests/test-5-operator.py (revision 28d09c206720ba8516c835daf824672e3380cdbd)
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 Operator functionality
190ef72598Sjeremylt
200ef72598Sjeremyltimport os
210ef72598Sjeremyltimport libceed
220ef72598Sjeremyltimport numpy as np
230ef72598Sjeremyltimport check
240ef72598Sjeremyltimport buildmats as bm
250ef72598Sjeremylt
2680a9ef05SNatalie BeamsTOL = libceed.EPSILON * 256
270ef72598Sjeremylt
280ef72598Sjeremylt# -------------------------------------------------------------------------------
290ef72598Sjeremylt# Utility
300ef72598Sjeremylt# -------------------------------------------------------------------------------
310ef72598Sjeremylt
320ef72598Sjeremylt
330ef72598Sjeremyltdef load_qfs_so():
340ef72598Sjeremylt    from distutils.sysconfig import get_config_var
350ef72598Sjeremylt    import ctypes
360ef72598Sjeremylt
370ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
380ef72598Sjeremylt    qfs_so = os.path.join(
390ef72598Sjeremylt        file_dir,
400ef72598Sjeremylt        "libceed_qfunctions" + get_config_var("EXT_SUFFIX"))
410ef72598Sjeremylt
420ef72598Sjeremylt    # Load library
430ef72598Sjeremylt    return ctypes.cdll.LoadLibrary(qfs_so)
440ef72598Sjeremylt
450ef72598Sjeremylt# -------------------------------------------------------------------------------
460ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
470ef72598Sjeremylt# -------------------------------------------------------------------------------
480ef72598Sjeremylt
490ef72598Sjeremylt
500ef72598Sjeremyltdef test_500(ceed_resource):
510ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
520ef72598Sjeremylt
530ef72598Sjeremylt    nelem = 15
540ef72598Sjeremylt    p = 5
550ef72598Sjeremylt    q = 8
560ef72598Sjeremylt    nx = nelem + 1
570ef72598Sjeremylt    nu = nelem * (p - 1) + 1
580ef72598Sjeremylt
590ef72598Sjeremylt    # Vectors
600ef72598Sjeremylt    x = ceed.Vector(nx)
610ef72598Sjeremylt    x_array = np.zeros(nx)
620ef72598Sjeremylt    for i in range(nx):
630ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
640ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
650ef72598Sjeremylt
660ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
670ef72598Sjeremylt    u = ceed.Vector(nu)
680ef72598Sjeremylt    v = ceed.Vector(nu)
690ef72598Sjeremylt
700ef72598Sjeremylt    # Restrictions
710ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
720ef72598Sjeremylt    for i in range(nx):
730ef72598Sjeremylt        indx[2 * i + 0] = i
740ef72598Sjeremylt        indx[2 * i + 1] = i + 1
750ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
760ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
770ef72598Sjeremylt
780ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
790ef72598Sjeremylt    for i in range(nelem):
800ef72598Sjeremylt        for j in range(p):
810ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
820ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
830ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
840ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
850ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
860ef72598Sjeremylt
870ef72598Sjeremylt    # Bases
880ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
890ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
900ef72598Sjeremylt
910ef72598Sjeremylt    # QFunctions
920ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
930ef72598Sjeremylt    qfs = load_qfs_so()
940ef72598Sjeremylt
950ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
960ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
970ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
980ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
990ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
1000ef72598Sjeremylt
1010ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
1020ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1030ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
1040ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
1050ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
1060ef72598Sjeremylt
1070ef72598Sjeremylt    # Operators
1080ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
1090ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
1100ef72598Sjeremylt                       libceed.VECTOR_NONE)
1110ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
1120ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
1130ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
114*28d09c20SJeremy L Thompson    op_setup.check()
1150ef72598Sjeremylt
1160ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
1170ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
1180ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
1190ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
120*28d09c20SJeremy L Thompson    op_mass.check()
1210ef72598Sjeremylt
1220ef72598Sjeremylt    # Setup
1230ef72598Sjeremylt    op_setup.apply(x, qdata)
1240ef72598Sjeremylt
1250ef72598Sjeremylt    # Apply mass matrix
1260ef72598Sjeremylt    u.set_value(0)
1270ef72598Sjeremylt    op_mass.apply(u, v)
1280ef72598Sjeremylt
1290ef72598Sjeremylt    # Check
1300ef72598Sjeremylt    with v.array_read() as v_array:
1310ef72598Sjeremylt        for i in range(q):
1320ef72598Sjeremylt            assert abs(v_array[i]) < TOL
1330ef72598Sjeremylt
1340ef72598Sjeremylt# -------------------------------------------------------------------------------
1350ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
1360ef72598Sjeremylt# -------------------------------------------------------------------------------
1370ef72598Sjeremylt
1380ef72598Sjeremylt
1390ef72598Sjeremyltdef test_501(ceed_resource):
1400ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1410ef72598Sjeremylt
1420ef72598Sjeremylt    nelem = 15
1430ef72598Sjeremylt    p = 5
1440ef72598Sjeremylt    q = 8
1450ef72598Sjeremylt    nx = nelem + 1
1460ef72598Sjeremylt    nu = nelem * (p - 1) + 1
1470ef72598Sjeremylt
1480ef72598Sjeremylt    # Vectors
1490ef72598Sjeremylt    x = ceed.Vector(nx)
15080a9ef05SNatalie Beams    x_array = np.zeros(nx, dtype=ceed.scalar_type())
1510ef72598Sjeremylt    for i in range(nx):
1520ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
1530ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
1540ef72598Sjeremylt
1550ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
1560ef72598Sjeremylt    u = ceed.Vector(nu)
1570ef72598Sjeremylt    v = ceed.Vector(nu)
1580ef72598Sjeremylt
1590ef72598Sjeremylt    # Restrictions
1600ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
1610ef72598Sjeremylt    for i in range(nx):
1620ef72598Sjeremylt        indx[2 * i + 0] = i
1630ef72598Sjeremylt        indx[2 * i + 1] = i + 1
1640ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
1650ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
1660ef72598Sjeremylt
1670ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
1680ef72598Sjeremylt    for i in range(nelem):
1690ef72598Sjeremylt        for j in range(p):
1700ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
1710ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
1720ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
1730ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
1740ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
1750ef72598Sjeremylt
1760ef72598Sjeremylt    # Bases
1770ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
1780ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
1790ef72598Sjeremylt
1800ef72598Sjeremylt    # QFunctions
1810ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
1820ef72598Sjeremylt    qfs = load_qfs_so()
1830ef72598Sjeremylt
1840ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
1850ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
1860ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
1870ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
1880ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
1890ef72598Sjeremylt
1900ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
1910ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1920ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
1930ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
1940ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
1950ef72598Sjeremylt
1960ef72598Sjeremylt    # Operators
1970ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
1980ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
1990ef72598Sjeremylt                       libceed.VECTOR_NONE)
2000ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
2010ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
2020ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
2030ef72598Sjeremylt
2040ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
2050ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
2060ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
2070ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
2080ef72598Sjeremylt
2090ef72598Sjeremylt    # Setup
2100ef72598Sjeremylt    op_setup.apply(x, qdata)
2110ef72598Sjeremylt
2120ef72598Sjeremylt    # Apply mass matrix
2130ef72598Sjeremylt    u.set_value(1.)
2140ef72598Sjeremylt    op_mass.apply(u, v)
2150ef72598Sjeremylt
2160ef72598Sjeremylt    # Check
2170ef72598Sjeremylt    with v.array_read() as v_array:
2180ef72598Sjeremylt        total = 0.0
2190ef72598Sjeremylt        for i in range(nu):
2200ef72598Sjeremylt            total = total + v_array[i]
2210ef72598Sjeremylt        assert abs(total - 1.0) < TOL
2220ef72598Sjeremylt
2230ef72598Sjeremylt# -------------------------------------------------------------------------------
2240ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with multiple
2250ef72598Sjeremylt#   components
2260ef72598Sjeremylt# -------------------------------------------------------------------------------
2270ef72598Sjeremylt
2280ef72598Sjeremylt
2290ef72598Sjeremyltdef test_502(ceed_resource):
2300ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
2310ef72598Sjeremylt
2320ef72598Sjeremylt    nelem = 15
2330ef72598Sjeremylt    p = 5
2340ef72598Sjeremylt    q = 8
2350ef72598Sjeremylt    nx = nelem + 1
2360ef72598Sjeremylt    nu = nelem * (p - 1) + 1
2370ef72598Sjeremylt
2380ef72598Sjeremylt    # Vectors
2390ef72598Sjeremylt    x = ceed.Vector(nx)
24080a9ef05SNatalie Beams    x_array = np.zeros(nx, dtype=ceed.scalar_type())
2410ef72598Sjeremylt    for i in range(nx):
2420ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
2430ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
2440ef72598Sjeremylt
2450ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
2460ef72598Sjeremylt    u = ceed.Vector(2 * nu)
2470ef72598Sjeremylt    v = ceed.Vector(2 * nu)
2480ef72598Sjeremylt
2490ef72598Sjeremylt    # Restrictions
2500ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
2510ef72598Sjeremylt    for i in range(nx):
2520ef72598Sjeremylt        indx[2 * i + 0] = i
2530ef72598Sjeremylt        indx[2 * i + 1] = i + 1
2540ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
2550ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
2560ef72598Sjeremylt
2570ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
2580ef72598Sjeremylt    for i in range(nelem):
2590ef72598Sjeremylt        for j in range(p):
2600ef72598Sjeremylt            indu[p * i + j] = 2 * (i * (p - 1) + j)
2610ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 2, 1, 2 * nu, indu,
2620ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
2630ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
2640ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
2650ef72598Sjeremylt
2660ef72598Sjeremylt    # Bases
2670ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
2680ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 2, p, q, libceed.GAUSS)
2690ef72598Sjeremylt
2700ef72598Sjeremylt    # QFunctions
2710ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
2720ef72598Sjeremylt    qfs = load_qfs_so()
2730ef72598Sjeremylt
2740ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
2750ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
2760ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
2770ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
2780ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
2790ef72598Sjeremylt
2800ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass_two,
2810ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass_two"))
2820ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
2830ef72598Sjeremylt    qf_mass.add_input("u", 2, libceed.EVAL_INTERP)
2840ef72598Sjeremylt    qf_mass.add_output("v", 2, libceed.EVAL_INTERP)
2850ef72598Sjeremylt
2860ef72598Sjeremylt    # Operators
2870ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
2880ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
2890ef72598Sjeremylt                       libceed.VECTOR_NONE)
2900ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
2910ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
2920ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
2930ef72598Sjeremylt
2940ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
2950ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
2960ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
2970ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
2980ef72598Sjeremylt
2990ef72598Sjeremylt    # Setup
3000ef72598Sjeremylt    op_setup.apply(x, qdata)
3010ef72598Sjeremylt
3020ef72598Sjeremylt    # Apply mass matrix
3030ef72598Sjeremylt    with u.array() as u_array:
3040ef72598Sjeremylt        for i in range(nu):
3050ef72598Sjeremylt            u_array[2 * i] = 1.
3060ef72598Sjeremylt            u_array[2 * i + 1] = 2.
3070ef72598Sjeremylt    op_mass.apply(u, v)
3080ef72598Sjeremylt
3090ef72598Sjeremylt    # Check
3100ef72598Sjeremylt    with v.array_read() as v_array:
3110ef72598Sjeremylt        total_1 = 0.0
3120ef72598Sjeremylt        total_2 = 0.0
3130ef72598Sjeremylt        for i in range(nu):
3140ef72598Sjeremylt            total_1 = total_1 + v_array[2 * i]
3150ef72598Sjeremylt            total_2 = total_2 + v_array[2 * i + 1]
31680a9ef05SNatalie Beams        assert abs(total_1 - 1.0) < TOL
31780a9ef05SNatalie Beams        assert abs(total_2 - 2.0) < TOL
3180ef72598Sjeremylt
3190ef72598Sjeremylt# -------------------------------------------------------------------------------
3200ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with passive
3210ef72598Sjeremylt#   inputs and outputs
3220ef72598Sjeremylt# -------------------------------------------------------------------------------
3230ef72598Sjeremylt
3240ef72598Sjeremylt
3250ef72598Sjeremyltdef test_503(ceed_resource):
3260ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
3270ef72598Sjeremylt
3280ef72598Sjeremylt    nelem = 15
3290ef72598Sjeremylt    p = 5
3300ef72598Sjeremylt    q = 8
3310ef72598Sjeremylt    nx = nelem + 1
3320ef72598Sjeremylt    nu = nelem * (p - 1) + 1
3330ef72598Sjeremylt
3340ef72598Sjeremylt    # Vectors
3350ef72598Sjeremylt    x = ceed.Vector(nx)
33680a9ef05SNatalie Beams    x_array = np.zeros(nx, dtype=ceed.scalar_type())
3370ef72598Sjeremylt    for i in range(nx):
3380ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
3390ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
3400ef72598Sjeremylt
3410ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
3420ef72598Sjeremylt    u = ceed.Vector(nu)
3430ef72598Sjeremylt    v = ceed.Vector(nu)
3440ef72598Sjeremylt
3450ef72598Sjeremylt    # Restrictions
3460ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
3470ef72598Sjeremylt    for i in range(nx):
3480ef72598Sjeremylt        indx[2 * i + 0] = i
3490ef72598Sjeremylt        indx[2 * i + 1] = i + 1
3500ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
3510ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
3520ef72598Sjeremylt
3530ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
3540ef72598Sjeremylt    for i in range(nelem):
3550ef72598Sjeremylt        for j in range(p):
3560ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
3570ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
3580ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
3590ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
3600ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
3610ef72598Sjeremylt
3620ef72598Sjeremylt    # Bases
3630ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
3640ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
3650ef72598Sjeremylt
3660ef72598Sjeremylt    # QFunctions
3670ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
3680ef72598Sjeremylt    qfs = load_qfs_so()
3690ef72598Sjeremylt
3700ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
3710ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
3720ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
3730ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
3740ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
3750ef72598Sjeremylt
3760ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
3770ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
3780ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
3790ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
3800ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
3810ef72598Sjeremylt
3820ef72598Sjeremylt    # Operators
3830ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
3840ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
3850ef72598Sjeremylt                       libceed.VECTOR_NONE)
3860ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
3870ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
3880ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
3890ef72598Sjeremylt
3900ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
3910ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
3920ef72598Sjeremylt    op_mass.set_field("u", ru, bu, u)
3930ef72598Sjeremylt    op_mass.set_field("v", ru, bu, v)
3940ef72598Sjeremylt
3950ef72598Sjeremylt    # Setup
3960ef72598Sjeremylt    op_setup.apply(x, qdata)
3970ef72598Sjeremylt
3980ef72598Sjeremylt    # Apply mass matrix
3990ef72598Sjeremylt    u.set_value(1)
4000ef72598Sjeremylt    op_mass.apply(libceed.VECTOR_NONE, libceed.VECTOR_NONE)
4010ef72598Sjeremylt
4020ef72598Sjeremylt    # Check
4030ef72598Sjeremylt    with v.array_read() as v_array:
4040ef72598Sjeremylt        total = 0.0
4050ef72598Sjeremylt        for i in range(nu):
4060ef72598Sjeremylt            total = total + v_array[i]
40780a9ef05SNatalie Beams        assert abs(total - 1.0) < TOL
4080ef72598Sjeremylt
4090ef72598Sjeremylt# -------------------------------------------------------------------------------
4100ef72598Sjeremylt# Test viewing of mass matrix operator
4110ef72598Sjeremylt# -------------------------------------------------------------------------------
4120ef72598Sjeremylt
4130ef72598Sjeremylt
4140ef72598Sjeremyltdef test_504(ceed_resource, capsys):
4150ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
4160ef72598Sjeremylt
4170ef72598Sjeremylt    nelem = 15
4180ef72598Sjeremylt    p = 5
4190ef72598Sjeremylt    q = 8
4200ef72598Sjeremylt    nx = nelem + 1
4210ef72598Sjeremylt    nu = nelem * (p - 1) + 1
4220ef72598Sjeremylt
4230ef72598Sjeremylt    # Vectors
4240ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
4250ef72598Sjeremylt
4260ef72598Sjeremylt    # Restrictions
4270ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
4280ef72598Sjeremylt    for i in range(nx):
4290ef72598Sjeremylt        indx[2 * i + 0] = i
4300ef72598Sjeremylt        indx[2 * i + 1] = i + 1
4310ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
4320ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
4330ef72598Sjeremylt
4340ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
4350ef72598Sjeremylt    for i in range(nelem):
4360ef72598Sjeremylt        for j in range(p):
4370ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
4380ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
4390ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
4400ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
4410ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
4420ef72598Sjeremylt
4430ef72598Sjeremylt    # Bases
4440ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
4450ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
4460ef72598Sjeremylt
4470ef72598Sjeremylt    # QFunctions
4480ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
4490ef72598Sjeremylt    qfs = load_qfs_so()
4500ef72598Sjeremylt
4510ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
4520ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
4530ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
4540ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
4550ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
4560ef72598Sjeremylt
4570ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
4580ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
4590ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
4600ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
4610ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
4620ef72598Sjeremylt
4630ef72598Sjeremylt    # Operators
4640ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
4650ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
4660ef72598Sjeremylt                       libceed.VECTOR_NONE)
4670ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
4680ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
4690ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
4700ef72598Sjeremylt
4710ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
4720ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
4730ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
4740ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
4750ef72598Sjeremylt
4760ef72598Sjeremylt    # View
4770ef72598Sjeremylt    print(op_setup)
4780ef72598Sjeremylt    print(op_mass)
4790ef72598Sjeremylt
4800ef72598Sjeremylt    stdout, stderr, ref_stdout = check.output(capsys)
4810ef72598Sjeremylt    assert not stderr
4820ef72598Sjeremylt    assert stdout == ref_stdout
4830ef72598Sjeremylt
4840ef72598Sjeremylt# -------------------------------------------------------------------------------
4850ef72598Sjeremylt# Test CeedOperatorApplyAdd
4860ef72598Sjeremylt# -------------------------------------------------------------------------------
4870ef72598Sjeremylt
4880ef72598Sjeremylt
4890ef72598Sjeremyltdef test_505(ceed_resource):
4900ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
4910ef72598Sjeremylt
4920ef72598Sjeremylt    nelem = 15
4930ef72598Sjeremylt    p = 5
4940ef72598Sjeremylt    q = 8
4950ef72598Sjeremylt    nx = nelem + 1
4960ef72598Sjeremylt    nu = nelem * (p - 1) + 1
4970ef72598Sjeremylt
4980ef72598Sjeremylt    # Vectors
4990ef72598Sjeremylt    x = ceed.Vector(nx)
50080a9ef05SNatalie Beams    x_array = np.zeros(nx, dtype=ceed.scalar_type())
5010ef72598Sjeremylt    for i in range(nx):
5020ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
5030ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
5040ef72598Sjeremylt
5050ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
5060ef72598Sjeremylt    u = ceed.Vector(nu)
5070ef72598Sjeremylt    v = ceed.Vector(nu)
5080ef72598Sjeremylt
5090ef72598Sjeremylt    # Restrictions
5100ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
5110ef72598Sjeremylt    for i in range(nx):
5120ef72598Sjeremylt        indx[2 * i + 0] = i
5130ef72598Sjeremylt        indx[2 * i + 1] = i + 1
5140ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
5150ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
5160ef72598Sjeremylt
5170ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
5180ef72598Sjeremylt    for i in range(nelem):
5190ef72598Sjeremylt        for j in range(p):
5200ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
5210ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
5220ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
5230ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
5240ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
5250ef72598Sjeremylt
5260ef72598Sjeremylt    # Bases
5270ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
5280ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
5290ef72598Sjeremylt
5300ef72598Sjeremylt    # QFunctions
5310ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
5320ef72598Sjeremylt    qfs = load_qfs_so()
5330ef72598Sjeremylt
5340ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
5350ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
5360ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
5370ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
5380ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
5390ef72598Sjeremylt
5400ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
5410ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
5420ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
5430ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
5440ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
5450ef72598Sjeremylt
5460ef72598Sjeremylt    # Operators
5470ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
5480ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
5490ef72598Sjeremylt                       libceed.VECTOR_NONE)
5500ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
5510ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
5520ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
5530ef72598Sjeremylt
5540ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
5550ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
5560ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
5570ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
5580ef72598Sjeremylt
5590ef72598Sjeremylt    # Setup
5600ef72598Sjeremylt    op_setup.apply(x, qdata)
5610ef72598Sjeremylt
5620ef72598Sjeremylt    # Apply mass matrix with v = 0
5630ef72598Sjeremylt    u.set_value(1.)
5640ef72598Sjeremylt    v.set_value(0.)
5650ef72598Sjeremylt    op_mass.apply_add(u, v)
5660ef72598Sjeremylt
5670ef72598Sjeremylt    # Check
5680ef72598Sjeremylt    with v.array_read() as v_array:
5690ef72598Sjeremylt        total = 0.0
5700ef72598Sjeremylt        for i in range(nu):
5710ef72598Sjeremylt            total = total + v_array[i]
5720ef72598Sjeremylt        assert abs(total - 1.0) < TOL
5730ef72598Sjeremylt
5740ef72598Sjeremylt    # Apply mass matrix with v = 0
5750ef72598Sjeremylt    v.set_value(1.)
5760ef72598Sjeremylt    op_mass.apply_add(u, v)
5770ef72598Sjeremylt
5780ef72598Sjeremylt    # Check
5790ef72598Sjeremylt    with v.array_read() as v_array:
5800ef72598Sjeremylt        total = -nu
5810ef72598Sjeremylt        for i in range(nu):
5820ef72598Sjeremylt            total = total + v_array[i]
58380a9ef05SNatalie Beams        assert abs(total - 1.0) < 10. * TOL
5840ef72598Sjeremylt
5850ef72598Sjeremylt# -------------------------------------------------------------------------------
5860ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
5870ef72598Sjeremylt# -------------------------------------------------------------------------------
5880ef72598Sjeremylt
5890ef72598Sjeremylt
5900ef72598Sjeremyltdef test_510(ceed_resource):
5910ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
5920ef72598Sjeremylt
5930ef72598Sjeremylt    nelem = 12
5940ef72598Sjeremylt    dim = 2
5950ef72598Sjeremylt    p = 6
5960ef72598Sjeremylt    q = 4
5970ef72598Sjeremylt    nx, ny = 3, 2
5980ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
5990ef72598Sjeremylt    nqpts = nelem * q
6000ef72598Sjeremylt
6010ef72598Sjeremylt    # Vectors
6020ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
6030ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
6040ef72598Sjeremylt    for i in range(ndofs):
6050ef72598Sjeremylt        x_array[i] = (1. / (nx * 2)) * (i % (nx * 2 + 1))
6060ef72598Sjeremylt        x_array[i + ndofs] = (1. / (ny * 2)) * (i / (nx * 2 + 1))
6070ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
6080ef72598Sjeremylt
6090ef72598Sjeremylt    qdata = ceed.Vector(nqpts)
6100ef72598Sjeremylt    u = ceed.Vector(ndofs)
6110ef72598Sjeremylt    v = ceed.Vector(ndofs)
6120ef72598Sjeremylt
6130ef72598Sjeremylt    # Restrictions
6140ef72598Sjeremylt    indx = np.zeros(nelem * p, dtype="int32")
6150ef72598Sjeremylt    for i in range(nelem // 2):
6160ef72598Sjeremylt        col = i % nx
6170ef72598Sjeremylt        row = i // nx
6180ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
6190ef72598Sjeremylt
6200ef72598Sjeremylt        indx[i * 2 * p + 0] = 2 + offset
6210ef72598Sjeremylt        indx[i * 2 * p + 1] = 9 + offset
6220ef72598Sjeremylt        indx[i * 2 * p + 2] = 16 + offset
6230ef72598Sjeremylt        indx[i * 2 * p + 3] = 1 + offset
6240ef72598Sjeremylt        indx[i * 2 * p + 4] = 8 + offset
6250ef72598Sjeremylt        indx[i * 2 * p + 5] = 0 + offset
6260ef72598Sjeremylt
6270ef72598Sjeremylt        indx[i * 2 * p + 6] = 14 + offset
6280ef72598Sjeremylt        indx[i * 2 * p + 7] = 7 + offset
6290ef72598Sjeremylt        indx[i * 2 * p + 8] = 0 + offset
6300ef72598Sjeremylt        indx[i * 2 * p + 9] = 15 + offset
6310ef72598Sjeremylt        indx[i * 2 * p + 10] = 8 + offset
6320ef72598Sjeremylt        indx[i * 2 * p + 11] = 16 + offset
6330ef72598Sjeremylt
6340ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, p, dim, ndofs, dim * ndofs, indx,
6350ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
6360ef72598Sjeremylt
6370ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, ndofs, indx,
6380ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
6390ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
6400ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, nqpts, strides)
6410ef72598Sjeremylt
6420ef72598Sjeremylt    # Bases
64380a9ef05SNatalie Beams    qref = np.empty(dim * q, dtype=ceed.scalar_type())
64480a9ef05SNatalie Beams    qweight = np.empty(q, dtype=ceed.scalar_type())
64580a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
64680a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
6470ef72598Sjeremylt
6480ef72598Sjeremylt    bx = ceed.BasisH1(libceed.TRIANGLE, dim, p, q, interp, grad, qref, qweight)
6490ef72598Sjeremylt    bu = ceed.BasisH1(libceed.TRIANGLE, 1, p, q, interp, grad, qref, qweight)
6500ef72598Sjeremylt
6510ef72598Sjeremylt    # QFunctions
6520ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
6530ef72598Sjeremylt    qfs = load_qfs_so()
6540ef72598Sjeremylt
6550ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass_2d,
6560ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
6570ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
6580ef72598Sjeremylt    qf_setup.add_input("dx", dim * dim, libceed.EVAL_GRAD)
6590ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
6600ef72598Sjeremylt
6610ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
6620ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
6630ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
6640ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
6650ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
6660ef72598Sjeremylt
6670ef72598Sjeremylt    # Operators
6680ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
6690ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
6700ef72598Sjeremylt                       libceed.VECTOR_NONE)
6710ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
6720ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
6730ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
6740ef72598Sjeremylt
6750ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
6760ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
6770ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
6780ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
6790ef72598Sjeremylt
6800ef72598Sjeremylt    # Setup
6810ef72598Sjeremylt    op_setup.apply(x, qdata)
6820ef72598Sjeremylt
6830ef72598Sjeremylt    # Apply mass matrix
6840ef72598Sjeremylt    u.set_value(0.)
6850ef72598Sjeremylt    op_mass.apply(u, v)
6860ef72598Sjeremylt
6870ef72598Sjeremylt    # Check
6880ef72598Sjeremylt    with v.array_read() as v_array:
6890ef72598Sjeremylt        for i in range(ndofs):
6900ef72598Sjeremylt            assert abs(v_array[i]) < TOL
6910ef72598Sjeremylt
6920ef72598Sjeremylt# -------------------------------------------------------------------------------
6930ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
6940ef72598Sjeremylt# -------------------------------------------------------------------------------
6950ef72598Sjeremylt
6960ef72598Sjeremylt
6970ef72598Sjeremyltdef test_511(ceed_resource):
6980ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
6990ef72598Sjeremylt
7000ef72598Sjeremylt    nelem = 12
7010ef72598Sjeremylt    dim = 2
7020ef72598Sjeremylt    p = 6
7030ef72598Sjeremylt    q = 4
7040ef72598Sjeremylt    nx, ny = 3, 2
7050ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
7060ef72598Sjeremylt    nqpts = nelem * q
7070ef72598Sjeremylt
7080ef72598Sjeremylt    # Vectors
7090ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
71080a9ef05SNatalie Beams    x_array = np.zeros(dim * ndofs, dtype=ceed.scalar_type())
7110ef72598Sjeremylt    for i in range(ndofs):
7120ef72598Sjeremylt        x_array[i] = (1. / (nx * 2)) * (i % (nx * 2 + 1))
7130ef72598Sjeremylt        x_array[i + ndofs] = (1. / (ny * 2)) * (i / (nx * 2 + 1))
7140ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
7150ef72598Sjeremylt
7160ef72598Sjeremylt    qdata = ceed.Vector(nqpts)
7170ef72598Sjeremylt    u = ceed.Vector(ndofs)
7180ef72598Sjeremylt    v = ceed.Vector(ndofs)
7190ef72598Sjeremylt
7200ef72598Sjeremylt    # Restrictions
7210ef72598Sjeremylt    indx = np.zeros(nelem * p, dtype="int32")
7220ef72598Sjeremylt    for i in range(nelem // 2):
7230ef72598Sjeremylt        col = i % nx
7240ef72598Sjeremylt        row = i // nx
7250ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
7260ef72598Sjeremylt
7270ef72598Sjeremylt        indx[i * 2 * p + 0] = 2 + offset
7280ef72598Sjeremylt        indx[i * 2 * p + 1] = 9 + offset
7290ef72598Sjeremylt        indx[i * 2 * p + 2] = 16 + offset
7300ef72598Sjeremylt        indx[i * 2 * p + 3] = 1 + offset
7310ef72598Sjeremylt        indx[i * 2 * p + 4] = 8 + offset
7320ef72598Sjeremylt        indx[i * 2 * p + 5] = 0 + offset
7330ef72598Sjeremylt
7340ef72598Sjeremylt        indx[i * 2 * p + 6] = 14 + offset
7350ef72598Sjeremylt        indx[i * 2 * p + 7] = 7 + offset
7360ef72598Sjeremylt        indx[i * 2 * p + 8] = 0 + offset
7370ef72598Sjeremylt        indx[i * 2 * p + 9] = 15 + offset
7380ef72598Sjeremylt        indx[i * 2 * p + 10] = 8 + offset
7390ef72598Sjeremylt        indx[i * 2 * p + 11] = 16 + offset
7400ef72598Sjeremylt
7410ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, p, dim, ndofs, dim * ndofs, indx,
7420ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
7430ef72598Sjeremylt
7440ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, ndofs, indx,
7450ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
7460ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
7470ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, nqpts, strides)
7480ef72598Sjeremylt
7490ef72598Sjeremylt    # Bases
75080a9ef05SNatalie Beams    qref = np.empty(dim * q, dtype=ceed.scalar_type())
75180a9ef05SNatalie Beams    qweight = np.empty(q, dtype=ceed.scalar_type())
75280a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
75380a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
7540ef72598Sjeremylt
7550ef72598Sjeremylt    bx = ceed.BasisH1(libceed.TRIANGLE, dim, p, q, interp, grad, qref, qweight)
7560ef72598Sjeremylt    bu = ceed.BasisH1(libceed.TRIANGLE, 1, p, q, interp, grad, qref, qweight)
7570ef72598Sjeremylt
7580ef72598Sjeremylt    # QFunctions
7590ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
7600ef72598Sjeremylt    qfs = load_qfs_so()
7610ef72598Sjeremylt
7620ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass_2d,
7630ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
7640ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
7650ef72598Sjeremylt    qf_setup.add_input("dx", dim * dim, libceed.EVAL_GRAD)
7660ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
7670ef72598Sjeremylt
7680ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
7690ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
7700ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
7710ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
7720ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
7730ef72598Sjeremylt
7740ef72598Sjeremylt    # Operators
7750ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
7760ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
7770ef72598Sjeremylt                       libceed.VECTOR_NONE)
7780ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
7790ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
7800ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
7810ef72598Sjeremylt
7820ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
7830ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
7840ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
7850ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
7860ef72598Sjeremylt
7870ef72598Sjeremylt    # Setup
7880ef72598Sjeremylt    op_setup.apply(x, qdata)
7890ef72598Sjeremylt
7900ef72598Sjeremylt    # Apply mass matrix
7910ef72598Sjeremylt    u.set_value(1.)
7920ef72598Sjeremylt    op_mass.apply(u, v)
7930ef72598Sjeremylt
7940ef72598Sjeremylt    # Check
7950ef72598Sjeremylt    with v.array_read() as v_array:
7960ef72598Sjeremylt        total = 0.0
7970ef72598Sjeremylt        for i in range(ndofs):
7980ef72598Sjeremylt            total = total + v_array[i]
79980a9ef05SNatalie Beams        assert abs(total - 1.0) < 10. * TOL
8000ef72598Sjeremylt
8010ef72598Sjeremylt# -------------------------------------------------------------------------------
8020ef72598Sjeremylt# Test creation, action, and destruction for composite mass matrix operator
8030ef72598Sjeremylt# -------------------------------------------------------------------------------
8040ef72598Sjeremylt
8050ef72598Sjeremylt
8060ef72598Sjeremyltdef test_520(ceed_resource):
8070ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
8080ef72598Sjeremylt
8090ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
8100ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
8110ef72598Sjeremylt    nx, ny = 3, 3
8120ef72598Sjeremylt    dim = 2
8130ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
8140ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
8150ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
8160ef72598Sjeremylt
8170ef72598Sjeremylt    # Vectors
8180ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
8190ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
8200ef72598Sjeremylt    for i in range(ny * 2 + 1):
8210ef72598Sjeremylt        for j in range(nx * 2 + 1):
8220ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1)] = i / (2 * ny)
8230ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1) + ndofs] = j / (2 * nx)
8240ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
8250ef72598Sjeremylt
8260ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
8270ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
8280ef72598Sjeremylt    u = ceed.Vector(ndofs)
8290ef72598Sjeremylt    v = ceed.Vector(ndofs)
8300ef72598Sjeremylt
8310ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
8320ef72598Sjeremylt
8330ef72598Sjeremylt    # Restrictions
8340ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
8350ef72598Sjeremylt    for i in range(nelem_tet // 2):
8360ef72598Sjeremylt        col = i % nx
8370ef72598Sjeremylt        row = i // nx
8380ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
8390ef72598Sjeremylt
8400ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
8410ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
8420ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
8430ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
8440ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
8450ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
8460ef72598Sjeremylt
8470ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
8480ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
8490ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
8500ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
8510ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
8520ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
8530ef72598Sjeremylt
8540ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
8550ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
8560ef72598Sjeremylt
8570ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
8580ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
8590ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
8600ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
8610ef72598Sjeremylt                                          strides)
8620ef72598Sjeremylt
8630ef72598Sjeremylt    # Bases
86480a9ef05SNatalie Beams    qref = np.empty(dim * q_tet, dtype=ceed.scalar_type())
86580a9ef05SNatalie Beams    qweight = np.empty(q_tet, dtype=ceed.scalar_type())
86680a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
86780a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
8680ef72598Sjeremylt
8690ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
8700ef72598Sjeremylt                          qweight)
8710ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
8720ef72598Sjeremylt                          qweight)
8730ef72598Sjeremylt
8740ef72598Sjeremylt    # QFunctions
8750ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
8760ef72598Sjeremylt    qfs = load_qfs_so()
8770ef72598Sjeremylt
8780ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
8790ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
8800ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
8810ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
8820ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
8830ef72598Sjeremylt
8840ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
8850ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
8860ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
8870ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
8880ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
8890ef72598Sjeremylt
8900ef72598Sjeremylt    # Operators
8910ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
8920ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
8930ef72598Sjeremylt                           libceed.VECTOR_NONE)
8940ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
8950ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
8960ef72598Sjeremylt                           qdata_tet)
8970ef72598Sjeremylt
8980ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
8990ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
9000ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
9010ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
9020ef72598Sjeremylt
9030ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
9040ef72598Sjeremylt
9050ef72598Sjeremylt    # Restrictions
9060ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
9070ef72598Sjeremylt    for i in range(nelem_hex):
9080ef72598Sjeremylt        col = i % nx_hex
9090ef72598Sjeremylt        row = i // nx_hex
9100ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
9110ef72598Sjeremylt
9120ef72598Sjeremylt        for j in range(p_hex):
9130ef72598Sjeremylt            for k in range(p_hex):
9140ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
9150ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
9160ef72598Sjeremylt
9170ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
9180ef72598Sjeremylt                                  dim * ndofs, indx_hex, cmode=libceed.USE_POINTER)
9190ef72598Sjeremylt
9200ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
9210ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
9220ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
9230ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
9240ef72598Sjeremylt                                          nqpts_hex, strides)
9250ef72598Sjeremylt
9260ef72598Sjeremylt    # Bases
9270ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
9280ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
9290ef72598Sjeremylt
9300ef72598Sjeremylt    # QFunctions
9310ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
9320ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
9330ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
9340ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
9350ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
9360ef72598Sjeremylt
9370ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
9380ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
9390ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
9400ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
9410ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
9420ef72598Sjeremylt
9430ef72598Sjeremylt    # Operators
9440ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
9450ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
9460ef72598Sjeremylt                           libceed.VECTOR_NONE)
9470ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
9480ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
9490ef72598Sjeremylt                           qdata_hex)
9500ef72598Sjeremylt
9510ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
9520ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
9530ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
9540ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
9550ef72598Sjeremylt
9560ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
9570ef72598Sjeremylt
9580ef72598Sjeremylt    # Setup
9590ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
9600ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
9610ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
9620ef72598Sjeremylt    op_setup.apply(x, libceed.VECTOR_NONE)
9630ef72598Sjeremylt
9640ef72598Sjeremylt    # Apply mass matrix
9650ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
9660ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
9670ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
9680ef72598Sjeremylt
9690ef72598Sjeremylt    u.set_value(0.)
9700ef72598Sjeremylt    op_mass.apply(u, v)
9710ef72598Sjeremylt
9720ef72598Sjeremylt    # Check
9730ef72598Sjeremylt    with v.array_read() as v_array:
9740ef72598Sjeremylt        for i in range(ndofs):
9750ef72598Sjeremylt            assert abs(v_array[i]) < TOL
9760ef72598Sjeremylt
9770ef72598Sjeremylt# -------------------------------------------------------------------------------
9780ef72598Sjeremylt# Test creation, action, and destruction for composite mass matrix operator
9790ef72598Sjeremylt# -------------------------------------------------------------------------------
9800ef72598Sjeremylt
9810ef72598Sjeremylt
9820ef72598Sjeremyltdef test_521(ceed_resource):
9830ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
9840ef72598Sjeremylt
9850ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
9860ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
9870ef72598Sjeremylt    nx, ny = 3, 3
9880ef72598Sjeremylt    dim = 2
9890ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
9900ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
9910ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
9920ef72598Sjeremylt
9930ef72598Sjeremylt    # Vectors
9940ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
99580a9ef05SNatalie Beams    x_array = np.zeros(dim * ndofs, dtype=ceed.scalar_type())
9960ef72598Sjeremylt    for i in range(ny * 2 + 1):
9970ef72598Sjeremylt        for j in range(nx * 2 + 1):
9980ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1)] = i / (2 * ny)
9990ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1) + ndofs] = j / (2 * nx)
10000ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
10010ef72598Sjeremylt
10020ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
10030ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
10040ef72598Sjeremylt    u = ceed.Vector(ndofs)
10050ef72598Sjeremylt    v = ceed.Vector(ndofs)
10060ef72598Sjeremylt
10070ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
10080ef72598Sjeremylt
10090ef72598Sjeremylt    # Restrictions
10100ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
10110ef72598Sjeremylt    for i in range(nelem_tet // 2):
10120ef72598Sjeremylt        col = i % nx
10130ef72598Sjeremylt        row = i // nx
10140ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
10150ef72598Sjeremylt
10160ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
10170ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
10180ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
10190ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
10200ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
10210ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
10220ef72598Sjeremylt
10230ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
10240ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
10250ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
10260ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
10270ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
10280ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
10290ef72598Sjeremylt
10300ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
10310ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
10320ef72598Sjeremylt
10330ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
10340ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
10350ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
10360ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
10370ef72598Sjeremylt                                          strides)
10380ef72598Sjeremylt
10390ef72598Sjeremylt    # Bases
104080a9ef05SNatalie Beams    qref = np.empty(dim * q_tet, dtype=ceed.scalar_type())
104180a9ef05SNatalie Beams    qweight = np.empty(q_tet, dtype=ceed.scalar_type())
104280a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
104380a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
10440ef72598Sjeremylt
10450ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
10460ef72598Sjeremylt                          qweight)
10470ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
10480ef72598Sjeremylt                          qweight)
10490ef72598Sjeremylt
10500ef72598Sjeremylt    # QFunctions
10510ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
10520ef72598Sjeremylt    qfs = load_qfs_so()
10530ef72598Sjeremylt
10540ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
10550ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
10560ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
10570ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
10580ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
10590ef72598Sjeremylt
10600ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
10610ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
10620ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
10630ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
10640ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
10650ef72598Sjeremylt
10660ef72598Sjeremylt    # Operators
10670ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
10680ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
10690ef72598Sjeremylt                           libceed.VECTOR_NONE)
10700ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
10710ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
10720ef72598Sjeremylt                           qdata_tet)
10730ef72598Sjeremylt
10740ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
10750ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
10760ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
10770ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
10780ef72598Sjeremylt
10790ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
10800ef72598Sjeremylt
10810ef72598Sjeremylt    # Restrictions
10820ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
10830ef72598Sjeremylt    for i in range(nelem_hex):
10840ef72598Sjeremylt        col = i % nx_hex
10850ef72598Sjeremylt        row = i // nx_hex
10860ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
10870ef72598Sjeremylt
10880ef72598Sjeremylt        for j in range(p_hex):
10890ef72598Sjeremylt            for k in range(p_hex):
10900ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
10910ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
10920ef72598Sjeremylt
10930ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
10940ef72598Sjeremylt                                  dim * ndofs, indx_hex, cmode=libceed.USE_POINTER)
10950ef72598Sjeremylt
10960ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
10970ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
10980ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
10990ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
11000ef72598Sjeremylt                                          nqpts_hex, strides)
11010ef72598Sjeremylt
11020ef72598Sjeremylt    # Bases
11030ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
11040ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
11050ef72598Sjeremylt
11060ef72598Sjeremylt    # QFunctions
11070ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
11080ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
11090ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
11100ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
11110ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
11120ef72598Sjeremylt
11130ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
11140ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
11150ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
11160ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
11170ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
11180ef72598Sjeremylt
11190ef72598Sjeremylt    # Operators
11200ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
11210ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
11220ef72598Sjeremylt                           libceed.VECTOR_NONE)
11230ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
11240ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
11250ef72598Sjeremylt                           qdata_hex)
11260ef72598Sjeremylt
11270ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
11280ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
11290ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
11300ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
11310ef72598Sjeremylt
11320ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
11330ef72598Sjeremylt
11340ef72598Sjeremylt    # Setup
11350ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
11360ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
11370ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
11380ef72598Sjeremylt    op_setup.apply(x, libceed.VECTOR_NONE)
11390ef72598Sjeremylt
11400ef72598Sjeremylt    # Apply mass matrix
11410ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
11420ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
11430ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
11440ef72598Sjeremylt    u.set_value(1.)
11450ef72598Sjeremylt    op_mass.apply(u, v)
11460ef72598Sjeremylt
11470ef72598Sjeremylt    # Check
11480ef72598Sjeremylt    with v.array_read() as v_array:
11490ef72598Sjeremylt        total = 0.0
11500ef72598Sjeremylt        for i in range(ndofs):
11510ef72598Sjeremylt            total = total + v_array[i]
115280a9ef05SNatalie Beams        assert abs(total - 1.0) < 10. * TOL
11530ef72598Sjeremylt
11540ef72598Sjeremylt# -------------------------------------------------------------------------------
11550ef72598Sjeremylt# Test viewing of composite mass matrix operator
11560ef72598Sjeremylt# -------------------------------------------------------------------------------
11570ef72598Sjeremylt
11580ef72598Sjeremylt
11590ef72598Sjeremyltdef test_523(ceed_resource, capsys):
11600ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
11610ef72598Sjeremylt
11620ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
11630ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
11640ef72598Sjeremylt    nx, ny = 3, 3
11650ef72598Sjeremylt    dim = 2
11660ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
11670ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
11680ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
11690ef72598Sjeremylt
11700ef72598Sjeremylt    # Vectors
11710ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
11720ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
11730ef72598Sjeremylt
11740ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
11750ef72598Sjeremylt
11760ef72598Sjeremylt    # Restrictions
11770ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
11780ef72598Sjeremylt    for i in range(nelem_tet // 2):
11790ef72598Sjeremylt        col = i % nx
11800ef72598Sjeremylt        row = i // nx
11810ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
11820ef72598Sjeremylt
11830ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
11840ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
11850ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
11860ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
11870ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
11880ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
11890ef72598Sjeremylt
11900ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
11910ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
11920ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
11930ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
11940ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
11950ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
11960ef72598Sjeremylt
11970ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
11980ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
11990ef72598Sjeremylt
12000ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
12010ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
12020ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
12030ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
12040ef72598Sjeremylt                                          strides)
12050ef72598Sjeremylt
12060ef72598Sjeremylt    # Bases
120780a9ef05SNatalie Beams    qref = np.empty(dim * q_tet, dtype=ceed.scalar_type())
120880a9ef05SNatalie Beams    qweight = np.empty(q_tet, dtype=ceed.scalar_type())
120980a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
121080a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
12110ef72598Sjeremylt
12120ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
12130ef72598Sjeremylt                          qweight)
12140ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
12150ef72598Sjeremylt                          qweight)
12160ef72598Sjeremylt
12170ef72598Sjeremylt    # QFunctions
12180ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
12190ef72598Sjeremylt    qfs = load_qfs_so()
12200ef72598Sjeremylt
12210ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
12220ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
12230ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
12240ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
12250ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
12260ef72598Sjeremylt
12270ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
12280ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
12290ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
12300ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
12310ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
12320ef72598Sjeremylt
12330ef72598Sjeremylt    # Operators
12340ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
12350ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
12360ef72598Sjeremylt                           libceed.VECTOR_NONE)
12370ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
12380ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
12390ef72598Sjeremylt                           qdata_tet)
12400ef72598Sjeremylt
12410ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
12420ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
12430ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
12440ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
12450ef72598Sjeremylt
12460ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
12470ef72598Sjeremylt
12480ef72598Sjeremylt    # Restrictions
12490ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
12500ef72598Sjeremylt    for i in range(nelem_hex):
12510ef72598Sjeremylt        col = i % nx_hex
12520ef72598Sjeremylt        row = i // nx_hex
12530ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
12540ef72598Sjeremylt
12550ef72598Sjeremylt        for j in range(p_hex):
12560ef72598Sjeremylt            for k in range(p_hex):
12570ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
12580ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
12590ef72598Sjeremylt
12600ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
12610ef72598Sjeremylt                                  dim * ndofs, indx_hex,
12620ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
12630ef72598Sjeremylt
12640ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
12650ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
12660ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
12670ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
12680ef72598Sjeremylt                                          nqpts_hex, strides)
12690ef72598Sjeremylt
12700ef72598Sjeremylt    # Bases
12710ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
12720ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
12730ef72598Sjeremylt
12740ef72598Sjeremylt    # QFunctions
12750ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
12760ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
12770ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
12780ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
12790ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
12800ef72598Sjeremylt
12810ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
12820ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
12830ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
12840ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
12850ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
12860ef72598Sjeremylt
12870ef72598Sjeremylt    # Operators
12880ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
12890ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
12900ef72598Sjeremylt                           libceed.VECTOR_NONE)
12910ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
12920ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
12930ef72598Sjeremylt                           qdata_hex)
12940ef72598Sjeremylt
12950ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
12960ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
12970ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
12980ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
12990ef72598Sjeremylt
13000ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
13010ef72598Sjeremylt
13020ef72598Sjeremylt    # Setup
13030ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
13040ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
13050ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
13060ef72598Sjeremylt
13070ef72598Sjeremylt    # Apply mass matrix
13080ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
13090ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
13100ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
13110ef72598Sjeremylt
13120ef72598Sjeremylt    # View
13130ef72598Sjeremylt    print(op_setup)
13140ef72598Sjeremylt    print(op_mass)
13150ef72598Sjeremylt
13160ef72598Sjeremylt    stdout, stderr, ref_stdout = check.output(capsys)
13170ef72598Sjeremylt    assert not stderr
13180ef72598Sjeremylt    assert stdout == ref_stdout
13190ef72598Sjeremylt
13200ef72598Sjeremylt# -------------------------------------------------------------------------------
13210ef72598Sjeremylt# CeedOperatorApplyAdd for composite operator
13220ef72598Sjeremylt# -------------------------------------------------------------------------------
13230ef72598Sjeremylt
13240ef72598Sjeremylt
13250ef72598Sjeremyltdef test_524(ceed_resource):
13260ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
13270ef72598Sjeremylt
13280ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
13290ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
13300ef72598Sjeremylt    nx, ny = 3, 3
13310ef72598Sjeremylt    dim = 2
13320ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
13330ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
13340ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
13350ef72598Sjeremylt
13360ef72598Sjeremylt    # Vectors
13370ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
133880a9ef05SNatalie Beams    x_array = np.zeros(dim * ndofs, dtype=ceed.scalar_type())
13390ef72598Sjeremylt    for i in range(ny * 2 + 1):
13400ef72598Sjeremylt        for j in range(nx * 2 + 1):
13410ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1)] = i / (2 * ny)
13420ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1) + ndofs] = j / (2 * nx)
13430ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
13440ef72598Sjeremylt
13450ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
13460ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
13470ef72598Sjeremylt    u = ceed.Vector(ndofs)
13480ef72598Sjeremylt    v = ceed.Vector(ndofs)
13490ef72598Sjeremylt
13500ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
13510ef72598Sjeremylt
13520ef72598Sjeremylt    # Restrictions
13530ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
13540ef72598Sjeremylt    for i in range(nelem_tet // 2):
13550ef72598Sjeremylt        col = i % nx
13560ef72598Sjeremylt        row = i // nx
13570ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
13580ef72598Sjeremylt
13590ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
13600ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
13610ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
13620ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
13630ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
13640ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
13650ef72598Sjeremylt
13660ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
13670ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
13680ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
13690ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
13700ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
13710ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
13720ef72598Sjeremylt
13730ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
13740ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
13750ef72598Sjeremylt
13760ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
13770ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
13780ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
13790ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
13800ef72598Sjeremylt                                          strides)
13810ef72598Sjeremylt
13820ef72598Sjeremylt    # Bases
138380a9ef05SNatalie Beams    qref = np.empty(dim * q_tet, dtype=ceed.scalar_type())
138480a9ef05SNatalie Beams    qweight = np.empty(q_tet, dtype=ceed.scalar_type())
138580a9ef05SNatalie Beams    interp, grad = bm.buildmats(qref, qweight, libceed.scalar_types[
138680a9ef05SNatalie Beams        libceed.lib.CEED_SCALAR_TYPE])
13870ef72598Sjeremylt
13880ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
13890ef72598Sjeremylt                          qweight)
13900ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
13910ef72598Sjeremylt                          qweight)
13920ef72598Sjeremylt
13930ef72598Sjeremylt    # QFunctions
13940ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
13950ef72598Sjeremylt    qfs = load_qfs_so()
13960ef72598Sjeremylt
13970ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
13980ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
13990ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
14000ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
14010ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
14020ef72598Sjeremylt
14030ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
14040ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
14050ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
14060ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
14070ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
14080ef72598Sjeremylt
14090ef72598Sjeremylt    # Operators
14100ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
14110ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
14120ef72598Sjeremylt                           libceed.VECTOR_NONE)
14130ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
14140ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
14150ef72598Sjeremylt                           qdata_tet)
14160ef72598Sjeremylt
14170ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
14180ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
14190ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
14200ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
14210ef72598Sjeremylt
14220ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
14230ef72598Sjeremylt
14240ef72598Sjeremylt    # Restrictions
14250ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
14260ef72598Sjeremylt    for i in range(nelem_hex):
14270ef72598Sjeremylt        col = i % nx_hex
14280ef72598Sjeremylt        row = i // nx_hex
14290ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
14300ef72598Sjeremylt
14310ef72598Sjeremylt        for j in range(p_hex):
14320ef72598Sjeremylt            for k in range(p_hex):
14330ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
14340ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
14350ef72598Sjeremylt
14360ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
14370ef72598Sjeremylt                                  dim * ndofs, indx_hex,
14380ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
14390ef72598Sjeremylt
14400ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
14410ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
14420ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
14430ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
14440ef72598Sjeremylt                                          nqpts_hex, strides)
14450ef72598Sjeremylt
14460ef72598Sjeremylt    # Bases
14470ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
14480ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
14490ef72598Sjeremylt
14500ef72598Sjeremylt    # QFunctions
14510ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
14520ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
14530ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
14540ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
14550ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
14560ef72598Sjeremylt
14570ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
14580ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
14590ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
14600ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
14610ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
14620ef72598Sjeremylt
14630ef72598Sjeremylt    # Operators
14640ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
14650ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
14660ef72598Sjeremylt                           libceed.VECTOR_NONE)
14670ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
14680ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
14690ef72598Sjeremylt                           qdata_hex)
14700ef72598Sjeremylt
14710ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
14720ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
14730ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
14740ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
14750ef72598Sjeremylt
14760ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
14770ef72598Sjeremylt
14780ef72598Sjeremylt    # Setup
14790ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
14800ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
14810ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
14820ef72598Sjeremylt    op_setup.apply(x, libceed.VECTOR_NONE)
14830ef72598Sjeremylt
14840ef72598Sjeremylt    # Apply mass matrix
14850ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
14860ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
14870ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
14880ef72598Sjeremylt    u.set_value(1.)
14890ef72598Sjeremylt    op_mass.apply(u, v)
14900ef72598Sjeremylt
14910ef72598Sjeremylt    # Check
14920ef72598Sjeremylt    with v.array_read() as v_array:
14930ef72598Sjeremylt        total = 0.0
14940ef72598Sjeremylt        for i in range(ndofs):
14950ef72598Sjeremylt            total = total + v_array[i]
149680a9ef05SNatalie Beams        assert abs(total - 1.0) < 10. * TOL
14970ef72598Sjeremylt
14980ef72598Sjeremylt    # ApplyAdd mass matrix
14990ef72598Sjeremylt    v.set_value(1.)
15000ef72598Sjeremylt    op_mass.apply_add(u, v)
15010ef72598Sjeremylt
15020ef72598Sjeremylt    # Check
15030ef72598Sjeremylt    with v.array_read() as v_array:
15040ef72598Sjeremylt        total = -ndofs
15050ef72598Sjeremylt        for i in range(ndofs):
15060ef72598Sjeremylt            total = total + v_array[i]
150780a9ef05SNatalie Beams        assert abs(total - 1.0) < 10. * TOL
15080ef72598Sjeremylt
15090ef72598Sjeremylt# -------------------------------------------------------------------------------
15100ef72598Sjeremylt# Test assembly of mass matrix operator diagonal
15110ef72598Sjeremylt# -------------------------------------------------------------------------------
15120ef72598Sjeremylt
15130ef72598Sjeremylt
15140ef72598Sjeremyltdef test_533(ceed_resource):
15150ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
15160ef72598Sjeremylt
15170ef72598Sjeremylt    nelem = 6
15180ef72598Sjeremylt    p = 3
15190ef72598Sjeremylt    q = 4
15200ef72598Sjeremylt    dim = 2
15210ef72598Sjeremylt    nx = 3
15220ef72598Sjeremylt    ny = 2
15230ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
15240ef72598Sjeremylt    nqpts = nelem * q * q
15250ef72598Sjeremylt
15260ef72598Sjeremylt    # Vectors
15270ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
15280ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
15290ef72598Sjeremylt    for i in range(nx * 2 + 1):
15300ef72598Sjeremylt        for j in range(ny * 2 + 1):
15310ef72598Sjeremylt            x_array[i + j * (nx * 2 + 1) + 0 * ndofs] = i / (2 * nx)
15320ef72598Sjeremylt            x_array[i + j * (nx * 2 + 1) + 1 * ndofs] = j / (2 * ny)
15330ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
15340ef72598Sjeremylt
15350ef72598Sjeremylt    qdata = ceed.Vector(nqpts)
15360ef72598Sjeremylt    u = ceed.Vector(ndofs)
15370ef72598Sjeremylt    v = ceed.Vector(ndofs)
15380ef72598Sjeremylt
15390ef72598Sjeremylt    # Restrictions
15400ef72598Sjeremylt    indx = np.zeros(nelem * p * p, dtype="int32")
15410ef72598Sjeremylt    for i in range(nelem):
15420ef72598Sjeremylt        col = i % nx
15430ef72598Sjeremylt        row = i // nx
15440ef72598Sjeremylt        offset = col * (p - 1) + row * (nx * 2 + 1) * (p - 1)
15450ef72598Sjeremylt        for j in range(p):
15460ef72598Sjeremylt            for k in range(p):
15470ef72598Sjeremylt                indx[p * (p * i + k) + j] = offset + k * (nx * 2 + 1) + j
15480ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, p * p, dim, ndofs, dim * ndofs,
15490ef72598Sjeremylt                              indx, cmode=libceed.USE_POINTER)
15500ef72598Sjeremylt
15510ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p * p, 1, 1, ndofs, indx,
15520ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
15530ef72598Sjeremylt    strides = np.array([1, q * q, q * q], dtype="int32")
15540ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q * q, 1, nqpts, strides)
15550ef72598Sjeremylt
15560ef72598Sjeremylt    # Bases
15570ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(dim, dim, p, q, libceed.GAUSS)
15580ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(dim, 1, p, q, libceed.GAUSS)
15590ef72598Sjeremylt
15600ef72598Sjeremylt    # QFunctions
15610ef72598Sjeremylt    qf_setup = ceed.QFunctionByName("Mass2DBuild")
15620ef72598Sjeremylt
15630ef72598Sjeremylt# -------------------------------------------------------------------------------
15640ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with
15650ef72598Sjeremylt#   multigrid level, tensor basis and interpolation basis generation
15660ef72598Sjeremylt# -------------------------------------------------------------------------------
15670ef72598Sjeremylt
15680ef72598Sjeremylt
15690ef72598Sjeremyltdef test_550(ceed_resource):
15700ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
15710ef72598Sjeremylt
15720ef72598Sjeremylt    nelem = 15
15730ef72598Sjeremylt    p_coarse = 3
15740ef72598Sjeremylt    p_fine = 5
15750ef72598Sjeremylt    q = 8
15760ef72598Sjeremylt    ncomp = 2
15770ef72598Sjeremylt    nx = nelem + 1
15780ef72598Sjeremylt    nu_coarse = nelem * (p_coarse - 1) + 1
15790ef72598Sjeremylt    nu_fine = nelem * (p_fine - 1) + 1
15800ef72598Sjeremylt
15810ef72598Sjeremylt    # Vectors
15820ef72598Sjeremylt    x = ceed.Vector(nx)
158380a9ef05SNatalie Beams    x_array = np.zeros(nx, dtype=ceed.scalar_type())
15840ef72598Sjeremylt    for i in range(nx):
15850ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
15860ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
15870ef72598Sjeremylt
15880ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
15890ef72598Sjeremylt    u_coarse = ceed.Vector(ncomp * nu_coarse)
15900ef72598Sjeremylt    v_coarse = ceed.Vector(ncomp * nu_coarse)
15910ef72598Sjeremylt    u_fine = ceed.Vector(ncomp * nu_fine)
15920ef72598Sjeremylt    v_fine = ceed.Vector(ncomp * nu_fine)
15930ef72598Sjeremylt
15940ef72598Sjeremylt    # Restrictions
15950ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
15960ef72598Sjeremylt    for i in range(nx):
15970ef72598Sjeremylt        indx[2 * i + 0] = i
15980ef72598Sjeremylt        indx[2 * i + 1] = i + 1
15990ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
16000ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
16010ef72598Sjeremylt
16020ef72598Sjeremylt    indu_coarse = np.zeros(nelem * p_coarse, dtype="int32")
16030ef72598Sjeremylt    for i in range(nelem):
16040ef72598Sjeremylt        for j in range(p_coarse):
16050ef72598Sjeremylt            indu_coarse[p_coarse * i + j] = i * (p_coarse - 1) + j
16060ef72598Sjeremylt    ru_coarse = ceed.ElemRestriction(nelem, p_coarse, ncomp, nu_coarse,
16070ef72598Sjeremylt                                     ncomp * nu_coarse, indu_coarse,
16080ef72598Sjeremylt                                     cmode=libceed.USE_POINTER)
16090ef72598Sjeremylt
16100ef72598Sjeremylt    indu_fine = np.zeros(nelem * p_fine, dtype="int32")
16110ef72598Sjeremylt    for i in range(nelem):
16120ef72598Sjeremylt        for j in range(p_fine):
16130ef72598Sjeremylt            indu_fine[p_fine * i + j] = i * (p_fine - 1) + j
16140ef72598Sjeremylt    ru_fine = ceed.ElemRestriction(nelem, p_fine, ncomp, nu_fine,
16150ef72598Sjeremylt                                   ncomp * nu_fine, indu_fine,
16160ef72598Sjeremylt                                   cmode=libceed.USE_POINTER)
16170ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
16180ef72598Sjeremylt
16190ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
16200ef72598Sjeremylt
16210ef72598Sjeremylt    # Bases
16220ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
16230ef72598Sjeremylt    bu_coarse = ceed.BasisTensorH1Lagrange(1, ncomp, p_coarse, q, libceed.GAUSS)
16240ef72598Sjeremylt    bu_fine = ceed.BasisTensorH1Lagrange(1, ncomp, p_fine, q, libceed.GAUSS)
16250ef72598Sjeremylt
16260ef72598Sjeremylt    # QFunctions
16270ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
16280ef72598Sjeremylt    qfs = load_qfs_so()
16290ef72598Sjeremylt
16300ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
16310ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
16320ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
16330ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
16340ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
16350ef72598Sjeremylt
16360ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass_two,
16370ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass_two"))
16380ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
16390ef72598Sjeremylt    qf_mass.add_input("u", ncomp, libceed.EVAL_INTERP)
16400ef72598Sjeremylt    qf_mass.add_output("v", ncomp, libceed.EVAL_INTERP)
16410ef72598Sjeremylt
16420ef72598Sjeremylt    # Operators
16430ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
16440ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
16450ef72598Sjeremylt                       libceed.VECTOR_NONE)
16460ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
16470ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
16480ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
16490ef72598Sjeremylt
16500ef72598Sjeremylt    op_mass_fine = ceed.Operator(qf_mass)
16510ef72598Sjeremylt    op_mass_fine.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
16520ef72598Sjeremylt    op_mass_fine.set_field("u", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
16530ef72598Sjeremylt    op_mass_fine.set_field("v", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
16540ef72598Sjeremylt
16550ef72598Sjeremylt    # Setup
16560ef72598Sjeremylt    op_setup.apply(x, qdata)
16570ef72598Sjeremylt
16580ef72598Sjeremylt    # Create multigrid level
16590ef72598Sjeremylt    p_mult_fine = ceed.Vector(ncomp * nu_fine)
16600ef72598Sjeremylt    p_mult_fine.set_value(1.0)
16610ef72598Sjeremylt    [op_mass_coarse, op_prolong, op_restrict] = op_mass_fine.multigrid_create(p_mult_fine,
16620ef72598Sjeremylt                                                                              ru_coarse,
16630ef72598Sjeremylt                                                                              bu_coarse)
16640ef72598Sjeremylt
16650ef72598Sjeremylt    # Apply coarse mass matrix
16660ef72598Sjeremylt    u_coarse.set_value(1.0)
16670ef72598Sjeremylt    op_mass_coarse.apply(u_coarse, v_coarse)
16680ef72598Sjeremylt
16690ef72598Sjeremylt    # Check
16700ef72598Sjeremylt    with v_coarse.array_read() as v_array:
16710ef72598Sjeremylt        total = 0.0
16720ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
16730ef72598Sjeremylt            total = total + v_array[i]
167480a9ef05SNatalie Beams        assert abs(total - 2.0) < 10. * TOL
16750ef72598Sjeremylt
16760ef72598Sjeremylt    # Prolong coarse u
16770ef72598Sjeremylt    op_prolong.apply(u_coarse, u_fine)
16780ef72598Sjeremylt
16790ef72598Sjeremylt    # Apply mass matrix
16800ef72598Sjeremylt    op_mass_fine.apply(u_fine, v_fine)
16810ef72598Sjeremylt
16820ef72598Sjeremylt    # Check
16830ef72598Sjeremylt    with v_fine.array_read() as v_array:
16840ef72598Sjeremylt        total = 0.0
16850ef72598Sjeremylt        for i in range(nu_fine * ncomp):
16860ef72598Sjeremylt            total = total + v_array[i]
168780a9ef05SNatalie Beams        assert abs(total - 2.0) < 10. * TOL
16880ef72598Sjeremylt
16890ef72598Sjeremylt    # Restrict state to coarse grid
16900ef72598Sjeremylt    op_restrict.apply(v_fine, v_coarse)
16910ef72598Sjeremylt
16920ef72598Sjeremylt    # Check
16930ef72598Sjeremylt    with v_coarse.array_read() as v_array:
16940ef72598Sjeremylt        total = 0.0
16950ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
16960ef72598Sjeremylt            total = total + v_array[i]
169780a9ef05SNatalie Beams        assert abs(total - 2.0) < 10. * TOL
16980ef72598Sjeremylt
16990ef72598Sjeremylt# -------------------------------------------------------------------------------
17000ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with
17010ef72598Sjeremylt#   multigrid level, tensor basis
17020ef72598Sjeremylt# -------------------------------------------------------------------------------
17030ef72598Sjeremylt
17040ef72598Sjeremylt
17050ef72598Sjeremyltdef test_552(ceed_resource):
17060ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
17070ef72598Sjeremylt
17080ef72598Sjeremylt    nelem = 15
17090ef72598Sjeremylt    p_coarse = 3
17100ef72598Sjeremylt    p_fine = 5
17110ef72598Sjeremylt    q = 8
17120ef72598Sjeremylt    ncomp = 2
17130ef72598Sjeremylt    nx = nelem + 1
17140ef72598Sjeremylt    nu_coarse = nelem * (p_coarse - 1) + 1
17150ef72598Sjeremylt    nu_fine = nelem * (p_fine - 1) + 1
17160ef72598Sjeremylt
17170ef72598Sjeremylt    # Vectors
17180ef72598Sjeremylt    x = ceed.Vector(nx)
171980a9ef05SNatalie Beams    x_array = np.zeros(nx, dtype=ceed.scalar_type())
17200ef72598Sjeremylt    for i in range(nx):
17210ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
17220ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
17230ef72598Sjeremylt
17240ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
17250ef72598Sjeremylt    u_coarse = ceed.Vector(ncomp * nu_coarse)
17260ef72598Sjeremylt    v_coarse = ceed.Vector(ncomp * nu_coarse)
17270ef72598Sjeremylt    u_fine = ceed.Vector(ncomp * nu_fine)
17280ef72598Sjeremylt    v_fine = ceed.Vector(ncomp * nu_fine)
17290ef72598Sjeremylt
17300ef72598Sjeremylt    # Restrictions
17310ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
17320ef72598Sjeremylt    for i in range(nx):
17330ef72598Sjeremylt        indx[2 * i + 0] = i
17340ef72598Sjeremylt        indx[2 * i + 1] = i + 1
17350ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
17360ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
17370ef72598Sjeremylt
17380ef72598Sjeremylt    indu_coarse = np.zeros(nelem * p_coarse, dtype="int32")
17390ef72598Sjeremylt    for i in range(nelem):
17400ef72598Sjeremylt        for j in range(p_coarse):
17410ef72598Sjeremylt            indu_coarse[p_coarse * i + j] = i * (p_coarse - 1) + j
17420ef72598Sjeremylt    ru_coarse = ceed.ElemRestriction(nelem, p_coarse, ncomp, nu_coarse,
17430ef72598Sjeremylt                                     ncomp * nu_coarse, indu_coarse,
17440ef72598Sjeremylt                                     cmode=libceed.USE_POINTER)
17450ef72598Sjeremylt
17460ef72598Sjeremylt    indu_fine = np.zeros(nelem * p_fine, dtype="int32")
17470ef72598Sjeremylt    for i in range(nelem):
17480ef72598Sjeremylt        for j in range(p_fine):
17490ef72598Sjeremylt            indu_fine[p_fine * i + j] = i * (p_fine - 1) + j
17500ef72598Sjeremylt    ru_fine = ceed.ElemRestriction(nelem, p_fine, ncomp, nu_fine,
17510ef72598Sjeremylt                                   ncomp * nu_fine, indu_fine,
17520ef72598Sjeremylt                                   cmode=libceed.USE_POINTER)
17530ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
17540ef72598Sjeremylt
17550ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
17560ef72598Sjeremylt
17570ef72598Sjeremylt    # Bases
17580ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
17590ef72598Sjeremylt    bu_coarse = ceed.BasisTensorH1Lagrange(1, ncomp, p_coarse, q, libceed.GAUSS)
17600ef72598Sjeremylt    bu_fine = ceed.BasisTensorH1Lagrange(1, ncomp, p_fine, q, libceed.GAUSS)
17610ef72598Sjeremylt
17620ef72598Sjeremylt    # QFunctions
17630ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
17640ef72598Sjeremylt    qfs = load_qfs_so()
17650ef72598Sjeremylt
17660ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
17670ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
17680ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
17690ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
17700ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
17710ef72598Sjeremylt
17720ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass_two,
17730ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass_two"))
17740ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
17750ef72598Sjeremylt    qf_mass.add_input("u", ncomp, libceed.EVAL_INTERP)
17760ef72598Sjeremylt    qf_mass.add_output("v", ncomp, libceed.EVAL_INTERP)
17770ef72598Sjeremylt
17780ef72598Sjeremylt    # Operators
17790ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
17800ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
17810ef72598Sjeremylt                       libceed.VECTOR_NONE)
17820ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
17830ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
17840ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
17850ef72598Sjeremylt
17860ef72598Sjeremylt    op_mass_fine = ceed.Operator(qf_mass)
17870ef72598Sjeremylt    op_mass_fine.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
17880ef72598Sjeremylt    op_mass_fine.set_field("u", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
17890ef72598Sjeremylt    op_mass_fine.set_field("v", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
17900ef72598Sjeremylt
17910ef72598Sjeremylt    # Setup
17920ef72598Sjeremylt    op_setup.apply(x, qdata)
17930ef72598Sjeremylt
17940ef72598Sjeremylt    # Create multigrid level
17950ef72598Sjeremylt    p_mult_fine = ceed.Vector(ncomp * nu_fine)
17960ef72598Sjeremylt    p_mult_fine.set_value(1.0)
17970ef72598Sjeremylt    b_c_to_f = ceed.BasisTensorH1Lagrange(
17980ef72598Sjeremylt        1, ncomp, p_coarse, p_fine, libceed.GAUSS_LOBATTO)
179966ce82e0Sjeremylt    interp_C_to_F = b_c_to_f.get_interp_1d()
18000ef72598Sjeremylt    [op_mass_coarse, op_prolong, op_restrict] = op_mass_fine.multigrid_create_tensor_h1(p_mult_fine,
18010ef72598Sjeremylt                                                                                        ru_coarse, bu_coarse, interp_C_to_F)
18020ef72598Sjeremylt
18030ef72598Sjeremylt    # Apply coarse mass matrix
18040ef72598Sjeremylt    u_coarse.set_value(1.0)
18050ef72598Sjeremylt    op_mass_coarse.apply(u_coarse, v_coarse)
18060ef72598Sjeremylt
18070ef72598Sjeremylt    # Check
18080ef72598Sjeremylt    with v_coarse.array_read() as v_array:
18090ef72598Sjeremylt        total = 0.0
18100ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
18110ef72598Sjeremylt            total = total + v_array[i]
181280a9ef05SNatalie Beams        assert abs(total - 2.0) < TOL
18130ef72598Sjeremylt
18140ef72598Sjeremylt    # Prolong coarse u
18150ef72598Sjeremylt    op_prolong.apply(u_coarse, u_fine)
18160ef72598Sjeremylt
18170ef72598Sjeremylt    # Apply mass matrix
18180ef72598Sjeremylt    op_mass_fine.apply(u_fine, v_fine)
18190ef72598Sjeremylt
18200ef72598Sjeremylt    # Check
18210ef72598Sjeremylt    with v_fine.array_read() as v_array:
18220ef72598Sjeremylt        total = 0.0
18230ef72598Sjeremylt        for i in range(nu_fine * ncomp):
18240ef72598Sjeremylt            total = total + v_array[i]
182580a9ef05SNatalie Beams        assert abs(total - 2.0) < TOL
18260ef72598Sjeremylt
18270ef72598Sjeremylt    # Restrict state to coarse grid
18280ef72598Sjeremylt    op_restrict.apply(v_fine, v_coarse)
18290ef72598Sjeremylt
18300ef72598Sjeremylt    # Check
18310ef72598Sjeremylt    with v_coarse.array_read() as v_array:
18320ef72598Sjeremylt        total = 0.0
18330ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
18340ef72598Sjeremylt            total = total + v_array[i]
183580a9ef05SNatalie Beams        assert abs(total - 2.0) < TOL
18360ef72598Sjeremylt
18370ef72598Sjeremylt# -------------------------------------------------------------------------------
18380ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with
18390ef72598Sjeremylt#   multigrid level, non-tensor basis
18400ef72598Sjeremylt# -------------------------------------------------------------------------------
18410ef72598Sjeremylt
18420ef72598Sjeremylt
18430ef72598Sjeremyltdef test_553(ceed_resource):
18440ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
18450ef72598Sjeremylt
18460ef72598Sjeremylt    nelem = 15
18470ef72598Sjeremylt    p_coarse = 3
18480ef72598Sjeremylt    p_fine = 5
18490ef72598Sjeremylt    q = 8
18500ef72598Sjeremylt    ncomp = 1
18510ef72598Sjeremylt    nx = nelem + 1
18520ef72598Sjeremylt    nu_coarse = nelem * (p_coarse - 1) + 1
18530ef72598Sjeremylt    nu_fine = nelem * (p_fine - 1) + 1
18540ef72598Sjeremylt
18550ef72598Sjeremylt    # Vectors
18560ef72598Sjeremylt    x = ceed.Vector(nx)
185780a9ef05SNatalie Beams    x_array = np.zeros(nx, dtype=ceed.scalar_type())
18580ef72598Sjeremylt    for i in range(nx):
18590ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
18600ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
18610ef72598Sjeremylt
18620ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
18630ef72598Sjeremylt    u_coarse = ceed.Vector(ncomp * nu_coarse)
18640ef72598Sjeremylt    v_coarse = ceed.Vector(ncomp * nu_coarse)
18650ef72598Sjeremylt    u_fine = ceed.Vector(ncomp * nu_fine)
18660ef72598Sjeremylt    v_fine = ceed.Vector(ncomp * nu_fine)
18670ef72598Sjeremylt
18680ef72598Sjeremylt    # Restrictions
18690ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
18700ef72598Sjeremylt    for i in range(nx):
18710ef72598Sjeremylt        indx[2 * i + 0] = i
18720ef72598Sjeremylt        indx[2 * i + 1] = i + 1
18730ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
18740ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
18750ef72598Sjeremylt
18760ef72598Sjeremylt    indu_coarse = np.zeros(nelem * p_coarse, dtype="int32")
18770ef72598Sjeremylt    for i in range(nelem):
18780ef72598Sjeremylt        for j in range(p_coarse):
18790ef72598Sjeremylt            indu_coarse[p_coarse * i + j] = i * (p_coarse - 1) + j
18800ef72598Sjeremylt    ru_coarse = ceed.ElemRestriction(nelem, p_coarse, ncomp, nu_coarse,
18810ef72598Sjeremylt                                     ncomp * nu_coarse, indu_coarse,
18820ef72598Sjeremylt                                     cmode=libceed.USE_POINTER)
18830ef72598Sjeremylt
18840ef72598Sjeremylt    indu_fine = np.zeros(nelem * p_fine, dtype="int32")
18850ef72598Sjeremylt    for i in range(nelem):
18860ef72598Sjeremylt        for j in range(p_fine):
18870ef72598Sjeremylt            indu_fine[p_fine * i + j] = i * (p_fine - 1) + j
18880ef72598Sjeremylt    ru_fine = ceed.ElemRestriction(nelem, p_fine, ncomp, nu_fine,
18890ef72598Sjeremylt                                   ncomp * nu_fine, indu_fine,
18900ef72598Sjeremylt                                   cmode=libceed.USE_POINTER)
18910ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
18920ef72598Sjeremylt
18930ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
18940ef72598Sjeremylt
18950ef72598Sjeremylt    # Bases
18960ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
18970ef72598Sjeremylt    bu_coarse = ceed.BasisTensorH1Lagrange(1, ncomp, p_coarse, q, libceed.GAUSS)
18980ef72598Sjeremylt    bu_fine = ceed.BasisTensorH1Lagrange(1, ncomp, p_fine, q, libceed.GAUSS)
18990ef72598Sjeremylt
19000ef72598Sjeremylt    # QFunctions
19010ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
19020ef72598Sjeremylt    qfs = load_qfs_so()
19030ef72598Sjeremylt
19040ef72598Sjeremylt    qf_setup = ceed.QFunctionByName("Mass1DBuild")
19050ef72598Sjeremylt    qf_mass = ceed.QFunctionByName("MassApply")
19060ef72598Sjeremylt
19070ef72598Sjeremylt    # Operators
19080ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
19090ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
19100ef72598Sjeremylt                       libceed.VECTOR_NONE)
19110ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
19120ef72598Sjeremylt    op_setup.set_field("qdata", rui, libceed.BASIS_COLLOCATED,
19130ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
19140ef72598Sjeremylt
19150ef72598Sjeremylt    op_mass_fine = ceed.Operator(qf_mass)
19160ef72598Sjeremylt    op_mass_fine.set_field("qdata", rui, libceed.BASIS_COLLOCATED, qdata)
19170ef72598Sjeremylt    op_mass_fine.set_field("u", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
19180ef72598Sjeremylt    op_mass_fine.set_field("v", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
19190ef72598Sjeremylt
19200ef72598Sjeremylt    # Setup
19210ef72598Sjeremylt    op_setup.apply(x, qdata)
19220ef72598Sjeremylt
19230ef72598Sjeremylt    # Create multigrid level
19240ef72598Sjeremylt    p_mult_fine = ceed.Vector(ncomp * nu_fine)
19250ef72598Sjeremylt    p_mult_fine.set_value(1.0)
19260ef72598Sjeremylt    b_c_to_f = ceed.BasisTensorH1Lagrange(
19270ef72598Sjeremylt        1, ncomp, p_coarse, p_fine, libceed.GAUSS_LOBATTO)
192866ce82e0Sjeremylt    interp_C_to_F = b_c_to_f.get_interp_1d()
19290ef72598Sjeremylt    [op_mass_coarse, op_prolong, op_restrict] = op_mass_fine.multigrid_create_h1(p_mult_fine,
19300ef72598Sjeremylt                                                                                 ru_coarse, bu_coarse, interp_C_to_F)
19310ef72598Sjeremylt
19320ef72598Sjeremylt    # Apply coarse mass matrix
19330ef72598Sjeremylt    u_coarse.set_value(1.0)
19340ef72598Sjeremylt    op_mass_coarse.apply(u_coarse, v_coarse)
19350ef72598Sjeremylt
19360ef72598Sjeremylt    # Check
19370ef72598Sjeremylt    with v_coarse.array_read() as v_array:
19380ef72598Sjeremylt        total = 0.0
19390ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
19400ef72598Sjeremylt            total = total + v_array[i]
194180a9ef05SNatalie Beams        assert abs(total - 1.0) < TOL
19420ef72598Sjeremylt
19430ef72598Sjeremylt    # Prolong coarse u
19440ef72598Sjeremylt    op_prolong.apply(u_coarse, u_fine)
19450ef72598Sjeremylt
19460ef72598Sjeremylt    # Apply mass matrix
19470ef72598Sjeremylt    op_mass_fine.apply(u_fine, v_fine)
19480ef72598Sjeremylt
19490ef72598Sjeremylt    # Check
19500ef72598Sjeremylt    with v_fine.array_read() as v_array:
19510ef72598Sjeremylt        total = 0.0
19520ef72598Sjeremylt        for i in range(nu_fine * ncomp):
19530ef72598Sjeremylt            total = total + v_array[i]
195480a9ef05SNatalie Beams        assert abs(total - 1.0) < TOL
19550ef72598Sjeremylt
19560ef72598Sjeremylt    # Restrict state to coarse grid
19570ef72598Sjeremylt    op_restrict.apply(v_fine, v_coarse)
19580ef72598Sjeremylt
19590ef72598Sjeremylt    # Check
19600ef72598Sjeremylt    with v_coarse.array_read() as v_array:
19610ef72598Sjeremylt        total = 0.0
19620ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
19630ef72598Sjeremylt            total = total + v_array[i]
196480a9ef05SNatalie Beams        assert abs(total - 1.0) < TOL
19650ef72598Sjeremylt
19660ef72598Sjeremylt# -------------------------------------------------------------------------------
1967