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