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 #define _POSIX_C_SOURCE 200112 9 #include <ceed/ceed.h> 10 #include <ceed/backend.h> 11 #include <ceed-impl.h> 12 #include <limits.h> 13 #include <stdarg.h> 14 #include <stddef.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 /// @cond DOXYGEN_SKIP 20 static CeedRequest ceed_request_immediate; 21 static CeedRequest ceed_request_ordered; 22 23 static struct { 24 char prefix[CEED_MAX_RESOURCE_LEN]; 25 int (*init)(const char *resource, Ceed f); 26 unsigned int priority; 27 } backends[32]; 28 static size_t num_backends; 29 30 #define CEED_FTABLE_ENTRY(class, method) \ 31 {#class #method, offsetof(struct class ##_private, method)} 32 /// @endcond 33 34 /// @file 35 /// Implementation of core components of Ceed library 36 37 /// @addtogroup CeedUser 38 /// @{ 39 40 /** 41 @brief Request immediate completion 42 43 This predefined constant is passed as the \ref CeedRequest argument to 44 interfaces when the caller wishes for the operation to be performed 45 immediately. The code 46 47 @code 48 CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 49 @endcode 50 51 is semantically equivalent to 52 53 @code 54 CeedRequest request; 55 CeedOperatorApply(op, ..., &request); 56 CeedRequestWait(&request); 57 @endcode 58 59 @sa CEED_REQUEST_ORDERED 60 **/ 61 CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 62 63 /** 64 @brief Request ordered completion 65 66 This predefined constant is passed as the \ref CeedRequest argument to 67 interfaces when the caller wishes for the operation to be completed in the 68 order that it is submitted to the device. It is typically used in a construct 69 such as 70 71 @code 72 CeedRequest request; 73 CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 74 CeedOperatorApply(op2, ..., &request); 75 // other optional work 76 CeedRequestWait(&request); 77 @endcode 78 79 which allows the sequence to complete asynchronously but does not start 80 `op2` until `op1` has completed. 81 82 @todo The current implementation is overly strict, offering equivalent 83 semantics to @ref CEED_REQUEST_IMMEDIATE. 84 85 @sa CEED_REQUEST_IMMEDIATE 86 */ 87 CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 88 89 /** 90 @brief Wait for a CeedRequest to complete. 91 92 Calling CeedRequestWait on a NULL request is a no-op. 93 94 @param req Address of CeedRequest to wait for; zeroed on completion. 95 96 @return An error code: 0 - success, otherwise - failure 97 98 @ref User 99 **/ 100 int CeedRequestWait(CeedRequest *req) { 101 if (!*req) 102 return CEED_ERROR_SUCCESS; 103 return CeedError(NULL, CEED_ERROR_UNSUPPORTED, 104 "CeedRequestWait not implemented"); 105 } 106 107 /// @} 108 109 /// ---------------------------------------------------------------------------- 110 /// Ceed Library Internal Functions 111 /// ---------------------------------------------------------------------------- 112 /// @addtogroup CeedDeveloper 113 /// @{ 114 115 /** 116 @brief Register a Ceed backend internally. 117 Note: Backends should call `CeedRegister` instead. 118 119 @param prefix Prefix of resources for this backend to respond to. For 120 example, the reference backend responds to "/cpu/self". 121 @param init Initialization function called by CeedInit() when the backend 122 is selected to drive the requested resource. 123 @param priority Integer priority. Lower values are preferred in case the 124 resource requested by CeedInit() has non-unique best prefix 125 match. 126 127 @return An error code: 0 - success, otherwise - failure 128 129 @ref Developer 130 **/ 131 int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), 132 unsigned int priority) { 133 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 134 // LCOV_EXCL_START 135 return CeedError(NULL, CEED_ERROR_MAJOR, "Too many backends"); 136 // LCOV_EXCL_STOP 137 138 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 139 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 140 backends[num_backends].init = init; 141 backends[num_backends].priority = priority; 142 num_backends++; 143 return CEED_ERROR_SUCCESS; 144 } 145 146 /// @} 147 148 /// ---------------------------------------------------------------------------- 149 /// Ceed Backend API 150 /// ---------------------------------------------------------------------------- 151 /// @addtogroup CeedBackend 152 /// @{ 153 154 /** 155 @brief Return value of CEED_DEBUG environment variable 156 157 @param ceed Ceed context 158 159 @return boolean value: true - debugging mode enabled 160 false - debugging mode disabled 161 162 @ref Backend 163 **/ 164 // LCOV_EXCL_START 165 bool CeedDebugFlag(const Ceed ceed) { 166 return ceed->is_debug; 167 } 168 // LCOV_EXCL_STOP 169 170 /** 171 @brief Return value of CEED_DEBUG environment variable 172 173 @return boolean value: true - debugging mode enabled 174 false - debugging mode disabled 175 176 @ref Backend 177 **/ 178 // LCOV_EXCL_START 179 bool CeedDebugFlagEnv(void) { 180 return !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG"); 181 } 182 // LCOV_EXCL_STOP 183 184 /** 185 @brief Print debugging information in color 186 187 @param color Color to print 188 @param format Printing format 189 190 @ref Backend 191 **/ 192 // LCOV_EXCL_START 193 void CeedDebugImpl256(const unsigned char color, const char *format,...) { 194 va_list args; 195 va_start(args, format); 196 fflush(stdout); 197 if (color != CEED_DEBUG_COLOR_NONE) 198 fprintf(stdout, "\033[38;5;%dm", color); 199 vfprintf(stdout, format, args); 200 if (color != CEED_DEBUG_COLOR_NONE) 201 fprintf(stdout, "\033[m"); 202 fprintf(stdout, "\n"); 203 fflush(stdout); 204 va_end(args); 205 } 206 // LCOV_EXCL_STOP 207 208 /** 209 @brief Allocate an array on the host; use CeedMalloc() 210 211 Memory usage can be tracked by the library. This ensures sufficient 212 alignment for vectorization and should be used for large allocations. 213 214 @param n Number of units to allocate 215 @param unit Size of each unit 216 @param p Address of pointer to hold the result. 217 218 @return An error code: 0 - success, otherwise - failure 219 220 @sa CeedFree() 221 222 @ref Backend 223 **/ 224 int CeedMallocArray(size_t n, size_t unit, void *p) { 225 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 226 if (ierr) 227 // LCOV_EXCL_START 228 return CeedError(NULL, CEED_ERROR_MAJOR, 229 "posix_memalign failed to allocate %zd " 230 "members of size %zd\n", n, unit); 231 // LCOV_EXCL_STOP 232 return CEED_ERROR_SUCCESS; 233 } 234 235 /** 236 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 237 238 Memory usage can be tracked by the library. 239 240 @param n Number of units to allocate 241 @param unit Size of each unit 242 @param p Address of pointer to hold the result. 243 244 @return An error code: 0 - success, otherwise - failure 245 246 @sa CeedFree() 247 248 @ref Backend 249 **/ 250 int CeedCallocArray(size_t n, size_t unit, void *p) { 251 *(void **)p = calloc(n, unit); 252 if (n && unit && !*(void **)p) 253 // LCOV_EXCL_START 254 return CeedError(NULL, CEED_ERROR_MAJOR, 255 "calloc failed to allocate %zd members of size " 256 "%zd\n", n, unit); 257 // LCOV_EXCL_STOP 258 return CEED_ERROR_SUCCESS; 259 } 260 261 /** 262 @brief Reallocate an array on the host; use CeedRealloc() 263 264 Memory usage can be tracked by the library. 265 266 @param n Number of units to allocate 267 @param unit Size of each unit 268 @param p Address of pointer to hold the result. 269 270 @return An error code: 0 - success, otherwise - failure 271 272 @sa CeedFree() 273 274 @ref Backend 275 **/ 276 int CeedReallocArray(size_t n, size_t unit, void *p) { 277 *(void **)p = realloc(*(void **)p, n*unit); 278 if (n && unit && !*(void **)p) 279 // LCOV_EXCL_START 280 return CeedError(NULL, CEED_ERROR_MAJOR, 281 "realloc failed to allocate %zd members of size " 282 "%zd\n", n, unit); 283 // LCOV_EXCL_STOP 284 return CEED_ERROR_SUCCESS; 285 } 286 287 /** 288 @brief Allocate a cleared string buffer on the host 289 290 Memory usage can be tracked by the library. 291 292 @param source Pointer to string to be copied 293 @param copy Pointer to variable to hold newly allocated string copy 294 295 @return An error code: 0 - success, otherwise - failure 296 297 @sa CeedFree() 298 299 @ref Backend 300 **/ 301 int CeedStringAllocCopy(const char *source, char **copy) { 302 int ierr; 303 size_t len = strlen(source); 304 ierr = CeedCalloc(len + 1, copy); CeedChk(ierr); 305 memcpy(*copy, source, len); 306 return CEED_ERROR_SUCCESS; 307 } 308 309 /** Free memory allocated using CeedMalloc() or CeedCalloc() 310 311 @param p address of pointer to memory. This argument is of type void* to 312 avoid needing a cast, but is the address of the pointer (which is 313 zeroed) rather than the pointer. 314 **/ 315 int CeedFree(void *p) { 316 free(*(void **)p); 317 *(void **)p = NULL; 318 return CEED_ERROR_SUCCESS; 319 } 320 321 /** 322 @brief Register a Ceed backend 323 324 @param prefix Prefix of resources for this backend to respond to. For 325 example, the reference backend responds to "/cpu/self". 326 @param init Initialization function called by CeedInit() when the backend 327 is selected to drive the requested resource. 328 @param priority Integer priority. Lower values are preferred in case the 329 resource requested by CeedInit() has non-unique best prefix 330 match. 331 332 @return An error code: 0 - success, otherwise - failure 333 334 @ref Backend 335 **/ 336 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 337 unsigned int priority) { 338 CeedDebugEnv("Backend Register: %s", prefix); 339 CeedRegisterImpl(prefix, init, priority); 340 return CEED_ERROR_SUCCESS; 341 } 342 343 /** 344 @brief Return debugging status flag 345 346 @param ceed Ceed context to get debugging flag 347 @param is_debug Variable to store debugging flag 348 349 @return An error code: 0 - success, otherwise - failure 350 351 @ref Backend 352 **/ 353 int CeedIsDebug(Ceed ceed, bool *is_debug) { 354 *is_debug = ceed->is_debug; 355 return CEED_ERROR_SUCCESS; 356 } 357 358 /** 359 @brief Retrieve a parent Ceed context 360 361 @param ceed Ceed context to retrieve parent of 362 @param[out] parent Address to save the parent to 363 364 @return An error code: 0 - success, otherwise - failure 365 366 @ref Backend 367 **/ 368 int CeedGetParent(Ceed ceed, Ceed *parent) { 369 int ierr; 370 if (ceed->parent) { 371 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 372 return CEED_ERROR_SUCCESS; 373 } 374 *parent = ceed; 375 return CEED_ERROR_SUCCESS; 376 } 377 378 /** 379 @brief Retrieve a delegate Ceed context 380 381 @param ceed Ceed context to retrieve delegate of 382 @param[out] delegate Address to save the delegate to 383 384 @return An error code: 0 - success, otherwise - failure 385 386 @ref Backend 387 **/ 388 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 389 *delegate = ceed->delegate; 390 return CEED_ERROR_SUCCESS; 391 } 392 393 /** 394 @brief Set a delegate Ceed context 395 396 This function allows a Ceed context to set a delegate Ceed context. All 397 backend implementations default to the delegate Ceed context, unless 398 overridden. 399 400 @param ceed Ceed context to set delegate of 401 @param[out] delegate Address to set the delegate to 402 403 @return An error code: 0 - success, otherwise - failure 404 405 @ref Backend 406 **/ 407 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 408 ceed->delegate = delegate; 409 delegate->parent = ceed; 410 return CEED_ERROR_SUCCESS; 411 } 412 413 /** 414 @brief Retrieve a delegate Ceed context for a specific object type 415 416 @param ceed Ceed context to retrieve delegate of 417 @param[out] delegate Address to save the delegate to 418 @param[in] obj_name Name of the object type to retrieve delegate for 419 420 @return An error code: 0 - success, otherwise - failure 421 422 @ref Backend 423 **/ 424 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) { 425 CeedInt ierr; 426 427 // Check for object delegate 428 for (CeedInt i=0; i<ceed->obj_delegate_count; i++) 429 if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) { 430 *delegate = ceed->obj_delegates->delegate; 431 return CEED_ERROR_SUCCESS; 432 } 433 434 // Use default delegate if no object delegate 435 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 436 return CEED_ERROR_SUCCESS; 437 } 438 439 /** 440 @brief Set a delegate Ceed context for a specific object type 441 442 This function allows a Ceed context to set a delegate Ceed context for a 443 given type of Ceed object. All backend implementations default to the 444 delegate Ceed context for this object. For example, 445 CeedSetObjectDelegate(ceed, refceed, "Basis") 446 uses refceed implementations for all CeedBasis backend functions. 447 448 @param ceed Ceed context to set delegate of 449 @param[out] delegate Address to set the delegate to 450 @param[in] obj_name Name of the object type to set delegate for 451 452 @return An error code: 0 - success, otherwise - failure 453 454 @ref Backend 455 **/ 456 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) { 457 int ierr; 458 CeedInt count = ceed->obj_delegate_count; 459 460 // Malloc or Realloc 461 if (count) { 462 ierr = CeedRealloc(count+1, &ceed->obj_delegates); CeedChk(ierr); 463 } else { 464 ierr = CeedCalloc(1, &ceed->obj_delegates); CeedChk(ierr); 465 } 466 ceed->obj_delegate_count++; 467 468 // Set object delegate 469 ceed->obj_delegates[count].delegate = delegate; 470 ierr = CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name); 471 CeedChk(ierr); 472 473 // Set delegate parent 474 delegate->parent = ceed; 475 return CEED_ERROR_SUCCESS; 476 } 477 478 /** 479 @brief Get the fallback resource for CeedOperators 480 481 @param ceed Ceed context 482 @param[out] resource Variable to store fallback resource 483 484 @return An error code: 0 - success, otherwise - failure 485 486 @ref Backend 487 **/ 488 489 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 490 *resource = (const char *)ceed->op_fallback_resource; 491 return CEED_ERROR_SUCCESS; 492 } 493 494 /** 495 @brief Get the fallback Ceed for CeedOperators 496 497 @param ceed Ceed context 498 @param[out] fallback_ceed Variable to store fallback Ceed 499 500 @return An error code: 0 - success, otherwise - failure 501 502 @ref Backend 503 **/ 504 505 int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) { 506 int ierr; 507 508 if (ceed->has_valid_op_fallback_resource) { 509 CeedDebug256(ceed, 1, "---------- CeedOperator Fallback ----------\n"); 510 CeedDebug256(ceed, 255, "Getting fallback from %s to %s\n", ceed->resource, 511 ceed->op_fallback_resource); 512 } 513 514 // Create fallback Ceed if uninitalized 515 if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) { 516 CeedDebug256(ceed, 255, "Creating fallback Ceed"); 517 518 Ceed fallback_ceed; 519 const char *fallback_resource; 520 521 ierr = CeedGetOperatorFallbackResource(ceed, &fallback_resource); CeedChk(ierr); 522 ierr = CeedInit(fallback_resource, &fallback_ceed); CeedChk(ierr); 523 fallback_ceed->op_fallback_parent = ceed; 524 fallback_ceed->Error = ceed->Error; 525 ceed->op_fallback_ceed = fallback_ceed; 526 } 527 *fallback_ceed = ceed->op_fallback_ceed; 528 529 return CEED_ERROR_SUCCESS; 530 } 531 532 /** 533 @brief Set the fallback resource for CeedOperators. The current resource, if 534 any, is freed by calling this function. This string is freed upon the 535 destruction of the Ceed context. 536 537 @param[out] ceed Ceed context 538 @param resource Fallback resource to set 539 540 @return An error code: 0 - success, otherwise - failure 541 542 @ref Backend 543 **/ 544 545 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 546 int ierr; 547 548 // Free old 549 ierr = CeedFree(&ceed->op_fallback_resource); CeedChk(ierr); 550 551 // Set new 552 ierr = CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource); 553 CeedChk(ierr); 554 555 // Check validity 556 ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && 557 ceed->resource && 558 strcmp(ceed->op_fallback_resource, ceed->resource); 559 560 return CEED_ERROR_SUCCESS; 561 } 562 563 /** 564 @brief Get the parent Ceed context associated with a fallback Ceed context 565 for a CeedOperator 566 567 @param ceed Ceed context 568 @param[out] parent Variable to store parent Ceed context 569 570 @return An error code: 0 - success, otherwise - failure 571 572 @ref Backend 573 **/ 574 575 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 576 *parent = ceed->op_fallback_parent; 577 return CEED_ERROR_SUCCESS; 578 } 579 580 /** 581 @brief Flag Ceed context as deterministic 582 583 @param ceed Ceed to flag as deterministic 584 @param[out] is_deterministic Deterministic status to set 585 586 @return An error code: 0 - success, otherwise - failure 587 588 @ref Backend 589 **/ 590 591 int CeedSetDeterministic(Ceed ceed, bool is_deterministic) { 592 ceed->is_deterministic = is_deterministic; 593 return CEED_ERROR_SUCCESS; 594 } 595 596 /** 597 @brief Set a backend function 598 599 This function is used for a backend to set the function associated with 600 the Ceed objects. For example, 601 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 602 sets the backend implementation of 'CeedVectorCreate' and 603 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 604 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 605 is not required for the object type ("Basis" vs "CeedBasis"). 606 607 @param ceed Ceed context for error handling 608 @param type Type of Ceed object to set function for 609 @param[out] object Ceed object to set function for 610 @param func_name Name of function to set 611 @param f Function to set 612 613 @return An error code: 0 - success, otherwise - failure 614 615 @ref Backend 616 **/ 617 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 618 const char *func_name, int (*f)()) { 619 char lookup_name[CEED_MAX_RESOURCE_LEN+1] = ""; 620 621 // Build lookup name 622 if (strcmp(type, "Ceed")) 623 strncat (lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN); 624 strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN); 625 strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN); 626 627 // Find and use offset 628 for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) 629 if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) { 630 size_t offset = ceed->f_offsets[i].offset; 631 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 632 *fpointer = f; 633 return CEED_ERROR_SUCCESS; 634 } 635 636 // LCOV_EXCL_START 637 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 638 "Requested function '%s' was not found for CEED " 639 "object '%s'", func_name, type); 640 // LCOV_EXCL_STOP 641 } 642 643 /** 644 @brief Retrieve backend data for a Ceed context 645 646 @param ceed Ceed context to retrieve data of 647 @param[out] data Address to save data to 648 649 @return An error code: 0 - success, otherwise - failure 650 651 @ref Backend 652 **/ 653 int CeedGetData(Ceed ceed, void *data) { 654 *(void **)data = ceed->data; 655 return CEED_ERROR_SUCCESS; 656 } 657 658 /** 659 @brief Set backend data for a Ceed context 660 661 @param ceed Ceed context to set data of 662 @param data Address of data to set 663 664 @return An error code: 0 - success, otherwise - failure 665 666 @ref Backend 667 **/ 668 int CeedSetData(Ceed ceed, void *data) { 669 ceed->data = data; 670 return CEED_ERROR_SUCCESS; 671 } 672 673 /** 674 @brief Increment the reference counter for a Ceed context 675 676 @param ceed Ceed context to increment the reference counter 677 678 @return An error code: 0 - success, otherwise - failure 679 680 @ref Backend 681 **/ 682 int CeedReference(Ceed ceed) { 683 ceed->ref_count++; 684 return CEED_ERROR_SUCCESS; 685 } 686 687 /// @} 688 689 /// ---------------------------------------------------------------------------- 690 /// Ceed Public API 691 /// ---------------------------------------------------------------------------- 692 /// @addtogroup CeedUser 693 /// @{ 694 695 /** 696 @brief Get the list of available resource names for Ceed contexts 697 Note: The caller is responsible for `free()`ing the resources and priorities arrays, 698 but should not `free()` the contents of the resources array. 699 700 @param[out] n Number of available resources 701 @param[out] resources List of available resource names 702 @param[out] priorities Resource name prioritization values, lower is better 703 704 @return An error code: 0 - success, otherwise - failure 705 706 @ref User 707 **/ 708 // LCOV_EXCL_START 709 int CeedRegistryGetList(size_t *n, char ***const resources, 710 CeedInt **priorities) { 711 *n = 0; 712 *resources = malloc(num_backends * sizeof(**resources)); 713 if (!resources) 714 return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure"); 715 if (priorities) { 716 *priorities = malloc(num_backends * sizeof(**priorities)); 717 if (!priorities) 718 return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure"); 719 } 720 for (size_t i=0; i<num_backends; i++) { 721 // Only report compiled backends 722 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) { 723 *resources[i] = backends[i].prefix; 724 if (priorities) *priorities[i] = backends[i].priority; 725 *n += 1; 726 } 727 } 728 if (*n == 0) 729 // LCOV_EXCL_START 730 return CeedError(NULL, CEED_ERROR_MAJOR, "No backends installed"); 731 // LCOV_EXCL_STOP 732 *resources = realloc(*resources, *n * sizeof(**resources)); 733 if (!resources) 734 return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure"); 735 if (priorities) { 736 *priorities = realloc(*priorities, *n * sizeof(**priorities)); 737 if (!priorities) 738 return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure"); 739 } 740 return CEED_ERROR_SUCCESS; 741 } 742 // LCOV_EXCL_STOP 743 744 /** 745 @brief Initialize a \ref Ceed context to use the specified resource. 746 Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self") 747 will result in CeedInt printing the current libCEED version number 748 and a list of current available backend resources to stderr. 749 750 @param resource Resource to use, e.g., "/cpu/self" 751 @param ceed The library context 752 @sa CeedRegister() CeedDestroy() 753 754 @return An error code: 0 - success, otherwise - failure 755 756 @ref User 757 **/ 758 int CeedInit(const char *resource, Ceed *ceed) { 759 int ierr; 760 size_t match_len = 0, match_index = UINT_MAX, 761 match_priority = CEED_MAX_BACKEND_PRIORITY, priority; 762 763 // Find matching backend 764 if (!resource) 765 // LCOV_EXCL_START 766 return CeedError(NULL, CEED_ERROR_MAJOR, "No resource provided"); 767 // LCOV_EXCL_STOP 768 ierr = CeedRegisterAll(); CeedChk(ierr); 769 770 // Check for help request 771 const char *help_prefix = "help"; 772 size_t match_help; 773 for (match_help=0; match_help<4 774 && resource[match_help] == help_prefix[match_help]; match_help++) {} 775 if (match_help == 4) { 776 fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, 777 CEED_VERSION_MINOR, CEED_VERSION_PATCH, 778 CEED_VERSION_RELEASE ? "" : "+development"); 779 fprintf(stderr, "Available backend resources:\n"); 780 for (size_t i=0; i<num_backends; i++) { 781 // Only report compiled backends 782 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) 783 fprintf(stderr, " %s\n", backends[i].prefix); 784 } 785 fflush(stderr); 786 match_help = 5; // Delineating character expected 787 } else { 788 match_help = 0; 789 } 790 791 // Find best match, computed as number of matching characters 792 // from requested resource stem 793 size_t stem_length; 794 for (stem_length=0; resource[stem_length+match_help] 795 && resource[stem_length+match_help] != ':'; stem_length++) {} 796 for (size_t i=0; i<num_backends; i++) { 797 size_t n; 798 const char *prefix = backends[i].prefix; 799 for (n=0; prefix[n] && prefix[n] == resource[n+match_help]; n++) {} 800 priority = backends[i].priority; 801 if (n > match_len || (n == match_len && match_priority > priority)) { 802 match_len = n; 803 match_priority = priority; 804 match_index = i; 805 } 806 } 807 // Using Levenshtein distance to find closest match 808 if (match_len <= 1 || match_len != stem_length) { 809 // LCOV_EXCL_START 810 size_t lev_dis = UINT_MAX; 811 size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY; 812 for (size_t i=0; i<num_backends; i++) { 813 const char *prefix = backends[i].prefix; 814 size_t prefix_length = strlen(backends[i].prefix); 815 size_t min_len = (prefix_length < stem_length) ? prefix_length : stem_length; 816 size_t column[min_len+1]; 817 for (size_t j=0; j<=min_len; j++) column[j] = j; 818 for (size_t j=1; j<=min_len; j++) { 819 column[0] = j; 820 for (size_t k=1, last_diag=j-1; k<=min_len; k++) { 821 size_t old_diag = column[k]; 822 size_t min_1 = (column[k] < column[k-1]) ? column[k]+1 : column[k-1]+1; 823 size_t min_2 = last_diag + (resource[k-1] == prefix[j-1] ? 0 : 1); 824 column[k] = (min_1 < min_2) ? min_1 : min_2; 825 last_diag = old_diag; 826 } 827 } 828 size_t n = column[min_len]; 829 priority = backends[i].priority; 830 if (n < lev_dis || (n == lev_dis 831 && lev_priority > priority)) { 832 lev_dis = n; 833 lev_priority = priority; 834 lev_index = i; 835 } 836 } 837 const char *prefix_lev = backends[lev_index].prefix; 838 size_t lev_length; 839 for (lev_length=0; prefix_lev[lev_length] 840 && prefix_lev[lev_length] != '\0'; lev_length++) {} 841 size_t m = (lev_length < stem_length) ? lev_length : stem_length; 842 if (lev_dis+1 >= m) { 843 return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", 844 resource); 845 } else { 846 return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\n" 847 "Closest match: %s", resource, backends[lev_index].prefix); 848 } 849 // LCOV_EXCL_STOP 850 } 851 852 // Setup Ceed 853 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 854 ierr = CeedCalloc(1, &(*ceed)->jit_source_roots); CeedChk(ierr); 855 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 856 if (!ceed_error_handler) 857 ceed_error_handler = "abort"; 858 if (!strcmp(ceed_error_handler, "exit")) 859 (*ceed)->Error = CeedErrorExit; 860 else if (!strcmp(ceed_error_handler, "store")) 861 (*ceed)->Error = CeedErrorStore; 862 else 863 (*ceed)->Error = CeedErrorAbort; 864 memcpy((*ceed)->err_msg, "No error message stored", 24); 865 (*ceed)->ref_count = 1; 866 (*ceed)->data = NULL; 867 868 // Set lookup table 869 FOffset f_offsets[] = { 870 CEED_FTABLE_ENTRY(Ceed, Error), 871 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 872 CEED_FTABLE_ENTRY(Ceed, Destroy), 873 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 874 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 875 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateOriented), 876 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 877 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 878 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 879 CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv), 880 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 881 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 882 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 883 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 884 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 885 CEED_FTABLE_ENTRY(CeedVector, HasValidArray), 886 CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType), 887 CEED_FTABLE_ENTRY(CeedVector, SetArray), 888 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 889 CEED_FTABLE_ENTRY(CeedVector, SetValue), 890 CEED_FTABLE_ENTRY(CeedVector, SyncArray), 891 CEED_FTABLE_ENTRY(CeedVector, GetArray), 892 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 893 CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite), 894 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 895 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 896 CEED_FTABLE_ENTRY(CeedVector, Norm), 897 CEED_FTABLE_ENTRY(CeedVector, Scale), 898 CEED_FTABLE_ENTRY(CeedVector, AXPY), 899 CEED_FTABLE_ENTRY(CeedVector, PointwiseMult), 900 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 901 CEED_FTABLE_ENTRY(CeedVector, Destroy), 902 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 903 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 904 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 905 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 906 CEED_FTABLE_ENTRY(CeedBasis, Apply), 907 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 908 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 909 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 910 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 911 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 912 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 913 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 914 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData), 915 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType), 916 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 917 CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData), 918 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 919 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead), 920 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 921 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead), 922 CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy), 923 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 924 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 925 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate), 926 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 927 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 928 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 929 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 930 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic), 931 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble), 932 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle), 933 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 934 CEED_FTABLE_ENTRY(CeedOperator, Apply), 935 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 936 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 937 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 938 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 939 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 940 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 941 }; 942 943 ierr = CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets); CeedChk(ierr); 944 memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets)); 945 946 // Set fallback for advanced CeedOperator functions 947 const char fallbackresource[] = ""; 948 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 949 CeedChk(ierr); 950 951 // Record env variables CEED_DEBUG or DBG 952 (*ceed)->is_debug = !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || 953 !!getenv("DBG"); 954 955 // Copy resource prefix, if backend setup successful 956 ierr = CeedStringAllocCopy(backends[match_index].prefix, 957 (char **)&(*ceed)->resource); 958 CeedChk(ierr); 959 960 // Set default JiT source root 961 // Note: there will always be the default root for every Ceed 962 // but all additional paths are added to the top-most parent 963 ierr = CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault); 964 CeedChk(ierr); 965 966 // Backend specific setup 967 ierr = backends[match_index].init(&resource[match_help], *ceed); CeedChk(ierr); 968 969 return CEED_ERROR_SUCCESS; 970 } 971 972 /** 973 @brief Copy the pointer to a Ceed context. Both pointers should 974 be destroyed with `CeedDestroy()`; 975 Note: If `*ceed_copy` is non-NULL, then it is assumed that 976 `*ceed_copy` is a pointer to a Ceed context. This Ceed 977 context will be destroyed if `*ceed_copy` is the only 978 reference to this Ceed context. 979 980 @param ceed Ceed context to copy reference to 981 @param[out] ceed_copy Variable to store copied reference 982 983 @return An error code: 0 - success, otherwise - failure 984 985 @ref User 986 **/ 987 int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) { 988 int ierr; 989 990 ierr = CeedReference(ceed); CeedChk(ierr); 991 ierr = CeedDestroy(ceed_copy); CeedChk(ierr); 992 *ceed_copy = ceed; 993 return CEED_ERROR_SUCCESS; 994 } 995 996 /** 997 @brief Get the full resource name for a Ceed context 998 999 @param ceed Ceed context to get resource name of 1000 @param[out] resource Variable to store resource name 1001 1002 @return An error code: 0 - success, otherwise - failure 1003 1004 @ref User 1005 **/ 1006 int CeedGetResource(Ceed ceed, const char **resource) { 1007 *resource = (const char *)ceed->resource; 1008 return CEED_ERROR_SUCCESS; 1009 } 1010 1011 /** 1012 @brief Return Ceed context preferred memory type 1013 1014 @param ceed Ceed context to get preferred memory type of 1015 @param[out] mem_type Address to save preferred memory type to 1016 1017 @return An error code: 0 - success, otherwise - failure 1018 1019 @ref User 1020 **/ 1021 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) { 1022 int ierr; 1023 1024 if (ceed->GetPreferredMemType) { 1025 ierr = ceed->GetPreferredMemType(mem_type); CeedChk(ierr); 1026 } else { 1027 Ceed delegate; 1028 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 1029 1030 if (delegate) { 1031 ierr = CeedGetPreferredMemType(delegate, mem_type); CeedChk(ierr); 1032 } else { 1033 *mem_type = CEED_MEM_HOST; 1034 } 1035 } 1036 return CEED_ERROR_SUCCESS; 1037 } 1038 1039 /** 1040 @brief Get deterministic status of Ceed 1041 1042 @param[in] ceed Ceed 1043 @param[out] is_deterministic Variable to store deterministic status 1044 1045 @return An error code: 0 - success, otherwise - failure 1046 1047 @ref User 1048 **/ 1049 int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) { 1050 *is_deterministic = ceed->is_deterministic; 1051 return CEED_ERROR_SUCCESS; 1052 } 1053 1054 /** 1055 @brief Set additional JiT source root for Ceed 1056 1057 @param[in] ceed Ceed 1058 @param[in] jit_source_root Absolute path to additional JiT source directory 1059 1060 @return An error code: 0 - success, otherwise - failure 1061 1062 @ref User 1063 **/ 1064 int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) { 1065 int ierr; 1066 Ceed ceed_parent; 1067 1068 ierr = CeedGetParent(ceed, &ceed_parent); CeedChk(ierr); 1069 1070 CeedInt index = ceed_parent->num_jit_source_roots; 1071 size_t path_length = strlen(jit_source_root); 1072 ierr = CeedRealloc(index + 1, &ceed_parent->jit_source_roots); CeedChk(ierr); 1073 ierr = CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]); 1074 CeedChk(ierr); 1075 memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length); 1076 ceed_parent->num_jit_source_roots++; 1077 1078 return CEED_ERROR_SUCCESS; 1079 } 1080 1081 /** 1082 @brief View a Ceed 1083 1084 @param[in] ceed Ceed to view 1085 @param[in] stream Filestream to write to 1086 1087 @return An error code: 0 - success, otherwise - failure 1088 1089 @ref User 1090 **/ 1091 int CeedView(Ceed ceed, FILE *stream) { 1092 int ierr; 1093 CeedMemType mem_type; 1094 1095 ierr = CeedGetPreferredMemType(ceed, &mem_type); CeedChk(ierr); 1096 1097 fprintf(stream, "Ceed\n" 1098 " Ceed Resource: %s\n" 1099 " Preferred MemType: %s\n", 1100 ceed->resource, CeedMemTypes[mem_type]); 1101 return CEED_ERROR_SUCCESS; 1102 } 1103 1104 /** 1105 @brief Destroy a Ceed context 1106 1107 @param ceed Address of Ceed context to destroy 1108 1109 @return An error code: 0 - success, otherwise - failure 1110 1111 @ref User 1112 **/ 1113 int CeedDestroy(Ceed *ceed) { 1114 int ierr; 1115 if (!*ceed || --(*ceed)->ref_count > 0) return CEED_ERROR_SUCCESS; 1116 if ((*ceed)->delegate) { 1117 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 1118 } 1119 1120 if ((*ceed)->obj_delegate_count > 0) { 1121 for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) { 1122 ierr = CeedDestroy(&((*ceed)->obj_delegates[i].delegate)); CeedChk(ierr); 1123 ierr = CeedFree(&(*ceed)->obj_delegates[i].obj_name); CeedChk(ierr); 1124 } 1125 ierr = CeedFree(&(*ceed)->obj_delegates); CeedChk(ierr); 1126 } 1127 1128 if ((*ceed)->Destroy) { 1129 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 1130 } 1131 1132 for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) { 1133 ierr = CeedFree(&(*ceed)->jit_source_roots[i]); CeedChk(ierr); 1134 } 1135 ierr = CeedFree(&(*ceed)->jit_source_roots); CeedChk(ierr); 1136 1137 ierr = CeedFree(&(*ceed)->f_offsets); CeedChk(ierr); 1138 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 1139 ierr = CeedDestroy(&(*ceed)->op_fallback_ceed); CeedChk(ierr); 1140 ierr = CeedFree(&(*ceed)->op_fallback_resource); CeedChk(ierr); 1141 ierr = CeedFree(ceed); CeedChk(ierr); 1142 return CEED_ERROR_SUCCESS; 1143 } 1144 1145 // LCOV_EXCL_START 1146 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 1147 if (ceed->parent) 1148 return CeedErrorFormat(ceed->parent, format, args); 1149 if (ceed->op_fallback_parent) 1150 return CeedErrorFormat(ceed->op_fallback_parent, format, args); 1151 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1152 vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); // NOLINT 1153 return ceed->err_msg; 1154 } 1155 // LCOV_EXCL_STOP 1156 1157 /** 1158 @brief Error handling implementation; use \ref CeedError instead. 1159 1160 @ref Developer 1161 **/ 1162 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 1163 int ecode, const char *format, ...) { 1164 va_list args; 1165 int ret_val; 1166 va_start(args, format); 1167 if (ceed) { 1168 ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 1169 } else { 1170 // LCOV_EXCL_START 1171 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 1172 if (!ceed_error_handler) 1173 ceed_error_handler = "abort"; 1174 if (!strcmp(ceed_error_handler, "return")) 1175 ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 1176 else 1177 // This function will not return 1178 ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 1179 } 1180 va_end(args); 1181 return ret_val; 1182 // LCOV_EXCL_STOP 1183 } 1184 1185 /** 1186 @brief Error handler that returns without printing anything. 1187 1188 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1189 1190 @ref Developer 1191 **/ 1192 // LCOV_EXCL_START 1193 int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, 1194 const char *func, int err_code, const char *format, 1195 va_list *args) { 1196 return err_code; 1197 } 1198 // LCOV_EXCL_STOP 1199 1200 /** 1201 @brief Error handler that stores the error message for future use and returns 1202 the error. 1203 1204 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1205 1206 @ref Developer 1207 **/ 1208 // LCOV_EXCL_START 1209 int CeedErrorStore(Ceed ceed, const char *filename, int line_no, 1210 const char *func, int err_code, const char *format, 1211 va_list *args) { 1212 if (ceed->parent) 1213 return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, 1214 args); 1215 if (ceed->op_fallback_parent) 1216 return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, 1217 err_code, format, args); 1218 1219 // Build message 1220 CeedInt len; 1221 len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", 1222 filename, line_no, func); 1223 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1224 // *INDENT-OFF* 1225 vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); // NOLINT 1226 // *INDENT-ON* 1227 return err_code; 1228 } 1229 // LCOV_EXCL_STOP 1230 1231 /** 1232 @brief Error handler that prints to stderr and aborts 1233 1234 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1235 1236 @ref Developer 1237 **/ 1238 // LCOV_EXCL_START 1239 int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, 1240 const char *func, int err_code, const char *format, 1241 va_list *args) { 1242 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1243 vfprintf(stderr, format, *args); 1244 fprintf(stderr, "\n"); 1245 abort(); 1246 return err_code; 1247 } 1248 // LCOV_EXCL_STOP 1249 1250 /** 1251 @brief Error handler that prints to stderr and exits 1252 1253 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1254 1255 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 1256 handlers (e.g., as used by gcov) are run. 1257 1258 @ref Developer 1259 **/ 1260 int CeedErrorExit(Ceed ceed, const char *filename, int line_no, 1261 const char *func, int err_code, const char *format, va_list *args) { 1262 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1263 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1264 vfprintf(stderr, format, *args); // NOLINT 1265 fprintf(stderr, "\n"); 1266 exit(err_code); 1267 return err_code; 1268 } 1269 1270 /** 1271 @brief Set error handler 1272 1273 A default error handler is set in CeedInit(). Use this function to change 1274 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 1275 error handler. 1276 1277 @ref Developer 1278 **/ 1279 int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) { 1280 ceed->Error = handler; 1281 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler); 1282 for (CeedInt i=0; i<ceed->obj_delegate_count; i++) 1283 CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler); 1284 return CEED_ERROR_SUCCESS; 1285 } 1286 1287 /** 1288 @brief Get error message 1289 1290 The error message is only stored when using the error handler 1291 CeedErrorStore() 1292 1293 @param[in] ceed Ceed contex to retrieve error message 1294 @param[out] err_msg Char pointer to hold error message 1295 1296 @ref Developer 1297 **/ 1298 int CeedGetErrorMessage(Ceed ceed, const char **err_msg) { 1299 if (ceed->parent) 1300 return CeedGetErrorMessage(ceed->parent, err_msg); 1301 if (ceed->op_fallback_parent) 1302 return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg); 1303 *err_msg = ceed->err_msg; 1304 return CEED_ERROR_SUCCESS; 1305 } 1306 1307 /** 1308 @brief Restore error message 1309 1310 The error message is only stored when using the error handler 1311 CeedErrorStore() 1312 1313 @param[in] ceed Ceed contex to restore error message 1314 @param[out] err_msg Char pointer that holds error message 1315 1316 @ref Developer 1317 **/ 1318 int CeedResetErrorMessage(Ceed ceed, const char **err_msg) { 1319 if (ceed->parent) 1320 return CeedResetErrorMessage(ceed->parent, err_msg); 1321 if (ceed->op_fallback_parent) 1322 return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg); 1323 *err_msg = NULL; 1324 memcpy(ceed->err_msg, "No error message stored", 24); 1325 return CEED_ERROR_SUCCESS; 1326 } 1327 1328 /** 1329 @brief Get libCEED library version info 1330 1331 libCEED version numbers have the form major.minor.patch. Non-release versions 1332 may contain unstable interfaces. 1333 1334 @param[out] major Major version of the library 1335 @param[out] minor Minor version of the library 1336 @param[out] patch Patch (subminor) version of the library 1337 @param[out] release True for releases; false for development branches. 1338 1339 The caller may pass NULL for any arguments that are not needed. 1340 1341 @sa CEED_VERSION_GE() 1342 1343 @ref Developer 1344 */ 1345 int CeedGetVersion(int *major, int *minor, int *patch, bool *release) { 1346 if (major) *major = CEED_VERSION_MAJOR; 1347 if (minor) *minor = CEED_VERSION_MINOR; 1348 if (patch) *patch = CEED_VERSION_PATCH; 1349 if (release) *release = CEED_VERSION_RELEASE; 1350 return 0; 1351 } 1352 1353 int CeedGetScalarType(CeedScalarType *scalar_type) { 1354 *scalar_type = CEED_SCALAR_TYPE; 1355 return 0; 1356 } 1357 1358 1359 /// @} 1360