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 CeedGetOperatorFallbackResource(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(CeedGetOperatorFallbackResource(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, ElemRestrictionCreateAtPoints), 792 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 793 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 794 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 795 CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv), 796 CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl), 797 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 798 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 799 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 800 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 801 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 802 CEED_FTABLE_ENTRY(CeedVector, HasValidArray), 803 CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType), 804 CEED_FTABLE_ENTRY(CeedVector, SetArray), 805 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 806 CEED_FTABLE_ENTRY(CeedVector, SetValue), 807 CEED_FTABLE_ENTRY(CeedVector, SyncArray), 808 CEED_FTABLE_ENTRY(CeedVector, GetArray), 809 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 810 CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite), 811 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 812 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 813 CEED_FTABLE_ENTRY(CeedVector, Norm), 814 CEED_FTABLE_ENTRY(CeedVector, Scale), 815 CEED_FTABLE_ENTRY(CeedVector, AXPY), 816 CEED_FTABLE_ENTRY(CeedVector, AXPBY), 817 CEED_FTABLE_ENTRY(CeedVector, PointwiseMult), 818 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 819 CEED_FTABLE_ENTRY(CeedVector, Destroy), 820 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 821 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned), 822 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented), 823 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyAtPoints), 824 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 825 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 826 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations), 827 CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations), 828 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 829 CEED_FTABLE_ENTRY(CeedBasis, Apply), 830 CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints), 831 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 832 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 833 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 834 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 835 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 836 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 837 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 838 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData), 839 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType), 840 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 841 CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData), 842 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 843 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead), 844 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 845 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead), 846 CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy), 847 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 848 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 849 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate), 850 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 851 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 852 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 853 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 854 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic), 855 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble), 856 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle), 857 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 858 CEED_FTABLE_ENTRY(CeedOperator, Apply), 859 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 860 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 861 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 862 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 863 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 864 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 865 }; 866 867 CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets)); 868 memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets)); 869 870 // Set fallback for advanced CeedOperator functions 871 const char fallback_resource[] = ""; 872 CeedCall(CeedSetOperatorFallbackResource(*ceed, fallback_resource)); 873 874 // Record env variables CEED_DEBUG or DBG 875 (*ceed)->is_debug = getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); 876 877 // Copy resource prefix, if backend setup successful 878 CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource)); 879 880 // Set default JiT source root 881 // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent 882 CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault)); 883 884 // Backend specific setup 885 CeedCall(backends[match_index].init(&resource[match_help], *ceed)); 886 return CEED_ERROR_SUCCESS; 887 } 888 889 /** 890 @brief Set the GPU stream for a Ceed context 891 892 @param[in,out] ceed Ceed context to set the stream 893 @param[in] handle Handle to GPU stream 894 895 @return An error code: 0 - success, otherwise - failure 896 897 @ref User 898 **/ 899 int CeedSetStream(Ceed ceed, void *handle) { 900 CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-null"); 901 if (ceed->SetStream) { 902 CeedCall(ceed->SetStream(ceed, handle)); 903 } else { 904 Ceed delegate; 905 CeedCall(CeedGetDelegate(ceed, &delegate)); 906 907 if (delegate) CeedCall(CeedSetStream(delegate, handle)); 908 else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream"); 909 } 910 return CEED_ERROR_SUCCESS; 911 } 912 913 /** 914 @brief Copy the pointer to a Ceed context. 915 916 Both pointers should be destroyed with `CeedDestroy()`. 917 918 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. 919 This Ceed context will be destroyed if `ceed_copy` is the only reference to this Ceed context. 920 921 @param[in] ceed Ceed context to copy reference to 922 @param[in,out] ceed_copy Variable to store copied reference 923 924 @return An error code: 0 - success, otherwise - failure 925 926 @ref User 927 **/ 928 int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) { 929 CeedCall(CeedReference(ceed)); 930 CeedCall(CeedDestroy(ceed_copy)); 931 *ceed_copy = ceed; 932 return CEED_ERROR_SUCCESS; 933 } 934 935 /** 936 @brief Get the full resource name for a Ceed context 937 938 @param[in] ceed Ceed context to get resource name of 939 @param[out] resource Variable to store resource name 940 941 @return An error code: 0 - success, otherwise - failure 942 943 @ref User 944 **/ 945 int CeedGetResource(Ceed ceed, const char **resource) { 946 *resource = (const char *)ceed->resource; 947 return CEED_ERROR_SUCCESS; 948 } 949 950 /** 951 @brief Return Ceed context preferred memory type 952 953 @param[in] ceed Ceed context to get preferred memory type of 954 @param[out] mem_type Address to save preferred memory type to 955 956 @return An error code: 0 - success, otherwise - failure 957 958 @ref User 959 **/ 960 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) { 961 if (ceed->GetPreferredMemType) { 962 CeedCall(ceed->GetPreferredMemType(mem_type)); 963 } else { 964 Ceed delegate; 965 CeedCall(CeedGetDelegate(ceed, &delegate)); 966 967 if (delegate) { 968 CeedCall(CeedGetPreferredMemType(delegate, mem_type)); 969 } else { 970 *mem_type = CEED_MEM_HOST; 971 } 972 } 973 return CEED_ERROR_SUCCESS; 974 } 975 976 /** 977 @brief Get deterministic status of Ceed 978 979 @param[in] ceed Ceed 980 @param[out] is_deterministic Variable to store deterministic status 981 982 @return An error code: 0 - success, otherwise - failure 983 984 @ref User 985 **/ 986 int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) { 987 *is_deterministic = ceed->is_deterministic; 988 return CEED_ERROR_SUCCESS; 989 } 990 991 /** 992 @brief Set additional JiT source root for Ceed 993 994 @param[in,out] ceed Ceed 995 @param[in] jit_source_root Absolute path to additional JiT source directory 996 997 @return An error code: 0 - success, otherwise - failure 998 999 @ref User 1000 **/ 1001 int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) { 1002 Ceed ceed_parent; 1003 1004 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1005 1006 CeedInt index = ceed_parent->num_jit_source_roots; 1007 size_t path_length = strlen(jit_source_root); 1008 1009 CeedCall(CeedRealloc(index + 1, &ceed_parent->jit_source_roots)); 1010 CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index])); 1011 memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length); 1012 ceed_parent->num_jit_source_roots++; 1013 return CEED_ERROR_SUCCESS; 1014 } 1015 1016 /** 1017 @brief View a Ceed 1018 1019 @param[in] ceed Ceed to view 1020 @param[in] stream Filestream to write to 1021 1022 @return An error code: 0 - success, otherwise - failure 1023 1024 @ref User 1025 **/ 1026 int CeedView(Ceed ceed, FILE *stream) { 1027 CeedMemType mem_type; 1028 1029 CeedCall(CeedGetPreferredMemType(ceed, &mem_type)); 1030 1031 fprintf(stream, 1032 "Ceed\n" 1033 " Ceed Resource: %s\n" 1034 " Preferred MemType: %s\n", 1035 ceed->resource, CeedMemTypes[mem_type]); 1036 return CEED_ERROR_SUCCESS; 1037 } 1038 1039 /** 1040 @brief Destroy a Ceed context 1041 1042 @param[in,out] ceed Address of Ceed context to destroy 1043 1044 @return An error code: 0 - success, otherwise - failure 1045 1046 @ref User 1047 **/ 1048 int CeedDestroy(Ceed *ceed) { 1049 if (!*ceed || --(*ceed)->ref_count > 0) { 1050 *ceed = NULL; 1051 return CEED_ERROR_SUCCESS; 1052 } 1053 if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate)); 1054 1055 if ((*ceed)->obj_delegate_count > 0) { 1056 for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) { 1057 CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate))); 1058 CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name)); 1059 } 1060 CeedCall(CeedFree(&(*ceed)->obj_delegates)); 1061 } 1062 1063 if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed)); 1064 1065 for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) { 1066 CeedCall(CeedFree(&(*ceed)->jit_source_roots[i])); 1067 } 1068 CeedCall(CeedFree(&(*ceed)->jit_source_roots)); 1069 1070 CeedCall(CeedFree(&(*ceed)->f_offsets)); 1071 CeedCall(CeedFree(&(*ceed)->resource)); 1072 CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed)); 1073 CeedCall(CeedFree(&(*ceed)->op_fallback_resource)); 1074 CeedCall(CeedFree(ceed)); 1075 return CEED_ERROR_SUCCESS; 1076 } 1077 1078 // LCOV_EXCL_START 1079 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 1080 if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args); 1081 if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args); 1082 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1083 vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); // NOLINT 1084 return ceed->err_msg; 1085 } 1086 // LCOV_EXCL_STOP 1087 1088 /** 1089 @brief Error handling implementation; use \ref CeedError instead. 1090 1091 @ref Developer 1092 **/ 1093 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) { 1094 va_list args; 1095 int ret_val; 1096 1097 va_start(args, format); 1098 if (ceed) { 1099 ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 1100 } else { 1101 // LCOV_EXCL_START 1102 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 1103 if (!ceed_error_handler) ceed_error_handler = "abort"; 1104 if (!strcmp(ceed_error_handler, "return")) ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 1105 else 1106 // This function will not return 1107 ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 1108 } 1109 va_end(args); 1110 return ret_val; 1111 // LCOV_EXCL_STOP 1112 } 1113 1114 /** 1115 @brief Error handler that returns without printing anything. 1116 1117 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1118 1119 @ref Developer 1120 **/ 1121 // LCOV_EXCL_START 1122 int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1123 return err_code; 1124 } 1125 // LCOV_EXCL_STOP 1126 1127 /** 1128 @brief Error handler that stores the error message for future use and returns the error. 1129 1130 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1131 1132 @ref Developer 1133 **/ 1134 // LCOV_EXCL_START 1135 int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1136 if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args); 1137 if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args); 1138 1139 // Build message 1140 int len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func); 1141 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1142 vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); // NOLINT 1143 return err_code; 1144 } 1145 // LCOV_EXCL_STOP 1146 1147 /** 1148 @brief Error handler that prints to stderr and aborts 1149 1150 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1151 1152 @ref Developer 1153 **/ 1154 // LCOV_EXCL_START 1155 int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1156 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1157 vfprintf(stderr, format, *args); 1158 fprintf(stderr, "\n"); 1159 abort(); 1160 return err_code; 1161 } 1162 // LCOV_EXCL_STOP 1163 1164 /** 1165 @brief Error handler that prints to stderr and exits 1166 1167 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1168 1169 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() handlers (e.g., as used by gcov) are run. 1170 1171 @ref Developer 1172 **/ 1173 int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1174 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1175 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1176 vfprintf(stderr, format, *args); // NOLINT 1177 fprintf(stderr, "\n"); 1178 exit(err_code); 1179 return err_code; 1180 } 1181 1182 /** 1183 @brief Set error handler 1184 1185 A default error handler is set in CeedInit(). 1186 Use this function to change the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined error handler. 1187 1188 @ref Developer 1189 **/ 1190 int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) { 1191 ceed->Error = handler; 1192 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler); 1193 for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler); 1194 return CEED_ERROR_SUCCESS; 1195 } 1196 1197 /** 1198 @brief Get error message 1199 1200 The error message is only stored when using the error handler CeedErrorStore() 1201 1202 @param[in] ceed Ceed context to retrieve error message 1203 @param[out] err_msg Char pointer to hold error message 1204 1205 @ref Developer 1206 **/ 1207 int CeedGetErrorMessage(Ceed ceed, const char **err_msg) { 1208 if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg); 1209 if (ceed->op_fallback_parent) return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg); 1210 *err_msg = ceed->err_msg; 1211 return CEED_ERROR_SUCCESS; 1212 } 1213 1214 /** 1215 @brief Restore error message 1216 1217 The error message is only stored when using the error handler CeedErrorStore() 1218 1219 @param[in] ceed Ceed context to restore error message 1220 @param[out] err_msg Char pointer that holds error message 1221 1222 @ref Developer 1223 **/ 1224 int CeedResetErrorMessage(Ceed ceed, const char **err_msg) { 1225 if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg); 1226 if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg); 1227 *err_msg = NULL; 1228 memcpy(ceed->err_msg, "No error message stored", 24); 1229 return CEED_ERROR_SUCCESS; 1230 } 1231 1232 /** 1233 @brief Get libCEED library version info 1234 1235 libCEED version numbers have the form major.minor.patch. 1236 Non-release versions may contain unstable interfaces. 1237 1238 @param[out] major Major version of the library 1239 @param[out] minor Minor version of the library 1240 @param[out] patch Patch (subminor) version of the library 1241 @param[out] release True for releases; false for development branches. 1242 1243 The caller may pass NULL for any arguments that are not needed. 1244 1245 @sa CEED_VERSION_GE() 1246 1247 @ref Developer 1248 */ 1249 int CeedGetVersion(int *major, int *minor, int *patch, bool *release) { 1250 if (major) *major = CEED_VERSION_MAJOR; 1251 if (minor) *minor = CEED_VERSION_MINOR; 1252 if (patch) *patch = CEED_VERSION_PATCH; 1253 if (release) *release = CEED_VERSION_RELEASE; 1254 return 0; 1255 } 1256 1257 int CeedGetScalarType(CeedScalarType *scalar_type) { 1258 *scalar_type = CEED_SCALAR_TYPE; 1259 return 0; 1260 } 1261 1262 /// @} 1263