xref: /libCEED/interface/ceed.c (revision aedaa0e5fd3a3e03ad33ad8a6308ac527f4f900e)
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>
20*aedaa0e5Sjeremylt #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;
313*aedaa0e5Sjeremylt   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)},
3471dfeef1dSjeremylt     {
3481dfeef1dSjeremylt       "CeedElemRestrictionCreateBlocked",
3491dfeef1dSjeremylt       ceedoffsetof(Ceed, ElemRestrictionCreateBlocked)
3501dfeef1dSjeremylt     },
3512c8abac2Sjeremylt     {"CeedBasisCreateTensorH1",    ceedoffsetof(Ceed, BasisCreateTensorH1)},
3522c8abac2Sjeremylt     {"CeedBasisCreateH1",          ceedoffsetof(Ceed, BasisCreateH1)},
3532c8abac2Sjeremylt     {"CeedQFunctionCreate",        ceedoffsetof(Ceed, QFunctionCreate)},
3542c8abac2Sjeremylt     {"CeedOperatorCreate",         ceedoffsetof(Ceed, OperatorCreate)},
3552c8abac2Sjeremylt     {"VectorSetArray",             ceedoffsetof(CeedVector, SetArray)},
3562c8abac2Sjeremylt     {"VectorSetValue",             ceedoffsetof(CeedVector, SetValue)},
3572c8abac2Sjeremylt     {"VectorGetArray",             ceedoffsetof(CeedVector, GetArray)},
3582c8abac2Sjeremylt     {"VectorGetArrayRead",         ceedoffsetof(CeedVector, GetArrayRead)},
3592c8abac2Sjeremylt     {"VectorRestoreArray",         ceedoffsetof(CeedVector, RestoreArray)},
3602c8abac2Sjeremylt     {"VectorRestoreArrayRead",     ceedoffsetof(CeedVector, RestoreArrayRead)},
361fe2413ffSjeremylt     {"VectorDestroy",              ceedoffsetof(CeedVector, Destroy)},
362fe2413ffSjeremylt     {"ElemRestrictionApply",       ceedoffsetof(CeedElemRestriction, Apply)},
363fe2413ffSjeremylt     {"ElemRestrictionDestroy",     ceedoffsetof(CeedElemRestriction, Destroy)},
364fe2413ffSjeremylt     {"BasisApply",                 ceedoffsetof(CeedBasis, Apply)},
365fe2413ffSjeremylt     {"BasisDestroy",               ceedoffsetof(CeedBasis, Destroy)},
366fe2413ffSjeremylt     {"QFunctionApply",             ceedoffsetof(CeedQFunction, Apply)},
367fe2413ffSjeremylt     {"QFunctionDestroy",           ceedoffsetof(CeedQFunction, Destroy)},
368fe2413ffSjeremylt     {"OperatorApply",              ceedoffsetof(CeedOperator, Apply)},
3692c8abac2Sjeremylt     {"OperatorApplyJacobian",      ceedoffsetof(CeedOperator, ApplyJacobian)},
3701dfeef1dSjeremylt     {"OperatorDestroy",            ceedoffsetof(CeedOperator, Destroy)}
3711dfeef1dSjeremylt   };
372fe2413ffSjeremylt 
37328d161eeSjeremylt   memcpy((*ceed)->foffsets, foffsets,
37428d161eeSjeremylt          CEED_NUM_BACKEND_FUNCTIONS*sizeof(foffset));
375fe2413ffSjeremylt 
376fe2413ffSjeremylt   // Backend specific setup
377d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
378fe2413ffSjeremylt 
379d7b241e6Sjeremylt   return 0;
380d7b241e6Sjeremylt }
381d7b241e6Sjeremylt 
382d7b241e6Sjeremylt /**
3835fe0d4faSjeremylt   @brief Retrieve a delegate CEED
3845fe0d4faSjeremylt 
3855fe0d4faSjeremylt   @param ceed           Ceed to retrieve delegate of
3865fe0d4faSjeremylt   @param[out] delegate  Address to save the delegate to
3875fe0d4faSjeremylt 
3885fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
3895fe0d4faSjeremylt 
39023617272Sjeremylt   @ref Developer
3915fe0d4faSjeremylt **/
3925fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
3934ce2993fSjeremylt   *delegate = ceed->delegate;
3944ce2993fSjeremylt   return 0;
3954ce2993fSjeremylt }
3964ce2993fSjeremylt 
3974ce2993fSjeremylt /**
3984ce2993fSjeremylt   @brief Set a delegate CEED
3994ce2993fSjeremylt 
4004ce2993fSjeremylt   @param ceed           Ceed to set delegate of
4014ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
4024ce2993fSjeremylt 
4034ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4044ce2993fSjeremylt 
40523617272Sjeremylt   @ref Advanced
4064ce2993fSjeremylt **/
4074ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) {
4084ce2993fSjeremylt   ceed->delegate = *delegate;
4094ce2993fSjeremylt   return 0;
4104ce2993fSjeremylt }
4114ce2993fSjeremylt 
4124ce2993fSjeremylt /**
413fe2413ffSjeremylt   @brief Set a backend function
414fe2413ffSjeremylt 
415fe2413ffSjeremylt   @param ceed           Ceed for error handling
416fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
417fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
418fe2413ffSjeremylt   @param fname          Name of function to set
419fe2413ffSjeremylt   @param f              Function to set
420fe2413ffSjeremylt 
421fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
422fe2413ffSjeremylt 
423fe2413ffSjeremylt   @ref Advanced
424fe2413ffSjeremylt **/
425fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed,
426fe2413ffSjeremylt                            const char *type, void *object,
427fe2413ffSjeremylt                            const char *fname, int (*f)()) {
428fe2413ffSjeremylt   char lookupname[100];
429fe2413ffSjeremylt   strcpy(lookupname, "");
430fe2413ffSjeremylt 
431fe2413ffSjeremylt   // Build lookup name
432fe2413ffSjeremylt   strcat(strcat(lookupname, type), fname);
433fe2413ffSjeremylt 
434fe2413ffSjeremylt   // Find and use offset
43528d161eeSjeremylt   for (CeedInt i = 0; i < CEED_NUM_BACKEND_FUNCTIONS; i++) {
436fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
437fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
438fe2413ffSjeremylt       size_t *fpointer;
439fe2413ffSjeremylt       fpointer = (size_t *)(object + offset);
440fe2413ffSjeremylt       *fpointer = (size_t) f;
441fe2413ffSjeremylt       return 0;
442fe2413ffSjeremylt     }
443fe2413ffSjeremylt   }
444fe2413ffSjeremylt 
4451dfeef1dSjeremylt   return CeedError(ceed, 1,
4461dfeef1dSjeremylt                    "Requested function '%s' was not found for CEED object '%s'", fname, type);
447fe2413ffSjeremylt }
448fe2413ffSjeremylt 
449fe2413ffSjeremylt /**
4504ce2993fSjeremylt   @brief Retrieve backend data for a CEED
4514ce2993fSjeremylt 
452fe2413ffSjeremylt   @param ceed           Ceed to retrieve data of
4534ce2993fSjeremylt   @param[out] data      Address to save data to
4544ce2993fSjeremylt 
4554ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4564ce2993fSjeremylt 
45723617272Sjeremylt   @ref Advanced
4584ce2993fSjeremylt **/
4594ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) {
4604ce2993fSjeremylt   *data = ceed->data;
4615fe0d4faSjeremylt   return 0;
4625fe0d4faSjeremylt }
4635fe0d4faSjeremylt 
4645fe0d4faSjeremylt /**
465fe2413ffSjeremylt   @brief Set backend data for a CEED
466fe2413ffSjeremylt 
467fe2413ffSjeremylt   @param ceed           Ceed to set data of
468fe2413ffSjeremylt   @param data           Address of data to set
469fe2413ffSjeremylt 
470fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
471fe2413ffSjeremylt 
472fe2413ffSjeremylt   @ref Advanced
473fe2413ffSjeremylt **/
474fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) {
475fe2413ffSjeremylt   ceed->data = *data;
476fe2413ffSjeremylt   return 0;
477fe2413ffSjeremylt }
478fe2413ffSjeremylt 
479fe2413ffSjeremylt /**
480b11c1e72Sjeremylt   @brief Destroy a Ceed context
481d7b241e6Sjeremylt 
482d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
483b11c1e72Sjeremylt 
484b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
485dfdf5a53Sjeremylt 
486dfdf5a53Sjeremylt   @ref Basic
487b11c1e72Sjeremylt **/
488d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
489d7b241e6Sjeremylt   int ierr;
490d7b241e6Sjeremylt 
491d7b241e6Sjeremylt   if (!*ceed || --(*ceed)->refcount > 0) return 0;
4925fe0d4faSjeremylt   if ((*ceed)->delegate) {
4935fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
4945fe0d4faSjeremylt   }
495d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
496d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
497d7b241e6Sjeremylt   }
498d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
499d7b241e6Sjeremylt   return 0;
500d7b241e6Sjeremylt }
501d7b241e6Sjeremylt 
502d7b241e6Sjeremylt /// @}
503