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