xref: /libCEED/interface/ceed-qfunction.c (revision 3f08121c3514eef2c33780965530b5ca922abfd3)
15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, 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 
27ca94c3ddSJeremy 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 /**
50ca94c3ddSJeremy L Thompson   @brief Register a gallery `CeedQFunction`
51288c0443SJeremy L Thompson 
52ea61e9acSJeremy L Thompson   @param[in] name       Name for this backend to respond to
53ca94c3ddSJeremy L Thompson   @param[in] source     Absolute path to source of `CeedQFunction`, "\path\CEED_DIR\gallery\folder\file.h:function_name"
54ca94c3ddSJeremy L Thompson   @param[in] vec_length Vector length.
55ca94c3ddSJeremy 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.
57ca94c3ddSJeremy L Thompson                           See `CeedQFunctionUser`.
58ca94c3ddSJeremy 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   }
85ca94c3ddSJeremy L Thompson   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "Too many gallery CeedQFunctions");
86e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
87288c0443SJeremy L Thompson }
88288c0443SJeremy L Thompson 
89288c0443SJeremy L Thompson /**
90ca94c3ddSJeremy L Thompson   @brief Set a `CeedQFunction` field, used by @ref CeedQFunctionAddInput() and @ref CeedQFunctionAddOutput()
917a982d89SJeremy L. Thompson 
92ca94c3ddSJeremy L Thompson   @param[out] f           `CeedQFunctionField`
93ca94c3ddSJeremy L Thompson   @param[in]  field_name  Name of `CeedQFunction` field
94ca94c3ddSJeremy 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.
95ca94c3ddSJeremy L Thompson   @param[in]  eval_mode   @ref CEED_EVAL_NONE to use values directly,
96ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_WEIGHT to use quadrature weights,
97ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_INTERP to use interpolated values,
98ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_GRAD to use gradients,
99ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_DIV to use divergence,
100ca94c3ddSJeremy L Thompson                             @ref CEED_EVAL_CURL to use curl
1017a982d89SJeremy L. Thompson 
1027a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1037a982d89SJeremy L. Thompson 
1047a982d89SJeremy L. Thompson   @ref Developer
1057a982d89SJeremy L. Thompson **/
1062b730f8bSJeremy L Thompson static int CeedQFunctionFieldSet(CeedQFunctionField *f, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
1072b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, f));
1082b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(field_name, (char **)&(*f)->field_name));
1097a982d89SJeremy L. Thompson   (*f)->size      = size;
110d1d35e2fSjeremylt   (*f)->eval_mode = eval_mode;
111e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1127a982d89SJeremy L. Thompson }
1137a982d89SJeremy L. Thompson 
1147a982d89SJeremy L. Thompson /**
115ca94c3ddSJeremy L Thompson   @brief View a field of a `CeedQFunction`
1167a982d89SJeremy L. Thompson 
117ca94c3ddSJeremy L Thompson   @param[in] field        `CeedQFunction` field to view
118d1d35e2fSjeremylt   @param[in] field_number Number of field being viewed
1194c4400c7SValeria Barra   @param[in] in           true for input field, false for output
120ca94c3ddSJeremy L Thompson   @param[in] stream       Stream to view to, e.g., `stdout`
1217a982d89SJeremy L. Thompson 
1227a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1237a982d89SJeremy L. Thompson 
1247a982d89SJeremy L. Thompson   @ref Utility
1257a982d89SJeremy L. Thompson **/
1262b730f8bSJeremy L Thompson static int CeedQFunctionFieldView(CeedQFunctionField field, CeedInt field_number, bool in, FILE *stream) {
1277a982d89SJeremy L. Thompson   const char  *inout = in ? "Input" : "Output";
1286f8994e9SJeremy L Thompson   const char  *field_name;
1298229195eSjeremylt   CeedInt      size;
1308229195eSjeremylt   CeedEvalMode eval_mode;
1311c66c397SJeremy L Thompson 
132ab747706SJeremy L Thompson   CeedCall(CeedQFunctionFieldGetData(field, &field_name, &size, &eval_mode));
1332b730f8bSJeremy L Thompson   fprintf(stream,
1342b730f8bSJeremy L Thompson           "    %s field %" CeedInt_FMT
1352b730f8bSJeremy L Thompson           ":\n"
1367a982d89SJeremy L. Thompson           "      Name: \"%s\"\n"
1372b730f8bSJeremy L Thompson           "      Size: %" CeedInt_FMT
1382b730f8bSJeremy L Thompson           "\n"
1397a982d89SJeremy L. Thompson           "      EvalMode: \"%s\"\n",
1408229195eSjeremylt           inout, field_number, field_name, size, CeedEvalModes[eval_mode]);
141e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1427a982d89SJeremy L. Thompson }
1437a982d89SJeremy L. Thompson 
144777ff853SJeremy L Thompson /**
145777ff853SJeremy L Thompson   @brief Set flag to determine if Fortran interface is used
146777ff853SJeremy L Thompson 
147ea61e9acSJeremy L Thompson   @param[in,out] qf     CeedQFunction
148ea61e9acSJeremy L Thompson   @param[in]     status Boolean value to set as Fortran status
149777ff853SJeremy L Thompson 
150777ff853SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
151777ff853SJeremy L Thompson 
152777ff853SJeremy L Thompson   @ref Backend
153777ff853SJeremy L Thompson **/
154777ff853SJeremy L Thompson int CeedQFunctionSetFortranStatus(CeedQFunction qf, bool status) {
155f04ea552SJeremy L Thompson   qf->is_fortran = status;
156e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
157777ff853SJeremy L Thompson }
158777ff853SJeremy L Thompson 
1597a982d89SJeremy L. Thompson /// @}
1607a982d89SJeremy L. Thompson 
1617a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1627a982d89SJeremy L. Thompson /// CeedQFunction Backend API
1637a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1647a982d89SJeremy L. Thompson /// @addtogroup CeedQFunctionBackend
1657a982d89SJeremy L. Thompson /// @{
1667a982d89SJeremy L. Thompson 
1677a982d89SJeremy L. Thompson /**
168ca94c3ddSJeremy L Thompson   @brief Get the vector length of a `CeedQFunction`
1697a982d89SJeremy L. Thompson 
170ca94c3ddSJeremy L Thompson   @param[in]  qf         `CeedQFunction`
171d1d35e2fSjeremylt   @param[out] vec_length Variable to store vector length
1727a982d89SJeremy L. Thompson 
1737a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1747a982d89SJeremy L. Thompson 
1757a982d89SJeremy L. Thompson   @ref Backend
1767a982d89SJeremy L. Thompson **/
177d1d35e2fSjeremylt int CeedQFunctionGetVectorLength(CeedQFunction qf, CeedInt *vec_length) {
178d1d35e2fSjeremylt   *vec_length = qf->vec_length;
179e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1807a982d89SJeremy L. Thompson }
1817a982d89SJeremy L. Thompson 
1827a982d89SJeremy L. Thompson /**
183ca94c3ddSJeremy L Thompson   @brief Get the number of inputs and outputs to a `CeedQFunction`
1847a982d89SJeremy L. Thompson 
185ca94c3ddSJeremy L Thompson   @param[in]  qf         `CeedQFunction`
186d1d35e2fSjeremylt   @param[out] num_input  Variable to store number of input fields
187d1d35e2fSjeremylt   @param[out] num_output Variable to store number of output fields
1887a982d89SJeremy L. Thompson 
1897a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1907a982d89SJeremy L. Thompson 
1917a982d89SJeremy L. Thompson   @ref Backend
1927a982d89SJeremy L. Thompson **/
1932b730f8bSJeremy L Thompson int CeedQFunctionGetNumArgs(CeedQFunction qf, CeedInt *num_input, CeedInt *num_output) {
194d1d35e2fSjeremylt   if (num_input) *num_input = qf->num_input_fields;
195d1d35e2fSjeremylt   if (num_output) *num_output = qf->num_output_fields;
196e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1977a982d89SJeremy L. Thompson }
1987a982d89SJeremy L. Thompson 
1997a982d89SJeremy L. Thompson /**
200ca94c3ddSJeremy L Thompson   @brief Get the name of the user function for a `CeedQFunction`
2017a982d89SJeremy L. Thompson 
202ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
20343e1b16fSJeremy L Thompson   @param[out] kernel_name Variable to store source path string
2047a982d89SJeremy L. Thompson 
2057a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2067a982d89SJeremy L. Thompson 
2077a982d89SJeremy L. Thompson   @ref Backend
2087a982d89SJeremy L. Thompson **/
2097d023984SJeremy L Thompson int CeedQFunctionGetKernelName(CeedQFunction qf, const char **kernel_name) {
210ca5eadf8SJeremy L Thompson   if (!qf->kernel_name) {
211ca5eadf8SJeremy L Thompson     char *kernel_name_copy;
212ca5eadf8SJeremy L Thompson 
213ca5eadf8SJeremy L Thompson     if (qf->user_source) {
214ca5eadf8SJeremy L Thompson       const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
215ca5eadf8SJeremy L Thompson       size_t      kernel_name_len = strlen(kernel_name);
216ca5eadf8SJeremy L Thompson 
2172b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(kernel_name_len + 1, &kernel_name_copy));
218ca5eadf8SJeremy L Thompson       memcpy(kernel_name_copy, kernel_name, kernel_name_len);
219ca5eadf8SJeremy L Thompson     } else {
2202b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(1, &kernel_name_copy));
221ca5eadf8SJeremy L Thompson     }
222ca5eadf8SJeremy L Thompson     qf->kernel_name = kernel_name_copy;
223ca5eadf8SJeremy L Thompson   }
224ca5eadf8SJeremy L Thompson 
2257d023984SJeremy L Thompson   *kernel_name = qf->kernel_name;
22643e1b16fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
22743e1b16fSJeremy L Thompson }
22843e1b16fSJeremy L Thompson 
22943e1b16fSJeremy L Thompson /**
230ca94c3ddSJeremy L Thompson   @brief Get the source path string for a `CeedQFunction`
23143e1b16fSJeremy L Thompson 
232ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
23343e1b16fSJeremy L Thompson   @param[out] source_path Variable to store source path string
23443e1b16fSJeremy L Thompson 
23543e1b16fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
23643e1b16fSJeremy L Thompson 
23743e1b16fSJeremy L Thompson   @ref Backend
23843e1b16fSJeremy L Thompson **/
23934ffed21SJeremy L Thompson int CeedQFunctionGetSourcePath(CeedQFunction qf, const char **source_path) {
240ca5eadf8SJeremy L Thompson   if (!qf->source_path && qf->user_source) {
241ca5eadf8SJeremy L Thompson     Ceed        ceed;
242ca5eadf8SJeremy L Thompson     bool        is_absolute_path;
24322070f95SJeremy L Thompson     char       *source_path_copy;
24422070f95SJeremy L Thompson     const char *absolute_path;
245ca5eadf8SJeremy L Thompson     const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
246ca5eadf8SJeremy L Thompson     size_t      kernel_name_len = strlen(kernel_name);
247ca5eadf8SJeremy L Thompson 
2482b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
2492b730f8bSJeremy L Thompson     CeedCall(CeedCheckFilePath(ceed, qf->user_source, &is_absolute_path));
250ca5eadf8SJeremy L Thompson     if (is_absolute_path) {
251ca5eadf8SJeremy L Thompson       absolute_path = (char *)qf->user_source;
252ca5eadf8SJeremy L Thompson     } else {
2532b730f8bSJeremy L Thompson       CeedCall(CeedGetJitAbsolutePath(ceed, qf->user_source, &absolute_path));
254ca5eadf8SJeremy L Thompson     }
255ca5eadf8SJeremy L Thompson 
256ca5eadf8SJeremy L Thompson     size_t source_len = strlen(absolute_path) - kernel_name_len - 1;
2571c66c397SJeremy L Thompson 
2582b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(source_len + 1, &source_path_copy));
259ca5eadf8SJeremy L Thompson     memcpy(source_path_copy, absolute_path, source_len);
260ca5eadf8SJeremy L Thompson     qf->source_path = source_path_copy;
261ca5eadf8SJeremy L Thompson 
2622b730f8bSJeremy L Thompson     if (!is_absolute_path) CeedCall(CeedFree(&absolute_path));
263ca5eadf8SJeremy L Thompson   }
264ca5eadf8SJeremy L Thompson 
26543e1b16fSJeremy L Thompson   *source_path = (char *)qf->source_path;
266e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2677a982d89SJeremy L. Thompson }
2687a982d89SJeremy L. Thompson 
2697a982d89SJeremy L. Thompson /**
270ca94c3ddSJeremy L Thompson   @brief Initialize and load `CeedQFunction` source file into string buffer, including full text of local files in place of `#include "local.h"`.
2714385fb7fSSebastian Grimberg 
272ca94c3ddSJeremy L Thompson   The `buffer` is set to `NULL` if there is no `CeedQFunction` source file.
2734385fb7fSSebastian Grimberg 
274f8d308faSJed Brown   Note: This function may as well return a mutable buffer, but all current uses
275f8d308faSJed Brown   do not modify it. (This is just a downside of `const` semantics with output
276f8d308faSJed Brown   arguments instead of returns.)
277f8d308faSJed Brown 
278ca94c3ddSJeremy L Thompson   Note: Caller is responsible for freeing the string buffer with @ref CeedFree().
2793d3250a0SJeremy L Thompson 
280ca94c3ddSJeremy L Thompson   @param[in]  qf            `CeedQFunction`
281f74ec584SJeremy L Thompson   @param[out] source_buffer String buffer for source file contents
2823d3250a0SJeremy L Thompson 
2833d3250a0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2843d3250a0SJeremy L Thompson 
2853d3250a0SJeremy L Thompson   @ref Backend
2863d3250a0SJeremy L Thompson **/
287f8d308faSJed Brown int CeedQFunctionLoadSourceToBuffer(CeedQFunction qf, const char **source_buffer) {
28834ffed21SJeremy L Thompson   const char *source_path;
2893d3250a0SJeremy L Thompson 
2902b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetSourcePath(qf, &source_path));
2913d3250a0SJeremy L Thompson   *source_buffer = NULL;
2923d3250a0SJeremy L Thompson   if (source_path) {
2931203703bSJeremy L Thompson     Ceed  ceed;
294f8d308faSJed Brown     char *buffer = NULL;
2951203703bSJeremy L Thompson 
2961203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
297f8d308faSJed Brown     CeedCall(CeedLoadSourceToBuffer(ceed, source_path, &buffer));
298f8d308faSJed Brown     *source_buffer = buffer;
2993d3250a0SJeremy L Thompson   }
3003d3250a0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3013d3250a0SJeremy L Thompson }
3023d3250a0SJeremy L Thompson 
3033d3250a0SJeremy L Thompson /**
304ca94c3ddSJeremy L Thompson   @brief Get the User Function for a `CeedQFunction`
3057a982d89SJeremy L. Thompson 
306ca94c3ddSJeremy L Thompson   @param[in]  qf `CeedQFunction`
3077a982d89SJeremy L. Thompson   @param[out] f  Variable to store user function
3087a982d89SJeremy L. Thompson 
3097a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3107a982d89SJeremy L. Thompson 
3117a982d89SJeremy L. Thompson   @ref Backend
3127a982d89SJeremy L. Thompson **/
3137a982d89SJeremy L. Thompson int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) {
3147a982d89SJeremy L. Thompson   *f = qf->function;
315e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3167a982d89SJeremy L. Thompson }
3177a982d89SJeremy L. Thompson 
3187a982d89SJeremy L. Thompson /**
319ca94c3ddSJeremy L Thompson   @brief Get global context for a `CeedQFunction`.
3204385fb7fSSebastian Grimberg 
321ca94c3ddSJeremy L Thompson   Note: For `CeedQFunction` from the Fortran interface, this function will return the Fortran context `CeedQFunctionContext`.
3227a982d89SJeremy L. Thompson 
323ea61e9acSJeremy L Thompson   @param[in]  qf  CeedQFunction
324777ff853SJeremy L Thompson   @param[out] ctx Variable to store CeedQFunctionContext
3257a982d89SJeremy L. Thompson 
3267a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3277a982d89SJeremy L. Thompson 
3287a982d89SJeremy L. Thompson   @ref Backend
3297a982d89SJeremy L. Thompson **/
330777ff853SJeremy L Thompson int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
3317a982d89SJeremy L. Thompson   *ctx = qf->ctx;
332e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3337a982d89SJeremy L. Thompson }
3347a982d89SJeremy L. Thompson 
3357a982d89SJeremy L. Thompson /**
336ca94c3ddSJeremy L Thompson   @brief Get context data of a `CeedQFunction`
337441428dfSJeremy L Thompson 
338ca94c3ddSJeremy L Thompson   @param[in]  qf       `CeedQFunction`
339ea61e9acSJeremy L Thompson   @param[in]  mem_type Memory type on which to access the data.
340ea61e9acSJeremy L Thompson                          If the backend uses a different memory type, this will perform a copy.
341441428dfSJeremy L Thompson   @param[out] data     Data on memory type mem_type
342441428dfSJeremy L Thompson 
343441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
344441428dfSJeremy L Thompson 
345441428dfSJeremy L Thompson   @ref Backend
346441428dfSJeremy L Thompson **/
3472b730f8bSJeremy L Thompson int CeedQFunctionGetContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
348441428dfSJeremy L Thompson   bool                 is_writable;
349441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
350441428dfSJeremy L Thompson 
3512b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &ctx));
352441428dfSJeremy L Thompson   if (ctx) {
3532b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
354441428dfSJeremy L Thompson     if (is_writable) {
3552b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
356441428dfSJeremy L Thompson     } else {
3572b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
358441428dfSJeremy L Thompson     }
359441428dfSJeremy L Thompson   } else {
360441428dfSJeremy L Thompson     *(void **)data = NULL;
361441428dfSJeremy L Thompson   }
362441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
363441428dfSJeremy L Thompson }
364441428dfSJeremy L Thompson 
365441428dfSJeremy L Thompson /**
366ca94c3ddSJeremy L Thompson   @brief Restore context data of a `CeedQFunction`
367441428dfSJeremy L Thompson 
368ca94c3ddSJeremy L Thompson   @param[in]     qf   `CeedQFunction`
369ea61e9acSJeremy L Thompson   @param[in,out] data Data to restore
370441428dfSJeremy L Thompson 
371441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
372441428dfSJeremy L Thompson 
373441428dfSJeremy L Thompson   @ref Backend
374441428dfSJeremy L Thompson **/
375441428dfSJeremy L Thompson int CeedQFunctionRestoreContextData(CeedQFunction qf, void *data) {
376441428dfSJeremy L Thompson   bool                 is_writable;
377441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
378441428dfSJeremy L Thompson 
3792b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &ctx));
380441428dfSJeremy L Thompson   if (ctx) {
3812b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
382441428dfSJeremy L Thompson     if (is_writable) {
3832b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
384441428dfSJeremy L Thompson     } else {
3852b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
386441428dfSJeremy L Thompson     }
387441428dfSJeremy L Thompson   }
3885f249b39SJeremy L Thompson   *(void **)data = NULL;
389441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
390441428dfSJeremy L Thompson }
391441428dfSJeremy L Thompson 
392441428dfSJeremy L Thompson /**
393ca94c3ddSJeremy L Thompson   @brief Get true user context for a `CeedQFunction`
3944385fb7fSSebastian Grimberg 
395ca94c3ddSJeremy L Thompson   Note: For all `CeedQFunction` this function will return the user `CeedQFunctionContext` and not interface context `CeedQFunctionContext`, if any such object exists.
3967a982d89SJeremy L. Thompson 
397ca94c3ddSJeremy L Thompson   @param[in]  qf  `CeedQFunction`
398ca94c3ddSJeremy L Thompson   @param[out] ctx Variable to store `CeedQFunctionContext`
3997a982d89SJeremy L. Thompson 
4007a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4017a982d89SJeremy L. Thompson   @ref Backend
4027a982d89SJeremy L. Thompson **/
403777ff853SJeremy L Thompson int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
4041203703bSJeremy L Thompson   CeedQFunctionContext qf_ctx;
4051203703bSJeremy L Thompson 
4061203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &qf_ctx));
407f04ea552SJeremy L Thompson   if (qf->is_fortran) {
408d1d35e2fSjeremylt     CeedFortranContext fortran_ctx = NULL;
4091c66c397SJeremy L Thompson 
4101203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextGetData(qf_ctx, CEED_MEM_HOST, &fortran_ctx));
4118cb0412aSJeremy L Thompson     *ctx = fortran_ctx->inner_ctx;
4129a25c351SJeremy L Thompson     CeedCall(CeedQFunctionContextRestoreData(qf_ctx, &fortran_ctx));
4137a982d89SJeremy L. Thompson   } else {
4141203703bSJeremy L Thompson     *ctx = qf_ctx;
4157a982d89SJeremy L. Thompson   }
416e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4177a982d89SJeremy L. Thompson }
4187a982d89SJeremy L. Thompson 
4197a982d89SJeremy L. Thompson /**
420ca94c3ddSJeremy L Thompson   @brief Get inner context data of a `CeedQFunction`
421441428dfSJeremy L Thompson 
422ca94c3ddSJeremy L Thompson   @param[in]  qf       `CeedQFunction`
423ea61e9acSJeremy L Thompson   @param[in]  mem_type Memory type on which to access the data.
424ea61e9acSJeremy L Thompson                          If the backend uses a different memory type, this will perform a copy.
425441428dfSJeremy L Thompson   @param[out] data     Data on memory type mem_type
426441428dfSJeremy L Thompson 
427441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
428441428dfSJeremy L Thompson 
429441428dfSJeremy L Thompson   @ref Backend
430441428dfSJeremy L Thompson **/
4312b730f8bSJeremy L Thompson int CeedQFunctionGetInnerContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
432441428dfSJeremy L Thompson   bool                 is_writable;
433441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
434441428dfSJeremy L Thompson 
4352b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
436441428dfSJeremy L Thompson   if (ctx) {
4372b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
438441428dfSJeremy L Thompson     if (is_writable) {
4392b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
440441428dfSJeremy L Thompson     } else {
4412b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
442441428dfSJeremy L Thompson     }
443441428dfSJeremy L Thompson   } else {
444441428dfSJeremy L Thompson     *(void **)data = NULL;
445441428dfSJeremy L Thompson   }
446441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
447441428dfSJeremy L Thompson }
448441428dfSJeremy L Thompson 
449441428dfSJeremy L Thompson /**
450ca94c3ddSJeremy L Thompson   @brief Restore inner context data of a `CeedQFunction`
451441428dfSJeremy L Thompson 
452ca94c3ddSJeremy L Thompson   @param[in]     qf   `CeedQFunction`
453ea61e9acSJeremy L Thompson   @param[in,out] data Data to restore
454441428dfSJeremy L Thompson 
455441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
456441428dfSJeremy L Thompson 
457441428dfSJeremy L Thompson   @ref Backend
458441428dfSJeremy L Thompson **/
459441428dfSJeremy L Thompson int CeedQFunctionRestoreInnerContextData(CeedQFunction qf, void *data) {
460441428dfSJeremy L Thompson   bool                 is_writable;
461441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
462441428dfSJeremy L Thompson 
4632b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
464441428dfSJeremy L Thompson   if (ctx) {
4652b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
466441428dfSJeremy L Thompson     if (is_writable) {
4672b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
468441428dfSJeremy L Thompson     } else {
4692b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
470441428dfSJeremy L Thompson     }
471441428dfSJeremy L Thompson   }
4725f249b39SJeremy L Thompson   *(void **)data = NULL;
473441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
474441428dfSJeremy L Thompson }
475441428dfSJeremy L Thompson 
476441428dfSJeremy L Thompson /**
477ca94c3ddSJeremy L Thompson   @brief Determine if `CeedQFunction` is identity
4787a982d89SJeremy L. Thompson 
479ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
480d1d35e2fSjeremylt   @param[out] is_identity Variable to store identity status
4817a982d89SJeremy L. Thompson 
4827a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4837a982d89SJeremy L. Thompson 
4847a982d89SJeremy L. Thompson   @ref Backend
4857a982d89SJeremy L. Thompson **/
486d1d35e2fSjeremylt int CeedQFunctionIsIdentity(CeedQFunction qf, bool *is_identity) {
487f04ea552SJeremy L Thompson   *is_identity = qf->is_identity;
488e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4897a982d89SJeremy L. Thompson }
4907a982d89SJeremy L. Thompson 
4917a982d89SJeremy L. Thompson /**
492ca94c3ddSJeremy L Thompson   @brief Determine if `CeedQFunctionContext` is writable
493441428dfSJeremy L Thompson 
494ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
495ea61e9acSJeremy L Thompson   @param[out] is_writable Variable to store context writeable status
496441428dfSJeremy L Thompson 
497441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
498441428dfSJeremy L Thompson 
499441428dfSJeremy L Thompson   @ref Backend
500441428dfSJeremy L Thompson **/
501441428dfSJeremy L Thompson int CeedQFunctionIsContextWritable(CeedQFunction qf, bool *is_writable) {
502441428dfSJeremy L Thompson   *is_writable = qf->is_context_writable;
503441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
504441428dfSJeremy L Thompson }
505441428dfSJeremy L Thompson 
506441428dfSJeremy L Thompson /**
507ca94c3ddSJeremy L Thompson   @brief Get backend data of a `CeedQFunction`
5087a982d89SJeremy L. Thompson 
509ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction`
5107a982d89SJeremy L. Thompson   @param[out] data Variable to store data
5117a982d89SJeremy L. Thompson 
5127a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5137a982d89SJeremy L. Thompson 
5147a982d89SJeremy L. Thompson   @ref Backend
5157a982d89SJeremy L. Thompson **/
516777ff853SJeremy L Thompson int CeedQFunctionGetData(CeedQFunction qf, void *data) {
517777ff853SJeremy L Thompson   *(void **)data = qf->data;
518e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5197a982d89SJeremy L. Thompson }
5207a982d89SJeremy L. Thompson 
5217a982d89SJeremy L. Thompson /**
522ca94c3ddSJeremy L Thompson   @brief Set backend data of a `CeedQFunction`
5237a982d89SJeremy L. Thompson 
524ca94c3ddSJeremy L Thompson   @param[in,out] qf   `CeedQFunction`
525ea61e9acSJeremy L Thompson   @param[in]     data Data to set
5267a982d89SJeremy L. Thompson 
5277a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5287a982d89SJeremy L. Thompson 
5297a982d89SJeremy L. Thompson   @ref Backend
5307a982d89SJeremy L. Thompson **/
531777ff853SJeremy L Thompson int CeedQFunctionSetData(CeedQFunction qf, void *data) {
532777ff853SJeremy L Thompson   qf->data = data;
533e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5347a982d89SJeremy L. Thompson }
5357a982d89SJeremy L. Thompson 
5367a982d89SJeremy L. Thompson /**
5371203703bSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedQFunction` is immutable
5381203703bSJeremy L Thompson 
5391203703bSJeremy L Thompson   @param[in]  qf           `CeedOperator`
5401203703bSJeremy L Thompson   @param[out] is_immutable Variable to store immutability status
5411203703bSJeremy L Thompson 
5421203703bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5431203703bSJeremy L Thompson 
5441203703bSJeremy L Thompson   @ref Backend
5451203703bSJeremy L Thompson **/
5461203703bSJeremy L Thompson int CeedQFunctionIsImmutable(CeedQFunction qf, bool *is_immutable) {
5471203703bSJeremy L Thompson   *is_immutable = qf->is_immutable;
5481203703bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
5491203703bSJeremy L Thompson }
5501203703bSJeremy L Thompson 
5511203703bSJeremy L Thompson /**
5521203703bSJeremy L Thompson   @brief Set the immutable flag of a `CeedQFunction` to `true`
5531203703bSJeremy L Thompson 
5541203703bSJeremy L Thompson   @param[in,out] qf `CeedQFunction`
5551203703bSJeremy L Thompson 
5561203703bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5571203703bSJeremy L Thompson 
5581203703bSJeremy L Thompson   @ref Backend
5591203703bSJeremy L Thompson **/
5601203703bSJeremy L Thompson int CeedQFunctionSetImmutable(CeedQFunction qf) {
5611203703bSJeremy L Thompson   qf->is_immutable = true;
5621203703bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
5631203703bSJeremy L Thompson }
5641203703bSJeremy L Thompson 
5651203703bSJeremy L Thompson /**
566ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedQFunction`
56734359f16Sjeremylt 
568ca94c3ddSJeremy L Thompson   @param[in,out] qf `CeedQFunction` to increment the reference counter
56934359f16Sjeremylt 
57034359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
57134359f16Sjeremylt 
57234359f16Sjeremylt   @ref Backend
57334359f16Sjeremylt **/
5749560d06aSjeremylt int CeedQFunctionReference(CeedQFunction qf) {
57534359f16Sjeremylt   qf->ref_count++;
57634359f16Sjeremylt   return CEED_ERROR_SUCCESS;
57734359f16Sjeremylt }
57834359f16Sjeremylt 
5796e15d496SJeremy L Thompson /**
580ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs per quadrature required to apply `CeedQFunction`
5816e15d496SJeremy L Thompson 
582ca94c3ddSJeremy L Thompson   @param[in]  qf    `CeedQFunction` to estimate FLOPs for
583ea61e9acSJeremy L Thompson   @param[out] flops Address of variable to hold FLOPs estimate
5846e15d496SJeremy L Thompson 
5856e15d496SJeremy L Thompson   @ref Backend
5866e15d496SJeremy L Thompson **/
5879d36ca50SJeremy L Thompson int CeedQFunctionGetFlopsEstimate(CeedQFunction qf, CeedSize *flops) {
5886e15d496SJeremy L Thompson   *flops = qf->user_flop_estimate;
5896e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5906e15d496SJeremy L Thompson }
5916e15d496SJeremy L Thompson 
5927a982d89SJeremy L. Thompson /// @}
5937a982d89SJeremy L. Thompson 
5947a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5957a982d89SJeremy L. Thompson /// CeedQFunction Public API
5967a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5977a982d89SJeremy L. Thompson /// @addtogroup CeedQFunctionUser
5987a982d89SJeremy L. Thompson /// @{
5997a982d89SJeremy L. Thompson 
6007a982d89SJeremy L. Thompson /**
601ca94c3ddSJeremy L Thompson   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms
6027a982d89SJeremy L. Thompson 
603ca94c3ddSJeremy L Thompson   @param[in]  ceed       `Ceed` object used to create the `CeedQFunction`
604ca94c3ddSJeremy L Thompson   @param[in]  vec_length Vector length.
605ca94c3ddSJeremy L Thompson                            Caller must ensure that number of quadrature points is a multiple of `vec_length`.
606ea61e9acSJeremy L Thompson   @param[in]  f          Function pointer to evaluate action at quadrature points.
607ca94c3ddSJeremy L Thompson                            See `CeedQFunctionUser`.
608ca94c3ddSJeremy L Thompson   @param[in]  source     Absolute path to source of `CeedQFunctionUser`, "\abs_path\file.h:function_name".
609ca94c3ddSJeremy 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.).
6104ada38baSJames Wright                            The entire contents of this file and all locally included files are used during JiT compilation for GPU backends.
6114ada38baSJames Wright                            All source files must be at the provided filepath at runtime for JiT to function.
612ca94c3ddSJeremy L Thompson   @param[out] qf         Address of the variable where the newly created `CeedQFunction` will be stored
6137a982d89SJeremy L. Thompson 
6147a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6157a982d89SJeremy L. Thompson 
616ca94c3ddSJeremy L Thompson   See \ref CeedQFunctionUser for details on the call-back function `f` arguments.
6177a982d89SJeremy L. Thompson 
6187a982d89SJeremy L. Thompson   @ref User
6197a982d89SJeremy L. Thompson **/
6202b730f8bSJeremy L Thompson int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vec_length, CeedQFunctionUser f, const char *source, CeedQFunction *qf) {
621ca5eadf8SJeremy L Thompson   char *user_source_copy;
6227a982d89SJeremy L. Thompson 
6237a982d89SJeremy L. Thompson   if (!ceed->QFunctionCreate) {
6247a982d89SJeremy L. Thompson     Ceed delegate;
6256574a04fSJeremy L Thompson 
6262b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "QFunction"));
6271ef3a2a9SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedQFunctionCreateInterior");
6282b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionCreateInterior(delegate, vec_length, f, source, qf));
629e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
6307a982d89SJeremy L. Thompson   }
6317a982d89SJeremy L. Thompson 
6326574a04fSJeremy L Thompson   CeedCheck(!strlen(source) || strrchr(source, ':'), ceed, CEED_ERROR_INCOMPLETE,
6336574a04fSJeremy L Thompson             "Provided path to source does not include function name. Provided: \"%s\"\nRequired: \"\\abs_path\\file.h:function_name\"", source);
63443e1b16fSJeremy L Thompson 
6352b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, qf));
636db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*qf)->ceed));
637d1d35e2fSjeremylt   (*qf)->ref_count           = 1;
638d1d35e2fSjeremylt   (*qf)->vec_length          = vec_length;
639f04ea552SJeremy L Thompson   (*qf)->is_identity         = false;
640441428dfSJeremy L Thompson   (*qf)->is_context_writable = true;
6417a982d89SJeremy L. Thompson   (*qf)->function            = f;
6426e15d496SJeremy L Thompson   (*qf)->user_flop_estimate  = -1;
64343e1b16fSJeremy L Thompson   if (strlen(source)) {
644ca5eadf8SJeremy L Thompson     size_t user_source_len = strlen(source);
645ee5a26f2SJeremy L Thompson 
6462b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(user_source_len + 1, &user_source_copy));
647ca5eadf8SJeremy L Thompson     memcpy(user_source_copy, source, user_source_len);
648ca5eadf8SJeremy L Thompson     (*qf)->user_source = user_source_copy;
64943e1b16fSJeremy L Thompson   }
6502b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->input_fields));
6512b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->output_fields));
6522b730f8bSJeremy L Thompson   CeedCall(ceed->QFunctionCreate(*qf));
653e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6547a982d89SJeremy L. Thompson }
6557a982d89SJeremy L. Thompson 
6567a982d89SJeremy L. Thompson /**
657ca94c3ddSJeremy L Thompson   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms by name
658288c0443SJeremy L Thompson 
659ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedQFunction`
660ca94c3ddSJeremy L Thompson   @param[in]  name Name of `CeedQFunction` to use from gallery
661ca94c3ddSJeremy L Thompson   @param[out] qf   Address of the variable where the newly created `CeedQFunction` will be stored
662288c0443SJeremy L Thompson 
663288c0443SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
664288c0443SJeremy L Thompson 
6657a982d89SJeremy L. Thompson   @ref User
666288c0443SJeremy L Thompson **/
6672b730f8bSJeremy L Thompson int CeedQFunctionCreateInteriorByName(Ceed ceed, const char *name, CeedQFunction *qf) {
668f7e22acaSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX;
669288c0443SJeremy L Thompson 
6702b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionRegisterAll());
671288c0443SJeremy L Thompson   // Find matching backend
672ca94c3ddSJeremy L Thompson   CeedCheck(name, ceed, CEED_ERROR_INCOMPLETE, "No CeedQFunction name provided");
673288c0443SJeremy L Thompson   for (size_t i = 0; i < num_qfunctions; i++) {
674288c0443SJeremy L Thompson     size_t      n;
675d1d35e2fSjeremylt     const char *curr_name = gallery_qfunctions[i].name;
6762b730f8bSJeremy L Thompson     for (n = 0; curr_name[n] && curr_name[n] == name[n]; n++) {
6772b730f8bSJeremy L Thompson     }
678d1d35e2fSjeremylt     if (n > match_len) {
679d1d35e2fSjeremylt       match_len   = n;
680f7e22acaSJeremy L Thompson       match_index = i;
681288c0443SJeremy L Thompson     }
682288c0443SJeremy L Thompson   }
683ca94c3ddSJeremy L Thompson   CeedCheck(match_len > 0, ceed, CEED_ERROR_UNSUPPORTED, "No suitable gallery CeedQFunction");
684288c0443SJeremy L Thompson 
685288c0443SJeremy L Thompson   // Create QFunction
6862b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionCreateInterior(ceed, gallery_qfunctions[match_index].vec_length, gallery_qfunctions[match_index].f,
6872b730f8bSJeremy L Thompson                                        gallery_qfunctions[match_index].source, qf));
688288c0443SJeremy L Thompson 
689288c0443SJeremy L Thompson   // QFunction specific setup
6902b730f8bSJeremy L Thompson   CeedCall(gallery_qfunctions[match_index].init(ceed, name, *qf));
691288c0443SJeremy L Thompson 
69275affc3bSjeremylt   // Copy name
6932b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(name, (char **)&(*qf)->gallery_name));
69443e1b16fSJeremy L Thompson   (*qf)->is_gallery = true;
695e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
696288c0443SJeremy L Thompson }
697288c0443SJeremy L Thompson 
698288c0443SJeremy L Thompson /**
699ca94c3ddSJeremy L Thompson   @brief Create an identity `CeedQFunction`.
7004385fb7fSSebastian Grimberg 
701ea61e9acSJeremy L Thompson   Inputs are written into outputs in the order given.
702ca94c3ddSJeremy 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.
703ca94c3ddSJeremy 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.
7040219ea01SJeremy L Thompson 
705ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` object used to create the `CeedQFunction`
706ca94c3ddSJeremy L Thompson   @param[in]  size     Size of the `CeedQFunction` fields
707ca94c3ddSJeremy L Thompson   @param[in]  in_mode  @ref CeedEvalMode for input to `CeedQFunction`
708ca94c3ddSJeremy L Thompson   @param[in]  out_mode @ref CeedEvalMode for output to `CeedQFunction`
709ca94c3ddSJeremy L Thompson   @param[out] qf       Address of the variable where the newly created `CeedQFunction` will be stored
7100219ea01SJeremy L Thompson 
7110219ea01SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
7120219ea01SJeremy L Thompson 
7137a982d89SJeremy L. Thompson   @ref User
7140219ea01SJeremy L Thompson **/
7152b730f8bSJeremy L Thompson int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode in_mode, CeedEvalMode out_mode, CeedQFunction *qf) {
7161c66c397SJeremy L Thompson   CeedQFunctionContext  ctx;
7171c66c397SJeremy L Thompson   CeedContextFieldLabel size_label;
7181c66c397SJeremy L Thompson 
7192b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Identity", qf));
7202b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAddInput(*qf, "input", size, in_mode));
7212b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAddOutput(*qf, "output", size, out_mode));
7220219ea01SJeremy L Thompson 
723f04ea552SJeremy L Thompson   (*qf)->is_identity = true;
724547dbd6fSJeremy L Thompson 
7252b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(*qf, &ctx));
7262b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextGetFieldLabel(ctx, "size", &size_label));
7272b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextSetInt32(ctx, size_label, &size));
728e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7290219ea01SJeremy L Thompson }
7300219ea01SJeremy L Thompson 
7310219ea01SJeremy L Thompson /**
732ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedQFunction`.
7334385fb7fSSebastian Grimberg 
734ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedQFunctionDestroy().
735512bb800SJeremy L Thompson 
736ca94c3ddSJeremy 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`.
737ca94c3ddSJeremy L Thompson         This `CeedQFunction` will be destroyed if `*qf_copy` is the only reference to this `CeedQFunction`.
7389560d06aSjeremylt 
739ca94c3ddSJeremy L Thompson   @param[in]  qf      `CeedQFunction` to copy reference to
7409560d06aSjeremylt   @param[out] qf_copy Variable to store copied reference
7419560d06aSjeremylt 
7429560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
7439560d06aSjeremylt 
7449560d06aSjeremylt   @ref User
7459560d06aSjeremylt **/
7469560d06aSjeremylt int CeedQFunctionReferenceCopy(CeedQFunction qf, CeedQFunction *qf_copy) {
7472b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionReference(qf));
7482b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(qf_copy));
7499560d06aSjeremylt   *qf_copy = qf;
7509560d06aSjeremylt   return CEED_ERROR_SUCCESS;
7519560d06aSjeremylt }
7529560d06aSjeremylt 
7539560d06aSjeremylt /**
754ca94c3ddSJeremy L Thompson   @brief Add a `CeedQFunction` input
755b11c1e72Sjeremylt 
756ca94c3ddSJeremy L Thompson   @param[in,out] qf         `CeedQFunction`
757ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of `CeedQFunction` field
758ca94c3ddSJeremy 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.
759ca94c3ddSJeremy L Thompson   @param[in]     eval_mode  @ref CEED_EVAL_NONE to use values directly,
760ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_INTERP to use interpolated values,
761ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_GRAD to use gradients,
762ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_DIV to use divergence,
763ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_CURL to use curl
764b11c1e72Sjeremylt 
765b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
766dfdf5a53Sjeremylt 
7677a982d89SJeremy L. Thompson   @ref User
768b11c1e72Sjeremylt **/
7692b730f8bSJeremy L Thompson int CeedQFunctionAddInput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
7701203703bSJeremy L Thompson   bool is_immutable;
7711203703bSJeremy L Thompson   Ceed ceed;
7721203703bSJeremy L Thompson 
7731203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetCeed(qf, &ceed));
7741203703bSJeremy L Thompson   CeedCall(CeedQFunctionIsImmutable(qf, &is_immutable));
7751203703bSJeremy L Thompson   CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable");
7761203703bSJeremy L Thompson   CeedCheck(eval_mode != CEED_EVAL_WEIGHT || size == 1, ceed, CEED_ERROR_DIMENSION, "CEED_EVAL_WEIGHT should have size 1");
777643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
778*3f08121cSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), ceed, CEED_ERROR_MINOR,
779*3f08121cSJeremy L Thompson               "CeedQFunction field names must be unique. Duplicate name: %s", field_name);
780643fbb69SJeremy L Thompson   }
781643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
782*3f08121cSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), ceed, CEED_ERROR_MINOR,
783*3f08121cSJeremy L Thompson               "CeedQFunction field names must be unique. Duplicate name: %s", field_name);
784643fbb69SJeremy L Thompson   }
7852b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionFieldSet(&qf->input_fields[qf->num_input_fields], field_name, size, eval_mode));
786d1d35e2fSjeremylt   qf->num_input_fields++;
787e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
788d7b241e6Sjeremylt }
789d7b241e6Sjeremylt 
790b11c1e72Sjeremylt /**
791ca94c3ddSJeremy L Thompson   @brief Add a `CeedQFunction` output
792b11c1e72Sjeremylt 
793ca94c3ddSJeremy L Thompson   @param[in,out] qf         `CeedQFunction`
794ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of `CeedQFunction` field
795ca94c3ddSJeremy 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.
796ca94c3ddSJeremy L Thompson   @param[in]     eval_mode  @ref CEED_EVAL_NONE to use values directly,
797ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_INTERP to use interpolated values,
798ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_GRAD to use gradients,
799ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_DIV to use divergence,
800ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_CURL to use curl.
801b11c1e72Sjeremylt 
802b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
803dfdf5a53Sjeremylt 
8047a982d89SJeremy L. Thompson   @ref User
805b11c1e72Sjeremylt **/
8062b730f8bSJeremy L Thompson int CeedQFunctionAddOutput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
8071203703bSJeremy L Thompson   bool is_immutable;
8081203703bSJeremy L Thompson   Ceed ceed;
8091203703bSJeremy L Thompson 
8101203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetCeed(qf, &ceed));
8111203703bSJeremy L Thompson   CeedCall(CeedQFunctionIsImmutable(qf, &is_immutable));
8121203703bSJeremy L Thompson   CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "CeedQFunction cannot be changed after set as immutable");
8131203703bSJeremy L Thompson   CeedCheck(eval_mode != CEED_EVAL_WEIGHT, ceed, CEED_ERROR_DIMENSION, "Cannot create CeedQFunction output with CEED_EVAL_WEIGHT");
814643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
8151203703bSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), ceed, CEED_ERROR_MINOR, "CeedQFunction field names must be unique");
816643fbb69SJeremy L Thompson   }
817643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
8181203703bSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), ceed, CEED_ERROR_MINOR, "CeedQFunction field names must be unique");
819643fbb69SJeremy L Thompson   }
8202b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionFieldSet(&qf->output_fields[qf->num_output_fields], field_name, size, eval_mode));
821d1d35e2fSjeremylt   qf->num_output_fields++;
822e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
823d7b241e6Sjeremylt }
824d7b241e6Sjeremylt 
825dfdf5a53Sjeremylt /**
826ca94c3ddSJeremy L Thompson   @brief Get the `CeedQFunctionField` of a `CeedQFunction`
82743bbe138SJeremy L Thompson 
828ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedQFunction` as immutable.
829f04ea552SJeremy L Thompson 
830ca94c3ddSJeremy L Thompson   @param[in]  qf                `CeedQFunction`
831f74ec584SJeremy L Thompson   @param[out] num_input_fields  Variable to store number of input fields
832f74ec584SJeremy L Thompson   @param[out] input_fields      Variable to store input fields
833f74ec584SJeremy L Thompson   @param[out] num_output_fields Variable to store number of output fields
834f74ec584SJeremy L Thompson   @param[out] output_fields     Variable to store output fields
83543bbe138SJeremy L Thompson 
83643bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
83743bbe138SJeremy L Thompson 
838e9b533fbSJeremy L Thompson   @ref Advanced
83943bbe138SJeremy L Thompson **/
8402b730f8bSJeremy L Thompson int CeedQFunctionGetFields(CeedQFunction qf, CeedInt *num_input_fields, CeedQFunctionField **input_fields, CeedInt *num_output_fields,
84143bbe138SJeremy L Thompson                            CeedQFunctionField **output_fields) {
8421203703bSJeremy L Thompson   CeedCall(CeedQFunctionSetImmutable(qf));
84343bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = qf->num_input_fields;
84443bbe138SJeremy L Thompson   if (input_fields) *input_fields = qf->input_fields;
84543bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = qf->num_output_fields;
84643bbe138SJeremy L Thompson   if (output_fields) *output_fields = qf->output_fields;
84743bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
84843bbe138SJeremy L Thompson }
84943bbe138SJeremy L Thompson 
85043bbe138SJeremy L Thompson /**
851ca94c3ddSJeremy L Thompson   @brief Get the name of a `CeedQFunctionField`
85243bbe138SJeremy L Thompson 
853ca94c3ddSJeremy L Thompson   @param[in]  qf_field   `CeedQFunctionField`
85443bbe138SJeremy L Thompson   @param[out] field_name Variable to store the field name
85543bbe138SJeremy L Thompson 
85643bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
85743bbe138SJeremy L Thompson 
858e9b533fbSJeremy L Thompson   @ref Advanced
85943bbe138SJeremy L Thompson **/
8606f8994e9SJeremy L Thompson int CeedQFunctionFieldGetName(CeedQFunctionField qf_field, const char **field_name) {
8616f8994e9SJeremy L Thompson   *field_name = qf_field->field_name;
86243bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
86343bbe138SJeremy L Thompson }
86443bbe138SJeremy L Thompson 
86543bbe138SJeremy L Thompson /**
866ca94c3ddSJeremy L Thompson   @brief Get the number of components of a `CeedQFunctionField`
86743bbe138SJeremy L Thompson 
868ca94c3ddSJeremy L Thompson   @param[in]  qf_field `CeedQFunctionField`
86943bbe138SJeremy L Thompson   @param[out] size     Variable to store the size of the field
87043bbe138SJeremy L Thompson 
87143bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
87243bbe138SJeremy L Thompson 
873e9b533fbSJeremy L Thompson   @ref Advanced
87443bbe138SJeremy L Thompson **/
87543bbe138SJeremy L Thompson int CeedQFunctionFieldGetSize(CeedQFunctionField qf_field, CeedInt *size) {
87643bbe138SJeremy L Thompson   *size = qf_field->size;
87743bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
87843bbe138SJeremy L Thompson }
87943bbe138SJeremy L Thompson 
88043bbe138SJeremy L Thompson /**
881ca94c3ddSJeremy L Thompson   @brief Get the @ref CeedEvalMode of a `CeedQFunctionField`
88243bbe138SJeremy L Thompson 
883ca94c3ddSJeremy L Thompson   @param[in]  qf_field  `CeedQFunctionField`
88443bbe138SJeremy L Thompson   @param[out] eval_mode Variable to store the field evaluation mode
88543bbe138SJeremy L Thompson 
88643bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
88743bbe138SJeremy L Thompson 
888e9b533fbSJeremy L Thompson   @ref Advanced
88943bbe138SJeremy L Thompson **/
8902b730f8bSJeremy L Thompson int CeedQFunctionFieldGetEvalMode(CeedQFunctionField qf_field, CeedEvalMode *eval_mode) {
89143bbe138SJeremy L Thompson   *eval_mode = qf_field->eval_mode;
89243bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
89343bbe138SJeremy L Thompson }
89443bbe138SJeremy L Thompson 
89543bbe138SJeremy L Thompson /**
896ab747706SJeremy L Thompson   @brief Get the data of a `CeedQFunctionField`.
897ab747706SJeremy L Thompson 
898ab747706SJeremy L Thompson   Any arguments set as `NULL` are ignored.
899ab747706SJeremy L Thompson 
900ab747706SJeremy L Thompson   @param[in]  qf_field   `CeedQFunctionField`
901ab747706SJeremy L Thompson   @param[out] field_name Variable to store the field name
902ab747706SJeremy L Thompson   @param[out] size       Variable to store the size of the field
903ab747706SJeremy L Thompson   @param[out] eval_mode  Variable to store the field evaluation mode
904ab747706SJeremy L Thompson 
905ab747706SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
906ab747706SJeremy L Thompson 
907ab747706SJeremy L Thompson   @ref Advanced
908ab747706SJeremy L Thompson **/
9096f8994e9SJeremy L Thompson int CeedQFunctionFieldGetData(CeedQFunctionField qf_field, const char **field_name, CeedInt *size, CeedEvalMode *eval_mode) {
910ab747706SJeremy L Thompson   if (field_name) CeedCall(CeedQFunctionFieldGetName(qf_field, field_name));
911ab747706SJeremy L Thompson   if (size) CeedCall(CeedQFunctionFieldGetSize(qf_field, size));
912ab747706SJeremy L Thompson   if (eval_mode) CeedCall(CeedQFunctionFieldGetEvalMode(qf_field, eval_mode));
913ab747706SJeremy L Thompson   return CEED_ERROR_SUCCESS;
914ab747706SJeremy L Thompson }
915ab747706SJeremy L Thompson 
916ab747706SJeremy L Thompson /**
917ca94c3ddSJeremy L Thompson   @brief Set global context for a `CeedQFunction`
918b11c1e72Sjeremylt 
919ca94c3ddSJeremy L Thompson   @param[in,out] qf  `CeedQFunction`
920ea61e9acSJeremy L Thompson   @param[in]     ctx Context data to set
921b11c1e72Sjeremylt 
922b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
923dfdf5a53Sjeremylt 
9247a982d89SJeremy L. Thompson   @ref User
925b11c1e72Sjeremylt **/
926777ff853SJeremy L Thompson int CeedQFunctionSetContext(CeedQFunction qf, CeedQFunctionContext ctx) {
9272b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextDestroy(&qf->ctx));
928d7b241e6Sjeremylt   qf->ctx = ctx;
929db002c03SJeremy L Thompson   if (ctx) CeedCall(CeedQFunctionContextReference(ctx));
930e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
931d7b241e6Sjeremylt }
932d7b241e6Sjeremylt 
933b11c1e72Sjeremylt /**
934ca94c3ddSJeremy L Thompson   @brief Set writability of `CeedQFunctionContext` when calling the `CeedQFunctionUser`.
9354385fb7fSSebastian Grimberg 
936859c15bbSJames Wright   The default value is `is_writable == true`.
937441428dfSJeremy L Thompson 
938ca94c3ddSJeremy L Thompson   Setting `is_writable == true` indicates the `CeedQFunctionUser` writes into the `CeedQFunctionContext` and requires memory synchronization after calling @ref CeedQFunctionApply().
939441428dfSJeremy L Thompson 
940ca94c3ddSJeremy L Thompson   Setting 'is_writable == false' asserts that `CeedQFunctionUser` does not modify the `CeedQFunctionContext`.
941ea61e9acSJeremy L Thompson   Violating this assertion may lead to inconsistent data.
942441428dfSJeremy L Thompson 
943441428dfSJeremy L Thompson   Setting `is_writable == false` may offer a performance improvement on GPU backends.
944441428dfSJeremy L Thompson 
945ca94c3ddSJeremy L Thompson   @param[in,out] qf          `CeedQFunction`
946ca94c3ddSJeremy L Thompson   @param[in]     is_writable Boolean flag for writability status
947441428dfSJeremy L Thompson 
948441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
949441428dfSJeremy L Thompson 
950441428dfSJeremy L Thompson   @ref User
951441428dfSJeremy L Thompson **/
952441428dfSJeremy L Thompson int CeedQFunctionSetContextWritable(CeedQFunction qf, bool is_writable) {
953441428dfSJeremy L Thompson   qf->is_context_writable = is_writable;
954441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
955441428dfSJeremy L Thompson }
956441428dfSJeremy L Thompson 
957441428dfSJeremy L Thompson /**
958ca94c3ddSJeremy L Thompson   @brief Set estimated number of FLOPs per quadrature required to apply `CeedQFunction`
9596e15d496SJeremy L Thompson 
960ca94c3ddSJeremy L Thompson   @param[in]  qf    `CeedQFunction` to estimate FLOPs for
961ea61e9acSJeremy L Thompson   @param[out] flops FLOPs per quadrature point estimate
9626e15d496SJeremy L Thompson 
9636e15d496SJeremy L Thompson   @ref Backend
9646e15d496SJeremy L Thompson **/
9659d36ca50SJeremy L Thompson int CeedQFunctionSetUserFlopsEstimate(CeedQFunction qf, CeedSize flops) {
9666e536b99SJeremy L Thompson   CeedCheck(flops >= 0, CeedQFunctionReturnCeed(qf), CEED_ERROR_INCOMPATIBLE, "Must set non-negative FLOPs estimate");
9676e15d496SJeremy L Thompson   qf->user_flop_estimate = flops;
9686e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9696e15d496SJeremy L Thompson }
9706e15d496SJeremy L Thompson 
9716e15d496SJeremy L Thompson /**
972ca94c3ddSJeremy L Thompson   @brief View a `CeedQFunction`
97375affc3bSjeremylt 
974ca94c3ddSJeremy L Thompson   @param[in] qf     `CeedQFunction` to view
975ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
97675affc3bSjeremylt 
97775affc3bSjeremylt   @return Error code: 0 - success, otherwise - failure
97875affc3bSjeremylt 
9797a982d89SJeremy L. Thompson   @ref User
98075affc3bSjeremylt **/
98175affc3bSjeremylt int CeedQFunctionView(CeedQFunction qf, FILE *stream) {
9827d023984SJeremy L Thompson   const char *kernel_name;
98375affc3bSjeremylt 
9842b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetKernelName(qf, &kernel_name));
9852b730f8bSJeremy L Thompson   fprintf(stream, "%sCeedQFunction - %s\n", qf->is_gallery ? "Gallery " : "User ", qf->is_gallery ? qf->gallery_name : kernel_name);
98675affc3bSjeremylt 
9872b730f8bSJeremy L Thompson   fprintf(stream, "  %" CeedInt_FMT " input field%s:\n", qf->num_input_fields, qf->num_input_fields > 1 ? "s" : "");
988d1d35e2fSjeremylt   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
9892b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionFieldView(qf->input_fields[i], i, 1, stream));
99075affc3bSjeremylt   }
99175affc3bSjeremylt 
9922b730f8bSJeremy L Thompson   fprintf(stream, "  %" CeedInt_FMT " output field%s:\n", qf->num_output_fields, qf->num_output_fields > 1 ? "s" : "");
993d1d35e2fSjeremylt   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
9942b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionFieldView(qf->output_fields[i], i, 0, stream));
99575affc3bSjeremylt   }
996e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
99775affc3bSjeremylt }
99875affc3bSjeremylt 
99975affc3bSjeremylt /**
1000ca94c3ddSJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedQFunction`
1001b7c9bbdaSJeremy L Thompson 
1002ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction`
1003ca94c3ddSJeremy L Thompson   @param[out] ceed Variable to store`Ceed`
1004b7c9bbdaSJeremy L Thompson 
1005b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1006b7c9bbdaSJeremy L Thompson 
1007b7c9bbdaSJeremy L Thompson   @ref Advanced
1008b7c9bbdaSJeremy L Thompson **/
1009b7c9bbdaSJeremy L Thompson int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) {
10106e536b99SJeremy L Thompson   *ceed = CeedQFunctionReturnCeed(qf);
1011b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1012b7c9bbdaSJeremy L Thompson }
1013b7c9bbdaSJeremy L Thompson 
1014b7c9bbdaSJeremy L Thompson /**
10156e536b99SJeremy L Thompson   @brief Return the `Ceed` associated with a `CeedQFunction`
10166e536b99SJeremy L Thompson 
10176e536b99SJeremy L Thompson   @param[in]  qf   `CeedQFunction`
10186e536b99SJeremy L Thompson 
10196e536b99SJeremy L Thompson   @return `Ceed` associated with the `qf`
10206e536b99SJeremy L Thompson 
10216e536b99SJeremy L Thompson   @ref Advanced
10226e536b99SJeremy L Thompson **/
10236e536b99SJeremy L Thompson Ceed CeedQFunctionReturnCeed(CeedQFunction qf) { return qf->ceed; }
10246e536b99SJeremy L Thompson 
10256e536b99SJeremy L Thompson /**
1026ca94c3ddSJeremy L Thompson   @brief Apply the action of a `CeedQFunction`
1027b11c1e72Sjeremylt 
1028ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedQFunction` as immutable.
1029f04ea552SJeremy L Thompson 
1030ca94c3ddSJeremy L Thompson   @param[in]  qf `CeedQFunction`
1031ea61e9acSJeremy L Thompson   @param[in]  Q  Number of quadrature points
1032ca94c3ddSJeremy L Thompson   @param[in]  u  Array of input `CeedVector`
1033ca94c3ddSJeremy L Thompson   @param[out] v  Array of output `CeedVector`
1034b11c1e72Sjeremylt 
1035b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1036dfdf5a53Sjeremylt 
10377a982d89SJeremy L. Thompson   @ref User
1038b11c1e72Sjeremylt **/
10392b730f8bSJeremy L Thompson int CeedQFunctionApply(CeedQFunction qf, CeedInt Q, CeedVector *u, CeedVector *v) {
10401203703bSJeremy L Thompson   CeedInt vec_length;
10411203703bSJeremy L Thompson   Ceed    ceed;
10421203703bSJeremy L Thompson 
10431203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetCeed(qf, &ceed));
10441203703bSJeremy L Thompson   CeedCheck(qf->Apply, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedQFunctionApply");
10451203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetVectorLength(qf, &vec_length));
10461203703bSJeremy L Thompson   CeedCheck(Q % vec_length == 0, ceed, CEED_ERROR_DIMENSION, "Number of quadrature points %" CeedInt_FMT " must be a multiple of %" CeedInt_FMT, Q,
10471203703bSJeremy L Thompson             qf->vec_length);
10481203703bSJeremy L Thompson   CeedCall(CeedQFunctionSetImmutable(qf));
10492b730f8bSJeremy L Thompson   CeedCall(qf->Apply(qf, Q, u, v));
1050e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1051d7b241e6Sjeremylt }
1052d7b241e6Sjeremylt 
1053b11c1e72Sjeremylt /**
1054ca94c3ddSJeremy L Thompson   @brief Destroy a `CeedQFunction`
1055b11c1e72Sjeremylt 
1056ca94c3ddSJeremy L Thompson   @param[in,out] qf `CeedQFunction` to destroy
1057b11c1e72Sjeremylt 
1058b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1059dfdf5a53Sjeremylt 
10607a982d89SJeremy L. Thompson   @ref User
1061b11c1e72Sjeremylt **/
1062d7b241e6Sjeremylt int CeedQFunctionDestroy(CeedQFunction *qf) {
1063ad6481ceSJeremy L Thompson   if (!*qf || --(*qf)->ref_count > 0) {
1064ad6481ceSJeremy L Thompson     *qf = NULL;
1065ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1066ad6481ceSJeremy L Thompson   }
1067fe2413ffSjeremylt   // Backend destroy
1068d7b241e6Sjeremylt   if ((*qf)->Destroy) {
10692b730f8bSJeremy L Thompson     CeedCall((*qf)->Destroy(*qf));
1070d7b241e6Sjeremylt   }
1071fe2413ffSjeremylt   // Free fields
107292ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*qf)->num_input_fields; i++) {
10732b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*(*qf)->input_fields[i]).field_name));
10742b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*qf)->input_fields[i]));
1075fe2413ffSjeremylt   }
107692ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*qf)->num_output_fields; i++) {
10772b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*(*qf)->output_fields[i]).field_name));
10782b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*qf)->output_fields[i]));
1079fe2413ffSjeremylt   }
10802b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->input_fields));
10812b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->output_fields));
1082777ff853SJeremy L Thompson 
1083777ff853SJeremy L Thompson   // User context data object
10842b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextDestroy(&(*qf)->ctx));
1085fe2413ffSjeremylt 
10862b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->user_source));
10872b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->source_path));
10882b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->gallery_name));
10892b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->kernel_name));
10902b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*qf)->ceed));
10912b730f8bSJeremy L Thompson   CeedCall(CeedFree(qf));
1092e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1093d7b241e6Sjeremylt }
1094d7b241e6Sjeremylt 
1095d7b241e6Sjeremylt /// @}
1096