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