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