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)}, 344c907536fSjeremylt {"CeedGetPreferredMemType", ceedoffsetof(Ceed, GetPreferredMemType)}, 345fe2413ffSjeremylt {"CeedDestroy", ceedoffsetof(Ceed, Destroy)}, 3462c8abac2Sjeremylt {"CeedVecCreate", ceedoffsetof(Ceed, VecCreate)}, 3472c8abac2Sjeremylt {"CeedElemRestrictionCreate", ceedoffsetof(Ceed, ElemRestrictionCreate)}, 3489f0427d9SYohann { 3499f0427d9SYohann "CeedElemRestrictionCreateBlocked", 3501dfeef1dSjeremylt ceedoffsetof(Ceed, ElemRestrictionCreateBlocked) 3511dfeef1dSjeremylt }, 3522c8abac2Sjeremylt {"CeedBasisCreateTensorH1", ceedoffsetof(Ceed, BasisCreateTensorH1)}, 3532c8abac2Sjeremylt {"CeedBasisCreateH1", ceedoffsetof(Ceed, BasisCreateH1)}, 3542f86a920SJeremy L Thompson {"CeedTensorContractCreate", ceedoffsetof(Ceed, TensorContractCreate)}, 3552c8abac2Sjeremylt {"CeedQFunctionCreate", ceedoffsetof(Ceed, QFunctionCreate)}, 3562c8abac2Sjeremylt {"CeedOperatorCreate", ceedoffsetof(Ceed, OperatorCreate)}, 35752d6035fSJeremy L Thompson {"CeedCompositeOperatorCreate",ceedoffsetof(Ceed, CompositeOperatorCreate)}, 3582c8abac2Sjeremylt {"VectorSetArray", ceedoffsetof(CeedVector, SetArray)}, 3592c8abac2Sjeremylt {"VectorSetValue", ceedoffsetof(CeedVector, SetValue)}, 3602c8abac2Sjeremylt {"VectorGetArray", ceedoffsetof(CeedVector, GetArray)}, 3612c8abac2Sjeremylt {"VectorGetArrayRead", ceedoffsetof(CeedVector, GetArrayRead)}, 3622c8abac2Sjeremylt {"VectorRestoreArray", ceedoffsetof(CeedVector, RestoreArray)}, 3632c8abac2Sjeremylt {"VectorRestoreArrayRead", ceedoffsetof(CeedVector, RestoreArrayRead)}, 364fe2413ffSjeremylt {"VectorDestroy", ceedoffsetof(CeedVector, Destroy)}, 365fe2413ffSjeremylt {"ElemRestrictionApply", ceedoffsetof(CeedElemRestriction, Apply)}, 366be9261b7Sjeremylt {"ElemRestrictionApplyBlock", ceedoffsetof(CeedElemRestriction, ApplyBlock)}, 367fe2413ffSjeremylt {"ElemRestrictionDestroy", ceedoffsetof(CeedElemRestriction, Destroy)}, 368fe2413ffSjeremylt {"BasisApply", ceedoffsetof(CeedBasis, Apply)}, 369fe2413ffSjeremylt {"BasisDestroy", ceedoffsetof(CeedBasis, Destroy)}, 3702f86a920SJeremy L Thompson {"TensorContractApply", ceedoffsetof(CeedTensorContract, Apply)}, 3712f86a920SJeremy L Thompson {"TensorContractDestroy", ceedoffsetof(CeedTensorContract, Destroy)}, 372fe2413ffSjeremylt {"QFunctionApply", ceedoffsetof(CeedQFunction, Apply)}, 373fe2413ffSjeremylt {"QFunctionDestroy", ceedoffsetof(CeedQFunction, Destroy)}, 374fe2413ffSjeremylt {"OperatorApply", ceedoffsetof(CeedOperator, Apply)}, 3752c8abac2Sjeremylt {"OperatorApplyJacobian", ceedoffsetof(CeedOperator, ApplyJacobian)}, 3761dfeef1dSjeremylt {"OperatorDestroy", ceedoffsetof(CeedOperator, Destroy)} 3771dfeef1dSjeremylt }; 378fe2413ffSjeremylt 37928d161eeSjeremylt memcpy((*ceed)->foffsets, foffsets, 38028d161eeSjeremylt CEED_NUM_BACKEND_FUNCTIONS*sizeof(foffset)); 381fe2413ffSjeremylt 382fe2413ffSjeremylt // Backend specific setup 383d7b241e6Sjeremylt ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 384fe2413ffSjeremylt 385d7b241e6Sjeremylt return 0; 386d7b241e6Sjeremylt } 387d7b241e6Sjeremylt 388d7b241e6Sjeremylt /** 3892f86a920SJeremy L Thompson @brief Retrieve a parent CEED 3902f86a920SJeremy L Thompson 3912f86a920SJeremy L Thompson @param ceed Ceed to retrieve parent of 3922f86a920SJeremy L Thompson @param[out] parent Address to save the parent to 3932f86a920SJeremy L Thompson 3942f86a920SJeremy L Thompson @return An error code: 0 - success, otherwise - failure 3952f86a920SJeremy L Thompson 3962f86a920SJeremy L Thompson @ref Developer 3972f86a920SJeremy L Thompson **/ 3982f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) { 3992f86a920SJeremy L Thompson int ierr; 4002f86a920SJeremy L Thompson if (ceed->parent) { 4012f86a920SJeremy L Thompson ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 4022f86a920SJeremy L Thompson return 0; 4032f86a920SJeremy L Thompson } 4042f86a920SJeremy L Thompson *parent = ceed; 4052f86a920SJeremy L Thompson return 0; 4062f86a920SJeremy L Thompson } 4072f86a920SJeremy L Thompson 4082f86a920SJeremy L Thompson /** 4095fe0d4faSjeremylt @brief Retrieve a delegate CEED 4105fe0d4faSjeremylt 4115fe0d4faSjeremylt @param ceed Ceed to retrieve delegate of 4125fe0d4faSjeremylt @param[out] delegate Address to save the delegate to 4135fe0d4faSjeremylt 4145fe0d4faSjeremylt @return An error code: 0 - success, otherwise - failure 4155fe0d4faSjeremylt 41623617272Sjeremylt @ref Developer 4175fe0d4faSjeremylt **/ 4185fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 4194ce2993fSjeremylt *delegate = ceed->delegate; 4204ce2993fSjeremylt return 0; 4214ce2993fSjeremylt } 4224ce2993fSjeremylt 4234ce2993fSjeremylt /** 4244ce2993fSjeremylt @brief Set a delegate CEED 4254ce2993fSjeremylt 4264ce2993fSjeremylt @param ceed Ceed to set delegate of 4274ce2993fSjeremylt @param[out] delegate Address to set the delegate to 4284ce2993fSjeremylt 4294ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 4304ce2993fSjeremylt 43123617272Sjeremylt @ref Advanced 4324ce2993fSjeremylt **/ 4334ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) { 4344ce2993fSjeremylt ceed->delegate = *delegate; 4352f86a920SJeremy L Thompson (*delegate)->parent = ceed; 4364ce2993fSjeremylt return 0; 4374ce2993fSjeremylt } 4384ce2993fSjeremylt 4394ce2993fSjeremylt /** 440c907536fSjeremylt @brief Return Ceed perferred memory type 441c907536fSjeremylt 442c907536fSjeremylt @param ceed Ceed to get preferred memory type of 443c907536fSjeremylt @param[out] delegate Address to save preferred memory type to 444c907536fSjeremylt 445c907536fSjeremylt @return An error code: 0 - success, otherwise - failure 446c907536fSjeremylt 447c907536fSjeremylt @ref Basic 448c907536fSjeremylt **/ 449c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 450c907536fSjeremylt int ierr; 451c907536fSjeremylt if (ceed->GetPreferredMemType) { 452c907536fSjeremylt ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 453c907536fSjeremylt } else { 454c907536fSjeremylt *type = CEED_MEM_HOST; 455c907536fSjeremylt } 456c907536fSjeremylt 457c907536fSjeremylt return 0; 458c907536fSjeremylt } 459c907536fSjeremylt 460c907536fSjeremylt /** 461fe2413ffSjeremylt @brief Set a backend function 462fe2413ffSjeremylt 463fe2413ffSjeremylt @param ceed Ceed for error handling 464fe2413ffSjeremylt @param type Type of Ceed object to set function for 465fe2413ffSjeremylt @param[out] object Ceed object to set function for 466fe2413ffSjeremylt @param fname Name of function to set 467fe2413ffSjeremylt @param f Function to set 468fe2413ffSjeremylt 469fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 470fe2413ffSjeremylt 471fe2413ffSjeremylt @ref Advanced 472fe2413ffSjeremylt **/ 473fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed, 474fe2413ffSjeremylt const char *type, void *object, 475fe2413ffSjeremylt const char *fname, int (*f)()) { 476409ab9adSjeremylt char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 477fe2413ffSjeremylt 478fe2413ffSjeremylt // Build lookup name 479409ab9adSjeremylt strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 480409ab9adSjeremylt strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 481fe2413ffSjeremylt 482fe2413ffSjeremylt // Find and use offset 48328d161eeSjeremylt for (CeedInt i = 0; i < CEED_NUM_BACKEND_FUNCTIONS; i++) { 484fe2413ffSjeremylt if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 485fe2413ffSjeremylt size_t offset = ceed->foffsets[i].offset; 486*a7a2e802Sjeremylt int (**fpointer)(void) = (int (**)(void))((char*)object + offset); 487*a7a2e802Sjeremylt *fpointer = f; 488fe2413ffSjeremylt return 0; 489fe2413ffSjeremylt } 490fe2413ffSjeremylt } 491fe2413ffSjeremylt 4921dfeef1dSjeremylt return CeedError(ceed, 1, 4931dfeef1dSjeremylt "Requested function '%s' was not found for CEED object '%s'", fname, type); 494fe2413ffSjeremylt } 495fe2413ffSjeremylt 496fe2413ffSjeremylt /** 4974ce2993fSjeremylt @brief Retrieve backend data for a CEED 4984ce2993fSjeremylt 499fe2413ffSjeremylt @param ceed Ceed to retrieve data of 5004ce2993fSjeremylt @param[out] data Address to save data to 5014ce2993fSjeremylt 5024ce2993fSjeremylt @return An error code: 0 - success, otherwise - failure 5034ce2993fSjeremylt 50423617272Sjeremylt @ref Advanced 5054ce2993fSjeremylt **/ 5064ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) { 5074ce2993fSjeremylt *data = ceed->data; 5085fe0d4faSjeremylt return 0; 5095fe0d4faSjeremylt } 5105fe0d4faSjeremylt 5115fe0d4faSjeremylt /** 512fe2413ffSjeremylt @brief Set backend data for a CEED 513fe2413ffSjeremylt 514fe2413ffSjeremylt @param ceed Ceed to set data of 515fe2413ffSjeremylt @param data Address of data to set 516fe2413ffSjeremylt 517fe2413ffSjeremylt @return An error code: 0 - success, otherwise - failure 518fe2413ffSjeremylt 519fe2413ffSjeremylt @ref Advanced 520fe2413ffSjeremylt **/ 521fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) { 522fe2413ffSjeremylt ceed->data = *data; 523fe2413ffSjeremylt return 0; 524fe2413ffSjeremylt } 525fe2413ffSjeremylt 526fe2413ffSjeremylt /** 527b11c1e72Sjeremylt @brief Destroy a Ceed context 528d7b241e6Sjeremylt 529d7b241e6Sjeremylt @param ceed Address of Ceed context to destroy 530b11c1e72Sjeremylt 531b11c1e72Sjeremylt @return An error code: 0 - success, otherwise - failure 532dfdf5a53Sjeremylt 533dfdf5a53Sjeremylt @ref Basic 534b11c1e72Sjeremylt **/ 535d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) { 536d7b241e6Sjeremylt int ierr; 537d7b241e6Sjeremylt 538d7b241e6Sjeremylt if (!*ceed || --(*ceed)->refcount > 0) return 0; 5395fe0d4faSjeremylt if ((*ceed)->delegate) { 5405fe0d4faSjeremylt ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 5415fe0d4faSjeremylt } 542d7b241e6Sjeremylt if ((*ceed)->Destroy) { 543d7b241e6Sjeremylt ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 544d7b241e6Sjeremylt } 545d7b241e6Sjeremylt ierr = CeedFree(ceed); CeedChk(ierr); 546d7b241e6Sjeremylt return 0; 547d7b241e6Sjeremylt } 548d7b241e6Sjeremylt 549d7b241e6Sjeremylt /// @} 550