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