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> 22d7b241e6Sjeremylt #include <stdio.h> 23d7b241e6Sjeremylt #include <stdlib.h> 24d7b241e6Sjeremylt #include <string.h> 25d7b241e6Sjeremylt 26d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP 27d7b241e6Sjeremylt static CeedRequest ceed_request_immediate; 28d7b241e6Sjeremylt static CeedRequest ceed_request_ordered; 29d7b241e6Sjeremylt 30d7b241e6Sjeremylt static struct { 31d7b241e6Sjeremylt char prefix[CEED_MAX_RESOURCE_LEN]; 32d7b241e6Sjeremylt int (*init)(const char *resource, Ceed f); 33d7b241e6Sjeremylt unsigned int priority; 34d7b241e6Sjeremylt } backends[32]; 35d7b241e6Sjeremylt static size_t num_backends; 36fe2413ffSjeremylt 37fe2413ffSjeremylt #define ceedoffsetof(st, m) \ 38fe2413ffSjeremylt ((size_t) ( (char *)&((st)(0))->m - (char *)0 )) 39d7b241e6Sjeremylt /// @endcond 40d7b241e6Sjeremylt 41d7b241e6Sjeremylt /// @file 42d7b241e6Sjeremylt /// Implementation of core components of Ceed library 43d7b241e6Sjeremylt /// 44dfdf5a53Sjeremylt /// @addtogroup Ceed 45d7b241e6Sjeremylt /// @{ 46d7b241e6Sjeremylt 47dfdf5a53Sjeremylt /** 48dfdf5a53Sjeremylt @brief Request immediate completion 49dfdf5a53Sjeremylt 50dfdf5a53Sjeremylt This predefined constant is passed as the \ref CeedRequest argument to 51dfdf5a53Sjeremylt interfaces when the caller wishes for the operation to be performed 52dfdf5a53Sjeremylt immediately. The code 53dfdf5a53Sjeremylt 54dfdf5a53Sjeremylt @code 55dfdf5a53Sjeremylt CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 56dfdf5a53Sjeremylt @endcode 57dfdf5a53Sjeremylt 58dfdf5a53Sjeremylt is semantically equivalent to 59dfdf5a53Sjeremylt 60dfdf5a53Sjeremylt @code 61dfdf5a53Sjeremylt CeedRequest request; 62dfdf5a53Sjeremylt CeedOperatorApply(op, ..., &request); 63dfdf5a53Sjeremylt CeedRequestWait(&request); 64dfdf5a53Sjeremylt @endcode 65dfdf5a53Sjeremylt 66dfdf5a53Sjeremylt @sa CEED_REQUEST_ORDERED 67dfdf5a53Sjeremylt **/ 68d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 69d7b241e6Sjeremylt 70d7b241e6Sjeremylt /** 71b11c1e72Sjeremylt @brief Request ordered completion 72d7b241e6Sjeremylt 73d7b241e6Sjeremylt This predefined constant is passed as the \ref CeedRequest argument to 74d7b241e6Sjeremylt interfaces when the caller wishes for the operation to be completed in the 75d7b241e6Sjeremylt order that it is submitted to the device. It is typically used in a construct 76d7b241e6Sjeremylt such as 77d7b241e6Sjeremylt 78d7b241e6Sjeremylt @code 79d7b241e6Sjeremylt CeedRequest request; 80d7b241e6Sjeremylt CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 81d7b241e6Sjeremylt CeedOperatorApply(op2, ..., &request); 82d7b241e6Sjeremylt // other optional work 83d7b241e6Sjeremylt CeedWait(&request); 84d7b241e6Sjeremylt @endcode 85d7b241e6Sjeremylt 86d7b241e6Sjeremylt which allows the sequence to complete asynchronously but does not start 87d7b241e6Sjeremylt `op2` until `op1` has completed. 88d7b241e6Sjeremylt 89d7b241e6Sjeremylt @fixme The current implementation is overly strict, offering equivalent 90d7b241e6Sjeremylt semantics to CEED_REQUEST_IMMEDIATE. 91d7b241e6Sjeremylt 92d7b241e6Sjeremylt @sa CEED_REQUEST_IMMEDIATE 93d7b241e6Sjeremylt */ 94d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 95d7b241e6Sjeremylt 96b11c1e72Sjeremylt /** 97b11c1e72Sjeremylt @brief Error handling implementation; use \ref CeedError instead. 98dfdf5a53Sjeremylt 99dfdf5a53Sjeremylt @ref Developer 100b11c1e72Sjeremylt **/ 101d7b241e6Sjeremylt int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 102d7b241e6Sjeremylt int ecode, const char *format, ...) { 103d7b241e6Sjeremylt va_list args; 104d7b241e6Sjeremylt va_start(args, format); 105d7b241e6Sjeremylt if (ceed) return ceed->Error(ceed, filename, lineno, func, ecode, format, args); 106d7b241e6Sjeremylt return CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args); 107d7b241e6Sjeremylt } 108d7b241e6Sjeremylt 109b11c1e72Sjeremylt /** 110b11c1e72Sjeremylt @brief Error handler that returns without printing anything. 111b11c1e72Sjeremylt 112b11c1e72Sjeremylt Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 113dfdf5a53Sjeremylt 114dfdf5a53Sjeremylt @ref Developer 115b11c1e72Sjeremylt **/ 116d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 117d7b241e6Sjeremylt const char *func, int ecode, const char *format, 118d7b241e6Sjeremylt va_list args) { 119d7b241e6Sjeremylt return ecode; 120d7b241e6Sjeremylt } 121d7b241e6Sjeremylt 122b11c1e72Sjeremylt /** 123b11c1e72Sjeremylt @brief Error handler that prints to stderr and aborts 124b11c1e72Sjeremylt 125b11c1e72Sjeremylt Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 126dfdf5a53Sjeremylt 127dfdf5a53Sjeremylt @ref Developer 128b11c1e72Sjeremylt **/ 129d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 130d7b241e6Sjeremylt const char *func, int ecode, 131d7b241e6Sjeremylt const char *format, va_list args) { 132d7b241e6Sjeremylt fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 133d7b241e6Sjeremylt vfprintf(stderr, format, args); 134d7b241e6Sjeremylt fprintf(stderr, "\n"); 135d7b241e6Sjeremylt abort(); 136d7b241e6Sjeremylt return ecode; 137d7b241e6Sjeremylt } 138d7b241e6Sjeremylt 139b11c1e72Sjeremylt /** 14056e866f4SJed Brown @brief Error handler that prints to stderr and exits 14156e866f4SJed Brown 14256e866f4SJed Brown Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 14356e866f4SJed Brown 14456e866f4SJed Brown In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 14556e866f4SJed Brown handlers (e.g., as used by gcov) are run. 14656e866f4SJed Brown 14756e866f4SJed Brown @ref Developer 14856e866f4SJed Brown **/ 14956e866f4SJed Brown int CeedErrorExit(Ceed ceed, const char *filename, int lineno, 15056e866f4SJed Brown const char *func, int ecode, 15156e866f4SJed Brown const char *format, va_list args) { 15256e866f4SJed Brown fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 15356e866f4SJed Brown vfprintf(stderr, format, args); 15456e866f4SJed Brown fprintf(stderr, "\n"); 15556e866f4SJed Brown exit(ecode); 15656e866f4SJed Brown return ecode; 15756e866f4SJed Brown } 15856e866f4SJed Brown 15956e866f4SJed Brown /** 160dfdf5a53Sjeremylt @brief Set error handler 161b11c1e72Sjeremylt 162b11c1e72Sjeremylt A default error handler is set in CeedInit(). Use this function to change 163b11c1e72Sjeremylt the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 164b11c1e72Sjeremylt error handler. 165dfdf5a53Sjeremylt 166dfdf5a53Sjeremylt @ref Developer 167b11c1e72Sjeremylt **/ 168d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed, 169d7b241e6Sjeremylt int (eh)(Ceed, const char *, int, const char *, 170d7b241e6Sjeremylt int, const char *, va_list)) { 171d7b241e6Sjeremylt ceed->Error = eh; 172d7b241e6Sjeremylt return 0; 173d7b241e6Sjeremylt } 174d7b241e6Sjeremylt 175d7b241e6Sjeremylt /** 176b11c1e72Sjeremylt @brief Register a Ceed backend 177d7b241e6Sjeremylt 178d7b241e6Sjeremylt @param prefix Prefix of resources for this backend to respond to. For 179d7b241e6Sjeremylt example, the reference backend responds to "/cpu/self". 180d7b241e6Sjeremylt @param init Initialization function called by CeedInit() when the backend 181d7b241e6Sjeremylt is selected to drive the requested resource. 182d7b241e6Sjeremylt @param priority Integer priority. Lower values are preferred in case the 183d7b241e6Sjeremylt resource requested by CeedInit() has non-unique best prefix 184d7b241e6Sjeremylt match. 185b11c1e72Sjeremylt 186b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 187dfdf5a53Sjeremylt 188dfdf5a53Sjeremylt @ref Advanced 189b11c1e72Sjeremylt **/ 190d7b241e6Sjeremylt int CeedRegister(const char *prefix, 191d7b241e6Sjeremylt int (*init)(const char *, Ceed), unsigned int priority) { 192d7b241e6Sjeremylt if (num_backends >= sizeof(backends) / sizeof(backends[0])) { 193d7b241e6Sjeremylt return CeedError(NULL, 1, "Too many backends"); 194d7b241e6Sjeremylt } 195d7b241e6Sjeremylt strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 196d7b241e6Sjeremylt backends[num_backends].init = init; 197d7b241e6Sjeremylt backends[num_backends].priority = priority; 198d7b241e6Sjeremylt num_backends++; 199d7b241e6Sjeremylt return 0; 200d7b241e6Sjeremylt } 201d7b241e6Sjeremylt 202b11c1e72Sjeremylt /** 203b11c1e72Sjeremylt @brief Allocate an array on the host; use CeedMalloc() 204b11c1e72Sjeremylt 205b11c1e72Sjeremylt Memory usage can be tracked by the library. This ensures sufficient 206b11c1e72Sjeremylt alignment for vectorization and should be used for large allocations. 207b11c1e72Sjeremylt 208b11c1e72Sjeremylt @param n Number of units to allocate 209b11c1e72Sjeremylt @param unit Size of each unit 210b11c1e72Sjeremylt @param p Address of pointer to hold the result. 211b11c1e72Sjeremylt 212b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 213b11c1e72Sjeremylt 214b11c1e72Sjeremylt @sa CeedFree() 215dfdf5a53Sjeremylt 216dfdf5a53Sjeremylt @ref Advanced 217b11c1e72Sjeremylt **/ 218d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) { 219d7b241e6Sjeremylt int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 220d7b241e6Sjeremylt if (ierr) 221d7b241e6Sjeremylt return CeedError(NULL, ierr, 222d7b241e6Sjeremylt "posix_memalign failed to allocate %zd members of size %zd\n", n, unit); 223d7b241e6Sjeremylt return 0; 224d7b241e6Sjeremylt } 225d7b241e6Sjeremylt 226b11c1e72Sjeremylt /** 227b11c1e72Sjeremylt @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 228b11c1e72Sjeremylt 229b11c1e72Sjeremylt Memory usage can be tracked by the library. 230b11c1e72Sjeremylt 231b11c1e72Sjeremylt @param n Number of units to allocate 232b11c1e72Sjeremylt @param unit Size of each unit 233b11c1e72Sjeremylt @param p Address of pointer to hold the result. 234b11c1e72Sjeremylt 235b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 236b11c1e72Sjeremylt 237b11c1e72Sjeremylt @sa CeedFree() 238dfdf5a53Sjeremylt 239dfdf5a53Sjeremylt @ref Advanced 240b11c1e72Sjeremylt **/ 241d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) { 242d7b241e6Sjeremylt *(void **)p = calloc(n, unit); 243d7b241e6Sjeremylt if (n && unit && !*(void **)p) 244d7b241e6Sjeremylt return CeedError(NULL, 1, "calloc failed to allocate %zd members of size %zd\n", 245d7b241e6Sjeremylt n, unit); 246d7b241e6Sjeremylt return 0; 247d7b241e6Sjeremylt } 248d7b241e6Sjeremylt 249b11c1e72Sjeremylt /** 250b11c1e72Sjeremylt @brief Reallocate an array on the host; use CeedRealloc() 251b11c1e72Sjeremylt 252b11c1e72Sjeremylt Memory usage can be tracked by the library. 253b11c1e72Sjeremylt 254b11c1e72Sjeremylt @param n Number of units to allocate 255b11c1e72Sjeremylt @param unit Size of each unit 256b11c1e72Sjeremylt @param p Address of pointer to hold the result. 257b11c1e72Sjeremylt 258b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 259b11c1e72Sjeremylt 260b11c1e72Sjeremylt @sa CeedFree() 261dfdf5a53Sjeremylt 262dfdf5a53Sjeremylt @ref Advanced 263b11c1e72Sjeremylt **/ 264d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) { 265d7b241e6Sjeremylt *(void **)p = realloc(*(void **)p, n*unit); 266d7b241e6Sjeremylt if (n && unit && !*(void **)p) 267d7b241e6Sjeremylt return CeedError(NULL, 1, 268d7b241e6Sjeremylt "realloc failed to allocate %zd members of size %zd\n", 269d7b241e6Sjeremylt n, unit); 270d7b241e6Sjeremylt return 0; 271d7b241e6Sjeremylt } 272d7b241e6Sjeremylt 273d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc() 274d7b241e6Sjeremylt /// 275d7b241e6Sjeremylt /// @param p address of pointer to memory. This argument is of type void* to 276d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed) 277d7b241e6Sjeremylt /// rather than the pointer. 278d7b241e6Sjeremylt int CeedFree(void *p) { 279d7b241e6Sjeremylt free(*(void **)p); 280d7b241e6Sjeremylt *(void **)p = NULL; 281d7b241e6Sjeremylt return 0; 282d7b241e6Sjeremylt } 283d7b241e6Sjeremylt 284d7b241e6Sjeremylt /** 285b11c1e72Sjeremylt @brief Wait for a CeedRequest to complete. 286d7b241e6Sjeremylt 287d7b241e6Sjeremylt Calling CeedRequestWait on a NULL request is a no-op. 288d7b241e6Sjeremylt 289d7b241e6Sjeremylt @param req Address of CeedRequest to wait for; zeroed on completion. 290b11c1e72Sjeremylt 291b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 292dfdf5a53Sjeremylt 293dfdf5a53Sjeremylt @ref Advanced 294b11c1e72Sjeremylt **/ 295d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) { 296d7b241e6Sjeremylt if (!*req) return 0; 297d7b241e6Sjeremylt return CeedError(NULL, 2, "CeedRequestWait not implemented"); 298d7b241e6Sjeremylt } 299d7b241e6Sjeremylt 300b11c1e72Sjeremylt /** 301b11c1e72Sjeremylt @brief Initialize a \ref Ceed to use the specified resource. 302b11c1e72Sjeremylt 303b11c1e72Sjeremylt @param resource Resource to use, e.g., "/cpu/self" 304b11c1e72Sjeremylt @param ceed The library context 305b11c1e72Sjeremylt @sa CeedRegister() CeedDestroy() 306b11c1e72Sjeremylt 307b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 308dfdf5a53Sjeremylt 309dfdf5a53Sjeremylt @ref Basic 310b11c1e72Sjeremylt **/ 311d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) { 312d7b241e6Sjeremylt int ierr; 313aedaa0e5Sjeremylt size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 314d7b241e6Sjeremylt 315fe2413ffSjeremylt // Find matching backend 316d7b241e6Sjeremylt if (!resource) return CeedError(NULL, 1, "No resource provided"); 317d7b241e6Sjeremylt for (size_t i=0; i<num_backends; i++) { 318d7b241e6Sjeremylt size_t n; 319d7b241e6Sjeremylt const char *prefix = backends[i].prefix; 320d7b241e6Sjeremylt for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 321d7b241e6Sjeremylt priority = backends[i].priority; 322d7b241e6Sjeremylt if (n > matchlen || (n == matchlen && matchpriority > priority)) { 323d7b241e6Sjeremylt matchlen = n; 324d7b241e6Sjeremylt matchpriority = priority; 325d7b241e6Sjeremylt matchidx = i; 326d7b241e6Sjeremylt } 327d7b241e6Sjeremylt } 328d7b241e6Sjeremylt if (!matchlen) return CeedError(NULL, 1, "No suitable backend"); 329fe2413ffSjeremylt 330fe2413ffSjeremylt // Setup Ceed 331d7b241e6Sjeremylt ierr = CeedCalloc(1,ceed); CeedChk(ierr); 332bc81ce41Sjeremylt const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 333bc81ce41Sjeremylt if (!ceed_error_handler) ceed_error_handler = "abort"; 334bc81ce41Sjeremylt if (!strcmp(ceed_error_handler, "exit")) 33556e866f4SJed Brown (*ceed)->Error = CeedErrorExit; 33656e866f4SJed Brown else 337d7b241e6Sjeremylt (*ceed)->Error = CeedErrorAbort; 338d7b241e6Sjeremylt (*ceed)->refcount = 1; 339d7b241e6Sjeremylt (*ceed)->data = NULL; 340fe2413ffSjeremylt 341fe2413ffSjeremylt // Set lookup table 34228d161eeSjeremylt foffset foffsets[CEED_NUM_BACKEND_FUNCTIONS] = { 3432c8abac2Sjeremylt {"CeedError", ceedoffsetof(Ceed, Error)}, 344fe2413ffSjeremylt {"CeedDestroy", ceedoffsetof(Ceed, Destroy)}, 3452c8abac2Sjeremylt {"CeedVecCreate", ceedoffsetof(Ceed, VecCreate)}, 3462c8abac2Sjeremylt {"CeedElemRestrictionCreate", ceedoffsetof(Ceed, ElemRestrictionCreate)}, 3479f0427d9SYohann { 3489f0427d9SYohann "CeedElemRestrictionCreateBlocked", 3491dfeef1dSjeremylt ceedoffsetof(Ceed, ElemRestrictionCreateBlocked) 3501dfeef1dSjeremylt }, 3512c8abac2Sjeremylt {"CeedBasisCreateTensorH1", ceedoffsetof(Ceed, BasisCreateTensorH1)}, 3522c8abac2Sjeremylt {"CeedBasisCreateH1", ceedoffsetof(Ceed, BasisCreateH1)}, 3532f86a920SJeremy L Thompson {"CeedTensorContractCreate", ceedoffsetof(Ceed, TensorContractCreate)}, 3542c8abac2Sjeremylt {"CeedQFunctionCreate", ceedoffsetof(Ceed, QFunctionCreate)}, 3552c8abac2Sjeremylt {"CeedOperatorCreate", ceedoffsetof(Ceed, OperatorCreate)}, 35652d6035fSJeremy L Thompson {"CeedCompositeOperatorCreate",ceedoffsetof(Ceed, CompositeOperatorCreate)}, 3572c8abac2Sjeremylt {"VectorSetArray", ceedoffsetof(CeedVector, SetArray)}, 3582c8abac2Sjeremylt {"VectorSetValue", ceedoffsetof(CeedVector, SetValue)}, 3592c8abac2Sjeremylt {"VectorGetArray", ceedoffsetof(CeedVector, GetArray)}, 3602c8abac2Sjeremylt {"VectorGetArrayRead", ceedoffsetof(CeedVector, GetArrayRead)}, 3612c8abac2Sjeremylt {"VectorRestoreArray", ceedoffsetof(CeedVector, RestoreArray)}, 3622c8abac2Sjeremylt {"VectorRestoreArrayRead", ceedoffsetof(CeedVector, RestoreArrayRead)}, 363fe2413ffSjeremylt {"VectorDestroy", ceedoffsetof(CeedVector, Destroy)}, 364fe2413ffSjeremylt {"ElemRestrictionApply", ceedoffsetof(CeedElemRestriction, Apply)}, 365fe2413ffSjeremylt {"ElemRestrictionDestroy", ceedoffsetof(CeedElemRestriction, Destroy)}, 366fe2413ffSjeremylt {"BasisApply", ceedoffsetof(CeedBasis, Apply)}, 367fe2413ffSjeremylt {"BasisDestroy", ceedoffsetof(CeedBasis, Destroy)}, 3682f86a920SJeremy L Thompson {"TensorContractApply", ceedoffsetof(CeedTensorContract, Apply)}, 3692f86a920SJeremy L Thompson {"TensorContractDestroy", ceedoffsetof(CeedTensorContract, Destroy)}, 370fe2413ffSjeremylt {"QFunctionApply", ceedoffsetof(CeedQFunction, Apply)}, 371fe2413ffSjeremylt {"QFunctionDestroy", ceedoffsetof(CeedQFunction, Destroy)}, 372fe2413ffSjeremylt {"OperatorApply", ceedoffsetof(CeedOperator, Apply)}, 3732c8abac2Sjeremylt {"OperatorApplyJacobian", ceedoffsetof(CeedOperator, ApplyJacobian)}, 3741dfeef1dSjeremylt {"OperatorDestroy", ceedoffsetof(CeedOperator, Destroy)} 3751dfeef1dSjeremylt }; 376fe2413ffSjeremylt 37728d161eeSjeremylt memcpy((*ceed)->foffsets, foffsets, 37828d161eeSjeremylt CEED_NUM_BACKEND_FUNCTIONS*sizeof(foffset)); 379fe2413ffSjeremylt 380fe2413ffSjeremylt // Backend specific setup 381d7b241e6Sjeremylt ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 382fe2413ffSjeremylt 383d7b241e6Sjeremylt return 0; 384d7b241e6Sjeremylt } 385d7b241e6Sjeremylt 386d7b241e6Sjeremylt /** 3872f86a920SJeremy L Thompson @brief Retrieve a parent CEED 3882f86a920SJeremy L Thompson 3892f86a920SJeremy L Thompson @param ceed Ceed to retrieve parent of 3902f86a920SJeremy L Thompson @param[out] parent Address to save the parent to 3912f86a920SJeremy L Thompson 3922f86a920SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 3932f86a920SJeremy L Thompson 3942f86a920SJeremy L Thompson @ref Developer 3952f86a920SJeremy L Thompson **/ 3962f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) { 3972f86a920SJeremy L Thompson int ierr; 3982f86a920SJeremy L Thompson if (ceed->parent) { 3992f86a920SJeremy L Thompson ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 4002f86a920SJeremy L Thompson return 0; 4012f86a920SJeremy L Thompson } 4022f86a920SJeremy L Thompson *parent = ceed; 4032f86a920SJeremy L Thompson return 0; 4042f86a920SJeremy L Thompson } 4052f86a920SJeremy L Thompson 4062f86a920SJeremy L Thompson /** 4075fe0d4faSjeremylt @brief Retrieve a delegate CEED 4085fe0d4faSjeremylt 4095fe0d4faSjeremylt @param ceed Ceed to retrieve delegate of 4105fe0d4faSjeremylt @param[out] delegate Address to save the delegate to 4115fe0d4faSjeremylt 4125fe0d4faSjeremylt @return An error code: 0 - success, otherwise - failure 4135fe0d4faSjeremylt 41423617272Sjeremylt @ref Developer 4155fe0d4faSjeremylt **/ 4165fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 4174ce2993fSjeremylt *delegate = ceed->delegate; 4184ce2993fSjeremylt return 0; 4194ce2993fSjeremylt } 4204ce2993fSjeremylt 4214ce2993fSjeremylt /** 4224ce2993fSjeremylt @brief Set a delegate CEED 4234ce2993fSjeremylt 4244ce2993fSjeremylt @param ceed Ceed to set delegate of 4254ce2993fSjeremylt @param[out] delegate Address to set the delegate to 4264ce2993fSjeremylt 4274ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 4284ce2993fSjeremylt 42923617272Sjeremylt @ref Advanced 4304ce2993fSjeremylt **/ 4314ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) { 4324ce2993fSjeremylt ceed->delegate = *delegate; 4332f86a920SJeremy L Thompson (*delegate)->parent = ceed; 4344ce2993fSjeremylt return 0; 4354ce2993fSjeremylt } 4364ce2993fSjeremylt 4374ce2993fSjeremylt /** 438fe2413ffSjeremylt @brief Set a backend function 439fe2413ffSjeremylt 440fe2413ffSjeremylt @param ceed Ceed for error handling 441fe2413ffSjeremylt @param type Type of Ceed object to set function for 442fe2413ffSjeremylt @param[out] object Ceed object to set function for 443fe2413ffSjeremylt @param fname Name of function to set 444fe2413ffSjeremylt @param f Function to set 445fe2413ffSjeremylt 446fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 447fe2413ffSjeremylt 448fe2413ffSjeremylt @ref Advanced 449fe2413ffSjeremylt **/ 450fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed, 451fe2413ffSjeremylt const char *type, void *object, 452fe2413ffSjeremylt const char *fname, int (*f)()) { 453*409ab9adSjeremylt char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 454fe2413ffSjeremylt 455fe2413ffSjeremylt // Build lookup name 456*409ab9adSjeremylt strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 457*409ab9adSjeremylt strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 458fe2413ffSjeremylt 459fe2413ffSjeremylt // Find and use offset 46028d161eeSjeremylt for (CeedInt i = 0; i < CEED_NUM_BACKEND_FUNCTIONS; i++) { 461fe2413ffSjeremylt if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 462fe2413ffSjeremylt size_t offset = ceed->foffsets[i].offset; 463fe2413ffSjeremylt size_t *fpointer; 464fe2413ffSjeremylt fpointer = (size_t *)(object + offset); 465fe2413ffSjeremylt *fpointer = (size_t) f; 466fe2413ffSjeremylt return 0; 467fe2413ffSjeremylt } 468fe2413ffSjeremylt } 469fe2413ffSjeremylt 4701dfeef1dSjeremylt return CeedError(ceed, 1, 4711dfeef1dSjeremylt "Requested function '%s' was not found for CEED object '%s'", fname, type); 472fe2413ffSjeremylt } 473fe2413ffSjeremylt 474fe2413ffSjeremylt /** 4754ce2993fSjeremylt @brief Retrieve backend data for a CEED 4764ce2993fSjeremylt 477fe2413ffSjeremylt @param ceed Ceed to retrieve data of 4784ce2993fSjeremylt @param[out] data Address to save data to 4794ce2993fSjeremylt 4804ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 4814ce2993fSjeremylt 48223617272Sjeremylt @ref Advanced 4834ce2993fSjeremylt **/ 4844ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) { 4854ce2993fSjeremylt *data = ceed->data; 4865fe0d4faSjeremylt return 0; 4875fe0d4faSjeremylt } 4885fe0d4faSjeremylt 4895fe0d4faSjeremylt /** 490fe2413ffSjeremylt @brief Set backend data for a CEED 491fe2413ffSjeremylt 492fe2413ffSjeremylt @param ceed Ceed to set data of 493fe2413ffSjeremylt @param data Address of data to set 494fe2413ffSjeremylt 495fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 496fe2413ffSjeremylt 497fe2413ffSjeremylt @ref Advanced 498fe2413ffSjeremylt **/ 499fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) { 500fe2413ffSjeremylt ceed->data = *data; 501fe2413ffSjeremylt return 0; 502fe2413ffSjeremylt } 503fe2413ffSjeremylt 504fe2413ffSjeremylt /** 505b11c1e72Sjeremylt @brief Destroy a Ceed context 506d7b241e6Sjeremylt 507d7b241e6Sjeremylt @param ceed Address of Ceed context to destroy 508b11c1e72Sjeremylt 509b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 510dfdf5a53Sjeremylt 511dfdf5a53Sjeremylt @ref Basic 512b11c1e72Sjeremylt **/ 513d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) { 514d7b241e6Sjeremylt int ierr; 515d7b241e6Sjeremylt 516d7b241e6Sjeremylt if (!*ceed || --(*ceed)->refcount > 0) return 0; 5175fe0d4faSjeremylt if ((*ceed)->delegate) { 5185fe0d4faSjeremylt ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 5195fe0d4faSjeremylt } 520d7b241e6Sjeremylt if ((*ceed)->Destroy) { 521d7b241e6Sjeremylt ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 522d7b241e6Sjeremylt } 523d7b241e6Sjeremylt ierr = CeedFree(ceed); CeedChk(ierr); 524d7b241e6Sjeremylt return 0; 525d7b241e6Sjeremylt } 526d7b241e6Sjeremylt 527d7b241e6Sjeremylt /// @} 528