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