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