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