xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-qfunctioncontext.c (revision 1c66c397a67401e1a222857807e6e5b7c45b88c0)
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   CeedInt field_index = -1;
62 
63   // Check for duplicate
64   CeedCall(CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index));
65   CeedCheck(field_index == -1, ctx->ceed, CEED_ERROR_UNSUPPORTED, "QFunctionContext field with name \"%s\" already registered", field_name);
66 
67   // Allocate space for field data
68   if (ctx->num_fields == 0) {
69     CeedCall(CeedCalloc(1, &ctx->field_labels));
70     ctx->max_fields = 1;
71   } else if (ctx->num_fields == ctx->max_fields) {
72     CeedCall(CeedRealloc(2 * ctx->max_fields, &ctx->field_labels));
73     ctx->max_fields *= 2;
74   }
75   CeedCall(CeedCalloc(1, &ctx->field_labels[ctx->num_fields]));
76 
77   // Copy field data
78   CeedCall(CeedStringAllocCopy(field_name, (char **)&ctx->field_labels[ctx->num_fields]->name));
79   CeedCall(CeedStringAllocCopy(field_description, (char **)&ctx->field_labels[ctx->num_fields]->description));
80   ctx->field_labels[ctx->num_fields]->type       = field_type;
81   ctx->field_labels[ctx->num_fields]->offset     = field_offset;
82   ctx->field_labels[ctx->num_fields]->size       = field_size * num_values;
83   ctx->field_labels[ctx->num_fields]->num_values = num_values;
84   ctx->num_fields++;
85   return CEED_ERROR_SUCCESS;
86 }
87 
88 /**
89   @brief Destroy user data held by CeedQFunctionContext, using function set by CeedQFunctionContextSetDataDestroy, if applicable
90 
91   @param[in,out] ctx CeedQFunctionContext to destroy user data
92 
93   @return An error code: 0 - success, otherwise - failure
94 
95   @ref Developer
96 **/
97 static int CeedQFunctionContextDestroyData(CeedQFunctionContext ctx) {
98   if (ctx->DataDestroy) {
99     CeedCall(ctx->DataDestroy(ctx));
100   } else {
101     CeedMemType                         data_destroy_mem_type;
102     CeedQFunctionContextDataDestroyUser data_destroy_function;
103 
104     CeedCall(CeedQFunctionContextGetDataDestroy(ctx, &data_destroy_mem_type, &data_destroy_function));
105     if (data_destroy_function) {
106       void *data;
107 
108       CeedCall(CeedQFunctionContextGetData(ctx, data_destroy_mem_type, &data));
109       CeedCall(data_destroy_function(data));
110       CeedCall(CeedQFunctionContextRestoreData(ctx, &data));
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 
231   CeedCall(CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index));
232 
233   if (field_index != -1) {
234     *field_label = ctx->field_labels[field_index];
235   } else {
236     *field_label = NULL;
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   char *data;
255 
256   // Check field type
257   CeedCheck(field_label->type == field_type, ctx->ceed, CEED_ERROR_UNSUPPORTED,
258             "QFunctionContext field with name \"%s\" registered as %s, not registered as %s", field_label->name,
259             CeedContextFieldTypes[field_label->type], CeedContextFieldTypes[field_type]);
260 
261   CeedCall(CeedQFunctionContextGetData(ctx, CEED_MEM_HOST, &data));
262   memcpy(&data[field_label->offset], values, field_label->size);
263   CeedCall(CeedQFunctionContextRestoreData(ctx, &data));
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   char *data;
283 
284   // Check field type
285   CeedCheck(field_label->type == field_type, ctx->ceed, CEED_ERROR_UNSUPPORTED,
286             "QFunctionContext field with name \"%s\" registered as %s, not registered as %s", field_label->name,
287             CeedContextFieldTypes[field_label->type], CeedContextFieldTypes[field_type]);
288 
289   CeedCall(CeedQFunctionContextGetDataRead(ctx, CEED_MEM_HOST, &data));
290   *(void **)values = &data[field_label->offset];
291   switch (field_type) {
292     case CEED_CONTEXT_FIELD_INT32:
293       *num_values = field_label->size / sizeof(int);
294       break;
295     case CEED_CONTEXT_FIELD_DOUBLE:
296       *num_values = field_label->size / sizeof(double);
297       break;
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   return CEED_ERROR_SUCCESS;
323 }
324 
325 /**
326   @brief Set QFunctionContext field holding a double precision value
327 
328   @param[in,out] ctx         CeedQFunctionContext
329   @param[in]     field_label Label for field to set
330   @param[in]     values      Values to set
331 
332   @return An error code: 0 - success, otherwise - failure
333 
334   @ref Backend
335 **/
336 int CeedQFunctionContextSetDouble(CeedQFunctionContext ctx, CeedContextFieldLabel field_label, double *values) {
337   CeedCheck(field_label, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
338   CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label, CEED_CONTEXT_FIELD_DOUBLE, values));
339   return CEED_ERROR_SUCCESS;
340 }
341 
342 /**
343   @brief Get QFunctionContext field holding a double precision value, read-only
344 
345   @param[in]  ctx         CeedQFunctionContext
346   @param[in]  field_label Label for field to get
347   @param[out] num_values  Number of values in the field label
348   @param[out] values      Pointer to context values
349 
350   @return An error code: 0 - success, otherwise - failure
351 
352   @ref Backend
353 **/
354 int CeedQFunctionContextGetDoubleRead(CeedQFunctionContext ctx, CeedContextFieldLabel field_label, size_t *num_values, const double **values) {
355   CeedCheck(field_label, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
356   CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values));
357   return CEED_ERROR_SUCCESS;
358 }
359 
360 /**
361   @brief Restore QFunctionContext field holding a double precision value, read-only
362 
363   @param[in]  ctx         CeedQFunctionContext
364   @param[in]  field_label Label for field to restore
365   @param[out] values      Pointer to context values
366 
367   @return An error code: 0 - success, otherwise - failure
368 
369   @ref Backend
370 **/
371 int CeedQFunctionContextRestoreDoubleRead(CeedQFunctionContext ctx, CeedContextFieldLabel field_label, const double **values) {
372   CeedCheck(field_label, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
373   CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label, CEED_CONTEXT_FIELD_DOUBLE, values));
374   return CEED_ERROR_SUCCESS;
375 }
376 
377 /**
378   @brief Set QFunctionContext field holding an int32 value
379 
380   @param[in,out] ctx         CeedQFunctionContext
381   @param[in]     field_label Label for field to set
382   @param[in]     values      Values to set
383 
384   @return An error code: 0 - success, otherwise - failure
385 
386   @ref Backend
387 **/
388 int CeedQFunctionContextSetInt32(CeedQFunctionContext ctx, CeedContextFieldLabel field_label, int *values) {
389   CeedCheck(field_label, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
390   CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label, CEED_CONTEXT_FIELD_INT32, values));
391   return CEED_ERROR_SUCCESS;
392 }
393 
394 /**
395   @brief Get QFunctionContext field holding a int32 value, read-only
396 
397   @param[in]  ctx         CeedQFunctionContext
398   @param[in]  field_label Label for field to get
399   @param[out] num_values  Number of values in the field label
400   @param[out] values      Pointer to context values
401 
402   @return An error code: 0 - success, otherwise - failure
403 
404   @ref Backend
405 **/
406 int CeedQFunctionContextGetInt32Read(CeedQFunctionContext ctx, CeedContextFieldLabel field_label, size_t *num_values, const int **values) {
407   CeedCheck(field_label, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
408   CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values));
409   return CEED_ERROR_SUCCESS;
410 }
411 
412 /**
413   @brief Restore QFunctionContext field holding a int32 value, read-only
414 
415   @param[in]  ctx         CeedQFunctionContext
416   @param[in]  field_label Label for field to restore
417   @param[out] values      Pointer to context values
418 
419   @return An error code: 0 - success, otherwise - failure
420 
421   @ref Backend
422 **/
423 int CeedQFunctionContextRestoreInt32Read(CeedQFunctionContext ctx, CeedContextFieldLabel field_label, const int **values) {
424   CeedCheck(field_label, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
425   CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label, CEED_CONTEXT_FIELD_INT32, values));
426   return CEED_ERROR_SUCCESS;
427 }
428 
429 /**
430   @brief Get additional destroy routine for CeedQFunctionContext user data
431 
432   @param[in] ctx         CeedQFunctionContext to get user destroy function
433   @param[out] f_mem_type Memory type to use when passing data into `f`
434   @param[out] f          Additional routine to use to destroy user data
435 
436   @return An error code: 0 - success, otherwise - failure
437 
438   @ref Backend
439 **/
440 int CeedQFunctionContextGetDataDestroy(CeedQFunctionContext ctx, CeedMemType *f_mem_type, CeedQFunctionContextDataDestroyUser *f) {
441   if (f_mem_type) *f_mem_type = ctx->data_destroy_mem_type;
442   if (f) *f = ctx->data_destroy_function;
443   return CEED_ERROR_SUCCESS;
444 }
445 
446 /**
447   @brief Increment the reference counter for a CeedQFunctionContext
448 
449   @param[in,out] ctx CeedQFunctionContext to increment the reference counter
450 
451   @return An error code: 0 - success, otherwise - failure
452 
453   @ref Backend
454 **/
455 int CeedQFunctionContextReference(CeedQFunctionContext ctx) {
456   ctx->ref_count++;
457   return CEED_ERROR_SUCCESS;
458 }
459 
460 /// @}
461 
462 /// ----------------------------------------------------------------------------
463 /// CeedQFunctionContext Public API
464 /// ----------------------------------------------------------------------------
465 /// @addtogroup CeedQFunctionUser
466 /// @{
467 
468 /**
469   @brief Create a CeedQFunctionContext for storing CeedQFunction user context data
470 
471   @param[in]  ceed Ceed object where the CeedQFunctionContext will be created
472   @param[out] ctx  Address of the variable where the newly created CeedQFunctionContext will be stored
473 
474   @return An error code: 0 - success, otherwise - failure
475 
476   @ref User
477 **/
478 int CeedQFunctionContextCreate(Ceed ceed, CeedQFunctionContext *ctx) {
479   if (!ceed->QFunctionContextCreate) {
480     Ceed delegate;
481 
482     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Context"));
483     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ContextCreate");
484     CeedCall(CeedQFunctionContextCreate(delegate, ctx));
485     return CEED_ERROR_SUCCESS;
486   }
487 
488   CeedCall(CeedCalloc(1, ctx));
489   CeedCall(CeedReferenceCopy(ceed, &(*ctx)->ceed));
490   (*ctx)->ref_count = 1;
491   CeedCall(ceed->QFunctionContextCreate(*ctx));
492   return CEED_ERROR_SUCCESS;
493 }
494 
495 /**
496   @brief Copy the pointer to a CeedQFunctionContext.
497 
498   Both pointers should be destroyed with `CeedQFunctionContextDestroy()`.
499 
500   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
501         CeedQFunctionContext. This CeedQFunctionContext will be destroyed if `ctx_copy` is the only reference to this CeedQFunctionContext.
502 
503   @param[in]     ctx      CeedQFunctionContext to copy reference to
504   @param[in,out] ctx_copy Variable to store copied reference
505 
506   @return An error code: 0 - success, otherwise - failure
507 
508   @ref User
509 **/
510 int CeedQFunctionContextReferenceCopy(CeedQFunctionContext ctx, CeedQFunctionContext *ctx_copy) {
511   CeedCall(CeedQFunctionContextReference(ctx));
512   CeedCall(CeedQFunctionContextDestroy(ctx_copy));
513   *ctx_copy = ctx;
514   return CEED_ERROR_SUCCESS;
515 }
516 
517 /**
518   @brief Set the data used by a CeedQFunctionContext, freeing any previously allocated data if applicable.
519 
520   The backend may copy values to a different memtype, such as during @ref CeedQFunctionApply().
521   See also @ref CeedQFunctionContextTakeData().
522 
523   @param[in,out] ctx       CeedQFunctionContext
524   @param[in]     mem_type  Memory type of the data being passed
525   @param[in]     copy_mode Copy mode for the data
526   @param[in]     size      Size of data, in bytes
527   @param[in]     data      Data to be used
528 
529   @return An error code: 0 - success, otherwise - failure
530 
531   @ref User
532 **/
533 int CeedQFunctionContextSetData(CeedQFunctionContext ctx, CeedMemType mem_type, CeedCopyMode copy_mode, size_t size, void *data) {
534   CeedCheck(ctx->SetData, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ContextSetData");
535   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
536 
537   CeedCall(CeedQFunctionContextDestroyData(ctx));
538   ctx->ctx_size = size;
539   CeedCall(ctx->SetData(ctx, mem_type, copy_mode, data));
540   ctx->state += 2;
541   return CEED_ERROR_SUCCESS;
542 }
543 
544 /**
545   @brief Take ownership of the data in a CeedQFunctionContext via the specified memory type.
546 
547   The caller is responsible for managing and freeing the memory.
548 
549   @param[in]  ctx      CeedQFunctionContext to access
550   @param[in]  mem_type Memory type on which to access the data.
551                          If the backend uses a different memory type, this will perform a copy.
552   @param[out] data     Data on memory type mem_type
553 
554   @return An error code: 0 - success, otherwise - failure
555 
556   @ref User
557 **/
558 int CeedQFunctionContextTakeData(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
559   void *temp_data      = NULL;
560   bool  has_valid_data = true, has_borrowed_data_of_type = true;
561 
562   CeedCall(CeedQFunctionContextHasValidData(ctx, &has_valid_data));
563   CeedCheck(has_valid_data, ctx->ceed, CEED_ERROR_BACKEND, "CeedQFunctionContext has no valid data to take, must set data");
564 
565   CeedCheck(ctx->TakeData, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support TakeData");
566   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
567 
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   CeedCall(ctx->TakeData(ctx, mem_type, &temp_data));
573   if (data) (*(void **)data) = temp_data;
574   return CEED_ERROR_SUCCESS;
575 }
576 
577 /**
578   @brief Get read/write access to a CeedQFunctionContext via the specified memory type.
579 
580   Restore access with @ref CeedQFunctionContextRestoreData().
581 
582   @param[in]  ctx      CeedQFunctionContext to access
583   @param[in]  mem_type Memory type on which to access the data.
584                          If the backend uses a different memory type, this will perform a copy.
585   @param[out] data     Data on memory type mem_type
586 
587   @note The CeedQFunctionContextGetData() and @ref CeedQFunctionContextRestoreData() functions provide access to array pointers in the desired memory
588 space.
589         Pairing get/restore allows the Context to track access.
590 
591   @return An error code: 0 - success, otherwise - failure
592 
593   @ref User
594 **/
595 int CeedQFunctionContextGetData(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
596   bool has_valid_data = true;
597 
598   CeedCheck(ctx->GetData, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetData");
599   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
600   CeedCheck(ctx->num_readers == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, a process has read access");
601 
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   bool has_valid_data = true;
630 
631   CeedCheck(ctx->GetDataRead, ctx->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetDataRead");
632   CeedCheck(ctx->state % 2 == 0, ctx->ceed, 1, "Cannot grant CeedQFunctionContext data access, the access lock is already in use");
633 
634   CeedCall(CeedQFunctionContextHasValidData(ctx, &has_valid_data));
635   CeedCheck(has_valid_data, ctx->ceed, CEED_ERROR_BACKEND, "CeedQFunctionContext has no valid data to get, must set data");
636 
637   CeedCall(ctx->GetDataRead(ctx, mem_type, data));
638   ctx->num_readers++;
639   return CEED_ERROR_SUCCESS;
640 }
641 
642 /**
643   @brief Restore data obtained using @ref CeedQFunctionContextGetData()
644 
645   @param[in]     ctx  CeedQFunctionContext to restore
646   @param[in,out] data Data to restore
647 
648   @return An error code: 0 - success, otherwise - failure
649 
650   @ref User
651 **/
652 int CeedQFunctionContextRestoreData(CeedQFunctionContext ctx, void *data) {
653   CeedCheck(ctx->state % 2 == 1, ctx->ceed, 1, "Cannot restore CeedQFunctionContext array access, access was not granted");
654 
655   if (ctx->RestoreData) CeedCall(ctx->RestoreData(ctx));
656   *(void **)data = NULL;
657   ctx->state++;
658   return CEED_ERROR_SUCCESS;
659 }
660 
661 /**
662   @brief Restore data obtained using @ref CeedQFunctionContextGetDataRead()
663 
664   @param[in]     ctx  CeedQFunctionContext to restore
665   @param[in,out] data Data to restore
666 
667   @return An error code: 0 - success, otherwise - failure
668 
669   @ref User
670 **/
671 int CeedQFunctionContextRestoreDataRead(CeedQFunctionContext ctx, void *data) {
672   CeedCheck(ctx->num_readers > 0, ctx->ceed, 1, "Cannot restore CeedQFunctionContext array access, access was not granted");
673 
674   ctx->num_readers--;
675   if (ctx->num_readers == 0 && ctx->RestoreDataRead) CeedCall(ctx->RestoreDataRead(ctx));
676   *(void **)data = NULL;
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