xref: /libCEED/python/tests/test-4-qfunction.py (revision 547dbd6f5071ad3a6569362aeaf8c427ad429b62)
1# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3# reserved. See files LICENSE and NOTICE for details.
4#
5# This file is part of CEED, a collection of benchmarks, miniapps, software
6# libraries and APIs for efficient high-order finite element and spectral
7# element discretizations for exascale applications. For more information and
8# source code availability see http://github.com/ceed.
9#
10# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11# a collaborative effort of two U.S. Department of Energy organizations (Office
12# of Science and the National Nuclear Security Administration) responsible for
13# the planning and preparation of a capable exascale ecosystem, including
14# software, applications, hardware, advanced system engineering and early
15# testbed platforms, in support of the nation's exascale computing imperative.
16
17# @file
18# Test Ceed QFunction functionality
19
20import os
21import libceed
22import numpy as np
23import check
24
25TOL = libceed.EPSILON * 256
26
27# -------------------------------------------------------------------------------
28# Utility
29# -------------------------------------------------------------------------------
30
31
32def load_qfs_so():
33    from distutils.sysconfig import get_config_var
34    import ctypes
35
36    file_dir = os.path.dirname(os.path.abspath(__file__))
37    qfs_so = os.path.join(
38        file_dir,
39        "libceed_qfunctions" + get_config_var("EXT_SUFFIX"))
40
41    # Load library
42    return ctypes.cdll.LoadLibrary(qfs_so)
43
44# -------------------------------------------------------------------------------
45# Test creation, evaluation, and destruction for qfunction
46# -------------------------------------------------------------------------------
47
48
49def test_400(ceed_resource):
50    ceed = libceed.Ceed(ceed_resource)
51
52    file_dir = os.path.dirname(os.path.abspath(__file__))
53    qfs = load_qfs_so()
54
55    qf_setup = ceed.QFunction(1, qfs.setup_mass,
56                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
57    qf_setup.add_input("w", 1, libceed.EVAL_WEIGHT)
58    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
59    qf_setup.add_output("qdata", 1, libceed.EVAL_NONE)
60
61    qf_mass = ceed.QFunction(1, qfs.apply_mass,
62                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
63    qf_mass.add_input("qdata", 1, libceed.EVAL_NONE)
64    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
65    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
66
67    q = 8
68
69    w_array = np.zeros(q, dtype=ceed.scalar_type())
70    u_array = np.zeros(q, dtype=ceed.scalar_type())
71    v_true = np.zeros(q, dtype=ceed.scalar_type())
72    for i in range(q):
73        x = 2. * i / (q - 1) - 1
74        w_array[i] = 1 - x * x
75        u_array[i] = 2 + 3 * x + 5 * x * x
76        v_true[i] = w_array[i] * u_array[i]
77
78    dx = ceed.Vector(q)
79    dx.set_value(1)
80    w = ceed.Vector(q)
81    w.set_array(w_array, cmode=libceed.USE_POINTER)
82    u = ceed.Vector(q)
83    u.set_array(u_array, cmode=libceed.USE_POINTER)
84    v = ceed.Vector(q)
85    v.set_value(0)
86    qdata = ceed.Vector(q)
87    qdata.set_value(0)
88
89    inputs = [dx, w]
90    outputs = [qdata]
91    qf_setup.apply(q, inputs, outputs)
92
93    inputs = [qdata, u]
94    outputs = [v]
95    qf_mass.apply(q, inputs, outputs)
96
97    with v.array_read() as v_array:
98        for i in range(q):
99            assert v_array[i] == v_true[i]
100
101# -------------------------------------------------------------------------------
102# Test creation, evaluation, and destruction for qfunction
103# -------------------------------------------------------------------------------
104
105
106def test_401(ceed_resource):
107    ceed = libceed.Ceed(ceed_resource)
108
109    file_dir = os.path.dirname(os.path.abspath(__file__))
110    qfs = load_qfs_so()
111
112    qf_setup = ceed.QFunction(1, qfs.setup_mass,
113                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
114    qf_setup.add_input("w", 1, libceed.EVAL_WEIGHT)
115    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
116    qf_setup.add_output("qdata", 1, libceed.EVAL_NONE)
117
118    qf_mass = ceed.QFunction(1, qfs.apply_mass,
119                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
120    qf_mass.add_input("qdata", 1, libceed.EVAL_NONE)
121    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
122    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
123
124    ctx_data = np.array([1., 2., 3., 4., 5.], dtype=ceed.scalar_type())
125    ctx = ceed.QFunctionContext()
126    ctx.set_data(ctx_data)
127    qf_mass.set_context(ctx)
128
129    q = 8
130
131    w_array = np.zeros(q, dtype=ceed.scalar_type())
132    u_array = np.zeros(q, dtype=ceed.scalar_type())
133    v_true = np.zeros(q, dtype=ceed.scalar_type())
134    for i in range(q):
135        x = 2. * i / (q - 1) - 1
136        w_array[i] = 1 - x * x
137        u_array[i] = 2 + 3 * x + 5 * x * x
138        v_true[i] = 5 * w_array[i] * u_array[i]
139
140    dx = ceed.Vector(q)
141    dx.set_value(1)
142    w = ceed.Vector(q)
143    w.set_array(w_array, cmode=libceed.USE_POINTER)
144    u = ceed.Vector(q)
145    u.set_array(u_array, cmode=libceed.USE_POINTER)
146    v = ceed.Vector(q)
147    v.set_value(0)
148    qdata = ceed.Vector(q)
149    qdata.set_value(0)
150
151    inputs = [dx, w]
152    outputs = [qdata]
153    qf_setup.apply(q, inputs, outputs)
154
155    inputs = [qdata, u]
156    outputs = [v]
157    qf_mass.apply(q, inputs, outputs)
158
159    with v.array_read() as v_array:
160        for i in range(q):
161            assert abs(v_array[i] - v_true[i]) < TOL
162
163# -------------------------------------------------------------------------------
164# Test viewing of qfunction
165# -------------------------------------------------------------------------------
166
167
168def test_402(ceed_resource, capsys):
169    ceed = libceed.Ceed(ceed_resource)
170
171    file_dir = os.path.dirname(os.path.abspath(__file__))
172    qfs = load_qfs_so()
173
174    qf_setup = ceed.QFunction(1, qfs.setup_mass,
175                              os.path.join(file_dir, "test-qfunctions.h:setup_mass"))
176    qf_setup.add_input("w", 1, libceed.EVAL_WEIGHT)
177    qf_setup.add_input("dx", 1, libceed.EVAL_GRAD)
178    qf_setup.add_output("qdata", 1, libceed.EVAL_NONE)
179
180    qf_mass = ceed.QFunction(1, qfs.apply_mass,
181                             os.path.join(file_dir, "test-qfunctions.h:apply_mass"))
182    qf_mass.add_input("qdata", 1, libceed.EVAL_NONE)
183    qf_mass.add_input("u", 1, libceed.EVAL_INTERP)
184    qf_mass.add_output("v", 1, libceed.EVAL_INTERP)
185
186    print(qf_setup)
187    print(qf_mass)
188
189    if libceed.lib.CEED_SCALAR_TYPE == libceed.SCALAR_FP64:
190        ctx_data = np.array([1., 2., 3., 4., 5.], dtype="float64")
191    # Make ctx twice as long in fp32, so size will be the same as fp64 output
192    else:
193        ctx_data = np.array([1., 2., 3., 4., 5., 1., 2., 3., 4., 5.],
194                            dtype="float32")
195    ctx = ceed.QFunctionContext()
196    ctx.set_data(ctx_data)
197    print(ctx)
198
199    stdout, stderr, ref_stdout = check.output(capsys)
200    assert not stderr
201    assert stdout == ref_stdout
202
203# -------------------------------------------------------------------------------
204# Test creation, evaluation, and destruction for qfunction by name
205# -------------------------------------------------------------------------------
206
207
208def test_410(ceed_resource):
209    ceed = libceed.Ceed(ceed_resource)
210
211    qf_setup = ceed.QFunctionByName("Mass1DBuild")
212    qf_mass = ceed.QFunctionByName("MassApply")
213
214    q = 8
215
216    j_array = np.zeros(q, dtype=ceed.scalar_type())
217    w_array = np.zeros(q, dtype=ceed.scalar_type())
218    u_array = np.zeros(q, dtype=ceed.scalar_type())
219    v_true = np.zeros(q, dtype=ceed.scalar_type())
220    for i in range(q):
221        x = 2. * i / (q - 1) - 1
222        j_array[i] = 1
223        w_array[i] = 1 - x * x
224        u_array[i] = 2 + 3 * x + 5 * x * x
225        v_true[i] = w_array[i] * u_array[i]
226
227    j = ceed.Vector(q)
228    j.set_array(j_array, cmode=libceed.USE_POINTER)
229    w = ceed.Vector(q)
230    w.set_array(w_array, cmode=libceed.USE_POINTER)
231    u = ceed.Vector(q)
232    u.set_array(u_array, cmode=libceed.USE_POINTER)
233    v = ceed.Vector(q)
234    v.set_value(0)
235    qdata = ceed.Vector(q)
236    qdata.set_value(0)
237
238    inputs = [j, w]
239    outputs = [qdata]
240    qf_setup.apply(q, inputs, outputs)
241
242    inputs = [w, u]
243    outputs = [v]
244    qf_mass.apply(q, inputs, outputs)
245
246    with v.array_read() as v_array:
247        for i in range(q):
248            assert v_array[i] == v_true[i]
249
250# -------------------------------------------------------------------------------
251# Test creation, evaluation, and destruction of identity qfunction
252# -------------------------------------------------------------------------------
253
254
255def test_411(ceed_resource):
256    ceed = libceed.Ceed(ceed_resource)
257
258    qf = ceed.IdentityQFunction(1, libceed.EVAL_INTERP, libceed.EVAL_INTERP)
259
260    q = 8
261
262    u_array = np.zeros(q, dtype=ceed.scalar_type())
263    for i in range(q):
264        u_array[i] = i * i
265
266    u = ceed.Vector(q)
267    u.set_array(u_array, cmode=libceed.USE_POINTER)
268    v = ceed.Vector(q)
269    v.set_value(0)
270
271    inputs = [u]
272    outputs = [v]
273    qf.apply(q, inputs, outputs)
274
275    with v.array_read() as v_array:
276        for i in range(q):
277            assert v_array[i] == i * i
278
279# -------------------------------------------------------------------------------
280# Test creation, evaluation, and destruction of identity qfunction with size>1
281# -------------------------------------------------------------------------------
282
283
284def test_412(ceed_resource):
285    ceed = libceed.Ceed(ceed_resource)
286
287    size = 3
288    qf = ceed.IdentityQFunction(size, libceed.EVAL_INTERP, libceed.EVAL_INTERP)
289
290    q = 8
291
292    u_array = np.zeros(q * size, dtype=ceed.scalar_type())
293    for i in range(q * size):
294        u_array[i] = i * i
295
296    u = ceed.Vector(q * size)
297    u.set_array(u_array, cmode=libceed.USE_POINTER)
298    v = ceed.Vector(q * size)
299    v.set_value(0)
300
301    inputs = [u]
302    outputs = [v]
303    qf.apply(q, inputs, outputs)
304
305    with v.array_read() as v_array:
306        for i in range(q * size):
307            assert v_array[i] == i * i
308
309# -------------------------------------------------------------------------------
310# Test viewing of qfunction by name
311# -------------------------------------------------------------------------------
312
313
314def test_413(ceed_resource, capsys):
315    ceed = libceed.Ceed(ceed_resource)
316
317    qf_setup = ceed.QFunctionByName("Mass1DBuild")
318    qf_mass = ceed.QFunctionByName("MassApply")
319
320    print(qf_setup)
321    print(qf_mass)
322
323    stdout, stderr, ref_stdout = check.output(capsys)
324    assert not stderr
325    assert stdout == ref_stdout
326
327# -------------------------------------------------------------------------------
328