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