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