xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-qfunction.c (revision 8c84ac63b73c26a63e4a9f04c3bfdd0e3f8b3b9f)
1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3 // reserved. See files LICENSE and NOTICE for details.
4 //
5 // This file is part of CEED, a collection of benchmarks, miniapps, software
6 // libraries and APIs for efficient high-order finite element and spectral
7 // element discretizations for exascale applications. For more information and
8 // source code availability see http://github.com/ceed.
9 //
10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11 // a collaborative effort of two U.S. Department of Energy organizations (Office
12 // of Science and the National Nuclear Security Administration) responsible for
13 // the planning and preparation of a capable exascale ecosystem, including
14 // software, applications, hardware, advanced system engineering and early
15 // testbed platforms, in support of the nation's exascale computing imperative.
16 
17 #include <ceed-impl.h>
18 #include <ceed-backend.h>
19 #include <string.h>
20 #include <limits.h>
21 #ifdef CEED_CUDA_ENABLED
22 #  include <ceed-cuda.h>
23 #endif
24 #ifdef CEED_HIP_ENABLED
25 #  include <ceed-hip.h>
26 #endif
27 
28 /// @file
29 /// Implementation of public CeedQFunction interfaces
30 
31 /// @cond DOXYGEN_SKIP
32 static struct CeedQFunction_private ceed_qfunction_none;
33 /// @endcond
34 
35 /// @addtogroup CeedQFunctionUser
36 /// @{
37 
38 // Indicate that no QFunction is provided by the user
39 const CeedQFunction CEED_QFUNCTION_NONE = &ceed_qfunction_none;
40 
41 /// @}
42 
43 /// @cond DOXYGEN_SKIP
44 static struct {
45   char name[CEED_MAX_RESOURCE_LEN];
46   char source[CEED_MAX_RESOURCE_LEN];
47   CeedInt vlength;
48   CeedQFunctionUser f;
49   int (*init)(Ceed ceed, const char *name, CeedQFunction qf);
50 } qfunctions[1024];
51 static size_t num_qfunctions;
52 /// @endcond
53 
54 /// ----------------------------------------------------------------------------
55 /// CeedQFunction Library Internal Functions
56 /// ----------------------------------------------------------------------------
57 /// @addtogroup CeedQFunctionDeveloper
58 /// @{
59 
60 /**
61   @brief Register a gallery QFunction
62 
63   @param name     Name for this backend to respond to
64   @param source   Absolute path to source of QFunction,
65                     "\path\CEED_DIR\gallery\folder\file.h:function_name"
66   @param vlength  Vector length.  Caller must ensure that number of quadrature
67                     points is a multiple of vlength.
68   @param f        Function pointer to evaluate action at quadrature points.
69                     See \ref CeedQFunctionUser.
70   @param init     Initialization function called by CeedQFunctionInit() when the
71                     QFunction is selected.
72 
73   @return An error code: 0 - success, otherwise - failure
74 
75   @ref Developer
76 **/
77 int CeedQFunctionRegister(const char *name, const char *source,
78                           CeedInt vlength, CeedQFunctionUser f,
79                           int (*init)(Ceed, const char *, CeedQFunction)) {
80   if (num_qfunctions >= sizeof(qfunctions) / sizeof(qfunctions[0]))
81     // LCOV_EXCL_START
82     return CeedError(NULL, 1, "Too many gallery QFunctions");
83   // LCOV_EXCL_STOP
84 
85   strncpy(qfunctions[num_qfunctions].name, name, CEED_MAX_RESOURCE_LEN);
86   qfunctions[num_qfunctions].name[CEED_MAX_RESOURCE_LEN-1] = 0;
87   strncpy(qfunctions[num_qfunctions].source, source, CEED_MAX_RESOURCE_LEN);
88   qfunctions[num_qfunctions].source[CEED_MAX_RESOURCE_LEN-1] = 0;
89   qfunctions[num_qfunctions].vlength = vlength;
90   qfunctions[num_qfunctions].f = f;
91   qfunctions[num_qfunctions].init = init;
92   num_qfunctions++;
93   return 0;
94 }
95 
96 /**
97   @brief Set a CeedQFunction field, used by CeedQFunctionAddInput/Output
98 
99   @param f          CeedQFunctionField
100   @param fieldname  Name of QFunction field
101   @param size       Size of QFunction field, (ncomp * dim) for @ref CEED_EVAL_GRAD or
102                       (ncomp * 1) for @ref CEED_EVAL_NONE, @ref CEED_EVAL_INTERP, and @ref CEED_EVAL_WEIGHT
103   @param emode      \ref CEED_EVAL_NONE to use values directly,
104                       \ref CEED_EVAL_INTERP to use interpolated values,
105                       \ref CEED_EVAL_GRAD to use gradients,
106                       \ref CEED_EVAL_WEIGHT to use quadrature weights.
107 
108   @return An error code: 0 - success, otherwise - failure
109 
110   @ref Developer
111 **/
112 static int CeedQFunctionFieldSet(CeedQFunctionField *f,const char *fieldname,
113                                  CeedInt size, CeedEvalMode emode) {
114   size_t len = strlen(fieldname);
115   char *tmp;
116   int ierr;
117   ierr = CeedCalloc(1,f); CeedChk(ierr);
118 
119   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
120   memcpy(tmp, fieldname, len+1);
121   (*f)->fieldname = tmp;
122   (*f)->size = size;
123   (*f)->emode = emode;
124   return 0;
125 }
126 
127 /**
128   @brief View a field of a CeedQFunction
129 
130   @param[in] field        QFunction field to view
131   @param[in] fieldnumber  Number of field being viewed
132   @param[in] in           true for input field, false for output
133   @param[in] stream       Stream to view to, e.g., stdout
134 
135   @return An error code: 0 - success, otherwise - failure
136 
137   @ref Utility
138 **/
139 static int CeedQFunctionFieldView(CeedQFunctionField field, CeedInt fieldnumber,
140                                   bool in, FILE *stream) {
141   const char *inout = in ? "Input" : "Output";
142   fprintf(stream, "    %s Field [%d]:\n"
143           "      Name: \"%s\"\n"
144           "      Size: %d\n"
145           "      EvalMode: \"%s\"\n",
146           inout, fieldnumber, field->fieldname, field->size,
147           CeedEvalModes[field->emode]);
148 
149   return 0;
150 }
151 
152 
153 /**
154   @brief Set flag to determine if Fortran interface is used
155 
156   @param qf                  CeedQFunction
157   @param status              Boolean value to set as Fortran status
158 
159   @return An error code: 0 - success, otherwise - failure
160 
161   @ref Backend
162 **/
163 int CeedQFunctionSetFortranStatus(CeedQFunction qf, bool status) {
164   qf->fortranstatus = status;
165   return 0;
166 }
167 
168 /// @}
169 
170 /// ----------------------------------------------------------------------------
171 /// CeedQFunction Backend API
172 /// ----------------------------------------------------------------------------
173 /// @addtogroup CeedQFunctionBackend
174 /// @{
175 
176 /**
177   @brief Get the Ceed associated with a CeedQFunction
178 
179   @param qf              CeedQFunction
180   @param[out] ceed       Variable to store Ceed
181 
182   @return An error code: 0 - success, otherwise - failure
183 
184   @ref Backend
185 **/
186 int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) {
187   *ceed = qf->ceed;
188   return 0;
189 }
190 
191 /**
192   @brief Get the vector length of a CeedQFunction
193 
194   @param qf            CeedQFunction
195   @param[out] vlength  Variable to store vector length
196 
197   @return An error code: 0 - success, otherwise - failure
198 
199   @ref Backend
200 **/
201 int CeedQFunctionGetVectorLength(CeedQFunction qf, CeedInt *vlength) {
202   *vlength = qf->vlength;
203   return 0;
204 }
205 
206 /**
207   @brief Get the number of inputs and outputs to a CeedQFunction
208 
209   @param qf              CeedQFunction
210   @param[out] numinput   Variable to store number of input fields
211   @param[out] numoutput  Variable to store number of output fields
212 
213   @return An error code: 0 - success, otherwise - failure
214 
215   @ref Backend
216 **/
217 int CeedQFunctionGetNumArgs(CeedQFunction qf, CeedInt *numinput,
218                             CeedInt *numoutput) {
219   if (numinput) *numinput = qf->numinputfields;
220   if (numoutput) *numoutput = qf->numoutputfields;
221   return 0;
222 }
223 
224 /**
225   @brief Get the source path string for a CeedQFunction
226 
227   @param qf              CeedQFunction
228   @param[out] source     Variable to store source path string
229 
230   @return An error code: 0 - success, otherwise - failure
231 
232   @ref Backend
233 **/
234 int CeedQFunctionGetSourcePath(CeedQFunction qf, char **source) {
235   *source = (char *) qf->sourcepath;
236   return 0;
237 }
238 
239 /**
240   @brief Get the User Function for a CeedQFunction
241 
242   @param qf              CeedQFunction
243   @param[out] f          Variable to store user function
244 
245   @return An error code: 0 - success, otherwise - failure
246 
247   @ref Backend
248 **/
249 int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) {
250   *f = qf->function;
251   return 0;
252 }
253 
254 /**
255   @brief Get global context for a CeedQFunction.
256          Note: For QFunctions from the Fortran interface, this
257                function will return the Fortran context
258                CeedQFunctionContext.
259 
260   @param qf              CeedQFunction
261   @param[out] ctx        Variable to store CeedQFunctionContext
262 
263   @return An error code: 0 - success, otherwise - failure
264 
265   @ref Backend
266 **/
267 int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
268   *ctx = qf->ctx;
269   return 0;
270 }
271 
272 /**
273   @brief Get true user context for a CeedQFunction
274          Note: For all QFunctions this function will return the user
275                CeedQFunctionContext and not interface context
276                CeedQFunctionContext, if any such object exists.
277 
278   @param qf              CeedQFunction
279   @param[out] ctx        Variable to store CeedQFunctionContext
280 
281   @return An error code: 0 - success, otherwise - failure
282   @ref Backend
283 **/
284 int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) {
285   int ierr;
286   if (qf->fortranstatus) {
287     CeedFortranContext fctx = NULL;
288     ierr = CeedQFunctionContextGetData(qf->ctx, CEED_MEM_HOST, &fctx);
289     CeedChk(ierr);
290     *ctx = fctx->innerctx;
291     ierr = CeedQFunctionContextRestoreData(qf->ctx, (void *)&fctx); CeedChk(ierr);
292   } else {
293     *ctx = qf->ctx;
294   }
295 
296 
297   return 0;
298 }
299 
300 /**
301   @brief Determine if QFunction is identity
302 
303   @param qf               CeedQFunction
304   @param[out] isidentity  Variable to store identity status
305 
306   @return An error code: 0 - success, otherwise - failure
307 
308   @ref Backend
309 **/
310 int CeedQFunctionIsIdentity(CeedQFunction qf, bool *isidentity) {
311   *isidentity = qf->identity;
312   return 0;
313 }
314 
315 /**
316   @brief Get backend data of a CeedQFunction
317 
318   @param qf              CeedQFunction
319   @param[out] data       Variable to store data
320 
321   @return An error code: 0 - success, otherwise - failure
322 
323   @ref Backend
324 **/
325 int CeedQFunctionGetData(CeedQFunction qf, void *data) {
326   *(void **)data = qf->data;
327   return 0;
328 }
329 
330 /**
331   @brief Set backend data of a CeedQFunction
332 
333   @param[out] qf         CeedQFunction
334   @param data            Data to set
335 
336   @return An error code: 0 - success, otherwise - failure
337 
338   @ref Backend
339 **/
340 int CeedQFunctionSetData(CeedQFunction qf, void *data) {
341   qf->data = data;
342   return 0;
343 }
344 
345 /**
346   @brief Get the CeedQFunctionFields of a CeedQFunction
347 
348   @param qf                 CeedQFunction
349   @param[out] inputfields   Variable to store inputfields
350   @param[out] outputfields  Variable to store outputfields
351 
352   @return An error code: 0 - success, otherwise - failure
353 
354   @ref Backend
355 **/
356 int CeedQFunctionGetFields(CeedQFunction qf, CeedQFunctionField **inputfields,
357                            CeedQFunctionField **outputfields) {
358   if (inputfields)
359     *inputfields = qf->inputfields;
360   if (outputfields)
361     *outputfields = qf->outputfields;
362   return 0;
363 }
364 
365 /**
366   @brief Get the name of a CeedQFunctionField
367 
368   @param qffield         CeedQFunctionField
369   @param[out] fieldname  Variable to store the field name
370 
371   @return An error code: 0 - success, otherwise - failure
372 
373   @ref Backend
374 **/
375 int CeedQFunctionFieldGetName(CeedQFunctionField qffield, char **fieldname) {
376   *fieldname = (char *)qffield->fieldname;
377   return 0;
378 }
379 
380 /**
381   @brief Get the number of components of a CeedQFunctionField
382 
383   @param qffield    CeedQFunctionField
384   @param[out] size  Variable to store the size of the field
385 
386   @return An error code: 0 - success, otherwise - failure
387 
388   @ref Backend
389 **/
390 int CeedQFunctionFieldGetSize(CeedQFunctionField qffield, CeedInt *size) {
391   *size = qffield->size;
392   return 0;
393 }
394 
395 /**
396   @brief Get the CeedEvalMode of a CeedQFunctionField
397 
398   @param qffield         CeedQFunctionField
399   @param[out] emode      Variable to store the field evaluation mode
400 
401   @return An error code: 0 - success, otherwise - failure
402 
403   @ref Backend
404 **/
405 int CeedQFunctionFieldGetEvalMode(CeedQFunctionField qffield,
406                                   CeedEvalMode *emode) {
407   *emode = qffield->emode;
408   return 0;
409 }
410 
411 /// @}
412 
413 /// ----------------------------------------------------------------------------
414 /// CeedQFunction Public API
415 /// ----------------------------------------------------------------------------
416 /// @addtogroup CeedQFunctionUser
417 /// @{
418 
419 /**
420   @brief Create a CeedQFunction for evaluating interior (volumetric) terms.
421 
422   @param ceed       A Ceed object where the CeedQFunction will be created
423   @param vlength    Vector length. Caller must ensure that number of quadrature
424                       points is a multiple of vlength.
425   @param f          Function pointer to evaluate action at quadrature points.
426                       See \ref CeedQFunctionUser.
427   @param source     Absolute path to source of QFunction,
428                       "\abs_path\file.h:function_name".
429                       For support across all backends, this source must only
430                       contain constructs supported by C99, C++11, and CUDA.
431   @param[out] qf    Address of the variable where the newly created
432                       CeedQFunction will be stored
433 
434   @return An error code: 0 - success, otherwise - failure
435 
436   See \ref CeedQFunctionUser for details on the call-back function @a f's
437     arguments.
438 
439   @ref User
440 **/
441 int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vlength, CeedQFunctionUser f,
442                                 const char *source, CeedQFunction *qf) {
443   int ierr;
444   char *source_copy;
445 
446   if (!ceed->QFunctionCreate) {
447     Ceed delegate;
448     ierr = CeedGetObjectDelegate(ceed, &delegate, "QFunction"); CeedChk(ierr);
449 
450     if (!delegate)
451       // LCOV_EXCL_START
452       return CeedError(ceed, 1, "Backend does not support QFunctionCreate");
453     // LCOV_EXCL_STOP
454 
455     ierr = CeedQFunctionCreateInterior(delegate, vlength, f, source, qf);
456     CeedChk(ierr);
457     return 0;
458   }
459 
460   ierr = CeedCalloc(1, qf); CeedChk(ierr);
461   (*qf)->ceed = ceed;
462   ceed->refcount++;
463   (*qf)->refcount = 1;
464   (*qf)->vlength = vlength;
465   (*qf)->identity = 0;
466   (*qf)->function = f;
467   size_t slen = strlen(source) + 1;
468   ierr = CeedMalloc(slen, &source_copy); CeedChk(ierr);
469   memcpy(source_copy, source, slen);
470   (*qf)->sourcepath = source_copy;
471   ierr = CeedCalloc(16, &(*qf)->inputfields); CeedChk(ierr);
472   ierr = CeedCalloc(16, &(*qf)->outputfields); CeedChk(ierr);
473   ierr = ceed->QFunctionCreate(*qf); CeedChk(ierr);
474   return 0;
475 }
476 
477 /**
478   @brief Create a CeedQFunction for evaluating interior (volumetric) terms by name.
479 
480   @param ceed       A Ceed object where the CeedQFunction will be created
481   @param name       Name of QFunction to use from gallery
482   @param[out] qf    Address of the variable where the newly created
483                       CeedQFunction will be stored
484 
485   @return An error code: 0 - success, otherwise - failure
486 
487   @ref User
488 **/
489 int CeedQFunctionCreateInteriorByName(Ceed ceed,  const char *name,
490                                       CeedQFunction *qf) {
491   int ierr;
492   size_t matchlen = 0, matchidx = UINT_MAX;
493   char *name_copy;
494 
495   // Find matching backend
496   if (!name) return CeedError(NULL, 1, "No QFunction name provided");
497   for (size_t i=0; i<num_qfunctions; i++) {
498     size_t n;
499     const char *currname = qfunctions[i].name;
500     for (n = 0; currname[n] && currname[n] == name[n]; n++) {}
501     if (n > matchlen) {
502       matchlen = n;
503       matchidx = i;
504     }
505   }
506   if (!matchlen)
507     // LCOV_EXCL_START
508     return CeedError(NULL, 1, "No suitable gallery QFunction");
509   // LCOV_EXCL_STOP
510 
511   // Create QFunction
512   ierr = CeedQFunctionCreateInterior(ceed, qfunctions[matchidx].vlength,
513                                      qfunctions[matchidx].f,
514                                      qfunctions[matchidx].source, qf);
515   CeedChk(ierr);
516 
517   // QFunction specific setup
518   ierr = qfunctions[matchidx].init(ceed, name, *qf); CeedChk(ierr);
519 
520   // Copy name
521   size_t slen = strlen(name) + 1;
522   ierr = CeedMalloc(slen, &name_copy); CeedChk(ierr);
523   memcpy(name_copy, name, slen);
524   (*qf)->qfname = name_copy;
525 
526   return 0;
527 }
528 
529 /**
530   @brief Create an identity CeedQFunction. Inputs are written into outputs in
531            the order given. This is useful for CeedOperators that can be
532            represented with only the action of a CeedRestriction and CeedBasis,
533            such as restriction and prolongation operators for p-multigrid.
534            Backends may optimize CeedOperators with this CeedQFunction to avoid
535            the copy of input data to output fields by using the same memory
536            location for both.
537 
538   @param ceed         A Ceed object where the CeedQFunction will be created
539   @param[in] size     Size of the qfunction fields
540   @param[in] inmode   CeedEvalMode for input to CeedQFunction
541   @param[in] outmode  CeedEvalMode for output to CeedQFunction
542   @param[out] qf      Address of the variable where the newly created
543                         CeedQFunction will be stored
544 
545   @return An error code: 0 - success, otherwise - failure
546 
547   @ref User
548 **/
549 int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode inmode,
550                                 CeedEvalMode outmode, CeedQFunction *qf) {
551   int ierr;
552 
553   if (inmode == CEED_EVAL_NONE && outmode == CEED_EVAL_NONE)
554     // LCOV_EXCL_START
555     return CeedError(ceed, 1, "CEED_EVAL_NONE for a both the input and "
556                      "output does not make sense with an identity QFunction");
557   // LCOV_EXCL_STOP
558 
559   ierr = CeedQFunctionCreateInteriorByName(ceed, "Identity", qf); CeedChk(ierr);
560   ierr = CeedQFunctionAddInput(*qf, "input", size, inmode); CeedChk(ierr);
561   ierr = CeedQFunctionAddOutput(*qf, "output", size, outmode); CeedChk(ierr);
562 
563   (*qf)->identity = 1;
564   CeedInt *sizeData;
565   ierr = CeedCalloc(1, &sizeData); CeedChk(ierr);
566   sizeData[0] = size;
567   CeedQFunctionContext ctx;
568   ierr = CeedQFunctionContextCreate(ceed, &ctx); CeedChk(ierr);
569   ierr = CeedQFunctionContextSetData(ctx, CEED_MEM_HOST, CEED_OWN_POINTER,
570                                      sizeof(*sizeData), (void *)sizeData);
571   CeedChk(ierr);
572   ierr = CeedQFunctionSetContext(*qf, ctx); CeedChk(ierr);
573   ierr = CeedQFunctionContextDestroy(&ctx); CeedChk(ierr);
574 
575   return 0;
576 }
577 
578 /**
579   @brief Add a CeedQFunction input
580 
581   @param qf         CeedQFunction
582   @param fieldname  Name of QFunction field
583   @param size       Size of QFunction field, (ncomp * dim) for @ref CEED_EVAL_GRAD or
584                       (ncomp * 1) for @ref CEED_EVAL_NONE and @ref CEED_EVAL_INTERP
585   @param emode      \ref CEED_EVAL_NONE to use values directly,
586                       \ref CEED_EVAL_INTERP to use interpolated values,
587                       \ref CEED_EVAL_GRAD to use gradients.
588 
589   @return An error code: 0 - success, otherwise - failure
590 
591   @ref User
592 **/
593 int CeedQFunctionAddInput(CeedQFunction qf, const char *fieldname, CeedInt size,
594                           CeedEvalMode emode) {
595   int ierr = CeedQFunctionFieldSet(&qf->inputfields[qf->numinputfields],
596                                    fieldname, size, emode);
597   CeedChk(ierr);
598   qf->numinputfields++;
599   return 0;
600 }
601 
602 /**
603   @brief Add a CeedQFunction output
604 
605   @param qf         CeedQFunction
606   @param fieldname  Name of QFunction field
607   @param size       Size of QFunction field, (ncomp * dim) for @ref CEED_EVAL_GRAD or
608                       (ncomp * 1) for @ref CEED_EVAL_NONE and @ref CEED_EVAL_INTERP
609   @param emode      \ref CEED_EVAL_NONE to use values directly,
610                       \ref CEED_EVAL_INTERP to use interpolated values,
611                       \ref CEED_EVAL_GRAD to use gradients.
612 
613   @return An error code: 0 - success, otherwise - failure
614 
615   @ref User
616 **/
617 int CeedQFunctionAddOutput(CeedQFunction qf, const char *fieldname,
618                            CeedInt size, CeedEvalMode emode) {
619   if (emode == CEED_EVAL_WEIGHT)
620     // LCOV_EXCL_START
621     return CeedError(qf->ceed, 1, "Cannot create QFunction output with "
622                      "CEED_EVAL_WEIGHT");
623   // LCOV_EXCL_STOP
624   int ierr = CeedQFunctionFieldSet(&qf->outputfields[qf->numoutputfields],
625                                    fieldname, size, emode);
626   CeedChk(ierr);
627   qf->numoutputfields++;
628   return 0;
629 }
630 
631 #ifdef CEED_CUDA_ENABLED
632 /**
633   @brief Set CUDA function pointer to evaluate action at quadrature points
634 
635   @param qf CeedQFunction to set device pointer
636   @param f  Device function pointer to evaluate action at quadrature points
637 
638   @return An error code: 0 - success, otherwise - failure
639 
640   @ref User
641 **/
642 int CeedQFunctionSetCUDAUserFunction(CeedQFunction qf, CUfunction f) {
643   int ierr;
644   if (!qf->SetCUDAUserFunction) {
645     Ceed ceed;
646     ierr = CeedQFunctionGetCeed(qf, &ceed); CeedChk(ierr);
647     CeedDebug("Backend does not support CUfunction pointers for QFunctions.");
648   } else {
649     ierr = qf->SetCUDAUserFunction(qf, f); CeedChk(ierr);
650   }
651   return 0;
652 }
653 #endif
654 
655 #ifdef CEED_HIP_ENABLED
656 /**
657   @brief Set HIP function pointer to evaluate action at quadrature points
658 
659   @param qf CeedQFunction to set device pointer
660   @param f  Device function pointer to evaluate action at quadrature points
661 
662   @return An error code: 0 - success, otherwise - failure
663 
664   @ref User
665 **/
666 int CeedQFunctionSetHIPUserFunction(CeedQFunction qf, hipFunction_t f) {
667   int ierr;
668   if (!qf->SetHIPUserFunction) {
669     Ceed ceed;
670     ierr = CeedQFunctionGetCeed(qf, &ceed); CeedChk(ierr);
671     CeedDebug("Backend does not support hipFunction_t pointers for QFunctions.");
672   } else {
673     ierr = qf->SetHIPUserFunction(qf, f); CeedChk(ierr);
674   }
675   return 0;
676 }
677 #endif
678 
679 /**
680   @brief Set global context for a CeedQFunction
681 
682   @param qf       CeedQFunction
683   @param ctx      Context data to set
684 
685   @return An error code: 0 - success, otherwise - failure
686 
687   @ref User
688 **/
689 int CeedQFunctionSetContext(CeedQFunction qf, CeedQFunctionContext ctx) {
690   qf->ctx = ctx;
691   ctx->refcount++;
692   return 0;
693 }
694 
695 /**
696   @brief View a CeedQFunction
697 
698   @param[in] qf      CeedQFunction to view
699   @param[in] stream  Stream to write; typically stdout/stderr or a file
700 
701   @return Error code: 0 - success, otherwise - failure
702 
703   @ref User
704 **/
705 int CeedQFunctionView(CeedQFunction qf, FILE *stream) {
706   int ierr;
707 
708   fprintf(stream, "%sCeedQFunction %s\n",
709           qf->qfname ? "Gallery " : "User ", qf->qfname ? qf->qfname : "");
710 
711   fprintf(stream, "  %d Input Field%s:\n", qf->numinputfields,
712           qf->numinputfields>1 ? "s" : "");
713   for (CeedInt i=0; i<qf->numinputfields; i++) {
714     ierr = CeedQFunctionFieldView(qf->inputfields[i], i, 1, stream);
715     CeedChk(ierr);
716   }
717 
718   fprintf(stream, "  %d Output Field%s:\n", qf->numoutputfields,
719           qf->numoutputfields>1 ? "s" : "");
720   for (CeedInt i=0; i<qf->numoutputfields; i++) {
721     ierr = CeedQFunctionFieldView(qf->outputfields[i], i, 0, stream);
722     CeedChk(ierr);
723   }
724   return 0;
725 }
726 
727 /**
728   @brief Apply the action of a CeedQFunction
729 
730   @param qf      CeedQFunction
731   @param Q       Number of quadrature points
732   @param[in] u   Array of input CeedVectors
733   @param[out] v  Array of output CeedVectors
734 
735   @return An error code: 0 - success, otherwise - failure
736 
737   @ref User
738 **/
739 int CeedQFunctionApply(CeedQFunction qf, CeedInt Q,
740                        CeedVector *u, CeedVector *v) {
741   int ierr;
742   if (!qf->Apply)
743     // LCOV_EXCL_START
744     return CeedError(qf->ceed, 1, "Backend does not support QFunctionApply");
745   // LCOV_EXCL_STOP
746   if (Q % qf->vlength)
747     // LCOV_EXCL_START
748     return CeedError(qf->ceed, 2, "Number of quadrature points %d must be a "
749                      "multiple of %d", Q, qf->vlength);
750   // LCOV_EXCL_STOP
751   ierr = qf->Apply(qf, Q, u, v); CeedChk(ierr);
752   return 0;
753 }
754 
755 /**
756   @brief Destroy a CeedQFunction
757 
758   @param qf CeedQFunction to destroy
759 
760   @return An error code: 0 - success, otherwise - failure
761 
762   @ref User
763 **/
764 int CeedQFunctionDestroy(CeedQFunction *qf) {
765   int ierr;
766 
767   if (!*qf || --(*qf)->refcount > 0) return 0;
768   // Backend destroy
769   if ((*qf)->Destroy) {
770     ierr = (*qf)->Destroy(*qf); CeedChk(ierr);
771   }
772   // Free fields
773   for (int i=0; i<(*qf)->numinputfields; i++) {
774     ierr = CeedFree(&(*(*qf)->inputfields[i]).fieldname); CeedChk(ierr);
775     ierr = CeedFree(&(*qf)->inputfields[i]); CeedChk(ierr);
776   }
777   for (int i=0; i<(*qf)->numoutputfields; i++) {
778     ierr = CeedFree(&(*(*qf)->outputfields[i]).fieldname); CeedChk(ierr);
779     ierr = CeedFree(&(*qf)->outputfields[i]); CeedChk(ierr);
780   }
781   ierr = CeedFree(&(*qf)->inputfields); CeedChk(ierr);
782   ierr = CeedFree(&(*qf)->outputfields); CeedChk(ierr);
783 
784   // User context data object
785   ierr = CeedQFunctionContextDestroy(&(*qf)->ctx); CeedChk(ierr);
786 
787   ierr = CeedFree(&(*qf)->sourcepath); CeedChk(ierr);
788   ierr = CeedFree(&(*qf)->qfname); CeedChk(ierr);
789   ierr = CeedDestroy(&(*qf)->ceed); CeedChk(ierr);
790   ierr = CeedFree(qf); CeedChk(ierr);
791   return 0;
792 }
793 
794 /// @}
795