xref: /libCEED/interface/ceed-qfunction.c (revision 22070f9510d4ff69aa6119a59aa3c46d57cc1cc7)
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 
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     Ceed  ceed;
212ca5eadf8SJeremy L Thompson     char *kernel_name_copy;
213ca5eadf8SJeremy L Thompson 
2141c66c397SJeremy L Thompson     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
215ca5eadf8SJeremy L Thompson     if (qf->user_source) {
216ca5eadf8SJeremy L Thompson       const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
217ca5eadf8SJeremy L Thompson       size_t      kernel_name_len = strlen(kernel_name);
218ca5eadf8SJeremy L Thompson 
2192b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(kernel_name_len + 1, &kernel_name_copy));
220ca5eadf8SJeremy L Thompson       memcpy(kernel_name_copy, kernel_name, kernel_name_len);
221ca5eadf8SJeremy L Thompson     } else {
2222b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(1, &kernel_name_copy));
223ca5eadf8SJeremy L Thompson     }
224ca5eadf8SJeremy L Thompson     qf->kernel_name = kernel_name_copy;
225ca5eadf8SJeremy L Thompson   }
226ca5eadf8SJeremy L Thompson 
2277d023984SJeremy L Thompson   *kernel_name = qf->kernel_name;
22843e1b16fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
22943e1b16fSJeremy L Thompson }
23043e1b16fSJeremy L Thompson 
23143e1b16fSJeremy L Thompson /**
232ca94c3ddSJeremy L Thompson   @brief Get the source path string for a `CeedQFunction`
23343e1b16fSJeremy L Thompson 
234ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
23543e1b16fSJeremy L Thompson   @param[out] source_path Variable to store source path string
23643e1b16fSJeremy L Thompson 
23743e1b16fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
23843e1b16fSJeremy L Thompson 
23943e1b16fSJeremy L Thompson   @ref Backend
24043e1b16fSJeremy L Thompson **/
24134ffed21SJeremy L Thompson int CeedQFunctionGetSourcePath(CeedQFunction qf, const char **source_path) {
242ca5eadf8SJeremy L Thompson   if (!qf->source_path && qf->user_source) {
243ca5eadf8SJeremy L Thompson     Ceed        ceed;
244ca5eadf8SJeremy L Thompson     bool        is_absolute_path;
245*22070f95SJeremy L Thompson     char       *source_path_copy;
246*22070f95SJeremy L Thompson     const char *absolute_path;
247ca5eadf8SJeremy L Thompson     const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
248ca5eadf8SJeremy L Thompson     size_t      kernel_name_len = strlen(kernel_name);
249ca5eadf8SJeremy L Thompson 
2502b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
2512b730f8bSJeremy L Thompson     CeedCall(CeedCheckFilePath(ceed, qf->user_source, &is_absolute_path));
252ca5eadf8SJeremy L Thompson     if (is_absolute_path) {
253ca5eadf8SJeremy L Thompson       absolute_path = (char *)qf->user_source;
254ca5eadf8SJeremy L Thompson     } else {
2552b730f8bSJeremy L Thompson       CeedCall(CeedGetJitAbsolutePath(ceed, qf->user_source, &absolute_path));
256ca5eadf8SJeremy L Thompson     }
257ca5eadf8SJeremy L Thompson 
258ca5eadf8SJeremy L Thompson     size_t source_len = strlen(absolute_path) - kernel_name_len - 1;
2591c66c397SJeremy L Thompson 
2602b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(source_len + 1, &source_path_copy));
261ca5eadf8SJeremy L Thompson     memcpy(source_path_copy, absolute_path, source_len);
262ca5eadf8SJeremy L Thompson     qf->source_path = source_path_copy;
263ca5eadf8SJeremy L Thompson 
2642b730f8bSJeremy L Thompson     if (!is_absolute_path) CeedCall(CeedFree(&absolute_path));
265ca5eadf8SJeremy L Thompson   }
266ca5eadf8SJeremy L Thompson 
26743e1b16fSJeremy L Thompson   *source_path = (char *)qf->source_path;
268e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2697a982d89SJeremy L. Thompson }
2707a982d89SJeremy L. Thompson 
2717a982d89SJeremy L. Thompson /**
272ca94c3ddSJeremy L Thompson   @brief Initialize and load `CeedQFunction` source file into string buffer, including full text of local files in place of `#include "local.h"`.
2734385fb7fSSebastian Grimberg 
274ca94c3ddSJeremy L Thompson   The `buffer` is set to `NULL` if there is no `CeedQFunction` source file.
2754385fb7fSSebastian Grimberg 
276f8d308faSJed Brown   Note: This function may as well return a mutable buffer, but all current uses
277f8d308faSJed Brown   do not modify it. (This is just a downside of `const` semantics with output
278f8d308faSJed Brown   arguments instead of returns.)
279f8d308faSJed Brown 
280ca94c3ddSJeremy L Thompson   Note: Caller is responsible for freeing the string buffer with @ref CeedFree().
2813d3250a0SJeremy L Thompson 
282ca94c3ddSJeremy L Thompson   @param[in]  qf            `CeedQFunction`
283f74ec584SJeremy L Thompson   @param[out] source_buffer String buffer for source file contents
2843d3250a0SJeremy L Thompson 
2853d3250a0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2863d3250a0SJeremy L Thompson 
2873d3250a0SJeremy L Thompson   @ref Backend
2883d3250a0SJeremy L Thompson **/
289f8d308faSJed Brown int CeedQFunctionLoadSourceToBuffer(CeedQFunction qf, const char **source_buffer) {
29034ffed21SJeremy L Thompson   const char *source_path;
2913d3250a0SJeremy L Thompson 
2922b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetSourcePath(qf, &source_path));
2933d3250a0SJeremy L Thompson   *source_buffer = NULL;
2943d3250a0SJeremy L Thompson   if (source_path) {
2951203703bSJeremy L Thompson     Ceed  ceed;
296f8d308faSJed Brown     char *buffer = NULL;
2971203703bSJeremy L Thompson 
2981203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
299f8d308faSJed Brown     CeedCall(CeedLoadSourceToBuffer(ceed, source_path, &buffer));
300f8d308faSJed Brown     *source_buffer = buffer;
3013d3250a0SJeremy L Thompson   }
3023d3250a0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3033d3250a0SJeremy L Thompson }
3043d3250a0SJeremy L Thompson 
3053d3250a0SJeremy L Thompson /**
306ca94c3ddSJeremy L Thompson   @brief Get the User Function for a `CeedQFunction`
3077a982d89SJeremy L. Thompson 
308ca94c3ddSJeremy L Thompson   @param[in]  qf `CeedQFunction`
3097a982d89SJeremy L. Thompson   @param[out] f  Variable to store user function
3107a982d89SJeremy L. Thompson 
3117a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3127a982d89SJeremy L. Thompson 
3137a982d89SJeremy L. Thompson   @ref Backend
3147a982d89SJeremy L. Thompson **/
3157a982d89SJeremy L. Thompson int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) {
3167a982d89SJeremy L. Thompson   *f = qf->function;
317e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3187a982d89SJeremy L. Thompson }
3197a982d89SJeremy L. Thompson 
3207a982d89SJeremy L. Thompson /**
321ca94c3ddSJeremy L Thompson   @brief Get global context for a `CeedQFunction`.
3224385fb7fSSebastian Grimberg 
323ca94c3ddSJeremy L Thompson   Note: For `CeedQFunction` from the Fortran interface, this function will return the Fortran context `CeedQFunctionContext`.
3247a982d89SJeremy L. Thompson 
325ea61e9acSJeremy L Thompson   @param[in]  qf  CeedQFunction
326777ff853SJeremy L Thompson   @param[out] ctx Variable to store CeedQFunctionContext
3277a982d89SJeremy L. Thompson 
3287a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3297a982d89SJeremy L. Thompson 
3307a982d89SJeremy L. Thompson   @ref Backend
3317a982d89SJeremy L. Thompson **/
332777ff853SJeremy L Thompson int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
3337a982d89SJeremy L. Thompson   *ctx = qf->ctx;
334e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3357a982d89SJeremy L. Thompson }
3367a982d89SJeremy L. Thompson 
3377a982d89SJeremy L. Thompson /**
338ca94c3ddSJeremy L Thompson   @brief Get context data of a `CeedQFunction`
339441428dfSJeremy L Thompson 
340ca94c3ddSJeremy L Thompson   @param[in]  qf       `CeedQFunction`
341ea61e9acSJeremy L Thompson   @param[in]  mem_type Memory type on which to access the data.
342ea61e9acSJeremy L Thompson                          If the backend uses a different memory type, this will perform a copy.
343441428dfSJeremy L Thompson   @param[out] data     Data on memory type mem_type
344441428dfSJeremy L Thompson 
345441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
346441428dfSJeremy L Thompson 
347441428dfSJeremy L Thompson   @ref Backend
348441428dfSJeremy L Thompson **/
3492b730f8bSJeremy L Thompson int CeedQFunctionGetContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
350441428dfSJeremy L Thompson   bool                 is_writable;
351441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
352441428dfSJeremy L Thompson 
3532b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &ctx));
354441428dfSJeremy L Thompson   if (ctx) {
3552b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
356441428dfSJeremy L Thompson     if (is_writable) {
3572b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
358441428dfSJeremy L Thompson     } else {
3592b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
360441428dfSJeremy L Thompson     }
361441428dfSJeremy L Thompson   } else {
362441428dfSJeremy L Thompson     *(void **)data = NULL;
363441428dfSJeremy L Thompson   }
364441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
365441428dfSJeremy L Thompson }
366441428dfSJeremy L Thompson 
367441428dfSJeremy L Thompson /**
368ca94c3ddSJeremy L Thompson   @brief Restore context data of a `CeedQFunction`
369441428dfSJeremy L Thompson 
370ca94c3ddSJeremy L Thompson   @param[in]     qf   `CeedQFunction`
371ea61e9acSJeremy L Thompson   @param[in,out] data Data to restore
372441428dfSJeremy L Thompson 
373441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
374441428dfSJeremy L Thompson 
375441428dfSJeremy L Thompson   @ref Backend
376441428dfSJeremy L Thompson **/
377441428dfSJeremy L Thompson int CeedQFunctionRestoreContextData(CeedQFunction qf, void *data) {
378441428dfSJeremy L Thompson   bool                 is_writable;
379441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
380441428dfSJeremy L Thompson 
3812b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &ctx));
382441428dfSJeremy L Thompson   if (ctx) {
3832b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
384441428dfSJeremy L Thompson     if (is_writable) {
3852b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
386441428dfSJeremy L Thompson     } else {
3872b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
388441428dfSJeremy L Thompson     }
389441428dfSJeremy L Thompson   }
3905f249b39SJeremy L Thompson   *(void **)data = NULL;
391441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
392441428dfSJeremy L Thompson }
393441428dfSJeremy L Thompson 
394441428dfSJeremy L Thompson /**
395ca94c3ddSJeremy L Thompson   @brief Get true user context for a `CeedQFunction`
3964385fb7fSSebastian Grimberg 
397ca94c3ddSJeremy L Thompson   Note: For all `CeedQFunction` this function will return the user `CeedQFunctionContext` and not interface context `CeedQFunctionContext`, if any such object exists.
3987a982d89SJeremy L. Thompson 
399ca94c3ddSJeremy L Thompson   @param[in]  qf  `CeedQFunction`
400ca94c3ddSJeremy L Thompson   @param[out] ctx Variable to store `CeedQFunctionContext`
4017a982d89SJeremy L. Thompson 
4027a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4037a982d89SJeremy L. Thompson   @ref Backend
4047a982d89SJeremy L. Thompson **/
405777ff853SJeremy L Thompson int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
4061203703bSJeremy L Thompson   CeedQFunctionContext qf_ctx;
4071203703bSJeremy L Thompson 
4081203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(qf, &qf_ctx));
409f04ea552SJeremy L Thompson   if (qf->is_fortran) {
410d1d35e2fSjeremylt     CeedFortranContext fortran_ctx = NULL;
4111c66c397SJeremy L Thompson 
4121203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextGetData(qf_ctx, CEED_MEM_HOST, &fortran_ctx));
4138cb0412aSJeremy L Thompson     *ctx = fortran_ctx->inner_ctx;
4141203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextRestoreData(qf_ctx, (void *)&fortran_ctx));
4157a982d89SJeremy L. Thompson   } else {
4161203703bSJeremy L Thompson     *ctx = qf_ctx;
4177a982d89SJeremy L. Thompson   }
418e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4197a982d89SJeremy L. Thompson }
4207a982d89SJeremy L. Thompson 
4217a982d89SJeremy L. Thompson /**
422ca94c3ddSJeremy L Thompson   @brief Get inner context data of a `CeedQFunction`
423441428dfSJeremy L Thompson 
424ca94c3ddSJeremy L Thompson   @param[in]  qf       `CeedQFunction`
425ea61e9acSJeremy L Thompson   @param[in]  mem_type Memory type on which to access the data.
426ea61e9acSJeremy L Thompson                          If the backend uses a different memory type, this will perform a copy.
427441428dfSJeremy L Thompson   @param[out] data     Data on memory type mem_type
428441428dfSJeremy L Thompson 
429441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
430441428dfSJeremy L Thompson 
431441428dfSJeremy L Thompson   @ref Backend
432441428dfSJeremy L Thompson **/
4332b730f8bSJeremy L Thompson int CeedQFunctionGetInnerContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
434441428dfSJeremy L Thompson   bool                 is_writable;
435441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
436441428dfSJeremy L Thompson 
4372b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
438441428dfSJeremy L Thompson   if (ctx) {
4392b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
440441428dfSJeremy L Thompson     if (is_writable) {
4412b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
442441428dfSJeremy L Thompson     } else {
4432b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
444441428dfSJeremy L Thompson     }
445441428dfSJeremy L Thompson   } else {
446441428dfSJeremy L Thompson     *(void **)data = NULL;
447441428dfSJeremy L Thompson   }
448441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
449441428dfSJeremy L Thompson }
450441428dfSJeremy L Thompson 
451441428dfSJeremy L Thompson /**
452ca94c3ddSJeremy L Thompson   @brief Restore inner context data of a `CeedQFunction`
453441428dfSJeremy L Thompson 
454ca94c3ddSJeremy L Thompson   @param[in]     qf   `CeedQFunction`
455ea61e9acSJeremy L Thompson   @param[in,out] data Data to restore
456441428dfSJeremy L Thompson 
457441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
458441428dfSJeremy L Thompson 
459441428dfSJeremy L Thompson   @ref Backend
460441428dfSJeremy L Thompson **/
461441428dfSJeremy L Thompson int CeedQFunctionRestoreInnerContextData(CeedQFunction qf, void *data) {
462441428dfSJeremy L Thompson   bool                 is_writable;
463441428dfSJeremy L Thompson   CeedQFunctionContext ctx;
464441428dfSJeremy L Thompson 
4652b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
466441428dfSJeremy L Thompson   if (ctx) {
4672b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
468441428dfSJeremy L Thompson     if (is_writable) {
4692b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
470441428dfSJeremy L Thompson     } else {
4712b730f8bSJeremy L Thompson       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
472441428dfSJeremy L Thompson     }
473441428dfSJeremy L Thompson   }
4745f249b39SJeremy L Thompson   *(void **)data = NULL;
475441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
476441428dfSJeremy L Thompson }
477441428dfSJeremy L Thompson 
478441428dfSJeremy L Thompson /**
479ca94c3ddSJeremy L Thompson   @brief Determine if `CeedQFunction` is identity
4807a982d89SJeremy L. Thompson 
481ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
482d1d35e2fSjeremylt   @param[out] is_identity Variable to store identity status
4837a982d89SJeremy L. Thompson 
4847a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4857a982d89SJeremy L. Thompson 
4867a982d89SJeremy L. Thompson   @ref Backend
4877a982d89SJeremy L. Thompson **/
488d1d35e2fSjeremylt int CeedQFunctionIsIdentity(CeedQFunction qf, bool *is_identity) {
489f04ea552SJeremy L Thompson   *is_identity = qf->is_identity;
490e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4917a982d89SJeremy L. Thompson }
4927a982d89SJeremy L. Thompson 
4937a982d89SJeremy L. Thompson /**
494ca94c3ddSJeremy L Thompson   @brief Determine if `CeedQFunctionContext` is writable
495441428dfSJeremy L Thompson 
496ca94c3ddSJeremy L Thompson   @param[in]  qf          `CeedQFunction`
497ea61e9acSJeremy L Thompson   @param[out] is_writable Variable to store context writeable status
498441428dfSJeremy L Thompson 
499441428dfSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
500441428dfSJeremy L Thompson 
501441428dfSJeremy L Thompson   @ref Backend
502441428dfSJeremy L Thompson **/
503441428dfSJeremy L Thompson int CeedQFunctionIsContextWritable(CeedQFunction qf, bool *is_writable) {
504441428dfSJeremy L Thompson   *is_writable = qf->is_context_writable;
505441428dfSJeremy L Thompson   return CEED_ERROR_SUCCESS;
506441428dfSJeremy L Thompson }
507441428dfSJeremy L Thompson 
508441428dfSJeremy L Thompson /**
509ca94c3ddSJeremy L Thompson   @brief Get backend data of a `CeedQFunction`
5107a982d89SJeremy L. Thompson 
511ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction`
5127a982d89SJeremy L. Thompson   @param[out] data Variable to store data
5137a982d89SJeremy L. Thompson 
5147a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5157a982d89SJeremy L. Thompson 
5167a982d89SJeremy L. Thompson   @ref Backend
5177a982d89SJeremy L. Thompson **/
518777ff853SJeremy L Thompson int CeedQFunctionGetData(CeedQFunction qf, void *data) {
519777ff853SJeremy L Thompson   *(void **)data = qf->data;
520e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5217a982d89SJeremy L. Thompson }
5227a982d89SJeremy L. Thompson 
5237a982d89SJeremy L. Thompson /**
524ca94c3ddSJeremy L Thompson   @brief Set backend data of a `CeedQFunction`
5257a982d89SJeremy L. Thompson 
526ca94c3ddSJeremy L Thompson   @param[in,out] qf   `CeedQFunction`
527ea61e9acSJeremy L Thompson   @param[in]     data Data to set
5287a982d89SJeremy L. Thompson 
5297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5307a982d89SJeremy L. Thompson 
5317a982d89SJeremy L. Thompson   @ref Backend
5327a982d89SJeremy L. Thompson **/
533777ff853SJeremy L Thompson int CeedQFunctionSetData(CeedQFunction qf, void *data) {
534777ff853SJeremy L Thompson   qf->data = data;
535e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5367a982d89SJeremy L. Thompson }
5377a982d89SJeremy L. Thompson 
5387a982d89SJeremy L. Thompson /**
5391203703bSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedQFunction` is immutable
5401203703bSJeremy L Thompson 
5411203703bSJeremy L Thompson   @param[in]  qf           `CeedOperator`
5421203703bSJeremy L Thompson   @param[out] is_immutable Variable to store immutability status
5431203703bSJeremy L Thompson 
5441203703bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5451203703bSJeremy L Thompson 
5461203703bSJeremy L Thompson   @ref Backend
5471203703bSJeremy L Thompson **/
5481203703bSJeremy L Thompson int CeedQFunctionIsImmutable(CeedQFunction qf, bool *is_immutable) {
5491203703bSJeremy L Thompson   *is_immutable = qf->is_immutable;
5501203703bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
5511203703bSJeremy L Thompson }
5521203703bSJeremy L Thompson 
5531203703bSJeremy L Thompson /**
5541203703bSJeremy L Thompson   @brief Set the immutable flag of a `CeedQFunction` to `true`
5551203703bSJeremy L Thompson 
5561203703bSJeremy L Thompson   @param[in,out] qf `CeedQFunction`
5571203703bSJeremy L Thompson 
5581203703bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5591203703bSJeremy L Thompson 
5601203703bSJeremy L Thompson   @ref Backend
5611203703bSJeremy L Thompson **/
5621203703bSJeremy L Thompson int CeedQFunctionSetImmutable(CeedQFunction qf) {
5631203703bSJeremy L Thompson   qf->is_immutable = true;
5641203703bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
5651203703bSJeremy L Thompson }
5661203703bSJeremy L Thompson 
5671203703bSJeremy L Thompson /**
568ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedQFunction`
56934359f16Sjeremylt 
570ca94c3ddSJeremy L Thompson   @param[in,out] qf `CeedQFunction` to increment the reference counter
57134359f16Sjeremylt 
57234359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
57334359f16Sjeremylt 
57434359f16Sjeremylt   @ref Backend
57534359f16Sjeremylt **/
5769560d06aSjeremylt int CeedQFunctionReference(CeedQFunction qf) {
57734359f16Sjeremylt   qf->ref_count++;
57834359f16Sjeremylt   return CEED_ERROR_SUCCESS;
57934359f16Sjeremylt }
58034359f16Sjeremylt 
5816e15d496SJeremy L Thompson /**
582ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs per quadrature required to apply `CeedQFunction`
5836e15d496SJeremy L Thompson 
584ca94c3ddSJeremy L Thompson   @param[in]  qf    `CeedQFunction` to estimate FLOPs for
585ea61e9acSJeremy L Thompson   @param[out] flops Address of variable to hold FLOPs estimate
5866e15d496SJeremy L Thompson 
5876e15d496SJeremy L Thompson   @ref Backend
5886e15d496SJeremy L Thompson **/
5899d36ca50SJeremy L Thompson int CeedQFunctionGetFlopsEstimate(CeedQFunction qf, CeedSize *flops) {
5906e15d496SJeremy L Thompson   *flops = qf->user_flop_estimate;
5916e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5926e15d496SJeremy L Thompson }
5936e15d496SJeremy L Thompson 
5947a982d89SJeremy L. Thompson /// @}
5957a982d89SJeremy L. Thompson 
5967a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5977a982d89SJeremy L. Thompson /// CeedQFunction Public API
5987a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5997a982d89SJeremy L. Thompson /// @addtogroup CeedQFunctionUser
6007a982d89SJeremy L. Thompson /// @{
6017a982d89SJeremy L. Thompson 
6027a982d89SJeremy L. Thompson /**
603ca94c3ddSJeremy L Thompson   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms
6047a982d89SJeremy L. Thompson 
605ca94c3ddSJeremy L Thompson   @param[in]  ceed       `Ceed` object used to create the `CeedQFunction`
606ca94c3ddSJeremy L Thompson   @param[in]  vec_length Vector length.
607ca94c3ddSJeremy L Thompson                            Caller must ensure that number of quadrature points is a multiple of `vec_length`.
608ea61e9acSJeremy L Thompson   @param[in]  f          Function pointer to evaluate action at quadrature points.
609ca94c3ddSJeremy L Thompson                            See `CeedQFunctionUser`.
610ca94c3ddSJeremy L Thompson   @param[in]  source     Absolute path to source of `CeedQFunctionUser`, "\abs_path\file.h:function_name".
611ca94c3ddSJeremy 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.).
6124ada38baSJames Wright                            The entire contents of this file and all locally included files are used during JiT compilation for GPU backends.
6134ada38baSJames Wright                            All source files must be at the provided filepath at runtime for JiT to function.
614ca94c3ddSJeremy L Thompson   @param[out] qf         Address of the variable where the newly created `CeedQFunction` will be stored
6157a982d89SJeremy L. Thompson 
6167a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6177a982d89SJeremy L. Thompson 
618ca94c3ddSJeremy L Thompson   See \ref CeedQFunctionUser for details on the call-back function `f` arguments.
6197a982d89SJeremy L. Thompson 
6207a982d89SJeremy L. Thompson   @ref User
6217a982d89SJeremy L. Thompson **/
6222b730f8bSJeremy L Thompson int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vec_length, CeedQFunctionUser f, const char *source, CeedQFunction *qf) {
623ca5eadf8SJeremy L Thompson   char *user_source_copy;
6247a982d89SJeremy L. Thompson 
6257a982d89SJeremy L. Thompson   if (!ceed->QFunctionCreate) {
6267a982d89SJeremy L. Thompson     Ceed delegate;
6276574a04fSJeremy L Thompson 
6282b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "QFunction"));
629ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedQFunctionCreateInterior");
6302b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionCreateInterior(delegate, vec_length, f, source, qf));
631e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
6327a982d89SJeremy L. Thompson   }
6337a982d89SJeremy L. Thompson 
6346574a04fSJeremy L Thompson   CeedCheck(!strlen(source) || strrchr(source, ':'), ceed, CEED_ERROR_INCOMPLETE,
6356574a04fSJeremy L Thompson             "Provided path to source does not include function name. Provided: \"%s\"\nRequired: \"\\abs_path\\file.h:function_name\"", source);
63643e1b16fSJeremy L Thompson 
6372b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, qf));
638db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*qf)->ceed));
639d1d35e2fSjeremylt   (*qf)->ref_count           = 1;
640d1d35e2fSjeremylt   (*qf)->vec_length          = vec_length;
641f04ea552SJeremy L Thompson   (*qf)->is_identity         = false;
642441428dfSJeremy L Thompson   (*qf)->is_context_writable = true;
6437a982d89SJeremy L. Thompson   (*qf)->function            = f;
6446e15d496SJeremy L Thompson   (*qf)->user_flop_estimate  = -1;
64543e1b16fSJeremy L Thompson   if (strlen(source)) {
646ca5eadf8SJeremy L Thompson     size_t user_source_len = strlen(source);
647ee5a26f2SJeremy L Thompson 
6482b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(user_source_len + 1, &user_source_copy));
649ca5eadf8SJeremy L Thompson     memcpy(user_source_copy, source, user_source_len);
650ca5eadf8SJeremy L Thompson     (*qf)->user_source = user_source_copy;
65143e1b16fSJeremy L Thompson   }
6522b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->input_fields));
6532b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->output_fields));
6542b730f8bSJeremy L Thompson   CeedCall(ceed->QFunctionCreate(*qf));
655e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6567a982d89SJeremy L. Thompson }
6577a982d89SJeremy L. Thompson 
6587a982d89SJeremy L. Thompson /**
659ca94c3ddSJeremy L Thompson   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms by name
660288c0443SJeremy L Thompson 
661ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedQFunction`
662ca94c3ddSJeremy L Thompson   @param[in]  name Name of `CeedQFunction` to use from gallery
663ca94c3ddSJeremy L Thompson   @param[out] qf   Address of the variable where the newly created `CeedQFunction` will be stored
664288c0443SJeremy L Thompson 
665288c0443SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
666288c0443SJeremy L Thompson 
6677a982d89SJeremy L. Thompson   @ref User
668288c0443SJeremy L Thompson **/
6692b730f8bSJeremy L Thompson int CeedQFunctionCreateInteriorByName(Ceed ceed, const char *name, CeedQFunction *qf) {
670f7e22acaSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX;
671288c0443SJeremy L Thompson 
6722b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionRegisterAll());
673288c0443SJeremy L Thompson   // Find matching backend
674ca94c3ddSJeremy L Thompson   CeedCheck(name, ceed, CEED_ERROR_INCOMPLETE, "No CeedQFunction name provided");
675288c0443SJeremy L Thompson   for (size_t i = 0; i < num_qfunctions; i++) {
676288c0443SJeremy L Thompson     size_t      n;
677d1d35e2fSjeremylt     const char *curr_name = gallery_qfunctions[i].name;
6782b730f8bSJeremy L Thompson     for (n = 0; curr_name[n] && curr_name[n] == name[n]; n++) {
6792b730f8bSJeremy L Thompson     }
680d1d35e2fSjeremylt     if (n > match_len) {
681d1d35e2fSjeremylt       match_len   = n;
682f7e22acaSJeremy L Thompson       match_index = i;
683288c0443SJeremy L Thompson     }
684288c0443SJeremy L Thompson   }
685ca94c3ddSJeremy L Thompson   CeedCheck(match_len > 0, ceed, CEED_ERROR_UNSUPPORTED, "No suitable gallery CeedQFunction");
686288c0443SJeremy L Thompson 
687288c0443SJeremy L Thompson   // Create QFunction
6882b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionCreateInterior(ceed, gallery_qfunctions[match_index].vec_length, gallery_qfunctions[match_index].f,
6892b730f8bSJeremy L Thompson                                        gallery_qfunctions[match_index].source, qf));
690288c0443SJeremy L Thompson 
691288c0443SJeremy L Thompson   // QFunction specific setup
6922b730f8bSJeremy L Thompson   CeedCall(gallery_qfunctions[match_index].init(ceed, name, *qf));
693288c0443SJeremy L Thompson 
69475affc3bSjeremylt   // Copy name
6952b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(name, (char **)&(*qf)->gallery_name));
69643e1b16fSJeremy L Thompson   (*qf)->is_gallery = true;
697e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
698288c0443SJeremy L Thompson }
699288c0443SJeremy L Thompson 
700288c0443SJeremy L Thompson /**
701ca94c3ddSJeremy L Thompson   @brief Create an identity `CeedQFunction`.
7024385fb7fSSebastian Grimberg 
703ea61e9acSJeremy L Thompson   Inputs are written into outputs in the order given.
704ca94c3ddSJeremy 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.
705ca94c3ddSJeremy 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.
7060219ea01SJeremy L Thompson 
707ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` object used to create the `CeedQFunction`
708ca94c3ddSJeremy L Thompson   @param[in]  size     Size of the `CeedQFunction` fields
709ca94c3ddSJeremy L Thompson   @param[in]  in_mode  @ref CeedEvalMode for input to `CeedQFunction`
710ca94c3ddSJeremy L Thompson   @param[in]  out_mode @ref CeedEvalMode for output to `CeedQFunction`
711ca94c3ddSJeremy L Thompson   @param[out] qf       Address of the variable where the newly created `CeedQFunction` will be stored
7120219ea01SJeremy L Thompson 
7130219ea01SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
7140219ea01SJeremy L Thompson 
7157a982d89SJeremy L. Thompson   @ref User
7160219ea01SJeremy L Thompson **/
7172b730f8bSJeremy L Thompson int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode in_mode, CeedEvalMode out_mode, CeedQFunction *qf) {
7181c66c397SJeremy L Thompson   CeedQFunctionContext  ctx;
7191c66c397SJeremy L Thompson   CeedContextFieldLabel size_label;
7201c66c397SJeremy L Thompson 
7212b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Identity", qf));
7222b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAddInput(*qf, "input", size, in_mode));
7232b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAddOutput(*qf, "output", size, out_mode));
7240219ea01SJeremy L Thompson 
725f04ea552SJeremy L Thompson   (*qf)->is_identity = true;
726547dbd6fSJeremy L Thompson 
7272b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetContext(*qf, &ctx));
7282b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextGetFieldLabel(ctx, "size", &size_label));
7292b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextSetInt32(ctx, size_label, &size));
730e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7310219ea01SJeremy L Thompson }
7320219ea01SJeremy L Thompson 
7330219ea01SJeremy L Thompson /**
734ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedQFunction`.
7354385fb7fSSebastian Grimberg 
736ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedQFunctionDestroy().
737512bb800SJeremy L Thompson 
738ca94c3ddSJeremy 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`.
739ca94c3ddSJeremy L Thompson         This `CeedQFunction` will be destroyed if `*qf_copy` is the only reference to this `CeedQFunction`.
7409560d06aSjeremylt 
741ca94c3ddSJeremy L Thompson   @param[in]  qf      `CeedQFunction` to copy reference to
7429560d06aSjeremylt   @param[out] qf_copy Variable to store copied reference
7439560d06aSjeremylt 
7449560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
7459560d06aSjeremylt 
7469560d06aSjeremylt   @ref User
7479560d06aSjeremylt **/
7489560d06aSjeremylt int CeedQFunctionReferenceCopy(CeedQFunction qf, CeedQFunction *qf_copy) {
7492b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionReference(qf));
7502b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(qf_copy));
7519560d06aSjeremylt   *qf_copy = qf;
7529560d06aSjeremylt   return CEED_ERROR_SUCCESS;
7539560d06aSjeremylt }
7549560d06aSjeremylt 
7559560d06aSjeremylt /**
756ca94c3ddSJeremy L Thompson   @brief Add a `CeedQFunction` input
757b11c1e72Sjeremylt 
758ca94c3ddSJeremy L Thompson   @param[in,out] qf         `CeedQFunction`
759ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of `CeedQFunction` field
760ca94c3ddSJeremy 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.
761ca94c3ddSJeremy L Thompson   @param[in]     eval_mode  @ref CEED_EVAL_NONE to use values directly,
762ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_INTERP to use interpolated values,
763ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_GRAD to use gradients,
764ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_DIV to use divergence,
765ca94c3ddSJeremy L Thompson                               @ref CEED_EVAL_CURL to use curl
766b11c1e72Sjeremylt 
767b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
768dfdf5a53Sjeremylt 
7697a982d89SJeremy L. Thompson   @ref User
770b11c1e72Sjeremylt **/
7712b730f8bSJeremy L Thompson int CeedQFunctionAddInput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
7721203703bSJeremy L Thompson   bool is_immutable;
7731203703bSJeremy L Thompson   Ceed ceed;
7741203703bSJeremy L Thompson 
7751203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetCeed(qf, &ceed));
7761203703bSJeremy L Thompson   CeedCall(CeedQFunctionIsImmutable(qf, &is_immutable));
7771203703bSJeremy L Thompson   CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable");
7781203703bSJeremy L Thompson   CeedCheck(eval_mode != CEED_EVAL_WEIGHT || size == 1, ceed, CEED_ERROR_DIMENSION, "CEED_EVAL_WEIGHT should have size 1");
779643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
7801203703bSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), ceed, CEED_ERROR_MINOR, "CeedQFunction field names must be unique");
781643fbb69SJeremy L Thompson   }
782643fbb69SJeremy L Thompson   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
7831203703bSJeremy L Thompson     CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), ceed, CEED_ERROR_MINOR, "CeedQFunction field names must be unique");
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) {
9661203703bSJeremy L Thompson   Ceed ceed;
9671203703bSJeremy L Thompson 
9681203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetCeed(qf, &ceed));
9691203703bSJeremy L Thompson   CeedCheck(flops >= 0, ceed, CEED_ERROR_INCOMPATIBLE, "Must set non-negative FLOPs estimate");
9706e15d496SJeremy L Thompson   qf->user_flop_estimate = flops;
9716e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9726e15d496SJeremy L Thompson }
9736e15d496SJeremy L Thompson 
9746e15d496SJeremy L Thompson /**
975ca94c3ddSJeremy L Thompson   @brief View a `CeedQFunction`
97675affc3bSjeremylt 
977ca94c3ddSJeremy L Thompson   @param[in] qf     `CeedQFunction` to view
978ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
97975affc3bSjeremylt 
98075affc3bSjeremylt   @return Error code: 0 - success, otherwise - failure
98175affc3bSjeremylt 
9827a982d89SJeremy L. Thompson   @ref User
98375affc3bSjeremylt **/
98475affc3bSjeremylt int CeedQFunctionView(CeedQFunction qf, FILE *stream) {
9857d023984SJeremy L Thompson   const char *kernel_name;
98675affc3bSjeremylt 
9872b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionGetKernelName(qf, &kernel_name));
9882b730f8bSJeremy L Thompson   fprintf(stream, "%sCeedQFunction - %s\n", qf->is_gallery ? "Gallery " : "User ", qf->is_gallery ? qf->gallery_name : kernel_name);
98975affc3bSjeremylt 
9902b730f8bSJeremy L Thompson   fprintf(stream, "  %" CeedInt_FMT " input field%s:\n", qf->num_input_fields, qf->num_input_fields > 1 ? "s" : "");
991d1d35e2fSjeremylt   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
9922b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionFieldView(qf->input_fields[i], i, 1, stream));
99375affc3bSjeremylt   }
99475affc3bSjeremylt 
9952b730f8bSJeremy L Thompson   fprintf(stream, "  %" CeedInt_FMT " output field%s:\n", qf->num_output_fields, qf->num_output_fields > 1 ? "s" : "");
996d1d35e2fSjeremylt   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
9972b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionFieldView(qf->output_fields[i], i, 0, stream));
99875affc3bSjeremylt   }
999e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
100075affc3bSjeremylt }
100175affc3bSjeremylt 
100275affc3bSjeremylt /**
1003ca94c3ddSJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedQFunction`
1004b7c9bbdaSJeremy L Thompson 
1005ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction`
1006ca94c3ddSJeremy L Thompson   @param[out] ceed Variable to store`Ceed`
1007b7c9bbdaSJeremy L Thompson 
1008b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1009b7c9bbdaSJeremy L Thompson 
1010b7c9bbdaSJeremy L Thompson   @ref Advanced
1011b7c9bbdaSJeremy L Thompson **/
1012b7c9bbdaSJeremy L Thompson int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) {
1013b7c9bbdaSJeremy L Thompson   *ceed = qf->ceed;
1014b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1015b7c9bbdaSJeremy L Thompson }
1016b7c9bbdaSJeremy L Thompson 
1017b7c9bbdaSJeremy L Thompson /**
1018ca94c3ddSJeremy L Thompson   @brief Apply the action of a `CeedQFunction`
1019b11c1e72Sjeremylt 
1020ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedQFunction` as immutable.
1021f04ea552SJeremy L Thompson 
1022ca94c3ddSJeremy L Thompson   @param[in]  qf `CeedQFunction`
1023ea61e9acSJeremy L Thompson   @param[in]  Q  Number of quadrature points
1024ca94c3ddSJeremy L Thompson   @param[in]  u  Array of input `CeedVector`
1025ca94c3ddSJeremy L Thompson   @param[out] v  Array of output `CeedVector`
1026b11c1e72Sjeremylt 
1027b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1028dfdf5a53Sjeremylt 
10297a982d89SJeremy L. Thompson   @ref User
1030b11c1e72Sjeremylt **/
10312b730f8bSJeremy L Thompson int CeedQFunctionApply(CeedQFunction qf, CeedInt Q, CeedVector *u, CeedVector *v) {
10321203703bSJeremy L Thompson   CeedInt vec_length;
10331203703bSJeremy L Thompson   Ceed    ceed;
10341203703bSJeremy L Thompson 
10351203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetCeed(qf, &ceed));
10361203703bSJeremy L Thompson   CeedCheck(qf->Apply, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedQFunctionApply");
10371203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetVectorLength(qf, &vec_length));
10381203703bSJeremy 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,
10391203703bSJeremy L Thompson             qf->vec_length);
10401203703bSJeremy L Thompson   CeedCall(CeedQFunctionSetImmutable(qf));
10412b730f8bSJeremy L Thompson   CeedCall(qf->Apply(qf, Q, u, v));
1042e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1043d7b241e6Sjeremylt }
1044d7b241e6Sjeremylt 
1045b11c1e72Sjeremylt /**
1046ca94c3ddSJeremy L Thompson   @brief Destroy a `CeedQFunction`
1047b11c1e72Sjeremylt 
1048ca94c3ddSJeremy L Thompson   @param[in,out] qf `CeedQFunction` to destroy
1049b11c1e72Sjeremylt 
1050b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1051dfdf5a53Sjeremylt 
10527a982d89SJeremy L. Thompson   @ref User
1053b11c1e72Sjeremylt **/
1054d7b241e6Sjeremylt int CeedQFunctionDestroy(CeedQFunction *qf) {
1055ad6481ceSJeremy L Thompson   if (!*qf || --(*qf)->ref_count > 0) {
1056ad6481ceSJeremy L Thompson     *qf = NULL;
1057ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1058ad6481ceSJeremy L Thompson   }
1059fe2413ffSjeremylt   // Backend destroy
1060d7b241e6Sjeremylt   if ((*qf)->Destroy) {
10612b730f8bSJeremy L Thompson     CeedCall((*qf)->Destroy(*qf));
1062d7b241e6Sjeremylt   }
1063fe2413ffSjeremylt   // Free fields
106492ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*qf)->num_input_fields; i++) {
10652b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*(*qf)->input_fields[i]).field_name));
10662b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*qf)->input_fields[i]));
1067fe2413ffSjeremylt   }
106892ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*qf)->num_output_fields; i++) {
10692b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*(*qf)->output_fields[i]).field_name));
10702b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*qf)->output_fields[i]));
1071fe2413ffSjeremylt   }
10722b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->input_fields));
10732b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->output_fields));
1074777ff853SJeremy L Thompson 
1075777ff853SJeremy L Thompson   // User context data object
10762b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionContextDestroy(&(*qf)->ctx));
1077fe2413ffSjeremylt 
10782b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->user_source));
10792b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->source_path));
10802b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->gallery_name));
10812b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*qf)->kernel_name));
10822b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*qf)->ceed));
10832b730f8bSJeremy L Thompson   CeedCall(CeedFree(qf));
1084e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1085d7b241e6Sjeremylt }
1086d7b241e6Sjeremylt 
1087d7b241e6Sjeremylt /// @}
1088