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