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 **/ 15756e866f4SJed Brown int CeedErrorExit(Ceed ceed, const char *filename, int lineno, 15856e866f4SJed Brown const char *func, int ecode, 15956e866f4SJed Brown const char *format, va_list args) { 16056e866f4SJed Brown fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 16156e866f4SJed Brown vfprintf(stderr, format, args); 16256e866f4SJed Brown fprintf(stderr, "\n"); 16356e866f4SJed Brown exit(ecode); 16456e866f4SJed Brown return ecode; 16556e866f4SJed Brown } 16656e866f4SJed Brown 16756e866f4SJed Brown /** 168dfdf5a53Sjeremylt @brief Set error handler 169b11c1e72Sjeremylt 170b11c1e72Sjeremylt A default error handler is set in CeedInit(). Use this function to change 171b11c1e72Sjeremylt the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 172b11c1e72Sjeremylt error handler. 173dfdf5a53Sjeremylt 174dfdf5a53Sjeremylt @ref Developer 175b11c1e72Sjeremylt **/ 176d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed, 177d7b241e6Sjeremylt int (eh)(Ceed, const char *, int, const char *, 178d7b241e6Sjeremylt int, const char *, va_list)) { 179d7b241e6Sjeremylt ceed->Error = eh; 180d7b241e6Sjeremylt return 0; 181d7b241e6Sjeremylt } 182d7b241e6Sjeremylt 183d7b241e6Sjeremylt /** 184b11c1e72Sjeremylt @brief Register a Ceed backend 185d7b241e6Sjeremylt 186d7b241e6Sjeremylt @param prefix Prefix of resources for this backend to respond to. For 187d7b241e6Sjeremylt example, the reference backend responds to "/cpu/self". 188d7b241e6Sjeremylt @param init Initialization function called by CeedInit() when the backend 189d7b241e6Sjeremylt is selected to drive the requested resource. 190d7b241e6Sjeremylt @param priority Integer priority. Lower values are preferred in case the 191d7b241e6Sjeremylt resource requested by CeedInit() has non-unique best prefix 192d7b241e6Sjeremylt match. 193b11c1e72Sjeremylt 194b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 195dfdf5a53Sjeremylt 196dfdf5a53Sjeremylt @ref Advanced 197b11c1e72Sjeremylt **/ 198d7b241e6Sjeremylt int CeedRegister(const char *prefix, 199d7b241e6Sjeremylt int (*init)(const char *, Ceed), unsigned int priority) { 200c042f62fSJeremy L Thompson if (num_backends >= sizeof(backends) / sizeof(backends[0])) 201c042f62fSJeremy L Thompson // LCOV_EXCL_START 202d7b241e6Sjeremylt return CeedError(NULL, 1, "Too many backends"); 203c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 204c042f62fSJeremy L Thompson 205d7b241e6Sjeremylt strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 206288c0443SJeremy L Thompson backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 207d7b241e6Sjeremylt backends[num_backends].init = init; 208d7b241e6Sjeremylt backends[num_backends].priority = priority; 209d7b241e6Sjeremylt num_backends++; 210d7b241e6Sjeremylt return 0; 211d7b241e6Sjeremylt } 212d7b241e6Sjeremylt 213b11c1e72Sjeremylt /** 214b11c1e72Sjeremylt @brief Allocate an array on the host; use CeedMalloc() 215b11c1e72Sjeremylt 216b11c1e72Sjeremylt Memory usage can be tracked by the library. This ensures sufficient 217b11c1e72Sjeremylt alignment for vectorization and should be used for large allocations. 218b11c1e72Sjeremylt 219b11c1e72Sjeremylt @param n Number of units to allocate 220b11c1e72Sjeremylt @param unit Size of each unit 221b11c1e72Sjeremylt @param p Address of pointer to hold the result. 222b11c1e72Sjeremylt 223b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 224b11c1e72Sjeremylt 225b11c1e72Sjeremylt @sa CeedFree() 226dfdf5a53Sjeremylt 227dfdf5a53Sjeremylt @ref Advanced 228b11c1e72Sjeremylt **/ 229d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) { 230d7b241e6Sjeremylt int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 231d7b241e6Sjeremylt if (ierr) 232c042f62fSJeremy L Thompson // LCOV_EXCL_START 2331d102b48SJeremy L Thompson return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 2341d102b48SJeremy L Thompson "members of size %zd\n", n, unit); 235c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 236c042f62fSJeremy L Thompson 237d7b241e6Sjeremylt return 0; 238d7b241e6Sjeremylt } 239d7b241e6Sjeremylt 240b11c1e72Sjeremylt /** 241b11c1e72Sjeremylt @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 242b11c1e72Sjeremylt 243b11c1e72Sjeremylt Memory usage can be tracked by the library. 244b11c1e72Sjeremylt 245b11c1e72Sjeremylt @param n Number of units to allocate 246b11c1e72Sjeremylt @param unit Size of each unit 247b11c1e72Sjeremylt @param p Address of pointer to hold the result. 248b11c1e72Sjeremylt 249b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 250b11c1e72Sjeremylt 251b11c1e72Sjeremylt @sa CeedFree() 252dfdf5a53Sjeremylt 253dfdf5a53Sjeremylt @ref Advanced 254b11c1e72Sjeremylt **/ 255d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) { 256d7b241e6Sjeremylt *(void **)p = calloc(n, unit); 257d7b241e6Sjeremylt if (n && unit && !*(void **)p) 258c042f62fSJeremy L Thompson // LCOV_EXCL_START 2591d102b48SJeremy L Thompson return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 2601d102b48SJeremy L Thompson "%zd\n", n, unit); 261c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 262c042f62fSJeremy L Thompson 263d7b241e6Sjeremylt return 0; 264d7b241e6Sjeremylt } 265d7b241e6Sjeremylt 266b11c1e72Sjeremylt /** 267b11c1e72Sjeremylt @brief Reallocate an array on the host; use CeedRealloc() 268b11c1e72Sjeremylt 269b11c1e72Sjeremylt Memory usage can be tracked by the library. 270b11c1e72Sjeremylt 271b11c1e72Sjeremylt @param n Number of units to allocate 272b11c1e72Sjeremylt @param unit Size of each unit 273b11c1e72Sjeremylt @param p Address of pointer to hold the result. 274b11c1e72Sjeremylt 275b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 276b11c1e72Sjeremylt 277b11c1e72Sjeremylt @sa CeedFree() 278dfdf5a53Sjeremylt 279dfdf5a53Sjeremylt @ref Advanced 280b11c1e72Sjeremylt **/ 281d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) { 282d7b241e6Sjeremylt *(void **)p = realloc(*(void **)p, n*unit); 283d7b241e6Sjeremylt if (n && unit && !*(void **)p) 284c042f62fSJeremy L Thompson // LCOV_EXCL_START 2851d102b48SJeremy L Thompson return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 2861d102b48SJeremy L Thompson "%zd\n", n, unit); 287c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 288c042f62fSJeremy L Thompson 289d7b241e6Sjeremylt return 0; 290d7b241e6Sjeremylt } 291d7b241e6Sjeremylt 292d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc() 293d7b241e6Sjeremylt /// 294d7b241e6Sjeremylt /// @param p address of pointer to memory. This argument is of type void* to 295d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed) 296d7b241e6Sjeremylt /// rather than the pointer. 297d7b241e6Sjeremylt int CeedFree(void *p) { 298d7b241e6Sjeremylt free(*(void **)p); 299d7b241e6Sjeremylt *(void **)p = NULL; 300d7b241e6Sjeremylt return 0; 301d7b241e6Sjeremylt } 302d7b241e6Sjeremylt 303d7b241e6Sjeremylt /** 304b11c1e72Sjeremylt @brief Wait for a CeedRequest to complete. 305d7b241e6Sjeremylt 306d7b241e6Sjeremylt Calling CeedRequestWait on a NULL request is a no-op. 307d7b241e6Sjeremylt 308d7b241e6Sjeremylt @param req Address of CeedRequest to wait for; zeroed on completion. 309b11c1e72Sjeremylt 310b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 311dfdf5a53Sjeremylt 312dfdf5a53Sjeremylt @ref Advanced 313b11c1e72Sjeremylt **/ 314d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) { 3151d102b48SJeremy L Thompson if (!*req) 3161d102b48SJeremy L Thompson return 0; 317d7b241e6Sjeremylt return CeedError(NULL, 2, "CeedRequestWait not implemented"); 318d7b241e6Sjeremylt } 319d7b241e6Sjeremylt 320b11c1e72Sjeremylt /** 321b11c1e72Sjeremylt @brief Initialize a \ref Ceed to use the specified resource. 322b11c1e72Sjeremylt 323b11c1e72Sjeremylt @param resource Resource to use, e.g., "/cpu/self" 324b11c1e72Sjeremylt @param ceed The library context 325b11c1e72Sjeremylt @sa CeedRegister() CeedDestroy() 326b11c1e72Sjeremylt 327b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 328dfdf5a53Sjeremylt 329dfdf5a53Sjeremylt @ref Basic 330b11c1e72Sjeremylt **/ 331d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) { 332d7b241e6Sjeremylt int ierr; 333aedaa0e5Sjeremylt size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 334d7b241e6Sjeremylt 335fe2413ffSjeremylt // Find matching backend 3361d102b48SJeremy L Thompson if (!resource) 3371d102b48SJeremy L Thompson return CeedError(NULL, 1, "No resource provided"); 338d7b241e6Sjeremylt for (size_t i=0; i<num_backends; i++) { 339d7b241e6Sjeremylt size_t n; 340d7b241e6Sjeremylt const char *prefix = backends[i].prefix; 341d7b241e6Sjeremylt for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 342d7b241e6Sjeremylt priority = backends[i].priority; 343d7b241e6Sjeremylt if (n > matchlen || (n == matchlen && matchpriority > priority)) { 344d7b241e6Sjeremylt matchlen = n; 345d7b241e6Sjeremylt matchpriority = priority; 346d7b241e6Sjeremylt matchidx = i; 347d7b241e6Sjeremylt } 348d7b241e6Sjeremylt } 3491d102b48SJeremy L Thompson if (!matchlen) 3501d102b48SJeremy L Thompson return CeedError(NULL, 1, "No suitable backend"); 351fe2413ffSjeremylt 352fe2413ffSjeremylt // Setup Ceed 353d7b241e6Sjeremylt ierr = CeedCalloc(1,ceed); CeedChk(ierr); 354bc81ce41Sjeremylt const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 3551d102b48SJeremy L Thompson if (!ceed_error_handler) 3561d102b48SJeremy L Thompson ceed_error_handler = "abort"; 357bc81ce41Sjeremylt if (!strcmp(ceed_error_handler, "exit")) 35856e866f4SJed Brown (*ceed)->Error = CeedErrorExit; 35956e866f4SJed Brown else 360d7b241e6Sjeremylt (*ceed)->Error = CeedErrorAbort; 361d7b241e6Sjeremylt (*ceed)->refcount = 1; 362d7b241e6Sjeremylt (*ceed)->data = NULL; 363fe2413ffSjeremylt 364fe2413ffSjeremylt // Set lookup table 3656e79d475Sjeremylt foffset foffsets[] = { 3666e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Error), 3676e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 3686e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Destroy), 369f8902d9eSjeremylt CEED_FTABLE_ENTRY(Ceed, VectorCreate), 3706e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 3716e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 3726e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 3736e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 3746e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 3756e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 3766e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 3776e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 3786e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetArray), 3796e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetValue), 3806e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArray), 3816e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 3826e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 3836e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 3846e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, Destroy), 3856e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 3866e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 3876e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 3886e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Apply), 3896e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Destroy), 3906e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 3916e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 3926e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Apply), 3936e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 3941d102b48SJeremy L Thompson CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction), 395*b7ec98d8SJeremy L Thompson CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal), 3966e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Apply), 3976e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 3986e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Destroy), 3996e79d475Sjeremylt {NULL, 0} // End of lookup table - used in SetBackendFunction loop 4001dfeef1dSjeremylt }; 401fe2413ffSjeremylt 4026e79d475Sjeremylt ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 4036e79d475Sjeremylt memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 404fe2413ffSjeremylt 405fe2413ffSjeremylt // Backend specific setup 406d7b241e6Sjeremylt ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 407fe2413ffSjeremylt 408d7b241e6Sjeremylt return 0; 409d7b241e6Sjeremylt } 410d7b241e6Sjeremylt 411d7b241e6Sjeremylt /** 4122f86a920SJeremy L Thompson @brief Retrieve a parent CEED 4132f86a920SJeremy L Thompson 4142f86a920SJeremy L Thompson @param ceed Ceed to retrieve parent of 4152f86a920SJeremy L Thompson @param[out] parent Address to save the parent to 4162f86a920SJeremy L Thompson 4172f86a920SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 4182f86a920SJeremy L Thompson 4192f86a920SJeremy L Thompson @ref Developer 4202f86a920SJeremy L Thompson **/ 4212f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) { 4222f86a920SJeremy L Thompson int ierr; 4232f86a920SJeremy L Thompson if (ceed->parent) { 4242f86a920SJeremy L Thompson ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 4252f86a920SJeremy L Thompson return 0; 4262f86a920SJeremy L Thompson } 4272f86a920SJeremy L Thompson *parent = ceed; 4282f86a920SJeremy L Thompson return 0; 4292f86a920SJeremy L Thompson } 4302f86a920SJeremy L Thompson 4312f86a920SJeremy L Thompson /** 4325fe0d4faSjeremylt @brief Retrieve a delegate CEED 4335fe0d4faSjeremylt 4345fe0d4faSjeremylt @param ceed Ceed to retrieve delegate of 4355fe0d4faSjeremylt @param[out] delegate Address to save the delegate to 4365fe0d4faSjeremylt 4375fe0d4faSjeremylt @return An error code: 0 - success, otherwise - failure 4385fe0d4faSjeremylt 43923617272Sjeremylt @ref Developer 4405fe0d4faSjeremylt **/ 4415fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 4424ce2993fSjeremylt *delegate = ceed->delegate; 4434ce2993fSjeremylt return 0; 4444ce2993fSjeremylt } 4454ce2993fSjeremylt 4464ce2993fSjeremylt /** 4474ce2993fSjeremylt @brief Set a delegate CEED 4484ce2993fSjeremylt 449f29ffe77Sjeremylt This function allows a CEED to set a delegate CEED. All backend 450f29ffe77Sjeremylt implementations default to the delegate CEED, unless overridden. 451f29ffe77Sjeremylt 4524ce2993fSjeremylt @param ceed Ceed to set delegate of 4534ce2993fSjeremylt @param[out] delegate Address to set the delegate to 4544ce2993fSjeremylt 4554ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 4564ce2993fSjeremylt 45723617272Sjeremylt @ref Advanced 4584ce2993fSjeremylt **/ 459a4999eddSjeremylt int CeedSetDelegate(Ceed ceed, Ceed delegate) { 460a4999eddSjeremylt ceed->delegate = delegate; 461a4999eddSjeremylt delegate->parent = ceed; 4624ce2993fSjeremylt return 0; 4634ce2993fSjeremylt } 4644ce2993fSjeremylt 4654ce2993fSjeremylt /** 466aefd8378Sjeremylt @brief Retrieve a delegate CEED for a specific object type 467aefd8378Sjeremylt 468aefd8378Sjeremylt @param ceed Ceed to retrieve delegate of 469aefd8378Sjeremylt @param[out] delegate Address to save the delegate to 470288c0443SJeremy L Thompson @param[in] objname Name of the object type to retrieve delegate for 471aefd8378Sjeremylt 472aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 473aefd8378Sjeremylt 474aefd8378Sjeremylt @ref Developer 475aefd8378Sjeremylt **/ 476aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 477aefd8378Sjeremylt CeedInt ierr; 478aefd8378Sjeremylt 479aefd8378Sjeremylt // Check for object delegate 4801d102b48SJeremy L Thompson for (CeedInt i=0; i<ceed->objdelegatecount; i++) 481aefd8378Sjeremylt if (!strcmp(objname, ceed->objdelegates->objname)) { 482aefd8378Sjeremylt *delegate = ceed->objdelegates->delegate; 483aefd8378Sjeremylt return 0; 484aefd8378Sjeremylt } 485aefd8378Sjeremylt 486aefd8378Sjeremylt // Use default delegate if no object delegate 487aefd8378Sjeremylt ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 488aefd8378Sjeremylt 489aefd8378Sjeremylt return 0; 490aefd8378Sjeremylt } 491aefd8378Sjeremylt 492aefd8378Sjeremylt /** 493aefd8378Sjeremylt @brief Set a delegate CEED for a specific object type 494aefd8378Sjeremylt 495f29ffe77Sjeremylt This function allows a CEED to set a delegate CEED for a given type of 496f29ffe77Sjeremylt CEED object. All backend implementations default to the delegate CEED for 497f29ffe77Sjeremylt this object. For example, 498f29ffe77Sjeremylt CeedSetObjectDelegate(ceed, refceed, "Basis") 499f29ffe77Sjeremylt uses refceed implementations for all CeedBasis backend functions. 500f29ffe77Sjeremylt 501aefd8378Sjeremylt @param ceed Ceed to set delegate of 502aefd8378Sjeremylt @param[out] delegate Address to set the delegate to 503288c0443SJeremy L Thompson @param[in] objname Name of the object type to set delegate for 504aefd8378Sjeremylt 505aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 506aefd8378Sjeremylt 507aefd8378Sjeremylt @ref Advanced 508aefd8378Sjeremylt **/ 509a4999eddSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 510aefd8378Sjeremylt CeedInt ierr; 511aefd8378Sjeremylt CeedInt count = ceed->objdelegatecount; 512aefd8378Sjeremylt 513aefd8378Sjeremylt // Malloc or Realloc 514aefd8378Sjeremylt if (count) { 5151d102b48SJeremy L Thompson ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 516aefd8378Sjeremylt } else { 517aefd8378Sjeremylt ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 518aefd8378Sjeremylt } 519aefd8378Sjeremylt ceed->objdelegatecount++; 520aefd8378Sjeremylt 521aefd8378Sjeremylt // Set object delegate 522a4999eddSjeremylt ceed->objdelegates[count].delegate = delegate; 52307a02837SJed Brown size_t slen = strlen(objname) + 1; 52407a02837SJed Brown ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 52507a02837SJed Brown memcpy(ceed->objdelegates[count].objname, objname, slen); 526aefd8378Sjeremylt 527aefd8378Sjeremylt // Set delegate parent 528a4999eddSjeremylt delegate->parent = ceed; 529aefd8378Sjeremylt 530aefd8378Sjeremylt return 0; 531aefd8378Sjeremylt } 532aefd8378Sjeremylt 533aefd8378Sjeremylt /** 5348c91a0c9SJeremy L Thompson @brief Return Ceed preferred memory type 535c907536fSjeremylt 536c907536fSjeremylt @param ceed Ceed to get preferred memory type of 537288c0443SJeremy L Thompson @param[out] type Address to save preferred memory type to 538c907536fSjeremylt 539c907536fSjeremylt @return An error code: 0 - success, otherwise - failure 540c907536fSjeremylt 541c907536fSjeremylt @ref Basic 542c907536fSjeremylt **/ 543c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 544c907536fSjeremylt int ierr; 545c263cd57Sjeremylt 546c907536fSjeremylt if (ceed->GetPreferredMemType) { 547c907536fSjeremylt ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 548c907536fSjeremylt } else { 549c263cd57Sjeremylt Ceed delegate; 550c263cd57Sjeremylt ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 551c263cd57Sjeremylt 552c263cd57Sjeremylt if (delegate) { 553c263cd57Sjeremylt ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 554c263cd57Sjeremylt } else { 555c907536fSjeremylt *type = CEED_MEM_HOST; 556c907536fSjeremylt } 557c263cd57Sjeremylt } 558c907536fSjeremylt 559c907536fSjeremylt return 0; 560c907536fSjeremylt } 561c907536fSjeremylt 562c907536fSjeremylt /** 563fe2413ffSjeremylt @brief Set a backend function 564fe2413ffSjeremylt 565cb37edd8Sjeremylt This function is used for a backend to set the function associated with 566cb37edd8Sjeremylt the CEED objects. For example, 567f8902d9eSjeremylt CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 568cb37edd8Sjeremylt sets the backend implementation of 'CeedVectorCreate' and 569cb37edd8Sjeremylt CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 570cb37edd8Sjeremylt sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 571cb37edd8Sjeremylt is not required for the object type ("Basis" vs "CeedBasis"). 572cb37edd8Sjeremylt 573fe2413ffSjeremylt @param ceed Ceed for error handling 574fe2413ffSjeremylt @param type Type of Ceed object to set function for 575fe2413ffSjeremylt @param[out] object Ceed object to set function for 576fe2413ffSjeremylt @param fname Name of function to set 577fe2413ffSjeremylt @param f Function to set 578fe2413ffSjeremylt 579fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 580fe2413ffSjeremylt 581fe2413ffSjeremylt @ref Advanced 582fe2413ffSjeremylt **/ 583fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed, 584fe2413ffSjeremylt const char *type, void *object, 585fe2413ffSjeremylt const char *fname, int (*f)()) { 586409ab9adSjeremylt char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 587fe2413ffSjeremylt 588fe2413ffSjeremylt // Build lookup name 5896e79d475Sjeremylt if (strcmp(type, "Ceed")) 5906e79d475Sjeremylt strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 591409ab9adSjeremylt strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 592409ab9adSjeremylt strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 593fe2413ffSjeremylt 594fe2413ffSjeremylt // Find and use offset 5951d102b48SJeremy L Thompson for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 596fe2413ffSjeremylt if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 597fe2413ffSjeremylt size_t offset = ceed->foffsets[i].offset; 598a7a2e802Sjeremylt int (**fpointer)(void) = (int (* *)(void))((char *)object + offset); 599a7a2e802Sjeremylt *fpointer = f; 600fe2413ffSjeremylt return 0; 601fe2413ffSjeremylt } 602fe2413ffSjeremylt 603c042f62fSJeremy L Thompson // LCOV_EXCL_START 6041d102b48SJeremy L Thompson return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 6051d102b48SJeremy L Thompson "object '%s'", fname, type); 606c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 607fe2413ffSjeremylt } 608fe2413ffSjeremylt 609fe2413ffSjeremylt /** 6104ce2993fSjeremylt @brief Retrieve backend data for a CEED 6114ce2993fSjeremylt 612fe2413ffSjeremylt @param ceed Ceed to retrieve data of 6134ce2993fSjeremylt @param[out] data Address to save data to 6144ce2993fSjeremylt 6154ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 6164ce2993fSjeremylt 61723617272Sjeremylt @ref Advanced 6184ce2993fSjeremylt **/ 6194ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) { 6204ce2993fSjeremylt *data = ceed->data; 6215fe0d4faSjeremylt return 0; 6225fe0d4faSjeremylt } 6235fe0d4faSjeremylt 6245fe0d4faSjeremylt /** 625fe2413ffSjeremylt @brief Set backend data for a CEED 626fe2413ffSjeremylt 627fe2413ffSjeremylt @param ceed Ceed to set data of 628fe2413ffSjeremylt @param data Address of data to set 629fe2413ffSjeremylt 630fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 631fe2413ffSjeremylt 632fe2413ffSjeremylt @ref Advanced 633fe2413ffSjeremylt **/ 634fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) { 635fe2413ffSjeremylt ceed->data = *data; 636fe2413ffSjeremylt return 0; 637fe2413ffSjeremylt } 638fe2413ffSjeremylt 639fe2413ffSjeremylt /** 640b11c1e72Sjeremylt @brief Destroy a Ceed context 641d7b241e6Sjeremylt 642d7b241e6Sjeremylt @param ceed Address of Ceed context to destroy 643b11c1e72Sjeremylt 644b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 645dfdf5a53Sjeremylt 646dfdf5a53Sjeremylt @ref Basic 647b11c1e72Sjeremylt **/ 648d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) { 649d7b241e6Sjeremylt int ierr; 650d7b241e6Sjeremylt 6511d102b48SJeremy L Thompson if (!*ceed || --(*ceed)->refcount > 0) 6521d102b48SJeremy L Thompson return 0; 6535fe0d4faSjeremylt if ((*ceed)->delegate) { 6545fe0d4faSjeremylt ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 6555fe0d4faSjeremylt } 656aefd8378Sjeremylt if ((*ceed)->objdelegatecount > 0) { 657aefd8378Sjeremylt for (int i=0; i<(*ceed)->objdelegatecount; i++) { 658aefd8378Sjeremylt ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 659aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 660aefd8378Sjeremylt } 661aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 662aefd8378Sjeremylt } 663d7b241e6Sjeremylt if ((*ceed)->Destroy) { 664d7b241e6Sjeremylt ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 665d7b241e6Sjeremylt } 6666e79d475Sjeremylt ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 667d7b241e6Sjeremylt ierr = CeedFree(ceed); CeedChk(ierr); 668d7b241e6Sjeremylt return 0; 669d7b241e6Sjeremylt } 670d7b241e6Sjeremylt 671d7b241e6Sjeremylt /// @} 672