xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-qfunctioncontext.c (revision cdf32b9369b06315737c6f9df3317771bd8e77c7)
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/ceed.h>
18 #include <ceed/backend.h>
19 #include <ceed-impl.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 /// @file
25 /// Implementation of public CeedQFunctionContext interfaces
26 
27 /// ----------------------------------------------------------------------------
28 /// CeedQFunctionContext Library Internal Functions
29 /// ----------------------------------------------------------------------------
30 /// @addtogroup CeedQFunctionDeveloper
31 /// @{
32 
33 /**
34   @brief Get index for QFunctionContext field
35 
36   @param ctx         CeedQFunctionContext
37   @param field_name  Name of field
38   @param field_index Index of field, or -1 if field is not registered
39 
40   @return An error code: 0 - success, otherwise - failure
41 
42   @ref Developer
43 **/
44 int CeedQFunctionContextGetFieldIndex(CeedQFunctionContext ctx,
45                                       const char *field_name, CeedInt *field_index) {
46   *field_index = -1;
47   for (CeedInt i=0; i<ctx->num_fields; i++)
48     if (!strcmp(ctx->field_descriptions[i].name, field_name))
49       *field_index = i;
50   return CEED_ERROR_SUCCESS;
51 }
52 
53 /**
54   @brief Common function for registering QFunctionContext fields
55 
56   @param ctx               CeedQFunctionContext
57   @param field_name        Name of field to register
58   @param field_offset      Offset of field to register
59   @param field_description Description of field, or NULL for none
60   @param field_type        Field data type, such as double or int32
61   @param field_size        Size of field, in bytes
62 
63   @return An error code: 0 - success, otherwise - failure
64 
65   @ref Developer
66 **/
67 int CeedQFunctionContextRegisterGeneric(CeedQFunctionContext ctx,
68                                         const char *field_name, size_t field_offset,
69                                         const char *field_description,
70                                         CeedContextFieldType field_type,
71                                         size_t field_size) {
72   int ierr;
73 
74   // Check for duplicate
75   CeedInt field_index = -1;
76   ierr = CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index);
77   CeedChk(ierr);
78   if (field_index != -1)
79     // LCOV_EXCL_START
80     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
81                      "QFunctionContext field with name \"%s\" already registered",
82                      field_name);
83   // LCOV_EXCL_STOP
84 
85   // Allocate space for field data
86   if (ctx->num_fields == 0) {
87     ierr = CeedCalloc(1, &ctx->field_descriptions); CeedChk(ierr);
88     ctx->max_fields = 1;
89   } else if (ctx->num_fields == ctx->max_fields) {
90     ierr = CeedRealloc(2*ctx->max_fields, &ctx->field_descriptions);
91     CeedChk(ierr);
92     ctx->max_fields *= 2;
93   }
94 
95   // Copy field data
96   {
97     size_t len = strlen(field_name);
98     char *tmp;
99     ierr = CeedCalloc(len + 1, &tmp); CeedChk(ierr);
100     memcpy(tmp, field_name, len+1);
101     ctx->field_descriptions[ctx->num_fields].name = tmp;
102   }
103   {
104     size_t len = strlen(field_description);
105     char *tmp;
106     ierr = CeedCalloc(len + 1, &tmp); CeedChk(ierr);
107     memcpy(tmp, field_description, len+1);
108     ctx->field_descriptions[ctx->num_fields].description = tmp;
109   }
110   ctx->field_descriptions[ctx->num_fields].type = field_type;
111   ctx->field_descriptions[ctx->num_fields].offset = field_offset;
112   ctx->field_descriptions[ctx->num_fields].size = field_size;
113   ctx->num_fields++;
114 
115   return CEED_ERROR_SUCCESS;
116 }
117 
118 /**
119   @brief Set QFunctionContext field holding a double precision value
120 
121   @param ctx        CeedQFunctionContext
122   @param field_name Name of field to set
123   @param field_type Type of field to set
124   @param value      Value to set
125 
126   @return An error code: 0 - success, otherwise - failure
127 
128   @ref User
129 **/
130 int CeedQFunctionContextSetGeneric(CeedQFunctionContext ctx,
131                                    const char *field_name,
132                                    CeedContextFieldType field_type, void *value) {
133   int ierr;
134 
135   // Check field index
136   CeedInt field_index = -1;
137   ierr = CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index);
138   CeedChk(ierr);
139   if (field_index == -1)
140     // LCOV_EXCL_START
141     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
142                      "QFunctionContext field with name \"%s\" not registered",
143                      field_name);
144   // LCOV_EXCL_STOP
145 
146   if (ctx->field_descriptions[field_index].type != field_type)
147     // LCOV_EXCL_START
148     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
149                      "QFunctionContext field with name \"%s\" registered as %s, "
150                      "not registered as %s", field_name,
151                      CeedContextFieldTypes[ctx->field_descriptions[field_index].type],
152                      CeedContextFieldTypes[field_type]);
153   // LCOV_EXCL_STOP
154 
155   char *data;
156   ierr = CeedQFunctionContextGetData(ctx, CEED_MEM_HOST, &data); CeedChk(ierr);
157   memcpy(&data[ctx->field_descriptions[field_index].offset], value,
158          ctx->field_descriptions[field_index].size);
159   ierr = CeedQFunctionContextRestoreData(ctx, &data); CeedChk(ierr);
160 
161   return CEED_ERROR_SUCCESS;
162 }
163 
164 /// @}
165 
166 /// ----------------------------------------------------------------------------
167 /// CeedQFunctionContext Backend API
168 /// ----------------------------------------------------------------------------
169 /// @addtogroup CeedQFunctionBackend
170 /// @{
171 
172 /**
173   @brief Get the Ceed associated with a CeedQFunctionContext
174 
175   @param ctx        CeedQFunctionContext
176   @param[out] ceed  Variable to store Ceed
177 
178   @return An error code: 0 - success, otherwise - failure
179 
180   @ref Backend
181 **/
182 int CeedQFunctionContextGetCeed(CeedQFunctionContext ctx, Ceed *ceed) {
183   *ceed = ctx->ceed;
184   return CEED_ERROR_SUCCESS;
185 }
186 
187 /**
188   @brief Check for valid data in a CeedQFunctionContext
189 
190   @param ctx                  CeedQFunctionContext to check validity
191   @param[out] has_valid_data  Variable to store validity
192 
193   @return An error code: 0 - success, otherwise - failure
194 
195   @ref Backend
196 **/
197 int CeedQFunctionContextHasValidData(CeedQFunctionContext ctx,
198                                      bool *has_valid_data) {
199   int ierr;
200 
201   if (!ctx->HasValidData)
202     // LCOV_EXCL_START
203     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
204                      "Backend does not support HasValidData");
205   // LCOV_EXCL_STOP
206 
207   ierr = ctx->HasValidData(ctx, has_valid_data); CeedChk(ierr);
208 
209   return CEED_ERROR_SUCCESS;
210 }
211 
212 /**
213   @brief Check for borrowed data of a specific CeedMemType in a
214            CeedQFunctionContext
215 
216   @param ctx                             CeedQFunctionContext to check
217   @param mem_type                        Memory type to check
218   @param[out] has_borrowed_data_of_type  Variable to store result
219 
220   @return An error code: 0 - success, otherwise - failure
221 
222   @ref Backend
223 **/
224 int CeedQFunctionContextHasBorrowedDataOfType(CeedQFunctionContext ctx,
225     CeedMemType mem_type, bool *has_borrowed_data_of_type) {
226   int ierr;
227 
228   if (!ctx->HasBorrowedDataOfType)
229     // LCOV_EXCL_START
230     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
231                      "Backend does not support HasBorrowedDataOfType");
232   // LCOV_EXCL_STOP
233 
234   ierr = ctx->HasBorrowedDataOfType(ctx, mem_type, has_borrowed_data_of_type);
235   CeedChk(ierr);
236 
237   return CEED_ERROR_SUCCESS;
238 }
239 
240 /**
241   @brief Get the state of a CeedQFunctionContext
242 
243   @param ctx         CeedQFunctionContext to retrieve state
244   @param[out] state  Variable to store state
245 
246   @return An error code: 0 - success, otherwise - failure
247 
248   @ref Backend
249 **/
250 int CeedQFunctionContextGetState(CeedQFunctionContext ctx, uint64_t *state) {
251   *state = ctx->state;
252   return CEED_ERROR_SUCCESS;
253 }
254 
255 /**
256   @brief Get backend data of a CeedQFunctionContext
257 
258   @param ctx        CeedQFunctionContext
259   @param[out] data  Variable to store data
260 
261   @return An error code: 0 - success, otherwise - failure
262 
263   @ref Backend
264 **/
265 int CeedQFunctionContextGetBackendData(CeedQFunctionContext ctx, void *data) {
266   *(void **)data = ctx->data;
267   return CEED_ERROR_SUCCESS;
268 }
269 
270 /**
271   @brief Set backend data of a CeedQFunctionContext
272 
273   @param[out] ctx  CeedQFunctionContext
274   @param data      Data to set
275 
276   @return An error code: 0 - success, otherwise - failure
277 
278   @ref Backend
279 **/
280 int CeedQFunctionContextSetBackendData(CeedQFunctionContext ctx, void *data) {
281   ctx->data = data;
282   return CEED_ERROR_SUCCESS;
283 }
284 
285 /**
286   @brief Increment the reference counter for a CeedQFunctionContext
287 
288   @param ctx  CeedQFunctionContext to increment the reference counter
289 
290   @return An error code: 0 - success, otherwise - failure
291 
292   @ref Backend
293 **/
294 int CeedQFunctionContextReference(CeedQFunctionContext ctx) {
295   ctx->ref_count++;
296   return CEED_ERROR_SUCCESS;
297 }
298 
299 /// @}
300 
301 /// ----------------------------------------------------------------------------
302 /// CeedQFunctionContext Public API
303 /// ----------------------------------------------------------------------------
304 /// @addtogroup CeedQFunctionUser
305 /// @{
306 
307 /**
308   @brief Create a CeedQFunctionContext for storing CeedQFunction user context data
309 
310   @param ceed      A Ceed object where the CeedQFunctionContext will be created
311   @param[out] ctx  Address of the variable where the newly created
312                      CeedQFunctionContext will be stored
313 
314   @return An error code: 0 - success, otherwise - failure
315 
316   @ref User
317 **/
318 int CeedQFunctionContextCreate(Ceed ceed, CeedQFunctionContext *ctx) {
319   int ierr;
320 
321   if (!ceed->QFunctionContextCreate) {
322     Ceed delegate;
323     ierr = CeedGetObjectDelegate(ceed, &delegate, "Context"); CeedChk(ierr);
324 
325     if (!delegate)
326       // LCOV_EXCL_START
327       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
328                        "Backend does not support ContextCreate");
329     // LCOV_EXCL_STOP
330 
331     ierr = CeedQFunctionContextCreate(delegate, ctx); CeedChk(ierr);
332     return CEED_ERROR_SUCCESS;
333   }
334 
335   ierr = CeedCalloc(1, ctx); CeedChk(ierr);
336   (*ctx)->ceed = ceed;
337   ierr = CeedReference(ceed); CeedChk(ierr);
338   (*ctx)->ref_count = 1;
339   ierr = ceed->QFunctionContextCreate(*ctx); CeedChk(ierr);
340   return CEED_ERROR_SUCCESS;
341 }
342 
343 /**
344   @brief Copy the pointer to a CeedQFunctionContext. Both pointers should
345            be destroyed with `CeedQFunctionContextDestroy()`;
346            Note: If `*ctx_copy` is non-NULL, then it is assumed that
347            `*ctx_copy` is a pointer to a CeedQFunctionContext. This
348            CeedQFunctionContext will be destroyed if `*ctx_copy` is the
349            only reference to this CeedQFunctionContext.
350 
351   @param ctx            CeedQFunctionContext to copy reference to
352   @param[out] ctx_copy  Variable to store copied reference
353 
354   @return An error code: 0 - success, otherwise - failure
355 
356   @ref User
357 **/
358 int CeedQFunctionContextReferenceCopy(CeedQFunctionContext ctx,
359                                       CeedQFunctionContext *ctx_copy) {
360   int ierr;
361 
362   ierr = CeedQFunctionContextReference(ctx); CeedChk(ierr);
363   ierr = CeedQFunctionContextDestroy(ctx_copy); CeedChk(ierr);
364   *ctx_copy = ctx;
365   return CEED_ERROR_SUCCESS;
366 }
367 
368 /**
369   @brief Set the data used by a CeedQFunctionContext, freeing any previously allocated
370            data if applicable. The backend may copy values to a different
371            memtype, such as during @ref CeedQFunctionApply().
372            See also @ref CeedQFunctionContextTakeData().
373 
374   @param ctx        CeedQFunctionContext
375   @param mem_type   Memory type of the data being passed
376   @param copy_mode  Copy mode for the data
377   @param size       Size of data, in bytes
378   @param data       Data to be used
379 
380   @return An error code: 0 - success, otherwise - failure
381 
382   @ref User
383 **/
384 int CeedQFunctionContextSetData(CeedQFunctionContext ctx, CeedMemType mem_type,
385                                 CeedCopyMode copy_mode,
386                                 size_t size, void *data) {
387   int ierr;
388 
389   if (!ctx->SetData)
390     // LCOV_EXCL_START
391     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
392                      "Backend does not support ContextSetData");
393   // LCOV_EXCL_STOP
394 
395   if (ctx->state % 2 == 1)
396     // LCOV_EXCL_START
397     return CeedError(ctx->ceed, 1,
398                      "Cannot grant CeedQFunctionContext data access, the "
399                      "access lock is already in use");
400   // LCOV_EXCL_STOP
401 
402   ctx->ctx_size = size;
403   ierr = ctx->SetData(ctx, mem_type, copy_mode, data); CeedChk(ierr);
404   ctx->state += 2;
405   return CEED_ERROR_SUCCESS;
406 }
407 
408 /**
409   @brief Take ownership of the data in a CeedQFunctionContext via the specified memory type.
410            The caller is responsible for managing and freeing the memory.
411 
412   @param ctx        CeedQFunctionContext to access
413   @param mem_type   Memory type on which to access the data. If the backend
414                       uses a different memory type, this will perform a copy.
415   @param[out] data  Data on memory type mem_type
416 
417   @return An error code: 0 - success, otherwise - failure
418 
419   @ref User
420 **/
421 int CeedQFunctionContextTakeData(CeedQFunctionContext ctx, CeedMemType mem_type,
422                                  void *data) {
423   int ierr;
424 
425   bool has_valid_data = true;
426   ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr);
427   if (!has_valid_data)
428     // LCOV_EXCL_START
429     return CeedError(ctx->ceed, CEED_ERROR_BACKEND,
430                      "CeedQFunctionContext has no valid data to take, must set data");
431   // LCOV_EXCL_STOP
432 
433   if (!ctx->TakeData)
434     // LCOV_EXCL_START
435     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
436                      "Backend does not support TakeData");
437   // LCOV_EXCL_STOP
438 
439   if (ctx->state % 2 == 1)
440     // LCOV_EXCL_START
441     return CeedError(ctx->ceed, 1,
442                      "Cannot grant CeedQFunctionContext data access, the "
443                      "access lock is already in use");
444   // LCOV_EXCL_STOP
445 
446   bool has_borrowed_data_of_type = true;
447   ierr = CeedQFunctionContextHasBorrowedDataOfType(ctx, mem_type,
448          &has_borrowed_data_of_type); CeedChk(ierr);
449   if (!has_borrowed_data_of_type)
450     // LCOV_EXCL_START
451     return CeedError(ctx->ceed, CEED_ERROR_BACKEND,
452                      "CeedQFunctionContext has no borowed %s data, "
453                      "must set data with CeedQFunctionContextSetData",
454                      CeedMemTypes[mem_type]);
455   // LCOV_EXCL_STOP
456 
457   void *temp_data = NULL;
458   ierr = ctx->TakeData(ctx, mem_type, &temp_data); CeedChk(ierr);
459   if (data) (*(void **)data) = temp_data;
460   return CEED_ERROR_SUCCESS;
461 }
462 
463 /**
464   @brief Get read/write access to a CeedQFunctionContext via the specified memory type.
465            Restore access with @ref CeedQFunctionContextRestoreData().
466 
467   @param ctx        CeedQFunctionContext to access
468   @param mem_type   Memory type on which to access the data. If the backend
469                       uses a different memory type, this will perform a copy.
470   @param[out] data  Data on memory type mem_type
471 
472   @note The CeedQFunctionContextGetData() and @ref CeedQFunctionContextRestoreData() functions
473     provide access to array pointers in the desired memory space. Pairing
474     get/restore allows the Context to track access.
475 
476   @return An error code: 0 - success, otherwise - failure
477 
478   @ref User
479 **/
480 int CeedQFunctionContextGetData(CeedQFunctionContext ctx, CeedMemType mem_type,
481                                 void *data) {
482   int ierr;
483 
484   if (!ctx->GetData)
485     // LCOV_EXCL_START
486     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
487                      "Backend does not support GetData");
488   // LCOV_EXCL_STOP
489 
490   if (ctx->state % 2 == 1)
491     // LCOV_EXCL_START
492     return CeedError(ctx->ceed, 1,
493                      "Cannot grant CeedQFunctionContext data access, the "
494                      "access lock is already in use");
495   // LCOV_EXCL_STOP
496 
497   bool has_valid_data = true;
498   ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr);
499   if (!has_valid_data)
500     // LCOV_EXCL_START
501     return CeedError(ctx->ceed, CEED_ERROR_BACKEND,
502                      "CeedQFunctionContext has no valid data to get, must set data");
503   // LCOV_EXCL_STOP
504 
505   ierr = ctx->GetData(ctx, mem_type, data); CeedChk(ierr);
506   ctx->state += 1;
507   return CEED_ERROR_SUCCESS;
508 }
509 
510 /**
511   @brief Restore data obtained using @ref CeedQFunctionContextGetData()
512 
513   @param ctx   CeedQFunctionContext to restore
514   @param data  Data to restore
515 
516   @return An error code: 0 - success, otherwise - failure
517 
518   @ref User
519 **/
520 int CeedQFunctionContextRestoreData(CeedQFunctionContext ctx, void *data) {
521   int ierr;
522 
523   if (!ctx->RestoreData)
524     // LCOV_EXCL_START
525     return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED,
526                      "Backend does not support RestoreData");
527   // LCOV_EXCL_STOP
528 
529   if (ctx->state % 2 != 1)
530     // LCOV_EXCL_START
531     return CeedError(ctx->ceed, 1,
532                      "Cannot restore CeedQFunctionContext array access, "
533                      "access was not granted");
534   // LCOV_EXCL_STOP
535 
536   ierr = ctx->RestoreData(ctx); CeedChk(ierr);
537   *(void **)data = NULL;
538   ctx->state += 1;
539   return CEED_ERROR_SUCCESS;
540 }
541 
542 /**
543   @brief Register QFunctionContext a field holding a double precision value
544 
545   @param ctx               CeedQFunctionContext
546   @param field_name        Name of field to register
547   @param field_offset      Offset of field to register
548   @param field_description Description of field, or NULL for none
549 
550   @return An error code: 0 - success, otherwise - failure
551 
552   @ref User
553 **/
554 int CeedQFunctionContextRegisterDouble(CeedQFunctionContext ctx,
555                                        const char *field_name, size_t field_offset,
556                                        const char *field_description) {
557   return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset,
558          field_description, CEED_CONTEXT_FIELD_DOUBLE, sizeof(double));
559 }
560 
561 /**
562   @brief Register QFunctionContext a field holding a int32 value
563 
564   @param ctx               CeedQFunctionContext
565   @param field_name        Name of field to register
566   @param field_offset      Offset of field to register
567   @param field_description Description of field, or NULL for none
568 
569   @return An error code: 0 - success, otherwise - failure
570 
571   @ref User
572 **/
573 int CeedQFunctionContextRegisterInt32(CeedQFunctionContext ctx,
574                                       const char *field_name, size_t field_offset,
575                                       const char *field_description) {
576   return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset,
577          field_description, CEED_CONTEXT_FIELD_INT32, sizeof(int));
578 }
579 
580 /**
581   @brief Get descriptions for registered QFunctionContext fields
582 
583   @param ctx                     CeedQFunctionContext
584   @param[out] field_descriptions Variable to hold array of field descriptions
585   @param[out] num_fields         Length of field descriptions array
586 
587   @return An error code: 0 - success, otherwise - failure
588 
589   @ref User
590 **/
591 int CeedQFunctionContextGetFieldDescriptions(CeedQFunctionContext ctx,
592     const CeedQFunctionContextFieldDescription **field_descriptions,
593     CeedInt *num_fields) {
594   *field_descriptions = ctx->field_descriptions;
595   *num_fields = ctx->num_fields;
596   return CEED_ERROR_SUCCESS;
597 }
598 
599 /**
600   @brief Set QFunctionContext field holding a double precision value
601 
602   @param ctx        CeedQFunctionContext
603   @param field_name Name of field to register
604   @param value      Value to set
605 
606   @return An error code: 0 - success, otherwise - failure
607 
608   @ref User
609 **/
610 int CeedQFunctionContextSetDouble(CeedQFunctionContext ctx,
611                                   const char *field_name, double value) {
612   return CeedQFunctionContextSetGeneric(ctx, field_name,
613                                         CEED_CONTEXT_FIELD_DOUBLE,
614                                         &value);
615 }
616 
617 /**
618   @brief Set QFunctionContext field holding a int32 value
619 
620   @param ctx        CeedQFunctionContext
621   @param field_name Name of field to set
622   @param value      Value to set
623 
624   @return An error code: 0 - success, otherwise - failure
625 
626   @ref User
627 **/
628 int CeedQFunctionContextSetInt32(CeedQFunctionContext ctx,
629                                  const char *field_name, int value) {
630   return CeedQFunctionContextSetGeneric(ctx, field_name, CEED_CONTEXT_FIELD_INT32,
631                                         &value);
632 }
633 
634 /**
635   @brief Get data size for a Context
636 
637   @param ctx            CeedQFunctionContext
638   @param[out] ctx_size  Variable to store size of context data values
639 
640   @return An error code: 0 - success, otherwise - failure
641 
642   @ref User
643 **/
644 int CeedQFunctionContextGetContextSize(CeedQFunctionContext ctx,
645                                        size_t *ctx_size) {
646   *ctx_size = ctx->ctx_size;
647   return CEED_ERROR_SUCCESS;
648 }
649 
650 
651 /**
652   @brief View a CeedQFunctionContext
653 
654   @param[in] ctx     CeedQFunctionContext to view
655   @param[in] stream  Filestream to write to
656 
657   @return An error code: 0 - success, otherwise - failure
658 
659   @ref User
660 **/
661 int CeedQFunctionContextView(CeedQFunctionContext ctx, FILE *stream) {
662   fprintf(stream, "CeedQFunctionContext\n");
663   fprintf(stream, "  Context Data Size: %ld\n", ctx->ctx_size);
664   return CEED_ERROR_SUCCESS;
665 }
666 
667 /**
668   @brief Destroy a CeedQFunctionContext
669 
670   @param ctx  CeedQFunctionContext to destroy
671 
672   @return An error code: 0 - success, otherwise - failure
673 
674   @ref User
675 **/
676 int CeedQFunctionContextDestroy(CeedQFunctionContext *ctx) {
677   int ierr;
678 
679   if (!*ctx || --(*ctx)->ref_count > 0)
680     return CEED_ERROR_SUCCESS;
681 
682   if ((*ctx) && ((*ctx)->state % 2) == 1)
683     // LCOV_EXCL_START
684     return CeedError((*ctx)->ceed, 1,
685                      "Cannot destroy CeedQFunctionContext, the access "
686                      "lock is in use");
687   // LCOV_EXCL_STOP
688 
689   if ((*ctx)->Destroy) {
690     ierr = (*ctx)->Destroy(*ctx); CeedChk(ierr);
691   }
692   for (CeedInt i=0; i<(*ctx)->num_fields; i++) {
693     ierr = CeedFree(&(*ctx)->field_descriptions[i].name); CeedChk(ierr);
694     ierr = CeedFree(&(*ctx)->field_descriptions[i].description); CeedChk(ierr);
695   }
696   ierr = CeedFree(&(*ctx)->field_descriptions); CeedChk(ierr);
697   ierr = CeedDestroy(&(*ctx)->ceed); CeedChk(ierr);
698   ierr = CeedFree(ctx); CeedChk(ierr);
699 
700   return CEED_ERROR_SUCCESS;
701 }
702 
703 /// @}
704