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 void CeedDebugImpl(const Ceed ceed, const char *format,...) { 210 if (!ceed->debug) return; 211 va_list args; 212 va_start(args, format); 213 CeedDebugImpl256(ceed, 0, format, args); 214 va_end(args); 215 } 216 217 /** 218 @brief Print Ceed debugging information in color 219 220 @param ceed Ceed context 221 @param color Color to print 222 @param format Printing format 223 224 @return None 225 226 @ref Backend 227 **/ 228 void CeedDebugImpl256(const Ceed ceed, const unsigned char color, 229 const char *format,...) { 230 if (!ceed->debug) return; 231 va_list args; 232 va_start(args, format); 233 fflush(stdout); 234 fprintf(stdout, "\033[38;5;%dm", color); 235 vfprintf(stdout, format, args); 236 fprintf(stdout, "\033[m"); 237 fprintf(stdout, "\n"); 238 fflush(stdout); 239 va_end(args); 240 } 241 242 /** 243 @brief Allocate an array on the host; use CeedMalloc() 244 245 Memory usage can be tracked by the library. This ensures sufficient 246 alignment for vectorization and should be used for large allocations. 247 248 @param n Number of units to allocate 249 @param unit Size of each unit 250 @param p Address of pointer to hold the result. 251 252 @return An error code: 0 - success, otherwise - failure 253 254 @sa CeedFree() 255 256 @ref Backend 257 **/ 258 int CeedMallocArray(size_t n, size_t unit, void *p) { 259 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 260 if (ierr) 261 // LCOV_EXCL_START 262 return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 263 "members of size %zd\n", n, unit); 264 // LCOV_EXCL_STOP 265 266 return 0; 267 } 268 269 /** 270 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 271 272 Memory usage can be tracked by the library. 273 274 @param n Number of units to allocate 275 @param unit Size of each unit 276 @param p Address of pointer to hold the result. 277 278 @return An error code: 0 - success, otherwise - failure 279 280 @sa CeedFree() 281 282 @ref Backend 283 **/ 284 int CeedCallocArray(size_t n, size_t unit, void *p) { 285 *(void **)p = calloc(n, unit); 286 if (n && unit && !*(void **)p) 287 // LCOV_EXCL_START 288 return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 289 "%zd\n", n, unit); 290 // LCOV_EXCL_STOP 291 292 return 0; 293 } 294 295 /** 296 @brief Reallocate an array on the host; use CeedRealloc() 297 298 Memory usage can be tracked by the library. 299 300 @param n Number of units to allocate 301 @param unit Size of each unit 302 @param p Address of pointer to hold the result. 303 304 @return An error code: 0 - success, otherwise - failure 305 306 @sa CeedFree() 307 308 @ref Backend 309 **/ 310 int CeedReallocArray(size_t n, size_t unit, void *p) { 311 *(void **)p = realloc(*(void **)p, n*unit); 312 if (n && unit && !*(void **)p) 313 // LCOV_EXCL_START 314 return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 315 "%zd\n", n, unit); 316 // LCOV_EXCL_STOP 317 318 return 0; 319 } 320 321 /** Free memory allocated using CeedMalloc() or CeedCalloc() 322 323 @param p address of pointer to memory. This argument is of type void* to 324 avoid needing a cast, but is the address of the pointer (which is 325 zeroed) rather than the pointer. 326 **/ 327 int CeedFree(void *p) { 328 free(*(void **)p); 329 *(void **)p = NULL; 330 return 0; 331 } 332 333 /** 334 @brief Register a Ceed backend 335 336 @param prefix Prefix of resources for this backend to respond to. For 337 example, the reference backend responds to "/cpu/self". 338 @param init Initialization function called by CeedInit() when the backend 339 is selected to drive the requested resource. 340 @param priority Integer priority. Lower values are preferred in case the 341 resource requested by CeedInit() has non-unique best prefix 342 match. 343 344 @return An error code: 0 - success, otherwise - failure 345 346 @ref Backend 347 **/ 348 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 349 unsigned int priority) { 350 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 351 // LCOV_EXCL_START 352 return CeedError(NULL, 1, "Too many backends"); 353 // LCOV_EXCL_STOP 354 355 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 356 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 357 backends[num_backends].init = init; 358 backends[num_backends].priority = priority; 359 num_backends++; 360 return 0; 361 } 362 363 /** 364 @brief Return debugging status flag 365 366 @param ceed Ceed context to get debugging flag 367 @param isDebug Variable to store debugging flag 368 369 @return An error code: 0 - success, otherwise - failure 370 371 @ref Bcakend 372 **/ 373 int CeedIsDebug(Ceed ceed, bool *isDebug) { 374 *isDebug = ceed->debug; 375 return 0; 376 } 377 378 /** 379 @brief Retrieve a parent Ceed context 380 381 @param ceed Ceed context to retrieve parent of 382 @param[out] parent Address to save the parent to 383 384 @return An error code: 0 - success, otherwise - failure 385 386 @ref Backend 387 **/ 388 int CeedGetParent(Ceed ceed, Ceed *parent) { 389 int ierr; 390 if (ceed->parent) { 391 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 392 return 0; 393 } 394 *parent = ceed; 395 return 0; 396 } 397 398 /** 399 @brief Retrieve a delegate Ceed context 400 401 @param ceed Ceed context to retrieve delegate of 402 @param[out] delegate Address to save the delegate to 403 404 @return An error code: 0 - success, otherwise - failure 405 406 @ref Backend 407 **/ 408 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 409 *delegate = ceed->delegate; 410 return 0; 411 } 412 413 /** 414 @brief Set a delegate Ceed context 415 416 This function allows a Ceed context to set a delegate Ceed context. All 417 backend implementations default to the delegate Ceed context, unless 418 overridden. 419 420 @param ceed Ceed context to set delegate of 421 @param[out] delegate Address to set the delegate to 422 423 @return An error code: 0 - success, otherwise - failure 424 425 @ref Backend 426 **/ 427 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 428 ceed->delegate = delegate; 429 delegate->parent = ceed; 430 return 0; 431 } 432 433 /** 434 @brief Retrieve a delegate Ceed context for a specific object type 435 436 @param ceed Ceed context to retrieve delegate of 437 @param[out] delegate Address to save the delegate to 438 @param[in] objname Name of the object type to retrieve delegate for 439 440 @return An error code: 0 - success, otherwise - failure 441 442 @ref Backend 443 **/ 444 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 445 CeedInt ierr; 446 447 // Check for object delegate 448 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 449 if (!strcmp(objname, ceed->objdelegates->objname)) { 450 *delegate = ceed->objdelegates->delegate; 451 return 0; 452 } 453 454 // Use default delegate if no object delegate 455 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 456 457 return 0; 458 } 459 460 /** 461 @brief Set a delegate Ceed context for a specific object type 462 463 This function allows a Ceed context to set a delegate Ceed context for a 464 given type of Ceed object. All backend implementations default to the 465 delegate Ceed context for this object. For example, 466 CeedSetObjectDelegate(ceed, refceed, "Basis") 467 uses refceed implementations for all CeedBasis backend functions. 468 469 @param ceed Ceed context to set delegate of 470 @param[out] delegate Address to set the delegate to 471 @param[in] objname Name of the object type to set delegate for 472 473 @return An error code: 0 - success, otherwise - failure 474 475 @ref Backend 476 **/ 477 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 478 CeedInt ierr; 479 CeedInt count = ceed->objdelegatecount; 480 481 // Malloc or Realloc 482 if (count) { 483 ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 484 } else { 485 ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 486 } 487 ceed->objdelegatecount++; 488 489 // Set object delegate 490 ceed->objdelegates[count].delegate = delegate; 491 size_t slen = strlen(objname) + 1; 492 ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 493 memcpy(ceed->objdelegates[count].objname, objname, slen); 494 495 // Set delegate parent 496 delegate->parent = ceed; 497 498 return 0; 499 } 500 501 /** 502 @brief Get the fallback resource for CeedOperators 503 504 @param ceed Ceed context 505 @param[out] resource Variable to store fallback resource 506 507 @return An error code: 0 - success, otherwise - failure 508 509 @ref Backend 510 **/ 511 512 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 513 *resource = (const char *)ceed->opfallbackresource; 514 return 0; 515 } 516 517 /** 518 @brief Set the fallback resource for CeedOperators. The current resource, if 519 any, is freed by calling this function. This string is freed upon the 520 destruction of the Ceed context. 521 522 @param[out] ceed Ceed context 523 @param resource Fallback resource to set 524 525 @return An error code: 0 - success, otherwise - failure 526 527 @ref Backend 528 **/ 529 530 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 531 int ierr; 532 533 // Free old 534 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 535 536 // Set new 537 size_t len = strlen(resource); 538 char *tmp; 539 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 540 memcpy(tmp, resource, len+1); 541 ceed->opfallbackresource = tmp; 542 543 return 0; 544 } 545 546 /** 547 @brief Get the parent Ceed context associated with a fallback Ceed context 548 for a CeedOperator 549 550 @param ceed Ceed context 551 @param[out] parent Variable to store parent Ceed context 552 553 @return An error code: 0 - success, otherwise - failure 554 555 @ref Backend 556 **/ 557 558 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 559 *parent = ceed->opfallbackparent; 560 return 0; 561 } 562 563 /** 564 @brief Flag Ceed context as deterministic 565 566 @param ceed Ceed to flag as deterministic 567 568 @return An error code: 0 - success, otherwise - failure 569 570 @ref Backend 571 **/ 572 573 int CeedSetDeterministic(Ceed ceed, bool isDeterministic) { 574 ceed->isDeterministic = isDeterministic; 575 return 0; 576 } 577 578 /** 579 @brief Set a backend function 580 581 This function is used for a backend to set the function associated with 582 the Ceed objects. For example, 583 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 584 sets the backend implementation of 'CeedVectorCreate' and 585 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 586 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 587 is not required for the object type ("Basis" vs "CeedBasis"). 588 589 @param ceed Ceed context for error handling 590 @param type Type of Ceed object to set function for 591 @param[out] object Ceed object to set function for 592 @param fname Name of function to set 593 @param f Function to set 594 595 @return An error code: 0 - success, otherwise - failure 596 597 @ref Backend 598 **/ 599 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 600 const char *fname, int (*f)()) { 601 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 602 603 // Build lookup name 604 if (strcmp(type, "Ceed")) 605 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 606 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 607 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 608 609 // Find and use offset 610 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 611 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 612 size_t offset = ceed->foffsets[i].offset; 613 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 614 *fpointer = f; 615 return 0; 616 } 617 618 // LCOV_EXCL_START 619 return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 620 "object '%s'", fname, type); 621 // LCOV_EXCL_STOP 622 } 623 624 /** 625 @brief Retrieve backend data for a Ceed context 626 627 @param ceed Ceed context to retrieve data of 628 @param[out] data Address to save data to 629 630 @return An error code: 0 - success, otherwise - failure 631 632 @ref Backend 633 **/ 634 int CeedGetData(Ceed ceed, void **data) { 635 *data = ceed->data; 636 return 0; 637 } 638 639 /** 640 @brief Set backend data for a Ceed context 641 642 @param ceed Ceed context to set data of 643 @param data Address of data to set 644 645 @return An error code: 0 - success, otherwise - failure 646 647 @ref Backend 648 **/ 649 int CeedSetData(Ceed ceed, void **data) { 650 ceed->data = *data; 651 return 0; 652 } 653 654 /// @} 655 656 /// ---------------------------------------------------------------------------- 657 /// Ceed Public API 658 /// ---------------------------------------------------------------------------- 659 /// @addtogroup CeedUser 660 /// @{ 661 662 /** 663 @brief Initialize a \ref Ceed context to use the specified resource. 664 665 @param resource Resource to use, e.g., "/cpu/self" 666 @param ceed The library context 667 @sa CeedRegister() CeedDestroy() 668 669 @return An error code: 0 - success, otherwise - failure 670 671 @ref User 672 **/ 673 int CeedInit(const char *resource, Ceed *ceed) { 674 int ierr; 675 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 676 677 // Find matching backend 678 if (!resource) 679 // LCOV_EXCL_START 680 return CeedError(NULL, 1, "No resource provided"); 681 // LCOV_EXCL_STOP 682 683 for (size_t i=0; i<num_backends; i++) { 684 size_t n; 685 const char *prefix = backends[i].prefix; 686 for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 687 priority = backends[i].priority; 688 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 689 matchlen = n; 690 matchpriority = priority; 691 matchidx = i; 692 } 693 } 694 if (!matchlen) 695 // LCOV_EXCL_START 696 return CeedError(NULL, 1, "No suitable backend: %s", resource); 697 // LCOV_EXCL_STOP 698 699 // Setup Ceed 700 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 701 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 702 if (!ceed_error_handler) 703 ceed_error_handler = "abort"; 704 if (!strcmp(ceed_error_handler, "exit")) 705 (*ceed)->Error = CeedErrorExit; 706 else 707 (*ceed)->Error = CeedErrorAbort; 708 (*ceed)->refcount = 1; 709 (*ceed)->data = NULL; 710 711 // Set lookup table 712 foffset foffsets[] = { 713 CEED_FTABLE_ENTRY(Ceed, Error), 714 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 715 CEED_FTABLE_ENTRY(Ceed, Destroy), 716 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 717 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 718 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 719 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 720 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 721 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 722 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 723 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 724 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 725 CEED_FTABLE_ENTRY(CeedVector, SetArray), 726 CEED_FTABLE_ENTRY(CeedVector, SetValue), 727 CEED_FTABLE_ENTRY(CeedVector, GetArray), 728 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 729 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 730 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 731 CEED_FTABLE_ENTRY(CeedVector, Norm), 732 CEED_FTABLE_ENTRY(CeedVector, Destroy), 733 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 734 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 735 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 736 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 737 CEED_FTABLE_ENTRY(CeedBasis, Apply), 738 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 739 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 740 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 741 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 742 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 743 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 744 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 745 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 746 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 747 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 748 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 749 CEED_FTABLE_ENTRY(CeedOperator, Apply), 750 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 751 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 752 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 753 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 754 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 755 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 756 }; 757 758 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 759 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 760 761 // Set fallback for advanced CeedOperator functions 762 const char fallbackresource[] = "/cpu/self/ref/serial"; 763 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 764 CeedChk(ierr); 765 766 // Record env variables CEED_DEBUG or DBG 767 (*ceed)->debug = !!getenv("CEED_DEBUG") || !!getenv("DBG"); 768 769 // Backend specific setup 770 ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 771 772 // Copy resource prefix, if backend setup sucessful 773 size_t len = strlen(backends[matchidx].prefix); 774 char *tmp; 775 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 776 memcpy(tmp, backends[matchidx].prefix, len+1); 777 (*ceed)->resource = tmp; 778 779 return 0; 780 } 781 782 /** 783 @brief Get the full resource name for a Ceed context 784 785 @param ceed Ceed context to get resource name of 786 @param[out] resource Variable to store resource name 787 788 @return An error code: 0 - success, otherwise - failure 789 790 @ref User 791 **/ 792 793 int CeedGetResource(Ceed ceed, const char **resource) { 794 *resource = (const char *)ceed->resource; 795 return 0; 796 } 797 798 /** 799 @brief Return Ceed context preferred memory type 800 801 @param ceed Ceed context to get preferred memory type of 802 @param[out] type Address to save preferred memory type to 803 804 @return An error code: 0 - success, otherwise - failure 805 806 @ref User 807 **/ 808 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 809 int ierr; 810 811 if (ceed->GetPreferredMemType) { 812 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 813 } else { 814 Ceed delegate; 815 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 816 817 if (delegate) { 818 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 819 } else { 820 *type = CEED_MEM_HOST; 821 } 822 } 823 824 return 0; 825 } 826 827 /** 828 @brief Get deterministic status of Ceed 829 830 @param[in] ceed Ceed 831 @param[out] isDeterministic Variable to store deterministic status 832 833 @return An error code: 0 - success, otherwise - failure 834 835 @ref User 836 **/ 837 int CeedIsDeterministic(Ceed ceed, bool *isDeterministic) { 838 *isDeterministic = ceed->isDeterministic; 839 return 0; 840 } 841 842 /** 843 @brief View a Ceed 844 845 @param[in] ceed Ceed to view 846 @param[in] stream Filestream to write to 847 848 @return An error code: 0 - success, otherwise - failure 849 850 @ref User 851 **/ 852 int CeedView(Ceed ceed, FILE *stream) { 853 int ierr; 854 CeedMemType memtype; 855 856 ierr = CeedGetPreferredMemType(ceed, &memtype); CeedChk(ierr); 857 858 fprintf(stream, "Ceed\n" 859 " Ceed Resource: %s\n" 860 " Preferred MemType: %s\n", 861 ceed->resource, CeedMemTypes[memtype]); 862 863 return 0; 864 } 865 866 /** 867 @brief Destroy a Ceed context 868 869 @param ceed Address of Ceed context to destroy 870 871 @return An error code: 0 - success, otherwise - failure 872 873 @ref User 874 **/ 875 int CeedDestroy(Ceed *ceed) { 876 int ierr; 877 if (!*ceed || --(*ceed)->refcount > 0) 878 return 0; 879 880 if ((*ceed)->delegate) { 881 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 882 } 883 884 if ((*ceed)->objdelegatecount > 0) { 885 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 886 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 887 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 888 } 889 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 890 } 891 892 if ((*ceed)->Destroy) { 893 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 894 } 895 896 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 897 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 898 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 899 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 900 ierr = CeedFree(ceed); CeedChk(ierr); 901 return 0; 902 } 903 904 /** 905 @brief Error handling implementation; use \ref CeedError instead. 906 907 @ref Developer 908 **/ 909 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 910 int ecode, const char *format, ...) { 911 va_list args; 912 int retval; 913 va_start(args, format); 914 if (ceed) { 915 retval = ceed->Error(ceed, filename, lineno, func, ecode, format, args); 916 } else { 917 // This function doesn't actually return 918 // LCOV_EXCL_START 919 retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args); 920 } 921 va_end(args); 922 return retval; 923 // LCOV_EXCL_STOP 924 } 925 926 /// @} 927