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