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 **/ 124d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 125d7b241e6Sjeremylt const char *func, int ecode, const char *format, 126d7b241e6Sjeremylt va_list args) { 127d7b241e6Sjeremylt return ecode; 128d7b241e6Sjeremylt } 129d7b241e6Sjeremylt 130b11c1e72Sjeremylt /** 131b11c1e72Sjeremylt @brief Error handler that prints to stderr and aborts 132b11c1e72Sjeremylt 133b11c1e72Sjeremylt Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 134dfdf5a53Sjeremylt 135dfdf5a53Sjeremylt @ref Developer 136b11c1e72Sjeremylt **/ 137d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 1381d102b48SJeremy L Thompson const char *func, int ecode, const char *format, 1391d102b48SJeremy L Thompson va_list args) { 140d7b241e6Sjeremylt fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 141d7b241e6Sjeremylt vfprintf(stderr, format, args); 142d7b241e6Sjeremylt fprintf(stderr, "\n"); 143d7b241e6Sjeremylt abort(); 144d7b241e6Sjeremylt return ecode; 145d7b241e6Sjeremylt } 146d7b241e6Sjeremylt 147b11c1e72Sjeremylt /** 14856e866f4SJed Brown @brief Error handler that prints to stderr and exits 14956e866f4SJed Brown 15056e866f4SJed Brown Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 15156e866f4SJed Brown 15256e866f4SJed Brown In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 15356e866f4SJed Brown handlers (e.g., as used by gcov) are run. 15456e866f4SJed Brown 15556e866f4SJed Brown @ref Developer 15656e866f4SJed Brown **/ 157692c2638Sjeremylt int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 158692c2638Sjeremylt int ecode, const char *format, va_list args) { 15956e866f4SJed Brown fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 16056e866f4SJed Brown vfprintf(stderr, format, args); 16156e866f4SJed Brown fprintf(stderr, "\n"); 16256e866f4SJed Brown exit(ecode); 16356e866f4SJed Brown return ecode; 16456e866f4SJed Brown } 16556e866f4SJed Brown 16656e866f4SJed Brown /** 167dfdf5a53Sjeremylt @brief Set error handler 168b11c1e72Sjeremylt 169b11c1e72Sjeremylt A default error handler is set in CeedInit(). Use this function to change 170b11c1e72Sjeremylt the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 171b11c1e72Sjeremylt error handler. 172dfdf5a53Sjeremylt 173dfdf5a53Sjeremylt @ref Developer 174b11c1e72Sjeremylt **/ 175d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed, 176d7b241e6Sjeremylt int (eh)(Ceed, const char *, int, const char *, 177d7b241e6Sjeremylt int, const char *, va_list)) { 178d7b241e6Sjeremylt ceed->Error = eh; 179d7b241e6Sjeremylt return 0; 180d7b241e6Sjeremylt } 181d7b241e6Sjeremylt 182d7b241e6Sjeremylt /** 183b11c1e72Sjeremylt @brief Register a Ceed backend 184d7b241e6Sjeremylt 185d7b241e6Sjeremylt @param prefix Prefix of resources for this backend to respond to. For 186d7b241e6Sjeremylt example, the reference backend responds to "/cpu/self". 187d7b241e6Sjeremylt @param init Initialization function called by CeedInit() when the backend 188d7b241e6Sjeremylt is selected to drive the requested resource. 189d7b241e6Sjeremylt @param priority Integer priority. Lower values are preferred in case the 190d7b241e6Sjeremylt resource requested by CeedInit() has non-unique best prefix 191d7b241e6Sjeremylt match. 192b11c1e72Sjeremylt 193b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 194dfdf5a53Sjeremylt 195dfdf5a53Sjeremylt @ref Advanced 196b11c1e72Sjeremylt **/ 197692c2638Sjeremylt int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 198692c2638Sjeremylt unsigned int priority) { 199c042f62fSJeremy L Thompson if (num_backends >= sizeof(backends) / sizeof(backends[0])) 200c042f62fSJeremy L Thompson // LCOV_EXCL_START 201d7b241e6Sjeremylt return CeedError(NULL, 1, "Too many backends"); 202c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 203c042f62fSJeremy L Thompson 204d7b241e6Sjeremylt strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 205288c0443SJeremy L Thompson backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 206d7b241e6Sjeremylt backends[num_backends].init = init; 207d7b241e6Sjeremylt backends[num_backends].priority = priority; 208d7b241e6Sjeremylt num_backends++; 209d7b241e6Sjeremylt return 0; 210d7b241e6Sjeremylt } 211d7b241e6Sjeremylt 212b11c1e72Sjeremylt /** 213b11c1e72Sjeremylt @brief Allocate an array on the host; use CeedMalloc() 214b11c1e72Sjeremylt 215b11c1e72Sjeremylt Memory usage can be tracked by the library. This ensures sufficient 216b11c1e72Sjeremylt alignment for vectorization and should be used for large allocations. 217b11c1e72Sjeremylt 218b11c1e72Sjeremylt @param n Number of units to allocate 219b11c1e72Sjeremylt @param unit Size of each unit 220b11c1e72Sjeremylt @param p Address of pointer to hold the result. 221b11c1e72Sjeremylt 222b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 223b11c1e72Sjeremylt 224b11c1e72Sjeremylt @sa CeedFree() 225dfdf5a53Sjeremylt 226dfdf5a53Sjeremylt @ref Advanced 227b11c1e72Sjeremylt **/ 228d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) { 229d7b241e6Sjeremylt int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 230d7b241e6Sjeremylt if (ierr) 231c042f62fSJeremy L Thompson // LCOV_EXCL_START 2321d102b48SJeremy L Thompson return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 2331d102b48SJeremy L Thompson "members of size %zd\n", n, unit); 234c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 235c042f62fSJeremy L Thompson 236d7b241e6Sjeremylt return 0; 237d7b241e6Sjeremylt } 238d7b241e6Sjeremylt 239b11c1e72Sjeremylt /** 240b11c1e72Sjeremylt @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 241b11c1e72Sjeremylt 242b11c1e72Sjeremylt Memory usage can be tracked by the library. 243b11c1e72Sjeremylt 244b11c1e72Sjeremylt @param n Number of units to allocate 245b11c1e72Sjeremylt @param unit Size of each unit 246b11c1e72Sjeremylt @param p Address of pointer to hold the result. 247b11c1e72Sjeremylt 248b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 249b11c1e72Sjeremylt 250b11c1e72Sjeremylt @sa CeedFree() 251dfdf5a53Sjeremylt 252dfdf5a53Sjeremylt @ref Advanced 253b11c1e72Sjeremylt **/ 254d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) { 255d7b241e6Sjeremylt *(void **)p = calloc(n, unit); 256d7b241e6Sjeremylt if (n && unit && !*(void **)p) 257c042f62fSJeremy L Thompson // LCOV_EXCL_START 2581d102b48SJeremy L Thompson return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 2591d102b48SJeremy L Thompson "%zd\n", n, unit); 260c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 261c042f62fSJeremy L Thompson 262d7b241e6Sjeremylt return 0; 263d7b241e6Sjeremylt } 264d7b241e6Sjeremylt 265b11c1e72Sjeremylt /** 266b11c1e72Sjeremylt @brief Reallocate an array on the host; use CeedRealloc() 267b11c1e72Sjeremylt 268b11c1e72Sjeremylt Memory usage can be tracked by the library. 269b11c1e72Sjeremylt 270b11c1e72Sjeremylt @param n Number of units to allocate 271b11c1e72Sjeremylt @param unit Size of each unit 272b11c1e72Sjeremylt @param p Address of pointer to hold the result. 273b11c1e72Sjeremylt 274b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 275b11c1e72Sjeremylt 276b11c1e72Sjeremylt @sa CeedFree() 277dfdf5a53Sjeremylt 278dfdf5a53Sjeremylt @ref Advanced 279b11c1e72Sjeremylt **/ 280d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) { 281d7b241e6Sjeremylt *(void **)p = realloc(*(void **)p, n*unit); 282d7b241e6Sjeremylt if (n && unit && !*(void **)p) 283c042f62fSJeremy L Thompson // LCOV_EXCL_START 2841d102b48SJeremy L Thompson return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 2851d102b48SJeremy L Thompson "%zd\n", n, unit); 286c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 287c042f62fSJeremy L Thompson 288d7b241e6Sjeremylt return 0; 289d7b241e6Sjeremylt } 290d7b241e6Sjeremylt 291d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc() 292d7b241e6Sjeremylt /// 293d7b241e6Sjeremylt /// @param p address of pointer to memory. This argument is of type void* to 294d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed) 295d7b241e6Sjeremylt /// rather than the pointer. 296d7b241e6Sjeremylt int CeedFree(void *p) { 297d7b241e6Sjeremylt free(*(void **)p); 298d7b241e6Sjeremylt *(void **)p = NULL; 299d7b241e6Sjeremylt return 0; 300d7b241e6Sjeremylt } 301d7b241e6Sjeremylt 302d7b241e6Sjeremylt /** 303b11c1e72Sjeremylt @brief Wait for a CeedRequest to complete. 304d7b241e6Sjeremylt 305d7b241e6Sjeremylt Calling CeedRequestWait on a NULL request is a no-op. 306d7b241e6Sjeremylt 307d7b241e6Sjeremylt @param req Address of CeedRequest to wait for; zeroed on completion. 308b11c1e72Sjeremylt 309b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 310dfdf5a53Sjeremylt 311dfdf5a53Sjeremylt @ref Advanced 312b11c1e72Sjeremylt **/ 313d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) { 3141d102b48SJeremy L Thompson if (!*req) 3151d102b48SJeremy L Thompson return 0; 316d7b241e6Sjeremylt return CeedError(NULL, 2, "CeedRequestWait not implemented"); 317d7b241e6Sjeremylt } 318d7b241e6Sjeremylt 319b11c1e72Sjeremylt /** 320b11c1e72Sjeremylt @brief Initialize a \ref Ceed to use the specified resource. 321b11c1e72Sjeremylt 322b11c1e72Sjeremylt @param resource Resource to use, e.g., "/cpu/self" 323b11c1e72Sjeremylt @param ceed The library context 324b11c1e72Sjeremylt @sa CeedRegister() CeedDestroy() 325b11c1e72Sjeremylt 326b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 327dfdf5a53Sjeremylt 328dfdf5a53Sjeremylt @ref Basic 329b11c1e72Sjeremylt **/ 330d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) { 331d7b241e6Sjeremylt int ierr; 332aedaa0e5Sjeremylt size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 333d7b241e6Sjeremylt 334fe2413ffSjeremylt // Find matching backend 3351d102b48SJeremy L Thompson if (!resource) 3361d102b48SJeremy L Thompson return CeedError(NULL, 1, "No resource provided"); 337d7b241e6Sjeremylt for (size_t i=0; i<num_backends; i++) { 338d7b241e6Sjeremylt size_t n; 339d7b241e6Sjeremylt const char *prefix = backends[i].prefix; 340d7b241e6Sjeremylt for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 341d7b241e6Sjeremylt priority = backends[i].priority; 342d7b241e6Sjeremylt if (n > matchlen || (n == matchlen && matchpriority > priority)) { 343d7b241e6Sjeremylt matchlen = n; 344d7b241e6Sjeremylt matchpriority = priority; 345d7b241e6Sjeremylt matchidx = i; 346d7b241e6Sjeremylt } 347d7b241e6Sjeremylt } 3481d102b48SJeremy L Thompson if (!matchlen) 3491d102b48SJeremy L Thompson return CeedError(NULL, 1, "No suitable backend"); 350fe2413ffSjeremylt 351fe2413ffSjeremylt // Setup Ceed 352d7b241e6Sjeremylt ierr = CeedCalloc(1,ceed); CeedChk(ierr); 353bc81ce41Sjeremylt const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 3541d102b48SJeremy L Thompson if (!ceed_error_handler) 3551d102b48SJeremy L Thompson ceed_error_handler = "abort"; 356bc81ce41Sjeremylt if (!strcmp(ceed_error_handler, "exit")) 35756e866f4SJed Brown (*ceed)->Error = CeedErrorExit; 35856e866f4SJed Brown else 359d7b241e6Sjeremylt (*ceed)->Error = CeedErrorAbort; 360d7b241e6Sjeremylt (*ceed)->refcount = 1; 361d7b241e6Sjeremylt (*ceed)->data = NULL; 362fe2413ffSjeremylt 363fe2413ffSjeremylt // Set lookup table 3646e79d475Sjeremylt foffset foffsets[] = { 3656e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Error), 3666e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 3676e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Destroy), 368f8902d9eSjeremylt CEED_FTABLE_ENTRY(Ceed, VectorCreate), 3696e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 3706e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 3716e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 3726e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 3736e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 3746e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 3756e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 3766e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 3776e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetArray), 3786e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetValue), 3796e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArray), 3806e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 3816e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 3826e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 3836e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, Destroy), 3846e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 3856e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 3866e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 3876e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Apply), 3886e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Destroy), 3896e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 3906e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 3916e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Apply), 3926e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 3931d102b48SJeremy L Thompson CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction), 394b7ec98d8SJeremy L Thompson CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal), 3956e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Apply), 396*250756a7Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 397cae8b89aSjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 398*250756a7Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 3996e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 4006e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Destroy), 4016e79d475Sjeremylt {NULL, 0} // End of lookup table - used in SetBackendFunction loop 4021dfeef1dSjeremylt }; 403fe2413ffSjeremylt 4046e79d475Sjeremylt ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 4056e79d475Sjeremylt memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 406fe2413ffSjeremylt 4075107b09fSJeremy L Thompson // Set fallback for advanced CeedOperator functions 4085107b09fSJeremy L Thompson const char fallbackresource[] = "/cpu/self/ref/serial"; 4095107b09fSJeremy L Thompson ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 4105107b09fSJeremy L Thompson CeedChk(ierr); 4115107b09fSJeremy L Thompson 412fe2413ffSjeremylt // Backend specific setup 413d7b241e6Sjeremylt ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 414fe2413ffSjeremylt 415e07206deSjeremylt // Copy resource prefix, if backend setup sucessful 416e07206deSjeremylt size_t len = strlen(backends[matchidx].prefix); 417e07206deSjeremylt char *tmp; 418e07206deSjeremylt ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 419e07206deSjeremylt memcpy(tmp, backends[matchidx].prefix, len+1); 420e07206deSjeremylt (*ceed)->resource = tmp; 421e07206deSjeremylt 422d7b241e6Sjeremylt return 0; 423d7b241e6Sjeremylt } 424d7b241e6Sjeremylt 425d7b241e6Sjeremylt /** 4262f86a920SJeremy L Thompson @brief Retrieve a parent CEED 4272f86a920SJeremy L Thompson 4282f86a920SJeremy L Thompson @param ceed Ceed to retrieve parent of 4292f86a920SJeremy L Thompson @param[out] parent Address to save the parent to 4302f86a920SJeremy L Thompson 4312f86a920SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 4322f86a920SJeremy L Thompson 4332f86a920SJeremy L Thompson @ref Developer 4342f86a920SJeremy L Thompson **/ 4352f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) { 4362f86a920SJeremy L Thompson int ierr; 4372f86a920SJeremy L Thompson if (ceed->parent) { 4382f86a920SJeremy L Thompson ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 4392f86a920SJeremy L Thompson return 0; 4402f86a920SJeremy L Thompson } 4412f86a920SJeremy L Thompson *parent = ceed; 4422f86a920SJeremy L Thompson return 0; 4432f86a920SJeremy L Thompson } 4442f86a920SJeremy L Thompson 4452f86a920SJeremy L Thompson /** 4465fe0d4faSjeremylt @brief Retrieve a delegate CEED 4475fe0d4faSjeremylt 4485fe0d4faSjeremylt @param ceed Ceed to retrieve delegate of 4495fe0d4faSjeremylt @param[out] delegate Address to save the delegate to 4505fe0d4faSjeremylt 4515fe0d4faSjeremylt @return An error code: 0 - success, otherwise - failure 4525fe0d4faSjeremylt 45323617272Sjeremylt @ref Developer 4545fe0d4faSjeremylt **/ 4555fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 4564ce2993fSjeremylt *delegate = ceed->delegate; 4574ce2993fSjeremylt return 0; 4584ce2993fSjeremylt } 4594ce2993fSjeremylt 4604ce2993fSjeremylt /** 4614ce2993fSjeremylt @brief Set a delegate CEED 4624ce2993fSjeremylt 463f29ffe77Sjeremylt This function allows a CEED to set a delegate CEED. All backend 464f29ffe77Sjeremylt implementations default to the delegate CEED, unless overridden. 465f29ffe77Sjeremylt 4664ce2993fSjeremylt @param ceed Ceed to set delegate of 4674ce2993fSjeremylt @param[out] delegate Address to set the delegate to 4684ce2993fSjeremylt 4694ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 4704ce2993fSjeremylt 47123617272Sjeremylt @ref Advanced 4724ce2993fSjeremylt **/ 473a4999eddSjeremylt int CeedSetDelegate(Ceed ceed, Ceed delegate) { 474a4999eddSjeremylt ceed->delegate = delegate; 475a4999eddSjeremylt delegate->parent = ceed; 4764ce2993fSjeremylt return 0; 4774ce2993fSjeremylt } 4784ce2993fSjeremylt 4794ce2993fSjeremylt /** 480aefd8378Sjeremylt @brief Retrieve a delegate CEED for a specific object type 481aefd8378Sjeremylt 482aefd8378Sjeremylt @param ceed Ceed to retrieve delegate of 483aefd8378Sjeremylt @param[out] delegate Address to save the delegate to 484288c0443SJeremy L Thompson @param[in] objname Name of the object type to retrieve delegate for 485aefd8378Sjeremylt 486aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 487aefd8378Sjeremylt 488aefd8378Sjeremylt @ref Developer 489aefd8378Sjeremylt **/ 490aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 491aefd8378Sjeremylt CeedInt ierr; 492aefd8378Sjeremylt 493aefd8378Sjeremylt // Check for object delegate 4941d102b48SJeremy L Thompson for (CeedInt i=0; i<ceed->objdelegatecount; i++) 495aefd8378Sjeremylt if (!strcmp(objname, ceed->objdelegates->objname)) { 496aefd8378Sjeremylt *delegate = ceed->objdelegates->delegate; 497aefd8378Sjeremylt return 0; 498aefd8378Sjeremylt } 499aefd8378Sjeremylt 500aefd8378Sjeremylt // Use default delegate if no object delegate 501aefd8378Sjeremylt ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 502aefd8378Sjeremylt 503aefd8378Sjeremylt return 0; 504aefd8378Sjeremylt } 505aefd8378Sjeremylt 506aefd8378Sjeremylt /** 507aefd8378Sjeremylt @brief Set a delegate CEED for a specific object type 508aefd8378Sjeremylt 509f29ffe77Sjeremylt This function allows a CEED to set a delegate CEED for a given type of 510f29ffe77Sjeremylt CEED object. All backend implementations default to the delegate CEED for 511f29ffe77Sjeremylt this object. For example, 512f29ffe77Sjeremylt CeedSetObjectDelegate(ceed, refceed, "Basis") 513f29ffe77Sjeremylt uses refceed implementations for all CeedBasis backend functions. 514f29ffe77Sjeremylt 515aefd8378Sjeremylt @param ceed Ceed to set delegate of 516aefd8378Sjeremylt @param[out] delegate Address to set the delegate to 517288c0443SJeremy L Thompson @param[in] objname Name of the object type to set delegate for 518aefd8378Sjeremylt 519aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 520aefd8378Sjeremylt 521aefd8378Sjeremylt @ref Advanced 522aefd8378Sjeremylt **/ 523a4999eddSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 524aefd8378Sjeremylt CeedInt ierr; 525aefd8378Sjeremylt CeedInt count = ceed->objdelegatecount; 526aefd8378Sjeremylt 527aefd8378Sjeremylt // Malloc or Realloc 528aefd8378Sjeremylt if (count) { 5291d102b48SJeremy L Thompson ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 530aefd8378Sjeremylt } else { 531aefd8378Sjeremylt ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 532aefd8378Sjeremylt } 533aefd8378Sjeremylt ceed->objdelegatecount++; 534aefd8378Sjeremylt 535aefd8378Sjeremylt // Set object delegate 536a4999eddSjeremylt ceed->objdelegates[count].delegate = delegate; 53707a02837SJed Brown size_t slen = strlen(objname) + 1; 53807a02837SJed Brown ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 53907a02837SJed Brown memcpy(ceed->objdelegates[count].objname, objname, slen); 540aefd8378Sjeremylt 541aefd8378Sjeremylt // Set delegate parent 542a4999eddSjeremylt delegate->parent = ceed; 543aefd8378Sjeremylt 544aefd8378Sjeremylt return 0; 545aefd8378Sjeremylt } 546aefd8378Sjeremylt 547aefd8378Sjeremylt /** 5485107b09fSJeremy L Thompson @brief Set the fallback resource for CeedOperators. The current resource, if 5495107b09fSJeremy L Thompson any, is freed by calling this function. This string is freed upon the 5505107b09fSJeremy L Thompson destruction of the Ceed. 5515107b09fSJeremy L Thompson 5525107b09fSJeremy L Thompson @param[out] ceed Ceed context 5535107b09fSJeremy L Thompson @param resource Fallback resource to set 5545107b09fSJeremy L Thompson 5555107b09fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 5565107b09fSJeremy L Thompson 5575107b09fSJeremy L Thompson @ref Advanced 5585107b09fSJeremy L Thompson **/ 5595107b09fSJeremy L Thompson 5605107b09fSJeremy L Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 5615107b09fSJeremy L Thompson int ierr; 5625107b09fSJeremy L Thompson 5635107b09fSJeremy L Thompson // Free old 5645107b09fSJeremy L Thompson ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 5655107b09fSJeremy L Thompson 5665107b09fSJeremy L Thompson // Set new 5675107b09fSJeremy L Thompson size_t len = strlen(resource); 5685107b09fSJeremy L Thompson char *tmp; 5695107b09fSJeremy L Thompson ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 5705107b09fSJeremy L Thompson memcpy(tmp, resource, len+1); 5715107b09fSJeremy L Thompson ceed->opfallbackresource = tmp; 5725107b09fSJeremy L Thompson 5735107b09fSJeremy L Thompson return 0; 5745107b09fSJeremy L Thompson } 5755107b09fSJeremy L Thompson 5765107b09fSJeremy L Thompson /** 5775107b09fSJeremy L Thompson @brief Get the fallback resource for CeedOperators 5785107b09fSJeremy L Thompson 5795107b09fSJeremy L Thompson @param ceed Ceed context 5805107b09fSJeremy L Thompson @param[out] resource Variable to store fallback resource 5815107b09fSJeremy L Thompson 5825107b09fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 5835107b09fSJeremy L Thompson 5845107b09fSJeremy L Thompson @ref Advanced 5855107b09fSJeremy L Thompson **/ 5865107b09fSJeremy L Thompson 5875107b09fSJeremy L Thompson int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 5885107b09fSJeremy L Thompson *resource = (const char *)ceed->opfallbackresource; 5895107b09fSJeremy L Thompson return 0; 5905107b09fSJeremy L Thompson } 5915107b09fSJeremy L Thompson 5925107b09fSJeremy L Thompson /** 5935107b09fSJeremy L Thompson @brief Get the parent Ceed associated with a fallback Ceed for a CeedOperator 5945107b09fSJeremy L Thompson 5955107b09fSJeremy L Thompson @param ceed Ceed context 5965107b09fSJeremy L Thompson @param[out] ceed Variable to store parent Ceed 5975107b09fSJeremy L Thompson 5985107b09fSJeremy L Thompson @return An error code: 0 - success, otherwise - failure 5995107b09fSJeremy L Thompson 6005107b09fSJeremy L Thompson @ref Advanced 6015107b09fSJeremy L Thompson **/ 6025107b09fSJeremy L Thompson 6035107b09fSJeremy L Thompson int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 6045107b09fSJeremy L Thompson *parent = ceed->opfallbackparent; 6055107b09fSJeremy L Thompson return 0; 6065107b09fSJeremy L Thompson } 6075107b09fSJeremy L Thompson 6085107b09fSJeremy L Thompson /** 6098c91a0c9SJeremy L Thompson @brief Return Ceed preferred memory type 610c907536fSjeremylt 611c907536fSjeremylt @param ceed Ceed to get preferred memory type of 612288c0443SJeremy L Thompson @param[out] type Address to save preferred memory type to 613c907536fSjeremylt 614c907536fSjeremylt @return An error code: 0 - success, otherwise - failure 615c907536fSjeremylt 616c907536fSjeremylt @ref Basic 617c907536fSjeremylt **/ 618c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 619c907536fSjeremylt int ierr; 620c263cd57Sjeremylt 621c907536fSjeremylt if (ceed->GetPreferredMemType) { 622c907536fSjeremylt ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 623c907536fSjeremylt } else { 624c263cd57Sjeremylt Ceed delegate; 625c263cd57Sjeremylt ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 626c263cd57Sjeremylt 627c263cd57Sjeremylt if (delegate) { 628c263cd57Sjeremylt ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 629c263cd57Sjeremylt } else { 630c907536fSjeremylt *type = CEED_MEM_HOST; 631c907536fSjeremylt } 632c263cd57Sjeremylt } 633c907536fSjeremylt 634c907536fSjeremylt return 0; 635c907536fSjeremylt } 636c907536fSjeremylt 637c907536fSjeremylt /** 638fe2413ffSjeremylt @brief Set a backend function 639fe2413ffSjeremylt 640cb37edd8Sjeremylt This function is used for a backend to set the function associated with 641cb37edd8Sjeremylt the CEED objects. For example, 642f8902d9eSjeremylt CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 643cb37edd8Sjeremylt sets the backend implementation of 'CeedVectorCreate' and 644cb37edd8Sjeremylt CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 645cb37edd8Sjeremylt sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 646cb37edd8Sjeremylt is not required for the object type ("Basis" vs "CeedBasis"). 647cb37edd8Sjeremylt 648fe2413ffSjeremylt @param ceed Ceed for error handling 649fe2413ffSjeremylt @param type Type of Ceed object to set function for 650fe2413ffSjeremylt @param[out] object Ceed object to set function for 651fe2413ffSjeremylt @param fname Name of function to set 652fe2413ffSjeremylt @param f Function to set 653fe2413ffSjeremylt 654fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 655fe2413ffSjeremylt 656fe2413ffSjeremylt @ref Advanced 657fe2413ffSjeremylt **/ 658692c2638Sjeremylt int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 659fe2413ffSjeremylt const char *fname, int (*f)()) { 660409ab9adSjeremylt char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 661fe2413ffSjeremylt 662fe2413ffSjeremylt // Build lookup name 6636e79d475Sjeremylt if (strcmp(type, "Ceed")) 6646e79d475Sjeremylt strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 665409ab9adSjeremylt strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 666409ab9adSjeremylt strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 667fe2413ffSjeremylt 668fe2413ffSjeremylt // Find and use offset 6691d102b48SJeremy L Thompson for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 670fe2413ffSjeremylt if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 671fe2413ffSjeremylt size_t offset = ceed->foffsets[i].offset; 672cb0b5415Sjeremylt int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 673a7a2e802Sjeremylt *fpointer = f; 674fe2413ffSjeremylt return 0; 675fe2413ffSjeremylt } 676fe2413ffSjeremylt 677c042f62fSJeremy L Thompson // LCOV_EXCL_START 6781d102b48SJeremy L Thompson return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 6791d102b48SJeremy L Thompson "object '%s'", fname, type); 680c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 681fe2413ffSjeremylt } 682fe2413ffSjeremylt 683fe2413ffSjeremylt /** 6844ce2993fSjeremylt @brief Retrieve backend data for a CEED 6854ce2993fSjeremylt 686fe2413ffSjeremylt @param ceed Ceed to retrieve data of 6874ce2993fSjeremylt @param[out] data Address to save data to 6884ce2993fSjeremylt 6894ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 6904ce2993fSjeremylt 69123617272Sjeremylt @ref Advanced 6924ce2993fSjeremylt **/ 6934ce2993fSjeremylt int CeedGetData(Ceed ceed, void **data) { 6944ce2993fSjeremylt *data = ceed->data; 6955fe0d4faSjeremylt return 0; 6965fe0d4faSjeremylt } 6975fe0d4faSjeremylt 6985fe0d4faSjeremylt /** 699fe2413ffSjeremylt @brief Set backend data for a CEED 700fe2413ffSjeremylt 701fe2413ffSjeremylt @param ceed Ceed to set data of 702fe2413ffSjeremylt @param data Address of data to set 703fe2413ffSjeremylt 704fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 705fe2413ffSjeremylt 706fe2413ffSjeremylt @ref Advanced 707fe2413ffSjeremylt **/ 708fe2413ffSjeremylt int CeedSetData(Ceed ceed, void **data) { 709fe2413ffSjeremylt ceed->data = *data; 710fe2413ffSjeremylt return 0; 711fe2413ffSjeremylt } 712fe2413ffSjeremylt 713fe2413ffSjeremylt /** 714e07206deSjeremylt @brief Get the full resource name for a CEED 715e07206deSjeremylt 716e07206deSjeremylt @param ceed Ceed to get resource name of 717e07206deSjeremylt @param[out] resource Variable to store resource name 718e07206deSjeremylt 719e07206deSjeremylt @return An error code: 0 - success, otherwise - failure 720e07206deSjeremylt 721e07206deSjeremylt @ref Basic 722e07206deSjeremylt **/ 723e07206deSjeremylt 724e07206deSjeremylt int CeedGetResource(Ceed ceed, const char **resource) { 725e07206deSjeremylt *resource = (const char *)ceed->resource; 726e07206deSjeremylt return 0; 727e07206deSjeremylt } 728e07206deSjeremylt 729e07206deSjeremylt /** 730b11c1e72Sjeremylt @brief Destroy a Ceed context 731d7b241e6Sjeremylt 732d7b241e6Sjeremylt @param ceed Address of Ceed context to destroy 733b11c1e72Sjeremylt 734b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 735dfdf5a53Sjeremylt 736dfdf5a53Sjeremylt @ref Basic 737b11c1e72Sjeremylt **/ 738d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) { 739d7b241e6Sjeremylt int ierr; 740d7b241e6Sjeremylt 7411d102b48SJeremy L Thompson if (!*ceed || --(*ceed)->refcount > 0) 7421d102b48SJeremy L Thompson return 0; 7435fe0d4faSjeremylt if ((*ceed)->delegate) { 7445fe0d4faSjeremylt ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 7455fe0d4faSjeremylt } 746aefd8378Sjeremylt if ((*ceed)->objdelegatecount > 0) { 747aefd8378Sjeremylt for (int i=0; i<(*ceed)->objdelegatecount; i++) { 748aefd8378Sjeremylt ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 749aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 750aefd8378Sjeremylt } 751aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 752aefd8378Sjeremylt } 753d7b241e6Sjeremylt if ((*ceed)->Destroy) { 754d7b241e6Sjeremylt ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 755d7b241e6Sjeremylt } 7566e79d475Sjeremylt ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 757e07206deSjeremylt ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 7585107b09fSJeremy L Thompson ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 7595107b09fSJeremy L Thompson ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 760d7b241e6Sjeremylt ierr = CeedFree(ceed); CeedChk(ierr); 761d7b241e6Sjeremylt return 0; 762d7b241e6Sjeremylt } 763d7b241e6Sjeremylt 764d7b241e6Sjeremylt /// @} 765