xref: /libCEED/interface/ceed.c (revision 2f86a9204e4fbd31e43e0982a43b4a40f1fd11a7)
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)},
353*2f86a920SJeremy 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)},
368*2f86a920SJeremy L Thompson     {"TensorContractApply",        ceedoffsetof(CeedTensorContract, Apply)},
369*2f86a920SJeremy 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 /**
387*2f86a920SJeremy L Thompson   @brief Retrieve a parent CEED
388*2f86a920SJeremy L Thompson 
389*2f86a920SJeremy L Thompson   @param ceed           Ceed to retrieve parent of
390*2f86a920SJeremy L Thompson   @param[out] parent    Address to save the parent to
391*2f86a920SJeremy L Thompson 
392*2f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
393*2f86a920SJeremy L Thompson 
394*2f86a920SJeremy L Thompson   @ref Developer
395*2f86a920SJeremy L Thompson **/
396*2f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
397*2f86a920SJeremy L Thompson   int ierr;
398*2f86a920SJeremy L Thompson   if (ceed->parent) {
399*2f86a920SJeremy L Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
400*2f86a920SJeremy L Thompson     return 0;
401*2f86a920SJeremy L Thompson   }
402*2f86a920SJeremy L Thompson   *parent = ceed;
403*2f86a920SJeremy L Thompson   return 0;
404*2f86a920SJeremy L Thompson }
405*2f86a920SJeremy L Thompson 
406*2f86a920SJeremy 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;
433*2f86a920SJeremy 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)()) {
453fe2413ffSjeremylt   char lookupname[100];
454fe2413ffSjeremylt   strcpy(lookupname, "");
455fe2413ffSjeremylt 
456fe2413ffSjeremylt   // Build lookup name
457fe2413ffSjeremylt   strcat(strcat(lookupname, type), fname);
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