1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #define _POSIX_C_SOURCE 200112 18 #include <ceed-impl.h> 19 #include <ceed-backend.h> 20 #include <limits.h> 21 #include <stdarg.h> 22 #include <stddef.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 /// @cond DOXYGEN_SKIP 28 static CeedRequest ceed_request_immediate; 29 static CeedRequest ceed_request_ordered; 30 31 static struct { 32 char prefix[CEED_MAX_RESOURCE_LEN]; 33 int (*init)(const char *resource, Ceed f); 34 unsigned int priority; 35 } backends[32]; 36 static size_t num_backends; 37 38 #define CEED_FTABLE_ENTRY(class, method) \ 39 {#class #method, offsetof(struct class ##_private, method)} 40 /// @endcond 41 42 /// @file 43 /// Implementation of core components of Ceed library 44 45 /// @addtogroup CeedUser 46 /// @{ 47 48 /** 49 @brief Request immediate completion 50 51 This predefined constant is passed as the \ref CeedRequest argument to 52 interfaces when the caller wishes for the operation to be performed 53 immediately. The code 54 55 @code 56 CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 57 @endcode 58 59 is semantically equivalent to 60 61 @code 62 CeedRequest request; 63 CeedOperatorApply(op, ..., &request); 64 CeedRequestWait(&request); 65 @endcode 66 67 @sa CEED_REQUEST_ORDERED 68 **/ 69 CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 70 71 /** 72 @brief Request ordered completion 73 74 This predefined constant is passed as the \ref CeedRequest argument to 75 interfaces when the caller wishes for the operation to be completed in the 76 order that it is submitted to the device. It is typically used in a construct 77 such as 78 79 @code 80 CeedRequest request; 81 CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 82 CeedOperatorApply(op2, ..., &request); 83 // other optional work 84 CeedWait(&request); 85 @endcode 86 87 which allows the sequence to complete asynchronously but does not start 88 `op2` until `op1` has completed. 89 90 @todo The current implementation is overly strict, offering equivalent 91 semantics to @ref CEED_REQUEST_IMMEDIATE. 92 93 @sa CEED_REQUEST_IMMEDIATE 94 */ 95 CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 96 97 /** 98 @brief Wait for a CeedRequest to complete. 99 100 Calling CeedRequestWait on a NULL request is a no-op. 101 102 @param req Address of CeedRequest to wait for; zeroed on completion. 103 104 @return An error code: 0 - success, otherwise - failure 105 106 @ref User 107 **/ 108 int CeedRequestWait(CeedRequest *req) { 109 if (!*req) 110 return 0; 111 return CeedError(NULL, 2, "CeedRequestWait not implemented"); 112 } 113 114 /// @} 115 116 /// ---------------------------------------------------------------------------- 117 /// Ceed Library Internal Functions 118 /// ---------------------------------------------------------------------------- 119 /// @addtogroup CeedDeveloper 120 /// @{ 121 122 /** 123 @brief Error handler that returns without printing anything. 124 125 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 126 127 @ref Developer 128 **/ 129 // LCOV_EXCL_START 130 int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 131 const char *func, int ecode, const char *format, 132 va_list args) { 133 return ecode; 134 } 135 // LCOV_EXCL_STOP 136 137 /** 138 @brief Error handler that prints to stderr and aborts 139 140 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 141 142 @ref Developer 143 **/ 144 // LCOV_EXCL_START 145 int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 146 const char *func, int ecode, const char *format, 147 va_list args) { 148 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 149 vfprintf(stderr, format, args); 150 fprintf(stderr, "\n"); 151 abort(); 152 return ecode; 153 } 154 // LCOV_EXCL_STOP 155 156 /** 157 @brief Error handler that prints to stderr and exits 158 159 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 160 161 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 162 handlers (e.g., as used by gcov) are run. 163 164 @ref Developer 165 **/ 166 int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 167 int ecode, const char *format, va_list args) { 168 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 169 vfprintf(stderr, format, args); 170 fprintf(stderr, "\n"); 171 exit(ecode); 172 return ecode; 173 } 174 175 /** 176 @brief Set error handler 177 178 A default error handler is set in CeedInit(). Use this function to change 179 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 180 error handler. 181 182 @ref Developer 183 **/ 184 int CeedSetErrorHandler(Ceed ceed, 185 int (*eh)(Ceed, const char *, int, const char *, 186 int, const char *, va_list)) { 187 ceed->Error = eh; 188 return 0; 189 } 190 191 /// @} 192 193 /// ---------------------------------------------------------------------------- 194 /// Ceed Backend API 195 /// ---------------------------------------------------------------------------- 196 /// @addtogroup CeedBackend 197 /// @{ 198 199 /** 200 @brief Print Ceed debugging information 201 202 @param ceed Ceed context 203 @param format Printing format 204 205 @return None 206 207 @ref Backend 208 **/ 209 // LCOV_EXCL_START 210 void CeedDebugImpl(const Ceed ceed, const char *format,...) { 211 if (!ceed->debug) return; 212 va_list args; 213 va_start(args, format); 214 CeedDebugImpl256(ceed, 0, format, args); 215 va_end(args); 216 } 217 // LCOV_EXCL_STOP 218 219 /** 220 @brief Print Ceed debugging information in color 221 222 @param ceed Ceed context 223 @param color Color to print 224 @param format Printing format 225 226 @return None 227 228 @ref Backend 229 **/ 230 // LCOV_EXCL_START 231 void CeedDebugImpl256(const Ceed ceed, const unsigned char color, 232 const char *format,...) { 233 if (!ceed->debug) return; 234 va_list args; 235 va_start(args, format); 236 fflush(stdout); 237 fprintf(stdout, "\033[38;5;%dm", color); 238 vfprintf(stdout, format, args); 239 fprintf(stdout, "\033[m"); 240 fprintf(stdout, "\n"); 241 fflush(stdout); 242 va_end(args); 243 } 244 // LCOV_EXCL_STOP 245 246 /** 247 @brief Allocate an array on the host; use CeedMalloc() 248 249 Memory usage can be tracked by the library. This ensures sufficient 250 alignment for vectorization and should be used for large allocations. 251 252 @param n Number of units to allocate 253 @param unit Size of each unit 254 @param p Address of pointer to hold the result. 255 256 @return An error code: 0 - success, otherwise - failure 257 258 @sa CeedFree() 259 260 @ref Backend 261 **/ 262 int CeedMallocArray(size_t n, size_t unit, void *p) { 263 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 264 if (ierr) 265 // LCOV_EXCL_START 266 return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 267 "members of size %zd\n", n, unit); 268 // LCOV_EXCL_STOP 269 270 return 0; 271 } 272 273 /** 274 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 275 276 Memory usage can be tracked by the library. 277 278 @param n Number of units to allocate 279 @param unit Size of each unit 280 @param p Address of pointer to hold the result. 281 282 @return An error code: 0 - success, otherwise - failure 283 284 @sa CeedFree() 285 286 @ref Backend 287 **/ 288 int CeedCallocArray(size_t n, size_t unit, void *p) { 289 *(void **)p = calloc(n, unit); 290 if (n && unit && !*(void **)p) 291 // LCOV_EXCL_START 292 return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 293 "%zd\n", n, unit); 294 // LCOV_EXCL_STOP 295 296 return 0; 297 } 298 299 /** 300 @brief Reallocate an array on the host; use CeedRealloc() 301 302 Memory usage can be tracked by the library. 303 304 @param n Number of units to allocate 305 @param unit Size of each unit 306 @param p Address of pointer to hold the result. 307 308 @return An error code: 0 - success, otherwise - failure 309 310 @sa CeedFree() 311 312 @ref Backend 313 **/ 314 int CeedReallocArray(size_t n, size_t unit, void *p) { 315 *(void **)p = realloc(*(void **)p, n*unit); 316 if (n && unit && !*(void **)p) 317 // LCOV_EXCL_START 318 return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 319 "%zd\n", n, unit); 320 // LCOV_EXCL_STOP 321 322 return 0; 323 } 324 325 /** Free memory allocated using CeedMalloc() or CeedCalloc() 326 327 @param p address of pointer to memory. This argument is of type void* to 328 avoid needing a cast, but is the address of the pointer (which is 329 zeroed) rather than the pointer. 330 **/ 331 int CeedFree(void *p) { 332 free(*(void **)p); 333 *(void **)p = NULL; 334 return 0; 335 } 336 337 /** 338 @brief Register a Ceed backend 339 340 @param prefix Prefix of resources for this backend to respond to. For 341 example, the reference backend responds to "/cpu/self". 342 @param init Initialization function called by CeedInit() when the backend 343 is selected to drive the requested resource. 344 @param priority Integer priority. Lower values are preferred in case the 345 resource requested by CeedInit() has non-unique best prefix 346 match. 347 348 @return An error code: 0 - success, otherwise - failure 349 350 @ref Backend 351 **/ 352 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 353 unsigned int priority) { 354 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 355 // LCOV_EXCL_START 356 return CeedError(NULL, 1, "Too many backends"); 357 // LCOV_EXCL_STOP 358 359 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 360 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 361 backends[num_backends].init = init; 362 backends[num_backends].priority = priority; 363 num_backends++; 364 return 0; 365 } 366 367 /** 368 @brief Return debugging status flag 369 370 @param ceed Ceed context to get debugging flag 371 @param isDebug Variable to store debugging flag 372 373 @return An error code: 0 - success, otherwise - failure 374 375 @ref Bcakend 376 **/ 377 int CeedIsDebug(Ceed ceed, bool *isDebug) { 378 *isDebug = ceed->debug; 379 return 0; 380 } 381 382 /** 383 @brief Retrieve a parent Ceed context 384 385 @param ceed Ceed context to retrieve parent of 386 @param[out] parent Address to save the parent to 387 388 @return An error code: 0 - success, otherwise - failure 389 390 @ref Backend 391 **/ 392 int CeedGetParent(Ceed ceed, Ceed *parent) { 393 int ierr; 394 if (ceed->parent) { 395 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 396 return 0; 397 } 398 *parent = ceed; 399 return 0; 400 } 401 402 /** 403 @brief Retrieve a delegate Ceed context 404 405 @param ceed Ceed context to retrieve delegate of 406 @param[out] delegate Address to save the delegate to 407 408 @return An error code: 0 - success, otherwise - failure 409 410 @ref Backend 411 **/ 412 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 413 *delegate = ceed->delegate; 414 return 0; 415 } 416 417 /** 418 @brief Set a delegate Ceed context 419 420 This function allows a Ceed context to set a delegate Ceed context. All 421 backend implementations default to the delegate Ceed context, unless 422 overridden. 423 424 @param ceed Ceed context to set delegate of 425 @param[out] delegate Address to set the delegate to 426 427 @return An error code: 0 - success, otherwise - failure 428 429 @ref Backend 430 **/ 431 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 432 ceed->delegate = delegate; 433 delegate->parent = ceed; 434 return 0; 435 } 436 437 /** 438 @brief Retrieve a delegate Ceed context for a specific object type 439 440 @param ceed Ceed context to retrieve delegate of 441 @param[out] delegate Address to save the delegate to 442 @param[in] objname Name of the object type to retrieve delegate for 443 444 @return An error code: 0 - success, otherwise - failure 445 446 @ref Backend 447 **/ 448 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 449 CeedInt ierr; 450 451 // Check for object delegate 452 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 453 if (!strcmp(objname, ceed->objdelegates->objname)) { 454 *delegate = ceed->objdelegates->delegate; 455 return 0; 456 } 457 458 // Use default delegate if no object delegate 459 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 460 461 return 0; 462 } 463 464 /** 465 @brief Set a delegate Ceed context for a specific object type 466 467 This function allows a Ceed context to set a delegate Ceed context for a 468 given type of Ceed object. All backend implementations default to the 469 delegate Ceed context for this object. For example, 470 CeedSetObjectDelegate(ceed, refceed, "Basis") 471 uses refceed implementations for all CeedBasis backend functions. 472 473 @param ceed Ceed context to set delegate of 474 @param[out] delegate Address to set the delegate to 475 @param[in] objname Name of the object type to set delegate for 476 477 @return An error code: 0 - success, otherwise - failure 478 479 @ref Backend 480 **/ 481 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 482 CeedInt ierr; 483 CeedInt count = ceed->objdelegatecount; 484 485 // Malloc or Realloc 486 if (count) { 487 ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 488 } else { 489 ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 490 } 491 ceed->objdelegatecount++; 492 493 // Set object delegate 494 ceed->objdelegates[count].delegate = delegate; 495 size_t slen = strlen(objname) + 1; 496 ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 497 memcpy(ceed->objdelegates[count].objname, objname, slen); 498 499 // Set delegate parent 500 delegate->parent = ceed; 501 502 return 0; 503 } 504 505 /** 506 @brief Get the fallback resource for CeedOperators 507 508 @param ceed Ceed context 509 @param[out] resource Variable to store fallback resource 510 511 @return An error code: 0 - success, otherwise - failure 512 513 @ref Backend 514 **/ 515 516 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 517 *resource = (const char *)ceed->opfallbackresource; 518 return 0; 519 } 520 521 /** 522 @brief Set the fallback resource for CeedOperators. The current resource, if 523 any, is freed by calling this function. This string is freed upon the 524 destruction of the Ceed context. 525 526 @param[out] ceed Ceed context 527 @param resource Fallback resource to set 528 529 @return An error code: 0 - success, otherwise - failure 530 531 @ref Backend 532 **/ 533 534 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 535 int ierr; 536 537 // Free old 538 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 539 540 // Set new 541 size_t len = strlen(resource); 542 char *tmp; 543 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 544 memcpy(tmp, resource, len+1); 545 ceed->opfallbackresource = tmp; 546 547 return 0; 548 } 549 550 /** 551 @brief Get the parent Ceed context associated with a fallback Ceed context 552 for a CeedOperator 553 554 @param ceed Ceed context 555 @param[out] parent Variable to store parent Ceed context 556 557 @return An error code: 0 - success, otherwise - failure 558 559 @ref Backend 560 **/ 561 562 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 563 *parent = ceed->opfallbackparent; 564 return 0; 565 } 566 567 /** 568 @brief Flag Ceed context as deterministic 569 570 @param ceed Ceed to flag as deterministic 571 572 @return An error code: 0 - success, otherwise - failure 573 574 @ref Backend 575 **/ 576 577 int CeedSetDeterministic(Ceed ceed, bool isDeterministic) { 578 ceed->isDeterministic = isDeterministic; 579 return 0; 580 } 581 582 /** 583 @brief Set a backend function 584 585 This function is used for a backend to set the function associated with 586 the Ceed objects. For example, 587 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 588 sets the backend implementation of 'CeedVectorCreate' and 589 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 590 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 591 is not required for the object type ("Basis" vs "CeedBasis"). 592 593 @param ceed Ceed context for error handling 594 @param type Type of Ceed object to set function for 595 @param[out] object Ceed object to set function for 596 @param fname Name of function to set 597 @param f Function to set 598 599 @return An error code: 0 - success, otherwise - failure 600 601 @ref Backend 602 **/ 603 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 604 const char *fname, int (*f)()) { 605 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 606 607 // Build lookup name 608 if (strcmp(type, "Ceed")) 609 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 610 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 611 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 612 613 // Find and use offset 614 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 615 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 616 size_t offset = ceed->foffsets[i].offset; 617 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 618 *fpointer = f; 619 return 0; 620 } 621 622 // LCOV_EXCL_START 623 return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 624 "object '%s'", fname, type); 625 // LCOV_EXCL_STOP 626 } 627 628 /** 629 @brief Retrieve backend data for a Ceed context 630 631 @param ceed Ceed context to retrieve data of 632 @param[out] data Address to save data to 633 634 @return An error code: 0 - success, otherwise - failure 635 636 @ref Backend 637 **/ 638 int CeedGetData(Ceed ceed, void **data) { 639 *data = ceed->data; 640 return 0; 641 } 642 643 /** 644 @brief Set backend data for a Ceed context 645 646 @param ceed Ceed context to set data of 647 @param data Address of data to set 648 649 @return An error code: 0 - success, otherwise - failure 650 651 @ref Backend 652 **/ 653 int CeedSetData(Ceed ceed, void **data) { 654 ceed->data = *data; 655 return 0; 656 } 657 658 /// @} 659 660 /// ---------------------------------------------------------------------------- 661 /// Ceed Public API 662 /// ---------------------------------------------------------------------------- 663 /// @addtogroup CeedUser 664 /// @{ 665 666 /** 667 @brief Initialize a \ref Ceed context to use the specified resource. 668 669 @param resource Resource to use, e.g., "/cpu/self" 670 @param ceed The library context 671 @sa CeedRegister() CeedDestroy() 672 673 @return An error code: 0 - success, otherwise - failure 674 675 @ref User 676 **/ 677 int CeedInit(const char *resource, Ceed *ceed) { 678 int ierr; 679 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 680 681 // Find matching backend 682 if (!resource) 683 // LCOV_EXCL_START 684 return CeedError(NULL, 1, "No resource provided"); 685 // LCOV_EXCL_STOP 686 687 for (size_t i=0; i<num_backends; i++) { 688 size_t n; 689 const char *prefix = backends[i].prefix; 690 for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 691 priority = backends[i].priority; 692 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 693 matchlen = n; 694 matchpriority = priority; 695 matchidx = i; 696 } 697 } 698 if (!matchlen) 699 // LCOV_EXCL_START 700 return CeedError(NULL, 1, "No suitable backend: %s", resource); 701 // LCOV_EXCL_STOP 702 703 // Setup Ceed 704 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 705 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 706 if (!ceed_error_handler) 707 ceed_error_handler = "abort"; 708 if (!strcmp(ceed_error_handler, "exit")) 709 (*ceed)->Error = CeedErrorExit; 710 else 711 (*ceed)->Error = CeedErrorAbort; 712 (*ceed)->refcount = 1; 713 (*ceed)->data = NULL; 714 715 // Set lookup table 716 foffset foffsets[] = { 717 CEED_FTABLE_ENTRY(Ceed, Error), 718 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 719 CEED_FTABLE_ENTRY(Ceed, Destroy), 720 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 721 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 722 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 723 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 724 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 725 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 726 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 727 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 728 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 729 CEED_FTABLE_ENTRY(CeedVector, SetArray), 730 CEED_FTABLE_ENTRY(CeedVector, SetValue), 731 CEED_FTABLE_ENTRY(CeedVector, GetArray), 732 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 733 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 734 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 735 CEED_FTABLE_ENTRY(CeedVector, Norm), 736 CEED_FTABLE_ENTRY(CeedVector, Destroy), 737 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 738 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 739 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 740 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 741 CEED_FTABLE_ENTRY(CeedBasis, Apply), 742 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 743 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 744 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 745 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 746 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 747 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 748 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 749 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 750 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 751 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 752 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 753 CEED_FTABLE_ENTRY(CeedOperator, Apply), 754 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 755 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 756 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 757 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 758 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 759 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 760 }; 761 762 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 763 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 764 765 // Set fallback for advanced CeedOperator functions 766 const char fallbackresource[] = "/cpu/self/ref/serial"; 767 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 768 CeedChk(ierr); 769 770 // Record env variables CEED_DEBUG or DBG 771 (*ceed)->debug = !!getenv("CEED_DEBUG") || !!getenv("DBG"); 772 773 // Backend specific setup 774 ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 775 776 // Copy resource prefix, if backend setup sucessful 777 size_t len = strlen(backends[matchidx].prefix); 778 char *tmp; 779 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 780 memcpy(tmp, backends[matchidx].prefix, len+1); 781 (*ceed)->resource = tmp; 782 783 return 0; 784 } 785 786 /** 787 @brief Get the full resource name for a Ceed context 788 789 @param ceed Ceed context to get resource name of 790 @param[out] resource Variable to store resource name 791 792 @return An error code: 0 - success, otherwise - failure 793 794 @ref User 795 **/ 796 797 int CeedGetResource(Ceed ceed, const char **resource) { 798 *resource = (const char *)ceed->resource; 799 return 0; 800 } 801 802 /** 803 @brief Return Ceed context preferred memory type 804 805 @param ceed Ceed context to get preferred memory type of 806 @param[out] type Address to save preferred memory type to 807 808 @return An error code: 0 - success, otherwise - failure 809 810 @ref User 811 **/ 812 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 813 int ierr; 814 815 if (ceed->GetPreferredMemType) { 816 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 817 } else { 818 Ceed delegate; 819 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 820 821 if (delegate) { 822 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 823 } else { 824 *type = CEED_MEM_HOST; 825 } 826 } 827 828 return 0; 829 } 830 831 /** 832 @brief Get deterministic status of Ceed 833 834 @param[in] ceed Ceed 835 @param[out] isDeterministic Variable to store deterministic status 836 837 @return An error code: 0 - success, otherwise - failure 838 839 @ref User 840 **/ 841 int CeedIsDeterministic(Ceed ceed, bool *isDeterministic) { 842 *isDeterministic = ceed->isDeterministic; 843 return 0; 844 } 845 846 /** 847 @brief View a Ceed 848 849 @param[in] ceed Ceed to view 850 @param[in] stream Filestream to write to 851 852 @return An error code: 0 - success, otherwise - failure 853 854 @ref User 855 **/ 856 int CeedView(Ceed ceed, FILE *stream) { 857 int ierr; 858 CeedMemType memtype; 859 860 ierr = CeedGetPreferredMemType(ceed, &memtype); CeedChk(ierr); 861 862 fprintf(stream, "Ceed\n" 863 " Ceed Resource: %s\n" 864 " Preferred MemType: %s\n", 865 ceed->resource, CeedMemTypes[memtype]); 866 867 return 0; 868 } 869 870 /** 871 @brief Destroy a Ceed context 872 873 @param ceed Address of Ceed context to destroy 874 875 @return An error code: 0 - success, otherwise - failure 876 877 @ref User 878 **/ 879 int CeedDestroy(Ceed *ceed) { 880 int ierr; 881 if (!*ceed || --(*ceed)->refcount > 0) 882 return 0; 883 884 if ((*ceed)->delegate) { 885 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 886 } 887 888 if ((*ceed)->objdelegatecount > 0) { 889 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 890 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 891 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 892 } 893 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 894 } 895 896 if ((*ceed)->Destroy) { 897 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 898 } 899 900 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 901 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 902 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 903 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 904 ierr = CeedFree(ceed); CeedChk(ierr); 905 return 0; 906 } 907 908 /** 909 @brief Error handling implementation; use \ref CeedError instead. 910 911 @ref Developer 912 **/ 913 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 914 int ecode, const char *format, ...) { 915 va_list args; 916 int retval; 917 va_start(args, format); 918 if (ceed) { 919 retval = ceed->Error(ceed, filename, lineno, func, ecode, format, args); 920 } else { 921 // This function doesn't actually return 922 // LCOV_EXCL_START 923 retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args); 924 } 925 va_end(args); 926 return retval; 927 // LCOV_EXCL_STOP 928 } 929 930 /// @} 931