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