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