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