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