1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details. 4d7b241e6Sjeremylt // 5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software 6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral 7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and 8d7b241e6Sjeremylt // source code availability see http://github.com/ceed. 9d7b241e6Sjeremylt // 10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office 12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for 13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including 14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early 15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative. 16d7b241e6Sjeremylt 17d7b241e6Sjeremylt #define _POSIX_C_SOURCE 200112 18d7b241e6Sjeremylt #include <ceed-impl.h> 19d863ab9bSjeremylt #include <ceed-backend.h> 20aedaa0e5Sjeremylt #include <limits.h> 21d7b241e6Sjeremylt #include <stdarg.h> 226e79d475Sjeremylt #include <stddef.h> 23d7b241e6Sjeremylt #include <stdio.h> 24d7b241e6Sjeremylt #include <stdlib.h> 25d7b241e6Sjeremylt #include <string.h> 26d7b241e6Sjeremylt 27d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP 28d7b241e6Sjeremylt static CeedRequest ceed_request_immediate; 29d7b241e6Sjeremylt static CeedRequest ceed_request_ordered; 30d7b241e6Sjeremylt 31d7b241e6Sjeremylt static struct { 32d7b241e6Sjeremylt char prefix[CEED_MAX_RESOURCE_LEN]; 33d7b241e6Sjeremylt int (*init)(const char *resource, Ceed f); 34d7b241e6Sjeremylt unsigned int priority; 35d7b241e6Sjeremylt } backends[32]; 36d7b241e6Sjeremylt static size_t num_backends; 37fe2413ffSjeremylt 386e79d475Sjeremylt #define CEED_FTABLE_ENTRY(class, method) \ 396e79d475Sjeremylt {#class #method, offsetof(struct class ##_private, method)} 40d7b241e6Sjeremylt /// @endcond 41d7b241e6Sjeremylt 42d7b241e6Sjeremylt /// @file 43d7b241e6Sjeremylt /// Implementation of core components of Ceed library 44d7b241e6Sjeremylt /// 45dfdf5a53Sjeremylt /// @addtogroup Ceed 46d7b241e6Sjeremylt /// @{ 47d7b241e6Sjeremylt 48dfdf5a53Sjeremylt /** 49dfdf5a53Sjeremylt @brief Request immediate completion 50dfdf5a53Sjeremylt 51dfdf5a53Sjeremylt This predefined constant is passed as the \ref CeedRequest argument to 52dfdf5a53Sjeremylt interfaces when the caller wishes for the operation to be performed 53dfdf5a53Sjeremylt immediately. The code 54dfdf5a53Sjeremylt 55dfdf5a53Sjeremylt @code 56dfdf5a53Sjeremylt CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 57dfdf5a53Sjeremylt @endcode 58dfdf5a53Sjeremylt 59dfdf5a53Sjeremylt is semantically equivalent to 60dfdf5a53Sjeremylt 61dfdf5a53Sjeremylt @code 62dfdf5a53Sjeremylt CeedRequest request; 63dfdf5a53Sjeremylt CeedOperatorApply(op, ..., &request); 64dfdf5a53Sjeremylt CeedRequestWait(&request); 65dfdf5a53Sjeremylt @endcode 66dfdf5a53Sjeremylt 67dfdf5a53Sjeremylt @sa CEED_REQUEST_ORDERED 68dfdf5a53Sjeremylt **/ 69d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 70d7b241e6Sjeremylt 71d7b241e6Sjeremylt /** 72b11c1e72Sjeremylt @brief Request ordered completion 73d7b241e6Sjeremylt 74d7b241e6Sjeremylt This predefined constant is passed as the \ref CeedRequest argument to 75d7b241e6Sjeremylt interfaces when the caller wishes for the operation to be completed in the 76d7b241e6Sjeremylt order that it is submitted to the device. It is typically used in a construct 77d7b241e6Sjeremylt such as 78d7b241e6Sjeremylt 79d7b241e6Sjeremylt @code 80d7b241e6Sjeremylt CeedRequest request; 81d7b241e6Sjeremylt CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 82d7b241e6Sjeremylt CeedOperatorApply(op2, ..., &request); 83d7b241e6Sjeremylt // other optional work 84d7b241e6Sjeremylt CeedWait(&request); 85d7b241e6Sjeremylt @endcode 86d7b241e6Sjeremylt 87d7b241e6Sjeremylt which allows the sequence to complete asynchronously but does not start 88d7b241e6Sjeremylt `op2` until `op1` has completed. 89d7b241e6Sjeremylt 90288c0443SJeremy L Thompson @todo The current implementation is overly strict, offering equivalent 91d7b241e6Sjeremylt semantics to CEED_REQUEST_IMMEDIATE. 92d7b241e6Sjeremylt 93d7b241e6Sjeremylt @sa CEED_REQUEST_IMMEDIATE 94d7b241e6Sjeremylt */ 95d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 96d7b241e6Sjeremylt 97b11c1e72Sjeremylt /** 98b11c1e72Sjeremylt @brief Error handling implementation; use \ref CeedError instead. 99dfdf5a53Sjeremylt 100dfdf5a53Sjeremylt @ref Developer 101b11c1e72Sjeremylt **/ 102d7b241e6Sjeremylt int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 103d7b241e6Sjeremylt int ecode, const char *format, ...) { 104d7b241e6Sjeremylt va_list args; 105683faae0SJed Brown int retval; 106d7b241e6Sjeremylt va_start(args, format); 107683faae0SJed Brown if (ceed) { 108683faae0SJed Brown retval = ceed->Error(ceed, filename, lineno, func, ecode, format, args); 109683faae0SJed Brown } else { 110683faae0SJed Brown // This function doesn't actually return 111683faae0SJed Brown retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args); 112683faae0SJed Brown } 113683faae0SJed Brown va_end(args); 114683faae0SJed Brown return retval; 115d7b241e6Sjeremylt } 116d7b241e6Sjeremylt 117b11c1e72Sjeremylt /** 118b11c1e72Sjeremylt @brief Error handler that returns without printing anything. 119b11c1e72Sjeremylt 120b11c1e72Sjeremylt Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 121dfdf5a53Sjeremylt 122dfdf5a53Sjeremylt @ref Developer 123b11c1e72Sjeremylt **/ 12413873f79Sjeremylt // LCOV_EXCL_START 125d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 126d7b241e6Sjeremylt const char *func, int ecode, const char *format, 127d7b241e6Sjeremylt va_list args) { 128d7b241e6Sjeremylt return ecode; 129d7b241e6Sjeremylt } 13013873f79Sjeremylt // LCOV_EXCL_STOP 131d7b241e6Sjeremylt 132b11c1e72Sjeremylt /** 133b11c1e72Sjeremylt @brief Error handler that prints to stderr and aborts 134b11c1e72Sjeremylt 135b11c1e72Sjeremylt Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 136dfdf5a53Sjeremylt 137dfdf5a53Sjeremylt @ref Developer 138b11c1e72Sjeremylt **/ 13913873f79Sjeremylt // LCOV_EXCL_START 140d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 1411d102b48SJeremy L Thompson const char *func, int ecode, const char *format, 1421d102b48SJeremy L Thompson va_list args) { 143d7b241e6Sjeremylt fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 144d7b241e6Sjeremylt vfprintf(stderr, format, args); 145d7b241e6Sjeremylt fprintf(stderr, "\n"); 146d7b241e6Sjeremylt abort(); 147d7b241e6Sjeremylt return ecode; 148d7b241e6Sjeremylt } 14913873f79Sjeremylt // LCOV_EXCL_STOP 150d7b241e6Sjeremylt 151b11c1e72Sjeremylt /** 15256e866f4SJed Brown @brief Error handler that prints to stderr and exits 15356e866f4SJed Brown 15456e866f4SJed Brown Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 15556e866f4SJed Brown 15656e866f4SJed Brown In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 15756e866f4SJed Brown handlers (e.g., as used by gcov) are run. 15856e866f4SJed Brown 15956e866f4SJed Brown @ref Developer 16056e866f4SJed Brown **/ 161692c2638Sjeremylt int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 162692c2638Sjeremylt int ecode, const char *format, va_list args) { 16356e866f4SJed Brown fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 16456e866f4SJed Brown vfprintf(stderr, format, args); 16556e866f4SJed Brown fprintf(stderr, "\n"); 16656e866f4SJed Brown exit(ecode); 16756e866f4SJed Brown return ecode; 16856e866f4SJed Brown } 16956e866f4SJed Brown 17056e866f4SJed Brown /** 171dfdf5a53Sjeremylt @brief Set error handler 172b11c1e72Sjeremylt 173b11c1e72Sjeremylt A default error handler is set in CeedInit(). Use this function to change 174b11c1e72Sjeremylt the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 175b11c1e72Sjeremylt error handler. 176dfdf5a53Sjeremylt 177dfdf5a53Sjeremylt @ref Developer 178b11c1e72Sjeremylt **/ 179d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed, 180d7b241e6Sjeremylt int (eh)(Ceed, const char *, int, const char *, 181d7b241e6Sjeremylt int, const char *, va_list)) { 182d7b241e6Sjeremylt ceed->Error = eh; 183d7b241e6Sjeremylt return 0; 184d7b241e6Sjeremylt } 185d7b241e6Sjeremylt 186d7b241e6Sjeremylt /** 187b11c1e72Sjeremylt @brief Register a Ceed backend 188d7b241e6Sjeremylt 189d7b241e6Sjeremylt @param prefix Prefix of resources for this backend to respond to. For 190d7b241e6Sjeremylt example, the reference backend responds to "/cpu/self". 191d7b241e6Sjeremylt @param init Initialization function called by CeedInit() when the backend 192d7b241e6Sjeremylt is selected to drive the requested resource. 193d7b241e6Sjeremylt @param priority Integer priority. Lower values are preferred in case the 194d7b241e6Sjeremylt resource requested by CeedInit() has non-unique best prefix 195d7b241e6Sjeremylt match. 196b11c1e72Sjeremylt 197b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 198dfdf5a53Sjeremylt 199dfdf5a53Sjeremylt @ref Advanced 200b11c1e72Sjeremylt **/ 201692c2638Sjeremylt int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 202692c2638Sjeremylt unsigned int priority) { 203c042f62fSJeremy L Thompson if (num_backends >= sizeof(backends) / sizeof(backends[0])) 204c042f62fSJeremy L Thompson // LCOV_EXCL_START 205d7b241e6Sjeremylt return CeedError(NULL, 1, "Too many backends"); 206c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 207c042f62fSJeremy L Thompson 208d7b241e6Sjeremylt strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 209288c0443SJeremy L Thompson backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 210d7b241e6Sjeremylt backends[num_backends].init = init; 211d7b241e6Sjeremylt backends[num_backends].priority = priority; 212d7b241e6Sjeremylt num_backends++; 213d7b241e6Sjeremylt return 0; 214d7b241e6Sjeremylt } 215d7b241e6Sjeremylt 216b11c1e72Sjeremylt /** 217b11c1e72Sjeremylt @brief Allocate an array on the host; use CeedMalloc() 218b11c1e72Sjeremylt 219b11c1e72Sjeremylt Memory usage can be tracked by the library. This ensures sufficient 220b11c1e72Sjeremylt alignment for vectorization and should be used for large allocations. 221b11c1e72Sjeremylt 222b11c1e72Sjeremylt @param n Number of units to allocate 223b11c1e72Sjeremylt @param unit Size of each unit 224b11c1e72Sjeremylt @param p Address of pointer to hold the result. 225b11c1e72Sjeremylt 226b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 227b11c1e72Sjeremylt 228b11c1e72Sjeremylt @sa CeedFree() 229dfdf5a53Sjeremylt 230dfdf5a53Sjeremylt @ref Advanced 231b11c1e72Sjeremylt **/ 232d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) { 233d7b241e6Sjeremylt int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 234d7b241e6Sjeremylt if (ierr) 235c042f62fSJeremy L Thompson // LCOV_EXCL_START 2361d102b48SJeremy L Thompson return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 2371d102b48SJeremy L Thompson "members of size %zd\n", n, unit); 238c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 239c042f62fSJeremy L Thompson 240d7b241e6Sjeremylt return 0; 241d7b241e6Sjeremylt } 242d7b241e6Sjeremylt 243b11c1e72Sjeremylt /** 244b11c1e72Sjeremylt @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 245b11c1e72Sjeremylt 246b11c1e72Sjeremylt Memory usage can be tracked by the library. 247b11c1e72Sjeremylt 248b11c1e72Sjeremylt @param n Number of units to allocate 249b11c1e72Sjeremylt @param unit Size of each unit 250b11c1e72Sjeremylt @param p Address of pointer to hold the result. 251b11c1e72Sjeremylt 252b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 253b11c1e72Sjeremylt 254b11c1e72Sjeremylt @sa CeedFree() 255dfdf5a53Sjeremylt 256dfdf5a53Sjeremylt @ref Advanced 257b11c1e72Sjeremylt **/ 258d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) { 259d7b241e6Sjeremylt *(void **)p = calloc(n, unit); 260d7b241e6Sjeremylt if (n && unit && !*(void **)p) 261c042f62fSJeremy L Thompson // LCOV_EXCL_START 2621d102b48SJeremy L Thompson return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 2631d102b48SJeremy L Thompson "%zd\n", n, unit); 264c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 265c042f62fSJeremy L Thompson 266d7b241e6Sjeremylt return 0; 267d7b241e6Sjeremylt } 268d7b241e6Sjeremylt 269b11c1e72Sjeremylt /** 270b11c1e72Sjeremylt @brief Reallocate an array on the host; use CeedRealloc() 271b11c1e72Sjeremylt 272b11c1e72Sjeremylt Memory usage can be tracked by the library. 273b11c1e72Sjeremylt 274b11c1e72Sjeremylt @param n Number of units to allocate 275b11c1e72Sjeremylt @param unit Size of each unit 276b11c1e72Sjeremylt @param p Address of pointer to hold the result. 277b11c1e72Sjeremylt 278b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 279b11c1e72Sjeremylt 280b11c1e72Sjeremylt @sa CeedFree() 281dfdf5a53Sjeremylt 282dfdf5a53Sjeremylt @ref Advanced 283b11c1e72Sjeremylt **/ 284d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) { 285d7b241e6Sjeremylt *(void **)p = realloc(*(void **)p, n*unit); 286d7b241e6Sjeremylt if (n && unit && !*(void **)p) 287c042f62fSJeremy L Thompson // LCOV_EXCL_START 2881d102b48SJeremy L Thompson return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 2891d102b48SJeremy L Thompson "%zd\n", n, unit); 290c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 291c042f62fSJeremy L Thompson 292d7b241e6Sjeremylt return 0; 293d7b241e6Sjeremylt } 294d7b241e6Sjeremylt 29534138859Sjeremylt /** Free memory allocated using CeedMalloc() or CeedCalloc() 29634138859Sjeremylt 29734138859Sjeremylt @param p address of pointer to memory. This argument is of type void* to 29834138859Sjeremylt avoid needing a cast, but is the address of the pointer (which is 29934138859Sjeremylt zeroed) rather than the pointer. 30034138859Sjeremylt **/ 301d7b241e6Sjeremylt int CeedFree(void *p) { 302d7b241e6Sjeremylt free(*(void **)p); 303d7b241e6Sjeremylt *(void **)p = NULL; 304d7b241e6Sjeremylt return 0; 305d7b241e6Sjeremylt } 306d7b241e6Sjeremylt 307d7b241e6Sjeremylt /** 308b11c1e72Sjeremylt @brief Wait for a CeedRequest to complete. 309d7b241e6Sjeremylt 310d7b241e6Sjeremylt Calling CeedRequestWait on a NULL request is a no-op. 311d7b241e6Sjeremylt 312d7b241e6Sjeremylt @param req Address of CeedRequest to wait for; zeroed on completion. 313b11c1e72Sjeremylt 314b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 315dfdf5a53Sjeremylt 316dfdf5a53Sjeremylt @ref Advanced 317b11c1e72Sjeremylt **/ 318d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) { 3191d102b48SJeremy L Thompson if (!*req) 3201d102b48SJeremy L Thompson return 0; 321d7b241e6Sjeremylt return CeedError(NULL, 2, "CeedRequestWait not implemented"); 322d7b241e6Sjeremylt } 323d7b241e6Sjeremylt 324b11c1e72Sjeremylt /** 325d79b80ecSjeremylt @brief Initialize a \ref Ceed context to use the specified resource. 326b11c1e72Sjeremylt 327b11c1e72Sjeremylt @param resource Resource to use, e.g., "/cpu/self" 328b11c1e72Sjeremylt @param ceed The library context 329b11c1e72Sjeremylt @sa CeedRegister() CeedDestroy() 330b11c1e72Sjeremylt 331b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 332dfdf5a53Sjeremylt 333dfdf5a53Sjeremylt @ref Basic 334b11c1e72Sjeremylt **/ 335d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) { 336d7b241e6Sjeremylt int ierr; 337aedaa0e5Sjeremylt size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 338d7b241e6Sjeremylt 339fe2413ffSjeremylt // Find matching backend 3401d102b48SJeremy L Thompson if (!resource) 34113873f79Sjeremylt // LCOV_EXCL_START 3421d102b48SJeremy L Thompson return CeedError(NULL, 1, "No resource provided"); 34313873f79Sjeremylt // LCOV_EXCL_STOP 34413873f79Sjeremylt 345d7b241e6Sjeremylt for (size_t i=0; i<num_backends; i++) { 346d7b241e6Sjeremylt size_t n; 347d7b241e6Sjeremylt const char *prefix = backends[i].prefix; 348d7b241e6Sjeremylt for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 349d7b241e6Sjeremylt priority = backends[i].priority; 350d7b241e6Sjeremylt if (n > matchlen || (n == matchlen && matchpriority > priority)) { 351d7b241e6Sjeremylt matchlen = n; 352d7b241e6Sjeremylt matchpriority = priority; 353d7b241e6Sjeremylt matchidx = i; 354d7b241e6Sjeremylt } 355d7b241e6Sjeremylt } 3561d102b48SJeremy L Thompson if (!matchlen) 35713873f79Sjeremylt // LCOV_EXCL_START 3581d102b48SJeremy L Thompson return CeedError(NULL, 1, "No suitable backend"); 35913873f79Sjeremylt // LCOV_EXCL_STOP 360fe2413ffSjeremylt 361fe2413ffSjeremylt // Setup Ceed 362d7b241e6Sjeremylt ierr = CeedCalloc(1, ceed); CeedChk(ierr); 363bc81ce41Sjeremylt const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 3641d102b48SJeremy L Thompson if (!ceed_error_handler) 3651d102b48SJeremy L Thompson ceed_error_handler = "abort"; 366bc81ce41Sjeremylt if (!strcmp(ceed_error_handler, "exit")) 36756e866f4SJed Brown (*ceed)->Error = CeedErrorExit; 36856e866f4SJed Brown else 369d7b241e6Sjeremylt (*ceed)->Error = CeedErrorAbort; 370d7b241e6Sjeremylt (*ceed)->refcount = 1; 371d7b241e6Sjeremylt (*ceed)->data = NULL; 372fe2413ffSjeremylt 373fe2413ffSjeremylt // Set lookup table 3746e79d475Sjeremylt foffset foffsets[] = { 3756e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Error), 3766e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 3776e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Destroy), 378f8902d9eSjeremylt CEED_FTABLE_ENTRY(Ceed, VectorCreate), 3796e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 3806e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 3816e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 3826e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 3836e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 3846e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 3856e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 3866e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 3876e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetArray), 3886e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetValue), 3896e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArray), 3906e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 3916e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 3926e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 393*547d9b97Sjeremylt CEED_FTABLE_ENTRY(CeedVector, Norm), 3946e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, Destroy), 3956e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 3966e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 3976e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 3986e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Apply), 3996e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Destroy), 4006e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 4016e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 4026e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Apply), 4036e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 4041d102b48SJeremy L Thompson CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction), 405b7ec98d8SJeremy L Thompson CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal), 406713f43c3Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 4076e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Apply), 408250756a7Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 409cae8b89aSjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 410250756a7Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 4116e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 4126e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Destroy), 4136e79d475Sjeremylt {NULL, 0} // End of lookup table - used in SetBackendFunction loop 4141dfeef1dSjeremylt }; 415fe2413ffSjeremylt 4166e79d475Sjeremylt ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 4176e79d475Sjeremylt memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 418fe2413ffSjeremylt 4195107b09fSJeremy L Thompson // Set fallback for advanced CeedOperator functions 4205107b09fSJeremy L Thompson const char fallbackresource[] = "/cpu/self/ref/serial"; 4215107b09fSJeremy L Thompson ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 4225107b09fSJeremy L Thompson CeedChk(ierr); 4235107b09fSJeremy L Thompson 424fe2413ffSjeremylt // Backend specific setup 425d7b241e6Sjeremylt ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 426fe2413ffSjeremylt 427e07206deSjeremylt // Copy resource prefix, if backend setup sucessful 428e07206deSjeremylt size_t len = strlen(backends[matchidx].prefix); 429e07206deSjeremylt char *tmp; 430e07206deSjeremylt ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 431e07206deSjeremylt memcpy(tmp, backends[matchidx].prefix, len+1); 432e07206deSjeremylt (*ceed)->resource = tmp; 433e07206deSjeremylt 434d7b241e6Sjeremylt return 0; 435d7b241e6Sjeremylt } 436d7b241e6Sjeremylt 437d7b241e6Sjeremylt /** 438d79b80ecSjeremylt @brief Retrieve a parent Ceed context 4392f86a920SJeremy L Thompson 440d79b80ecSjeremylt @param ceed Ceed context to retrieve parent of 4412f86a920SJeremy L Thompson @param[out] parent Address to save the parent to 4422f86a920SJeremy L Thompson 4432f86a920SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 4442f86a920SJeremy L Thompson 4452f86a920SJeremy L Thompson @ref Developer 4462f86a920SJeremy L Thompson **/ 4472f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) { 4482f86a920SJeremy L Thompson int ierr; 4492f86a920SJeremy L Thompson if (ceed->parent) { 4502f86a920SJeremy L Thompson ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 4512f86a920SJeremy L Thompson return 0; 4522f86a920SJeremy L Thompson } 4532f86a920SJeremy L Thompson *parent = ceed; 4542f86a920SJeremy L Thompson return 0; 4552f86a920SJeremy L Thompson } 4562f86a920SJeremy L Thompson 4572f86a920SJeremy L Thompson /** 458d79b80ecSjeremylt @brief Retrieve a delegate Ceed context 4595fe0d4faSjeremylt 460d79b80ecSjeremylt @param ceed Ceed context to retrieve delegate of 4615fe0d4faSjeremylt @param[out] delegate Address to save the delegate to 4625fe0d4faSjeremylt 4635fe0d4faSjeremylt @return An error code: 0 - success, otherwise - failure 4645fe0d4faSjeremylt 46523617272Sjeremylt @ref Developer 4665fe0d4faSjeremylt **/ 4675fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 4684ce2993fSjeremylt *delegate = ceed->delegate; 4694ce2993fSjeremylt return 0; 4704ce2993fSjeremylt } 4714ce2993fSjeremylt 4724ce2993fSjeremylt /** 473d79b80ecSjeremylt @brief Set a delegate Ceed context 4744ce2993fSjeremylt 475d79b80ecSjeremylt This function allows a Ceed context to set a delegate Ceed context. All 476d79b80ecSjeremylt backend implementations default to the delegate Ceed context, unless 477d79b80ecSjeremylt overridden. 478f29ffe77Sjeremylt 479d79b80ecSjeremylt @param ceed Ceed context to set delegate of 4804ce2993fSjeremylt @param[out] delegate Address to set the delegate to 4814ce2993fSjeremylt 4824ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 4834ce2993fSjeremylt 48423617272Sjeremylt @ref Advanced 4854ce2993fSjeremylt **/ 486a4999eddSjeremylt int CeedSetDelegate(Ceed ceed, Ceed delegate) { 487a4999eddSjeremylt ceed->delegate = delegate; 488a4999eddSjeremylt delegate->parent = ceed; 4894ce2993fSjeremylt return 0; 4904ce2993fSjeremylt } 4914ce2993fSjeremylt 4924ce2993fSjeremylt /** 493d79b80ecSjeremylt @brief Retrieve a delegate Ceed context for a specific object type 494aefd8378Sjeremylt 495d79b80ecSjeremylt @param ceed Ceed context to retrieve delegate of 496aefd8378Sjeremylt @param[out] delegate Address to save the delegate to 497288c0443SJeremy L Thompson @param[in] objname Name of the object type to retrieve delegate for 498aefd8378Sjeremylt 499aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 500aefd8378Sjeremylt 501aefd8378Sjeremylt @ref Developer 502aefd8378Sjeremylt **/ 503aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 504aefd8378Sjeremylt CeedInt ierr; 505aefd8378Sjeremylt 506aefd8378Sjeremylt // Check for object delegate 5071d102b48SJeremy L Thompson for (CeedInt i=0; i<ceed->objdelegatecount; i++) 508aefd8378Sjeremylt if (!strcmp(objname, ceed->objdelegates->objname)) { 509aefd8378Sjeremylt *delegate = ceed->objdelegates->delegate; 510aefd8378Sjeremylt return 0; 511aefd8378Sjeremylt } 512aefd8378Sjeremylt 513aefd8378Sjeremylt // Use default delegate if no object delegate 514aefd8378Sjeremylt ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 515aefd8378Sjeremylt 516aefd8378Sjeremylt return 0; 517aefd8378Sjeremylt } 518aefd8378Sjeremylt 519aefd8378Sjeremylt /** 520d79b80ecSjeremylt @brief Set a delegate Ceed context for a specific object type 521aefd8378Sjeremylt 522d79b80ecSjeremylt This function allows a Ceed context to set a delegate Ceed context for a 523d79b80ecSjeremylt given type of Ceed object. All backend implementations default to the 524d79b80ecSjeremylt delegate Ceed context for this object. For example, 525f29ffe77Sjeremylt CeedSetObjectDelegate(ceed, refceed, "Basis") 526f29ffe77Sjeremylt uses refceed implementations for all CeedBasis backend functions. 527f29ffe77Sjeremylt 528d79b80ecSjeremylt @param ceed Ceed context to set delegate of 529aefd8378Sjeremylt @param[out] delegate Address to set the delegate to 530288c0443SJeremy L Thompson @param[in] objname Name of the object type to set delegate for 531aefd8378Sjeremylt 532aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 533aefd8378Sjeremylt 534aefd8378Sjeremylt @ref Advanced 535aefd8378Sjeremylt **/ 536a4999eddSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 537aefd8378Sjeremylt CeedInt ierr; 538aefd8378Sjeremylt CeedInt count = ceed->objdelegatecount; 539aefd8378Sjeremylt 540aefd8378Sjeremylt // Malloc or Realloc 541aefd8378Sjeremylt if (count) { 5421d102b48SJeremy L Thompson ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 543aefd8378Sjeremylt } else { 544aefd8378Sjeremylt ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 545aefd8378Sjeremylt } 546aefd8378Sjeremylt ceed->objdelegatecount++; 547aefd8378Sjeremylt 548aefd8378Sjeremylt // Set object delegate 549a4999eddSjeremylt ceed->objdelegates[count].delegate = delegate; 55007a02837SJed Brown size_t slen = strlen(objname) + 1; 55107a02837SJed Brown ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 55207a02837SJed Brown memcpy(ceed->objdelegates[count].objname, objname, slen); 553aefd8378Sjeremylt 554aefd8378Sjeremylt // Set delegate parent 555a4999eddSjeremylt delegate->parent = ceed; 556aefd8378Sjeremylt 557aefd8378Sjeremylt return 0; 558aefd8378Sjeremylt } 559aefd8378Sjeremylt 560aefd8378Sjeremylt /** 5615107b09fSJeremy L Thompson @brief Set the fallback resource for CeedOperators. The current resource, if 5625107b09fSJeremy L Thompson any, is freed by calling this function. This string is freed upon the 563d79b80ecSjeremylt destruction of the Ceed context. 5645107b09fSJeremy L Thompson 5655107b09fSJeremy L Thompson @param[out] ceed Ceed context 5665107b09fSJeremy L Thompson @param resource Fallback resource to set 5675107b09fSJeremy L Thompson 5685107b09fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 5695107b09fSJeremy L Thompson 5705107b09fSJeremy L Thompson @ref Advanced 5715107b09fSJeremy L Thompson **/ 5725107b09fSJeremy L Thompson 5735107b09fSJeremy L Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 5745107b09fSJeremy L Thompson int ierr; 5755107b09fSJeremy L Thompson 5765107b09fSJeremy L Thompson // Free old 5775107b09fSJeremy L Thompson ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 5785107b09fSJeremy L Thompson 5795107b09fSJeremy L Thompson // Set new 5805107b09fSJeremy L Thompson size_t len = strlen(resource); 5815107b09fSJeremy L Thompson char *tmp; 5825107b09fSJeremy L Thompson ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 5835107b09fSJeremy L Thompson memcpy(tmp, resource, len+1); 5845107b09fSJeremy L Thompson ceed->opfallbackresource = tmp; 5855107b09fSJeremy L Thompson 5865107b09fSJeremy L Thompson return 0; 5875107b09fSJeremy L Thompson } 5885107b09fSJeremy L Thompson 5895107b09fSJeremy L Thompson /** 5905107b09fSJeremy L Thompson @brief Get the fallback resource for CeedOperators 5915107b09fSJeremy L Thompson 5925107b09fSJeremy L Thompson @param ceed Ceed context 5935107b09fSJeremy L Thompson @param[out] resource Variable to store fallback resource 5945107b09fSJeremy L Thompson 5955107b09fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 5965107b09fSJeremy L Thompson 5975107b09fSJeremy L Thompson @ref Advanced 5985107b09fSJeremy L Thompson **/ 5995107b09fSJeremy L Thompson 6005107b09fSJeremy L Thompson int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 6015107b09fSJeremy L Thompson *resource = (const char *)ceed->opfallbackresource; 6025107b09fSJeremy L Thompson return 0; 6035107b09fSJeremy L Thompson } 6045107b09fSJeremy L Thompson 6055107b09fSJeremy L Thompson /** 606d79b80ecSjeremylt @brief Get the parent Ceed context associated with a fallback Ceed context 607d79b80ecSjeremylt for a CeedOperator 6085107b09fSJeremy L Thompson 6095107b09fSJeremy L Thompson @param ceed Ceed context 61077645d7bSjeremylt @param[out] parent Variable to store parent Ceed context 6115107b09fSJeremy L Thompson 6125107b09fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 6135107b09fSJeremy L Thompson 6145107b09fSJeremy L Thompson @ref Advanced 6155107b09fSJeremy L Thompson **/ 6165107b09fSJeremy L Thompson 6175107b09fSJeremy L Thompson int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 6185107b09fSJeremy L Thompson *parent = ceed->opfallbackparent; 6195107b09fSJeremy L Thompson return 0; 6205107b09fSJeremy L Thompson } 6215107b09fSJeremy L Thompson 6225107b09fSJeremy L Thompson /** 623d79b80ecSjeremylt @brief Return Ceed context preferred memory type 624c907536fSjeremylt 625d79b80ecSjeremylt @param ceed Ceed context to get preferred memory type of 626288c0443SJeremy L Thompson @param[out] type Address to save preferred memory type to 627c907536fSjeremylt 628c907536fSjeremylt @return An error code: 0 - success, otherwise - failure 629c907536fSjeremylt 630c907536fSjeremylt @ref Basic 631c907536fSjeremylt **/ 632c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 633c907536fSjeremylt int ierr; 634c263cd57Sjeremylt 635c907536fSjeremylt if (ceed->GetPreferredMemType) { 636c907536fSjeremylt ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 637c907536fSjeremylt } else { 638c263cd57Sjeremylt Ceed delegate; 639c263cd57Sjeremylt ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 640c263cd57Sjeremylt 641c263cd57Sjeremylt if (delegate) { 642c263cd57Sjeremylt ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 643c263cd57Sjeremylt } else { 644c907536fSjeremylt *type = CEED_MEM_HOST; 645c907536fSjeremylt } 646c263cd57Sjeremylt } 647c907536fSjeremylt 648c907536fSjeremylt return 0; 649c907536fSjeremylt } 650c907536fSjeremylt 651c907536fSjeremylt /** 652fe2413ffSjeremylt @brief Set a backend function 653fe2413ffSjeremylt 654cb37edd8Sjeremylt This function is used for a backend to set the function associated with 655d79b80ecSjeremylt the Ceed objects. For example, 656f8902d9eSjeremylt CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 657cb37edd8Sjeremylt sets the backend implementation of 'CeedVectorCreate' and 658cb37edd8Sjeremylt CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 659cb37edd8Sjeremylt sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 660cb37edd8Sjeremylt is not required for the object type ("Basis" vs "CeedBasis"). 661cb37edd8Sjeremylt 662d79b80ecSjeremylt @param ceed Ceed context for error handling 663fe2413ffSjeremylt @param type Type of Ceed object to set function for 664fe2413ffSjeremylt @param[out] object Ceed object to set function for 665fe2413ffSjeremylt @param fname Name of function to set 666fe2413ffSjeremylt @param f Function to set 667fe2413ffSjeremylt 668fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 669fe2413ffSjeremylt 670fe2413ffSjeremylt @ref Advanced 671fe2413ffSjeremylt **/ 672692c2638Sjeremylt int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 673fe2413ffSjeremylt const char *fname, int (*f)()) { 674409ab9adSjeremylt char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 675fe2413ffSjeremylt 676fe2413ffSjeremylt // Build lookup name 6776e79d475Sjeremylt if (strcmp(type, "Ceed")) 6786e79d475Sjeremylt strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 679409ab9adSjeremylt strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 680409ab9adSjeremylt strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 681fe2413ffSjeremylt 682fe2413ffSjeremylt // Find and use offset 6831d102b48SJeremy L Thompson for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 684fe2413ffSjeremylt if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 685fe2413ffSjeremylt size_t offset = ceed->foffsets[i].offset; 686cb0b5415Sjeremylt int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 687a7a2e802Sjeremylt *fpointer = f; 688fe2413ffSjeremylt return 0; 689fe2413ffSjeremylt } 690fe2413ffSjeremylt 691c042f62fSJeremy L Thompson // LCOV_EXCL_START 6921d102b48SJeremy L Thompson return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 6931d102b48SJeremy L Thompson "object '%s'", fname, type); 694c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 695fe2413ffSjeremylt } 696fe2413ffSjeremylt 697fe2413ffSjeremylt /** 698d79b80ecSjeremylt @brief Retrieve backend data for a Ceed context 6994ce2993fSjeremylt 700d79b80ecSjeremylt @param ceed Ceed context to retrieve data of 7014ce2993fSjeremylt @param[out] data Address to save data to 7024ce2993fSjeremylt 7034ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 7044ce2993fSjeremylt 70523617272Sjeremylt @ref Advanced 7064ce2993fSjeremylt **/ 7074ce2993fSjeremylt int CeedGetData(Ceed ceed, void **data) { 7084ce2993fSjeremylt *data = ceed->data; 7095fe0d4faSjeremylt return 0; 7105fe0d4faSjeremylt } 7115fe0d4faSjeremylt 7125fe0d4faSjeremylt /** 713d79b80ecSjeremylt @brief Set backend data for a Ceed context 714fe2413ffSjeremylt 715d79b80ecSjeremylt @param ceed Ceed context to set data of 716fe2413ffSjeremylt @param data Address of data to set 717fe2413ffSjeremylt 718fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 719fe2413ffSjeremylt 720fe2413ffSjeremylt @ref Advanced 721fe2413ffSjeremylt **/ 722fe2413ffSjeremylt int CeedSetData(Ceed ceed, void **data) { 723fe2413ffSjeremylt ceed->data = *data; 724fe2413ffSjeremylt return 0; 725fe2413ffSjeremylt } 726fe2413ffSjeremylt 727fe2413ffSjeremylt /** 728d79b80ecSjeremylt @brief Get the full resource name for a Ceed context 729e07206deSjeremylt 730d79b80ecSjeremylt @param ceed Ceed context to get resource name of 731e07206deSjeremylt @param[out] resource Variable to store resource name 732e07206deSjeremylt 733e07206deSjeremylt @return An error code: 0 - success, otherwise - failure 734e07206deSjeremylt 735e07206deSjeremylt @ref Basic 736e07206deSjeremylt **/ 737e07206deSjeremylt 738e07206deSjeremylt int CeedGetResource(Ceed ceed, const char **resource) { 739e07206deSjeremylt *resource = (const char *)ceed->resource; 740e07206deSjeremylt return 0; 741e07206deSjeremylt } 742e07206deSjeremylt 743e07206deSjeremylt /** 744b11c1e72Sjeremylt @brief Destroy a Ceed context 745d7b241e6Sjeremylt 746d7b241e6Sjeremylt @param ceed Address of Ceed context to destroy 747b11c1e72Sjeremylt 748b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 749dfdf5a53Sjeremylt 750dfdf5a53Sjeremylt @ref Basic 751b11c1e72Sjeremylt **/ 752d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) { 753d7b241e6Sjeremylt int ierr; 7541d102b48SJeremy L Thompson if (!*ceed || --(*ceed)->refcount > 0) 7551d102b48SJeremy L Thompson return 0; 7560ace9bf2Sjeremylt 7575fe0d4faSjeremylt if ((*ceed)->delegate) { 7585fe0d4faSjeremylt ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 7595fe0d4faSjeremylt } 7600ace9bf2Sjeremylt 761aefd8378Sjeremylt if ((*ceed)->objdelegatecount > 0) { 762aefd8378Sjeremylt for (int i=0; i<(*ceed)->objdelegatecount; i++) { 763aefd8378Sjeremylt ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 764aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 765aefd8378Sjeremylt } 766aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 767aefd8378Sjeremylt } 7680ace9bf2Sjeremylt 769d7b241e6Sjeremylt if ((*ceed)->Destroy) { 770d7b241e6Sjeremylt ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 771d7b241e6Sjeremylt } 7720ace9bf2Sjeremylt 7736e79d475Sjeremylt ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 774e07206deSjeremylt ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 7755107b09fSJeremy L Thompson ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 7765107b09fSJeremy L Thompson ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 777d7b241e6Sjeremylt ierr = CeedFree(ceed); CeedChk(ierr); 778d7b241e6Sjeremylt return 0; 779d7b241e6Sjeremylt } 780d7b241e6Sjeremylt 781d7b241e6Sjeremylt /// @} 782