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