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