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