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