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