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 // Create fallback Ceed if uninitalized 509 if (!ceed->op_fallback_ceed) { 510 // Check resource 511 const char *resource, *fallback_resource; 512 ierr = CeedGetResource(ceed, &resource); CeedChk(ierr); 513 ierr = CeedGetOperatorFallbackResource(ceed, &fallback_resource); CeedChk(ierr); 514 if (!strcmp(resource, fallback_resource)) 515 // LCOV_EXCL_START 516 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 517 "Backend %s cannot create an operator" 518 "fallback to resource %s", resource, fallback_resource); 519 // LCOV_EXCL_STOP 520 521 // Create fallback 522 Ceed fallback_ceed; 523 ierr = CeedInit(fallback_resource, &fallback_ceed); CeedChk(ierr); 524 fallback_ceed->op_fallback_parent = ceed; 525 fallback_ceed->Error = ceed->Error; 526 ceed->op_fallback_ceed = fallback_ceed; 527 } 528 *fallback_ceed = ceed->op_fallback_ceed; 529 530 return CEED_ERROR_SUCCESS; 531 } 532 533 /** 534 @brief Set the fallback resource for CeedOperators. The current resource, if 535 any, is freed by calling this function. This string is freed upon the 536 destruction of the Ceed context. 537 538 @param[out] ceed Ceed context 539 @param resource Fallback resource to set 540 541 @return An error code: 0 - success, otherwise - failure 542 543 @ref Backend 544 **/ 545 546 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 547 int ierr; 548 549 // Free old 550 ierr = CeedFree(&ceed->op_fallback_resource); CeedChk(ierr); 551 552 // Set new 553 ierr = CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource); 554 CeedChk(ierr); 555 return CEED_ERROR_SUCCESS; 556 } 557 558 /** 559 @brief Get the parent Ceed context associated with a fallback Ceed context 560 for a CeedOperator 561 562 @param ceed Ceed context 563 @param[out] parent Variable to store parent Ceed context 564 565 @return An error code: 0 - success, otherwise - failure 566 567 @ref Backend 568 **/ 569 570 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 571 *parent = ceed->op_fallback_parent; 572 return CEED_ERROR_SUCCESS; 573 } 574 575 /** 576 @brief Flag Ceed context as deterministic 577 578 @param ceed Ceed to flag as deterministic 579 @param[out] is_deterministic Deterministic status to set 580 581 @return An error code: 0 - success, otherwise - failure 582 583 @ref Backend 584 **/ 585 586 int CeedSetDeterministic(Ceed ceed, bool is_deterministic) { 587 ceed->is_deterministic = is_deterministic; 588 return CEED_ERROR_SUCCESS; 589 } 590 591 /** 592 @brief Set a backend function 593 594 This function is used for a backend to set the function associated with 595 the Ceed objects. For example, 596 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 597 sets the backend implementation of 'CeedVectorCreate' and 598 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 599 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 600 is not required for the object type ("Basis" vs "CeedBasis"). 601 602 @param ceed Ceed context for error handling 603 @param type Type of Ceed object to set function for 604 @param[out] object Ceed object to set function for 605 @param func_name Name of function to set 606 @param f Function to set 607 608 @return An error code: 0 - success, otherwise - failure 609 610 @ref Backend 611 **/ 612 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 613 const char *func_name, int (*f)()) { 614 char lookup_name[CEED_MAX_RESOURCE_LEN+1] = ""; 615 616 // Build lookup name 617 if (strcmp(type, "Ceed")) 618 strncat (lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN); 619 strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN); 620 strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN); 621 622 // Find and use offset 623 for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) 624 if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) { 625 size_t offset = ceed->f_offsets[i].offset; 626 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 627 *fpointer = f; 628 return CEED_ERROR_SUCCESS; 629 } 630 631 // LCOV_EXCL_START 632 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 633 "Requested function '%s' was not found for CEED " 634 "object '%s'", func_name, type); 635 // LCOV_EXCL_STOP 636 } 637 638 /** 639 @brief Retrieve backend data for a Ceed context 640 641 @param ceed Ceed context to retrieve data of 642 @param[out] data Address to save data to 643 644 @return An error code: 0 - success, otherwise - failure 645 646 @ref Backend 647 **/ 648 int CeedGetData(Ceed ceed, void *data) { 649 *(void **)data = ceed->data; 650 return CEED_ERROR_SUCCESS; 651 } 652 653 /** 654 @brief Set backend data for a Ceed context 655 656 @param ceed Ceed context to set data of 657 @param data Address of data to set 658 659 @return An error code: 0 - success, otherwise - failure 660 661 @ref Backend 662 **/ 663 int CeedSetData(Ceed ceed, void *data) { 664 ceed->data = data; 665 return CEED_ERROR_SUCCESS; 666 } 667 668 /** 669 @brief Increment the reference counter for a Ceed context 670 671 @param ceed Ceed context to increment the reference counter 672 673 @return An error code: 0 - success, otherwise - failure 674 675 @ref Backend 676 **/ 677 int CeedReference(Ceed ceed) { 678 ceed->ref_count++; 679 return CEED_ERROR_SUCCESS; 680 } 681 682 /// @} 683 684 /// ---------------------------------------------------------------------------- 685 /// Ceed Public API 686 /// ---------------------------------------------------------------------------- 687 /// @addtogroup CeedUser 688 /// @{ 689 690 /** 691 @brief Get the list of available resource names for Ceed contexts 692 Note: The caller is responsible for `free()`ing the resources and priorities arrays, 693 but should not `free()` the contents of the resources array. 694 695 @param[out] n Number of available resources 696 @param[out] resources List of available resource names 697 @param[out] priorities Resource name prioritization values, lower is better 698 699 @return An error code: 0 - success, otherwise - failure 700 701 @ref User 702 **/ 703 // LCOV_EXCL_START 704 int CeedRegistryGetList(size_t *n, char ***const resources, 705 CeedInt **priorities) { 706 *n = 0; 707 *resources = malloc(num_backends * sizeof(**resources)); 708 if (!resources) 709 return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure"); 710 if (priorities) { 711 *priorities = malloc(num_backends * sizeof(**priorities)); 712 if (!priorities) 713 return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure"); 714 } 715 for (size_t i=0; i<num_backends; i++) { 716 // Only report compiled backends 717 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) { 718 *resources[i] = backends[i].prefix; 719 if (priorities) *priorities[i] = backends[i].priority; 720 *n += 1; 721 } 722 } 723 if (*n == 0) 724 // LCOV_EXCL_START 725 return CeedError(NULL, CEED_ERROR_MAJOR, "No backends installed"); 726 // LCOV_EXCL_STOP 727 *resources = realloc(*resources, *n * sizeof(**resources)); 728 if (!resources) 729 return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure"); 730 if (priorities) { 731 *priorities = realloc(*priorities, *n * sizeof(**priorities)); 732 if (!priorities) 733 return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure"); 734 } 735 return CEED_ERROR_SUCCESS; 736 } 737 // LCOV_EXCL_STOP 738 739 /** 740 @brief Initialize a \ref Ceed context to use the specified resource. 741 Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self") 742 will result in CeedInt printing the current libCEED version number 743 and a list of current available backend resources to stderr. 744 745 @param resource Resource to use, e.g., "/cpu/self" 746 @param ceed The library context 747 @sa CeedRegister() CeedDestroy() 748 749 @return An error code: 0 - success, otherwise - failure 750 751 @ref User 752 **/ 753 int CeedInit(const char *resource, Ceed *ceed) { 754 int ierr; 755 size_t match_len = 0, match_index = UINT_MAX, 756 match_priority = CEED_MAX_BACKEND_PRIORITY, priority; 757 758 // Find matching backend 759 if (!resource) 760 // LCOV_EXCL_START 761 return CeedError(NULL, CEED_ERROR_MAJOR, "No resource provided"); 762 // LCOV_EXCL_STOP 763 ierr = CeedRegisterAll(); CeedChk(ierr); 764 765 // Check for help request 766 const char *help_prefix = "help"; 767 size_t match_help; 768 for (match_help=0; match_help<4 769 && resource[match_help] == help_prefix[match_help]; match_help++) {} 770 if (match_help == 4) { 771 fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, 772 CEED_VERSION_MINOR, CEED_VERSION_PATCH, 773 CEED_VERSION_RELEASE ? "" : "+development"); 774 fprintf(stderr, "Available backend resources:\n"); 775 for (size_t i=0; i<num_backends; i++) { 776 // Only report compiled backends 777 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) 778 fprintf(stderr, " %s\n", backends[i].prefix); 779 } 780 fflush(stderr); 781 match_help = 5; // Delineating character expected 782 } else { 783 match_help = 0; 784 } 785 786 // Find best match, computed as number of matching characters 787 // from requested resource stem 788 size_t stem_length; 789 for (stem_length=0; resource[stem_length+match_help] 790 && resource[stem_length+match_help] != ':'; stem_length++) {} 791 for (size_t i=0; i<num_backends; i++) { 792 size_t n; 793 const char *prefix = backends[i].prefix; 794 for (n=0; prefix[n] && prefix[n] == resource[n+match_help]; n++) {} 795 priority = backends[i].priority; 796 if (n > match_len || (n == match_len && match_priority > priority)) { 797 match_len = n; 798 match_priority = priority; 799 match_index = i; 800 } 801 } 802 // Using Levenshtein distance to find closest match 803 if (match_len <= 1 || match_len != stem_length) { 804 // LCOV_EXCL_START 805 size_t lev_dis = UINT_MAX; 806 size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY; 807 for (size_t i=0; i<num_backends; i++) { 808 const char *prefix = backends[i].prefix; 809 size_t prefix_length = strlen(backends[i].prefix); 810 size_t min_len = (prefix_length < stem_length) ? prefix_length : stem_length; 811 size_t column[min_len+1]; 812 for (size_t j=0; j<=min_len; j++) column[j] = j; 813 for (size_t j=1; j<=min_len; j++) { 814 column[0] = j; 815 for (size_t k=1, last_diag=j-1; k<=min_len; k++) { 816 size_t old_diag = column[k]; 817 size_t min_1 = (column[k] < column[k-1]) ? column[k]+1 : column[k-1]+1; 818 size_t min_2 = last_diag + (resource[k-1] == prefix[j-1] ? 0 : 1); 819 column[k] = (min_1 < min_2) ? min_1 : min_2; 820 last_diag = old_diag; 821 } 822 } 823 size_t n = column[min_len]; 824 priority = backends[i].priority; 825 if (n < lev_dis || (n == lev_dis 826 && lev_priority > priority)) { 827 lev_dis = n; 828 lev_priority = priority; 829 lev_index = i; 830 } 831 } 832 const char *prefix_lev = backends[lev_index].prefix; 833 size_t lev_length; 834 for (lev_length=0; prefix_lev[lev_length] 835 && prefix_lev[lev_length] != '\0'; lev_length++) {} 836 size_t m = (lev_length < stem_length) ? lev_length : stem_length; 837 if (lev_dis+1 >= m) { 838 return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", 839 resource); 840 } else { 841 return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\n" 842 "Closest match: %s", resource, backends[lev_index].prefix); 843 } 844 // LCOV_EXCL_STOP 845 } 846 847 // Setup Ceed 848 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 849 ierr = CeedCalloc(1, &(*ceed)->jit_source_roots); CeedChk(ierr); 850 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 851 if (!ceed_error_handler) 852 ceed_error_handler = "abort"; 853 if (!strcmp(ceed_error_handler, "exit")) 854 (*ceed)->Error = CeedErrorExit; 855 else if (!strcmp(ceed_error_handler, "store")) 856 (*ceed)->Error = CeedErrorStore; 857 else 858 (*ceed)->Error = CeedErrorAbort; 859 memcpy((*ceed)->err_msg, "No error message stored", 24); 860 (*ceed)->ref_count = 1; 861 (*ceed)->data = NULL; 862 863 // Set lookup table 864 FOffset f_offsets[] = { 865 CEED_FTABLE_ENTRY(Ceed, Error), 866 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 867 CEED_FTABLE_ENTRY(Ceed, Destroy), 868 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 869 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 870 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateOriented), 871 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 872 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 873 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 874 CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv), 875 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 876 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 877 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 878 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 879 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 880 CEED_FTABLE_ENTRY(CeedVector, HasValidArray), 881 CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType), 882 CEED_FTABLE_ENTRY(CeedVector, SetArray), 883 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 884 CEED_FTABLE_ENTRY(CeedVector, SetValue), 885 CEED_FTABLE_ENTRY(CeedVector, SyncArray), 886 CEED_FTABLE_ENTRY(CeedVector, GetArray), 887 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 888 CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite), 889 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 890 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 891 CEED_FTABLE_ENTRY(CeedVector, Norm), 892 CEED_FTABLE_ENTRY(CeedVector, Scale), 893 CEED_FTABLE_ENTRY(CeedVector, AXPY), 894 CEED_FTABLE_ENTRY(CeedVector, PointwiseMult), 895 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 896 CEED_FTABLE_ENTRY(CeedVector, Destroy), 897 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 898 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 899 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 900 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 901 CEED_FTABLE_ENTRY(CeedBasis, Apply), 902 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 903 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 904 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 905 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 906 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 907 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 908 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 909 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData), 910 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType), 911 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 912 CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData), 913 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 914 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead), 915 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 916 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead), 917 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 918 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 919 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate), 920 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 921 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 922 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 923 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 924 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic), 925 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble), 926 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 927 CEED_FTABLE_ENTRY(CeedOperator, Apply), 928 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 929 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 930 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 931 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 932 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 933 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 934 }; 935 936 ierr = CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets); CeedChk(ierr); 937 memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets)); 938 939 // Set fallback for advanced CeedOperator functions 940 const char fallbackresource[] = ""; 941 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 942 CeedChk(ierr); 943 944 // Record env variables CEED_DEBUG or DBG 945 (*ceed)->is_debug = !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || 946 !!getenv("DBG"); 947 948 // Backend specific setup 949 ierr = backends[match_index].init(&resource[match_help], *ceed); CeedChk(ierr); 950 951 // Copy resource prefix, if backend setup successful 952 ierr = CeedStringAllocCopy(backends[match_index].prefix, 953 (char **)&(*ceed)->resource); 954 CeedChk(ierr); 955 956 // Set default JiT source root 957 // Note: there will always be the default root for every Ceed 958 // but all additional paths are added to the top-most parent 959 ierr = CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault); 960 CeedChk(ierr); 961 962 return CEED_ERROR_SUCCESS; 963 } 964 965 /** 966 @brief Copy the pointer to a Ceed context. Both pointers should 967 be destroyed with `CeedDestroy()`; 968 Note: If `*ceed_copy` is non-NULL, then it is assumed that 969 `*ceed_copy` is a pointer to a Ceed context. This Ceed 970 context will be destroyed if `*ceed_copy` is the only 971 reference to this Ceed context. 972 973 @param ceed Ceed context to copy reference to 974 @param[out] ceed_copy Variable to store copied reference 975 976 @return An error code: 0 - success, otherwise - failure 977 978 @ref User 979 **/ 980 int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) { 981 int ierr; 982 983 ierr = CeedReference(ceed); CeedChk(ierr); 984 ierr = CeedDestroy(ceed_copy); CeedChk(ierr); 985 *ceed_copy = ceed; 986 return CEED_ERROR_SUCCESS; 987 } 988 989 /** 990 @brief Get the full resource name for a Ceed context 991 992 @param ceed Ceed context to get resource name of 993 @param[out] resource Variable to store resource name 994 995 @return An error code: 0 - success, otherwise - failure 996 997 @ref User 998 **/ 999 int CeedGetResource(Ceed ceed, const char **resource) { 1000 *resource = (const char *)ceed->resource; 1001 return CEED_ERROR_SUCCESS; 1002 } 1003 1004 /** 1005 @brief Return Ceed context preferred memory type 1006 1007 @param ceed Ceed context to get preferred memory type of 1008 @param[out] mem_type Address to save preferred memory type to 1009 1010 @return An error code: 0 - success, otherwise - failure 1011 1012 @ref User 1013 **/ 1014 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) { 1015 int ierr; 1016 1017 if (ceed->GetPreferredMemType) { 1018 ierr = ceed->GetPreferredMemType(mem_type); CeedChk(ierr); 1019 } else { 1020 Ceed delegate; 1021 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 1022 1023 if (delegate) { 1024 ierr = CeedGetPreferredMemType(delegate, mem_type); CeedChk(ierr); 1025 } else { 1026 *mem_type = CEED_MEM_HOST; 1027 } 1028 } 1029 return CEED_ERROR_SUCCESS; 1030 } 1031 1032 /** 1033 @brief Get deterministic status of Ceed 1034 1035 @param[in] ceed Ceed 1036 @param[out] is_deterministic Variable to store deterministic status 1037 1038 @return An error code: 0 - success, otherwise - failure 1039 1040 @ref User 1041 **/ 1042 int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) { 1043 *is_deterministic = ceed->is_deterministic; 1044 return CEED_ERROR_SUCCESS; 1045 } 1046 1047 /** 1048 @brief Set additional JiT source root for Ceed 1049 1050 @param[in] ceed Ceed 1051 @param[in] jit_source_root Absolute path to additional JiT source directory 1052 1053 @return An error code: 0 - success, otherwise - failure 1054 1055 @ref User 1056 **/ 1057 int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) { 1058 int ierr; 1059 Ceed ceed_parent; 1060 1061 ierr = CeedGetParent(ceed, &ceed_parent); CeedChk(ierr); 1062 1063 CeedInt index = ceed_parent->num_jit_source_roots; 1064 size_t path_length = strlen(jit_source_root); 1065 ierr = CeedRealloc(index + 1, &ceed_parent->jit_source_roots); CeedChk(ierr); 1066 ierr = CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]); 1067 CeedChk(ierr); 1068 memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length); 1069 ceed_parent->num_jit_source_roots++; 1070 1071 return CEED_ERROR_SUCCESS; 1072 } 1073 1074 /** 1075 @brief View a Ceed 1076 1077 @param[in] ceed Ceed to view 1078 @param[in] stream Filestream to write to 1079 1080 @return An error code: 0 - success, otherwise - failure 1081 1082 @ref User 1083 **/ 1084 int CeedView(Ceed ceed, FILE *stream) { 1085 int ierr; 1086 CeedMemType mem_type; 1087 1088 ierr = CeedGetPreferredMemType(ceed, &mem_type); CeedChk(ierr); 1089 1090 fprintf(stream, "Ceed\n" 1091 " Ceed Resource: %s\n" 1092 " Preferred MemType: %s\n", 1093 ceed->resource, CeedMemTypes[mem_type]); 1094 return CEED_ERROR_SUCCESS; 1095 } 1096 1097 /** 1098 @brief Destroy a Ceed context 1099 1100 @param ceed Address of Ceed context to destroy 1101 1102 @return An error code: 0 - success, otherwise - failure 1103 1104 @ref User 1105 **/ 1106 int CeedDestroy(Ceed *ceed) { 1107 int ierr; 1108 if (!*ceed || --(*ceed)->ref_count > 0) return CEED_ERROR_SUCCESS; 1109 if ((*ceed)->delegate) { 1110 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 1111 } 1112 1113 if ((*ceed)->obj_delegate_count > 0) { 1114 for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) { 1115 ierr = CeedDestroy(&((*ceed)->obj_delegates[i].delegate)); CeedChk(ierr); 1116 ierr = CeedFree(&(*ceed)->obj_delegates[i].obj_name); CeedChk(ierr); 1117 } 1118 ierr = CeedFree(&(*ceed)->obj_delegates); CeedChk(ierr); 1119 } 1120 1121 if ((*ceed)->Destroy) { 1122 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 1123 } 1124 1125 for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) { 1126 ierr = CeedFree(&(*ceed)->jit_source_roots[i]); CeedChk(ierr); 1127 } 1128 ierr = CeedFree(&(*ceed)->jit_source_roots); CeedChk(ierr); 1129 1130 ierr = CeedFree(&(*ceed)->f_offsets); CeedChk(ierr); 1131 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 1132 ierr = CeedDestroy(&(*ceed)->op_fallback_ceed); CeedChk(ierr); 1133 ierr = CeedFree(&(*ceed)->op_fallback_resource); CeedChk(ierr); 1134 ierr = CeedFree(ceed); CeedChk(ierr); 1135 return CEED_ERROR_SUCCESS; 1136 } 1137 1138 // LCOV_EXCL_START 1139 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 1140 if (ceed->parent) 1141 return CeedErrorFormat(ceed->parent, format, args); 1142 if (ceed->op_fallback_parent) 1143 return CeedErrorFormat(ceed->op_fallback_parent, format, args); 1144 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1145 vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); // NOLINT 1146 return ceed->err_msg; 1147 } 1148 // LCOV_EXCL_STOP 1149 1150 /** 1151 @brief Error handling implementation; use \ref CeedError instead. 1152 1153 @ref Developer 1154 **/ 1155 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 1156 int ecode, const char *format, ...) { 1157 va_list args; 1158 int ret_val; 1159 va_start(args, format); 1160 if (ceed) { 1161 ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 1162 } else { 1163 // LCOV_EXCL_START 1164 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 1165 if (!ceed_error_handler) 1166 ceed_error_handler = "abort"; 1167 if (!strcmp(ceed_error_handler, "return")) 1168 ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 1169 else 1170 // This function will not return 1171 ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 1172 } 1173 va_end(args); 1174 return ret_val; 1175 // LCOV_EXCL_STOP 1176 } 1177 1178 /** 1179 @brief Error handler that returns without printing anything. 1180 1181 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1182 1183 @ref Developer 1184 **/ 1185 // LCOV_EXCL_START 1186 int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, 1187 const char *func, int err_code, const char *format, 1188 va_list *args) { 1189 return err_code; 1190 } 1191 // LCOV_EXCL_STOP 1192 1193 /** 1194 @brief Error handler that stores the error message for future use and returns 1195 the error. 1196 1197 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1198 1199 @ref Developer 1200 **/ 1201 // LCOV_EXCL_START 1202 int CeedErrorStore(Ceed ceed, const char *filename, int line_no, 1203 const char *func, int err_code, const char *format, 1204 va_list *args) { 1205 if (ceed->parent) 1206 return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, 1207 args); 1208 if (ceed->op_fallback_parent) 1209 return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, 1210 err_code, format, args); 1211 1212 // Build message 1213 CeedInt len; 1214 len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", 1215 filename, line_no, func); 1216 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1217 // *INDENT-OFF* 1218 vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); // NOLINT 1219 // *INDENT-ON* 1220 return err_code; 1221 } 1222 // LCOV_EXCL_STOP 1223 1224 /** 1225 @brief Error handler that prints to stderr and aborts 1226 1227 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1228 1229 @ref Developer 1230 **/ 1231 // LCOV_EXCL_START 1232 int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, 1233 const char *func, int err_code, const char *format, 1234 va_list *args) { 1235 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1236 vfprintf(stderr, format, *args); 1237 fprintf(stderr, "\n"); 1238 abort(); 1239 return err_code; 1240 } 1241 // LCOV_EXCL_STOP 1242 1243 /** 1244 @brief Error handler that prints to stderr and exits 1245 1246 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1247 1248 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 1249 handlers (e.g., as used by gcov) are run. 1250 1251 @ref Developer 1252 **/ 1253 int CeedErrorExit(Ceed ceed, const char *filename, int line_no, 1254 const char *func, int err_code, const char *format, va_list *args) { 1255 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1256 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1257 vfprintf(stderr, format, *args); // NOLINT 1258 fprintf(stderr, "\n"); 1259 exit(err_code); 1260 return err_code; 1261 } 1262 1263 /** 1264 @brief Set error handler 1265 1266 A default error handler is set in CeedInit(). Use this function to change 1267 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 1268 error handler. 1269 1270 @ref Developer 1271 **/ 1272 int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) { 1273 ceed->Error = handler; 1274 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler); 1275 for (CeedInt i=0; i<ceed->obj_delegate_count; i++) 1276 CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler); 1277 return CEED_ERROR_SUCCESS; 1278 } 1279 1280 /** 1281 @brief Get error message 1282 1283 The error message is only stored when using the error handler 1284 CeedErrorStore() 1285 1286 @param[in] ceed Ceed contex to retrieve error message 1287 @param[out] err_msg Char pointer to hold error message 1288 1289 @ref Developer 1290 **/ 1291 int CeedGetErrorMessage(Ceed ceed, const char **err_msg) { 1292 if (ceed->parent) 1293 return CeedGetErrorMessage(ceed->parent, err_msg); 1294 if (ceed->op_fallback_parent) 1295 return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg); 1296 *err_msg = ceed->err_msg; 1297 return CEED_ERROR_SUCCESS; 1298 } 1299 1300 /** 1301 @brief Restore error message 1302 1303 The error message is only stored when using the error handler 1304 CeedErrorStore() 1305 1306 @param[in] ceed Ceed contex to restore error message 1307 @param[out] err_msg Char pointer that holds error message 1308 1309 @ref Developer 1310 **/ 1311 int CeedResetErrorMessage(Ceed ceed, const char **err_msg) { 1312 if (ceed->parent) 1313 return CeedResetErrorMessage(ceed->parent, err_msg); 1314 if (ceed->op_fallback_parent) 1315 return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg); 1316 *err_msg = NULL; 1317 memcpy(ceed->err_msg, "No error message stored", 24); 1318 return CEED_ERROR_SUCCESS; 1319 } 1320 1321 /** 1322 @brief Get libCEED library version info 1323 1324 libCEED version numbers have the form major.minor.patch. Non-release versions 1325 may contain unstable interfaces. 1326 1327 @param[out] major Major version of the library 1328 @param[out] minor Minor version of the library 1329 @param[out] patch Patch (subminor) version of the library 1330 @param[out] release True for releases; false for development branches. 1331 1332 The caller may pass NULL for any arguments that are not needed. 1333 1334 @sa CEED_VERSION_GE() 1335 1336 @ref Developer 1337 */ 1338 int CeedGetVersion(int *major, int *minor, int *patch, bool *release) { 1339 if (major) *major = CEED_VERSION_MAJOR; 1340 if (minor) *minor = CEED_VERSION_MINOR; 1341 if (patch) *patch = CEED_VERSION_PATCH; 1342 if (release) *release = CEED_VERSION_RELEASE; 1343 return 0; 1344 } 1345 1346 int CeedGetScalarType(CeedScalarType *scalar_type) { 1347 *scalar_type = CEED_SCALAR_TYPE; 1348 return 0; 1349 } 1350 1351 1352 /// @} 1353