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