xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-qfunction.c (revision 20a16a5fde8c37c2820b3798c7dd8f97d46128bb)
1 // Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 #include <ceed-impl.h>
9 #include <ceed.h>
10 #include <ceed/backend.h>
11 #include <ceed/jit-tools.h>
12 #include <limits.h>
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 /// @file
18 /// Implementation of public CeedQFunction interfaces
19 
20 /// @cond DOXYGEN_SKIP
21 static struct CeedQFunction_private ceed_qfunction_none;
22 /// @endcond
23 
24 /// @addtogroup CeedQFunctionUser
25 /// @{
26 
27 // Indicate that no `CeedQFunction` is provided by the user
28 const CeedQFunction CEED_QFUNCTION_NONE = &ceed_qfunction_none;
29 
30 /// @}
31 
32 /// @cond DOXYGEN_SKIP
33 static struct {
34   char              name[CEED_MAX_RESOURCE_LEN];
35   char              source[CEED_MAX_RESOURCE_LEN];
36   CeedInt           vec_length;
37   CeedQFunctionUser f;
38   int (*init)(Ceed ceed, const char *name, CeedQFunction qf);
39 } gallery_qfunctions[1024];
40 static size_t num_qfunctions;
41 /// @endcond
42 
43 /// ----------------------------------------------------------------------------
44 /// CeedQFunction Library Internal Functions
45 /// ----------------------------------------------------------------------------
46 /// @addtogroup CeedQFunctionDeveloper
47 /// @{
48 
49 /**
50   @brief Register a gallery `CeedQFunction`
51 
52   @param[in] name       Name for this backend to respond to
53   @param[in] source     Absolute path to source of `CeedQFunction`, "\path\CEED_DIR\gallery\folder\file.h:function_name"
54   @param[in] vec_length Vector length.
55                           Caller must ensure that number of quadrature points is a multiple of `vec_length`.
56   @param[in] f          Function pointer to evaluate action at quadrature points.
57                           See `CeedQFunctionUser`.
58   @param[in] init       Initialization function called by @ref CeedQFunctionCreateInteriorByName() when the `CeedQFunction` is selected.
59 
60   @return An error code: 0 - success, otherwise - failure
61 
62   @ref Developer
63 **/
64 int CeedQFunctionRegister(const char *name, const char *source, CeedInt vec_length, CeedQFunctionUser f,
65                           int (*init)(Ceed, const char *, CeedQFunction)) {
66   const char *relative_file_path;
67   int         ierr = 0;
68 
69   CeedDebugEnv("Gallery Register: %s", name);
70   CeedCall(CeedGetJitRelativePath(source, &relative_file_path));
71   CeedPragmaCritical(CeedQFunctionRegister) {
72     if (num_qfunctions < sizeof(gallery_qfunctions) / sizeof(gallery_qfunctions[0])) {
73       strncpy(gallery_qfunctions[num_qfunctions].name, name, CEED_MAX_RESOURCE_LEN);
74       gallery_qfunctions[num_qfunctions].name[CEED_MAX_RESOURCE_LEN - 1] = 0;
75       strncpy(gallery_qfunctions[num_qfunctions].source, relative_file_path, CEED_MAX_RESOURCE_LEN);
76       gallery_qfunctions[num_qfunctions].source[CEED_MAX_RESOURCE_LEN - 1] = 0;
77       gallery_qfunctions[num_qfunctions].vec_length                        = vec_length;
78       gallery_qfunctions[num_qfunctions].f                                 = f;
79       gallery_qfunctions[num_qfunctions].init                              = init;
80       num_qfunctions++;
81     } else {
82       ierr = 1;
83     }
84   }
85   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "Too many gallery CeedQFunctions");
86   return CEED_ERROR_SUCCESS;
87 }
88 
89 /**
90   @brief Set a `CeedQFunction` field, used by @ref CeedQFunctionAddInput() and @ref CeedQFunctionAddOutput()
91 
92   @param[out] f           `CeedQFunctionField`
93   @param[in]  field_name  Name of `CeedQFunction` field
94   @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.
95   @param[in]  eval_mode   @ref CEED_EVAL_NONE to use values directly,
96                             @ref CEED_EVAL_WEIGHT to use quadrature weights,
97                             @ref CEED_EVAL_INTERP to use interpolated values,
98                             @ref CEED_EVAL_GRAD to use gradients,
99                             @ref CEED_EVAL_DIV to use divergence,
100                             @ref CEED_EVAL_CURL to use curl
101 
102   @return An error code: 0 - success, otherwise - failure
103 
104   @ref Developer
105 **/
106 static int CeedQFunctionFieldSet(CeedQFunctionField *f, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
107   CeedCall(CeedCalloc(1, f));
108   CeedCall(CeedStringAllocCopy(field_name, (char **)&(*f)->field_name));
109   (*f)->size      = size;
110   (*f)->eval_mode = eval_mode;
111   return CEED_ERROR_SUCCESS;
112 }
113 
114 /**
115   @brief View a field of a `CeedQFunction`
116 
117   @param[in] field        `CeedQFunction` field to view
118   @param[in] field_number Number of field being viewed
119   @param[in] in           true for input field, false for output
120   @param[in] stream       Stream to view to, e.g., `stdout`
121 
122   @return An error code: 0 - success, otherwise - failure
123 
124   @ref Utility
125 **/
126 static int CeedQFunctionFieldView(CeedQFunctionField field, CeedInt field_number, bool in, FILE *stream) {
127   const char  *inout = in ? "Input" : "Output";
128   const char  *field_name;
129   CeedInt      size;
130   CeedEvalMode eval_mode;
131 
132   CeedCall(CeedQFunctionFieldGetData(field, &field_name, &size, &eval_mode));
133   fprintf(stream,
134           "    %s field %" CeedInt_FMT
135           ":\n"
136           "      Name: \"%s\"\n"
137           "      Size: %" CeedInt_FMT
138           "\n"
139           "      EvalMode: \"%s\"\n",
140           inout, field_number, field_name, size, CeedEvalModes[eval_mode]);
141   return CEED_ERROR_SUCCESS;
142 }
143 
144 /**
145   @brief Set flag to determine if Fortran interface is used
146 
147   @param[in,out] qf     CeedQFunction
148   @param[in]     status Boolean value to set as Fortran status
149 
150   @return An error code: 0 - success, otherwise - failure
151 
152   @ref Backend
153 **/
154 int CeedQFunctionSetFortranStatus(CeedQFunction qf, bool status) {
155   qf->is_fortran = status;
156   return CEED_ERROR_SUCCESS;
157 }
158 
159 /// @}
160 
161 /// ----------------------------------------------------------------------------
162 /// CeedQFunction Backend API
163 /// ----------------------------------------------------------------------------
164 /// @addtogroup CeedQFunctionBackend
165 /// @{
166 
167 /**
168   @brief Get the vector length of a `CeedQFunction`
169 
170   @param[in]  qf         `CeedQFunction`
171   @param[out] vec_length Variable to store vector length
172 
173   @return An error code: 0 - success, otherwise - failure
174 
175   @ref Backend
176 **/
177 int CeedQFunctionGetVectorLength(CeedQFunction qf, CeedInt *vec_length) {
178   *vec_length = qf->vec_length;
179   return CEED_ERROR_SUCCESS;
180 }
181 
182 /**
183   @brief Get the number of inputs and outputs to a `CeedQFunction`
184 
185   @param[in]  qf         `CeedQFunction`
186   @param[out] num_input  Variable to store number of input fields
187   @param[out] num_output Variable to store number of output fields
188 
189   @return An error code: 0 - success, otherwise - failure
190 
191   @ref Backend
192 **/
193 int CeedQFunctionGetNumArgs(CeedQFunction qf, CeedInt *num_input, CeedInt *num_output) {
194   if (num_input) *num_input = qf->num_input_fields;
195   if (num_output) *num_output = qf->num_output_fields;
196   return CEED_ERROR_SUCCESS;
197 }
198 
199 /**
200   @brief Get the name of the user function for a `CeedQFunction`
201 
202   @param[in]  qf          `CeedQFunction`
203   @param[out] kernel_name Variable to store source path string
204 
205   @return An error code: 0 - success, otherwise - failure
206 
207   @ref Backend
208 **/
209 int CeedQFunctionGetKernelName(CeedQFunction qf, const char **kernel_name) {
210   if (!qf->kernel_name) {
211     char *kernel_name_copy;
212 
213     if (qf->user_source) {
214       const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
215       size_t      kernel_name_len = strlen(kernel_name);
216 
217       CeedCall(CeedCalloc(kernel_name_len + 1, &kernel_name_copy));
218       memcpy(kernel_name_copy, kernel_name, kernel_name_len);
219     } else {
220       CeedCall(CeedCalloc(1, &kernel_name_copy));
221     }
222     qf->kernel_name = kernel_name_copy;
223   }
224 
225   *kernel_name = qf->kernel_name;
226   return CEED_ERROR_SUCCESS;
227 }
228 
229 /**
230   @brief Get the source path string for a `CeedQFunction`
231 
232   @param[in]  qf          `CeedQFunction`
233   @param[out] source_path Variable to store source path string
234 
235   @return An error code: 0 - success, otherwise - failure
236 
237   @ref Backend
238 **/
239 int CeedQFunctionGetSourcePath(CeedQFunction qf, const char **source_path) {
240   if (!qf->source_path && qf->user_source) {
241     Ceed        ceed;
242     bool        is_absolute_path;
243     char       *source_path_copy;
244     const char *absolute_path;
245     const char *kernel_name     = strrchr(qf->user_source, ':') + 1;
246     size_t      kernel_name_len = strlen(kernel_name);
247 
248     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
249     CeedCall(CeedCheckFilePath(ceed, qf->user_source, &is_absolute_path));
250     if (is_absolute_path) {
251       absolute_path = (char *)qf->user_source;
252     } else {
253       CeedCall(CeedGetJitAbsolutePath(ceed, qf->user_source, &absolute_path));
254     }
255     CeedCall(CeedDestroy(&ceed));
256 
257     size_t source_len = strlen(absolute_path) - kernel_name_len - 1;
258 
259     CeedCall(CeedCalloc(source_len + 1, &source_path_copy));
260     memcpy(source_path_copy, absolute_path, source_len);
261     qf->source_path = source_path_copy;
262 
263     if (!is_absolute_path) CeedCall(CeedFree(&absolute_path));
264   }
265 
266   *source_path = (char *)qf->source_path;
267   return CEED_ERROR_SUCCESS;
268 }
269 
270 /**
271   @brief Initialize and load `CeedQFunction` source file into string buffer, including full text of local files in place of `#include "local.h"`.
272 
273   The `buffer` is set to `NULL` if there is no `CeedQFunction` source file.
274 
275   Note: This function may as well return a mutable buffer, but all current uses
276   do not modify it. (This is just a downside of `const` semantics with output
277   arguments instead of returns.)
278 
279   Note: Caller is responsible for freeing the string buffer with @ref CeedFree().
280 
281   @param[in]  qf            `CeedQFunction`
282   @param[out] source_buffer String buffer for source file contents
283 
284   @return An error code: 0 - success, otherwise - failure
285 
286   @ref Backend
287 **/
288 int CeedQFunctionLoadSourceToBuffer(CeedQFunction qf, const char **source_buffer) {
289   const char *source_path;
290 
291   CeedCall(CeedQFunctionGetSourcePath(qf, &source_path));
292   *source_buffer = NULL;
293   if (source_path) {
294     Ceed  ceed;
295     char *buffer = NULL;
296 
297     CeedCall(CeedQFunctionGetCeed(qf, &ceed));
298     CeedCall(CeedLoadSourceToBuffer(ceed, source_path, &buffer));
299     CeedCall(CeedDestroy(&ceed));
300     *source_buffer = buffer;
301   }
302   return CEED_ERROR_SUCCESS;
303 }
304 
305 /**
306   @brief Get the User Function for a `CeedQFunction`
307 
308   @param[in]  qf `CeedQFunction`
309   @param[out] f  Variable to store user function
310 
311   @return An error code: 0 - success, otherwise - failure
312 
313   @ref Backend
314 **/
315 int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) {
316   *f = qf->function;
317   return CEED_ERROR_SUCCESS;
318 }
319 
320 /**
321   @brief Get global context for a `CeedQFunction`.
322 
323   Note: For `CeedQFunction` from the Fortran interface, this function will return the Fortran context `CeedQFunctionContext`.
324 
325   @param[in]  qf  CeedQFunction
326   @param[out] ctx Variable to store CeedQFunctionContext
327 
328   @return An error code: 0 - success, otherwise - failure
329 
330   @ref Backend
331 **/
332 int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
333   *ctx = NULL;
334   if (qf->ctx) CeedCall(CeedQFunctionContextReferenceCopy(qf->ctx, ctx));
335   return CEED_ERROR_SUCCESS;
336 }
337 
338 /**
339   @brief Get context data of a `CeedQFunction`
340 
341   @param[in]  qf       `CeedQFunction`
342   @param[in]  mem_type Memory type on which to access the data.
343                          If the backend uses a different memory type, this will perform a copy.
344   @param[out] data     Data on memory type mem_type
345 
346   @return An error code: 0 - success, otherwise - failure
347 
348   @ref Backend
349 **/
350 int CeedQFunctionGetContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
351   bool                 is_writable;
352   CeedQFunctionContext ctx;
353 
354   CeedCall(CeedQFunctionGetContext(qf, &ctx));
355   if (ctx) {
356     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
357     if (is_writable) {
358       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
359     } else {
360       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
361     }
362   } else {
363     *(void **)data = NULL;
364   }
365   CeedCall(CeedQFunctionContextDestroy(&ctx));
366   return CEED_ERROR_SUCCESS;
367 }
368 
369 /**
370   @brief Restore context data of a `CeedQFunction`
371 
372   @param[in]     qf   `CeedQFunction`
373   @param[in,out] data Data to restore
374 
375   @return An error code: 0 - success, otherwise - failure
376 
377   @ref Backend
378 **/
379 int CeedQFunctionRestoreContextData(CeedQFunction qf, void *data) {
380   bool                 is_writable;
381   CeedQFunctionContext ctx;
382 
383   CeedCall(CeedQFunctionGetContext(qf, &ctx));
384   if (ctx) {
385     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
386     if (is_writable) {
387       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
388     } else {
389       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
390     }
391   }
392   CeedCall(CeedQFunctionContextDestroy(&ctx));
393   return CEED_ERROR_SUCCESS;
394 }
395 
396 /**
397   @brief Get true user context for a `CeedQFunction`
398 
399   Note: For all `CeedQFunction` this function will return the user `CeedQFunctionContext` and not interface context `CeedQFunctionContext`, if any such object exists.
400 
401   @param[in]  qf  `CeedQFunction`
402   @param[out] ctx Variable to store `CeedQFunctionContext`
403 
404   @return An error code: 0 - success, otherwise - failure
405   @ref Backend
406 **/
407 int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
408   CeedQFunctionContext qf_ctx;
409 
410   CeedCall(CeedQFunctionGetContext(qf, &qf_ctx));
411   if (qf->is_fortran) {
412     CeedFortranContext fortran_ctx = NULL;
413 
414     CeedCall(CeedQFunctionContextGetData(qf_ctx, CEED_MEM_HOST, &fortran_ctx));
415     *ctx = fortran_ctx->inner_ctx;
416     CeedCall(CeedQFunctionContextRestoreData(qf_ctx, &fortran_ctx));
417   } else {
418     *ctx = qf_ctx;
419   }
420   CeedCall(CeedQFunctionContextDestroy(&qf_ctx));
421   return CEED_ERROR_SUCCESS;
422 }
423 
424 /**
425   @brief Get inner context data of a `CeedQFunction`
426 
427   @param[in]  qf       `CeedQFunction`
428   @param[in]  mem_type Memory type on which to access the data.
429                          If the backend uses a different memory type, this will perform a copy.
430   @param[out] data     Data on memory type mem_type
431 
432   @return An error code: 0 - success, otherwise - failure
433 
434   @ref Backend
435 **/
436 int CeedQFunctionGetInnerContextData(CeedQFunction qf, CeedMemType mem_type, void *data) {
437   bool                 is_writable;
438   CeedQFunctionContext ctx;
439 
440   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
441   if (ctx) {
442     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
443     if (is_writable) {
444       CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data));
445     } else {
446       CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data));
447     }
448   } else {
449     *(void **)data = NULL;
450   }
451   return CEED_ERROR_SUCCESS;
452 }
453 
454 /**
455   @brief Restore inner context data of a `CeedQFunction`
456 
457   @param[in]     qf   `CeedQFunction`
458   @param[in,out] data Data to restore
459 
460   @return An error code: 0 - success, otherwise - failure
461 
462   @ref Backend
463 **/
464 int CeedQFunctionRestoreInnerContextData(CeedQFunction qf, void *data) {
465   bool                 is_writable;
466   CeedQFunctionContext ctx;
467 
468   CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
469   if (ctx) {
470     CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable));
471     if (is_writable) {
472       CeedCall(CeedQFunctionContextRestoreData(ctx, data));
473     } else {
474       CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data));
475     }
476   }
477   *(void **)data = NULL;
478   return CEED_ERROR_SUCCESS;
479 }
480 
481 /**
482   @brief Determine if `CeedQFunction` is identity
483 
484   @param[in]  qf          `CeedQFunction`
485   @param[out] is_identity Variable to store identity status
486 
487   @return An error code: 0 - success, otherwise - failure
488 
489   @ref Backend
490 **/
491 int CeedQFunctionIsIdentity(CeedQFunction qf, bool *is_identity) {
492   *is_identity = qf->is_identity;
493   return CEED_ERROR_SUCCESS;
494 }
495 
496 /**
497   @brief Determine if `CeedQFunctionContext` is writable
498 
499   @param[in]  qf          `CeedQFunction`
500   @param[out] is_writable Variable to store context writeable status
501 
502   @return An error code: 0 - success, otherwise - failure
503 
504   @ref Backend
505 **/
506 int CeedQFunctionIsContextWritable(CeedQFunction qf, bool *is_writable) {
507   *is_writable = qf->is_context_writable;
508   return CEED_ERROR_SUCCESS;
509 }
510 
511 /**
512   @brief Get backend data of a `CeedQFunction`
513 
514   @param[in]  qf   `CeedQFunction`
515   @param[out] data Variable to store data
516 
517   @return An error code: 0 - success, otherwise - failure
518 
519   @ref Backend
520 **/
521 int CeedQFunctionGetData(CeedQFunction qf, void *data) {
522   *(void **)data = qf->data;
523   return CEED_ERROR_SUCCESS;
524 }
525 
526 /**
527   @brief Set backend data of a `CeedQFunction`
528 
529   @param[in,out] qf   `CeedQFunction`
530   @param[in]     data Data to set
531 
532   @return An error code: 0 - success, otherwise - failure
533 
534   @ref Backend
535 **/
536 int CeedQFunctionSetData(CeedQFunction qf, void *data) {
537   qf->data = data;
538   return CEED_ERROR_SUCCESS;
539 }
540 
541 /**
542   @brief Get a boolean value indicating if the `CeedQFunction` is immutable
543 
544   @param[in]  qf           `CeedOperator`
545   @param[out] is_immutable Variable to store immutability status
546 
547   @return An error code: 0 - success, otherwise - failure
548 
549   @ref Backend
550 **/
551 int CeedQFunctionIsImmutable(CeedQFunction qf, bool *is_immutable) {
552   *is_immutable = qf->is_immutable;
553   return CEED_ERROR_SUCCESS;
554 }
555 
556 /**
557   @brief Set the immutable flag of a `CeedQFunction` to `true`
558 
559   @param[in,out] qf `CeedQFunction`
560 
561   @return An error code: 0 - success, otherwise - failure
562 
563   @ref Backend
564 **/
565 int CeedQFunctionSetImmutable(CeedQFunction qf) {
566   qf->is_immutable = true;
567   return CEED_ERROR_SUCCESS;
568 }
569 
570 /**
571   @brief Increment the reference counter for a `CeedQFunction`
572 
573   @param[in,out] qf `CeedQFunction` to increment the reference counter
574 
575   @return An error code: 0 - success, otherwise - failure
576 
577   @ref Backend
578 **/
579 int CeedQFunctionReference(CeedQFunction qf) {
580   qf->ref_count++;
581   return CEED_ERROR_SUCCESS;
582 }
583 
584 /**
585   @brief Estimate number of FLOPs per quadrature required to apply `CeedQFunction`
586 
587   @param[in]  qf    `CeedQFunction` to estimate FLOPs for
588   @param[out] flops Address of variable to hold FLOPs estimate
589 
590   @ref Backend
591 **/
592 int CeedQFunctionGetFlopsEstimate(CeedQFunction qf, CeedSize *flops) {
593   *flops = qf->user_flop_estimate;
594   return CEED_ERROR_SUCCESS;
595 }
596 
597 /// @}
598 
599 /// ----------------------------------------------------------------------------
600 /// CeedQFunction Public API
601 /// ----------------------------------------------------------------------------
602 /// @addtogroup CeedQFunctionUser
603 /// @{
604 
605 /**
606   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms
607 
608   @param[in]  ceed       `Ceed` object used to create the `CeedQFunction`
609   @param[in]  vec_length Vector length.
610                            Caller must ensure that number of quadrature points is a multiple of `vec_length`.
611   @param[in]  f          Function pointer to evaluate action at quadrature points.
612                            See `CeedQFunctionUser`.
613   @param[in]  source     Absolute path to source of `CeedQFunctionUser`, "\abs_path\file.h:function_name".
614                            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.).
615                            The entire contents of this file and all locally included files are used during JiT compilation for GPU backends.
616                            The header `ceed/types.h` is preferred over `ceed.h` or `ceed/ceed.h` for `CeedQFunction` source files.
617                            The macro `CEED_RUNNING_JIT_PASS` is set during JiT and can be used to guard include statements that JiT compilers cannot use, such as `math.h` or `std*.h`.
618                            All source files must be at the provided filepath at runtime for JiT to function.
619   @param[out] qf         Address of the variable where the newly created `CeedQFunction` will be stored
620 
621   @return An error code: 0 - success, otherwise - failure
622 
623   See \ref CeedQFunctionUser for details on the call-back function `f` arguments.
624 
625   @ref User
626 **/
627 int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vec_length, CeedQFunctionUser f, const char *source, CeedQFunction *qf) {
628   char *user_source_copy;
629 
630   if (!ceed->QFunctionCreate) {
631     Ceed delegate;
632 
633     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "QFunction"));
634     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedQFunctionCreateInterior");
635     CeedCall(CeedQFunctionCreateInterior(delegate, vec_length, f, source, qf));
636     CeedCall(CeedDestroy(&delegate));
637     return CEED_ERROR_SUCCESS;
638   }
639 
640   CeedCheck(!strlen(source) || strrchr(source, ':'), ceed, CEED_ERROR_INCOMPLETE,
641             "Provided path to source does not include function name. Provided: \"%s\"\nRequired: \"\\abs_path\\file.h:function_name\"", source);
642 
643   CeedCall(CeedCalloc(1, qf));
644   CeedCall(CeedReferenceCopy(ceed, &(*qf)->ceed));
645   (*qf)->ref_count           = 1;
646   (*qf)->vec_length          = vec_length;
647   (*qf)->is_identity         = false;
648   (*qf)->is_context_writable = true;
649   (*qf)->function            = f;
650   (*qf)->user_flop_estimate  = -1;
651   if (strlen(source)) {
652     size_t user_source_len = strlen(source);
653 
654     CeedCall(CeedCalloc(user_source_len + 1, &user_source_copy));
655     memcpy(user_source_copy, source, user_source_len);
656     (*qf)->user_source = user_source_copy;
657   }
658   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->input_fields));
659   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->output_fields));
660   CeedCall(ceed->QFunctionCreate(*qf));
661   return CEED_ERROR_SUCCESS;
662 }
663 
664 /**
665   @brief Create a `CeedQFunction` for evaluating interior (volumetric) terms by name
666 
667   @param[in]  ceed `Ceed` object used to create the `CeedQFunction`
668   @param[in]  name Name of `CeedQFunction` to use from gallery
669   @param[out] qf   Address of the variable where the newly created `CeedQFunction` will be stored
670 
671   @return An error code: 0 - success, otherwise - failure
672 
673   @ref User
674 **/
675 int CeedQFunctionCreateInteriorByName(Ceed ceed, const char *name, CeedQFunction *qf) {
676   size_t match_len = 0, match_index = UINT_MAX;
677 
678   CeedCall(CeedQFunctionRegisterAll());
679   // Find matching backend
680   CeedCheck(name, ceed, CEED_ERROR_INCOMPLETE, "No CeedQFunction name provided");
681   for (size_t i = 0; i < num_qfunctions; i++) {
682     size_t      n;
683     const char *curr_name = gallery_qfunctions[i].name;
684     for (n = 0; curr_name[n] && curr_name[n] == name[n]; n++) {
685     }
686     if (n > match_len) {
687       match_len   = n;
688       match_index = i;
689     }
690   }
691   CeedCheck(match_len > 0, ceed, CEED_ERROR_UNSUPPORTED, "No suitable gallery CeedQFunction");
692 
693   // Create QFunction
694   CeedCall(CeedQFunctionCreateInterior(ceed, gallery_qfunctions[match_index].vec_length, gallery_qfunctions[match_index].f,
695                                        gallery_qfunctions[match_index].source, qf));
696 
697   // QFunction specific setup
698   CeedCall(gallery_qfunctions[match_index].init(ceed, name, *qf));
699 
700   // Copy name
701   CeedCall(CeedStringAllocCopy(name, (char **)&(*qf)->gallery_name));
702   (*qf)->is_gallery = true;
703   return CEED_ERROR_SUCCESS;
704 }
705 
706 /**
707   @brief Create an identity `CeedQFunction`.
708 
709   Inputs are written into outputs in the order given.
710   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.
711   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.
712 
713   @param[in]  ceed     `Ceed` object used to create the `CeedQFunction`
714   @param[in]  size     Size of the `CeedQFunction` fields
715   @param[in]  in_mode  @ref CeedEvalMode for input to `CeedQFunction`
716   @param[in]  out_mode @ref CeedEvalMode for output to `CeedQFunction`
717   @param[out] qf       Address of the variable where the newly created `CeedQFunction` will be stored
718 
719   @return An error code: 0 - success, otherwise - failure
720 
721   @ref User
722 **/
723 int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode in_mode, CeedEvalMode out_mode, CeedQFunction *qf) {
724   CeedQFunctionContext  ctx;
725   CeedContextFieldLabel size_label;
726 
727   CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Identity", qf));
728   CeedCall(CeedQFunctionAddInput(*qf, "input", size, in_mode));
729   CeedCall(CeedQFunctionAddOutput(*qf, "output", size, out_mode));
730 
731   (*qf)->is_identity = true;
732 
733   CeedCall(CeedQFunctionGetContext(*qf, &ctx));
734   CeedCall(CeedQFunctionContextGetFieldLabel(ctx, "size", &size_label));
735   CeedCall(CeedQFunctionContextSetInt32(ctx, size_label, &size));
736   CeedCall(CeedQFunctionContextDestroy(&ctx));
737   return CEED_ERROR_SUCCESS;
738 }
739 
740 /**
741   @brief Copy the pointer to a `CeedQFunction`.
742 
743   Both pointers should be destroyed with @ref CeedQFunctionDestroy().
744 
745   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`.
746         This `CeedQFunction` will be destroyed if `*qf_copy` is the only reference to this `CeedQFunction`.
747 
748   @param[in]  qf      `CeedQFunction` to copy reference to
749   @param[out] qf_copy Variable to store copied reference
750 
751   @return An error code: 0 - success, otherwise - failure
752 
753   @ref User
754 **/
755 int CeedQFunctionReferenceCopy(CeedQFunction qf, CeedQFunction *qf_copy) {
756   CeedCall(CeedQFunctionReference(qf));
757   CeedCall(CeedQFunctionDestroy(qf_copy));
758   *qf_copy = qf;
759   return CEED_ERROR_SUCCESS;
760 }
761 
762 /**
763   @brief Add a `CeedQFunction` input
764 
765   @param[in,out] qf         `CeedQFunction`
766   @param[in]     field_name Name of `CeedQFunction` field
767   @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.
768   @param[in]     eval_mode  @ref CEED_EVAL_NONE to use values directly,
769                               @ref CEED_EVAL_INTERP to use interpolated values,
770                               @ref CEED_EVAL_GRAD to use gradients,
771                               @ref CEED_EVAL_DIV to use divergence,
772                               @ref CEED_EVAL_CURL to use curl
773 
774   @return An error code: 0 - success, otherwise - failure
775 
776   @ref User
777 **/
778 int CeedQFunctionAddInput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
779   bool is_immutable;
780 
781   CeedCall(CeedQFunctionIsImmutable(qf, &is_immutable));
782   CeedCheck(!is_immutable, CeedQFunctionReturnCeed(qf), CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable");
783   CeedCheck(eval_mode != CEED_EVAL_WEIGHT || size == 1, CeedQFunctionReturnCeed(qf), CEED_ERROR_DIMENSION, "CEED_EVAL_WEIGHT should have size 1");
784   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
785     CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), CeedQFunctionReturnCeed(qf), CEED_ERROR_MINOR,
786               "CeedQFunction field names must be unique. Duplicate name: %s", field_name);
787   }
788   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
789     CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), CeedQFunctionReturnCeed(qf), CEED_ERROR_MINOR,
790               "CeedQFunction field names must be unique. Duplicate name: %s", field_name);
791   }
792   CeedCall(CeedQFunctionFieldSet(&qf->input_fields[qf->num_input_fields], field_name, size, eval_mode));
793   qf->num_input_fields++;
794   return CEED_ERROR_SUCCESS;
795 }
796 
797 /**
798   @brief Add a `CeedQFunction` output
799 
800   @param[in,out] qf         `CeedQFunction`
801   @param[in]     field_name Name of `CeedQFunction` field
802   @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.
803   @param[in]     eval_mode  @ref CEED_EVAL_NONE to use values directly,
804                               @ref CEED_EVAL_INTERP to use interpolated values,
805                               @ref CEED_EVAL_GRAD to use gradients,
806                               @ref CEED_EVAL_DIV to use divergence,
807                               @ref CEED_EVAL_CURL to use curl.
808 
809   @return An error code: 0 - success, otherwise - failure
810 
811   @ref User
812 **/
813 int CeedQFunctionAddOutput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) {
814   bool is_immutable;
815 
816   CeedCall(CeedQFunctionIsImmutable(qf, &is_immutable));
817   CeedCheck(!is_immutable, CeedQFunctionReturnCeed(qf), CEED_ERROR_MAJOR, "CeedQFunction cannot be changed after set as immutable");
818   CeedCheck(eval_mode != CEED_EVAL_WEIGHT, CeedQFunctionReturnCeed(qf), CEED_ERROR_DIMENSION,
819             "Cannot create CeedQFunction output with CEED_EVAL_WEIGHT");
820   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
821     CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), CeedQFunctionReturnCeed(qf), CEED_ERROR_MINOR,
822               "CeedQFunction field names must be unique");
823   }
824   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
825     CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), CeedQFunctionReturnCeed(qf), CEED_ERROR_MINOR,
826               "CeedQFunction field names must be unique");
827   }
828   CeedCall(CeedQFunctionFieldSet(&qf->output_fields[qf->num_output_fields], field_name, size, eval_mode));
829   qf->num_output_fields++;
830   return CEED_ERROR_SUCCESS;
831 }
832 
833 /**
834   @brief Get the `CeedQFunctionField` of a `CeedQFunction`
835 
836   Note: Calling this function asserts that setup is complete and sets the `CeedQFunction` as immutable.
837 
838   @param[in]  qf                `CeedQFunction`
839   @param[out] num_input_fields  Variable to store number of input fields
840   @param[out] input_fields      Variable to store input fields
841   @param[out] num_output_fields Variable to store number of output fields
842   @param[out] output_fields     Variable to store output fields
843 
844   @return An error code: 0 - success, otherwise - failure
845 
846   @ref Advanced
847 **/
848 int CeedQFunctionGetFields(CeedQFunction qf, CeedInt *num_input_fields, CeedQFunctionField **input_fields, CeedInt *num_output_fields,
849                            CeedQFunctionField **output_fields) {
850   CeedCall(CeedQFunctionSetImmutable(qf));
851   if (num_input_fields) *num_input_fields = qf->num_input_fields;
852   if (input_fields) *input_fields = qf->input_fields;
853   if (num_output_fields) *num_output_fields = qf->num_output_fields;
854   if (output_fields) *output_fields = qf->output_fields;
855   return CEED_ERROR_SUCCESS;
856 }
857 
858 /**
859   @brief Get the name of a `CeedQFunctionField`
860 
861   @param[in]  qf_field   `CeedQFunctionField`
862   @param[out] field_name Variable to store the field name
863 
864   @return An error code: 0 - success, otherwise - failure
865 
866   @ref Advanced
867 **/
868 int CeedQFunctionFieldGetName(CeedQFunctionField qf_field, const char **field_name) {
869   *field_name = qf_field->field_name;
870   return CEED_ERROR_SUCCESS;
871 }
872 
873 /**
874   @brief Get the number of components of a `CeedQFunctionField`
875 
876   @param[in]  qf_field `CeedQFunctionField`
877   @param[out] size     Variable to store the size of the field
878 
879   @return An error code: 0 - success, otherwise - failure
880 
881   @ref Advanced
882 **/
883 int CeedQFunctionFieldGetSize(CeedQFunctionField qf_field, CeedInt *size) {
884   *size = qf_field->size;
885   return CEED_ERROR_SUCCESS;
886 }
887 
888 /**
889   @brief Get the @ref CeedEvalMode of a `CeedQFunctionField`
890 
891   @param[in]  qf_field  `CeedQFunctionField`
892   @param[out] eval_mode Variable to store the field evaluation mode
893 
894   @return An error code: 0 - success, otherwise - failure
895 
896   @ref Advanced
897 **/
898 int CeedQFunctionFieldGetEvalMode(CeedQFunctionField qf_field, CeedEvalMode *eval_mode) {
899   *eval_mode = qf_field->eval_mode;
900   return CEED_ERROR_SUCCESS;
901 }
902 
903 /**
904   @brief Get the data of a `CeedQFunctionField`.
905 
906   Any arguments set as `NULL` are ignored.
907 
908   @param[in]  qf_field   `CeedQFunctionField`
909   @param[out] field_name Variable to store the field name
910   @param[out] size       Variable to store the size of the field
911   @param[out] eval_mode  Variable to store the field evaluation mode
912 
913   @return An error code: 0 - success, otherwise - failure
914 
915   @ref Advanced
916 **/
917 int CeedQFunctionFieldGetData(CeedQFunctionField qf_field, const char **field_name, CeedInt *size, CeedEvalMode *eval_mode) {
918   if (field_name) CeedCall(CeedQFunctionFieldGetName(qf_field, field_name));
919   if (size) CeedCall(CeedQFunctionFieldGetSize(qf_field, size));
920   if (eval_mode) CeedCall(CeedQFunctionFieldGetEvalMode(qf_field, eval_mode));
921   return CEED_ERROR_SUCCESS;
922 }
923 
924 /**
925   @brief Set global context for a `CeedQFunction`
926 
927   @param[in,out] qf  `CeedQFunction`
928   @param[in]     ctx Context data to set
929 
930   @return An error code: 0 - success, otherwise - failure
931 
932   @ref User
933 **/
934 int CeedQFunctionSetContext(CeedQFunction qf, CeedQFunctionContext ctx) {
935   CeedCall(CeedQFunctionContextDestroy(&qf->ctx));
936   qf->ctx = ctx;
937   if (ctx) CeedCall(CeedQFunctionContextReference(ctx));
938   return CEED_ERROR_SUCCESS;
939 }
940 
941 /**
942   @brief Set writability of `CeedQFunctionContext` when calling the `CeedQFunctionUser`.
943 
944   The default value is `is_writable == true`.
945 
946   Setting `is_writable == true` indicates the `CeedQFunctionUser` writes into the `CeedQFunctionContext` and requires memory synchronization after calling @ref CeedQFunctionApply().
947 
948   Setting 'is_writable == false' asserts that `CeedQFunctionUser` does not modify the `CeedQFunctionContext`.
949   Violating this assertion may lead to inconsistent data.
950 
951   Setting `is_writable == false` may offer a performance improvement on GPU backends.
952 
953   @param[in,out] qf          `CeedQFunction`
954   @param[in]     is_writable Boolean flag for writability status
955 
956   @return An error code: 0 - success, otherwise - failure
957 
958   @ref User
959 **/
960 int CeedQFunctionSetContextWritable(CeedQFunction qf, bool is_writable) {
961   qf->is_context_writable = is_writable;
962   return CEED_ERROR_SUCCESS;
963 }
964 
965 /**
966   @brief Set estimated number of FLOPs per quadrature required to apply `CeedQFunction`
967 
968   @param[in]  qf    `CeedQFunction` to estimate FLOPs for
969   @param[out] flops FLOPs per quadrature point estimate
970 
971   @ref Backend
972 **/
973 int CeedQFunctionSetUserFlopsEstimate(CeedQFunction qf, CeedSize flops) {
974   CeedCheck(flops >= 0, CeedQFunctionReturnCeed(qf), CEED_ERROR_INCOMPATIBLE, "Must set non-negative FLOPs estimate");
975   qf->user_flop_estimate = flops;
976   return CEED_ERROR_SUCCESS;
977 }
978 
979 /**
980   @brief View a `CeedQFunction`
981 
982   @param[in] qf     `CeedQFunction` to view
983   @param[in] stream Stream to write; typically `stdout` or a file
984 
985   @return Error code: 0 - success, otherwise - failure
986 
987   @ref User
988 **/
989 int CeedQFunctionView(CeedQFunction qf, FILE *stream) {
990   const char *kernel_name;
991 
992   CeedCall(CeedQFunctionGetKernelName(qf, &kernel_name));
993   fprintf(stream, "%sCeedQFunction - %s\n", qf->is_gallery ? "Gallery " : "User ", qf->is_gallery ? qf->gallery_name : kernel_name);
994 
995   fprintf(stream, "  %" CeedInt_FMT " input field%s:\n", qf->num_input_fields, qf->num_input_fields > 1 ? "s" : "");
996   for (CeedInt i = 0; i < qf->num_input_fields; i++) {
997     CeedCall(CeedQFunctionFieldView(qf->input_fields[i], i, 1, stream));
998   }
999 
1000   fprintf(stream, "  %" CeedInt_FMT " output field%s:\n", qf->num_output_fields, qf->num_output_fields > 1 ? "s" : "");
1001   for (CeedInt i = 0; i < qf->num_output_fields; i++) {
1002     CeedCall(CeedQFunctionFieldView(qf->output_fields[i], i, 0, stream));
1003   }
1004   return CEED_ERROR_SUCCESS;
1005 }
1006 
1007 /**
1008   @brief Get the `Ceed` associated with a `CeedQFunction`
1009 
1010   @param[in]  qf   `CeedQFunction`
1011   @param[out] ceed Variable to store`Ceed`
1012 
1013   @return An error code: 0 - success, otherwise - failure
1014 
1015   @ref Advanced
1016 **/
1017 int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) {
1018   *ceed = NULL;
1019   CeedCall(CeedReferenceCopy(CeedQFunctionReturnCeed(qf), ceed));
1020   return CEED_ERROR_SUCCESS;
1021 }
1022 
1023 /**
1024   @brief Return the `Ceed` associated with a `CeedQFunction`
1025 
1026   @param[in]  qf   `CeedQFunction`
1027 
1028   @return `Ceed` associated with the `qf`
1029 
1030   @ref Advanced
1031 **/
1032 Ceed CeedQFunctionReturnCeed(CeedQFunction qf) { return qf->ceed; }
1033 
1034 /**
1035   @brief Apply the action of a `CeedQFunction`
1036 
1037   Note: Calling this function asserts that setup is complete and sets the `CeedQFunction` as immutable.
1038 
1039   @param[in]  qf `CeedQFunction`
1040   @param[in]  Q  Number of quadrature points
1041   @param[in]  u  Array of input `CeedVector`
1042   @param[out] v  Array of output `CeedVector`
1043 
1044   @return An error code: 0 - success, otherwise - failure
1045 
1046   @ref User
1047 **/
1048 int CeedQFunctionApply(CeedQFunction qf, CeedInt Q, CeedVector *u, CeedVector *v) {
1049   CeedInt vec_length;
1050 
1051   CeedCheck(qf->Apply, CeedQFunctionReturnCeed(qf), CEED_ERROR_UNSUPPORTED, "Backend does not support CeedQFunctionApply");
1052   CeedCall(CeedQFunctionGetVectorLength(qf, &vec_length));
1053   CeedCheck(Q % vec_length == 0, CeedQFunctionReturnCeed(qf), CEED_ERROR_DIMENSION,
1054             "Number of quadrature points %" CeedInt_FMT " must be a multiple of %" CeedInt_FMT, Q, qf->vec_length);
1055   CeedCall(CeedQFunctionSetImmutable(qf));
1056   CeedCall(qf->Apply(qf, Q, u, v));
1057   return CEED_ERROR_SUCCESS;
1058 }
1059 
1060 /**
1061   @brief Destroy a `CeedQFunction`
1062 
1063   @param[in,out] qf `CeedQFunction` to destroy
1064 
1065   @return An error code: 0 - success, otherwise - failure
1066 
1067   @ref User
1068 **/
1069 int CeedQFunctionDestroy(CeedQFunction *qf) {
1070   if (!*qf || --(*qf)->ref_count > 0) {
1071     *qf = NULL;
1072     return CEED_ERROR_SUCCESS;
1073   }
1074   // Backend destroy
1075   if ((*qf)->Destroy) {
1076     CeedCall((*qf)->Destroy(*qf));
1077   }
1078   // Free fields
1079   for (CeedInt i = 0; i < (*qf)->num_input_fields; i++) {
1080     CeedCall(CeedFree(&(*(*qf)->input_fields[i]).field_name));
1081     CeedCall(CeedFree(&(*qf)->input_fields[i]));
1082   }
1083   for (CeedInt i = 0; i < (*qf)->num_output_fields; i++) {
1084     CeedCall(CeedFree(&(*(*qf)->output_fields[i]).field_name));
1085     CeedCall(CeedFree(&(*qf)->output_fields[i]));
1086   }
1087   CeedCall(CeedFree(&(*qf)->input_fields));
1088   CeedCall(CeedFree(&(*qf)->output_fields));
1089 
1090   // User context data object
1091   CeedCall(CeedQFunctionContextDestroy(&(*qf)->ctx));
1092 
1093   CeedCall(CeedFree(&(*qf)->user_source));
1094   CeedCall(CeedFree(&(*qf)->source_path));
1095   CeedCall(CeedFree(&(*qf)->gallery_name));
1096   CeedCall(CeedFree(&(*qf)->kernel_name));
1097   CeedCall(CeedDestroy(&(*qf)->ceed));
1098   CeedCall(CeedFree(qf));
1099   return CEED_ERROR_SUCCESS;
1100 }
1101 
1102 /// @}
1103