xref: /libCEED/python/ceed_qfunction.py (revision 4a46e67df50c06c939702143cae794ef585805bd)
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