xref: /libCEED/rust/libceed-sys/c-src/interface/ceed.c (revision 5107b09fcb4710dffb8bf2363d6d7d4be3d24cc9)
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>
226e79d475Sjeremylt #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 
386e79d475Sjeremylt #define CEED_FTABLE_ENTRY(class, method) \
396e79d475Sjeremylt   {#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 
90288c0443SJeremy L Thompson   @todo 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;
105683faae0SJed Brown   int retval;
106d7b241e6Sjeremylt   va_start(args, format);
107683faae0SJed Brown   if (ceed) {
108683faae0SJed Brown     retval = ceed->Error(ceed, filename, lineno, func, ecode, format, args);
109683faae0SJed Brown   } else {
110683faae0SJed Brown     // This function doesn't actually return
111683faae0SJed Brown     retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args);
112683faae0SJed Brown   }
113683faae0SJed Brown   va_end(args);
114683faae0SJed Brown   return retval;
115d7b241e6Sjeremylt }
116d7b241e6Sjeremylt 
117b11c1e72Sjeremylt /**
118b11c1e72Sjeremylt   @brief Error handler that returns without printing anything.
119b11c1e72Sjeremylt 
120b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
121dfdf5a53Sjeremylt 
122dfdf5a53Sjeremylt   @ref Developer
123b11c1e72Sjeremylt **/
124d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno,
125d7b241e6Sjeremylt                     const char *func, int ecode, const char *format,
126d7b241e6Sjeremylt                     va_list args) {
127d7b241e6Sjeremylt   return ecode;
128d7b241e6Sjeremylt }
129d7b241e6Sjeremylt 
130b11c1e72Sjeremylt /**
131b11c1e72Sjeremylt   @brief Error handler that prints to stderr and aborts
132b11c1e72Sjeremylt 
133b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
134dfdf5a53Sjeremylt 
135dfdf5a53Sjeremylt   @ref Developer
136b11c1e72Sjeremylt **/
137d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno,
1381d102b48SJeremy L Thompson                    const char *func, int ecode, const char *format,
1391d102b48SJeremy L Thompson                    va_list args) {
140d7b241e6Sjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
141d7b241e6Sjeremylt   vfprintf(stderr, format, args);
142d7b241e6Sjeremylt   fprintf(stderr, "\n");
143d7b241e6Sjeremylt   abort();
144d7b241e6Sjeremylt   return ecode;
145d7b241e6Sjeremylt }
146d7b241e6Sjeremylt 
147b11c1e72Sjeremylt /**
14856e866f4SJed Brown   @brief Error handler that prints to stderr and exits
14956e866f4SJed Brown 
15056e866f4SJed Brown   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
15156e866f4SJed Brown 
15256e866f4SJed Brown   In contrast to CeedErrorAbort(), this exits without a signal, so atexit()
15356e866f4SJed Brown   handlers (e.g., as used by gcov) are run.
15456e866f4SJed Brown 
15556e866f4SJed Brown   @ref Developer
15656e866f4SJed Brown **/
157692c2638Sjeremylt int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func,
158692c2638Sjeremylt                   int ecode, const char *format, va_list args) {
15956e866f4SJed Brown   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
16056e866f4SJed Brown   vfprintf(stderr, format, args);
16156e866f4SJed Brown   fprintf(stderr, "\n");
16256e866f4SJed Brown   exit(ecode);
16356e866f4SJed Brown   return ecode;
16456e866f4SJed Brown }
16556e866f4SJed Brown 
16656e866f4SJed Brown /**
167dfdf5a53Sjeremylt   @brief Set error handler
168b11c1e72Sjeremylt 
169b11c1e72Sjeremylt   A default error handler is set in CeedInit().  Use this function to change
170b11c1e72Sjeremylt   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
171b11c1e72Sjeremylt   error handler.
172dfdf5a53Sjeremylt 
173dfdf5a53Sjeremylt   @ref Developer
174b11c1e72Sjeremylt **/
175d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed,
176d7b241e6Sjeremylt                         int (eh)(Ceed, const char *, int, const char *,
177d7b241e6Sjeremylt                                  int, const char *, va_list)) {
178d7b241e6Sjeremylt   ceed->Error = eh;
179d7b241e6Sjeremylt   return 0;
180d7b241e6Sjeremylt }
181d7b241e6Sjeremylt 
182d7b241e6Sjeremylt /**
183b11c1e72Sjeremylt   @brief Register a Ceed backend
184d7b241e6Sjeremylt 
185d7b241e6Sjeremylt   @param prefix   Prefix of resources for this backend to respond to.  For
186d7b241e6Sjeremylt                     example, the reference backend responds to "/cpu/self".
187d7b241e6Sjeremylt   @param init     Initialization function called by CeedInit() when the backend
188d7b241e6Sjeremylt                     is selected to drive the requested resource.
189d7b241e6Sjeremylt   @param priority Integer priority.  Lower values are preferred in case the
190d7b241e6Sjeremylt                     resource requested by CeedInit() has non-unique best prefix
191d7b241e6Sjeremylt                     match.
192b11c1e72Sjeremylt 
193b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
194dfdf5a53Sjeremylt 
195dfdf5a53Sjeremylt   @ref Advanced
196b11c1e72Sjeremylt **/
197692c2638Sjeremylt int CeedRegister(const char *prefix, int (*init)(const char *, Ceed),
198692c2638Sjeremylt                  unsigned int priority) {
199c042f62fSJeremy L Thompson   if (num_backends >= sizeof(backends) / sizeof(backends[0]))
200c042f62fSJeremy L Thompson     // LCOV_EXCL_START
201d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
202c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
203c042f62fSJeremy L Thompson 
204d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
205288c0443SJeremy L Thompson   backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0;
206d7b241e6Sjeremylt   backends[num_backends].init = init;
207d7b241e6Sjeremylt   backends[num_backends].priority = priority;
208d7b241e6Sjeremylt   num_backends++;
209d7b241e6Sjeremylt   return 0;
210d7b241e6Sjeremylt }
211d7b241e6Sjeremylt 
212b11c1e72Sjeremylt /**
213b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
214b11c1e72Sjeremylt 
215b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
216b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
217b11c1e72Sjeremylt 
218b11c1e72Sjeremylt   @param n Number of units to allocate
219b11c1e72Sjeremylt   @param unit Size of each unit
220b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
221b11c1e72Sjeremylt 
222b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
223b11c1e72Sjeremylt 
224b11c1e72Sjeremylt   @sa CeedFree()
225dfdf5a53Sjeremylt 
226dfdf5a53Sjeremylt   @ref Advanced
227b11c1e72Sjeremylt **/
228d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
229d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
230d7b241e6Sjeremylt   if (ierr)
231c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2321d102b48SJeremy L Thompson     return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd "
2331d102b48SJeremy L Thompson                      "members of size %zd\n", n, unit);
234c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
235c042f62fSJeremy L Thompson 
236d7b241e6Sjeremylt   return 0;
237d7b241e6Sjeremylt }
238d7b241e6Sjeremylt 
239b11c1e72Sjeremylt /**
240b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
241b11c1e72Sjeremylt 
242b11c1e72Sjeremylt   Memory usage can be tracked by the library.
243b11c1e72Sjeremylt 
244b11c1e72Sjeremylt   @param n Number of units to allocate
245b11c1e72Sjeremylt   @param unit Size of each unit
246b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
247b11c1e72Sjeremylt 
248b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
249b11c1e72Sjeremylt 
250b11c1e72Sjeremylt   @sa CeedFree()
251dfdf5a53Sjeremylt 
252dfdf5a53Sjeremylt   @ref Advanced
253b11c1e72Sjeremylt **/
254d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
255d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
256d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
257c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2581d102b48SJeremy L Thompson     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size "
2591d102b48SJeremy L Thompson                      "%zd\n", n, unit);
260c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
261c042f62fSJeremy L Thompson 
262d7b241e6Sjeremylt   return 0;
263d7b241e6Sjeremylt }
264d7b241e6Sjeremylt 
265b11c1e72Sjeremylt /**
266b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
267b11c1e72Sjeremylt 
268b11c1e72Sjeremylt   Memory usage can be tracked by the library.
269b11c1e72Sjeremylt 
270b11c1e72Sjeremylt   @param n Number of units to allocate
271b11c1e72Sjeremylt   @param unit Size of each unit
272b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
273b11c1e72Sjeremylt 
274b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
275b11c1e72Sjeremylt 
276b11c1e72Sjeremylt   @sa CeedFree()
277dfdf5a53Sjeremylt 
278dfdf5a53Sjeremylt   @ref Advanced
279b11c1e72Sjeremylt **/
280d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
281d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
282d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
283c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2841d102b48SJeremy L Thompson     return CeedError(NULL, 1, "realloc failed to allocate %zd members of size "
2851d102b48SJeremy L Thompson                      "%zd\n", n, unit);
286c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
287c042f62fSJeremy L Thompson 
288d7b241e6Sjeremylt   return 0;
289d7b241e6Sjeremylt }
290d7b241e6Sjeremylt 
291d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc()
292d7b241e6Sjeremylt ///
293d7b241e6Sjeremylt /// @param p address of pointer to memory.  This argument is of type void* to
294d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed)
295d7b241e6Sjeremylt /// rather than the pointer.
296d7b241e6Sjeremylt int CeedFree(void *p) {
297d7b241e6Sjeremylt   free(*(void **)p);
298d7b241e6Sjeremylt   *(void **)p = NULL;
299d7b241e6Sjeremylt   return 0;
300d7b241e6Sjeremylt }
301d7b241e6Sjeremylt 
302d7b241e6Sjeremylt /**
303b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
304d7b241e6Sjeremylt 
305d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
306d7b241e6Sjeremylt 
307d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
308b11c1e72Sjeremylt 
309b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
310dfdf5a53Sjeremylt 
311dfdf5a53Sjeremylt   @ref Advanced
312b11c1e72Sjeremylt **/
313d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
3141d102b48SJeremy L Thompson   if (!*req)
3151d102b48SJeremy L Thompson     return 0;
316d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
317d7b241e6Sjeremylt }
318d7b241e6Sjeremylt 
319b11c1e72Sjeremylt /**
320b11c1e72Sjeremylt   @brief Initialize a \ref Ceed to use the specified resource.
321b11c1e72Sjeremylt 
322b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
323b11c1e72Sjeremylt   @param ceed The library context
324b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
325b11c1e72Sjeremylt 
326b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
327dfdf5a53Sjeremylt 
328dfdf5a53Sjeremylt   @ref Basic
329b11c1e72Sjeremylt **/
330d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
331d7b241e6Sjeremylt   int ierr;
332aedaa0e5Sjeremylt   size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority;
333d7b241e6Sjeremylt 
334fe2413ffSjeremylt   // Find matching backend
3351d102b48SJeremy L Thompson   if (!resource)
3361d102b48SJeremy L Thompson     return CeedError(NULL, 1, "No resource provided");
337d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
338d7b241e6Sjeremylt     size_t n;
339d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
340d7b241e6Sjeremylt     for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {}
341d7b241e6Sjeremylt     priority = backends[i].priority;
342d7b241e6Sjeremylt     if (n > matchlen || (n == matchlen && matchpriority > priority)) {
343d7b241e6Sjeremylt       matchlen = n;
344d7b241e6Sjeremylt       matchpriority = priority;
345d7b241e6Sjeremylt       matchidx = i;
346d7b241e6Sjeremylt     }
347d7b241e6Sjeremylt   }
3481d102b48SJeremy L Thompson   if (!matchlen)
3491d102b48SJeremy L Thompson     return CeedError(NULL, 1, "No suitable backend");
350fe2413ffSjeremylt 
351fe2413ffSjeremylt   // Setup Ceed
352d7b241e6Sjeremylt   ierr = CeedCalloc(1,ceed); CeedChk(ierr);
353bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
3541d102b48SJeremy L Thompson   if (!ceed_error_handler)
3551d102b48SJeremy L Thompson     ceed_error_handler = "abort";
356bc81ce41Sjeremylt   if (!strcmp(ceed_error_handler, "exit"))
35756e866f4SJed Brown     (*ceed)->Error = CeedErrorExit;
35856e866f4SJed Brown   else
359d7b241e6Sjeremylt     (*ceed)->Error = CeedErrorAbort;
360d7b241e6Sjeremylt   (*ceed)->refcount = 1;
361d7b241e6Sjeremylt   (*ceed)->data = NULL;
362fe2413ffSjeremylt 
363fe2413ffSjeremylt   // Set lookup table
3646e79d475Sjeremylt   foffset foffsets[] = {
3656e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Error),
3666e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
3676e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Destroy),
368f8902d9eSjeremylt     CEED_FTABLE_ENTRY(Ceed, VectorCreate),
3696e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
3706e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
3716e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
3726e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
3736e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
3746e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
3756e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
3766e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
3776e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetArray),
3786e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetValue),
3796e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArray),
3806e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
3816e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
3826e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
3836e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Destroy),
3846e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
3856e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
3866e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
3876e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Apply),
3886e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Destroy),
3896e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
3906e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
3916e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Apply),
3926e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
3931d102b48SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction),
394b7ec98d8SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal),
3956e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Apply),
3966e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
3976e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Destroy),
3986e79d475Sjeremylt     {NULL, 0} // End of lookup table - used in SetBackendFunction loop
3991dfeef1dSjeremylt   };
400fe2413ffSjeremylt 
4016e79d475Sjeremylt   ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr);
4026e79d475Sjeremylt   memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets));
403fe2413ffSjeremylt 
404*5107b09fSJeremy L Thompson   // Set fallback for advanced CeedOperator functions
405*5107b09fSJeremy L Thompson   const char fallbackresource[] = "/cpu/self/ref/serial";
406*5107b09fSJeremy L Thompson   ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource);
407*5107b09fSJeremy L Thompson   CeedChk(ierr);
408*5107b09fSJeremy L Thompson 
409fe2413ffSjeremylt   // Backend specific setup
410d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
411fe2413ffSjeremylt 
412e07206deSjeremylt   // Copy resource prefix, if backend setup sucessful
413e07206deSjeremylt   size_t len = strlen(backends[matchidx].prefix);
414e07206deSjeremylt   char *tmp;
415e07206deSjeremylt   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
416e07206deSjeremylt   memcpy(tmp, backends[matchidx].prefix, len+1);
417e07206deSjeremylt   (*ceed)->resource = tmp;
418e07206deSjeremylt 
419d7b241e6Sjeremylt   return 0;
420d7b241e6Sjeremylt }
421d7b241e6Sjeremylt 
422d7b241e6Sjeremylt /**
4232f86a920SJeremy L Thompson   @brief Retrieve a parent CEED
4242f86a920SJeremy L Thompson 
4252f86a920SJeremy L Thompson   @param ceed           Ceed to retrieve parent of
4262f86a920SJeremy L Thompson   @param[out] parent    Address to save the parent to
4272f86a920SJeremy L Thompson 
4282f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4292f86a920SJeremy L Thompson 
4302f86a920SJeremy L Thompson   @ref Developer
4312f86a920SJeremy L Thompson **/
4322f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
4332f86a920SJeremy L Thompson   int ierr;
4342f86a920SJeremy L Thompson   if (ceed->parent) {
4352f86a920SJeremy L Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
4362f86a920SJeremy L Thompson     return 0;
4372f86a920SJeremy L Thompson   }
4382f86a920SJeremy L Thompson   *parent = ceed;
4392f86a920SJeremy L Thompson   return 0;
4402f86a920SJeremy L Thompson }
4412f86a920SJeremy L Thompson 
4422f86a920SJeremy L Thompson /**
4435fe0d4faSjeremylt   @brief Retrieve a delegate CEED
4445fe0d4faSjeremylt 
4455fe0d4faSjeremylt   @param ceed           Ceed to retrieve delegate of
4465fe0d4faSjeremylt   @param[out] delegate  Address to save the delegate to
4475fe0d4faSjeremylt 
4485fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
4495fe0d4faSjeremylt 
45023617272Sjeremylt   @ref Developer
4515fe0d4faSjeremylt **/
4525fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
4534ce2993fSjeremylt   *delegate = ceed->delegate;
4544ce2993fSjeremylt   return 0;
4554ce2993fSjeremylt }
4564ce2993fSjeremylt 
4574ce2993fSjeremylt /**
4584ce2993fSjeremylt   @brief Set a delegate CEED
4594ce2993fSjeremylt 
460f29ffe77Sjeremylt   This function allows a CEED to set a delegate CEED. All backend
461f29ffe77Sjeremylt   implementations default to the delegate CEED, unless overridden.
462f29ffe77Sjeremylt 
4634ce2993fSjeremylt   @param ceed           Ceed to set delegate of
4644ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
4654ce2993fSjeremylt 
4664ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4674ce2993fSjeremylt 
46823617272Sjeremylt   @ref Advanced
4694ce2993fSjeremylt **/
470a4999eddSjeremylt int CeedSetDelegate(Ceed ceed, Ceed delegate) {
471a4999eddSjeremylt   ceed->delegate = delegate;
472a4999eddSjeremylt   delegate->parent = ceed;
4734ce2993fSjeremylt   return 0;
4744ce2993fSjeremylt }
4754ce2993fSjeremylt 
4764ce2993fSjeremylt /**
477aefd8378Sjeremylt   @brief Retrieve a delegate CEED for a specific object type
478aefd8378Sjeremylt 
479aefd8378Sjeremylt   @param ceed           Ceed to retrieve delegate of
480aefd8378Sjeremylt   @param[out] delegate  Address to save the delegate to
481288c0443SJeremy L Thompson   @param[in] objname    Name of the object type to retrieve delegate for
482aefd8378Sjeremylt 
483aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
484aefd8378Sjeremylt 
485aefd8378Sjeremylt   @ref Developer
486aefd8378Sjeremylt **/
487aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) {
488aefd8378Sjeremylt   CeedInt ierr;
489aefd8378Sjeremylt 
490aefd8378Sjeremylt   // Check for object delegate
4911d102b48SJeremy L Thompson   for (CeedInt i=0; i<ceed->objdelegatecount; i++)
492aefd8378Sjeremylt     if (!strcmp(objname, ceed->objdelegates->objname)) {
493aefd8378Sjeremylt       *delegate = ceed->objdelegates->delegate;
494aefd8378Sjeremylt       return 0;
495aefd8378Sjeremylt     }
496aefd8378Sjeremylt 
497aefd8378Sjeremylt   // Use default delegate if no object delegate
498aefd8378Sjeremylt   ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr);
499aefd8378Sjeremylt 
500aefd8378Sjeremylt   return 0;
501aefd8378Sjeremylt }
502aefd8378Sjeremylt 
503aefd8378Sjeremylt /**
504aefd8378Sjeremylt   @brief Set a delegate CEED for a specific object type
505aefd8378Sjeremylt 
506f29ffe77Sjeremylt   This function allows a CEED to set a delegate CEED for a given type of
507f29ffe77Sjeremylt   CEED object. All backend implementations default to the delegate CEED for
508f29ffe77Sjeremylt   this object. For example,
509f29ffe77Sjeremylt     CeedSetObjectDelegate(ceed, refceed, "Basis")
510f29ffe77Sjeremylt   uses refceed implementations for all CeedBasis backend functions.
511f29ffe77Sjeremylt 
512aefd8378Sjeremylt   @param ceed           Ceed to set delegate of
513aefd8378Sjeremylt   @param[out] delegate  Address to set the delegate to
514288c0443SJeremy L Thompson   @param[in] objname    Name of the object type to set delegate for
515aefd8378Sjeremylt 
516aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
517aefd8378Sjeremylt 
518aefd8378Sjeremylt   @ref Advanced
519aefd8378Sjeremylt **/
520a4999eddSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) {
521aefd8378Sjeremylt   CeedInt ierr;
522aefd8378Sjeremylt   CeedInt count = ceed->objdelegatecount;
523aefd8378Sjeremylt 
524aefd8378Sjeremylt   // Malloc or Realloc
525aefd8378Sjeremylt   if (count) {
5261d102b48SJeremy L Thompson     ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr);
527aefd8378Sjeremylt   } else {
528aefd8378Sjeremylt     ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr);
529aefd8378Sjeremylt   }
530aefd8378Sjeremylt   ceed->objdelegatecount++;
531aefd8378Sjeremylt 
532aefd8378Sjeremylt   // Set object delegate
533a4999eddSjeremylt   ceed->objdelegates[count].delegate = delegate;
53407a02837SJed Brown   size_t slen = strlen(objname) + 1;
53507a02837SJed Brown   ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr);
53607a02837SJed Brown   memcpy(ceed->objdelegates[count].objname, objname, slen);
537aefd8378Sjeremylt 
538aefd8378Sjeremylt   // Set delegate parent
539a4999eddSjeremylt   delegate->parent = ceed;
540aefd8378Sjeremylt 
541aefd8378Sjeremylt   return 0;
542aefd8378Sjeremylt }
543aefd8378Sjeremylt 
544aefd8378Sjeremylt /**
545*5107b09fSJeremy L Thompson   @brief Set the fallback resource for CeedOperators. The current resource, if
546*5107b09fSJeremy L Thompson            any, is freed by calling this function. This string is freed upon the
547*5107b09fSJeremy L Thompson            destruction of the Ceed.
548*5107b09fSJeremy L Thompson 
549*5107b09fSJeremy L Thompson   @param[out] ceed Ceed context
550*5107b09fSJeremy L Thompson   @param resource  Fallback resource to set
551*5107b09fSJeremy L Thompson 
552*5107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
553*5107b09fSJeremy L Thompson 
554*5107b09fSJeremy L Thompson   @ref Advanced
555*5107b09fSJeremy L Thompson **/
556*5107b09fSJeremy L Thompson 
557*5107b09fSJeremy L Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
558*5107b09fSJeremy L Thompson   int ierr;
559*5107b09fSJeremy L Thompson 
560*5107b09fSJeremy L Thompson   // Free old
561*5107b09fSJeremy L Thompson   ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr);
562*5107b09fSJeremy L Thompson 
563*5107b09fSJeremy L Thompson   // Set new
564*5107b09fSJeremy L Thompson   size_t len = strlen(resource);
565*5107b09fSJeremy L Thompson   char *tmp;
566*5107b09fSJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
567*5107b09fSJeremy L Thompson   memcpy(tmp, resource, len+1);
568*5107b09fSJeremy L Thompson   ceed->opfallbackresource = tmp;
569*5107b09fSJeremy L Thompson 
570*5107b09fSJeremy L Thompson   return 0;
571*5107b09fSJeremy L Thompson }
572*5107b09fSJeremy L Thompson 
573*5107b09fSJeremy L Thompson /**
574*5107b09fSJeremy L Thompson   @brief Get the fallback resource for CeedOperators
575*5107b09fSJeremy L Thompson 
576*5107b09fSJeremy L Thompson   @param ceed          Ceed context
577*5107b09fSJeremy L Thompson   @param[out] resource Variable to store fallback resource
578*5107b09fSJeremy L Thompson 
579*5107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
580*5107b09fSJeremy L Thompson 
581*5107b09fSJeremy L Thompson   @ref Advanced
582*5107b09fSJeremy L Thompson **/
583*5107b09fSJeremy L Thompson 
584*5107b09fSJeremy L Thompson int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
585*5107b09fSJeremy L Thompson   *resource = (const char *)ceed->opfallbackresource;
586*5107b09fSJeremy L Thompson   return 0;
587*5107b09fSJeremy L Thompson }
588*5107b09fSJeremy L Thompson 
589*5107b09fSJeremy L Thompson /**
590*5107b09fSJeremy L Thompson   @brief Get the parent Ceed associated with a fallback Ceed for a CeedOperator
591*5107b09fSJeremy L Thompson 
592*5107b09fSJeremy L Thompson   @param ceed            Ceed context
593*5107b09fSJeremy L Thompson   @param[out] ceed       Variable to store parent Ceed
594*5107b09fSJeremy L Thompson 
595*5107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
596*5107b09fSJeremy L Thompson 
597*5107b09fSJeremy L Thompson   @ref Advanced
598*5107b09fSJeremy L Thompson **/
599*5107b09fSJeremy L Thompson 
600*5107b09fSJeremy L Thompson int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) {
601*5107b09fSJeremy L Thompson   *parent = ceed->opfallbackparent;
602*5107b09fSJeremy L Thompson   return 0;
603*5107b09fSJeremy L Thompson }
604*5107b09fSJeremy L Thompson 
605*5107b09fSJeremy L Thompson /**
6068c91a0c9SJeremy L Thompson   @brief Return Ceed preferred memory type
607c907536fSjeremylt 
608c907536fSjeremylt   @param ceed           Ceed to get preferred memory type of
609288c0443SJeremy L Thompson   @param[out] type      Address to save preferred memory type to
610c907536fSjeremylt 
611c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
612c907536fSjeremylt 
613c907536fSjeremylt   @ref Basic
614c907536fSjeremylt **/
615c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) {
616c907536fSjeremylt   int ierr;
617c263cd57Sjeremylt 
618c907536fSjeremylt   if (ceed->GetPreferredMemType) {
619c907536fSjeremylt     ierr = ceed->GetPreferredMemType(type); CeedChk(ierr);
620c907536fSjeremylt   } else {
621c263cd57Sjeremylt     Ceed delegate;
622c263cd57Sjeremylt     ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr);
623c263cd57Sjeremylt 
624c263cd57Sjeremylt     if (delegate) {
625c263cd57Sjeremylt       ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr);
626c263cd57Sjeremylt     } else {
627c907536fSjeremylt       *type = CEED_MEM_HOST;
628c907536fSjeremylt     }
629c263cd57Sjeremylt   }
630c907536fSjeremylt 
631c907536fSjeremylt   return 0;
632c907536fSjeremylt }
633c907536fSjeremylt 
634c907536fSjeremylt /**
635fe2413ffSjeremylt   @brief Set a backend function
636fe2413ffSjeremylt 
637cb37edd8Sjeremylt   This function is used for a backend to set the function associated with
638cb37edd8Sjeremylt   the CEED objects. For example,
639f8902d9eSjeremylt     CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate)
640cb37edd8Sjeremylt   sets the backend implementation of 'CeedVectorCreate' and
641cb37edd8Sjeremylt     CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply)
642cb37edd8Sjeremylt   sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed'
643cb37edd8Sjeremylt   is not required for the object type ("Basis" vs "CeedBasis").
644cb37edd8Sjeremylt 
645fe2413ffSjeremylt   @param ceed           Ceed for error handling
646fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
647fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
648fe2413ffSjeremylt   @param fname          Name of function to set
649fe2413ffSjeremylt   @param f              Function to set
650fe2413ffSjeremylt 
651fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
652fe2413ffSjeremylt 
653fe2413ffSjeremylt   @ref Advanced
654fe2413ffSjeremylt **/
655692c2638Sjeremylt int CeedSetBackendFunction(Ceed ceed, const char *type, void *object,
656fe2413ffSjeremylt                            const char *fname, int (*f)()) {
657409ab9adSjeremylt   char lookupname[CEED_MAX_RESOURCE_LEN+1] = "";
658fe2413ffSjeremylt 
659fe2413ffSjeremylt   // Build lookup name
6606e79d475Sjeremylt   if (strcmp(type, "Ceed"))
6616e79d475Sjeremylt     strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN);
662409ab9adSjeremylt   strncat(lookupname, type, CEED_MAX_RESOURCE_LEN);
663409ab9adSjeremylt   strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN);
664fe2413ffSjeremylt 
665fe2413ffSjeremylt   // Find and use offset
6661d102b48SJeremy L Thompson   for (CeedInt i = 0; ceed->foffsets[i].fname; i++)
667fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
668fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
669cb0b5415Sjeremylt       int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD*
670a7a2e802Sjeremylt       *fpointer = f;
671fe2413ffSjeremylt       return 0;
672fe2413ffSjeremylt     }
673fe2413ffSjeremylt 
674c042f62fSJeremy L Thompson   // LCOV_EXCL_START
6751d102b48SJeremy L Thompson   return CeedError(ceed, 1, "Requested function '%s' was not found for CEED "
6761d102b48SJeremy L Thompson                    "object '%s'", fname, type);
677c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
678fe2413ffSjeremylt }
679fe2413ffSjeremylt 
680fe2413ffSjeremylt /**
6814ce2993fSjeremylt   @brief Retrieve backend data for a CEED
6824ce2993fSjeremylt 
683fe2413ffSjeremylt   @param ceed           Ceed to retrieve data of
6844ce2993fSjeremylt   @param[out] data      Address to save data to
6854ce2993fSjeremylt 
6864ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6874ce2993fSjeremylt 
68823617272Sjeremylt   @ref Advanced
6894ce2993fSjeremylt **/
6904ce2993fSjeremylt int CeedGetData(Ceed ceed, void **data) {
6914ce2993fSjeremylt   *data = ceed->data;
6925fe0d4faSjeremylt   return 0;
6935fe0d4faSjeremylt }
6945fe0d4faSjeremylt 
6955fe0d4faSjeremylt /**
696fe2413ffSjeremylt   @brief Set backend data for a CEED
697fe2413ffSjeremylt 
698fe2413ffSjeremylt   @param ceed           Ceed to set data of
699fe2413ffSjeremylt   @param data           Address of data to set
700fe2413ffSjeremylt 
701fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
702fe2413ffSjeremylt 
703fe2413ffSjeremylt   @ref Advanced
704fe2413ffSjeremylt **/
705fe2413ffSjeremylt int CeedSetData(Ceed ceed, void **data) {
706fe2413ffSjeremylt   ceed->data = *data;
707fe2413ffSjeremylt   return 0;
708fe2413ffSjeremylt }
709fe2413ffSjeremylt 
710fe2413ffSjeremylt /**
711e07206deSjeremylt   @brief Get the full resource name for a CEED
712e07206deSjeremylt 
713e07206deSjeremylt   @param ceed            Ceed to get resource name of
714e07206deSjeremylt   @param[out] resource   Variable to store resource name
715e07206deSjeremylt 
716e07206deSjeremylt   @return An error code: 0 - success, otherwise - failure
717e07206deSjeremylt 
718e07206deSjeremylt   @ref Basic
719e07206deSjeremylt **/
720e07206deSjeremylt 
721e07206deSjeremylt int CeedGetResource(Ceed ceed, const char **resource) {
722e07206deSjeremylt   *resource = (const char *)ceed->resource;
723e07206deSjeremylt   return 0;
724e07206deSjeremylt }
725e07206deSjeremylt 
726e07206deSjeremylt /**
727b11c1e72Sjeremylt   @brief Destroy a Ceed context
728d7b241e6Sjeremylt 
729d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
730b11c1e72Sjeremylt 
731b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
732dfdf5a53Sjeremylt 
733dfdf5a53Sjeremylt   @ref Basic
734b11c1e72Sjeremylt **/
735d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
736d7b241e6Sjeremylt   int ierr;
737d7b241e6Sjeremylt 
7381d102b48SJeremy L Thompson   if (!*ceed || --(*ceed)->refcount > 0)
7391d102b48SJeremy L Thompson     return 0;
7405fe0d4faSjeremylt   if ((*ceed)->delegate) {
7415fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
7425fe0d4faSjeremylt   }
743aefd8378Sjeremylt   if ((*ceed)->objdelegatecount > 0) {
744aefd8378Sjeremylt     for (int i=0; i<(*ceed)->objdelegatecount; i++) {
745aefd8378Sjeremylt       ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr);
746aefd8378Sjeremylt       ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr);
747aefd8378Sjeremylt     }
748aefd8378Sjeremylt     ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr);
749aefd8378Sjeremylt   }
750d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
751d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
752d7b241e6Sjeremylt   }
7536e79d475Sjeremylt   ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr);
754e07206deSjeremylt   ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr);
755*5107b09fSJeremy L Thompson   ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr);
756*5107b09fSJeremy L Thompson   ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr);
757d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
758d7b241e6Sjeremylt   return 0;
759d7b241e6Sjeremylt }
760d7b241e6Sjeremylt 
761d7b241e6Sjeremylt /// @}
762