xref: /libCEED/interface/ceed-qfunctioncontext.c (revision 6e6704a8423bd3768f5be9a2123202698796761d) !
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            Both pointers should be destroyed with `CeedQFunctionContextDestroy()`.
500 
501            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
502              CeedQFunctionContext. This CeedQFunctionContext will be destroyed if `ctx_copy` is the only reference to this CeedQFunctionContext.
503 
504   @param[in]     ctx      CeedQFunctionContext to copy reference to
505   @param[in,out] ctx_copy Variable to store copied reference
506 
507   @return An error code: 0 - success, otherwise - failure
508 
509   @ref User
510 **/
511 int CeedQFunctionContextReferenceCopy(CeedQFunctionContext ctx, CeedQFunctionContext *ctx_copy) {
512   CeedCall(CeedQFunctionContextReference(ctx));
513   CeedCall(CeedQFunctionContextDestroy(ctx_copy));
514   *ctx_copy = ctx;
515   return CEED_ERROR_SUCCESS;
516 }
517 
518 /**
519   @brief Set the data used by a CeedQFunctionContext, freeing any previously allocated data if applicable.
520            The backend may copy values to a different memtype, such as during @ref CeedQFunctionApply().
521            See also @ref CeedQFunctionContextTakeData().
522 
523   @param[in,out] ctx       CeedQFunctionContext
524   @param[in]     mem_type  Memory type of the data being passed
525   @param[in]     copy_mode Copy mode for the data
526   @param[in]     size      Size of data, in bytes
527   @param[in]     data      Data to be used
528 
529   @return An error code: 0 - success, otherwise - failure
530 
531   @ref User
532 **/
533 int CeedQFunctionContextSetData(CeedQFunctionContext ctx, CeedMemType mem_type, CeedCopyMode copy_mode, size_t size, void *data) {
534   CeedCheck(ctx->SetData, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ContextSetData");
535   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
536 
537   CeedCall(CeedQFunctionContextDestroyData(ctx));
538   ctx->ctx_size = size;
539   CeedCall(ctx->SetData(ctx, mem_type, copy_mode, data));
540   ctx->state += 2;
541   return CEED_ERROR_SUCCESS;
542 }
543 
544 /**
545   @brief Take ownership of the data in a CeedQFunctionContext via the specified memory type.
546            The caller is responsible for managing and freeing the memory.
547 
548   @param[in]  ctx      CeedQFunctionContext to access
549   @param[in]  mem_type Memory type on which to access the data.
550                          If the backend uses a different memory type, this will perform a copy.
551   @param[out] data     Data on memory type mem_type
552 
553   @return An error code: 0 - success, otherwise - failure
554 
555   @ref User
556 **/
557 int CeedQFunctionContextTakeData(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
558   bool has_valid_data = true;
559   CeedCall(CeedQFunctionContextHasValidData(ctx, &has_valid_data));
560   CeedCheck(has_valid_data, ctx->ceed, CEED_ERROR_BACKEND, "CeedQFunctionContext has no valid data to take, must set data");
561 
562   CeedCheck(ctx->TakeData, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support TakeData");
563   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
564 
565   bool has_borrowed_data_of_type = true;
566   CeedCall(CeedQFunctionContextHasBorrowedDataOfType(ctx, mem_type, &has_borrowed_data_of_type));
567   CeedCheck(has_borrowed_data_of_type, ctx->ceed, CEED_ERROR_BACKEND,
568             "CeedQFunctionContext has no borrowed %s data, must set data with CeedQFunctionContextSetData", CeedMemTypes[mem_type]);
569 
570   void *temp_data = NULL;
571   CeedCall(ctx->TakeData(ctx, mem_type, &temp_data));
572   if (data) (*(void **)data) = temp_data;
573   return CEED_ERROR_SUCCESS;
574 }
575 
576 /**
577   @brief Get read/write access to a CeedQFunctionContext via the specified memory type.
578            Restore access with @ref CeedQFunctionContextRestoreData().
579 
580   @param[in]  ctx      CeedQFunctionContext to access
581   @param[in]  mem_type Memory type on which to access the data.
582                          If the backend uses a different memory type, this will perform a copy.
583   @param[out] data     Data on memory type mem_type
584 
585   @note The CeedQFunctionContextGetData() and @ref CeedQFunctionContextRestoreData() functions provide access to array pointers in the desired memory
586 space. Pairing get/restore allows the Context to track access.
587 
588   @return An error code: 0 - success, otherwise - failure
589 
590   @ref User
591 **/
592 int CeedQFunctionContextGetData(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
593   CeedCheck(ctx->GetData, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetData");
594   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
595   CeedCheck(ctx->num_readers == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, a process has read access");
596 
597   bool has_valid_data = true;
598   CeedCall(CeedQFunctionContextHasValidData(ctx, &has_valid_data));
599   CeedCheck(has_valid_data, ctx->ceed, CEED_ERROR_BACKEND, "CeedQFunctionContext has no valid data to get, must set data");
600 
601   CeedCall(ctx->GetData(ctx, mem_type, data));
602   ctx->state++;
603   return CEED_ERROR_SUCCESS;
604 }
605 
606 /**
607   @brief Get read only access to a CeedQFunctionContext via the specified memory type.
608            Restore access with @ref CeedQFunctionContextRestoreData().
609 
610   @param[in]  ctx      CeedQFunctionContext to access
611   @param[in]  mem_type Memory type on which to access the data.
612                          If the backend uses a different memory type, this will perform a copy.
613   @param[out] data     Data on memory type mem_type
614 
615   @note The CeedQFunctionContextGetDataRead() and @ref CeedQFunctionContextRestoreDataRead() functions provide access to array pointers in the desired
616 memory space. Pairing get/restore allows the Context to track access.
617 
618   @return An error code: 0 - success, otherwise - failure
619 
620   @ref User
621 **/
622 int CeedQFunctionContextGetDataRead(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
623   CeedCheck(ctx->GetDataRead, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetDataRead");
624   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
625 
626   bool has_valid_data = true;
627   CeedCall(CeedQFunctionContextHasValidData(ctx, &has_valid_data));
628   CeedCheck(has_valid_data, ctx->ceed, CEED_ERROR_BACKEND, "CeedQFunctionContext has no valid data to get, must set data");
629 
630   CeedCall(ctx->GetDataRead(ctx, mem_type, data));
631   ctx->num_readers++;
632   return CEED_ERROR_SUCCESS;
633 }
634 
635 /**
636   @brief Restore data obtained using @ref CeedQFunctionContextGetData()
637 
638   @param[in]     ctx  CeedQFunctionContext to restore
639   @param[in,out] data Data to restore
640 
641   @return An error code: 0 - success, otherwise - failure
642 
643   @ref User
644 **/
645 int CeedQFunctionContextRestoreData(CeedQFunctionContext ctx, void *data) {
646   CeedCheck(ctx->state % 2 == 1, ctx->ceed, 1, "Cannot restore CeedQFunctionContext array access, access was not granted");
647 
648   if (ctx->RestoreData) CeedCall(ctx->RestoreData(ctx));
649   *(void **)data = NULL;
650   ctx->state++;
651   return CEED_ERROR_SUCCESS;
652 }
653 
654 /**
655   @brief Restore data obtained using @ref CeedQFunctionContextGetDataRead()
656 
657   @param[in]     ctx  CeedQFunctionContext to restore
658   @param[in,out] data Data to restore
659 
660   @return An error code: 0 - success, otherwise - failure
661 
662   @ref User
663 **/
664 int CeedQFunctionContextRestoreDataRead(CeedQFunctionContext ctx, void *data) {
665   CeedCheck(ctx->num_readers > 0, ctx->ceed, 1, "Cannot restore CeedQFunctionContext array access, access was not granted");
666 
667   ctx->num_readers--;
668   if (ctx->num_readers == 0 && ctx->RestoreDataRead) CeedCall(ctx->RestoreDataRead(ctx));
669   *(void **)data = NULL;
670 
671   return CEED_ERROR_SUCCESS;
672 }
673 
674 /**
675   @brief Register QFunctionContext a field holding a double precision value
676 
677   @param[in,out] ctx               CeedQFunctionContext
678   @param[in]     field_name        Name of field to register
679   @param[in]     field_offset      Offset of field to register
680   @param[in]     num_values        Number of values to register, must be contiguous in memory
681   @param[in]     field_description Description of field, or NULL for none
682 
683   @return An error code: 0 - success, otherwise - failure
684 
685   @ref User
686 **/
687 int CeedQFunctionContextRegisterDouble(CeedQFunctionContext ctx, const char *field_name, size_t field_offset, size_t num_values,
688                                        const char *field_description) {
689   return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset, field_description, CEED_CONTEXT_FIELD_DOUBLE, sizeof(double), num_values);
690 }
691 
692 /**
693   @brief Register QFunctionContext a field holding a int32 value
694 
695   @param[in,out] ctx               CeedQFunctionContext
696   @param[in]     field_name        Name of field to register
697   @param[in]     field_offset      Offset of field to register
698   @param[in]     num_values        Number of values to register, must be contiguous in memory
699   @param[in]     field_description Description of field, or NULL for none
700 
701   @return An error code: 0 - success, otherwise - failure
702 
703   @ref User
704 **/
705 int CeedQFunctionContextRegisterInt32(CeedQFunctionContext ctx, const char *field_name, size_t field_offset, size_t num_values,
706                                       const char *field_description) {
707   return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset, field_description, CEED_CONTEXT_FIELD_INT32, sizeof(int), num_values);
708 }
709 
710 /**
711   @brief Get labels for all registered QFunctionContext fields
712 
713   @param[in]  ctx          CeedQFunctionContext
714   @param[out] field_labels Variable to hold array of field labels
715   @param[out] num_fields   Length of field descriptions array
716 
717   @return An error code: 0 - success, otherwise - failure
718 
719   @ref User
720 **/
721 int CeedQFunctionContextGetAllFieldLabels(CeedQFunctionContext ctx, const CeedContextFieldLabel **field_labels, CeedInt *num_fields) {
722   *field_labels = ctx->field_labels;
723   *num_fields   = ctx->num_fields;
724   return CEED_ERROR_SUCCESS;
725 }
726 
727 /**
728   @brief Get the descriptive information about a CeedContextFieldLabel
729 
730   @param[in]  label             CeedContextFieldLabel
731   @param[out] field_name        Name of labeled field
732   @param[out] field_description Description of field, or NULL for none
733   @param[out] num_values        Number of values registered
734   @param[out] field_type        CeedContextFieldType
735 
736   @return An error code: 0 - success, otherwise - failure
737 
738   @ref User
739 **/
740 int CeedContextFieldLabelGetDescription(CeedContextFieldLabel label, const char **field_name, const char **field_description, size_t *num_values,
741                                         CeedContextFieldType *field_type) {
742   if (field_name) *field_name = label->name;
743   if (field_description) *field_description = label->description;
744   if (num_values) *num_values = label->num_values;
745   if (field_type) *field_type = label->type;
746   return CEED_ERROR_SUCCESS;
747 }
748 
749 /**
750   @brief Get data size for a Context
751 
752   @param[in]  ctx      CeedQFunctionContext
753   @param[out] ctx_size Variable to store size of context data values
754 
755   @return An error code: 0 - success, otherwise - failure
756 
757   @ref User
758 **/
759 int CeedQFunctionContextGetContextSize(CeedQFunctionContext ctx, size_t *ctx_size) {
760   *ctx_size = ctx->ctx_size;
761   return CEED_ERROR_SUCCESS;
762 }
763 
764 /**
765   @brief View a CeedQFunctionContext
766 
767   @param[in] ctx    CeedQFunctionContext to view
768   @param[in] stream Filestream to write to
769 
770   @return An error code: 0 - success, otherwise - failure
771 
772   @ref User
773 **/
774 int CeedQFunctionContextView(CeedQFunctionContext ctx, FILE *stream) {
775   fprintf(stream, "CeedQFunctionContext\n");
776   fprintf(stream, "  Context Data Size: %ld\n", ctx->ctx_size);
777   for (CeedInt i = 0; i < ctx->num_fields; i++) {
778     // LCOV_EXCL_START
779     fprintf(stream, "  Labeled %s field: %s\n", CeedContextFieldTypes[ctx->field_labels[i]->type], ctx->field_labels[i]->name);
780     // LCOV_EXCL_STOP
781   }
782   return CEED_ERROR_SUCCESS;
783 }
784 
785 /**
786   @brief Set additional destroy routine for CeedQFunctionContext user data
787 
788   @param[in,out] ctx        CeedQFunctionContext to set user destroy function
789   @param[in]     f_mem_type Memory type to use when passing data into `f`
790   @param[in]     f          Additional routine to use to destroy user data
791 
792   @return An error code: 0 - success, otherwise - failure
793 
794   @ref User
795 **/
796 int CeedQFunctionContextSetDataDestroy(CeedQFunctionContext ctx, CeedMemType f_mem_type, CeedQFunctionContextDataDestroyUser f) {
797   CeedCheck(f, ctx->ceed, 1, "Must provide valid callback function for destroying user data");
798   ctx->data_destroy_mem_type = f_mem_type;
799   ctx->data_destroy_function = f;
800   return CEED_ERROR_SUCCESS;
801 }
802 
803 /**
804   @brief Destroy a CeedQFunctionContext
805 
806   @param[in,out] ctx CeedQFunctionContext to destroy
807 
808   @return An error code: 0 - success, otherwise - failure
809 
810   @ref User
811 **/
812 int CeedQFunctionContextDestroy(CeedQFunctionContext *ctx) {
813   if (!*ctx || --(*ctx)->ref_count > 0) {
814     *ctx = NULL;
815     return CEED_ERROR_SUCCESS;
816   }
817   CeedCheck(((*ctx)->state % 2) == 0, (*ctx)->ceed, 1, "Cannot destroy CeedQFunctionContext, the access lock is in use");
818 
819   CeedCall(CeedQFunctionContextDestroyData(*ctx));
820   if ((*ctx)->Destroy) CeedCall((*ctx)->Destroy(*ctx));
821   for (CeedInt i = 0; i < (*ctx)->num_fields; i++) {
822     CeedCall(CeedFree(&(*ctx)->field_labels[i]->name));
823     CeedCall(CeedFree(&(*ctx)->field_labels[i]->description));
824     CeedCall(CeedFree(&(*ctx)->field_labels[i]));
825   }
826   CeedCall(CeedFree(&(*ctx)->field_labels));
827   CeedCall(CeedDestroy(&(*ctx)->ceed));
828   CeedCall(CeedFree(ctx));
829 
830   return CEED_ERROR_SUCCESS;
831 }
832 
833 /// @}
834