1*9ba83ac0SJeremy L Thompson# Copyright (c) 2017-2026, Lawrence Livermore National Security, LLC and other CEED contributors 23d8e8822SJeremy L Thompson# All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 30ef72598Sjeremylt# 43d8e8822SJeremy L Thompson# SPDX-License-Identifier: BSD-2-Clause 50ef72598Sjeremylt# 63d8e8822SJeremy L Thompson# This file is part of CEED: http://github.com/ceed 70ef72598Sjeremylt 80ef72598Sjeremylt# @file 90ef72598Sjeremylt# Test Ceed QFunction functionality 100ef72598Sjeremylt 110ef72598Sjeremyltimport os 120ef72598Sjeremyltimport libceed 130ef72598Sjeremyltimport numpy as np 140ef72598Sjeremyltimport check 150ef72598Sjeremylt 1680a9ef05SNatalie BeamsTOL = libceed.EPSILON * 256 1780a9ef05SNatalie Beams 180ef72598Sjeremylt# ------------------------------------------------------------------------------- 190ef72598Sjeremylt# Utility 200ef72598Sjeremylt# ------------------------------------------------------------------------------- 210ef72598Sjeremylt 220ef72598Sjeremylt 230ef72598Sjeremyltdef load_qfs_so(): 241f401ad2SJeremy L Thompson from sysconfig import get_config_var 250ef72598Sjeremylt import ctypes 260ef72598Sjeremylt 270ef72598Sjeremylt file_dir = os.path.dirname(os.path.abspath(__file__)) 280ef72598Sjeremylt qfs_so = os.path.join( 290ef72598Sjeremylt file_dir, 300ef72598Sjeremylt "libceed_qfunctions" + get_config_var("EXT_SUFFIX")) 310ef72598Sjeremylt 320ef72598Sjeremylt # Load library 330ef72598Sjeremylt return ctypes.cdll.LoadLibrary(qfs_so) 340ef72598Sjeremylt 350ef72598Sjeremylt# ------------------------------------------------------------------------------- 360ef72598Sjeremylt# Test creation, evaluation, and destruction for qfunction 370ef72598Sjeremylt# ------------------------------------------------------------------------------- 380ef72598Sjeremylt 390ef72598Sjeremylt 400ef72598Sjeremyltdef test_400(ceed_resource): 410ef72598Sjeremylt ceed = libceed.Ceed(ceed_resource) 420ef72598Sjeremylt 430ef72598Sjeremylt file_dir = os.path.dirname(os.path.abspath(__file__)) 440ef72598Sjeremylt qfs = load_qfs_so() 450ef72598Sjeremylt 460ef72598Sjeremylt qf_setup = ceed.QFunction(1, qfs.setup_mass, 470ef72598Sjeremylt os.path.join(file_dir, "test-qfunctions.h:setup_mass")) 480ef72598Sjeremylt qf_setup.add_input("w", 1, libceed.EVAL_WEIGHT) 490ef72598Sjeremylt qf_setup.add_input("dx", 1, libceed.EVAL_GRAD) 500ef72598Sjeremylt qf_setup.add_output("qdata", 1, libceed.EVAL_NONE) 510ef72598Sjeremylt 520ef72598Sjeremylt qf_mass = ceed.QFunction(1, qfs.apply_mass, 530ef72598Sjeremylt os.path.join(file_dir, "test-qfunctions.h:apply_mass")) 540ef72598Sjeremylt qf_mass.add_input("qdata", 1, libceed.EVAL_NONE) 550ef72598Sjeremylt qf_mass.add_input("u", 1, libceed.EVAL_INTERP) 560ef72598Sjeremylt qf_mass.add_output("v", 1, libceed.EVAL_INTERP) 570ef72598Sjeremylt 580ef72598Sjeremylt q = 8 590ef72598Sjeremylt 6080a9ef05SNatalie Beams w_array = np.zeros(q, dtype=ceed.scalar_type()) 6180a9ef05SNatalie Beams u_array = np.zeros(q, dtype=ceed.scalar_type()) 6280a9ef05SNatalie Beams v_true = np.zeros(q, dtype=ceed.scalar_type()) 630ef72598Sjeremylt for i in range(q): 640ef72598Sjeremylt x = 2. * i / (q - 1) - 1 650ef72598Sjeremylt w_array[i] = 1 - x * x 660ef72598Sjeremylt u_array[i] = 2 + 3 * x + 5 * x * x 670ef72598Sjeremylt v_true[i] = w_array[i] * u_array[i] 680ef72598Sjeremylt 690ef72598Sjeremylt dx = ceed.Vector(q) 700ef72598Sjeremylt dx.set_value(1) 710ef72598Sjeremylt w = ceed.Vector(q) 720ef72598Sjeremylt w.set_array(w_array, cmode=libceed.USE_POINTER) 730ef72598Sjeremylt u = ceed.Vector(q) 740ef72598Sjeremylt u.set_array(u_array, cmode=libceed.USE_POINTER) 750ef72598Sjeremylt v = ceed.Vector(q) 760ef72598Sjeremylt v.set_value(0) 770ef72598Sjeremylt qdata = ceed.Vector(q) 780ef72598Sjeremylt qdata.set_value(0) 790ef72598Sjeremylt 800ef72598Sjeremylt inputs = [dx, w] 810ef72598Sjeremylt outputs = [qdata] 820ef72598Sjeremylt qf_setup.apply(q, inputs, outputs) 830ef72598Sjeremylt 840ef72598Sjeremylt inputs = [qdata, u] 850ef72598Sjeremylt outputs = [v] 860ef72598Sjeremylt qf_mass.apply(q, inputs, outputs) 870ef72598Sjeremylt 880ef72598Sjeremylt with v.array_read() as v_array: 890ef72598Sjeremylt for i in range(q): 900ef72598Sjeremylt assert v_array[i] == v_true[i] 910ef72598Sjeremylt 920ef72598Sjeremylt# ------------------------------------------------------------------------------- 930ef72598Sjeremylt# Test creation, evaluation, and destruction for qfunction 940ef72598Sjeremylt# ------------------------------------------------------------------------------- 950ef72598Sjeremylt 960ef72598Sjeremylt 970ef72598Sjeremyltdef test_401(ceed_resource): 980ef72598Sjeremylt ceed = libceed.Ceed(ceed_resource) 990ef72598Sjeremylt 1000ef72598Sjeremylt file_dir = os.path.dirname(os.path.abspath(__file__)) 1010ef72598Sjeremylt qfs = load_qfs_so() 1020ef72598Sjeremylt 1030ef72598Sjeremylt qf_setup = ceed.QFunction(1, qfs.setup_mass, 1040ef72598Sjeremylt os.path.join(file_dir, "test-qfunctions.h:setup_mass")) 1050ef72598Sjeremylt qf_setup.add_input("w", 1, libceed.EVAL_WEIGHT) 1060ef72598Sjeremylt qf_setup.add_input("dx", 1, libceed.EVAL_GRAD) 1070ef72598Sjeremylt qf_setup.add_output("qdata", 1, libceed.EVAL_NONE) 1080ef72598Sjeremylt 1090ef72598Sjeremylt qf_mass = ceed.QFunction(1, qfs.apply_mass, 11080a9ef05SNatalie Beams os.path.join(file_dir, "test-qfunctions.h:apply_mass")) 1110ef72598Sjeremylt qf_mass.add_input("qdata", 1, libceed.EVAL_NONE) 1120ef72598Sjeremylt qf_mass.add_input("u", 1, libceed.EVAL_INTERP) 1130ef72598Sjeremylt qf_mass.add_output("v", 1, libceed.EVAL_INTERP) 1140ef72598Sjeremylt 11580a9ef05SNatalie Beams ctx_data = np.array([1., 2., 3., 4., 5.], dtype=ceed.scalar_type()) 1160ef72598Sjeremylt ctx = ceed.QFunctionContext() 1170ef72598Sjeremylt ctx.set_data(ctx_data) 1180ef72598Sjeremylt qf_mass.set_context(ctx) 1190ef72598Sjeremylt 1200ef72598Sjeremylt q = 8 1210ef72598Sjeremylt 12280a9ef05SNatalie Beams w_array = np.zeros(q, dtype=ceed.scalar_type()) 12380a9ef05SNatalie Beams u_array = np.zeros(q, dtype=ceed.scalar_type()) 12480a9ef05SNatalie Beams v_true = np.zeros(q, dtype=ceed.scalar_type()) 1250ef72598Sjeremylt for i in range(q): 1260ef72598Sjeremylt x = 2. * i / (q - 1) - 1 1270ef72598Sjeremylt w_array[i] = 1 - x * x 1280ef72598Sjeremylt u_array[i] = 2 + 3 * x + 5 * x * x 1290ef72598Sjeremylt v_true[i] = 5 * w_array[i] * u_array[i] 1300ef72598Sjeremylt 1310ef72598Sjeremylt dx = ceed.Vector(q) 1320ef72598Sjeremylt dx.set_value(1) 1330ef72598Sjeremylt w = ceed.Vector(q) 1340ef72598Sjeremylt w.set_array(w_array, cmode=libceed.USE_POINTER) 1350ef72598Sjeremylt u = ceed.Vector(q) 1360ef72598Sjeremylt u.set_array(u_array, cmode=libceed.USE_POINTER) 1370ef72598Sjeremylt v = ceed.Vector(q) 1380ef72598Sjeremylt v.set_value(0) 1390ef72598Sjeremylt qdata = ceed.Vector(q) 1400ef72598Sjeremylt qdata.set_value(0) 1410ef72598Sjeremylt 1420ef72598Sjeremylt inputs = [dx, w] 1430ef72598Sjeremylt outputs = [qdata] 1440ef72598Sjeremylt qf_setup.apply(q, inputs, outputs) 1450ef72598Sjeremylt 1460ef72598Sjeremylt inputs = [qdata, u] 1470ef72598Sjeremylt outputs = [v] 1480ef72598Sjeremylt qf_mass.apply(q, inputs, outputs) 1490ef72598Sjeremylt 1500ef72598Sjeremylt with v.array_read() as v_array: 1510ef72598Sjeremylt for i in range(q): 15280a9ef05SNatalie Beams assert abs(v_array[i] - v_true[i]) < TOL 1530ef72598Sjeremylt 1540ef72598Sjeremylt# ------------------------------------------------------------------------------- 1550ef72598Sjeremylt# Test viewing of qfunction 1560ef72598Sjeremylt# ------------------------------------------------------------------------------- 1570ef72598Sjeremylt 1580ef72598Sjeremylt 1590ef72598Sjeremyltdef test_402(ceed_resource, capsys): 1600ef72598Sjeremylt ceed = libceed.Ceed(ceed_resource) 1610ef72598Sjeremylt 1620ef72598Sjeremylt file_dir = os.path.dirname(os.path.abspath(__file__)) 1630ef72598Sjeremylt qfs = load_qfs_so() 1640ef72598Sjeremylt 1650ef72598Sjeremylt qf_setup = ceed.QFunction(1, qfs.setup_mass, 1660ef72598Sjeremylt os.path.join(file_dir, "test-qfunctions.h:setup_mass")) 1670ef72598Sjeremylt qf_setup.add_input("w", 1, libceed.EVAL_WEIGHT) 1680ef72598Sjeremylt qf_setup.add_input("dx", 1, libceed.EVAL_GRAD) 1690ef72598Sjeremylt qf_setup.add_output("qdata", 1, libceed.EVAL_NONE) 1700ef72598Sjeremylt 1710ef72598Sjeremylt qf_mass = ceed.QFunction(1, qfs.apply_mass, 17280a9ef05SNatalie Beams os.path.join(file_dir, "test-qfunctions.h:apply_mass")) 1730ef72598Sjeremylt qf_mass.add_input("qdata", 1, libceed.EVAL_NONE) 1740ef72598Sjeremylt qf_mass.add_input("u", 1, libceed.EVAL_INTERP) 1750ef72598Sjeremylt qf_mass.add_output("v", 1, libceed.EVAL_INTERP) 1760ef72598Sjeremylt 1770ef72598Sjeremylt print(qf_setup) 1780ef72598Sjeremylt print(qf_mass) 1790ef72598Sjeremylt 18080a9ef05SNatalie Beams if libceed.lib.CEED_SCALAR_TYPE == libceed.SCALAR_FP64: 18180a9ef05SNatalie Beams ctx_data = np.array([1., 2., 3., 4., 5.], dtype="float64") 18280a9ef05SNatalie Beams # Make ctx twice as long in fp32, so size will be the same as fp64 output 18380a9ef05SNatalie Beams else: 18480a9ef05SNatalie Beams ctx_data = np.array([1., 2., 3., 4., 5., 1., 2., 3., 4., 5.], 18580a9ef05SNatalie Beams dtype="float32") 1860ef72598Sjeremylt ctx = ceed.QFunctionContext() 1870ef72598Sjeremylt ctx.set_data(ctx_data) 1880ef72598Sjeremylt print(ctx) 1890ef72598Sjeremylt 1900ef72598Sjeremylt stdout, stderr, ref_stdout = check.output(capsys) 1910ef72598Sjeremylt assert not stderr 1920ef72598Sjeremylt assert stdout == ref_stdout 1930ef72598Sjeremylt 1940ef72598Sjeremylt# ------------------------------------------------------------------------------- 1950ef72598Sjeremylt# Test creation, evaluation, and destruction for qfunction by name 1960ef72598Sjeremylt# ------------------------------------------------------------------------------- 1970ef72598Sjeremylt 1980ef72598Sjeremylt 1990ef72598Sjeremyltdef test_410(ceed_resource): 2000ef72598Sjeremylt ceed = libceed.Ceed(ceed_resource) 2010ef72598Sjeremylt 2020ef72598Sjeremylt qf_setup = ceed.QFunctionByName("Mass1DBuild") 2030ef72598Sjeremylt qf_mass = ceed.QFunctionByName("MassApply") 2040ef72598Sjeremylt 2050ef72598Sjeremylt q = 8 2060ef72598Sjeremylt 20780a9ef05SNatalie Beams j_array = np.zeros(q, dtype=ceed.scalar_type()) 20880a9ef05SNatalie Beams w_array = np.zeros(q, dtype=ceed.scalar_type()) 20980a9ef05SNatalie Beams u_array = np.zeros(q, dtype=ceed.scalar_type()) 21080a9ef05SNatalie Beams v_true = np.zeros(q, dtype=ceed.scalar_type()) 2110ef72598Sjeremylt for i in range(q): 2120ef72598Sjeremylt x = 2. * i / (q - 1) - 1 2130ef72598Sjeremylt j_array[i] = 1 2140ef72598Sjeremylt w_array[i] = 1 - x * x 2150ef72598Sjeremylt u_array[i] = 2 + 3 * x + 5 * x * x 2160ef72598Sjeremylt v_true[i] = w_array[i] * u_array[i] 2170ef72598Sjeremylt 2180ef72598Sjeremylt j = ceed.Vector(q) 2190ef72598Sjeremylt j.set_array(j_array, cmode=libceed.USE_POINTER) 2200ef72598Sjeremylt w = ceed.Vector(q) 2210ef72598Sjeremylt w.set_array(w_array, cmode=libceed.USE_POINTER) 2220ef72598Sjeremylt u = ceed.Vector(q) 2230ef72598Sjeremylt u.set_array(u_array, cmode=libceed.USE_POINTER) 2240ef72598Sjeremylt v = ceed.Vector(q) 2250ef72598Sjeremylt v.set_value(0) 2260ef72598Sjeremylt qdata = ceed.Vector(q) 2270ef72598Sjeremylt qdata.set_value(0) 2280ef72598Sjeremylt 2290ef72598Sjeremylt inputs = [j, w] 2300ef72598Sjeremylt outputs = [qdata] 2310ef72598Sjeremylt qf_setup.apply(q, inputs, outputs) 2320ef72598Sjeremylt 2330ef72598Sjeremylt inputs = [w, u] 2340ef72598Sjeremylt outputs = [v] 2350ef72598Sjeremylt qf_mass.apply(q, inputs, outputs) 2360ef72598Sjeremylt 2370ef72598Sjeremylt with v.array_read() as v_array: 2380ef72598Sjeremylt for i in range(q): 2390ef72598Sjeremylt assert v_array[i] == v_true[i] 2400ef72598Sjeremylt 2410ef72598Sjeremylt# ------------------------------------------------------------------------------- 2420ef72598Sjeremylt# Test creation, evaluation, and destruction of identity qfunction 2430ef72598Sjeremylt# ------------------------------------------------------------------------------- 2440ef72598Sjeremylt 2450ef72598Sjeremylt 2460ef72598Sjeremyltdef test_411(ceed_resource): 2470ef72598Sjeremylt ceed = libceed.Ceed(ceed_resource) 2480ef72598Sjeremylt 2490ef72598Sjeremylt qf = ceed.IdentityQFunction(1, libceed.EVAL_INTERP, libceed.EVAL_INTERP) 2500ef72598Sjeremylt 2510ef72598Sjeremylt q = 8 2520ef72598Sjeremylt 25380a9ef05SNatalie Beams u_array = np.zeros(q, dtype=ceed.scalar_type()) 2540ef72598Sjeremylt for i in range(q): 2550ef72598Sjeremylt u_array[i] = i * i 2560ef72598Sjeremylt 2570ef72598Sjeremylt u = ceed.Vector(q) 2580ef72598Sjeremylt u.set_array(u_array, cmode=libceed.USE_POINTER) 2590ef72598Sjeremylt v = ceed.Vector(q) 2600ef72598Sjeremylt v.set_value(0) 2610ef72598Sjeremylt 2620ef72598Sjeremylt inputs = [u] 2630ef72598Sjeremylt outputs = [v] 2640ef72598Sjeremylt qf.apply(q, inputs, outputs) 2650ef72598Sjeremylt 2660ef72598Sjeremylt with v.array_read() as v_array: 2670ef72598Sjeremylt for i in range(q): 2680ef72598Sjeremylt assert v_array[i] == i * i 2690ef72598Sjeremylt 2700ef72598Sjeremylt# ------------------------------------------------------------------------------- 2710ef72598Sjeremylt# Test creation, evaluation, and destruction of identity qfunction with size>1 2720ef72598Sjeremylt# ------------------------------------------------------------------------------- 2730ef72598Sjeremylt 2740ef72598Sjeremylt 2750ef72598Sjeremyltdef test_412(ceed_resource): 2760ef72598Sjeremylt ceed = libceed.Ceed(ceed_resource) 2770ef72598Sjeremylt 2780ef72598Sjeremylt size = 3 2790ef72598Sjeremylt qf = ceed.IdentityQFunction(size, libceed.EVAL_INTERP, libceed.EVAL_INTERP) 2800ef72598Sjeremylt 2810ef72598Sjeremylt q = 8 2820ef72598Sjeremylt 28380a9ef05SNatalie Beams u_array = np.zeros(q * size, dtype=ceed.scalar_type()) 2840ef72598Sjeremylt for i in range(q * size): 2850ef72598Sjeremylt u_array[i] = i * i 2860ef72598Sjeremylt 2870ef72598Sjeremylt u = ceed.Vector(q * size) 2880ef72598Sjeremylt u.set_array(u_array, cmode=libceed.USE_POINTER) 2890ef72598Sjeremylt v = ceed.Vector(q * size) 2900ef72598Sjeremylt v.set_value(0) 2910ef72598Sjeremylt 2920ef72598Sjeremylt inputs = [u] 2930ef72598Sjeremylt outputs = [v] 2940ef72598Sjeremylt qf.apply(q, inputs, outputs) 2950ef72598Sjeremylt 2960ef72598Sjeremylt with v.array_read() as v_array: 2970ef72598Sjeremylt for i in range(q * size): 2980ef72598Sjeremylt assert v_array[i] == i * i 2990ef72598Sjeremylt 3000ef72598Sjeremylt# ------------------------------------------------------------------------------- 3010ef72598Sjeremylt# Test viewing of qfunction by name 3020ef72598Sjeremylt# ------------------------------------------------------------------------------- 3030ef72598Sjeremylt 3040ef72598Sjeremylt 3050ef72598Sjeremyltdef test_413(ceed_resource, capsys): 3060ef72598Sjeremylt ceed = libceed.Ceed(ceed_resource) 3070ef72598Sjeremylt 3080ef72598Sjeremylt qf_setup = ceed.QFunctionByName("Mass1DBuild") 3090ef72598Sjeremylt qf_mass = ceed.QFunctionByName("MassApply") 3100ef72598Sjeremylt 3110ef72598Sjeremylt print(qf_setup) 3120ef72598Sjeremylt print(qf_mass) 3130ef72598Sjeremylt 3140ef72598Sjeremylt stdout, stderr, ref_stdout = check.output(capsys) 3150ef72598Sjeremylt assert not stderr 3160ef72598Sjeremylt assert stdout == ref_stdout 3170ef72598Sjeremylt 3180ef72598Sjeremylt# ------------------------------------------------------------------------------- 319