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 90d7b241e6Sjeremylt @fixme 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, 138d7b241e6Sjeremylt const char *func, int ecode, 139d7b241e6Sjeremylt const char *format, 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) { 200d7b241e6Sjeremylt if (num_backends >= sizeof(backends) / sizeof(backends[0])) { 201d7b241e6Sjeremylt return CeedError(NULL, 1, "Too many backends"); 202d7b241e6Sjeremylt } 203d7b241e6Sjeremylt strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 204d7b241e6Sjeremylt backends[num_backends].init = init; 205d7b241e6Sjeremylt backends[num_backends].priority = priority; 206d7b241e6Sjeremylt num_backends++; 207d7b241e6Sjeremylt return 0; 208d7b241e6Sjeremylt } 209d7b241e6Sjeremylt 210b11c1e72Sjeremylt /** 211b11c1e72Sjeremylt @brief Allocate an array on the host; use CeedMalloc() 212b11c1e72Sjeremylt 213b11c1e72Sjeremylt Memory usage can be tracked by the library. This ensures sufficient 214b11c1e72Sjeremylt alignment for vectorization and should be used for large allocations. 215b11c1e72Sjeremylt 216b11c1e72Sjeremylt @param n Number of units to allocate 217b11c1e72Sjeremylt @param unit Size of each unit 218b11c1e72Sjeremylt @param p Address of pointer to hold the result. 219b11c1e72Sjeremylt 220b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 221b11c1e72Sjeremylt 222b11c1e72Sjeremylt @sa CeedFree() 223dfdf5a53Sjeremylt 224dfdf5a53Sjeremylt @ref Advanced 225b11c1e72Sjeremylt **/ 226d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) { 227d7b241e6Sjeremylt int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 228d7b241e6Sjeremylt if (ierr) 229d7b241e6Sjeremylt return CeedError(NULL, ierr, 230d7b241e6Sjeremylt "posix_memalign failed to allocate %zd members of size %zd\n", n, unit); 231d7b241e6Sjeremylt return 0; 232d7b241e6Sjeremylt } 233d7b241e6Sjeremylt 234b11c1e72Sjeremylt /** 235b11c1e72Sjeremylt @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 236b11c1e72Sjeremylt 237b11c1e72Sjeremylt Memory usage can be tracked by the library. 238b11c1e72Sjeremylt 239b11c1e72Sjeremylt @param n Number of units to allocate 240b11c1e72Sjeremylt @param unit Size of each unit 241b11c1e72Sjeremylt @param p Address of pointer to hold the result. 242b11c1e72Sjeremylt 243b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 244b11c1e72Sjeremylt 245b11c1e72Sjeremylt @sa CeedFree() 246dfdf5a53Sjeremylt 247dfdf5a53Sjeremylt @ref Advanced 248b11c1e72Sjeremylt **/ 249d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) { 250d7b241e6Sjeremylt *(void **)p = calloc(n, unit); 251d7b241e6Sjeremylt if (n && unit && !*(void **)p) 252d7b241e6Sjeremylt return CeedError(NULL, 1, "calloc failed to allocate %zd members of size %zd\n", 253d7b241e6Sjeremylt n, unit); 254d7b241e6Sjeremylt return 0; 255d7b241e6Sjeremylt } 256d7b241e6Sjeremylt 257b11c1e72Sjeremylt /** 258b11c1e72Sjeremylt @brief Reallocate an array on the host; use CeedRealloc() 259b11c1e72Sjeremylt 260b11c1e72Sjeremylt Memory usage can be tracked by the library. 261b11c1e72Sjeremylt 262b11c1e72Sjeremylt @param n Number of units to allocate 263b11c1e72Sjeremylt @param unit Size of each unit 264b11c1e72Sjeremylt @param p Address of pointer to hold the result. 265b11c1e72Sjeremylt 266b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 267b11c1e72Sjeremylt 268b11c1e72Sjeremylt @sa CeedFree() 269dfdf5a53Sjeremylt 270dfdf5a53Sjeremylt @ref Advanced 271b11c1e72Sjeremylt **/ 272d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) { 273d7b241e6Sjeremylt *(void **)p = realloc(*(void **)p, n*unit); 274d7b241e6Sjeremylt if (n && unit && !*(void **)p) 275d7b241e6Sjeremylt return CeedError(NULL, 1, 276d7b241e6Sjeremylt "realloc failed to allocate %zd members of size %zd\n", 277d7b241e6Sjeremylt n, unit); 278d7b241e6Sjeremylt return 0; 279d7b241e6Sjeremylt } 280d7b241e6Sjeremylt 281d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc() 282d7b241e6Sjeremylt /// 283d7b241e6Sjeremylt /// @param p address of pointer to memory. This argument is of type void* to 284d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed) 285d7b241e6Sjeremylt /// rather than the pointer. 286d7b241e6Sjeremylt int CeedFree(void *p) { 287d7b241e6Sjeremylt free(*(void **)p); 288d7b241e6Sjeremylt *(void **)p = NULL; 289d7b241e6Sjeremylt return 0; 290d7b241e6Sjeremylt } 291d7b241e6Sjeremylt 292d7b241e6Sjeremylt /** 293b11c1e72Sjeremylt @brief Wait for a CeedRequest to complete. 294d7b241e6Sjeremylt 295d7b241e6Sjeremylt Calling CeedRequestWait on a NULL request is a no-op. 296d7b241e6Sjeremylt 297d7b241e6Sjeremylt @param req Address of CeedRequest to wait for; zeroed on completion. 298b11c1e72Sjeremylt 299b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 300dfdf5a53Sjeremylt 301dfdf5a53Sjeremylt @ref Advanced 302b11c1e72Sjeremylt **/ 303d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) { 304d7b241e6Sjeremylt if (!*req) return 0; 305d7b241e6Sjeremylt return CeedError(NULL, 2, "CeedRequestWait not implemented"); 306d7b241e6Sjeremylt } 307d7b241e6Sjeremylt 308b11c1e72Sjeremylt /** 309b11c1e72Sjeremylt @brief Initialize a \ref Ceed to use the specified resource. 310b11c1e72Sjeremylt 311b11c1e72Sjeremylt @param resource Resource to use, e.g., "/cpu/self" 312b11c1e72Sjeremylt @param ceed The library context 313b11c1e72Sjeremylt @sa CeedRegister() CeedDestroy() 314b11c1e72Sjeremylt 315b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 316dfdf5a53Sjeremylt 317dfdf5a53Sjeremylt @ref Basic 318b11c1e72Sjeremylt **/ 319d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) { 320d7b241e6Sjeremylt int ierr; 321aedaa0e5Sjeremylt size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 322d7b241e6Sjeremylt 323fe2413ffSjeremylt // Find matching backend 324d7b241e6Sjeremylt if (!resource) return CeedError(NULL, 1, "No resource provided"); 325d7b241e6Sjeremylt for (size_t i=0; i<num_backends; i++) { 326d7b241e6Sjeremylt size_t n; 327d7b241e6Sjeremylt const char *prefix = backends[i].prefix; 328d7b241e6Sjeremylt for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 329d7b241e6Sjeremylt priority = backends[i].priority; 330d7b241e6Sjeremylt if (n > matchlen || (n == matchlen && matchpriority > priority)) { 331d7b241e6Sjeremylt matchlen = n; 332d7b241e6Sjeremylt matchpriority = priority; 333d7b241e6Sjeremylt matchidx = i; 334d7b241e6Sjeremylt } 335d7b241e6Sjeremylt } 336d7b241e6Sjeremylt if (!matchlen) return CeedError(NULL, 1, "No suitable backend"); 337fe2413ffSjeremylt 338fe2413ffSjeremylt // Setup Ceed 339d7b241e6Sjeremylt ierr = CeedCalloc(1,ceed); CeedChk(ierr); 340bc81ce41Sjeremylt const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 341bc81ce41Sjeremylt if (!ceed_error_handler) ceed_error_handler = "abort"; 342bc81ce41Sjeremylt if (!strcmp(ceed_error_handler, "exit")) 34356e866f4SJed Brown (*ceed)->Error = CeedErrorExit; 34456e866f4SJed Brown else 345d7b241e6Sjeremylt (*ceed)->Error = CeedErrorAbort; 346d7b241e6Sjeremylt (*ceed)->refcount = 1; 347d7b241e6Sjeremylt (*ceed)->data = NULL; 348fe2413ffSjeremylt 349fe2413ffSjeremylt // Set lookup table 3506e79d475Sjeremylt foffset foffsets[] = { 3516e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Error), 3526e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 3536e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, Destroy), 354f8902d9eSjeremylt CEED_FTABLE_ENTRY(Ceed, VectorCreate), 3556e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 3566e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 3576e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 3586e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 3596e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 3606e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 3616e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 3626e79d475Sjeremylt CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 3636e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetArray), 3646e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, SetValue), 3656e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArray), 3666e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 3676e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 3686e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 3696e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedVector, Destroy), 3706e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 3716e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 3726e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 3736e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Apply), 3746e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedBasis, Destroy), 3756e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 3766e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 3776e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Apply), 3786e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 3796e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Apply), 3806e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 3816e79d475Sjeremylt CEED_FTABLE_ENTRY(CeedOperator, Destroy), 3826e79d475Sjeremylt {NULL, 0} // End of lookup table - used in SetBackendFunction loop 3831dfeef1dSjeremylt }; 384fe2413ffSjeremylt 3856e79d475Sjeremylt ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 3866e79d475Sjeremylt memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 387fe2413ffSjeremylt 388fe2413ffSjeremylt // Backend specific setup 389d7b241e6Sjeremylt ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 390fe2413ffSjeremylt 391d7b241e6Sjeremylt return 0; 392d7b241e6Sjeremylt } 393d7b241e6Sjeremylt 394d7b241e6Sjeremylt /** 3952f86a920SJeremy L Thompson @brief Retrieve a parent CEED 3962f86a920SJeremy L Thompson 3972f86a920SJeremy L Thompson @param ceed Ceed to retrieve parent of 3982f86a920SJeremy L Thompson @param[out] parent Address to save the parent to 3992f86a920SJeremy L Thompson 4002f86a920SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 4012f86a920SJeremy L Thompson 4022f86a920SJeremy L Thompson @ref Developer 4032f86a920SJeremy L Thompson **/ 4042f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) { 4052f86a920SJeremy L Thompson int ierr; 4062f86a920SJeremy L Thompson if (ceed->parent) { 4072f86a920SJeremy L Thompson ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 4082f86a920SJeremy L Thompson return 0; 4092f86a920SJeremy L Thompson } 4102f86a920SJeremy L Thompson *parent = ceed; 4112f86a920SJeremy L Thompson return 0; 4122f86a920SJeremy L Thompson } 4132f86a920SJeremy L Thompson 4142f86a920SJeremy L Thompson /** 4155fe0d4faSjeremylt @brief Retrieve a delegate CEED 4165fe0d4faSjeremylt 4175fe0d4faSjeremylt @param ceed Ceed to retrieve delegate of 4185fe0d4faSjeremylt @param[out] delegate Address to save the delegate to 4195fe0d4faSjeremylt 4205fe0d4faSjeremylt @return An error code: 0 - success, otherwise - failure 4215fe0d4faSjeremylt 42223617272Sjeremylt @ref Developer 4235fe0d4faSjeremylt **/ 4245fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 4254ce2993fSjeremylt *delegate = ceed->delegate; 4264ce2993fSjeremylt return 0; 4274ce2993fSjeremylt } 4284ce2993fSjeremylt 4294ce2993fSjeremylt /** 4304ce2993fSjeremylt @brief Set a delegate CEED 4314ce2993fSjeremylt 4324ce2993fSjeremylt @param ceed Ceed to set delegate of 4334ce2993fSjeremylt @param[out] delegate Address to set the delegate to 4344ce2993fSjeremylt 4354ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 4364ce2993fSjeremylt 43723617272Sjeremylt @ref Advanced 4384ce2993fSjeremylt **/ 4394ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) { 4404ce2993fSjeremylt ceed->delegate = *delegate; 4412f86a920SJeremy L Thompson (*delegate)->parent = ceed; 4424ce2993fSjeremylt return 0; 4434ce2993fSjeremylt } 4444ce2993fSjeremylt 4454ce2993fSjeremylt /** 446*aefd8378Sjeremylt @brief Retrieve a delegate CEED for a specific object type 447*aefd8378Sjeremylt 448*aefd8378Sjeremylt @param ceed Ceed to retrieve delegate of 449*aefd8378Sjeremylt @param[out] delegate Address to save the delegate to 450*aefd8378Sjeremylt 451*aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 452*aefd8378Sjeremylt 453*aefd8378Sjeremylt @ref Developer 454*aefd8378Sjeremylt **/ 455*aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 456*aefd8378Sjeremylt CeedInt ierr; 457*aefd8378Sjeremylt 458*aefd8378Sjeremylt // Check for object delegate 459*aefd8378Sjeremylt for (CeedInt i=0; i<ceed->objdelegatecount; i++) { 460*aefd8378Sjeremylt if (!strcmp(objname, ceed->objdelegates->objname)) { 461*aefd8378Sjeremylt *delegate = ceed->objdelegates->delegate; 462*aefd8378Sjeremylt return 0; 463*aefd8378Sjeremylt } 464*aefd8378Sjeremylt } 465*aefd8378Sjeremylt 466*aefd8378Sjeremylt // Use default delegate if no object delegate 467*aefd8378Sjeremylt ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 468*aefd8378Sjeremylt 469*aefd8378Sjeremylt return 0; 470*aefd8378Sjeremylt } 471*aefd8378Sjeremylt 472*aefd8378Sjeremylt /** 473*aefd8378Sjeremylt @brief Set a delegate CEED for a specific object type 474*aefd8378Sjeremylt 475*aefd8378Sjeremylt @param ceed Ceed to set delegate of 476*aefd8378Sjeremylt @param[out] delegate Address to set the delegate to 477*aefd8378Sjeremylt 478*aefd8378Sjeremylt @return An error code: 0 - success, otherwise - failure 479*aefd8378Sjeremylt 480*aefd8378Sjeremylt @ref Advanced 481*aefd8378Sjeremylt **/ 482*aefd8378Sjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 483*aefd8378Sjeremylt CeedInt ierr; 484*aefd8378Sjeremylt CeedInt count = ceed->objdelegatecount; 485*aefd8378Sjeremylt 486*aefd8378Sjeremylt // Malloc or Realloc 487*aefd8378Sjeremylt if (count) { 488*aefd8378Sjeremylt ierr = CeedRealloc(count+1, &ceed->objdelegates); 489*aefd8378Sjeremylt CeedChk(ierr); 490*aefd8378Sjeremylt } else { 491*aefd8378Sjeremylt ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 492*aefd8378Sjeremylt } 493*aefd8378Sjeremylt ceed->objdelegatecount++; 494*aefd8378Sjeremylt 495*aefd8378Sjeremylt // Set object delegate 496*aefd8378Sjeremylt ceed->objdelegates[count].delegate = *delegate; 497*aefd8378Sjeremylt ierr = CeedCalloc(strlen(objname)+1, &ceed->objdelegates[count].objname); 498*aefd8378Sjeremylt CeedChk(ierr); 499*aefd8378Sjeremylt strncpy(ceed->objdelegates[count].objname, objname, strlen(objname)+1); 500*aefd8378Sjeremylt 501*aefd8378Sjeremylt // Set delegate parent 502*aefd8378Sjeremylt (*delegate)->parent = ceed; 503*aefd8378Sjeremylt 504*aefd8378Sjeremylt return 0; 505*aefd8378Sjeremylt } 506*aefd8378Sjeremylt 507*aefd8378Sjeremylt /** 508c907536fSjeremylt @brief Return Ceed perferred memory type 509c907536fSjeremylt 510c907536fSjeremylt @param ceed Ceed to get preferred memory type of 511c907536fSjeremylt @param[out] delegate Address to save preferred memory type to 512c907536fSjeremylt 513c907536fSjeremylt @return An error code: 0 - success, otherwise - failure 514c907536fSjeremylt 515c907536fSjeremylt @ref Basic 516c907536fSjeremylt **/ 517c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 518c907536fSjeremylt int ierr; 519c907536fSjeremylt if (ceed->GetPreferredMemType) { 520c907536fSjeremylt ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 521c907536fSjeremylt } else { 522c907536fSjeremylt *type = CEED_MEM_HOST; 523c907536fSjeremylt } 524c907536fSjeremylt 525c907536fSjeremylt return 0; 526c907536fSjeremylt } 527c907536fSjeremylt 528c907536fSjeremylt /** 529fe2413ffSjeremylt @brief Set a backend function 530fe2413ffSjeremylt 531cb37edd8Sjeremylt This function is used for a backend to set the function associated with 532cb37edd8Sjeremylt the CEED objects. For example, 533f8902d9eSjeremylt CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 534cb37edd8Sjeremylt sets the backend implementation of 'CeedVectorCreate' and 535cb37edd8Sjeremylt CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 536cb37edd8Sjeremylt sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 537cb37edd8Sjeremylt is not required for the object type ("Basis" vs "CeedBasis"). 538cb37edd8Sjeremylt 539fe2413ffSjeremylt @param ceed Ceed for error handling 540fe2413ffSjeremylt @param type Type of Ceed object to set function for 541fe2413ffSjeremylt @param[out] object Ceed object to set function for 542fe2413ffSjeremylt @param fname Name of function to set 543fe2413ffSjeremylt @param f Function to set 544fe2413ffSjeremylt 545fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 546fe2413ffSjeremylt 547fe2413ffSjeremylt @ref Advanced 548fe2413ffSjeremylt **/ 549fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed, 550fe2413ffSjeremylt const char *type, void *object, 551fe2413ffSjeremylt const char *fname, int (*f)()) { 552409ab9adSjeremylt char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 553fe2413ffSjeremylt 554fe2413ffSjeremylt // Build lookup name 5556e79d475Sjeremylt if (strcmp(type, "Ceed")) 5566e79d475Sjeremylt strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 557409ab9adSjeremylt strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 558409ab9adSjeremylt strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 559fe2413ffSjeremylt 560fe2413ffSjeremylt // Find and use offset 5616e79d475Sjeremylt for (CeedInt i = 0; ceed->foffsets[i].fname; i++) { 562fe2413ffSjeremylt if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 563fe2413ffSjeremylt size_t offset = ceed->foffsets[i].offset; 564a7a2e802Sjeremylt int (**fpointer)(void) = (int (**)(void))((char*)object + offset); 565a7a2e802Sjeremylt *fpointer = f; 566fe2413ffSjeremylt return 0; 567fe2413ffSjeremylt } 568fe2413ffSjeremylt } 569fe2413ffSjeremylt 5701dfeef1dSjeremylt return CeedError(ceed, 1, 5711dfeef1dSjeremylt "Requested function '%s' was not found for CEED object '%s'", fname, type); 572fe2413ffSjeremylt } 573fe2413ffSjeremylt 574fe2413ffSjeremylt /** 5754ce2993fSjeremylt @brief Retrieve backend data for a CEED 5764ce2993fSjeremylt 577fe2413ffSjeremylt @param ceed Ceed to retrieve data of 5784ce2993fSjeremylt @param[out] data Address to save data to 5794ce2993fSjeremylt 5804ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 5814ce2993fSjeremylt 58223617272Sjeremylt @ref Advanced 5834ce2993fSjeremylt **/ 5844ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) { 5854ce2993fSjeremylt *data = ceed->data; 5865fe0d4faSjeremylt return 0; 5875fe0d4faSjeremylt } 5885fe0d4faSjeremylt 5895fe0d4faSjeremylt /** 590fe2413ffSjeremylt @brief Set backend data for a CEED 591fe2413ffSjeremylt 592fe2413ffSjeremylt @param ceed Ceed to set data of 593fe2413ffSjeremylt @param data Address of data to set 594fe2413ffSjeremylt 595fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 596fe2413ffSjeremylt 597fe2413ffSjeremylt @ref Advanced 598fe2413ffSjeremylt **/ 599fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) { 600fe2413ffSjeremylt ceed->data = *data; 601fe2413ffSjeremylt return 0; 602fe2413ffSjeremylt } 603fe2413ffSjeremylt 604fe2413ffSjeremylt /** 605b11c1e72Sjeremylt @brief Destroy a Ceed context 606d7b241e6Sjeremylt 607d7b241e6Sjeremylt @param ceed Address of Ceed context to destroy 608b11c1e72Sjeremylt 609b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 610dfdf5a53Sjeremylt 611dfdf5a53Sjeremylt @ref Basic 612b11c1e72Sjeremylt **/ 613d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) { 614d7b241e6Sjeremylt int ierr; 615d7b241e6Sjeremylt 616d7b241e6Sjeremylt if (!*ceed || --(*ceed)->refcount > 0) return 0; 6175fe0d4faSjeremylt if ((*ceed)->delegate) { 6185fe0d4faSjeremylt ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 6195fe0d4faSjeremylt } 620*aefd8378Sjeremylt if ((*ceed)->objdelegatecount > 0) { 621*aefd8378Sjeremylt for (int i=0; i<(*ceed)->objdelegatecount; i++) { 622*aefd8378Sjeremylt ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 623*aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 624*aefd8378Sjeremylt } 625*aefd8378Sjeremylt ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 626*aefd8378Sjeremylt } 627d7b241e6Sjeremylt if ((*ceed)->Destroy) { 628d7b241e6Sjeremylt ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 629d7b241e6Sjeremylt } 6306e79d475Sjeremylt ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 631d7b241e6Sjeremylt ierr = CeedFree(ceed); CeedChk(ierr); 632d7b241e6Sjeremylt return 0; 633d7b241e6Sjeremylt } 634d7b241e6Sjeremylt 635d7b241e6Sjeremylt /// @} 636