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