xref: /libCEED/python/tests/test-5-operator.py (revision 0ef725981a32b9079ff6c5100673b913b8f4d7c0) !
1*0ef72598Sjeremylt# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2*0ef72598Sjeremylt# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3*0ef72598Sjeremylt# reserved. See files LICENSE and NOTICE for details.
4*0ef72598Sjeremylt#
5*0ef72598Sjeremylt# This file is part of CEED, a collection of benchmarks, miniapps, software
6*0ef72598Sjeremylt# libraries and APIs for efficient high-order finite element and spectral
7*0ef72598Sjeremylt# element discretizations for exascale applications. For more information and
8*0ef72598Sjeremylt# source code availability see http://github.com/ceed.
9*0ef72598Sjeremylt#
10*0ef72598Sjeremylt# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11*0ef72598Sjeremylt# a collaborative effort of two U.S. Department of Energy organizations (Office
12*0ef72598Sjeremylt# of Science and the National Nuclear Security Administration) responsible for
13*0ef72598Sjeremylt# the planning and preparation of a capable exascale ecosystem, including
14*0ef72598Sjeremylt# software, applications, hardware, advanced system engineering and early
15*0ef72598Sjeremylt# testbed platforms, in support of the nation's exascale computing imperative.
16*0ef72598Sjeremylt
17*0ef72598Sjeremylt# @file
18*0ef72598Sjeremylt# Test Ceed Operator functionality
19*0ef72598Sjeremylt
20*0ef72598Sjeremyltimport os
21*0ef72598Sjeremyltimport libceed
22*0ef72598Sjeremyltimport numpy as np
23*0ef72598Sjeremyltimport check
24*0ef72598Sjeremyltimport buildmats as bm
25*0ef72598Sjeremylt
26*0ef72598SjeremyltTOL = np.finfo(float).eps * 256
27*0ef72598Sjeremylt
28*0ef72598Sjeremylt# -------------------------------------------------------------------------------
29*0ef72598Sjeremylt# Utility
30*0ef72598Sjeremylt# -------------------------------------------------------------------------------
31*0ef72598Sjeremylt
32*0ef72598Sjeremylt
33*0ef72598Sjeremyltdef load_qfs_so():
34*0ef72598Sjeremylt    from distutils.sysconfig import get_config_var
35*0ef72598Sjeremylt    import ctypes
36*0ef72598Sjeremylt
37*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
38*0ef72598Sjeremylt    qfs_so = os.path.join(
39*0ef72598Sjeremylt        file_dir,
40*0ef72598Sjeremylt        "libceed_qfunctions" + get_config_var("EXT_SUFFIX"))
41*0ef72598Sjeremylt
42*0ef72598Sjeremylt    # Load library
43*0ef72598Sjeremylt    return ctypes.cdll.LoadLibrary(qfs_so)
44*0ef72598Sjeremylt
45*0ef72598Sjeremylt# -------------------------------------------------------------------------------
46*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
47*0ef72598Sjeremylt# -------------------------------------------------------------------------------
48*0ef72598Sjeremylt
49*0ef72598Sjeremylt
50*0ef72598Sjeremyltdef test_500(ceed_resource):
51*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
52*0ef72598Sjeremylt
53*0ef72598Sjeremylt    nelem = 15
54*0ef72598Sjeremylt    p = 5
55*0ef72598Sjeremylt    q = 8
56*0ef72598Sjeremylt    nx = nelem + 1
57*0ef72598Sjeremylt    nu = nelem * (p - 1) + 1
58*0ef72598Sjeremylt
59*0ef72598Sjeremylt    # Vectors
60*0ef72598Sjeremylt    x = ceed.Vector(nx)
61*0ef72598Sjeremylt    x_array = np.zeros(nx)
62*0ef72598Sjeremylt    for i in range(nx):
63*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
64*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
65*0ef72598Sjeremylt
66*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
67*0ef72598Sjeremylt    u = ceed.Vector(nu)
68*0ef72598Sjeremylt    v = ceed.Vector(nu)
69*0ef72598Sjeremylt
70*0ef72598Sjeremylt    # Restrictions
71*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
72*0ef72598Sjeremylt    for i in range(nx):
73*0ef72598Sjeremylt        indx[2 * i + 0] = i
74*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
75*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
76*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
77*0ef72598Sjeremylt
78*0ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
79*0ef72598Sjeremylt    for i in range(nelem):
80*0ef72598Sjeremylt        for j in range(p):
81*0ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
82*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
83*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
84*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
85*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
86*0ef72598Sjeremylt
87*0ef72598Sjeremylt    # Bases
88*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
89*0ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
90*0ef72598Sjeremylt
91*0ef72598Sjeremylt    # QFunctions
92*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
93*0ef72598Sjeremylt    qfs = load_qfs_so()
94*0ef72598Sjeremylt
95*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
96*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
97*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
98*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
99*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
100*0ef72598Sjeremylt
101*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
102*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
103*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
104*0ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
105*0ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
106*0ef72598Sjeremylt
107*0ef72598Sjeremylt    # Operators
108*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
109*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
110*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
111*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
112*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
113*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
114*0ef72598Sjeremylt
115*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
116*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
117*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
118*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
119*0ef72598Sjeremylt
120*0ef72598Sjeremylt    # Setup
121*0ef72598Sjeremylt    op_setup.apply(x, qdata)
122*0ef72598Sjeremylt
123*0ef72598Sjeremylt    # Apply mass matrix
124*0ef72598Sjeremylt    u.set_value(0)
125*0ef72598Sjeremylt    op_mass.apply(u, v)
126*0ef72598Sjeremylt
127*0ef72598Sjeremylt    # Check
128*0ef72598Sjeremylt    with v.array_read() as v_array:
129*0ef72598Sjeremylt        for i in range(q):
130*0ef72598Sjeremylt            assert abs(v_array[i]) < TOL
131*0ef72598Sjeremylt
132*0ef72598Sjeremylt# -------------------------------------------------------------------------------
133*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
134*0ef72598Sjeremylt# -------------------------------------------------------------------------------
135*0ef72598Sjeremylt
136*0ef72598Sjeremylt
137*0ef72598Sjeremyltdef test_501(ceed_resource):
138*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
139*0ef72598Sjeremylt
140*0ef72598Sjeremylt    nelem = 15
141*0ef72598Sjeremylt    p = 5
142*0ef72598Sjeremylt    q = 8
143*0ef72598Sjeremylt    nx = nelem + 1
144*0ef72598Sjeremylt    nu = nelem * (p - 1) + 1
145*0ef72598Sjeremylt
146*0ef72598Sjeremylt    # Vectors
147*0ef72598Sjeremylt    x = ceed.Vector(nx)
148*0ef72598Sjeremylt    x_array = np.zeros(nx)
149*0ef72598Sjeremylt    for i in range(nx):
150*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
151*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
152*0ef72598Sjeremylt
153*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
154*0ef72598Sjeremylt    u = ceed.Vector(nu)
155*0ef72598Sjeremylt    v = ceed.Vector(nu)
156*0ef72598Sjeremylt
157*0ef72598Sjeremylt    # Restrictions
158*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
159*0ef72598Sjeremylt    for i in range(nx):
160*0ef72598Sjeremylt        indx[2 * i + 0] = i
161*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
162*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
163*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
164*0ef72598Sjeremylt
165*0ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
166*0ef72598Sjeremylt    for i in range(nelem):
167*0ef72598Sjeremylt        for j in range(p):
168*0ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
169*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
170*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
171*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
172*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
173*0ef72598Sjeremylt
174*0ef72598Sjeremylt    # Bases
175*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
176*0ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
177*0ef72598Sjeremylt
178*0ef72598Sjeremylt    # QFunctions
179*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
180*0ef72598Sjeremylt    qfs = load_qfs_so()
181*0ef72598Sjeremylt
182*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
183*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
184*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
185*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
186*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
187*0ef72598Sjeremylt
188*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
189*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
190*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
191*0ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
192*0ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
193*0ef72598Sjeremylt
194*0ef72598Sjeremylt    # Operators
195*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
196*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
197*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
198*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
199*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
200*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
201*0ef72598Sjeremylt
202*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
203*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
204*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
205*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
206*0ef72598Sjeremylt
207*0ef72598Sjeremylt    # Setup
208*0ef72598Sjeremylt    op_setup.apply(x, qdata)
209*0ef72598Sjeremylt
210*0ef72598Sjeremylt    # Apply mass matrix
211*0ef72598Sjeremylt    u.set_value(1.)
212*0ef72598Sjeremylt    op_mass.apply(u, v)
213*0ef72598Sjeremylt
214*0ef72598Sjeremylt    # Check
215*0ef72598Sjeremylt    with v.array_read() as v_array:
216*0ef72598Sjeremylt        total = 0.0
217*0ef72598Sjeremylt        for i in range(nu):
218*0ef72598Sjeremylt            total = total + v_array[i]
219*0ef72598Sjeremylt        assert abs(total - 1.0) < TOL
220*0ef72598Sjeremylt
221*0ef72598Sjeremylt# -------------------------------------------------------------------------------
222*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with multiple
223*0ef72598Sjeremylt#   components
224*0ef72598Sjeremylt# -------------------------------------------------------------------------------
225*0ef72598Sjeremylt
226*0ef72598Sjeremylt
227*0ef72598Sjeremyltdef test_502(ceed_resource):
228*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
229*0ef72598Sjeremylt
230*0ef72598Sjeremylt    nelem = 15
231*0ef72598Sjeremylt    p = 5
232*0ef72598Sjeremylt    q = 8
233*0ef72598Sjeremylt    nx = nelem + 1
234*0ef72598Sjeremylt    nu = nelem * (p - 1) + 1
235*0ef72598Sjeremylt
236*0ef72598Sjeremylt    # Vectors
237*0ef72598Sjeremylt    x = ceed.Vector(nx)
238*0ef72598Sjeremylt    x_array = np.zeros(nx)
239*0ef72598Sjeremylt    for i in range(nx):
240*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
241*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
242*0ef72598Sjeremylt
243*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
244*0ef72598Sjeremylt    u = ceed.Vector(2 * nu)
245*0ef72598Sjeremylt    v = ceed.Vector(2 * nu)
246*0ef72598Sjeremylt
247*0ef72598Sjeremylt    # Restrictions
248*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
249*0ef72598Sjeremylt    for i in range(nx):
250*0ef72598Sjeremylt        indx[2 * i + 0] = i
251*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
252*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
253*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
254*0ef72598Sjeremylt
255*0ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
256*0ef72598Sjeremylt    for i in range(nelem):
257*0ef72598Sjeremylt        for j in range(p):
258*0ef72598Sjeremylt            indu[p * i + j] = 2 * (i * (p - 1) + j)
259*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 2, 1, 2 * nu, indu,
260*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
261*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
262*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
263*0ef72598Sjeremylt
264*0ef72598Sjeremylt    # Bases
265*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
266*0ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 2, p, q, libceed.GAUSS)
267*0ef72598Sjeremylt
268*0ef72598Sjeremylt    # QFunctions
269*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
270*0ef72598Sjeremylt    qfs = load_qfs_so()
271*0ef72598Sjeremylt
272*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
273*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
274*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
275*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
276*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
277*0ef72598Sjeremylt
278*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass_two,
279*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass_two"))
280*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
281*0ef72598Sjeremylt    qf_mass.add_input("u", 2, libceed.EVAL_INTERP)
282*0ef72598Sjeremylt    qf_mass.add_output("v", 2, libceed.EVAL_INTERP)
283*0ef72598Sjeremylt
284*0ef72598Sjeremylt    # Operators
285*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
286*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
287*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
288*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
289*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
290*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
291*0ef72598Sjeremylt
292*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
293*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
294*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
295*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
296*0ef72598Sjeremylt
297*0ef72598Sjeremylt    # Setup
298*0ef72598Sjeremylt    op_setup.apply(x, qdata)
299*0ef72598Sjeremylt
300*0ef72598Sjeremylt    # Apply mass matrix
301*0ef72598Sjeremylt    with u.array() as u_array:
302*0ef72598Sjeremylt        for i in range(nu):
303*0ef72598Sjeremylt            u_array[2 * i] = 1.
304*0ef72598Sjeremylt            u_array[2 * i + 1] = 2.
305*0ef72598Sjeremylt    op_mass.apply(u, v)
306*0ef72598Sjeremylt
307*0ef72598Sjeremylt    # Check
308*0ef72598Sjeremylt    with v.array_read() as v_array:
309*0ef72598Sjeremylt        total_1 = 0.0
310*0ef72598Sjeremylt        total_2 = 0.0
311*0ef72598Sjeremylt        for i in range(nu):
312*0ef72598Sjeremylt            total_1 = total_1 + v_array[2 * i]
313*0ef72598Sjeremylt            total_2 = total_2 + v_array[2 * i + 1]
314*0ef72598Sjeremylt        assert abs(total_1 - 1.0) < 1E-13
315*0ef72598Sjeremylt        assert abs(total_2 - 2.0) < 1E-13
316*0ef72598Sjeremylt
317*0ef72598Sjeremylt# -------------------------------------------------------------------------------
318*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with passive
319*0ef72598Sjeremylt#   inputs and outputs
320*0ef72598Sjeremylt# -------------------------------------------------------------------------------
321*0ef72598Sjeremylt
322*0ef72598Sjeremylt
323*0ef72598Sjeremyltdef test_503(ceed_resource):
324*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
325*0ef72598Sjeremylt
326*0ef72598Sjeremylt    nelem = 15
327*0ef72598Sjeremylt    p = 5
328*0ef72598Sjeremylt    q = 8
329*0ef72598Sjeremylt    nx = nelem + 1
330*0ef72598Sjeremylt    nu = nelem * (p - 1) + 1
331*0ef72598Sjeremylt
332*0ef72598Sjeremylt    # Vectors
333*0ef72598Sjeremylt    x = ceed.Vector(nx)
334*0ef72598Sjeremylt    x_array = np.zeros(nx)
335*0ef72598Sjeremylt    for i in range(nx):
336*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
337*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
338*0ef72598Sjeremylt
339*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
340*0ef72598Sjeremylt    u = ceed.Vector(nu)
341*0ef72598Sjeremylt    v = ceed.Vector(nu)
342*0ef72598Sjeremylt
343*0ef72598Sjeremylt    # Restrictions
344*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
345*0ef72598Sjeremylt    for i in range(nx):
346*0ef72598Sjeremylt        indx[2 * i + 0] = i
347*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
348*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
349*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
350*0ef72598Sjeremylt
351*0ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
352*0ef72598Sjeremylt    for i in range(nelem):
353*0ef72598Sjeremylt        for j in range(p):
354*0ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
355*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
356*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
357*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
358*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
359*0ef72598Sjeremylt
360*0ef72598Sjeremylt    # Bases
361*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
362*0ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
363*0ef72598Sjeremylt
364*0ef72598Sjeremylt    # QFunctions
365*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
366*0ef72598Sjeremylt    qfs = load_qfs_so()
367*0ef72598Sjeremylt
368*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
369*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
370*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
371*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
372*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
373*0ef72598Sjeremylt
374*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
375*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
376*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
377*0ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
378*0ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
379*0ef72598Sjeremylt
380*0ef72598Sjeremylt    # Operators
381*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
382*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
383*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
384*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
385*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
386*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
387*0ef72598Sjeremylt
388*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
389*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
390*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, u)
391*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, v)
392*0ef72598Sjeremylt
393*0ef72598Sjeremylt    # Setup
394*0ef72598Sjeremylt    op_setup.apply(x, qdata)
395*0ef72598Sjeremylt
396*0ef72598Sjeremylt    # Apply mass matrix
397*0ef72598Sjeremylt    u.set_value(1)
398*0ef72598Sjeremylt    op_mass.apply(libceed.VECTOR_NONE, libceed.VECTOR_NONE)
399*0ef72598Sjeremylt
400*0ef72598Sjeremylt    # Check
401*0ef72598Sjeremylt    with v.array_read() as v_array:
402*0ef72598Sjeremylt        total = 0.0
403*0ef72598Sjeremylt        for i in range(nu):
404*0ef72598Sjeremylt            total = total + v_array[i]
405*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-13
406*0ef72598Sjeremylt
407*0ef72598Sjeremylt# -------------------------------------------------------------------------------
408*0ef72598Sjeremylt# Test viewing of mass matrix operator
409*0ef72598Sjeremylt# -------------------------------------------------------------------------------
410*0ef72598Sjeremylt
411*0ef72598Sjeremylt
412*0ef72598Sjeremyltdef test_504(ceed_resource, capsys):
413*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
414*0ef72598Sjeremylt
415*0ef72598Sjeremylt    nelem = 15
416*0ef72598Sjeremylt    p = 5
417*0ef72598Sjeremylt    q = 8
418*0ef72598Sjeremylt    nx = nelem + 1
419*0ef72598Sjeremylt    nu = nelem * (p - 1) + 1
420*0ef72598Sjeremylt
421*0ef72598Sjeremylt    # Vectors
422*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
423*0ef72598Sjeremylt
424*0ef72598Sjeremylt    # Restrictions
425*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
426*0ef72598Sjeremylt    for i in range(nx):
427*0ef72598Sjeremylt        indx[2 * i + 0] = i
428*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
429*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
430*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
431*0ef72598Sjeremylt
432*0ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
433*0ef72598Sjeremylt    for i in range(nelem):
434*0ef72598Sjeremylt        for j in range(p):
435*0ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
436*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
437*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
438*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
439*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
440*0ef72598Sjeremylt
441*0ef72598Sjeremylt    # Bases
442*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
443*0ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
444*0ef72598Sjeremylt
445*0ef72598Sjeremylt    # QFunctions
446*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
447*0ef72598Sjeremylt    qfs = load_qfs_so()
448*0ef72598Sjeremylt
449*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
450*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
451*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
452*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
453*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
454*0ef72598Sjeremylt
455*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
456*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
457*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
458*0ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
459*0ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
460*0ef72598Sjeremylt
461*0ef72598Sjeremylt    # Operators
462*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
463*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
464*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
465*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
466*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
467*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
468*0ef72598Sjeremylt
469*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
470*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
471*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
472*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
473*0ef72598Sjeremylt
474*0ef72598Sjeremylt    # View
475*0ef72598Sjeremylt    print(op_setup)
476*0ef72598Sjeremylt    print(op_mass)
477*0ef72598Sjeremylt
478*0ef72598Sjeremylt    stdout, stderr, ref_stdout = check.output(capsys)
479*0ef72598Sjeremylt    assert not stderr
480*0ef72598Sjeremylt    assert stdout == ref_stdout
481*0ef72598Sjeremylt
482*0ef72598Sjeremylt# -------------------------------------------------------------------------------
483*0ef72598Sjeremylt# Test CeedOperatorApplyAdd
484*0ef72598Sjeremylt# -------------------------------------------------------------------------------
485*0ef72598Sjeremylt
486*0ef72598Sjeremylt
487*0ef72598Sjeremyltdef test_505(ceed_resource):
488*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
489*0ef72598Sjeremylt
490*0ef72598Sjeremylt    nelem = 15
491*0ef72598Sjeremylt    p = 5
492*0ef72598Sjeremylt    q = 8
493*0ef72598Sjeremylt    nx = nelem + 1
494*0ef72598Sjeremylt    nu = nelem * (p - 1) + 1
495*0ef72598Sjeremylt
496*0ef72598Sjeremylt    # Vectors
497*0ef72598Sjeremylt    x = ceed.Vector(nx)
498*0ef72598Sjeremylt    x_array = np.zeros(nx)
499*0ef72598Sjeremylt    for i in range(nx):
500*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
501*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
502*0ef72598Sjeremylt
503*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
504*0ef72598Sjeremylt    u = ceed.Vector(nu)
505*0ef72598Sjeremylt    v = ceed.Vector(nu)
506*0ef72598Sjeremylt
507*0ef72598Sjeremylt    # Restrictions
508*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
509*0ef72598Sjeremylt    for i in range(nx):
510*0ef72598Sjeremylt        indx[2 * i + 0] = i
511*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
512*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
513*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
514*0ef72598Sjeremylt
515*0ef72598Sjeremylt    indu = np.zeros(nelem * p, dtype="int32")
516*0ef72598Sjeremylt    for i in range(nelem):
517*0ef72598Sjeremylt        for j in range(p):
518*0ef72598Sjeremylt            indu[p * i + j] = i * (p - 1) + j
519*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu,
520*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
521*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
522*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
523*0ef72598Sjeremylt
524*0ef72598Sjeremylt    # Bases
525*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
526*0ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)
527*0ef72598Sjeremylt
528*0ef72598Sjeremylt    # QFunctions
529*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
530*0ef72598Sjeremylt    qfs = load_qfs_so()
531*0ef72598Sjeremylt
532*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
533*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
534*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
535*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
536*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
537*0ef72598Sjeremylt
538*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
539*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
540*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
541*0ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
542*0ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
543*0ef72598Sjeremylt
544*0ef72598Sjeremylt    # Operators
545*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
546*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
547*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
548*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
549*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
550*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
551*0ef72598Sjeremylt
552*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
553*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
554*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
555*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
556*0ef72598Sjeremylt
557*0ef72598Sjeremylt    # Setup
558*0ef72598Sjeremylt    op_setup.apply(x, qdata)
559*0ef72598Sjeremylt
560*0ef72598Sjeremylt    # Apply mass matrix with v = 0
561*0ef72598Sjeremylt    u.set_value(1.)
562*0ef72598Sjeremylt    v.set_value(0.)
563*0ef72598Sjeremylt    op_mass.apply_add(u, v)
564*0ef72598Sjeremylt
565*0ef72598Sjeremylt    # Check
566*0ef72598Sjeremylt    with v.array_read() as v_array:
567*0ef72598Sjeremylt        total = 0.0
568*0ef72598Sjeremylt        for i in range(nu):
569*0ef72598Sjeremylt            total = total + v_array[i]
570*0ef72598Sjeremylt        assert abs(total - 1.0) < TOL
571*0ef72598Sjeremylt
572*0ef72598Sjeremylt    # Apply mass matrix with v = 0
573*0ef72598Sjeremylt    v.set_value(1.)
574*0ef72598Sjeremylt    op_mass.apply_add(u, v)
575*0ef72598Sjeremylt
576*0ef72598Sjeremylt    # Check
577*0ef72598Sjeremylt    with v.array_read() as v_array:
578*0ef72598Sjeremylt        total = -nu
579*0ef72598Sjeremylt        for i in range(nu):
580*0ef72598Sjeremylt            total = total + v_array[i]
581*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-10
582*0ef72598Sjeremylt
583*0ef72598Sjeremylt# -------------------------------------------------------------------------------
584*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
585*0ef72598Sjeremylt# -------------------------------------------------------------------------------
586*0ef72598Sjeremylt
587*0ef72598Sjeremylt
588*0ef72598Sjeremyltdef test_510(ceed_resource):
589*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
590*0ef72598Sjeremylt
591*0ef72598Sjeremylt    nelem = 12
592*0ef72598Sjeremylt    dim = 2
593*0ef72598Sjeremylt    p = 6
594*0ef72598Sjeremylt    q = 4
595*0ef72598Sjeremylt    nx, ny = 3, 2
596*0ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
597*0ef72598Sjeremylt    nqpts = nelem * q
598*0ef72598Sjeremylt
599*0ef72598Sjeremylt    # Vectors
600*0ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
601*0ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
602*0ef72598Sjeremylt    for i in range(ndofs):
603*0ef72598Sjeremylt        x_array[i] = (1. / (nx * 2)) * (i % (nx * 2 + 1))
604*0ef72598Sjeremylt        x_array[i + ndofs] = (1. / (ny * 2)) * (i / (nx * 2 + 1))
605*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
606*0ef72598Sjeremylt
607*0ef72598Sjeremylt    qdata = ceed.Vector(nqpts)
608*0ef72598Sjeremylt    u = ceed.Vector(ndofs)
609*0ef72598Sjeremylt    v = ceed.Vector(ndofs)
610*0ef72598Sjeremylt
611*0ef72598Sjeremylt    # Restrictions
612*0ef72598Sjeremylt    indx = np.zeros(nelem * p, dtype="int32")
613*0ef72598Sjeremylt    for i in range(nelem // 2):
614*0ef72598Sjeremylt        col = i % nx
615*0ef72598Sjeremylt        row = i // nx
616*0ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
617*0ef72598Sjeremylt
618*0ef72598Sjeremylt        indx[i * 2 * p + 0] = 2 + offset
619*0ef72598Sjeremylt        indx[i * 2 * p + 1] = 9 + offset
620*0ef72598Sjeremylt        indx[i * 2 * p + 2] = 16 + offset
621*0ef72598Sjeremylt        indx[i * 2 * p + 3] = 1 + offset
622*0ef72598Sjeremylt        indx[i * 2 * p + 4] = 8 + offset
623*0ef72598Sjeremylt        indx[i * 2 * p + 5] = 0 + offset
624*0ef72598Sjeremylt
625*0ef72598Sjeremylt        indx[i * 2 * p + 6] = 14 + offset
626*0ef72598Sjeremylt        indx[i * 2 * p + 7] = 7 + offset
627*0ef72598Sjeremylt        indx[i * 2 * p + 8] = 0 + offset
628*0ef72598Sjeremylt        indx[i * 2 * p + 9] = 15 + offset
629*0ef72598Sjeremylt        indx[i * 2 * p + 10] = 8 + offset
630*0ef72598Sjeremylt        indx[i * 2 * p + 11] = 16 + offset
631*0ef72598Sjeremylt
632*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, p, dim, ndofs, dim * ndofs, indx,
633*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
634*0ef72598Sjeremylt
635*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, ndofs, indx,
636*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
637*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
638*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, nqpts, strides)
639*0ef72598Sjeremylt
640*0ef72598Sjeremylt    # Bases
641*0ef72598Sjeremylt    qref = np.empty(dim * q, dtype="float64")
642*0ef72598Sjeremylt    qweight = np.empty(q, dtype="float64")
643*0ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
644*0ef72598Sjeremylt
645*0ef72598Sjeremylt    bx = ceed.BasisH1(libceed.TRIANGLE, dim, p, q, interp, grad, qref, qweight)
646*0ef72598Sjeremylt    bu = ceed.BasisH1(libceed.TRIANGLE, 1, p, q, interp, grad, qref, qweight)
647*0ef72598Sjeremylt
648*0ef72598Sjeremylt    # QFunctions
649*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
650*0ef72598Sjeremylt    qfs = load_qfs_so()
651*0ef72598Sjeremylt
652*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass_2d,
653*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
654*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
655*0ef72598Sjeremylt    qf_setup.add_input("dx", dim * dim, libceed.EVAL_GRAD)
656*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
657*0ef72598Sjeremylt
658*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
659*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
660*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
661*0ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
662*0ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
663*0ef72598Sjeremylt
664*0ef72598Sjeremylt    # Operators
665*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
666*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
667*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
668*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
669*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
670*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
671*0ef72598Sjeremylt
672*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
673*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
674*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
675*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
676*0ef72598Sjeremylt
677*0ef72598Sjeremylt    # Setup
678*0ef72598Sjeremylt    op_setup.apply(x, qdata)
679*0ef72598Sjeremylt
680*0ef72598Sjeremylt    # Apply mass matrix
681*0ef72598Sjeremylt    u.set_value(0.)
682*0ef72598Sjeremylt    op_mass.apply(u, v)
683*0ef72598Sjeremylt
684*0ef72598Sjeremylt    # Check
685*0ef72598Sjeremylt    with v.array_read() as v_array:
686*0ef72598Sjeremylt        for i in range(ndofs):
687*0ef72598Sjeremylt            assert abs(v_array[i]) < TOL
688*0ef72598Sjeremylt
689*0ef72598Sjeremylt# -------------------------------------------------------------------------------
690*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator
691*0ef72598Sjeremylt# -------------------------------------------------------------------------------
692*0ef72598Sjeremylt
693*0ef72598Sjeremylt
694*0ef72598Sjeremyltdef test_511(ceed_resource):
695*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
696*0ef72598Sjeremylt
697*0ef72598Sjeremylt    nelem = 12
698*0ef72598Sjeremylt    dim = 2
699*0ef72598Sjeremylt    p = 6
700*0ef72598Sjeremylt    q = 4
701*0ef72598Sjeremylt    nx, ny = 3, 2
702*0ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
703*0ef72598Sjeremylt    nqpts = nelem * q
704*0ef72598Sjeremylt
705*0ef72598Sjeremylt    # Vectors
706*0ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
707*0ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
708*0ef72598Sjeremylt    for i in range(ndofs):
709*0ef72598Sjeremylt        x_array[i] = (1. / (nx * 2)) * (i % (nx * 2 + 1))
710*0ef72598Sjeremylt        x_array[i + ndofs] = (1. / (ny * 2)) * (i / (nx * 2 + 1))
711*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
712*0ef72598Sjeremylt
713*0ef72598Sjeremylt    qdata = ceed.Vector(nqpts)
714*0ef72598Sjeremylt    u = ceed.Vector(ndofs)
715*0ef72598Sjeremylt    v = ceed.Vector(ndofs)
716*0ef72598Sjeremylt
717*0ef72598Sjeremylt    # Restrictions
718*0ef72598Sjeremylt    indx = np.zeros(nelem * p, dtype="int32")
719*0ef72598Sjeremylt    for i in range(nelem // 2):
720*0ef72598Sjeremylt        col = i % nx
721*0ef72598Sjeremylt        row = i // nx
722*0ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
723*0ef72598Sjeremylt
724*0ef72598Sjeremylt        indx[i * 2 * p + 0] = 2 + offset
725*0ef72598Sjeremylt        indx[i * 2 * p + 1] = 9 + offset
726*0ef72598Sjeremylt        indx[i * 2 * p + 2] = 16 + offset
727*0ef72598Sjeremylt        indx[i * 2 * p + 3] = 1 + offset
728*0ef72598Sjeremylt        indx[i * 2 * p + 4] = 8 + offset
729*0ef72598Sjeremylt        indx[i * 2 * p + 5] = 0 + offset
730*0ef72598Sjeremylt
731*0ef72598Sjeremylt        indx[i * 2 * p + 6] = 14 + offset
732*0ef72598Sjeremylt        indx[i * 2 * p + 7] = 7 + offset
733*0ef72598Sjeremylt        indx[i * 2 * p + 8] = 0 + offset
734*0ef72598Sjeremylt        indx[i * 2 * p + 9] = 15 + offset
735*0ef72598Sjeremylt        indx[i * 2 * p + 10] = 8 + offset
736*0ef72598Sjeremylt        indx[i * 2 * p + 11] = 16 + offset
737*0ef72598Sjeremylt
738*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, p, dim, ndofs, dim * ndofs, indx,
739*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
740*0ef72598Sjeremylt
741*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p, 1, 1, ndofs, indx,
742*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
743*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
744*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, nqpts, strides)
745*0ef72598Sjeremylt
746*0ef72598Sjeremylt    # Bases
747*0ef72598Sjeremylt    qref = np.empty(dim * q, dtype="float64")
748*0ef72598Sjeremylt    qweight = np.empty(q, dtype="float64")
749*0ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
750*0ef72598Sjeremylt
751*0ef72598Sjeremylt    bx = ceed.BasisH1(libceed.TRIANGLE, dim, p, q, interp, grad, qref, qweight)
752*0ef72598Sjeremylt    bu = ceed.BasisH1(libceed.TRIANGLE, 1, p, q, interp, grad, qref, qweight)
753*0ef72598Sjeremylt
754*0ef72598Sjeremylt    # QFunctions
755*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
756*0ef72598Sjeremylt    qfs = load_qfs_so()
757*0ef72598Sjeremylt
758*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass_2d,
759*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
760*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
761*0ef72598Sjeremylt    qf_setup.add_input("dx", dim * dim, libceed.EVAL_GRAD)
762*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
763*0ef72598Sjeremylt
764*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass,
765*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
766*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
767*0ef72598Sjeremylt    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
768*0ef72598Sjeremylt    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
769*0ef72598Sjeremylt
770*0ef72598Sjeremylt    # Operators
771*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
772*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
773*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
774*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
775*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
776*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
777*0ef72598Sjeremylt
778*0ef72598Sjeremylt    op_mass = ceed.Operator(qf_mass)
779*0ef72598Sjeremylt    op_mass.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
780*0ef72598Sjeremylt    op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
781*0ef72598Sjeremylt    op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
782*0ef72598Sjeremylt
783*0ef72598Sjeremylt    # Setup
784*0ef72598Sjeremylt    op_setup.apply(x, qdata)
785*0ef72598Sjeremylt
786*0ef72598Sjeremylt    # Apply mass matrix
787*0ef72598Sjeremylt    u.set_value(1.)
788*0ef72598Sjeremylt    op_mass.apply(u, v)
789*0ef72598Sjeremylt
790*0ef72598Sjeremylt    # Check
791*0ef72598Sjeremylt    with v.array_read() as v_array:
792*0ef72598Sjeremylt        total = 0.0
793*0ef72598Sjeremylt        for i in range(ndofs):
794*0ef72598Sjeremylt            total = total + v_array[i]
795*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-10
796*0ef72598Sjeremylt
797*0ef72598Sjeremylt# -------------------------------------------------------------------------------
798*0ef72598Sjeremylt# Test creation, action, and destruction for composite mass matrix operator
799*0ef72598Sjeremylt# -------------------------------------------------------------------------------
800*0ef72598Sjeremylt
801*0ef72598Sjeremylt
802*0ef72598Sjeremyltdef test_520(ceed_resource):
803*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
804*0ef72598Sjeremylt
805*0ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
806*0ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
807*0ef72598Sjeremylt    nx, ny = 3, 3
808*0ef72598Sjeremylt    dim = 2
809*0ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
810*0ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
811*0ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
812*0ef72598Sjeremylt
813*0ef72598Sjeremylt    # Vectors
814*0ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
815*0ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
816*0ef72598Sjeremylt    for i in range(ny * 2 + 1):
817*0ef72598Sjeremylt        for j in range(nx * 2 + 1):
818*0ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1)] = i / (2 * ny)
819*0ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1) + ndofs] = j / (2 * nx)
820*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
821*0ef72598Sjeremylt
822*0ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
823*0ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
824*0ef72598Sjeremylt    u = ceed.Vector(ndofs)
825*0ef72598Sjeremylt    v = ceed.Vector(ndofs)
826*0ef72598Sjeremylt
827*0ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
828*0ef72598Sjeremylt
829*0ef72598Sjeremylt    # Restrictions
830*0ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
831*0ef72598Sjeremylt    for i in range(nelem_tet // 2):
832*0ef72598Sjeremylt        col = i % nx
833*0ef72598Sjeremylt        row = i // nx
834*0ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
835*0ef72598Sjeremylt
836*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
837*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
838*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
839*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
840*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
841*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
842*0ef72598Sjeremylt
843*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
844*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
845*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
846*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
847*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
848*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
849*0ef72598Sjeremylt
850*0ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
851*0ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
852*0ef72598Sjeremylt
853*0ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
854*0ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
855*0ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
856*0ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
857*0ef72598Sjeremylt                                          strides)
858*0ef72598Sjeremylt
859*0ef72598Sjeremylt    # Bases
860*0ef72598Sjeremylt    qref = np.empty(dim * q_tet, dtype="float64")
861*0ef72598Sjeremylt    qweight = np.empty(q_tet, dtype="float64")
862*0ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
863*0ef72598Sjeremylt
864*0ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
865*0ef72598Sjeremylt                          qweight)
866*0ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
867*0ef72598Sjeremylt                          qweight)
868*0ef72598Sjeremylt
869*0ef72598Sjeremylt    # QFunctions
870*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
871*0ef72598Sjeremylt    qfs = load_qfs_so()
872*0ef72598Sjeremylt
873*0ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
874*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
875*0ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
876*0ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
877*0ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
878*0ef72598Sjeremylt
879*0ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
880*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
881*0ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
882*0ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
883*0ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
884*0ef72598Sjeremylt
885*0ef72598Sjeremylt    # Operators
886*0ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
887*0ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
888*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
889*0ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
890*0ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
891*0ef72598Sjeremylt                           qdata_tet)
892*0ef72598Sjeremylt
893*0ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
894*0ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
895*0ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
896*0ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
897*0ef72598Sjeremylt
898*0ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
899*0ef72598Sjeremylt
900*0ef72598Sjeremylt    # Restrictions
901*0ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
902*0ef72598Sjeremylt    for i in range(nelem_hex):
903*0ef72598Sjeremylt        col = i % nx_hex
904*0ef72598Sjeremylt        row = i // nx_hex
905*0ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
906*0ef72598Sjeremylt
907*0ef72598Sjeremylt        for j in range(p_hex):
908*0ef72598Sjeremylt            for k in range(p_hex):
909*0ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
910*0ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
911*0ef72598Sjeremylt
912*0ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
913*0ef72598Sjeremylt                                  dim * ndofs, indx_hex, cmode=libceed.USE_POINTER)
914*0ef72598Sjeremylt
915*0ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
916*0ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
917*0ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
918*0ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
919*0ef72598Sjeremylt                                          nqpts_hex, strides)
920*0ef72598Sjeremylt
921*0ef72598Sjeremylt    # Bases
922*0ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
923*0ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
924*0ef72598Sjeremylt
925*0ef72598Sjeremylt    # QFunctions
926*0ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
927*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
928*0ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
929*0ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
930*0ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
931*0ef72598Sjeremylt
932*0ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
933*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
934*0ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
935*0ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
936*0ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
937*0ef72598Sjeremylt
938*0ef72598Sjeremylt    # Operators
939*0ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
940*0ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
941*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
942*0ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
943*0ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
944*0ef72598Sjeremylt                           qdata_hex)
945*0ef72598Sjeremylt
946*0ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
947*0ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
948*0ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
949*0ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
950*0ef72598Sjeremylt
951*0ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
952*0ef72598Sjeremylt
953*0ef72598Sjeremylt    # Setup
954*0ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
955*0ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
956*0ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
957*0ef72598Sjeremylt    op_setup.apply(x, libceed.VECTOR_NONE)
958*0ef72598Sjeremylt
959*0ef72598Sjeremylt    # Apply mass matrix
960*0ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
961*0ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
962*0ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
963*0ef72598Sjeremylt
964*0ef72598Sjeremylt    u.set_value(0.)
965*0ef72598Sjeremylt    op_mass.apply(u, v)
966*0ef72598Sjeremylt
967*0ef72598Sjeremylt    # Check
968*0ef72598Sjeremylt    with v.array_read() as v_array:
969*0ef72598Sjeremylt        for i in range(ndofs):
970*0ef72598Sjeremylt            assert abs(v_array[i]) < TOL
971*0ef72598Sjeremylt
972*0ef72598Sjeremylt# -------------------------------------------------------------------------------
973*0ef72598Sjeremylt# Test creation, action, and destruction for composite mass matrix operator
974*0ef72598Sjeremylt# -------------------------------------------------------------------------------
975*0ef72598Sjeremylt
976*0ef72598Sjeremylt
977*0ef72598Sjeremyltdef test_521(ceed_resource):
978*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
979*0ef72598Sjeremylt
980*0ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
981*0ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
982*0ef72598Sjeremylt    nx, ny = 3, 3
983*0ef72598Sjeremylt    dim = 2
984*0ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
985*0ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
986*0ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
987*0ef72598Sjeremylt
988*0ef72598Sjeremylt    # Vectors
989*0ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
990*0ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
991*0ef72598Sjeremylt    for i in range(ny * 2 + 1):
992*0ef72598Sjeremylt        for j in range(nx * 2 + 1):
993*0ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1)] = i / (2 * ny)
994*0ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1) + ndofs] = j / (2 * nx)
995*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
996*0ef72598Sjeremylt
997*0ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
998*0ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
999*0ef72598Sjeremylt    u = ceed.Vector(ndofs)
1000*0ef72598Sjeremylt    v = ceed.Vector(ndofs)
1001*0ef72598Sjeremylt
1002*0ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
1003*0ef72598Sjeremylt
1004*0ef72598Sjeremylt    # Restrictions
1005*0ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
1006*0ef72598Sjeremylt    for i in range(nelem_tet // 2):
1007*0ef72598Sjeremylt        col = i % nx
1008*0ef72598Sjeremylt        row = i // nx
1009*0ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
1010*0ef72598Sjeremylt
1011*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
1012*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
1013*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
1014*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
1015*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
1016*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
1017*0ef72598Sjeremylt
1018*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
1019*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
1020*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
1021*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
1022*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
1023*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
1024*0ef72598Sjeremylt
1025*0ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
1026*0ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
1027*0ef72598Sjeremylt
1028*0ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
1029*0ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
1030*0ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
1031*0ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
1032*0ef72598Sjeremylt                                          strides)
1033*0ef72598Sjeremylt
1034*0ef72598Sjeremylt    # Bases
1035*0ef72598Sjeremylt    qref = np.empty(dim * q_tet, dtype="float64")
1036*0ef72598Sjeremylt    qweight = np.empty(q_tet, dtype="float64")
1037*0ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
1038*0ef72598Sjeremylt
1039*0ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
1040*0ef72598Sjeremylt                          qweight)
1041*0ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
1042*0ef72598Sjeremylt                          qweight)
1043*0ef72598Sjeremylt
1044*0ef72598Sjeremylt    # QFunctions
1045*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
1046*0ef72598Sjeremylt    qfs = load_qfs_so()
1047*0ef72598Sjeremylt
1048*0ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
1049*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
1050*0ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
1051*0ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
1052*0ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
1053*0ef72598Sjeremylt
1054*0ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
1055*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1056*0ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
1057*0ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
1058*0ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
1059*0ef72598Sjeremylt
1060*0ef72598Sjeremylt    # Operators
1061*0ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
1062*0ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
1063*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
1064*0ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
1065*0ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
1066*0ef72598Sjeremylt                           qdata_tet)
1067*0ef72598Sjeremylt
1068*0ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
1069*0ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
1070*0ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
1071*0ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
1072*0ef72598Sjeremylt
1073*0ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
1074*0ef72598Sjeremylt
1075*0ef72598Sjeremylt    # Restrictions
1076*0ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
1077*0ef72598Sjeremylt    for i in range(nelem_hex):
1078*0ef72598Sjeremylt        col = i % nx_hex
1079*0ef72598Sjeremylt        row = i // nx_hex
1080*0ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
1081*0ef72598Sjeremylt
1082*0ef72598Sjeremylt        for j in range(p_hex):
1083*0ef72598Sjeremylt            for k in range(p_hex):
1084*0ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
1085*0ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
1086*0ef72598Sjeremylt
1087*0ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
1088*0ef72598Sjeremylt                                  dim * ndofs, indx_hex, cmode=libceed.USE_POINTER)
1089*0ef72598Sjeremylt
1090*0ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
1091*0ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
1092*0ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
1093*0ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
1094*0ef72598Sjeremylt                                          nqpts_hex, strides)
1095*0ef72598Sjeremylt
1096*0ef72598Sjeremylt    # Bases
1097*0ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
1098*0ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
1099*0ef72598Sjeremylt
1100*0ef72598Sjeremylt    # QFunctions
1101*0ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
1102*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
1103*0ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
1104*0ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
1105*0ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
1106*0ef72598Sjeremylt
1107*0ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
1108*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1109*0ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
1110*0ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
1111*0ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
1112*0ef72598Sjeremylt
1113*0ef72598Sjeremylt    # Operators
1114*0ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
1115*0ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
1116*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
1117*0ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
1118*0ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
1119*0ef72598Sjeremylt                           qdata_hex)
1120*0ef72598Sjeremylt
1121*0ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
1122*0ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
1123*0ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
1124*0ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
1125*0ef72598Sjeremylt
1126*0ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
1127*0ef72598Sjeremylt
1128*0ef72598Sjeremylt    # Setup
1129*0ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
1130*0ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
1131*0ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
1132*0ef72598Sjeremylt    op_setup.apply(x, libceed.VECTOR_NONE)
1133*0ef72598Sjeremylt
1134*0ef72598Sjeremylt    # Apply mass matrix
1135*0ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
1136*0ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
1137*0ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
1138*0ef72598Sjeremylt    u.set_value(1.)
1139*0ef72598Sjeremylt    op_mass.apply(u, v)
1140*0ef72598Sjeremylt
1141*0ef72598Sjeremylt    # Check
1142*0ef72598Sjeremylt    with v.array_read() as v_array:
1143*0ef72598Sjeremylt        total = 0.0
1144*0ef72598Sjeremylt        for i in range(ndofs):
1145*0ef72598Sjeremylt            total = total + v_array[i]
1146*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-10
1147*0ef72598Sjeremylt
1148*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1149*0ef72598Sjeremylt# Test viewing of composite mass matrix operator
1150*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1151*0ef72598Sjeremylt
1152*0ef72598Sjeremylt
1153*0ef72598Sjeremyltdef test_523(ceed_resource, capsys):
1154*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1155*0ef72598Sjeremylt
1156*0ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
1157*0ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
1158*0ef72598Sjeremylt    nx, ny = 3, 3
1159*0ef72598Sjeremylt    dim = 2
1160*0ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
1161*0ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
1162*0ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
1163*0ef72598Sjeremylt
1164*0ef72598Sjeremylt    # Vectors
1165*0ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
1166*0ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
1167*0ef72598Sjeremylt
1168*0ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
1169*0ef72598Sjeremylt
1170*0ef72598Sjeremylt    # Restrictions
1171*0ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
1172*0ef72598Sjeremylt    for i in range(nelem_tet // 2):
1173*0ef72598Sjeremylt        col = i % nx
1174*0ef72598Sjeremylt        row = i // nx
1175*0ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
1176*0ef72598Sjeremylt
1177*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
1178*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
1179*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
1180*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
1181*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
1182*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
1183*0ef72598Sjeremylt
1184*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
1185*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
1186*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
1187*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
1188*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
1189*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
1190*0ef72598Sjeremylt
1191*0ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
1192*0ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
1193*0ef72598Sjeremylt
1194*0ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
1195*0ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
1196*0ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
1197*0ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
1198*0ef72598Sjeremylt                                          strides)
1199*0ef72598Sjeremylt
1200*0ef72598Sjeremylt    # Bases
1201*0ef72598Sjeremylt    qref = np.empty(dim * q_tet, dtype="float64")
1202*0ef72598Sjeremylt    qweight = np.empty(q_tet, dtype="float64")
1203*0ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
1204*0ef72598Sjeremylt
1205*0ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
1206*0ef72598Sjeremylt                          qweight)
1207*0ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
1208*0ef72598Sjeremylt                          qweight)
1209*0ef72598Sjeremylt
1210*0ef72598Sjeremylt    # QFunctions
1211*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
1212*0ef72598Sjeremylt    qfs = load_qfs_so()
1213*0ef72598Sjeremylt
1214*0ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
1215*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
1216*0ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
1217*0ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
1218*0ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
1219*0ef72598Sjeremylt
1220*0ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
1221*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1222*0ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
1223*0ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
1224*0ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
1225*0ef72598Sjeremylt
1226*0ef72598Sjeremylt    # Operators
1227*0ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
1228*0ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
1229*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
1230*0ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
1231*0ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
1232*0ef72598Sjeremylt                           qdata_tet)
1233*0ef72598Sjeremylt
1234*0ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
1235*0ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
1236*0ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
1237*0ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
1238*0ef72598Sjeremylt
1239*0ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
1240*0ef72598Sjeremylt
1241*0ef72598Sjeremylt    # Restrictions
1242*0ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
1243*0ef72598Sjeremylt    for i in range(nelem_hex):
1244*0ef72598Sjeremylt        col = i % nx_hex
1245*0ef72598Sjeremylt        row = i // nx_hex
1246*0ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
1247*0ef72598Sjeremylt
1248*0ef72598Sjeremylt        for j in range(p_hex):
1249*0ef72598Sjeremylt            for k in range(p_hex):
1250*0ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
1251*0ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
1252*0ef72598Sjeremylt
1253*0ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
1254*0ef72598Sjeremylt                                  dim * ndofs, indx_hex,
1255*0ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
1256*0ef72598Sjeremylt
1257*0ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
1258*0ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
1259*0ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
1260*0ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
1261*0ef72598Sjeremylt                                          nqpts_hex, strides)
1262*0ef72598Sjeremylt
1263*0ef72598Sjeremylt    # Bases
1264*0ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
1265*0ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
1266*0ef72598Sjeremylt
1267*0ef72598Sjeremylt    # QFunctions
1268*0ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
1269*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
1270*0ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
1271*0ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
1272*0ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
1273*0ef72598Sjeremylt
1274*0ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
1275*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1276*0ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
1277*0ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
1278*0ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
1279*0ef72598Sjeremylt
1280*0ef72598Sjeremylt    # Operators
1281*0ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
1282*0ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
1283*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
1284*0ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
1285*0ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
1286*0ef72598Sjeremylt                           qdata_hex)
1287*0ef72598Sjeremylt
1288*0ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
1289*0ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
1290*0ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
1291*0ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
1292*0ef72598Sjeremylt
1293*0ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
1294*0ef72598Sjeremylt
1295*0ef72598Sjeremylt    # Setup
1296*0ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
1297*0ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
1298*0ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
1299*0ef72598Sjeremylt
1300*0ef72598Sjeremylt    # Apply mass matrix
1301*0ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
1302*0ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
1303*0ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
1304*0ef72598Sjeremylt
1305*0ef72598Sjeremylt    # View
1306*0ef72598Sjeremylt    print(op_setup)
1307*0ef72598Sjeremylt    print(op_mass)
1308*0ef72598Sjeremylt
1309*0ef72598Sjeremylt    stdout, stderr, ref_stdout = check.output(capsys)
1310*0ef72598Sjeremylt    assert not stderr
1311*0ef72598Sjeremylt    assert stdout == ref_stdout
1312*0ef72598Sjeremylt
1313*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1314*0ef72598Sjeremylt# CeedOperatorApplyAdd for composite operator
1315*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1316*0ef72598Sjeremylt
1317*0ef72598Sjeremylt
1318*0ef72598Sjeremyltdef test_524(ceed_resource):
1319*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1320*0ef72598Sjeremylt
1321*0ef72598Sjeremylt    nelem_tet, p_tet, q_tet = 6, 6, 4
1322*0ef72598Sjeremylt    nelem_hex, p_hex, q_hex = 6, 3, 4
1323*0ef72598Sjeremylt    nx, ny = 3, 3
1324*0ef72598Sjeremylt    dim = 2
1325*0ef72598Sjeremylt    nx_tet, ny_tet, nx_hex = 3, 1, 3
1326*0ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
1327*0ef72598Sjeremylt    nqpts_tet, nqpts_hex = nelem_tet * q_tet, nelem_hex * q_hex * q_hex
1328*0ef72598Sjeremylt
1329*0ef72598Sjeremylt    # Vectors
1330*0ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
1331*0ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
1332*0ef72598Sjeremylt    for i in range(ny * 2 + 1):
1333*0ef72598Sjeremylt        for j in range(nx * 2 + 1):
1334*0ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1)] = i / (2 * ny)
1335*0ef72598Sjeremylt            x_array[i + j * (ny * 2 + 1) + ndofs] = j / (2 * nx)
1336*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
1337*0ef72598Sjeremylt
1338*0ef72598Sjeremylt    qdata_hex = ceed.Vector(nqpts_hex)
1339*0ef72598Sjeremylt    qdata_tet = ceed.Vector(nqpts_tet)
1340*0ef72598Sjeremylt    u = ceed.Vector(ndofs)
1341*0ef72598Sjeremylt    v = ceed.Vector(ndofs)
1342*0ef72598Sjeremylt
1343*0ef72598Sjeremylt    # ------------------------- Tet Elements -------------------------
1344*0ef72598Sjeremylt
1345*0ef72598Sjeremylt    # Restrictions
1346*0ef72598Sjeremylt    indx_tet = np.zeros(nelem_tet * p_tet, dtype="int32")
1347*0ef72598Sjeremylt    for i in range(nelem_tet // 2):
1348*0ef72598Sjeremylt        col = i % nx
1349*0ef72598Sjeremylt        row = i // nx
1350*0ef72598Sjeremylt        offset = col * 2 + row * (nx * 2 + 1) * 2
1351*0ef72598Sjeremylt
1352*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 0] = 2 + offset
1353*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 1] = 9 + offset
1354*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 2] = 16 + offset
1355*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 3] = 1 + offset
1356*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 4] = 8 + offset
1357*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 5] = 0 + offset
1358*0ef72598Sjeremylt
1359*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 6] = 14 + offset
1360*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 7] = 7 + offset
1361*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 8] = 0 + offset
1362*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 9] = 15 + offset
1363*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 10] = 8 + offset
1364*0ef72598Sjeremylt        indx_tet[i * 2 * p_tet + 11] = 16 + offset
1365*0ef72598Sjeremylt
1366*0ef72598Sjeremylt    rx_tet = ceed.ElemRestriction(nelem_tet, p_tet, dim, ndofs, dim * ndofs,
1367*0ef72598Sjeremylt                                  indx_tet, cmode=libceed.USE_POINTER)
1368*0ef72598Sjeremylt
1369*0ef72598Sjeremylt    ru_tet = ceed.ElemRestriction(nelem_tet, p_tet, 1, 1, ndofs, indx_tet,
1370*0ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
1371*0ef72598Sjeremylt    strides = np.array([1, q_tet, q_tet], dtype="int32")
1372*0ef72598Sjeremylt    rui_tet = ceed.StridedElemRestriction(nelem_tet, q_tet, 1, nqpts_tet,
1373*0ef72598Sjeremylt                                          strides)
1374*0ef72598Sjeremylt
1375*0ef72598Sjeremylt    # Bases
1376*0ef72598Sjeremylt    qref = np.empty(dim * q_tet, dtype="float64")
1377*0ef72598Sjeremylt    qweight = np.empty(q_tet, dtype="float64")
1378*0ef72598Sjeremylt    interp, grad = bm.buildmats(qref, qweight)
1379*0ef72598Sjeremylt
1380*0ef72598Sjeremylt    bx_tet = ceed.BasisH1(libceed.TRIANGLE, dim, p_tet, q_hex, interp, grad, qref,
1381*0ef72598Sjeremylt                          qweight)
1382*0ef72598Sjeremylt    bu_tet = ceed.BasisH1(libceed.TRIANGLE, 1, p_tet, q_hex, interp, grad, qref,
1383*0ef72598Sjeremylt                          qweight)
1384*0ef72598Sjeremylt
1385*0ef72598Sjeremylt    # QFunctions
1386*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
1387*0ef72598Sjeremylt    qfs = load_qfs_so()
1388*0ef72598Sjeremylt
1389*0ef72598Sjeremylt    qf_setup_tet = ceed.QFunction(1, qfs.setup_mass_2d,
1390*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
1391*0ef72598Sjeremylt    qf_setup_tet.add_input("weights", 1, libceed.EVAL_WEIGHT)
1392*0ef72598Sjeremylt    qf_setup_tet.add_input("dx", dim * dim, libceed.EVAL_GRAD)
1393*0ef72598Sjeremylt    qf_setup_tet.add_output("rho", 1, libceed.EVAL_NONE)
1394*0ef72598Sjeremylt
1395*0ef72598Sjeremylt    qf_mass_tet = ceed.QFunction(1, qfs.apply_mass,
1396*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1397*0ef72598Sjeremylt    qf_mass_tet.add_input("rho", 1, libceed.EVAL_NONE)
1398*0ef72598Sjeremylt    qf_mass_tet.add_input("u", 1, libceed.EVAL_INTERP)
1399*0ef72598Sjeremylt    qf_mass_tet.add_output("v", 1, libceed.EVAL_INTERP)
1400*0ef72598Sjeremylt
1401*0ef72598Sjeremylt    # Operators
1402*0ef72598Sjeremylt    op_setup_tet = ceed.Operator(qf_setup_tet)
1403*0ef72598Sjeremylt    op_setup_tet.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_tet,
1404*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
1405*0ef72598Sjeremylt    op_setup_tet.set_field("dx", rx_tet, bx_tet, libceed.VECTOR_ACTIVE)
1406*0ef72598Sjeremylt    op_setup_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED,
1407*0ef72598Sjeremylt                           qdata_tet)
1408*0ef72598Sjeremylt
1409*0ef72598Sjeremylt    op_mass_tet = ceed.Operator(qf_mass_tet)
1410*0ef72598Sjeremylt    op_mass_tet.set_field("rho", rui_tet, libceed.BASIS_COLLOCATED, qdata_tet)
1411*0ef72598Sjeremylt    op_mass_tet.set_field("u", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
1412*0ef72598Sjeremylt    op_mass_tet.set_field("v", ru_tet, bu_tet, libceed.VECTOR_ACTIVE)
1413*0ef72598Sjeremylt
1414*0ef72598Sjeremylt    # ------------------------- Hex Elements -------------------------
1415*0ef72598Sjeremylt
1416*0ef72598Sjeremylt    # Restrictions
1417*0ef72598Sjeremylt    indx_hex = np.zeros(nelem_hex * p_hex * p_hex, dtype="int32")
1418*0ef72598Sjeremylt    for i in range(nelem_hex):
1419*0ef72598Sjeremylt        col = i % nx_hex
1420*0ef72598Sjeremylt        row = i // nx_hex
1421*0ef72598Sjeremylt        offset = (nx_tet * 2 + 1) * (ny_tet * 2) * (1 + row) + col * 2
1422*0ef72598Sjeremylt
1423*0ef72598Sjeremylt        for j in range(p_hex):
1424*0ef72598Sjeremylt            for k in range(p_hex):
1425*0ef72598Sjeremylt                indx_hex[p_hex * (p_hex * i + k) + j] = offset + \
1426*0ef72598Sjeremylt                    k * (nx_hex * 2 + 1) + j
1427*0ef72598Sjeremylt
1428*0ef72598Sjeremylt    rx_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, dim, ndofs,
1429*0ef72598Sjeremylt                                  dim * ndofs, indx_hex,
1430*0ef72598Sjeremylt                                  cmode=libceed.USE_POINTER)
1431*0ef72598Sjeremylt
1432*0ef72598Sjeremylt    ru_hex = ceed.ElemRestriction(nelem_hex, p_hex * p_hex, 1, 1, ndofs,
1433*0ef72598Sjeremylt                                  indx_hex, cmode=libceed.USE_POINTER)
1434*0ef72598Sjeremylt    strides = np.array([1, q_hex * q_hex, q_hex * q_hex], dtype="int32")
1435*0ef72598Sjeremylt    rui_hex = ceed.StridedElemRestriction(nelem_hex, q_hex * q_hex, 1,
1436*0ef72598Sjeremylt                                          nqpts_hex, strides)
1437*0ef72598Sjeremylt
1438*0ef72598Sjeremylt    # Bases
1439*0ef72598Sjeremylt    bx_hex = ceed.BasisTensorH1Lagrange(dim, dim, p_hex, q_hex, libceed.GAUSS)
1440*0ef72598Sjeremylt    bu_hex = ceed.BasisTensorH1Lagrange(dim, 1, p_hex, q_hex, libceed.GAUSS)
1441*0ef72598Sjeremylt
1442*0ef72598Sjeremylt    # QFunctions
1443*0ef72598Sjeremylt    qf_setup_hex = ceed.QFunction(1, qfs.setup_mass_2d,
1444*0ef72598Sjeremylt                                  os.path.join(file_dir, "test-qfunctions.h:setup_mass_2d"))
1445*0ef72598Sjeremylt    qf_setup_hex.add_input("weights", 1, libceed.EVAL_WEIGHT)
1446*0ef72598Sjeremylt    qf_setup_hex.add_input("dx", dim * dim, libceed.EVAL_GRAD)
1447*0ef72598Sjeremylt    qf_setup_hex.add_output("rho", 1, libceed.EVAL_NONE)
1448*0ef72598Sjeremylt
1449*0ef72598Sjeremylt    qf_mass_hex = ceed.QFunction(1, qfs.apply_mass,
1450*0ef72598Sjeremylt                                 os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
1451*0ef72598Sjeremylt    qf_mass_hex.add_input("rho", 1, libceed.EVAL_NONE)
1452*0ef72598Sjeremylt    qf_mass_hex.add_input("u", 1, libceed.EVAL_INTERP)
1453*0ef72598Sjeremylt    qf_mass_hex.add_output("v", 1, libceed.EVAL_INTERP)
1454*0ef72598Sjeremylt
1455*0ef72598Sjeremylt    # Operators
1456*0ef72598Sjeremylt    op_setup_hex = ceed.Operator(qf_setup_tet)
1457*0ef72598Sjeremylt    op_setup_hex.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx_hex,
1458*0ef72598Sjeremylt                           libceed.VECTOR_NONE)
1459*0ef72598Sjeremylt    op_setup_hex.set_field("dx", rx_hex, bx_hex, libceed.VECTOR_ACTIVE)
1460*0ef72598Sjeremylt    op_setup_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED,
1461*0ef72598Sjeremylt                           qdata_hex)
1462*0ef72598Sjeremylt
1463*0ef72598Sjeremylt    op_mass_hex = ceed.Operator(qf_mass_hex)
1464*0ef72598Sjeremylt    op_mass_hex.set_field("rho", rui_hex, libceed.BASIS_COLLOCATED, qdata_hex)
1465*0ef72598Sjeremylt    op_mass_hex.set_field("u", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
1466*0ef72598Sjeremylt    op_mass_hex.set_field("v", ru_hex, bu_hex, libceed.VECTOR_ACTIVE)
1467*0ef72598Sjeremylt
1468*0ef72598Sjeremylt    # ------------------------- Composite Operators -------------------------
1469*0ef72598Sjeremylt
1470*0ef72598Sjeremylt    # Setup
1471*0ef72598Sjeremylt    op_setup = ceed.CompositeOperator()
1472*0ef72598Sjeremylt    op_setup.add_sub(op_setup_tet)
1473*0ef72598Sjeremylt    op_setup.add_sub(op_setup_hex)
1474*0ef72598Sjeremylt    op_setup.apply(x, libceed.VECTOR_NONE)
1475*0ef72598Sjeremylt
1476*0ef72598Sjeremylt    # Apply mass matrix
1477*0ef72598Sjeremylt    op_mass = ceed.CompositeOperator()
1478*0ef72598Sjeremylt    op_mass.add_sub(op_mass_tet)
1479*0ef72598Sjeremylt    op_mass.add_sub(op_mass_hex)
1480*0ef72598Sjeremylt    u.set_value(1.)
1481*0ef72598Sjeremylt    op_mass.apply(u, v)
1482*0ef72598Sjeremylt
1483*0ef72598Sjeremylt    # Check
1484*0ef72598Sjeremylt    with v.array_read() as v_array:
1485*0ef72598Sjeremylt        total = 0.0
1486*0ef72598Sjeremylt        for i in range(ndofs):
1487*0ef72598Sjeremylt            total = total + v_array[i]
1488*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-10
1489*0ef72598Sjeremylt
1490*0ef72598Sjeremylt    # ApplyAdd mass matrix
1491*0ef72598Sjeremylt    v.set_value(1.)
1492*0ef72598Sjeremylt    op_mass.apply_add(u, v)
1493*0ef72598Sjeremylt
1494*0ef72598Sjeremylt    # Check
1495*0ef72598Sjeremylt    with v.array_read() as v_array:
1496*0ef72598Sjeremylt        total = -ndofs
1497*0ef72598Sjeremylt        for i in range(ndofs):
1498*0ef72598Sjeremylt            total = total + v_array[i]
1499*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-10
1500*0ef72598Sjeremylt
1501*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1502*0ef72598Sjeremylt# Test assembly of mass matrix operator diagonal
1503*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1504*0ef72598Sjeremylt
1505*0ef72598Sjeremylt
1506*0ef72598Sjeremyltdef test_533(ceed_resource):
1507*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1508*0ef72598Sjeremylt
1509*0ef72598Sjeremylt    nelem = 6
1510*0ef72598Sjeremylt    p = 3
1511*0ef72598Sjeremylt    q = 4
1512*0ef72598Sjeremylt    dim = 2
1513*0ef72598Sjeremylt    nx = 3
1514*0ef72598Sjeremylt    ny = 2
1515*0ef72598Sjeremylt    ndofs = (nx * 2 + 1) * (ny * 2 + 1)
1516*0ef72598Sjeremylt    nqpts = nelem * q * q
1517*0ef72598Sjeremylt
1518*0ef72598Sjeremylt    # Vectors
1519*0ef72598Sjeremylt    x = ceed.Vector(dim * ndofs)
1520*0ef72598Sjeremylt    x_array = np.zeros(dim * ndofs)
1521*0ef72598Sjeremylt    for i in range(nx * 2 + 1):
1522*0ef72598Sjeremylt        for j in range(ny * 2 + 1):
1523*0ef72598Sjeremylt            x_array[i + j * (nx * 2 + 1) + 0 * ndofs] = i / (2 * nx)
1524*0ef72598Sjeremylt            x_array[i + j * (nx * 2 + 1) + 1 * ndofs] = j / (2 * ny)
1525*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
1526*0ef72598Sjeremylt
1527*0ef72598Sjeremylt    qdata = ceed.Vector(nqpts)
1528*0ef72598Sjeremylt    u = ceed.Vector(ndofs)
1529*0ef72598Sjeremylt    v = ceed.Vector(ndofs)
1530*0ef72598Sjeremylt
1531*0ef72598Sjeremylt    # Restrictions
1532*0ef72598Sjeremylt    indx = np.zeros(nelem * p * p, dtype="int32")
1533*0ef72598Sjeremylt    for i in range(nelem):
1534*0ef72598Sjeremylt        col = i % nx
1535*0ef72598Sjeremylt        row = i // nx
1536*0ef72598Sjeremylt        offset = col * (p - 1) + row * (nx * 2 + 1) * (p - 1)
1537*0ef72598Sjeremylt        for j in range(p):
1538*0ef72598Sjeremylt            for k in range(p):
1539*0ef72598Sjeremylt                indx[p * (p * i + k) + j] = offset + k * (nx * 2 + 1) + j
1540*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, p * p, dim, ndofs, dim * ndofs,
1541*0ef72598Sjeremylt                              indx, cmode=libceed.USE_POINTER)
1542*0ef72598Sjeremylt
1543*0ef72598Sjeremylt    ru = ceed.ElemRestriction(nelem, p * p, 1, 1, ndofs, indx,
1544*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
1545*0ef72598Sjeremylt    strides = np.array([1, q * q, q * q], dtype="int32")
1546*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q * q, 1, nqpts, strides)
1547*0ef72598Sjeremylt
1548*0ef72598Sjeremylt    # Bases
1549*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(dim, dim, p, q, libceed.GAUSS)
1550*0ef72598Sjeremylt    bu = ceed.BasisTensorH1Lagrange(dim, 1, p, q, libceed.GAUSS)
1551*0ef72598Sjeremylt
1552*0ef72598Sjeremylt    # QFunctions
1553*0ef72598Sjeremylt    qf_setup = ceed.QFunctionByName("Mass2DBuild")
1554*0ef72598Sjeremylt
1555*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1556*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with
1557*0ef72598Sjeremylt#   multigrid level, tensor basis and interpolation basis generation
1558*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1559*0ef72598Sjeremylt
1560*0ef72598Sjeremylt
1561*0ef72598Sjeremyltdef test_550(ceed_resource):
1562*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1563*0ef72598Sjeremylt
1564*0ef72598Sjeremylt    nelem = 15
1565*0ef72598Sjeremylt    p_coarse = 3
1566*0ef72598Sjeremylt    p_fine = 5
1567*0ef72598Sjeremylt    q = 8
1568*0ef72598Sjeremylt    ncomp = 2
1569*0ef72598Sjeremylt    nx = nelem + 1
1570*0ef72598Sjeremylt    nu_coarse = nelem * (p_coarse - 1) + 1
1571*0ef72598Sjeremylt    nu_fine = nelem * (p_fine - 1) + 1
1572*0ef72598Sjeremylt
1573*0ef72598Sjeremylt    # Vectors
1574*0ef72598Sjeremylt    x = ceed.Vector(nx)
1575*0ef72598Sjeremylt    x_array = np.zeros(nx)
1576*0ef72598Sjeremylt    for i in range(nx):
1577*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
1578*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
1579*0ef72598Sjeremylt
1580*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
1581*0ef72598Sjeremylt    u_coarse = ceed.Vector(ncomp * nu_coarse)
1582*0ef72598Sjeremylt    v_coarse = ceed.Vector(ncomp * nu_coarse)
1583*0ef72598Sjeremylt    u_fine = ceed.Vector(ncomp * nu_fine)
1584*0ef72598Sjeremylt    v_fine = ceed.Vector(ncomp * nu_fine)
1585*0ef72598Sjeremylt
1586*0ef72598Sjeremylt    # Restrictions
1587*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
1588*0ef72598Sjeremylt    for i in range(nx):
1589*0ef72598Sjeremylt        indx[2 * i + 0] = i
1590*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
1591*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
1592*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
1593*0ef72598Sjeremylt
1594*0ef72598Sjeremylt    indu_coarse = np.zeros(nelem * p_coarse, dtype="int32")
1595*0ef72598Sjeremylt    for i in range(nelem):
1596*0ef72598Sjeremylt        for j in range(p_coarse):
1597*0ef72598Sjeremylt            indu_coarse[p_coarse * i + j] = i * (p_coarse - 1) + j
1598*0ef72598Sjeremylt    ru_coarse = ceed.ElemRestriction(nelem, p_coarse, ncomp, nu_coarse,
1599*0ef72598Sjeremylt                                     ncomp * nu_coarse, indu_coarse,
1600*0ef72598Sjeremylt                                     cmode=libceed.USE_POINTER)
1601*0ef72598Sjeremylt
1602*0ef72598Sjeremylt    indu_fine = np.zeros(nelem * p_fine, dtype="int32")
1603*0ef72598Sjeremylt    for i in range(nelem):
1604*0ef72598Sjeremylt        for j in range(p_fine):
1605*0ef72598Sjeremylt            indu_fine[p_fine * i + j] = i * (p_fine - 1) + j
1606*0ef72598Sjeremylt    ru_fine = ceed.ElemRestriction(nelem, p_fine, ncomp, nu_fine,
1607*0ef72598Sjeremylt                                   ncomp * nu_fine, indu_fine,
1608*0ef72598Sjeremylt                                   cmode=libceed.USE_POINTER)
1609*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
1610*0ef72598Sjeremylt
1611*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
1612*0ef72598Sjeremylt
1613*0ef72598Sjeremylt    # Bases
1614*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
1615*0ef72598Sjeremylt    bu_coarse = ceed.BasisTensorH1Lagrange(1, ncomp, p_coarse, q, libceed.GAUSS)
1616*0ef72598Sjeremylt    bu_fine = ceed.BasisTensorH1Lagrange(1, ncomp, p_fine, q, libceed.GAUSS)
1617*0ef72598Sjeremylt
1618*0ef72598Sjeremylt    # QFunctions
1619*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
1620*0ef72598Sjeremylt    qfs = load_qfs_so()
1621*0ef72598Sjeremylt
1622*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
1623*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
1624*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
1625*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
1626*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
1627*0ef72598Sjeremylt
1628*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass_two,
1629*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass_two"))
1630*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
1631*0ef72598Sjeremylt    qf_mass.add_input("u", ncomp, libceed.EVAL_INTERP)
1632*0ef72598Sjeremylt    qf_mass.add_output("v", ncomp, libceed.EVAL_INTERP)
1633*0ef72598Sjeremylt
1634*0ef72598Sjeremylt    # Operators
1635*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
1636*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
1637*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
1638*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
1639*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
1640*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
1641*0ef72598Sjeremylt
1642*0ef72598Sjeremylt    op_mass_fine = ceed.Operator(qf_mass)
1643*0ef72598Sjeremylt    op_mass_fine.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
1644*0ef72598Sjeremylt    op_mass_fine.set_field("u", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
1645*0ef72598Sjeremylt    op_mass_fine.set_field("v", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
1646*0ef72598Sjeremylt
1647*0ef72598Sjeremylt    # Setup
1648*0ef72598Sjeremylt    op_setup.apply(x, qdata)
1649*0ef72598Sjeremylt
1650*0ef72598Sjeremylt    # Create multigrid level
1651*0ef72598Sjeremylt    p_mult_fine = ceed.Vector(ncomp * nu_fine)
1652*0ef72598Sjeremylt    p_mult_fine.set_value(1.0)
1653*0ef72598Sjeremylt    [op_mass_coarse, op_prolong, op_restrict] = op_mass_fine.multigrid_create(p_mult_fine,
1654*0ef72598Sjeremylt                                                                              ru_coarse,
1655*0ef72598Sjeremylt                                                                              bu_coarse)
1656*0ef72598Sjeremylt
1657*0ef72598Sjeremylt    # Apply coarse mass matrix
1658*0ef72598Sjeremylt    u_coarse.set_value(1.0)
1659*0ef72598Sjeremylt    op_mass_coarse.apply(u_coarse, v_coarse)
1660*0ef72598Sjeremylt
1661*0ef72598Sjeremylt    # Check
1662*0ef72598Sjeremylt    with v_coarse.array_read() as v_array:
1663*0ef72598Sjeremylt        total = 0.0
1664*0ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
1665*0ef72598Sjeremylt            total = total + v_array[i]
1666*0ef72598Sjeremylt        assert abs(total - 2.0) < 1E-13
1667*0ef72598Sjeremylt
1668*0ef72598Sjeremylt    # Prolong coarse u
1669*0ef72598Sjeremylt    op_prolong.apply(u_coarse, u_fine)
1670*0ef72598Sjeremylt
1671*0ef72598Sjeremylt    # Apply mass matrix
1672*0ef72598Sjeremylt    op_mass_fine.apply(u_fine, v_fine)
1673*0ef72598Sjeremylt
1674*0ef72598Sjeremylt    # Check
1675*0ef72598Sjeremylt    with v_fine.array_read() as v_array:
1676*0ef72598Sjeremylt        total = 0.0
1677*0ef72598Sjeremylt        for i in range(nu_fine * ncomp):
1678*0ef72598Sjeremylt            total = total + v_array[i]
1679*0ef72598Sjeremylt        assert abs(total - 2.0) < 1E-13
1680*0ef72598Sjeremylt
1681*0ef72598Sjeremylt    # Restrict state to coarse grid
1682*0ef72598Sjeremylt    op_restrict.apply(v_fine, v_coarse)
1683*0ef72598Sjeremylt
1684*0ef72598Sjeremylt    # Check
1685*0ef72598Sjeremylt    with v_coarse.array_read() as v_array:
1686*0ef72598Sjeremylt        total = 0.0
1687*0ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
1688*0ef72598Sjeremylt            total = total + v_array[i]
1689*0ef72598Sjeremylt        assert abs(total - 2.0) < 1E-13
1690*0ef72598Sjeremylt
1691*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1692*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with
1693*0ef72598Sjeremylt#   multigrid level, tensor basis
1694*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1695*0ef72598Sjeremylt
1696*0ef72598Sjeremylt
1697*0ef72598Sjeremyltdef test_552(ceed_resource):
1698*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1699*0ef72598Sjeremylt
1700*0ef72598Sjeremylt    nelem = 15
1701*0ef72598Sjeremylt    p_coarse = 3
1702*0ef72598Sjeremylt    p_fine = 5
1703*0ef72598Sjeremylt    q = 8
1704*0ef72598Sjeremylt    ncomp = 2
1705*0ef72598Sjeremylt    nx = nelem + 1
1706*0ef72598Sjeremylt    nu_coarse = nelem * (p_coarse - 1) + 1
1707*0ef72598Sjeremylt    nu_fine = nelem * (p_fine - 1) + 1
1708*0ef72598Sjeremylt
1709*0ef72598Sjeremylt    # Vectors
1710*0ef72598Sjeremylt    x = ceed.Vector(nx)
1711*0ef72598Sjeremylt    x_array = np.zeros(nx)
1712*0ef72598Sjeremylt    for i in range(nx):
1713*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
1714*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
1715*0ef72598Sjeremylt
1716*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
1717*0ef72598Sjeremylt    u_coarse = ceed.Vector(ncomp * nu_coarse)
1718*0ef72598Sjeremylt    v_coarse = ceed.Vector(ncomp * nu_coarse)
1719*0ef72598Sjeremylt    u_fine = ceed.Vector(ncomp * nu_fine)
1720*0ef72598Sjeremylt    v_fine = ceed.Vector(ncomp * nu_fine)
1721*0ef72598Sjeremylt
1722*0ef72598Sjeremylt    # Restrictions
1723*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
1724*0ef72598Sjeremylt    for i in range(nx):
1725*0ef72598Sjeremylt        indx[2 * i + 0] = i
1726*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
1727*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
1728*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
1729*0ef72598Sjeremylt
1730*0ef72598Sjeremylt    indu_coarse = np.zeros(nelem * p_coarse, dtype="int32")
1731*0ef72598Sjeremylt    for i in range(nelem):
1732*0ef72598Sjeremylt        for j in range(p_coarse):
1733*0ef72598Sjeremylt            indu_coarse[p_coarse * i + j] = i * (p_coarse - 1) + j
1734*0ef72598Sjeremylt    ru_coarse = ceed.ElemRestriction(nelem, p_coarse, ncomp, nu_coarse,
1735*0ef72598Sjeremylt                                     ncomp * nu_coarse, indu_coarse,
1736*0ef72598Sjeremylt                                     cmode=libceed.USE_POINTER)
1737*0ef72598Sjeremylt
1738*0ef72598Sjeremylt    indu_fine = np.zeros(nelem * p_fine, dtype="int32")
1739*0ef72598Sjeremylt    for i in range(nelem):
1740*0ef72598Sjeremylt        for j in range(p_fine):
1741*0ef72598Sjeremylt            indu_fine[p_fine * i + j] = i * (p_fine - 1) + j
1742*0ef72598Sjeremylt    ru_fine = ceed.ElemRestriction(nelem, p_fine, ncomp, nu_fine,
1743*0ef72598Sjeremylt                                   ncomp * nu_fine, indu_fine,
1744*0ef72598Sjeremylt                                   cmode=libceed.USE_POINTER)
1745*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
1746*0ef72598Sjeremylt
1747*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
1748*0ef72598Sjeremylt
1749*0ef72598Sjeremylt    # Bases
1750*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
1751*0ef72598Sjeremylt    bu_coarse = ceed.BasisTensorH1Lagrange(1, ncomp, p_coarse, q, libceed.GAUSS)
1752*0ef72598Sjeremylt    bu_fine = ceed.BasisTensorH1Lagrange(1, ncomp, p_fine, q, libceed.GAUSS)
1753*0ef72598Sjeremylt
1754*0ef72598Sjeremylt    # QFunctions
1755*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
1756*0ef72598Sjeremylt    qfs = load_qfs_so()
1757*0ef72598Sjeremylt
1758*0ef72598Sjeremylt    qf_setup = ceed.QFunction(1, qfs.setup_mass,
1759*0ef72598Sjeremylt                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
1760*0ef72598Sjeremylt    qf_setup.add_input("weights", 1, libceed.EVAL_WEIGHT)
1761*0ef72598Sjeremylt    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
1762*0ef72598Sjeremylt    qf_setup.add_output("rho", 1, libceed.EVAL_NONE)
1763*0ef72598Sjeremylt
1764*0ef72598Sjeremylt    qf_mass = ceed.QFunction(1, qfs.apply_mass_two,
1765*0ef72598Sjeremylt                             os.path.join(file_dir, "test-qfunctions.h:apply_mass_two"))
1766*0ef72598Sjeremylt    qf_mass.add_input("rho", 1, libceed.EVAL_NONE)
1767*0ef72598Sjeremylt    qf_mass.add_input("u", ncomp, libceed.EVAL_INTERP)
1768*0ef72598Sjeremylt    qf_mass.add_output("v", ncomp, libceed.EVAL_INTERP)
1769*0ef72598Sjeremylt
1770*0ef72598Sjeremylt    # Operators
1771*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
1772*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
1773*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
1774*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
1775*0ef72598Sjeremylt    op_setup.set_field("rho", rui, libceed.BASIS_COLLOCATED,
1776*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
1777*0ef72598Sjeremylt
1778*0ef72598Sjeremylt    op_mass_fine = ceed.Operator(qf_mass)
1779*0ef72598Sjeremylt    op_mass_fine.set_field("rho", rui, libceed.BASIS_COLLOCATED, qdata)
1780*0ef72598Sjeremylt    op_mass_fine.set_field("u", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
1781*0ef72598Sjeremylt    op_mass_fine.set_field("v", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
1782*0ef72598Sjeremylt
1783*0ef72598Sjeremylt    # Setup
1784*0ef72598Sjeremylt    op_setup.apply(x, qdata)
1785*0ef72598Sjeremylt
1786*0ef72598Sjeremylt    # Create multigrid level
1787*0ef72598Sjeremylt    p_mult_fine = ceed.Vector(ncomp * nu_fine)
1788*0ef72598Sjeremylt    p_mult_fine.set_value(1.0)
1789*0ef72598Sjeremylt    b_c_to_f = ceed.BasisTensorH1Lagrange(
1790*0ef72598Sjeremylt        1, ncomp, p_coarse, p_fine, libceed.GAUSS_LOBATTO)
1791*0ef72598Sjeremylt    interp_C_to_F = b_c_to_f.get_interp1d()
1792*0ef72598Sjeremylt    [op_mass_coarse, op_prolong, op_restrict] = op_mass_fine.multigrid_create_tensor_h1(p_mult_fine,
1793*0ef72598Sjeremylt                                                                                        ru_coarse, bu_coarse, interp_C_to_F)
1794*0ef72598Sjeremylt
1795*0ef72598Sjeremylt    # Apply coarse mass matrix
1796*0ef72598Sjeremylt    u_coarse.set_value(1.0)
1797*0ef72598Sjeremylt    op_mass_coarse.apply(u_coarse, v_coarse)
1798*0ef72598Sjeremylt
1799*0ef72598Sjeremylt    # Check
1800*0ef72598Sjeremylt    with v_coarse.array_read() as v_array:
1801*0ef72598Sjeremylt        total = 0.0
1802*0ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
1803*0ef72598Sjeremylt            total = total + v_array[i]
1804*0ef72598Sjeremylt        assert abs(total - 2.0) < 1E-13
1805*0ef72598Sjeremylt
1806*0ef72598Sjeremylt    # Prolong coarse u
1807*0ef72598Sjeremylt    op_prolong.apply(u_coarse, u_fine)
1808*0ef72598Sjeremylt
1809*0ef72598Sjeremylt    # Apply mass matrix
1810*0ef72598Sjeremylt    op_mass_fine.apply(u_fine, v_fine)
1811*0ef72598Sjeremylt
1812*0ef72598Sjeremylt    # Check
1813*0ef72598Sjeremylt    with v_fine.array_read() as v_array:
1814*0ef72598Sjeremylt        total = 0.0
1815*0ef72598Sjeremylt        for i in range(nu_fine * ncomp):
1816*0ef72598Sjeremylt            total = total + v_array[i]
1817*0ef72598Sjeremylt        assert abs(total - 2.0) < 1E-13
1818*0ef72598Sjeremylt
1819*0ef72598Sjeremylt    # Restrict state to coarse grid
1820*0ef72598Sjeremylt    op_restrict.apply(v_fine, v_coarse)
1821*0ef72598Sjeremylt
1822*0ef72598Sjeremylt    # Check
1823*0ef72598Sjeremylt    with v_coarse.array_read() as v_array:
1824*0ef72598Sjeremylt        total = 0.0
1825*0ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
1826*0ef72598Sjeremylt            total = total + v_array[i]
1827*0ef72598Sjeremylt        assert abs(total - 2.0) < 1E-13
1828*0ef72598Sjeremylt
1829*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1830*0ef72598Sjeremylt# Test creation, action, and destruction for mass matrix operator with
1831*0ef72598Sjeremylt#   multigrid level, non-tensor basis
1832*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1833*0ef72598Sjeremylt
1834*0ef72598Sjeremylt
1835*0ef72598Sjeremyltdef test_553(ceed_resource):
1836*0ef72598Sjeremylt    ceed = libceed.Ceed(ceed_resource)
1837*0ef72598Sjeremylt
1838*0ef72598Sjeremylt    nelem = 15
1839*0ef72598Sjeremylt    p_coarse = 3
1840*0ef72598Sjeremylt    p_fine = 5
1841*0ef72598Sjeremylt    q = 8
1842*0ef72598Sjeremylt    ncomp = 1
1843*0ef72598Sjeremylt    nx = nelem + 1
1844*0ef72598Sjeremylt    nu_coarse = nelem * (p_coarse - 1) + 1
1845*0ef72598Sjeremylt    nu_fine = nelem * (p_fine - 1) + 1
1846*0ef72598Sjeremylt
1847*0ef72598Sjeremylt    # Vectors
1848*0ef72598Sjeremylt    x = ceed.Vector(nx)
1849*0ef72598Sjeremylt    x_array = np.zeros(nx)
1850*0ef72598Sjeremylt    for i in range(nx):
1851*0ef72598Sjeremylt        x_array[i] = i / (nx - 1.0)
1852*0ef72598Sjeremylt    x.set_array(x_array, cmode=libceed.USE_POINTER)
1853*0ef72598Sjeremylt
1854*0ef72598Sjeremylt    qdata = ceed.Vector(nelem * q)
1855*0ef72598Sjeremylt    u_coarse = ceed.Vector(ncomp * nu_coarse)
1856*0ef72598Sjeremylt    v_coarse = ceed.Vector(ncomp * nu_coarse)
1857*0ef72598Sjeremylt    u_fine = ceed.Vector(ncomp * nu_fine)
1858*0ef72598Sjeremylt    v_fine = ceed.Vector(ncomp * nu_fine)
1859*0ef72598Sjeremylt
1860*0ef72598Sjeremylt    # Restrictions
1861*0ef72598Sjeremylt    indx = np.zeros(nx * 2, dtype="int32")
1862*0ef72598Sjeremylt    for i in range(nx):
1863*0ef72598Sjeremylt        indx[2 * i + 0] = i
1864*0ef72598Sjeremylt        indx[2 * i + 1] = i + 1
1865*0ef72598Sjeremylt    rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx,
1866*0ef72598Sjeremylt                              cmode=libceed.USE_POINTER)
1867*0ef72598Sjeremylt
1868*0ef72598Sjeremylt    indu_coarse = np.zeros(nelem * p_coarse, dtype="int32")
1869*0ef72598Sjeremylt    for i in range(nelem):
1870*0ef72598Sjeremylt        for j in range(p_coarse):
1871*0ef72598Sjeremylt            indu_coarse[p_coarse * i + j] = i * (p_coarse - 1) + j
1872*0ef72598Sjeremylt    ru_coarse = ceed.ElemRestriction(nelem, p_coarse, ncomp, nu_coarse,
1873*0ef72598Sjeremylt                                     ncomp * nu_coarse, indu_coarse,
1874*0ef72598Sjeremylt                                     cmode=libceed.USE_POINTER)
1875*0ef72598Sjeremylt
1876*0ef72598Sjeremylt    indu_fine = np.zeros(nelem * p_fine, dtype="int32")
1877*0ef72598Sjeremylt    for i in range(nelem):
1878*0ef72598Sjeremylt        for j in range(p_fine):
1879*0ef72598Sjeremylt            indu_fine[p_fine * i + j] = i * (p_fine - 1) + j
1880*0ef72598Sjeremylt    ru_fine = ceed.ElemRestriction(nelem, p_fine, ncomp, nu_fine,
1881*0ef72598Sjeremylt                                   ncomp * nu_fine, indu_fine,
1882*0ef72598Sjeremylt                                   cmode=libceed.USE_POINTER)
1883*0ef72598Sjeremylt    strides = np.array([1, q, q], dtype="int32")
1884*0ef72598Sjeremylt
1885*0ef72598Sjeremylt    rui = ceed.StridedElemRestriction(nelem, q, 1, q * nelem, strides)
1886*0ef72598Sjeremylt
1887*0ef72598Sjeremylt    # Bases
1888*0ef72598Sjeremylt    bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
1889*0ef72598Sjeremylt    bu_coarse = ceed.BasisTensorH1Lagrange(1, ncomp, p_coarse, q, libceed.GAUSS)
1890*0ef72598Sjeremylt    bu_fine = ceed.BasisTensorH1Lagrange(1, ncomp, p_fine, q, libceed.GAUSS)
1891*0ef72598Sjeremylt
1892*0ef72598Sjeremylt    # QFunctions
1893*0ef72598Sjeremylt    file_dir = os.path.dirname(os.path.abspath(__file__))
1894*0ef72598Sjeremylt    qfs = load_qfs_so()
1895*0ef72598Sjeremylt
1896*0ef72598Sjeremylt    qf_setup = ceed.QFunctionByName("Mass1DBuild")
1897*0ef72598Sjeremylt    qf_mass = ceed.QFunctionByName("MassApply")
1898*0ef72598Sjeremylt
1899*0ef72598Sjeremylt    # Operators
1900*0ef72598Sjeremylt    op_setup = ceed.Operator(qf_setup)
1901*0ef72598Sjeremylt    op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
1902*0ef72598Sjeremylt                       libceed.VECTOR_NONE)
1903*0ef72598Sjeremylt    op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
1904*0ef72598Sjeremylt    op_setup.set_field("qdata", rui, libceed.BASIS_COLLOCATED,
1905*0ef72598Sjeremylt                       libceed.VECTOR_ACTIVE)
1906*0ef72598Sjeremylt
1907*0ef72598Sjeremylt    op_mass_fine = ceed.Operator(qf_mass)
1908*0ef72598Sjeremylt    op_mass_fine.set_field("qdata", rui, libceed.BASIS_COLLOCATED, qdata)
1909*0ef72598Sjeremylt    op_mass_fine.set_field("u", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
1910*0ef72598Sjeremylt    op_mass_fine.set_field("v", ru_fine, bu_fine, libceed.VECTOR_ACTIVE)
1911*0ef72598Sjeremylt
1912*0ef72598Sjeremylt    # Setup
1913*0ef72598Sjeremylt    op_setup.apply(x, qdata)
1914*0ef72598Sjeremylt
1915*0ef72598Sjeremylt    # Create multigrid level
1916*0ef72598Sjeremylt    p_mult_fine = ceed.Vector(ncomp * nu_fine)
1917*0ef72598Sjeremylt    p_mult_fine.set_value(1.0)
1918*0ef72598Sjeremylt    b_c_to_f = ceed.BasisTensorH1Lagrange(
1919*0ef72598Sjeremylt        1, ncomp, p_coarse, p_fine, libceed.GAUSS_LOBATTO)
1920*0ef72598Sjeremylt    interp_C_to_F = b_c_to_f.get_interp1d()
1921*0ef72598Sjeremylt    [op_mass_coarse, op_prolong, op_restrict] = op_mass_fine.multigrid_create_h1(p_mult_fine,
1922*0ef72598Sjeremylt                                                                                 ru_coarse, bu_coarse, interp_C_to_F)
1923*0ef72598Sjeremylt
1924*0ef72598Sjeremylt    # Apply coarse mass matrix
1925*0ef72598Sjeremylt    u_coarse.set_value(1.0)
1926*0ef72598Sjeremylt    op_mass_coarse.apply(u_coarse, v_coarse)
1927*0ef72598Sjeremylt
1928*0ef72598Sjeremylt    # Check
1929*0ef72598Sjeremylt    with v_coarse.array_read() as v_array:
1930*0ef72598Sjeremylt        total = 0.0
1931*0ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
1932*0ef72598Sjeremylt            total = total + v_array[i]
1933*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-13
1934*0ef72598Sjeremylt
1935*0ef72598Sjeremylt    # Prolong coarse u
1936*0ef72598Sjeremylt    op_prolong.apply(u_coarse, u_fine)
1937*0ef72598Sjeremylt
1938*0ef72598Sjeremylt    # Apply mass matrix
1939*0ef72598Sjeremylt    op_mass_fine.apply(u_fine, v_fine)
1940*0ef72598Sjeremylt
1941*0ef72598Sjeremylt    # Check
1942*0ef72598Sjeremylt    with v_fine.array_read() as v_array:
1943*0ef72598Sjeremylt        total = 0.0
1944*0ef72598Sjeremylt        for i in range(nu_fine * ncomp):
1945*0ef72598Sjeremylt            total = total + v_array[i]
1946*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-13
1947*0ef72598Sjeremylt
1948*0ef72598Sjeremylt    # Restrict state to coarse grid
1949*0ef72598Sjeremylt    op_restrict.apply(v_fine, v_coarse)
1950*0ef72598Sjeremylt
1951*0ef72598Sjeremylt    # Check
1952*0ef72598Sjeremylt    with v_coarse.array_read() as v_array:
1953*0ef72598Sjeremylt        total = 0.0
1954*0ef72598Sjeremylt        for i in range(nu_coarse * ncomp):
1955*0ef72598Sjeremylt            total = total + v_array[i]
1956*0ef72598Sjeremylt        assert abs(total - 1.0) < 1E-13
1957*0ef72598Sjeremylt
1958*0ef72598Sjeremylt# -------------------------------------------------------------------------------
1959