1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed-impl.h> 20 #include <stdint.h> 21 #include <stdio.h> 22 #include <string.h> 23 24 /// @file 25 /// Implementation of public CeedQFunctionContext interfaces 26 27 /// ---------------------------------------------------------------------------- 28 /// CeedQFunctionContext Library Internal Functions 29 /// ---------------------------------------------------------------------------- 30 /// @addtogroup CeedQFunctionDeveloper 31 /// @{ 32 33 /** 34 @brief Get index for QFunctionContext field 35 36 @param ctx CeedQFunctionContext 37 @param field_name Name of field 38 @param field_index Index of field, or -1 if field is not registered 39 40 @return An error code: 0 - success, otherwise - failure 41 42 @ref Developer 43 **/ 44 int CeedQFunctionContextGetFieldIndex(CeedQFunctionContext ctx, 45 const char *field_name, CeedInt *field_index) { 46 *field_index = -1; 47 for (CeedInt i=0; i<ctx->num_fields; i++) 48 if (!strcmp(ctx->field_descriptions[i].name, field_name)) 49 *field_index = i; 50 return CEED_ERROR_SUCCESS; 51 } 52 53 /** 54 @brief Common function for registering QFunctionContext fields 55 56 @param ctx CeedQFunctionContext 57 @param field_name Name of field to register 58 @param field_offset Offset of field to register 59 @param field_description Description of field, or NULL for none 60 @param field_type Field data type, such as double or int32 61 @param field_size Size of field, in bytes 62 63 @return An error code: 0 - success, otherwise - failure 64 65 @ref Developer 66 **/ 67 int CeedQFunctionContextRegisterGeneric(CeedQFunctionContext ctx, 68 const char *field_name, size_t field_offset, 69 const char *field_description, 70 CeedContextFieldType field_type, 71 size_t field_size) { 72 int ierr; 73 74 // Check for duplicate 75 CeedInt field_index = -1; 76 ierr = CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index); 77 CeedChk(ierr); 78 if (field_index != -1) 79 // LCOV_EXCL_START 80 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 81 "QFunctionContext field with name \"%s\" already registered", 82 field_name); 83 // LCOV_EXCL_STOP 84 85 // Allocate space for field data 86 if (ctx->num_fields == 0) { 87 ierr = CeedCalloc(1, &ctx->field_descriptions); CeedChk(ierr); 88 ctx->max_fields = 1; 89 } else if (ctx->num_fields == ctx->max_fields) { 90 ierr = CeedRealloc(2*ctx->max_fields, &ctx->field_descriptions); 91 CeedChk(ierr); 92 ctx->max_fields *= 2; 93 } 94 95 // Copy field data 96 { 97 size_t len = strlen(field_name); 98 char *tmp; 99 ierr = CeedCalloc(len + 1, &tmp); CeedChk(ierr); 100 memcpy(tmp, field_name, len+1); 101 ctx->field_descriptions[ctx->num_fields].name = tmp; 102 } 103 { 104 size_t len = strlen(field_description); 105 char *tmp; 106 ierr = CeedCalloc(len + 1, &tmp); CeedChk(ierr); 107 memcpy(tmp, field_description, len+1); 108 ctx->field_descriptions[ctx->num_fields].description = tmp; 109 } 110 ctx->field_descriptions[ctx->num_fields].type = field_type; 111 ctx->field_descriptions[ctx->num_fields].offset = field_offset; 112 ctx->field_descriptions[ctx->num_fields].size = field_size; 113 ctx->num_fields++; 114 115 return CEED_ERROR_SUCCESS; 116 } 117 118 /** 119 @brief Set QFunctionContext field holding a double precision value 120 121 @param ctx CeedQFunctionContext 122 @param field_name Name of field to set 123 @param field_type Type of field to set 124 @param value Value to set 125 126 @return An error code: 0 - success, otherwise - failure 127 128 @ref User 129 **/ 130 int CeedQFunctionContextSetGeneric(CeedQFunctionContext ctx, 131 const char *field_name, 132 CeedContextFieldType field_type, void *value) { 133 int ierr; 134 135 // Check field index 136 CeedInt field_index = -1; 137 ierr = CeedQFunctionContextGetFieldIndex(ctx, field_name, &field_index); 138 CeedChk(ierr); 139 if (field_index == -1) 140 // LCOV_EXCL_START 141 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 142 "QFunctionContext field with name \"%s\" not registered", 143 field_name); 144 // LCOV_EXCL_STOP 145 146 if (ctx->field_descriptions[field_index].type != field_type) 147 // LCOV_EXCL_START 148 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 149 "QFunctionContext field with name \"%s\" registered as %s, " 150 "not registered as %s", field_name, 151 CeedContextFieldTypes[ctx->field_descriptions[field_index].type], 152 CeedContextFieldTypes[field_type]); 153 // LCOV_EXCL_STOP 154 155 char *data; 156 ierr = CeedQFunctionContextGetData(ctx, CEED_MEM_HOST, &data); CeedChk(ierr); 157 memcpy(&data[ctx->field_descriptions[field_index].offset], value, 158 ctx->field_descriptions[field_index].size); 159 ierr = CeedQFunctionContextRestoreData(ctx, &data); CeedChk(ierr); 160 161 return CEED_ERROR_SUCCESS; 162 } 163 164 /// @} 165 166 /// ---------------------------------------------------------------------------- 167 /// CeedQFunctionContext Backend API 168 /// ---------------------------------------------------------------------------- 169 /// @addtogroup CeedQFunctionBackend 170 /// @{ 171 172 /** 173 @brief Get the Ceed associated with a CeedQFunctionContext 174 175 @param ctx CeedQFunctionContext 176 @param[out] ceed Variable to store Ceed 177 178 @return An error code: 0 - success, otherwise - failure 179 180 @ref Backend 181 **/ 182 int CeedQFunctionContextGetCeed(CeedQFunctionContext ctx, Ceed *ceed) { 183 *ceed = ctx->ceed; 184 return CEED_ERROR_SUCCESS; 185 } 186 187 /** 188 @brief Check for valid data in a CeedQFunctionContext 189 190 @param ctx CeedQFunctionContext to check validity 191 @param[out] has_valid_data Variable to store validity 192 193 @return An error code: 0 - success, otherwise - failure 194 195 @ref Backend 196 **/ 197 int CeedQFunctionContextHasValidData(CeedQFunctionContext ctx, 198 bool *has_valid_data) { 199 int ierr; 200 201 if (!ctx->HasValidData) 202 // LCOV_EXCL_START 203 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 204 "Backend does not support HasValidData"); 205 // LCOV_EXCL_STOP 206 207 ierr = ctx->HasValidData(ctx, has_valid_data); CeedChk(ierr); 208 209 return CEED_ERROR_SUCCESS; 210 } 211 212 /** 213 @brief Check for borrowed data of a specific CeedMemType in a 214 CeedQFunctionContext 215 216 @param ctx CeedQFunctionContext to check 217 @param mem_type Memory type to check 218 @param[out] has_borrowed_data_of_type Variable to store result 219 220 @return An error code: 0 - success, otherwise - failure 221 222 @ref Backend 223 **/ 224 int CeedQFunctionContextHasBorrowedDataOfType(CeedQFunctionContext ctx, 225 CeedMemType mem_type, bool *has_borrowed_data_of_type) { 226 int ierr; 227 228 if (!ctx->HasBorrowedDataOfType) 229 // LCOV_EXCL_START 230 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 231 "Backend does not support HasBorrowedDataOfType"); 232 // LCOV_EXCL_STOP 233 234 ierr = ctx->HasBorrowedDataOfType(ctx, mem_type, has_borrowed_data_of_type); 235 CeedChk(ierr); 236 237 return CEED_ERROR_SUCCESS; 238 } 239 240 /** 241 @brief Get the state of a CeedQFunctionContext 242 243 @param ctx CeedQFunctionContext to retrieve state 244 @param[out] state Variable to store state 245 246 @return An error code: 0 - success, otherwise - failure 247 248 @ref Backend 249 **/ 250 int CeedQFunctionContextGetState(CeedQFunctionContext ctx, uint64_t *state) { 251 *state = ctx->state; 252 return CEED_ERROR_SUCCESS; 253 } 254 255 /** 256 @brief Get backend data of a CeedQFunctionContext 257 258 @param ctx CeedQFunctionContext 259 @param[out] data Variable to store data 260 261 @return An error code: 0 - success, otherwise - failure 262 263 @ref Backend 264 **/ 265 int CeedQFunctionContextGetBackendData(CeedQFunctionContext ctx, void *data) { 266 *(void **)data = ctx->data; 267 return CEED_ERROR_SUCCESS; 268 } 269 270 /** 271 @brief Set backend data of a CeedQFunctionContext 272 273 @param[out] ctx CeedQFunctionContext 274 @param data Data to set 275 276 @return An error code: 0 - success, otherwise - failure 277 278 @ref Backend 279 **/ 280 int CeedQFunctionContextSetBackendData(CeedQFunctionContext ctx, void *data) { 281 ctx->data = data; 282 return CEED_ERROR_SUCCESS; 283 } 284 285 /** 286 @brief Increment the reference counter for a CeedQFunctionContext 287 288 @param ctx CeedQFunctionContext to increment the reference counter 289 290 @return An error code: 0 - success, otherwise - failure 291 292 @ref Backend 293 **/ 294 int CeedQFunctionContextReference(CeedQFunctionContext ctx) { 295 ctx->ref_count++; 296 return CEED_ERROR_SUCCESS; 297 } 298 299 /// @} 300 301 /// ---------------------------------------------------------------------------- 302 /// CeedQFunctionContext Public API 303 /// ---------------------------------------------------------------------------- 304 /// @addtogroup CeedQFunctionUser 305 /// @{ 306 307 /** 308 @brief Create a CeedQFunctionContext for storing CeedQFunction user context data 309 310 @param ceed A Ceed object where the CeedQFunctionContext will be created 311 @param[out] ctx Address of the variable where the newly created 312 CeedQFunctionContext will be stored 313 314 @return An error code: 0 - success, otherwise - failure 315 316 @ref User 317 **/ 318 int CeedQFunctionContextCreate(Ceed ceed, CeedQFunctionContext *ctx) { 319 int ierr; 320 321 if (!ceed->QFunctionContextCreate) { 322 Ceed delegate; 323 ierr = CeedGetObjectDelegate(ceed, &delegate, "Context"); CeedChk(ierr); 324 325 if (!delegate) 326 // LCOV_EXCL_START 327 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 328 "Backend does not support ContextCreate"); 329 // LCOV_EXCL_STOP 330 331 ierr = CeedQFunctionContextCreate(delegate, ctx); CeedChk(ierr); 332 return CEED_ERROR_SUCCESS; 333 } 334 335 ierr = CeedCalloc(1, ctx); CeedChk(ierr); 336 (*ctx)->ceed = ceed; 337 ierr = CeedReference(ceed); CeedChk(ierr); 338 (*ctx)->ref_count = 1; 339 ierr = ceed->QFunctionContextCreate(*ctx); CeedChk(ierr); 340 return CEED_ERROR_SUCCESS; 341 } 342 343 /** 344 @brief Copy the pointer to a CeedQFunctionContext. Both pointers should 345 be destroyed with `CeedQFunctionContextDestroy()`; 346 Note: If `*ctx_copy` is non-NULL, then it is assumed that 347 `*ctx_copy` is a pointer to a CeedQFunctionContext. This 348 CeedQFunctionContext will be destroyed if `*ctx_copy` is the 349 only reference to this CeedQFunctionContext. 350 351 @param ctx CeedQFunctionContext to copy reference to 352 @param[out] ctx_copy Variable to store copied reference 353 354 @return An error code: 0 - success, otherwise - failure 355 356 @ref User 357 **/ 358 int CeedQFunctionContextReferenceCopy(CeedQFunctionContext ctx, 359 CeedQFunctionContext *ctx_copy) { 360 int ierr; 361 362 ierr = CeedQFunctionContextReference(ctx); CeedChk(ierr); 363 ierr = CeedQFunctionContextDestroy(ctx_copy); CeedChk(ierr); 364 *ctx_copy = ctx; 365 return CEED_ERROR_SUCCESS; 366 } 367 368 /** 369 @brief Set the data used by a CeedQFunctionContext, freeing any previously allocated 370 data if applicable. The backend may copy values to a different 371 memtype, such as during @ref CeedQFunctionApply(). 372 See also @ref CeedQFunctionContextTakeData(). 373 374 @param ctx CeedQFunctionContext 375 @param mem_type Memory type of the data being passed 376 @param copy_mode Copy mode for the data 377 @param size Size of data, in bytes 378 @param data Data to be used 379 380 @return An error code: 0 - success, otherwise - failure 381 382 @ref User 383 **/ 384 int CeedQFunctionContextSetData(CeedQFunctionContext ctx, CeedMemType mem_type, 385 CeedCopyMode copy_mode, 386 size_t size, void *data) { 387 int ierr; 388 389 if (!ctx->SetData) 390 // LCOV_EXCL_START 391 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 392 "Backend does not support ContextSetData"); 393 // LCOV_EXCL_STOP 394 395 if (ctx->state % 2 == 1) 396 // LCOV_EXCL_START 397 return CeedError(ctx->ceed, 1, 398 "Cannot grant CeedQFunctionContext data access, the " 399 "access lock is already in use"); 400 // LCOV_EXCL_STOP 401 402 ctx->ctx_size = size; 403 ierr = ctx->SetData(ctx, mem_type, copy_mode, data); CeedChk(ierr); 404 ctx->state += 2; 405 return CEED_ERROR_SUCCESS; 406 } 407 408 /** 409 @brief Take ownership of the data in a CeedQFunctionContext via the specified memory type. 410 The caller is responsible for managing and freeing the memory. 411 412 @param ctx CeedQFunctionContext to access 413 @param mem_type Memory type on which to access the data. If the backend 414 uses a different memory type, this will perform a copy. 415 @param[out] data Data on memory type mem_type 416 417 @return An error code: 0 - success, otherwise - failure 418 419 @ref User 420 **/ 421 int CeedQFunctionContextTakeData(CeedQFunctionContext ctx, CeedMemType mem_type, 422 void *data) { 423 int ierr; 424 425 bool has_valid_data = true; 426 ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr); 427 if (!has_valid_data) 428 // LCOV_EXCL_START 429 return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 430 "CeedQFunctionContext has no valid data to take, must set data"); 431 // LCOV_EXCL_STOP 432 433 if (!ctx->TakeData) 434 // LCOV_EXCL_START 435 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 436 "Backend does not support TakeData"); 437 // LCOV_EXCL_STOP 438 439 if (ctx->state % 2 == 1) 440 // LCOV_EXCL_START 441 return CeedError(ctx->ceed, 1, 442 "Cannot grant CeedQFunctionContext data access, the " 443 "access lock is already in use"); 444 // LCOV_EXCL_STOP 445 446 bool has_borrowed_data_of_type = true; 447 ierr = CeedQFunctionContextHasBorrowedDataOfType(ctx, mem_type, 448 &has_borrowed_data_of_type); CeedChk(ierr); 449 if (!has_borrowed_data_of_type) 450 // LCOV_EXCL_START 451 return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 452 "CeedQFunctionContext has no borowed %s data, " 453 "must set data with CeedQFunctionContextSetData", 454 CeedMemTypes[mem_type]); 455 // LCOV_EXCL_STOP 456 457 void *temp_data = NULL; 458 ierr = ctx->TakeData(ctx, mem_type, &temp_data); CeedChk(ierr); 459 if (data) (*(void **)data) = temp_data; 460 return CEED_ERROR_SUCCESS; 461 } 462 463 /** 464 @brief Get read/write access to a CeedQFunctionContext via the specified memory type. 465 Restore access with @ref CeedQFunctionContextRestoreData(). 466 467 @param ctx CeedQFunctionContext to access 468 @param mem_type Memory type on which to access the data. If the backend 469 uses a different memory type, this will perform a copy. 470 @param[out] data Data on memory type mem_type 471 472 @note The CeedQFunctionContextGetData() and @ref CeedQFunctionContextRestoreData() functions 473 provide access to array pointers in the desired memory space. Pairing 474 get/restore allows the Context to track access. 475 476 @return An error code: 0 - success, otherwise - failure 477 478 @ref User 479 **/ 480 int CeedQFunctionContextGetData(CeedQFunctionContext ctx, CeedMemType mem_type, 481 void *data) { 482 int ierr; 483 484 if (!ctx->GetData) 485 // LCOV_EXCL_START 486 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 487 "Backend does not support GetData"); 488 // LCOV_EXCL_STOP 489 490 if (ctx->state % 2 == 1) 491 // LCOV_EXCL_START 492 return CeedError(ctx->ceed, 1, 493 "Cannot grant CeedQFunctionContext data access, the " 494 "access lock is already in use"); 495 // LCOV_EXCL_STOP 496 497 bool has_valid_data = true; 498 ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr); 499 if (!has_valid_data) 500 // LCOV_EXCL_START 501 return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 502 "CeedQFunctionContext has no valid data to get, must set data"); 503 // LCOV_EXCL_STOP 504 505 ierr = ctx->GetData(ctx, mem_type, data); CeedChk(ierr); 506 ctx->state += 1; 507 return CEED_ERROR_SUCCESS; 508 } 509 510 /** 511 @brief Restore data obtained using @ref CeedQFunctionContextGetData() 512 513 @param ctx CeedQFunctionContext to restore 514 @param data Data to restore 515 516 @return An error code: 0 - success, otherwise - failure 517 518 @ref User 519 **/ 520 int CeedQFunctionContextRestoreData(CeedQFunctionContext ctx, void *data) { 521 int ierr; 522 523 if (!ctx->RestoreData) 524 // LCOV_EXCL_START 525 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 526 "Backend does not support RestoreData"); 527 // LCOV_EXCL_STOP 528 529 if (ctx->state % 2 != 1) 530 // LCOV_EXCL_START 531 return CeedError(ctx->ceed, 1, 532 "Cannot restore CeedQFunctionContext array access, " 533 "access was not granted"); 534 // LCOV_EXCL_STOP 535 536 ierr = ctx->RestoreData(ctx); CeedChk(ierr); 537 *(void **)data = NULL; 538 ctx->state += 1; 539 return CEED_ERROR_SUCCESS; 540 } 541 542 /** 543 @brief Register QFunctionContext a field holding a double precision value 544 545 @param ctx CeedQFunctionContext 546 @param field_name Name of field to register 547 @param field_offset Offset of field to register 548 @param field_description Description of field, or NULL for none 549 550 @return An error code: 0 - success, otherwise - failure 551 552 @ref User 553 **/ 554 int CeedQFunctionContextRegisterDouble(CeedQFunctionContext ctx, 555 const char *field_name, size_t field_offset, 556 const char *field_description) { 557 return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset, 558 field_description, CEED_CONTEXT_FIELD_DOUBLE, sizeof(double)); 559 } 560 561 /** 562 @brief Register QFunctionContext a field holding a int32 value 563 564 @param ctx CeedQFunctionContext 565 @param field_name Name of field to register 566 @param field_offset Offset of field to register 567 @param field_description Description of field, or NULL for none 568 569 @return An error code: 0 - success, otherwise - failure 570 571 @ref User 572 **/ 573 int CeedQFunctionContextRegisterInt32(CeedQFunctionContext ctx, 574 const char *field_name, size_t field_offset, 575 const char *field_description) { 576 return CeedQFunctionContextRegisterGeneric(ctx, field_name, field_offset, 577 field_description, CEED_CONTEXT_FIELD_INT32, sizeof(int)); 578 } 579 580 /** 581 @brief Get descriptions for registered QFunctionContext fields 582 583 @param ctx CeedQFunctionContext 584 @param[out] field_descriptions Variable to hold array of field descriptions 585 @param[out] num_fields Length of field descriptions array 586 587 @return An error code: 0 - success, otherwise - failure 588 589 @ref User 590 **/ 591 int CeedQFunctionContextGetFieldDescriptions(CeedQFunctionContext ctx, 592 const CeedQFunctionContextFieldDescription **field_descriptions, 593 CeedInt *num_fields) { 594 *field_descriptions = ctx->field_descriptions; 595 *num_fields = ctx->num_fields; 596 return CEED_ERROR_SUCCESS; 597 } 598 599 /** 600 @brief Set QFunctionContext field holding a double precision value 601 602 @param ctx CeedQFunctionContext 603 @param field_name Name of field to register 604 @param value Value to set 605 606 @return An error code: 0 - success, otherwise - failure 607 608 @ref User 609 **/ 610 int CeedQFunctionContextSetDouble(CeedQFunctionContext ctx, 611 const char *field_name, double value) { 612 return CeedQFunctionContextSetGeneric(ctx, field_name, 613 CEED_CONTEXT_FIELD_DOUBLE, 614 &value); 615 } 616 617 /** 618 @brief Set QFunctionContext field holding a int32 value 619 620 @param ctx CeedQFunctionContext 621 @param field_name Name of field to set 622 @param value Value to set 623 624 @return An error code: 0 - success, otherwise - failure 625 626 @ref User 627 **/ 628 int CeedQFunctionContextSetInt32(CeedQFunctionContext ctx, 629 const char *field_name, int value) { 630 return CeedQFunctionContextSetGeneric(ctx, field_name, CEED_CONTEXT_FIELD_INT32, 631 &value); 632 } 633 634 /** 635 @brief Get data size for a Context 636 637 @param ctx CeedQFunctionContext 638 @param[out] ctx_size Variable to store size of context data values 639 640 @return An error code: 0 - success, otherwise - failure 641 642 @ref User 643 **/ 644 int CeedQFunctionContextGetContextSize(CeedQFunctionContext ctx, 645 size_t *ctx_size) { 646 *ctx_size = ctx->ctx_size; 647 return CEED_ERROR_SUCCESS; 648 } 649 650 651 /** 652 @brief View a CeedQFunctionContext 653 654 @param[in] ctx CeedQFunctionContext to view 655 @param[in] stream Filestream to write to 656 657 @return An error code: 0 - success, otherwise - failure 658 659 @ref User 660 **/ 661 int CeedQFunctionContextView(CeedQFunctionContext ctx, FILE *stream) { 662 fprintf(stream, "CeedQFunctionContext\n"); 663 fprintf(stream, " Context Data Size: %ld\n", ctx->ctx_size); 664 return CEED_ERROR_SUCCESS; 665 } 666 667 /** 668 @brief Destroy a CeedQFunctionContext 669 670 @param ctx CeedQFunctionContext to destroy 671 672 @return An error code: 0 - success, otherwise - failure 673 674 @ref User 675 **/ 676 int CeedQFunctionContextDestroy(CeedQFunctionContext *ctx) { 677 int ierr; 678 679 if (!*ctx || --(*ctx)->ref_count > 0) 680 return CEED_ERROR_SUCCESS; 681 682 if ((*ctx) && ((*ctx)->state % 2) == 1) 683 // LCOV_EXCL_START 684 return CeedError((*ctx)->ceed, 1, 685 "Cannot destroy CeedQFunctionContext, the access " 686 "lock is in use"); 687 // LCOV_EXCL_STOP 688 689 if ((*ctx)->Destroy) { 690 ierr = (*ctx)->Destroy(*ctx); CeedChk(ierr); 691 } 692 for (CeedInt i=0; i<(*ctx)->num_fields; i++) { 693 ierr = CeedFree(&(*ctx)->field_descriptions[i].name); CeedChk(ierr); 694 ierr = CeedFree(&(*ctx)->field_descriptions[i].description); CeedChk(ierr); 695 } 696 ierr = CeedFree(&(*ctx)->field_descriptions); CeedChk(ierr); 697 ierr = CeedDestroy(&(*ctx)->ceed); CeedChk(ierr); 698 ierr = CeedFree(ctx); CeedChk(ierr); 699 700 return CEED_ERROR_SUCCESS; 701 } 702 703 /// @} 704