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