xref: /libCEED/interface/ceed-qfunction.c (revision ca94c3ddc8f82b7d93a79f9e4812e99b8be840ff)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, 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.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
83d576824SJeremy L Thompson #include <ceed-impl.h>
949aac155SJeremy L Thompson #include <ceed.h>
102b730f8bSJeremy L Thompson #include <ceed/backend.h>
112b730f8bSJeremy L Thompson #include <ceed/jit-tools.h>
12288c0443SJeremy L Thompson #include <limits.h>
133d576824SJeremy L Thompson #include <stdbool.h>
143d576824SJeremy L Thompson #include <stdio.h>
153d576824SJeremy L Thompson #include <string.h>
16288c0443SJeremy L Thompson 
177a982d89SJeremy L. Thompson /// @file
187a982d89SJeremy L. Thompson /// Implementation of public CeedQFunction interfaces
197a982d89SJeremy L. Thompson 
20288c0443SJeremy L Thompson /// @cond DOXYGEN_SKIP
21442e7f0bSjeremylt static struct CeedQFunction_private ceed_qfunction_none;
22442e7f0bSjeremylt /// @endcond
23442e7f0bSjeremylt 
247a982d89SJeremy L. Thompson /// @addtogroup CeedQFunctionUser
257a982d89SJeremy L. Thompson /// @{
267a982d89SJeremy L. Thompson 
27*ca94c3ddSJeremy L Thompson // Indicate that no `CeedQFunction` is provided by the user
287a982d89SJeremy L. Thompson const CeedQFunction CEED_QFUNCTION_NONE = &ceed_qfunction_none;
297a982d89SJeremy L. Thompson 
307a982d89SJeremy L. Thompson /// @}
317a982d89SJeremy L. Thompson 
32442e7f0bSjeremylt /// @cond DOXYGEN_SKIP
33288c0443SJeremy L Thompson static struct {
34288c0443SJeremy L Thompson   char              name[CEED_MAX_RESOURCE_LEN];
35288c0443SJeremy L Thompson   char              source[CEED_MAX_RESOURCE_LEN];
36d1d35e2fSjeremylt   CeedInt           vec_length;
37288c0443SJeremy L Thompson   CeedQFunctionUser f;
38288c0443SJeremy L Thompson   int (*init)(Ceed ceed, const char *name, CeedQFunction qf);
39d1d35e2fSjeremylt } gallery_qfunctions[1024];
40288c0443SJeremy L Thompson static size_t num_qfunctions;
41288c0443SJeremy L Thompson /// @endcond
42d7b241e6Sjeremylt 
43777ff853SJeremy L Thompson /// ----------------------------------------------------------------------------
44777ff853SJeremy L Thompson /// CeedQFunction Library Internal Functions
45777ff853SJeremy L Thompson /// ----------------------------------------------------------------------------
46777ff853SJeremy L Thompson /// @addtogroup CeedQFunctionDeveloper
47777ff853SJeremy L Thompson /// @{
48777ff853SJeremy L Thompson 
49b11c1e72Sjeremylt /**
50*ca94c3ddSJeremy L Thompson   @brief Register a gallery `CeedQFunction`
51288c0443SJeremy L Thompson 
52ea61e9acSJeremy L Thompson   @param[in] name       Name for this backend to respond to
53*ca94c3ddSJeremy L Thompson   @param[in] source     Absolute path to source of `CeedQFunction`, "\path\CEED_DIR\gallery\folder\file.h:function_name"
54*ca94c3ddSJeremy L Thompson   @param[in] vec_length Vector length.
55*ca94c3ddSJeremy L Thompson                           Caller must ensure that number of quadrature points is a multiple of `vec_length`.
56ea61e9acSJeremy L Thompson   @param[in] f          Function pointer to evaluate action at quadrature points.
57*ca94c3ddSJeremy L Thompson                           See `CeedQFunctionUser`.
58*ca94c3ddSJeremy L Thompson   @param[in] init       Initialization function called by @ref CeedQFunctionCreateInteriorByName() when the `CeedQFunction` is selected.
59288c0443SJeremy L Thompson 
60288c0443SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
61288c0443SJeremy L Thompson 
627a982d89SJeremy L. Thompson   @ref Developer
63288c0443SJeremy L Thompson **/
642b730f8bSJeremy L Thompson int CeedQFunctionRegister(const char *name, const char *source, CeedInt vec_length, CeedQFunctionUser f,
65288c0443SJeremy L Thompson                           int (*init)(Ceed, const char *, CeedQFunction)) {
661c66c397SJeremy L Thompson   const char *relative_file_path;
6758c07c4fSSebastian Grimberg   int         ierr = 0;
68c042f62fSJeremy L Thompson 
698ccf1006SJeremy L Thompson   CeedDebugEnv("Gallery Register: %s", name);
702b730f8bSJeremy L Thompson   CeedCall(CeedGetJitRelativePath(source, &relative_file_path));
7158c07c4fSSebastian Grimberg   CeedPragmaCritical(CeedQFunctionRegister) {
7258c07c4fSSebastian Grimberg     if (num_qfunctions < sizeof(gallery_qfunctions) / sizeof(gallery_qfunctions[0])) {
73d1d35e2fSjeremylt       strncpy(gallery_qfunctions[num_qfunctions].name, name, CEED_MAX_RESOURCE_LEN);
74d1d35e2fSjeremylt       gallery_qfunctions[num_qfunctions].name[CEED_MAX_RESOURCE_LEN - 1] = 0;
752b730f8bSJeremy L Thompson       strncpy(gallery_qfunctions[num_qfunctions].source, relative_file_path, CEED_MAX_RESOURCE_LEN);
76d1d35e2fSjeremylt       gallery_qfunctions[num_qfunctions].source[CEED_MAX_RESOURCE_LEN - 1] = 0;
77d1d35e2fSjeremylt       gallery_qfunctions[num_qfunctions].vec_length                        = vec_length;
78d1d35e2fSjeremylt       gallery_qfunctions[num_qfunctions].f                                 = f;
79d1d35e2fSjeremylt       gallery_qfunctions[num_qfunctions].init                              = init;
80288c0443SJeremy L Thompson       num_qfunctions++;
8158c07c4fSSebastian Grimberg     } else {
8258c07c4fSSebastian Grimberg       ierr = 1;
8358c07c4fSSebastian Grimberg     }
8458c07c4fSSebastian Grimberg   }
8558c07c4fSSebastian Grimberg   // LCOV_EXCL_START
86*ca94c3ddSJeremy L Thompson   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "Too many gallery CeedQFunctions");
8758c07c4fSSebastian Grimberg   // LCOV_EXCL_STOP
88e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
89288c0443SJeremy L Thompson }
90288c0443SJeremy L Thompson 
91288c0443SJeremy L Thompson /**
92*ca94c3ddSJeremy L Thompson   @brief Set a `CeedQFunction` field, used by @ref CeedQFunctionAddInput() and @ref CeedQFunctionAddOutput()
937a982d89SJeremy L. Thompson 
94*ca94c3ddSJeremy L Thompson   @param[out] f           `CeedQFunctionField`
95*ca94c3ddSJeremy L Thompson   @param[in]  field_name  Name of `CeedQFunction` field
96*ca94c3ddSJeremy L Thompson   @param[in]  size        Size of `CeedQFunction` field, (`num_comp * 1`) for @ref CEED_EVAL_NONE and @ref CEED_EVAL_WEIGHT, (`num_comp * 1`) for @ref CEED_EVAL_INTERP for an \f$H^1\f$ space or (`num_comp * dim`) for an \f$H(\mathrm{div})\f$ or \f$H(\mathrm{curl})\f$ space, (`num_comp * dim`) for @ref CEED_EVAL_GRAD, or (num_comp * 1) for @ref CEED_EVAL_DIV, and (`num_comp * curl_dim`) with `curl_dim = 1` if `dim < 3` and `curl_dim = dim` for @ref CEED_EVAL_CURL.
97*ca94c3ddSJeremy L Thompson   @param[in]  eval_mode   @ref CEED_EVAL_NONE to use values directly,
98*ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_WEIGHT to use quadrature weights,
99*ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_INTERP to use interpolated values,
100*ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_GRAD to use gradients,
101*ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_DIV to use divergence,
102*ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_CURL to use curl
1037a982d89SJeremy L. Thompson 
1047a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1057a982d89SJeremy L. Thompson 
1067a982d89SJeremy L. Thompson   @ref Developer
1077a982d89SJeremy L. Thompson **/
1082b730f8bSJeremy L Thompson static int CeedQFunctionFieldSet(CeedQFunctionField *f, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
1092b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, f));
1102b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(field_name, (char **)&(*f)->field_name));
1117a982d89SJeremy L. Thompson   (*f)->size      = size;
112d1d35e2fSjeremylt   (*f)->eval_mode = eval_mode;
113e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1147a982d89SJeremy L. Thompson }
1157a982d89SJeremy L. Thompson 
1167a982d89SJeremy L. Thompson /**
117*ca94c3ddSJeremy L Thompson   @brief View a field of a `CeedQFunction`
1187a982d89SJeremy L. Thompson 
119*ca94c3ddSJeremy L Thompson   @param[in] field        `CeedQFunction` field to view
120d1d35e2fSjeremylt   @param[in] field_number Number of field being viewed
1214c4400c7SValeria Barra   @param[in] in           true for input field, false for output
122*ca94c3ddSJeremy L Thompson   @param[in] stream       Stream to view to, e.g., `stdout`
1237a982d89SJeremy L. Thompson 
1247a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1257a982d89SJeremy L. Thompson 
1267a982d89SJeremy L. Thompson   @ref Utility
1277a982d89SJeremy L. Thompson **/
1282b730f8bSJeremy L Thompson static int CeedQFunctionFieldView(CeedQFunctionField field, CeedInt field_number, bool in, FILE *stream) {
1297a982d89SJeremy L. Thompson   const char  *inout = in ? "Input" : "Output";
1308229195eSjeremylt   char        *field_name;
1318229195eSjeremylt   CeedInt      size;
1328229195eSjeremylt   CeedEvalMode eval_mode;
1331c66c397SJeremy L Thompson 
1341c66c397SJeremy L Thompson   CeedCall(CeedQFunctionFieldGetName(field, &field_name));
1351c66c397SJeremy L Thompson   CeedCall(CeedQFunctionFieldGetSize(field, &size));
1362b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionFieldGetEvalMode(field, &eval_mode));
1372b730f8bSJeremy L Thompson   fprintf(stream,
1382b730f8bSJeremy L Thompson           "    %s field %" CeedInt_FMT
1392b730f8bSJeremy L Thompson           ":\n"
1407a982d89SJeremy L. Thompson           "      Name: \"%s\"\n"
1412b730f8bSJeremy L Thompson           "      Size: %" CeedInt_FMT
1422b730f8bSJeremy L Thompson           "\n"
1437a982d89SJeremy L. Thompson           "      EvalMode: \"%s\"\n",
1448229195eSjeremylt           inout, field_number, field_name, size, CeedEvalModes[eval_mode]);
145e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1467a982d89SJeremy L. Thompson }
1477a982d89SJeremy L. Thompson 
148777ff853SJeremy L Thompson /**
149777ff853SJeremy L Thompson   @brief Set flag to determine if Fortran interface is used
150777ff853SJeremy L Thompson 
151ea61e9acSJeremy L Thompson   @param[in,out] qf     CeedQFunction
152ea61e9acSJeremy L Thompson   @param[in]     status Boolean value to set as Fortran status
153777ff853SJeremy L Thompson 
154777ff853SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
155777ff853SJeremy L Thompson 
156777ff853SJeremy L Thompson   @ref Backend
157777ff853SJeremy L Thompson **/
158777ff853SJeremy L Thompson int CeedQFunctionSetFortranStatus(CeedQFunction qf, bool status) {
159f04ea552SJeremy L Thompson   qf->is_fortran = status;
160e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
161777ff853SJeremy L Thompson }
162777ff853SJeremy L Thompson 
1637a982d89SJeremy L. Thompson /// @}
1647a982d89SJeremy L. Thompson 
1657a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1667a982d89SJeremy L. Thompson /// CeedQFunction Backend API
1677a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1687a982d89SJeremy L. Thompson /// @addtogroup CeedQFunctionBackend
1697a982d89SJeremy L. Thompson /// @{
1707a982d89SJeremy L. Thompson 
1717a982d89SJeremy L. Thompson /**
172*ca94c3ddSJeremy L Thompson   @brief Get the vector length of a `CeedQFunction`
1737a982d89SJeremy L. Thompson 
174*ca94c3ddSJeremy L Thompson   @param[in]  qf         `CeedQFunction`
175d1d35e2fSjeremylt   @param[out] vec_length Variable to store vector length
1767a982d89SJeremy L. Thompson 
1777a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1787a982d89SJeremy L. Thompson 
1797a982d89SJeremy L. Thompson   @ref Backend
1807a982d89SJeremy L. Thompson **/
181d1d35e2fSjeremylt int CeedQFunctionGetVectorLength(CeedQFunction qf, CeedInt *vec_length) {
182d1d35e2fSjeremylt   *vec_length = qf->vec_length;
183e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1847a982d89SJeremy L. Thompson }
1857a982d89SJeremy L. Thompson 
1867a982d89SJeremy L. Thompson /**
187*ca94c3ddSJeremy L Thompson   @brief Get the number of inputs and outputs to a `CeedQFunction`
1887a982d89SJeremy L. Thompson 
189*ca94c3ddSJeremy L Thompson   @param[in]  qf         `CeedQFunction`
190d1d35e2fSjeremylt   @param[out] num_input  Variable to store number of input fields
191d1d35e2fSjeremylt   @param[out] num_output Variable to store number of output fields
1927a982d89SJeremy L. Thompson 
1937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1947a982d89SJeremy L. Thompson 
1957a982d89SJeremy L. Thompson   @ref Backend
1967a982d89SJeremy L. Thompson **/
1972b730f8bSJeremy L Thompson int CeedQFunctionGetNumArgs(CeedQFunction qf, CeedInt *num_input, CeedInt *num_output) {
198d1d35e2fSjeremylt   if (num_input) *num_input = qf->num_input_fields;
199d1d35e2fSjeremylt   if (num_output) *num_output = qf->num_output_fields;
200e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2017a982d89SJeremy L. Thompson }
2027a982d89SJeremy L. Thompson 
2037a982d89SJeremy L. Thompson /**
204*ca94c3ddSJeremy L Thompson   @brief Get the name of the user function for a `CeedQFunction`
2057a982d89SJeremy L. Thompson 
206*ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
20743e1b16fSJeremy L Thompson   @param[out] kernel_name Variable to store source path string
2087a982d89SJeremy L. Thompson 
2097a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2107a982d89SJeremy L. Thompson 
2117a982d89SJeremy L. Thompson   @ref Backend
2127a982d89SJeremy L. Thompson **/
21343e1b16fSJeremy L Thompson int CeedQFunctionGetKernelName(CeedQFunction qf, char **kernel_name) {
214ca5eadf8SJeremy L Thompson   if (!qf->kernel_name) {
215ca5eadf8SJeremy L Thompson     Ceed  ceed;
216ca5eadf8SJeremy L Thompson     char *kernel_name_copy;
217ca5eadf8SJeremy L Thompson 
2181c66c397SJeremy L Thompson     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
219ca5eadf8SJeremy L Thompson     if (qf->user_source) {
220ca5eadf8SJeremy L Thompson       const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
221ca5eadf8SJeremy L Thompson       size_t      kernel_name_len = strlen(kernel_name);
222ca5eadf8SJeremy L Thompson 
2232b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(kernel_name_len + 1, &kernel_name_copy));
224ca5eadf8SJeremy L Thompson       memcpy(kernel_name_copy, kernel_name, kernel_name_len);
225ca5eadf8SJeremy L Thompson     } else {
2262b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(1, &kernel_name_copy));
227ca5eadf8SJeremy L Thompson     }
228ca5eadf8SJeremy L Thompson     qf->kernel_name = kernel_name_copy;
229ca5eadf8SJeremy L Thompson   }
230ca5eadf8SJeremy L Thompson 
23143e1b16fSJeremy L Thompson   *kernel_name = (char *)qf->kernel_name;
23243e1b16fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
23343e1b16fSJeremy L Thompson }
23443e1b16fSJeremy L Thompson 
23543e1b16fSJeremy L Thompson /**
236*ca94c3ddSJeremy L Thompson   @brief Get the source path string for a `CeedQFunction`
23743e1b16fSJeremy L Thompson 
238*ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
23943e1b16fSJeremy L Thompson   @param[out] source_path Variable to store source path string
24043e1b16fSJeremy L Thompson 
24143e1b16fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
24243e1b16fSJeremy L Thompson 
24343e1b16fSJeremy L Thompson   @ref Backend
24443e1b16fSJeremy L Thompson **/
24543e1b16fSJeremy L Thompson int CeedQFunctionGetSourcePath(CeedQFunction qf, char **source_path) {
246ca5eadf8SJeremy L Thompson   if (!qf->source_path && qf->user_source) {
247ca5eadf8SJeremy L Thompson     Ceed        ceed;
248ca5eadf8SJeremy L Thompson     bool        is_absolute_path;
249ca5eadf8SJeremy L Thompson     char       *absolute_path, *source_path_copy;
250ca5eadf8SJeremy L Thompson     const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
251ca5eadf8SJeremy L Thompson     size_t      kernel_name_len = strlen(kernel_name);
252ca5eadf8SJeremy L Thompson 
2532b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
2542b730f8bSJeremy L Thompson     CeedCall(CeedCheckFilePath(ceed, qf->user_source, &is_absolute_path));
255ca5eadf8SJeremy L Thompson     if (is_absolute_path) {
256ca5eadf8SJeremy L Thompson       absolute_path = (char *)qf->user_source;
257ca5eadf8SJeremy L Thompson     } else {
2582b730f8bSJeremy L Thompson       CeedCall(CeedGetJitAbsolutePath(ceed, qf->user_source, &absolute_path));
259ca5eadf8SJeremy L Thompson     }
260ca5eadf8SJeremy L Thompson 
261ca5eadf8SJeremy L Thompson     size_t source_len = strlen(absolute_path) - kernel_name_len - 1;
2621c66c397SJeremy L Thompson 
2632b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(source_len + 1, &source_path_copy));
264ca5eadf8SJeremy L Thompson     memcpy(source_path_copy, absolute_path, source_len);
265ca5eadf8SJeremy L Thompson     qf->source_path = source_path_copy;
266ca5eadf8SJeremy L Thompson 
2672b730f8bSJeremy L Thompson     if (!is_absolute_path) CeedCall(CeedFree(&absolute_path));
268ca5eadf8SJeremy L Thompson   }
269ca5eadf8SJeremy L Thompson 
27043e1b16fSJeremy L Thompson   *source_path = (char *)qf->source_path;
271e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2727a982d89SJeremy L. Thompson }
2737a982d89SJeremy L. Thompson 
2747a982d89SJeremy L. Thompson /**
275*ca94c3ddSJeremy L Thompson   @brief Initialize and load `CeedQFunction` source file into string buffer, including full text of local files in place of `#include "local.h"`.
2764385fb7fSSebastian Grimberg 
277*ca94c3ddSJeremy L Thompson   The `buffer` is set to `NULL` if there is no `CeedQFunction` source file.
2784385fb7fSSebastian Grimberg 
279*ca94c3ddSJeremy L Thompson   Note: Caller is responsible for freeing the string buffer with @ref CeedFree().
2803d3250a0SJeremy L Thompson 
281*ca94c3ddSJeremy L Thompson   @param[in]  qf            `CeedQFunction`
282f74ec584SJeremy L Thompson   @param[out] source_buffer String buffer for source file contents
2833d3250a0SJeremy L Thompson 
2843d3250a0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2853d3250a0SJeremy L Thompson 
2863d3250a0SJeremy L Thompson   @ref Backend
2873d3250a0SJeremy L Thompson **/
2883d3250a0SJeremy L Thompson int CeedQFunctionLoadSourceToBuffer(CeedQFunction qf, char **source_buffer) {
2893d3250a0SJeremy L Thompson   char *source_path;
2903d3250a0SJeremy L Thompson 
2912b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetSourcePath(qf, &source_path));
2923d3250a0SJeremy L Thompson   *source_buffer = NULL;
2933d3250a0SJeremy L Thompson   if (source_path) {
2942b730f8bSJeremy L Thompson     CeedCall(CeedLoadSourceToBuffer(qf->ceed, source_path, source_buffer));
2953d3250a0SJeremy L Thompson   }
2963d3250a0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2973d3250a0SJeremy L Thompson }
2983d3250a0SJeremy L Thompson 
2993d3250a0SJeremy L Thompson /**
300*ca94c3ddSJeremy L Thompson   @brief Get the User Function for a `CeedQFunction`
3017a982d89SJeremy L. Thompson 
302*ca94c3ddSJeremy L Thompson   @param[in]  qf `CeedQFunction`
3037a982d89SJeremy L. Thompson   @param[out] f  Variable to store user function
3047a982d89SJeremy L. Thompson 
3057a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3067a982d89SJeremy L. Thompson 
3077a982d89SJeremy L. Thompson   @ref Backend
3087a982d89SJeremy L. Thompson **/
3097a982d89SJeremy L. Thompson int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) {
3107a982d89SJeremy L. Thompson   *f = qf->function;
311e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3127a982d89SJeremy L. Thompson }
3137a982d89SJeremy L. Thompson 
3147a982d89SJeremy L. Thompson /**
315*ca94c3ddSJeremy L Thompson   @brief Get global context for a `CeedQFunction`.
3164385fb7fSSebastian Grimberg 
317*ca94c3ddSJeremy L Thompson   Note: For `CeedQFunction` from the Fortran interface, this function will return the Fortran context `CeedQFunctionContext`.
3187a982d89SJeremy L. Thompson 
319ea61e9acSJeremy L Thompson   @param[in]  qf  CeedQFunction
320777ff853SJeremy L Thompson   @param[out] ctx Variable to store CeedQFunctionContext
3217a982d89SJeremy L. Thompson 
3227a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3237a982d89SJeremy L. Thompson 
3247a982d89SJeremy L. Thompson   @ref Backend
3257a982d89SJeremy L. Thompson **/
326777ff853SJeremy L Thompson int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
3277a982d89SJeremy L. Thompson   *ctx = qf->ctx;
328e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3297a982d89SJeremy L. Thompson }
3307a982d89SJeremy L. Thompson 
3317a982d89SJeremy L. Thompson /**
332*ca94c3ddSJeremy L Thompson   @brief Get context data of a `CeedQFunction`
333441428dfSJeremy L Thompson 
334*ca94c3ddSJeremy L Thompson   @param[in]  qf       `CeedQFunction`
335ea61e9acSJeremy L Thompson   @param[in]  mem_type Memory type on which to access the data.
336ea61e9acSJeremy L Thompson                          If the backend uses a different memory type, this will perform a copy.
337441428dfSJeremy L Thompson   @param[out] data     Data on memory type mem_type
338441428dfSJeremy L Thompson 
339441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
340441428dfSJeremy L Thompson 
341441428dfSJeremy L Thompson   @ref Backend
342441428dfSJeremy L Thompson **/
3432b730f8bSJeremy L Thompson int CeedQFunctionGetContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
344441428dfSJeremy L Thompson   bool                 is_writable;
345441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
346441428dfSJeremy L Thompson 
3472b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &ctx));
348441428dfSJeremy L Thompson   if (ctx) {
3492b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
350441428dfSJeremy L Thompson     if (is_writable) {
3512b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
352441428dfSJeremy L Thompson     } else {
3532b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
354441428dfSJeremy L Thompson     }
355441428dfSJeremy L Thompson   } else {
356441428dfSJeremy L Thompson     *(void **)data = NULL;
357441428dfSJeremy L Thompson   }
358441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
359441428dfSJeremy L Thompson }
360441428dfSJeremy L Thompson 
361441428dfSJeremy L Thompson /**
362*ca94c3ddSJeremy L Thompson   @brief Restore context data of a `CeedQFunction`
363441428dfSJeremy L Thompson 
364*ca94c3ddSJeremy L Thompson   @param[in]     qf   `CeedQFunction`
365ea61e9acSJeremy L Thompson   @param[in,out] data Data to restore
366441428dfSJeremy L Thompson 
367441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
368441428dfSJeremy L Thompson 
369441428dfSJeremy L Thompson   @ref Backend
370441428dfSJeremy L Thompson **/
371441428dfSJeremy L Thompson int CeedQFunctionRestoreContextData(CeedQFunction qf, void *data) {
372441428dfSJeremy L Thompson   bool                 is_writable;
373441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
374441428dfSJeremy L Thompson 
3752b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &ctx));
376441428dfSJeremy L Thompson   if (ctx) {
3772b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
378441428dfSJeremy L Thompson     if (is_writable) {
3792b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
380441428dfSJeremy L Thompson     } else {
3812b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
382441428dfSJeremy L Thompson     }
383441428dfSJeremy L Thompson   }
3845f249b39SJeremy L Thompson   *(void **)data = NULL;
385441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
386441428dfSJeremy L Thompson }
387441428dfSJeremy L Thompson 
388441428dfSJeremy L Thompson /**
389*ca94c3ddSJeremy L Thompson   @brief Get true user context for a `CeedQFunction`
3904385fb7fSSebastian Grimberg 
391*ca94c3ddSJeremy L Thompson   Note: For all `CeedQFunction` this function will return the user `CeedQFunctionContext` and not interface context `CeedQFunctionContext`, if any such object exists.
3927a982d89SJeremy L. Thompson 
393*ca94c3ddSJeremy L Thompson   @param[in]  qf  `CeedQFunction`
394*ca94c3ddSJeremy L Thompson   @param[out] ctx Variable to store `CeedQFunctionContext`
3957a982d89SJeremy L. Thompson 
3967a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3977a982d89SJeremy L. Thompson   @ref Backend
3987a982d89SJeremy L. Thompson **/
399777ff853SJeremy L Thompson int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
400f04ea552SJeremy L Thompson   if (qf->is_fortran) {
401d1d35e2fSjeremylt     CeedFortranContext fortran_ctx = NULL;
4021c66c397SJeremy L Thompson 
4032b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionContextGetData(qf->ctx, CEED_MEM_HOST, &fortran_ctx));
4048cb0412aSJeremy L Thompson     *ctx = fortran_ctx->inner_ctx;
4052b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionContextRestoreData(qf->ctx, (void *)&fortran_ctx));
4067a982d89SJeremy L. Thompson   } else {
4077a982d89SJeremy L. Thompson     *ctx = qf->ctx;
4087a982d89SJeremy L. Thompson   }
409e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4107a982d89SJeremy L. Thompson }
4117a982d89SJeremy L. Thompson 
4127a982d89SJeremy L. Thompson /**
413*ca94c3ddSJeremy L Thompson   @brief Get inner context data of a `CeedQFunction`
414441428dfSJeremy L Thompson 
415*ca94c3ddSJeremy L Thompson   @param[in]  qf       `CeedQFunction`
416ea61e9acSJeremy L Thompson   @param[in]  mem_type Memory type on which to access the data.
417ea61e9acSJeremy L Thompson                          If the backend uses a different memory type, this will perform a copy.
418441428dfSJeremy L Thompson   @param[out] data     Data on memory type mem_type
419441428dfSJeremy L Thompson 
420441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
421441428dfSJeremy L Thompson 
422441428dfSJeremy L Thompson   @ref Backend
423441428dfSJeremy L Thompson **/
4242b730f8bSJeremy L Thompson int CeedQFunctionGetInnerContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
425441428dfSJeremy L Thompson   bool                 is_writable;
426441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
427441428dfSJeremy L Thompson 
4282b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
429441428dfSJeremy L Thompson   if (ctx) {
4302b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
431441428dfSJeremy L Thompson     if (is_writable) {
4322b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
433441428dfSJeremy L Thompson     } else {
4342b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
435441428dfSJeremy L Thompson     }
436441428dfSJeremy L Thompson   } else {
437441428dfSJeremy L Thompson     *(void **)data = NULL;
438441428dfSJeremy L Thompson   }
439441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
440441428dfSJeremy L Thompson }
441441428dfSJeremy L Thompson 
442441428dfSJeremy L Thompson /**
443*ca94c3ddSJeremy L Thompson   @brief Restore inner context data of a `CeedQFunction`
444441428dfSJeremy L Thompson 
445*ca94c3ddSJeremy L Thompson   @param[in]     qf   `CeedQFunction`
446ea61e9acSJeremy L Thompson   @param[in,out] data Data to restore
447441428dfSJeremy L Thompson 
448441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
449441428dfSJeremy L Thompson 
450441428dfSJeremy L Thompson   @ref Backend
451441428dfSJeremy L Thompson **/
452441428dfSJeremy L Thompson int CeedQFunctionRestoreInnerContextData(CeedQFunction qf, void *data) {
453441428dfSJeremy L Thompson   bool                 is_writable;
454441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
455441428dfSJeremy L Thompson 
4562b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
457441428dfSJeremy L Thompson   if (ctx) {
4582b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
459441428dfSJeremy L Thompson     if (is_writable) {
4602b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
461441428dfSJeremy L Thompson     } else {
4622b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
463441428dfSJeremy L Thompson     }
464441428dfSJeremy L Thompson   }
4655f249b39SJeremy L Thompson   *(void **)data = NULL;
466441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
467441428dfSJeremy L Thompson }
468441428dfSJeremy L Thompson 
469441428dfSJeremy L Thompson /**
470*ca94c3ddSJeremy L Thompson   @brief Determine if `CeedQFunction` is identity
4717a982d89SJeremy L. Thompson 
472*ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
473d1d35e2fSjeremylt   @param[out] is_identity Variable to store identity status
4747a982d89SJeremy L. Thompson 
4757a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4767a982d89SJeremy L. Thompson 
4777a982d89SJeremy L. Thompson   @ref Backend
4787a982d89SJeremy L. Thompson **/
479d1d35e2fSjeremylt int CeedQFunctionIsIdentity(CeedQFunction qf, bool *is_identity) {
480f04ea552SJeremy L Thompson   *is_identity = qf->is_identity;
481e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4827a982d89SJeremy L. Thompson }
4837a982d89SJeremy L. Thompson 
4847a982d89SJeremy L. Thompson /**
485*ca94c3ddSJeremy L Thompson   @brief Determine if `CeedQFunctionContext` is writable
486441428dfSJeremy L Thompson 
487*ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
488ea61e9acSJeremy L Thompson   @param[out] is_writable Variable to store context writeable status
489441428dfSJeremy L Thompson 
490441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
491441428dfSJeremy L Thompson 
492441428dfSJeremy L Thompson   @ref Backend
493441428dfSJeremy L Thompson **/
494441428dfSJeremy L Thompson int CeedQFunctionIsContextWritable(CeedQFunction qf, bool *is_writable) {
495441428dfSJeremy L Thompson   *is_writable = qf->is_context_writable;
496441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
497441428dfSJeremy L Thompson }
498441428dfSJeremy L Thompson 
499441428dfSJeremy L Thompson /**
500*ca94c3ddSJeremy L Thompson   @brief Get backend data of a `CeedQFunction`
5017a982d89SJeremy L. Thompson 
502*ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction`
5037a982d89SJeremy L. Thompson   @param[out] data Variable to store data
5047a982d89SJeremy L. Thompson 
5057a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5067a982d89SJeremy L. Thompson 
5077a982d89SJeremy L. Thompson   @ref Backend
5087a982d89SJeremy L. Thompson **/
509777ff853SJeremy L Thompson int CeedQFunctionGetData(CeedQFunction qf, void *data) {
510777ff853SJeremy L Thompson   *(void **)data = qf->data;
511e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5127a982d89SJeremy L. Thompson }
5137a982d89SJeremy L. Thompson 
5147a982d89SJeremy L. Thompson /**
515*ca94c3ddSJeremy L Thompson   @brief Set backend data of a `CeedQFunction`
5167a982d89SJeremy L. Thompson 
517*ca94c3ddSJeremy L Thompson   @param[in,out] qf   `CeedQFunction`
518ea61e9acSJeremy L Thompson   @param[in]     data Data to set
5197a982d89SJeremy L. Thompson 
5207a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5217a982d89SJeremy L. Thompson 
5227a982d89SJeremy L. Thompson   @ref Backend
5237a982d89SJeremy L. Thompson **/
524777ff853SJeremy L Thompson int CeedQFunctionSetData(CeedQFunction qf, void *data) {
525777ff853SJeremy L Thompson   qf->data = data;
526e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5277a982d89SJeremy L. Thompson }
5287a982d89SJeremy L. Thompson 
5297a982d89SJeremy L. Thompson /**
530*ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedQFunction`
53134359f16Sjeremylt 
532*ca94c3ddSJeremy L Thompson   @param[in,out] qf `CeedQFunction` to increment the reference counter
53334359f16Sjeremylt 
53434359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
53534359f16Sjeremylt 
53634359f16Sjeremylt   @ref Backend
53734359f16Sjeremylt **/
5389560d06aSjeremylt int CeedQFunctionReference(CeedQFunction qf) {
53934359f16Sjeremylt   qf->ref_count++;
54034359f16Sjeremylt   return CEED_ERROR_SUCCESS;
54134359f16Sjeremylt }
54234359f16Sjeremylt 
5436e15d496SJeremy L Thompson /**
544*ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs per quadrature required to apply `CeedQFunction`
5456e15d496SJeremy L Thompson 
546*ca94c3ddSJeremy L Thompson   @param[in]  qf    `CeedQFunction` to estimate FLOPs for
547ea61e9acSJeremy L Thompson   @param[out] flops Address of variable to hold FLOPs estimate
5486e15d496SJeremy L Thompson 
5496e15d496SJeremy L Thompson   @ref Backend
5506e15d496SJeremy L Thompson **/
5519d36ca50SJeremy L Thompson int CeedQFunctionGetFlopsEstimate(CeedQFunction qf, CeedSize *flops) {
5526574a04fSJeremy L Thompson   CeedCheck(qf->user_flop_estimate > -1, qf->ceed, CEED_ERROR_INCOMPLETE, "Must set FLOPs estimate with CeedQFunctionSetUserFlopsEstimate");
5536e15d496SJeremy L Thompson   *flops = qf->user_flop_estimate;
5546e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5556e15d496SJeremy L Thompson }
5566e15d496SJeremy L Thompson 
5577a982d89SJeremy L. Thompson /// @}
5587a982d89SJeremy L. Thompson 
5597a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5607a982d89SJeremy L. Thompson /// CeedQFunction Public API
5617a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5627a982d89SJeremy L. Thompson /// @addtogroup CeedQFunctionUser
5637a982d89SJeremy L. Thompson /// @{
5647a982d89SJeremy L. Thompson 
5657a982d89SJeremy L. Thompson /**
566*ca94c3ddSJeremy L Thompson   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms
5677a982d89SJeremy L. Thompson 
568*ca94c3ddSJeremy L Thompson   @param[in]  ceed       `Ceed` object used to create the `CeedQFunction`
569*ca94c3ddSJeremy L Thompson   @param[in]  vec_length Vector length.
570*ca94c3ddSJeremy L Thompson                            Caller must ensure that number of quadrature points is a multiple of `vec_length`.
571ea61e9acSJeremy L Thompson   @param[in]  f          Function pointer to evaluate action at quadrature points.
572*ca94c3ddSJeremy L Thompson                            See `CeedQFunctionUser`.
573*ca94c3ddSJeremy L Thompson   @param[in]  source     Absolute path to source of `CeedQFunctionUser`, "\abs_path\file.h:function_name".
574*ca94c3ddSJeremy L Thompson                            The entire source file must only contain constructs supported by all targeted backends (i.e. CUDA for `/gpu/cuda`, OpenCL/SYCL for `/gpu/sycl`, etc.).
5754ada38baSJames Wright                            The entire contents of this file and all locally included files are used during JiT compilation for GPU backends.
5764ada38baSJames Wright                            All source files must be at the provided filepath at runtime for JiT to function.
577*ca94c3ddSJeremy L Thompson   @param[out] qf         Address of the variable where the newly created `CeedQFunction` will be stored
5787a982d89SJeremy L. Thompson 
5797a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5807a982d89SJeremy L. Thompson 
581*ca94c3ddSJeremy L Thompson   See \ref CeedQFunctionUser for details on the call-back function `f` arguments.
5827a982d89SJeremy L. Thompson 
5837a982d89SJeremy L. Thompson   @ref User
5847a982d89SJeremy L. Thompson **/
5852b730f8bSJeremy L Thompson int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vec_length, CeedQFunctionUser f, const char *source, CeedQFunction *qf) {
586ca5eadf8SJeremy L Thompson   char *user_source_copy;
5877a982d89SJeremy L. Thompson 
5887a982d89SJeremy L. Thompson   if (!ceed->QFunctionCreate) {
5897a982d89SJeremy L. Thompson     Ceed delegate;
5906574a04fSJeremy L Thompson 
5912b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "QFunction"));
592*ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedQFunctionCreateInterior");
5932b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionCreateInterior(delegate, vec_length, f, source, qf));
594e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5957a982d89SJeremy L. Thompson   }
5967a982d89SJeremy L. Thompson 
5976574a04fSJeremy L Thompson   CeedCheck(!strlen(source) || strrchr(source, ':'), ceed, CEED_ERROR_INCOMPLETE,
5986574a04fSJeremy L Thompson             "Provided path to source does not include function name. Provided: \"%s\"\nRequired: \"\\abs_path\\file.h:function_name\"", source);
59943e1b16fSJeremy L Thompson 
6002b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, qf));
601db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*qf)->ceed));
602d1d35e2fSjeremylt   (*qf)->ref_count           = 1;
603d1d35e2fSjeremylt   (*qf)->vec_length          = vec_length;
604f04ea552SJeremy L Thompson   (*qf)->is_identity         = false;
605441428dfSJeremy L Thompson   (*qf)->is_context_writable = true;
6067a982d89SJeremy L. Thompson   (*qf)->function            = f;
6076e15d496SJeremy L Thompson   (*qf)->user_flop_estimate  = -1;
60843e1b16fSJeremy L Thompson   if (strlen(source)) {
609ca5eadf8SJeremy L Thompson     size_t user_source_len = strlen(source);
610ee5a26f2SJeremy L Thompson 
6112b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(user_source_len + 1, &user_source_copy));
612ca5eadf8SJeremy L Thompson     memcpy(user_source_copy, source, user_source_len);
613ca5eadf8SJeremy L Thompson     (*qf)->user_source = user_source_copy;
61443e1b16fSJeremy L Thompson   }
6152b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->input_fields));
6162b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->output_fields));
6172b730f8bSJeremy L Thompson   CeedCall(ceed->QFunctionCreate(*qf));
618e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6197a982d89SJeremy L. Thompson }
6207a982d89SJeremy L. Thompson 
6217a982d89SJeremy L. Thompson /**
622*ca94c3ddSJeremy L Thompson   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms by name
623288c0443SJeremy L Thompson 
624*ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedQFunction`
625*ca94c3ddSJeremy L Thompson   @param[in]  name Name of `CeedQFunction` to use from gallery
626*ca94c3ddSJeremy L Thompson   @param[out] qf   Address of the variable where the newly created `CeedQFunction` will be stored
627288c0443SJeremy L Thompson 
628288c0443SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
629288c0443SJeremy L Thompson 
6307a982d89SJeremy L. Thompson   @ref User
631288c0443SJeremy L Thompson **/
6322b730f8bSJeremy L Thompson int CeedQFunctionCreateInteriorByName(Ceed ceed, const char *name, CeedQFunction *qf) {
633f7e22acaSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX;
634288c0443SJeremy L Thompson 
6352b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionRegisterAll());
636288c0443SJeremy L Thompson   // Find matching backend
637*ca94c3ddSJeremy L Thompson   CeedCheck(name, ceed, CEED_ERROR_INCOMPLETE, "No CeedQFunction name provided");
638288c0443SJeremy L Thompson   for (size_t i = 0; i < num_qfunctions; i++) {
639288c0443SJeremy L Thompson     size_t      n;
640d1d35e2fSjeremylt     const char *curr_name = gallery_qfunctions[i].name;
6412b730f8bSJeremy L Thompson     for (n = 0; curr_name[n] && curr_name[n] == name[n]; n++) {
6422b730f8bSJeremy L Thompson     }
643d1d35e2fSjeremylt     if (n > match_len) {
644d1d35e2fSjeremylt       match_len   = n;
645f7e22acaSJeremy L Thompson       match_index = i;
646288c0443SJeremy L Thompson     }
647288c0443SJeremy L Thompson   }
648*ca94c3ddSJeremy L Thompson   CeedCheck(match_len > 0, ceed, CEED_ERROR_UNSUPPORTED, "No suitable gallery CeedQFunction");
649288c0443SJeremy L Thompson 
650288c0443SJeremy L Thompson   // Create QFunction
6512b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionCreateInterior(ceed, gallery_qfunctions[match_index].vec_length, gallery_qfunctions[match_index].f,
6522b730f8bSJeremy L Thompson                                        gallery_qfunctions[match_index].source, qf));
653288c0443SJeremy L Thompson 
654288c0443SJeremy L Thompson   // QFunction specific setup
6552b730f8bSJeremy L Thompson   CeedCall(gallery_qfunctions[match_index].init(ceed, name, *qf));
656288c0443SJeremy L Thompson 
65775affc3bSjeremylt   // Copy name
6582b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(name, (char **)&(*qf)->gallery_name));
65943e1b16fSJeremy L Thompson   (*qf)->is_gallery = true;
660e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
661288c0443SJeremy L Thompson }
662288c0443SJeremy L Thompson 
663288c0443SJeremy L Thompson /**
664*ca94c3ddSJeremy L Thompson   @brief Create an identity `CeedQFunction`.
6654385fb7fSSebastian Grimberg 
666ea61e9acSJeremy L Thompson   Inputs are written into outputs in the order given.
667*ca94c3ddSJeremy L Thompson   This is useful for `CeedOperator that can be represented with only the action of a `CeedElemRestriction` and `CeedBasis`, such as restriction and prolongation operators for p-multigrid.
668*ca94c3ddSJeremy L Thompson   Backends may optimize `CeedOperator` with this `CeedQFunction` to avoid the copy of input data to output fields by using the same memory location for both.
6690219ea01SJeremy L Thompson 
670*ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` object used to create the `CeedQFunction`
671*ca94c3ddSJeremy L Thompson   @param[in]  size     Size of the `CeedQFunction` fields
672*ca94c3ddSJeremy L Thompson   @param[in]  in_mode  @ref CeedEvalMode for input to `CeedQFunction`
673*ca94c3ddSJeremy L Thompson   @param[in]  out_mode @ref CeedEvalMode for output to `CeedQFunction`
674*ca94c3ddSJeremy L Thompson   @param[out] qf       Address of the variable where the newly created `CeedQFunction` will be stored
6750219ea01SJeremy L Thompson 
6760219ea01SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6770219ea01SJeremy L Thompson 
6787a982d89SJeremy L. Thompson   @ref User
6790219ea01SJeremy L Thompson **/
6802b730f8bSJeremy L Thompson int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode in_mode, CeedEvalMode out_mode, CeedQFunction *qf) {
6811c66c397SJeremy L Thompson   CeedQFunctionContext  ctx;
6821c66c397SJeremy L Thompson   CeedContextFieldLabel size_label;
6831c66c397SJeremy L Thompson 
6842b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Identity", qf));
6852b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAddInput(*qf, "input", size, in_mode));
6862b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAddOutput(*qf, "output", size, out_mode));
6870219ea01SJeremy L Thompson 
688f04ea552SJeremy L Thompson   (*qf)->is_identity = true;
689547dbd6fSJeremy L Thompson 
6902b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(*qf, &ctx));
6912b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextGetFieldLabel(ctx, "size", &size_label));
6922b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextSetInt32(ctx, size_label, &size));
693e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6940219ea01SJeremy L Thompson }
6950219ea01SJeremy L Thompson 
6960219ea01SJeremy L Thompson /**
697*ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedQFunction`.
6984385fb7fSSebastian Grimberg 
699*ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedQFunctionDestroy().
700512bb800SJeremy L Thompson 
701*ca94c3ddSJeremy L Thompson   Note: If the value of `*qf_copy` passed to this function is non-NULL, then it is assumed that `*qf_copy` is a pointer to a `CeedQFunction`.
702*ca94c3ddSJeremy L Thompson         This `CeedQFunction` will be destroyed if `*qf_copy` is the only reference to this `CeedQFunction`.
7039560d06aSjeremylt 
704*ca94c3ddSJeremy L Thompson   @param[in]  qf      `CeedQFunction` to copy reference to
7059560d06aSjeremylt   @param[out] qf_copy Variable to store copied reference
7069560d06aSjeremylt 
7079560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
7089560d06aSjeremylt 
7099560d06aSjeremylt   @ref User
7109560d06aSjeremylt **/
7119560d06aSjeremylt int CeedQFunctionReferenceCopy(CeedQFunction qf, CeedQFunction *qf_copy) {
7122b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionReference(qf));
7132b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(qf_copy));
7149560d06aSjeremylt   *qf_copy = qf;
7159560d06aSjeremylt   return CEED_ERROR_SUCCESS;
7169560d06aSjeremylt }
7179560d06aSjeremylt 
7189560d06aSjeremylt /**
719*ca94c3ddSJeremy L Thompson   @brief Add a `CeedQFunction` input
720b11c1e72Sjeremylt 
721*ca94c3ddSJeremy L Thompson   @param[in,out] qf         `CeedQFunction`
722*ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of `CeedQFunction` field
723*ca94c3ddSJeremy L Thompson   @param[in]     size       Size of `CeedQFunction` field, (`num_comp * 1`) for @ref CEED_EVAL_NONE, (`num_comp * 1`) for @ref CEED_EVAL_INTERP for an \f$H^1\f$ space or (`num_comp * dim`) for an \f$H(\mathrm{div})\f$ or \f$H(\mathrm{curl})\f$ space, (`num_comp * dim`) for @ref CEED_EVAL_GRAD, or (`num_comp * 1`) for @ref CEED_EVAL_DIV, and (`num_comp * curl_dim`) with `curl_dim = 1` if `dim < 3` otherwise `curl_dim = dim` for @ref CEED_EVAL_CURL.
724*ca94c3ddSJeremy L Thompson   @param[in]     eval_mode  @ref CEED_EVAL_NONE to use values directly,
725*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_INTERP to use interpolated values,
726*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_GRAD to use gradients,
727*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_DIV to use divergence,
728*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_CURL to use curl
729b11c1e72Sjeremylt 
730b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
731dfdf5a53Sjeremylt 
7327a982d89SJeremy L. Thompson   @ref User
733b11c1e72Sjeremylt **/
7342b730f8bSJeremy L Thompson int CeedQFunctionAddInput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
7356574a04fSJeremy L Thompson   CeedCheck(!qf->is_immutable, qf->ceed, CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable");
7366574a04fSJeremy L Thompson   CeedCheck(eval_mode != CEED_EVAL_WEIGHT || size == 1, qf->ceed, CEED_ERROR_DIMENSION, "CEED_EVAL_WEIGHT should have size 1");
737643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
7386574a04fSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique");
739643fbb69SJeremy L Thompson   }
740643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
7416574a04fSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique");
742643fbb69SJeremy L Thompson   }
7432b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionFieldSet(&qf->input_fields[qf->num_input_fields], field_name, size, eval_mode));
744d1d35e2fSjeremylt   qf->num_input_fields++;
745e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
746d7b241e6Sjeremylt }
747d7b241e6Sjeremylt 
748b11c1e72Sjeremylt /**
749*ca94c3ddSJeremy L Thompson   @brief Add a `CeedQFunction` output
750b11c1e72Sjeremylt 
751*ca94c3ddSJeremy L Thompson   @param[in,out] qf         `CeedQFunction`
752*ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of `CeedQFunction` field
753*ca94c3ddSJeremy L Thompson   @param[in]     size       Size of `CeedQFunction` field, (`num_comp * 1`) for @ref CEED_EVAL_NONE, (`num_comp * 1`) for @ref CEED_EVAL_INTERP for an \f$H^1\f$ space or (`num_comp * dim`) for an \f$H(\mathrm{div})\f$ or \f$H(\mathrm{curl})\f$ space, (`num_comp * dim`) for @ref CEED_EVAL_GRAD, or (`num_comp * 1`) for @ref CEED_EVAL_DIV, and (`num_comp * curl_dim`) with `curl_dim = 1` if `dim < 3` else dim for @ref CEED_EVAL_CURL.
754*ca94c3ddSJeremy L Thompson   @param[in]     eval_mode  @ref CEED_EVAL_NONE to use values directly,
755*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_INTERP to use interpolated values,
756*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_GRAD to use gradients,
757*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_DIV to use divergence,
758*ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_CURL to use curl.
759b11c1e72Sjeremylt 
760b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
761dfdf5a53Sjeremylt 
7627a982d89SJeremy L. Thompson   @ref User
763b11c1e72Sjeremylt **/
7642b730f8bSJeremy L Thompson int CeedQFunctionAddOutput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
765*ca94c3ddSJeremy L Thompson   CeedCheck(!qf->is_immutable, qf->ceed, CEED_ERROR_MAJOR, "CeedQFunction cannot be changed after set as immutable");
766*ca94c3ddSJeremy L Thompson   CeedCheck(eval_mode != CEED_EVAL_WEIGHT, qf->ceed, CEED_ERROR_DIMENSION, "Cannot create CeedQFunction output with CEED_EVAL_WEIGHT");
767643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
768*ca94c3ddSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "CeedQFunction field names must be unique");
769643fbb69SJeremy L Thompson   }
770643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
771*ca94c3ddSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "CeedQFunction field names must be unique");
772643fbb69SJeremy L Thompson   }
7732b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionFieldSet(&qf->output_fields[qf->num_output_fields], field_name, size, eval_mode));
774d1d35e2fSjeremylt   qf->num_output_fields++;
775e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
776d7b241e6Sjeremylt }
777d7b241e6Sjeremylt 
778dfdf5a53Sjeremylt /**
779*ca94c3ddSJeremy L Thompson   @brief Get the `CeedQFunctionField` of a `CeedQFunction`
78043bbe138SJeremy L Thompson 
781*ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedQFunction` as immutable.
782f04ea552SJeremy L Thompson 
783*ca94c3ddSJeremy L Thompson   @param[in]  qf                `CeedQFunction`
784f74ec584SJeremy L Thompson   @param[out] num_input_fields  Variable to store number of input fields
785f74ec584SJeremy L Thompson   @param[out] input_fields      Variable to store input fields
786f74ec584SJeremy L Thompson   @param[out] num_output_fields Variable to store number of output fields
787f74ec584SJeremy L Thompson   @param[out] output_fields     Variable to store output fields
78843bbe138SJeremy L Thompson 
78943bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
79043bbe138SJeremy L Thompson 
791e9b533fbSJeremy L Thompson   @ref Advanced
79243bbe138SJeremy L Thompson **/
7932b730f8bSJeremy L Thompson int CeedQFunctionGetFields(CeedQFunction qf, CeedInt *num_input_fields, CeedQFunctionField **input_fields, CeedInt *num_output_fields,
79443bbe138SJeremy L Thompson                            CeedQFunctionField **output_fields) {
795f04ea552SJeremy L Thompson   qf->is_immutable = true;
79643bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = qf->num_input_fields;
79743bbe138SJeremy L Thompson   if (input_fields) *input_fields = qf->input_fields;
79843bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = qf->num_output_fields;
79943bbe138SJeremy L Thompson   if (output_fields) *output_fields = qf->output_fields;
80043bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
80143bbe138SJeremy L Thompson }
80243bbe138SJeremy L Thompson 
80343bbe138SJeremy L Thompson /**
804*ca94c3ddSJeremy L Thompson   @brief Get the name of a `CeedQFunctionField`
80543bbe138SJeremy L Thompson 
806*ca94c3ddSJeremy L Thompson   @param[in]  qf_field   `CeedQFunctionField`
80743bbe138SJeremy L Thompson   @param[out] field_name Variable to store the field name
80843bbe138SJeremy L Thompson 
80943bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
81043bbe138SJeremy L Thompson 
811e9b533fbSJeremy L Thompson   @ref Advanced
81243bbe138SJeremy L Thompson **/
81343bbe138SJeremy L Thompson int CeedQFunctionFieldGetName(CeedQFunctionField qf_field, char **field_name) {
81443bbe138SJeremy L Thompson   *field_name = (char *)qf_field->field_name;
81543bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
81643bbe138SJeremy L Thompson }
81743bbe138SJeremy L Thompson 
81843bbe138SJeremy L Thompson /**
819*ca94c3ddSJeremy L Thompson   @brief Get the number of components of a `CeedQFunctionField`
82043bbe138SJeremy L Thompson 
821*ca94c3ddSJeremy L Thompson   @param[in]  qf_field `CeedQFunctionField`
82243bbe138SJeremy L Thompson   @param[out] size     Variable to store the size of the field
82343bbe138SJeremy L Thompson 
82443bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
82543bbe138SJeremy L Thompson 
826e9b533fbSJeremy L Thompson   @ref Advanced
82743bbe138SJeremy L Thompson **/
82843bbe138SJeremy L Thompson int CeedQFunctionFieldGetSize(CeedQFunctionField qf_field, CeedInt *size) {
82943bbe138SJeremy L Thompson   *size = qf_field->size;
83043bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
83143bbe138SJeremy L Thompson }
83243bbe138SJeremy L Thompson 
83343bbe138SJeremy L Thompson /**
834*ca94c3ddSJeremy L Thompson   @brief Get the @ref CeedEvalMode of a `CeedQFunctionField`
83543bbe138SJeremy L Thompson 
836*ca94c3ddSJeremy L Thompson   @param[in]  qf_field  `CeedQFunctionField`
83743bbe138SJeremy L Thompson   @param[out] eval_mode Variable to store the field evaluation mode
83843bbe138SJeremy L Thompson 
83943bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
84043bbe138SJeremy L Thompson 
841e9b533fbSJeremy L Thompson   @ref Advanced
84243bbe138SJeremy L Thompson **/
8432b730f8bSJeremy L Thompson int CeedQFunctionFieldGetEvalMode(CeedQFunctionField qf_field, CeedEvalMode *eval_mode) {
84443bbe138SJeremy L Thompson   *eval_mode = qf_field->eval_mode;
84543bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
84643bbe138SJeremy L Thompson }
84743bbe138SJeremy L Thompson 
84843bbe138SJeremy L Thompson /**
849*ca94c3ddSJeremy L Thompson   @brief Set global context for a `CeedQFunction`
850b11c1e72Sjeremylt 
851*ca94c3ddSJeremy L Thompson   @param[in,out] qf  `CeedQFunction`
852ea61e9acSJeremy L Thompson   @param[in]     ctx Context data to set
853b11c1e72Sjeremylt 
854b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
855dfdf5a53Sjeremylt 
8567a982d89SJeremy L. Thompson   @ref User
857b11c1e72Sjeremylt **/
858777ff853SJeremy L Thompson int CeedQFunctionSetContext(CeedQFunction qf, CeedQFunctionContext ctx) {
8592b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextDestroy(&qf->ctx));
860d7b241e6Sjeremylt   qf->ctx = ctx;
861db002c03SJeremy L Thompson   if (ctx) CeedCall(CeedQFunctionContextReference(ctx));
862e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
863d7b241e6Sjeremylt }
864d7b241e6Sjeremylt 
865b11c1e72Sjeremylt /**
866*ca94c3ddSJeremy L Thompson   @brief Set writability of `CeedQFunctionContext` when calling the `CeedQFunctionUser`.
8674385fb7fSSebastian Grimberg 
868859c15bbSJames Wright   The default value is `is_writable == true`.
869441428dfSJeremy L Thompson 
870*ca94c3ddSJeremy L Thompson   Setting `is_writable == true` indicates the `CeedQFunctionUser` writes into the `CeedQFunctionContext` and requires memory synchronization after calling @ref CeedQFunctionApply().
871441428dfSJeremy L Thompson 
872*ca94c3ddSJeremy L Thompson   Setting 'is_writable == false' asserts that `CeedQFunctionUser` does not modify the `CeedQFunctionContext`.
873ea61e9acSJeremy L Thompson   Violating this assertion may lead to inconsistent data.
874441428dfSJeremy L Thompson 
875441428dfSJeremy L Thompson   Setting `is_writable == false` may offer a performance improvement on GPU backends.
876441428dfSJeremy L Thompson 
877*ca94c3ddSJeremy L Thompson   @param[in,out] qf          `CeedQFunction`
878*ca94c3ddSJeremy L Thompson   @param[in]     is_writable Boolean flag for writability status
879441428dfSJeremy L Thompson 
880441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
881441428dfSJeremy L Thompson 
882441428dfSJeremy L Thompson   @ref User
883441428dfSJeremy L Thompson **/
884441428dfSJeremy L Thompson int CeedQFunctionSetContextWritable(CeedQFunction qf, bool is_writable) {
885441428dfSJeremy L Thompson   qf->is_context_writable = is_writable;
886441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
887441428dfSJeremy L Thompson }
888441428dfSJeremy L Thompson 
889441428dfSJeremy L Thompson /**
890*ca94c3ddSJeremy L Thompson   @brief Set estimated number of FLOPs per quadrature required to apply `CeedQFunction`
8916e15d496SJeremy L Thompson 
892*ca94c3ddSJeremy L Thompson   @param[in]  qf    `CeedQFunction` to estimate FLOPs for
893ea61e9acSJeremy L Thompson   @param[out] flops FLOPs per quadrature point estimate
8946e15d496SJeremy L Thompson 
8956e15d496SJeremy L Thompson   @ref Backend
8966e15d496SJeremy L Thompson **/
8979d36ca50SJeremy L Thompson int CeedQFunctionSetUserFlopsEstimate(CeedQFunction qf, CeedSize flops) {
8986574a04fSJeremy L Thompson   CeedCheck(flops >= 0, qf->ceed, CEED_ERROR_INCOMPATIBLE, "Must set non-negative FLOPs estimate");
8996e15d496SJeremy L Thompson   qf->user_flop_estimate = flops;
9006e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9016e15d496SJeremy L Thompson }
9026e15d496SJeremy L Thompson 
9036e15d496SJeremy L Thompson /**
904*ca94c3ddSJeremy L Thompson   @brief View a `CeedQFunction`
90575affc3bSjeremylt 
906*ca94c3ddSJeremy L Thompson   @param[in] qf     `CeedQFunction` to view
907*ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
90875affc3bSjeremylt 
90975affc3bSjeremylt   @return Error code: 0 - success, otherwise - failure
91075affc3bSjeremylt 
9117a982d89SJeremy L. Thompson   @ref User
91275affc3bSjeremylt **/
91375affc3bSjeremylt int CeedQFunctionView(CeedQFunction qf, FILE *stream) {
914ca5eadf8SJeremy L Thompson   char *kernel_name;
91575affc3bSjeremylt 
9162b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetKernelName(qf, &kernel_name));
9172b730f8bSJeremy L Thompson   fprintf(stream, "%sCeedQFunction - %s\n", qf->is_gallery ? "Gallery " : "User ", qf->is_gallery ? qf->gallery_name : kernel_name);
91875affc3bSjeremylt 
9192b730f8bSJeremy L Thompson   fprintf(stream, "  %" CeedInt_FMT " input field%s:\n", qf->num_input_fields, qf->num_input_fields > 1 ? "s" : "");
920d1d35e2fSjeremylt   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
9212b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionFieldView(qf->input_fields[i], i, 1, stream));
92275affc3bSjeremylt   }
92375affc3bSjeremylt 
9242b730f8bSJeremy L Thompson   fprintf(stream, "  %" CeedInt_FMT " output field%s:\n", qf->num_output_fields, qf->num_output_fields > 1 ? "s" : "");
925d1d35e2fSjeremylt   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
9262b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionFieldView(qf->output_fields[i], i, 0, stream));
92775affc3bSjeremylt   }
928e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
92975affc3bSjeremylt }
93075affc3bSjeremylt 
93175affc3bSjeremylt /**
932*ca94c3ddSJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedQFunction`
933b7c9bbdaSJeremy L Thompson 
934*ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction`
935*ca94c3ddSJeremy L Thompson   @param[out] ceed Variable to store`Ceed`
936b7c9bbdaSJeremy L Thompson 
937b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
938b7c9bbdaSJeremy L Thompson 
939b7c9bbdaSJeremy L Thompson   @ref Advanced
940b7c9bbdaSJeremy L Thompson **/
941b7c9bbdaSJeremy L Thompson int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) {
942b7c9bbdaSJeremy L Thompson   *ceed = qf->ceed;
943b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
944b7c9bbdaSJeremy L Thompson }
945b7c9bbdaSJeremy L Thompson 
946b7c9bbdaSJeremy L Thompson /**
947*ca94c3ddSJeremy L Thompson   @brief Apply the action of a `CeedQFunction`
948b11c1e72Sjeremylt 
949*ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedQFunction` as immutable.
950f04ea552SJeremy L Thompson 
951*ca94c3ddSJeremy L Thompson   @param[in]  qf `CeedQFunction`
952ea61e9acSJeremy L Thompson   @param[in]  Q  Number of quadrature points
953*ca94c3ddSJeremy L Thompson   @param[in]  u  Array of input `CeedVector`
954*ca94c3ddSJeremy L Thompson   @param[out] v  Array of output `CeedVector`
955b11c1e72Sjeremylt 
956b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
957dfdf5a53Sjeremylt 
9587a982d89SJeremy L. Thompson   @ref User
959b11c1e72Sjeremylt **/
9602b730f8bSJeremy L Thompson int CeedQFunctionApply(CeedQFunction qf, CeedInt Q, CeedVector *u, CeedVector *v) {
961*ca94c3ddSJeremy L Thompson   CeedCheck(qf->Apply, qf->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedQFunctionApply");
9626574a04fSJeremy L Thompson   CeedCheck(Q % qf->vec_length == 0, qf->ceed, CEED_ERROR_DIMENSION,
9636574a04fSJeremy L Thompson             "Number of quadrature points %" CeedInt_FMT " must be a multiple of %" CeedInt_FMT, Q, qf->vec_length);
964f04ea552SJeremy L Thompson   qf->is_immutable = true;
9652b730f8bSJeremy L Thompson   CeedCall(qf->Apply(qf, Q, u, v));
966e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
967d7b241e6Sjeremylt }
968d7b241e6Sjeremylt 
969b11c1e72Sjeremylt /**
970*ca94c3ddSJeremy L Thompson   @brief Destroy a `CeedQFunction`
971b11c1e72Sjeremylt 
972*ca94c3ddSJeremy L Thompson   @param[in,out] qf `CeedQFunction` to destroy
973b11c1e72Sjeremylt 
974b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
975dfdf5a53Sjeremylt 
9767a982d89SJeremy L. Thompson   @ref User
977b11c1e72Sjeremylt **/
978d7b241e6Sjeremylt int CeedQFunctionDestroy(CeedQFunction *qf) {
979ad6481ceSJeremy L Thompson   if (!*qf || --(*qf)->ref_count > 0) {
980ad6481ceSJeremy L Thompson     *qf = NULL;
981ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
982ad6481ceSJeremy L Thompson   }
983fe2413ffSjeremylt   // Backend destroy
984d7b241e6Sjeremylt   if ((*qf)->Destroy) {
9852b730f8bSJeremy L Thompson     CeedCall((*qf)->Destroy(*qf));
986d7b241e6Sjeremylt   }
987fe2413ffSjeremylt   // Free fields
98892ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*qf)->num_input_fields; i++) {
9892b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*(*qf)->input_fields[i]).field_name));
9902b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*qf)->input_fields[i]));
991fe2413ffSjeremylt   }
99292ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*qf)->num_output_fields; i++) {
9932b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*(*qf)->output_fields[i]).field_name));
9942b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*qf)->output_fields[i]));
995fe2413ffSjeremylt   }
9962b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->input_fields));
9972b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->output_fields));
998777ff853SJeremy L Thompson 
999777ff853SJeremy L Thompson   // User context data object
10002b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextDestroy(&(*qf)->ctx));
1001fe2413ffSjeremylt 
10022b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->user_source));
10032b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->source_path));
10042b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->gallery_name));
10052b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->kernel_name));
10062b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*qf)->ceed));
10072b730f8bSJeremy L Thompson   CeedCall(CeedFree(qf));
1008e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1009d7b241e6Sjeremylt }
1010d7b241e6Sjeremylt 
1011d7b241e6Sjeremylt /// @}
1012