xref: /libCEED/interface/ceed.c (revision 6e79d475b20c142f61e16db0198d1cd6f01a0826)
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>
22*6e79d475Sjeremylt #include <stddef.h>
23d7b241e6Sjeremylt #include <stdio.h>
24d7b241e6Sjeremylt #include <stdlib.h>
25d7b241e6Sjeremylt #include <string.h>
26d7b241e6Sjeremylt 
27d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
28d7b241e6Sjeremylt static CeedRequest ceed_request_immediate;
29d7b241e6Sjeremylt static CeedRequest ceed_request_ordered;
30d7b241e6Sjeremylt 
31d7b241e6Sjeremylt static struct {
32d7b241e6Sjeremylt   char prefix[CEED_MAX_RESOURCE_LEN];
33d7b241e6Sjeremylt   int (*init)(const char *resource, Ceed f);
34d7b241e6Sjeremylt   unsigned int priority;
35d7b241e6Sjeremylt } backends[32];
36d7b241e6Sjeremylt static size_t num_backends;
37fe2413ffSjeremylt 
38*6e79d475Sjeremylt #define CEED_FTABLE_ENTRY(class, method) \
39*6e79d475Sjeremylt   {#class #method, offsetof(struct class ##_private, method)}
40d7b241e6Sjeremylt /// @endcond
41d7b241e6Sjeremylt 
42d7b241e6Sjeremylt /// @file
43d7b241e6Sjeremylt /// Implementation of core components of Ceed library
44d7b241e6Sjeremylt ///
45dfdf5a53Sjeremylt /// @addtogroup Ceed
46d7b241e6Sjeremylt /// @{
47d7b241e6Sjeremylt 
48dfdf5a53Sjeremylt /**
49dfdf5a53Sjeremylt   @brief Request immediate completion
50dfdf5a53Sjeremylt 
51dfdf5a53Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
52dfdf5a53Sjeremylt   interfaces when the caller wishes for the operation to be performed
53dfdf5a53Sjeremylt   immediately.  The code
54dfdf5a53Sjeremylt 
55dfdf5a53Sjeremylt   @code
56dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
57dfdf5a53Sjeremylt   @endcode
58dfdf5a53Sjeremylt 
59dfdf5a53Sjeremylt   is semantically equivalent to
60dfdf5a53Sjeremylt 
61dfdf5a53Sjeremylt   @code
62dfdf5a53Sjeremylt     CeedRequest request;
63dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
64dfdf5a53Sjeremylt     CeedRequestWait(&request);
65dfdf5a53Sjeremylt   @endcode
66dfdf5a53Sjeremylt 
67dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
68dfdf5a53Sjeremylt **/
69d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
70d7b241e6Sjeremylt 
71d7b241e6Sjeremylt /**
72b11c1e72Sjeremylt   @brief Request ordered completion
73d7b241e6Sjeremylt 
74d7b241e6Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
75d7b241e6Sjeremylt   interfaces when the caller wishes for the operation to be completed in the
76d7b241e6Sjeremylt   order that it is submitted to the device.  It is typically used in a construct
77d7b241e6Sjeremylt   such as
78d7b241e6Sjeremylt 
79d7b241e6Sjeremylt   @code
80d7b241e6Sjeremylt     CeedRequest request;
81d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
82d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
83d7b241e6Sjeremylt     // other optional work
84d7b241e6Sjeremylt     CeedWait(&request);
85d7b241e6Sjeremylt   @endcode
86d7b241e6Sjeremylt 
87d7b241e6Sjeremylt   which allows the sequence to complete asynchronously but does not start
88d7b241e6Sjeremylt   `op2` until `op1` has completed.
89d7b241e6Sjeremylt 
90d7b241e6Sjeremylt   @fixme The current implementation is overly strict, offering equivalent
91d7b241e6Sjeremylt   semantics to CEED_REQUEST_IMMEDIATE.
92d7b241e6Sjeremylt 
93d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
94d7b241e6Sjeremylt  */
95d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
96d7b241e6Sjeremylt 
97b11c1e72Sjeremylt /**
98b11c1e72Sjeremylt   @brief Error handling implementation; use \ref CeedError instead.
99dfdf5a53Sjeremylt 
100dfdf5a53Sjeremylt   @ref Developer
101b11c1e72Sjeremylt **/
102d7b241e6Sjeremylt int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func,
103d7b241e6Sjeremylt                   int ecode, const char *format, ...) {
104d7b241e6Sjeremylt   va_list args;
105d7b241e6Sjeremylt   va_start(args, format);
106d7b241e6Sjeremylt   if (ceed) return ceed->Error(ceed, filename, lineno, func, ecode, format, args);
107d7b241e6Sjeremylt   return CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args);
108d7b241e6Sjeremylt }
109d7b241e6Sjeremylt 
110b11c1e72Sjeremylt /**
111b11c1e72Sjeremylt   @brief Error handler that returns without printing anything.
112b11c1e72Sjeremylt 
113b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
114dfdf5a53Sjeremylt 
115dfdf5a53Sjeremylt   @ref Developer
116b11c1e72Sjeremylt **/
117d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno,
118d7b241e6Sjeremylt                     const char *func, int ecode, const char *format,
119d7b241e6Sjeremylt                     va_list args) {
120d7b241e6Sjeremylt   return ecode;
121d7b241e6Sjeremylt }
122d7b241e6Sjeremylt 
123b11c1e72Sjeremylt /**
124b11c1e72Sjeremylt   @brief Error handler that prints to stderr and aborts
125b11c1e72Sjeremylt 
126b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
127dfdf5a53Sjeremylt 
128dfdf5a53Sjeremylt   @ref Developer
129b11c1e72Sjeremylt **/
130d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno,
131d7b241e6Sjeremylt                    const char *func, int ecode,
132d7b241e6Sjeremylt                    const char *format, va_list args) {
133d7b241e6Sjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
134d7b241e6Sjeremylt   vfprintf(stderr, format, args);
135d7b241e6Sjeremylt   fprintf(stderr, "\n");
136d7b241e6Sjeremylt   abort();
137d7b241e6Sjeremylt   return ecode;
138d7b241e6Sjeremylt }
139d7b241e6Sjeremylt 
140b11c1e72Sjeremylt /**
14156e866f4SJed Brown   @brief Error handler that prints to stderr and exits
14256e866f4SJed Brown 
14356e866f4SJed Brown   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
14456e866f4SJed Brown 
14556e866f4SJed Brown   In contrast to CeedErrorAbort(), this exits without a signal, so atexit()
14656e866f4SJed Brown   handlers (e.g., as used by gcov) are run.
14756e866f4SJed Brown 
14856e866f4SJed Brown   @ref Developer
14956e866f4SJed Brown **/
15056e866f4SJed Brown int CeedErrorExit(Ceed ceed, const char *filename, int lineno,
15156e866f4SJed Brown                   const char *func, int ecode,
15256e866f4SJed Brown                   const char *format, va_list args) {
15356e866f4SJed Brown   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
15456e866f4SJed Brown   vfprintf(stderr, format, args);
15556e866f4SJed Brown   fprintf(stderr, "\n");
15656e866f4SJed Brown   exit(ecode);
15756e866f4SJed Brown   return ecode;
15856e866f4SJed Brown }
15956e866f4SJed Brown 
16056e866f4SJed Brown /**
161dfdf5a53Sjeremylt   @brief Set error handler
162b11c1e72Sjeremylt 
163b11c1e72Sjeremylt   A default error handler is set in CeedInit().  Use this function to change
164b11c1e72Sjeremylt   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
165b11c1e72Sjeremylt   error handler.
166dfdf5a53Sjeremylt 
167dfdf5a53Sjeremylt   @ref Developer
168b11c1e72Sjeremylt **/
169d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed,
170d7b241e6Sjeremylt                         int (eh)(Ceed, const char *, int, const char *,
171d7b241e6Sjeremylt                                  int, const char *, va_list)) {
172d7b241e6Sjeremylt   ceed->Error = eh;
173d7b241e6Sjeremylt   return 0;
174d7b241e6Sjeremylt }
175d7b241e6Sjeremylt 
176d7b241e6Sjeremylt /**
177b11c1e72Sjeremylt   @brief Register a Ceed backend
178d7b241e6Sjeremylt 
179d7b241e6Sjeremylt   @param prefix   Prefix of resources for this backend to respond to.  For
180d7b241e6Sjeremylt                     example, the reference backend responds to "/cpu/self".
181d7b241e6Sjeremylt   @param init     Initialization function called by CeedInit() when the backend
182d7b241e6Sjeremylt                     is selected to drive the requested resource.
183d7b241e6Sjeremylt   @param priority Integer priority.  Lower values are preferred in case the
184d7b241e6Sjeremylt                     resource requested by CeedInit() has non-unique best prefix
185d7b241e6Sjeremylt                     match.
186b11c1e72Sjeremylt 
187b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
188dfdf5a53Sjeremylt 
189dfdf5a53Sjeremylt   @ref Advanced
190b11c1e72Sjeremylt **/
191d7b241e6Sjeremylt int CeedRegister(const char *prefix,
192d7b241e6Sjeremylt                  int (*init)(const char *, Ceed), unsigned int priority) {
193d7b241e6Sjeremylt   if (num_backends >= sizeof(backends) / sizeof(backends[0])) {
194d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
195d7b241e6Sjeremylt   }
196d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
197d7b241e6Sjeremylt   backends[num_backends].init = init;
198d7b241e6Sjeremylt   backends[num_backends].priority = priority;
199d7b241e6Sjeremylt   num_backends++;
200d7b241e6Sjeremylt   return 0;
201d7b241e6Sjeremylt }
202d7b241e6Sjeremylt 
203b11c1e72Sjeremylt /**
204b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
205b11c1e72Sjeremylt 
206b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
207b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
208b11c1e72Sjeremylt 
209b11c1e72Sjeremylt   @param n Number of units to allocate
210b11c1e72Sjeremylt   @param unit Size of each unit
211b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
212b11c1e72Sjeremylt 
213b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
214b11c1e72Sjeremylt 
215b11c1e72Sjeremylt   @sa CeedFree()
216dfdf5a53Sjeremylt 
217dfdf5a53Sjeremylt   @ref Advanced
218b11c1e72Sjeremylt **/
219d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
220d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
221d7b241e6Sjeremylt   if (ierr)
222d7b241e6Sjeremylt     return CeedError(NULL, ierr,
223d7b241e6Sjeremylt                      "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
224d7b241e6Sjeremylt   return 0;
225d7b241e6Sjeremylt }
226d7b241e6Sjeremylt 
227b11c1e72Sjeremylt /**
228b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
229b11c1e72Sjeremylt 
230b11c1e72Sjeremylt   Memory usage can be tracked by the library.
231b11c1e72Sjeremylt 
232b11c1e72Sjeremylt   @param n Number of units to allocate
233b11c1e72Sjeremylt   @param unit Size of each unit
234b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
235b11c1e72Sjeremylt 
236b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
237b11c1e72Sjeremylt 
238b11c1e72Sjeremylt   @sa CeedFree()
239dfdf5a53Sjeremylt 
240dfdf5a53Sjeremylt   @ref Advanced
241b11c1e72Sjeremylt **/
242d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
243d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
244d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
245d7b241e6Sjeremylt     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size %zd\n",
246d7b241e6Sjeremylt                      n, unit);
247d7b241e6Sjeremylt   return 0;
248d7b241e6Sjeremylt }
249d7b241e6Sjeremylt 
250b11c1e72Sjeremylt /**
251b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
252b11c1e72Sjeremylt 
253b11c1e72Sjeremylt   Memory usage can be tracked by the library.
254b11c1e72Sjeremylt 
255b11c1e72Sjeremylt   @param n Number of units to allocate
256b11c1e72Sjeremylt   @param unit Size of each unit
257b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
258b11c1e72Sjeremylt 
259b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
260b11c1e72Sjeremylt 
261b11c1e72Sjeremylt   @sa CeedFree()
262dfdf5a53Sjeremylt 
263dfdf5a53Sjeremylt   @ref Advanced
264b11c1e72Sjeremylt **/
265d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
266d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
267d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
268d7b241e6Sjeremylt     return CeedError(NULL, 1,
269d7b241e6Sjeremylt                      "realloc failed to allocate %zd members of size %zd\n",
270d7b241e6Sjeremylt                      n, unit);
271d7b241e6Sjeremylt   return 0;
272d7b241e6Sjeremylt }
273d7b241e6Sjeremylt 
274d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc()
275d7b241e6Sjeremylt ///
276d7b241e6Sjeremylt /// @param p address of pointer to memory.  This argument is of type void* to
277d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed)
278d7b241e6Sjeremylt /// rather than the pointer.
279d7b241e6Sjeremylt int CeedFree(void *p) {
280d7b241e6Sjeremylt   free(*(void **)p);
281d7b241e6Sjeremylt   *(void **)p = NULL;
282d7b241e6Sjeremylt   return 0;
283d7b241e6Sjeremylt }
284d7b241e6Sjeremylt 
285d7b241e6Sjeremylt /**
286b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
287d7b241e6Sjeremylt 
288d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
289d7b241e6Sjeremylt 
290d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
291b11c1e72Sjeremylt 
292b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
293dfdf5a53Sjeremylt 
294dfdf5a53Sjeremylt   @ref Advanced
295b11c1e72Sjeremylt **/
296d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
297d7b241e6Sjeremylt   if (!*req) return 0;
298d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
299d7b241e6Sjeremylt }
300d7b241e6Sjeremylt 
301b11c1e72Sjeremylt /**
302b11c1e72Sjeremylt   @brief Initialize a \ref Ceed to use the specified resource.
303b11c1e72Sjeremylt 
304b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
305b11c1e72Sjeremylt   @param ceed The library context
306b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
307b11c1e72Sjeremylt 
308b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
309dfdf5a53Sjeremylt 
310dfdf5a53Sjeremylt   @ref Basic
311b11c1e72Sjeremylt **/
312d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
313d7b241e6Sjeremylt   int ierr;
314aedaa0e5Sjeremylt   size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority;
315d7b241e6Sjeremylt 
316fe2413ffSjeremylt   // Find matching backend
317d7b241e6Sjeremylt   if (!resource) return CeedError(NULL, 1, "No resource provided");
318d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
319d7b241e6Sjeremylt     size_t n;
320d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
321d7b241e6Sjeremylt     for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {}
322d7b241e6Sjeremylt     priority = backends[i].priority;
323d7b241e6Sjeremylt     if (n > matchlen || (n == matchlen && matchpriority > priority)) {
324d7b241e6Sjeremylt       matchlen = n;
325d7b241e6Sjeremylt       matchpriority = priority;
326d7b241e6Sjeremylt       matchidx = i;
327d7b241e6Sjeremylt     }
328d7b241e6Sjeremylt   }
329d7b241e6Sjeremylt   if (!matchlen) return CeedError(NULL, 1, "No suitable backend");
330fe2413ffSjeremylt 
331fe2413ffSjeremylt   // Setup Ceed
332d7b241e6Sjeremylt   ierr = CeedCalloc(1,ceed); CeedChk(ierr);
333bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
334bc81ce41Sjeremylt   if (!ceed_error_handler) ceed_error_handler = "abort";
335bc81ce41Sjeremylt   if (!strcmp(ceed_error_handler, "exit"))
33656e866f4SJed Brown     (*ceed)->Error = CeedErrorExit;
33756e866f4SJed Brown   else
338d7b241e6Sjeremylt     (*ceed)->Error = CeedErrorAbort;
339d7b241e6Sjeremylt   (*ceed)->refcount = 1;
340d7b241e6Sjeremylt   (*ceed)->data = NULL;
341fe2413ffSjeremylt 
342fe2413ffSjeremylt   // Set lookup table
343*6e79d475Sjeremylt   foffset foffsets[] = {
344*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Error),
345*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
346*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Destroy),
347*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, VecCreate),
348*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
349*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
350*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
351*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
352*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
353*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
354*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
355*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
356*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetArray),
357*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetValue),
358*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArray),
359*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
360*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
361*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
362*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Destroy),
363*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
364*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
365*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
366*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Apply),
367*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Destroy),
368*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
369*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
370*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Apply),
371*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
372*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Apply),
373*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
374*6e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Destroy),
375*6e79d475Sjeremylt     {NULL, 0} // End of lookup table - used in SetBackendFunction loop
3761dfeef1dSjeremylt   };
377fe2413ffSjeremylt 
378*6e79d475Sjeremylt   ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr);
379*6e79d475Sjeremylt   memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets));
380fe2413ffSjeremylt 
381fe2413ffSjeremylt   // Backend specific setup
382d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
383fe2413ffSjeremylt 
384d7b241e6Sjeremylt   return 0;
385d7b241e6Sjeremylt }
386d7b241e6Sjeremylt 
387d7b241e6Sjeremylt /**
3882f86a920SJeremy L Thompson   @brief Retrieve a parent CEED
3892f86a920SJeremy L Thompson 
3902f86a920SJeremy L Thompson   @param ceed           Ceed to retrieve parent of
3912f86a920SJeremy L Thompson   @param[out] parent    Address to save the parent to
3922f86a920SJeremy L Thompson 
3932f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3942f86a920SJeremy L Thompson 
3952f86a920SJeremy L Thompson   @ref Developer
3962f86a920SJeremy L Thompson **/
3972f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
3982f86a920SJeremy L Thompson   int ierr;
3992f86a920SJeremy L Thompson   if (ceed->parent) {
4002f86a920SJeremy L Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
4012f86a920SJeremy L Thompson     return 0;
4022f86a920SJeremy L Thompson   }
4032f86a920SJeremy L Thompson   *parent = ceed;
4042f86a920SJeremy L Thompson   return 0;
4052f86a920SJeremy L Thompson }
4062f86a920SJeremy L Thompson 
4072f86a920SJeremy L Thompson /**
4085fe0d4faSjeremylt   @brief Retrieve a delegate CEED
4095fe0d4faSjeremylt 
4105fe0d4faSjeremylt   @param ceed           Ceed to retrieve delegate of
4115fe0d4faSjeremylt   @param[out] delegate  Address to save the delegate to
4125fe0d4faSjeremylt 
4135fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
4145fe0d4faSjeremylt 
41523617272Sjeremylt   @ref Developer
4165fe0d4faSjeremylt **/
4175fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
4184ce2993fSjeremylt   *delegate = ceed->delegate;
4194ce2993fSjeremylt   return 0;
4204ce2993fSjeremylt }
4214ce2993fSjeremylt 
4224ce2993fSjeremylt /**
4234ce2993fSjeremylt   @brief Set a delegate CEED
4244ce2993fSjeremylt 
4254ce2993fSjeremylt   @param ceed           Ceed to set delegate of
4264ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
4274ce2993fSjeremylt 
4284ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4294ce2993fSjeremylt 
43023617272Sjeremylt   @ref Advanced
4314ce2993fSjeremylt **/
4324ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) {
4334ce2993fSjeremylt   ceed->delegate = *delegate;
4342f86a920SJeremy L Thompson   (*delegate)->parent = ceed;
4354ce2993fSjeremylt   return 0;
4364ce2993fSjeremylt }
4374ce2993fSjeremylt 
4384ce2993fSjeremylt /**
439c907536fSjeremylt   @brief Return Ceed perferred memory type
440c907536fSjeremylt 
441c907536fSjeremylt   @param ceed           Ceed to get preferred memory type of
442c907536fSjeremylt   @param[out] delegate  Address to save preferred memory type to
443c907536fSjeremylt 
444c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
445c907536fSjeremylt 
446c907536fSjeremylt   @ref Basic
447c907536fSjeremylt **/
448c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) {
449c907536fSjeremylt   int ierr;
450c907536fSjeremylt   if (ceed->GetPreferredMemType) {
451c907536fSjeremylt     ierr = ceed->GetPreferredMemType(type); CeedChk(ierr);
452c907536fSjeremylt   } else {
453c907536fSjeremylt     *type = CEED_MEM_HOST;
454c907536fSjeremylt   }
455c907536fSjeremylt 
456c907536fSjeremylt   return 0;
457c907536fSjeremylt }
458c907536fSjeremylt 
459c907536fSjeremylt /**
460fe2413ffSjeremylt   @brief Set a backend function
461fe2413ffSjeremylt 
462fe2413ffSjeremylt   @param ceed           Ceed for error handling
463fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
464fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
465fe2413ffSjeremylt   @param fname          Name of function to set
466fe2413ffSjeremylt   @param f              Function to set
467fe2413ffSjeremylt 
468fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
469fe2413ffSjeremylt 
470fe2413ffSjeremylt   @ref Advanced
471fe2413ffSjeremylt **/
472fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed,
473fe2413ffSjeremylt                            const char *type, void *object,
474fe2413ffSjeremylt                            const char *fname, int (*f)()) {
475409ab9adSjeremylt   char lookupname[CEED_MAX_RESOURCE_LEN+1] = "";
476fe2413ffSjeremylt 
477fe2413ffSjeremylt   // Build lookup name
478*6e79d475Sjeremylt   if (strcmp(type, "Ceed"))
479*6e79d475Sjeremylt     strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN);
480409ab9adSjeremylt   strncat(lookupname, type, CEED_MAX_RESOURCE_LEN);
481409ab9adSjeremylt   strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN);
482fe2413ffSjeremylt 
483fe2413ffSjeremylt   // Find and use offset
484*6e79d475Sjeremylt   for (CeedInt i = 0; ceed->foffsets[i].fname; i++) {
485fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
486fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
487a7a2e802Sjeremylt       int (**fpointer)(void) = (int (**)(void))((char*)object + offset);
488a7a2e802Sjeremylt       *fpointer = f;
489fe2413ffSjeremylt       return 0;
490fe2413ffSjeremylt     }
491fe2413ffSjeremylt   }
492fe2413ffSjeremylt 
4931dfeef1dSjeremylt   return CeedError(ceed, 1,
4941dfeef1dSjeremylt                    "Requested function '%s' was not found for CEED object '%s'", fname, type);
495fe2413ffSjeremylt }
496fe2413ffSjeremylt 
497fe2413ffSjeremylt /**
4984ce2993fSjeremylt   @brief Retrieve backend data for a CEED
4994ce2993fSjeremylt 
500fe2413ffSjeremylt   @param ceed           Ceed to retrieve data of
5014ce2993fSjeremylt   @param[out] data      Address to save data to
5024ce2993fSjeremylt 
5034ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
5044ce2993fSjeremylt 
50523617272Sjeremylt   @ref Advanced
5064ce2993fSjeremylt **/
5074ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) {
5084ce2993fSjeremylt   *data = ceed->data;
5095fe0d4faSjeremylt   return 0;
5105fe0d4faSjeremylt }
5115fe0d4faSjeremylt 
5125fe0d4faSjeremylt /**
513fe2413ffSjeremylt   @brief Set backend data for a CEED
514fe2413ffSjeremylt 
515fe2413ffSjeremylt   @param ceed           Ceed to set data of
516fe2413ffSjeremylt   @param data           Address of data to set
517fe2413ffSjeremylt 
518fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
519fe2413ffSjeremylt 
520fe2413ffSjeremylt   @ref Advanced
521fe2413ffSjeremylt **/
522fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) {
523fe2413ffSjeremylt   ceed->data = *data;
524fe2413ffSjeremylt   return 0;
525fe2413ffSjeremylt }
526fe2413ffSjeremylt 
527fe2413ffSjeremylt /**
528b11c1e72Sjeremylt   @brief Destroy a Ceed context
529d7b241e6Sjeremylt 
530d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
531b11c1e72Sjeremylt 
532b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
533dfdf5a53Sjeremylt 
534dfdf5a53Sjeremylt   @ref Basic
535b11c1e72Sjeremylt **/
536d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
537d7b241e6Sjeremylt   int ierr;
538d7b241e6Sjeremylt 
539d7b241e6Sjeremylt   if (!*ceed || --(*ceed)->refcount > 0) return 0;
5405fe0d4faSjeremylt   if ((*ceed)->delegate) {
5415fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
5425fe0d4faSjeremylt   }
543d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
544d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
545d7b241e6Sjeremylt   }
546*6e79d475Sjeremylt   ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr);
547d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
548d7b241e6Sjeremylt   return 0;
549d7b241e6Sjeremylt }
550d7b241e6Sjeremylt 
551d7b241e6Sjeremylt /// @}
552