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