1# Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and other CEED contributors 2# All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3# 4# SPDX-License-Identifier: BSD-2-Clause 5# 6# This file is part of CEED: http://github.com/ceed 7 8from _ceed_cffi import ffi, lib 9import ctypes 10import tempfile 11from abc import ABC 12 13# ------------------------------------------------------------------------------ 14 15 16class _QFunctionBase(ABC): 17 """Ceed QFunction: point-wise operation at quadrature points for evaluating 18 volumetric terms.""" 19 20 # Destructor 21 def __del__(self): 22 # libCEED call 23 err_code = lib.CeedQFunctionDestroy(self._pointer) 24 self._ceed._check_error(err_code) 25 26 # Representation 27 def __repr__(self): 28 return "<CeedQFunction instance at " + hex(id(self)) + ">" 29 30 # String conversion for print() to stdout 31 def __str__(self): 32 """View a QFunction via print().""" 33 34 # libCEED call 35 with tempfile.NamedTemporaryFile() as key_file: 36 with open(key_file.name, 'r+') as stream_file: 37 stream = ffi.cast("FILE *", stream_file) 38 39 err_code = lib.CeedQFunctionView(self._pointer[0], stream) 40 self._ceed._check_error(err_code) 41 42 stream_file.seek(0) 43 out_string = stream_file.read() 44 45 return out_string 46 47 # Apply CeedQFunction 48 def apply(self, q, inputs, outputs): 49 """Apply the action of a QFunction. 50 51 Args: 52 q: number of quadrature points 53 *inputs: array of input data vectors 54 *outputs: array of output data vectors""" 55 56 # Array of vectors 57 invecs = ffi.new("CeedVector[16]") 58 for i in range(min(16, len(inputs))): 59 invecs[i] = inputs[i]._pointer[0] 60 outvecs = ffi.new("CeedVector[16]") 61 for i in range(min(16, len(outputs))): 62 outvecs[i] = outputs[i]._pointer[0] 63 64 # libCEED call 65 err_code = lib.CeedQFunctionApply(self._pointer[0], q, invecs, outvecs) 66 self._ceed._check_error(err_code) 67 68 # Clean-up 69 ffi.release(invecs) 70 ffi.release(outvecs) 71 72 73# ------------------------------------------------------------------------------ 74class QFunction(_QFunctionBase): 75 """Ceed QFunction: point-wise operation at quadrature points for evaluating 76 volumetric terms.""" 77 78 # Constructor 79 def __init__(self, ceed, vlength, f, source): 80 # libCEED object 81 self._pointer = ffi.new("CeedQFunction *") 82 83 # Reference to Ceed 84 self._ceed = ceed 85 86 # Function pointer 87 fpointer = ffi.cast( 88 "CeedQFunctionUser", ctypes.cast( 89 f, ctypes.c_void_p).value) 90 91 # libCEED call 92 sourceAscii = ffi.new("char[]", source.encode('ascii')) 93 err_code = lib.CeedQFunctionCreateInterior(self._ceed._pointer[0], vlength, 94 fpointer, sourceAscii, self._pointer) 95 self._ceed._check_error(err_code) 96 97 # Set context data 98 def set_context(self, ctx): 99 """Set global context for a QFunction. 100 101 Args: 102 ctx: Ceed User Context object holding context data""" 103 104 # libCEED call 105 err_code = lib.CeedQFunctionSetContext( 106 self._pointer[0], 107 ctx._pointer[0]) 108 self._ceed._check_error(err_code) 109 110 # Add fields to CeedQFunction 111 def add_input(self, fieldname, size, emode): 112 """Add a QFunction input. 113 114 Args: 115 fieldname: name of QFunction field 116 size: size of QFunction field, (ncomp * dim) for CEED_EVAL_GRAD or 117 (ncomp * 1) for CEED_EVAL_NONE and CEED_EVAL_INTERP 118 **emode: CEED_EVAL_NONE to use values directly, 119 CEED_EVAL_INTERP to use interpolated values, 120 CEED_EVAL_GRAD to use gradients.""" 121 122 # libCEED call 123 fieldnameAscii = ffi.new("char[]", fieldname.encode('ascii')) 124 err_code = lib.CeedQFunctionAddInput( 125 self._pointer[0], fieldnameAscii, size, emode) 126 self._ceed._check_error(err_code) 127 128 def add_output(self, fieldname, size, emode): 129 """Add a QFunction output. 130 131 Args: 132 fieldname: name of QFunction field 133 size: size of QFunction field, (ncomp * dim) for CEED_EVAL_GRAD or 134 (ncomp * 1) for CEED_EVAL_NONE and CEED_EVAL_INTERP 135 **emode: CEED_EVAL_NONE to use values directly, 136 CEED_EVAL_INTERP to use interpolated values, 137 CEED_EVAL_GRAD to use gradients.""" 138 139 # libCEED call 140 fieldnameAscii = ffi.new("char[]", fieldname.encode('ascii')) 141 err_code = lib.CeedQFunctionAddOutput( 142 self._pointer[0], fieldnameAscii, size, emode) 143 self._ceed._check_error(err_code) 144 145# ------------------------------------------------------------------------------ 146 147 148class QFunctionByName(_QFunctionBase): 149 """Ceed QFunction By Name: point-wise operation at quadrature points 150 from a given gallery, for evaluating volumetric terms.""" 151 152 # Constructor 153 def __init__(self, ceed, name): 154 # libCEED object 155 self._pointer = ffi.new("CeedQFunction *") 156 157 # Reference to Ceed 158 self._ceed = ceed 159 160 # libCEED call 161 nameAscii = ffi.new("char[]", name.encode('ascii')) 162 err_code = lib.CeedQFunctionCreateInteriorByName(self._ceed._pointer[0], 163 nameAscii, self._pointer) 164 self._ceed._check_error(err_code) 165 166# ------------------------------------------------------------------------------ 167 168 169class IdentityQFunction(_QFunctionBase): 170 """Ceed Identity QFunction: identity qfunction operation.""" 171 172 # Constructor 173 def __init__(self, ceed, size, inmode, outmode): 174 # libCEED object 175 self._pointer = ffi.new("CeedQFunction *") 176 177 # Reference to Ceed 178 self._ceed = ceed 179 180 # libCEED call 181 err_code = lib.CeedQFunctionCreateIdentity(self._ceed._pointer[0], size, 182 inmode, outmode, self._pointer) 183 184# ------------------------------------------------------------------------------ 185