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