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