xref: /libCEED/rust/libceed-sys/c-src/interface/ceed.c (revision e07206de23a3ad6f238e5da2d646d1a5a514f718)
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 **/
15756e866f4SJed Brown int CeedErrorExit(Ceed ceed, const char *filename, int lineno,
15856e866f4SJed Brown                   const char *func, int ecode,
15956e866f4SJed Brown                   const char *format, va_list args) {
16056e866f4SJed Brown   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
16156e866f4SJed Brown   vfprintf(stderr, format, args);
16256e866f4SJed Brown   fprintf(stderr, "\n");
16356e866f4SJed Brown   exit(ecode);
16456e866f4SJed Brown   return ecode;
16556e866f4SJed Brown }
16656e866f4SJed Brown 
16756e866f4SJed Brown /**
168dfdf5a53Sjeremylt   @brief Set error handler
169b11c1e72Sjeremylt 
170b11c1e72Sjeremylt   A default error handler is set in CeedInit().  Use this function to change
171b11c1e72Sjeremylt   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
172b11c1e72Sjeremylt   error handler.
173dfdf5a53Sjeremylt 
174dfdf5a53Sjeremylt   @ref Developer
175b11c1e72Sjeremylt **/
176d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed,
177d7b241e6Sjeremylt                         int (eh)(Ceed, const char *, int, const char *,
178d7b241e6Sjeremylt                                  int, const char *, va_list)) {
179d7b241e6Sjeremylt   ceed->Error = eh;
180d7b241e6Sjeremylt   return 0;
181d7b241e6Sjeremylt }
182d7b241e6Sjeremylt 
183d7b241e6Sjeremylt /**
184b11c1e72Sjeremylt   @brief Register a Ceed backend
185d7b241e6Sjeremylt 
186d7b241e6Sjeremylt   @param prefix   Prefix of resources for this backend to respond to.  For
187d7b241e6Sjeremylt                     example, the reference backend responds to "/cpu/self".
188d7b241e6Sjeremylt   @param init     Initialization function called by CeedInit() when the backend
189d7b241e6Sjeremylt                     is selected to drive the requested resource.
190d7b241e6Sjeremylt   @param priority Integer priority.  Lower values are preferred in case the
191d7b241e6Sjeremylt                     resource requested by CeedInit() has non-unique best prefix
192d7b241e6Sjeremylt                     match.
193b11c1e72Sjeremylt 
194b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
195dfdf5a53Sjeremylt 
196dfdf5a53Sjeremylt   @ref Advanced
197b11c1e72Sjeremylt **/
198d7b241e6Sjeremylt int CeedRegister(const char *prefix,
199d7b241e6Sjeremylt                  int (*init)(const char *, Ceed), unsigned int priority) {
200c042f62fSJeremy L Thompson   if (num_backends >= sizeof(backends) / sizeof(backends[0]))
201c042f62fSJeremy L Thompson     // LCOV_EXCL_START
202d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
203c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
204c042f62fSJeremy L Thompson 
205d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
206288c0443SJeremy L Thompson   backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0;
207d7b241e6Sjeremylt   backends[num_backends].init = init;
208d7b241e6Sjeremylt   backends[num_backends].priority = priority;
209d7b241e6Sjeremylt   num_backends++;
210d7b241e6Sjeremylt   return 0;
211d7b241e6Sjeremylt }
212d7b241e6Sjeremylt 
213b11c1e72Sjeremylt /**
214b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
215b11c1e72Sjeremylt 
216b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
217b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
218b11c1e72Sjeremylt 
219b11c1e72Sjeremylt   @param n Number of units to allocate
220b11c1e72Sjeremylt   @param unit Size of each unit
221b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
222b11c1e72Sjeremylt 
223b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
224b11c1e72Sjeremylt 
225b11c1e72Sjeremylt   @sa CeedFree()
226dfdf5a53Sjeremylt 
227dfdf5a53Sjeremylt   @ref Advanced
228b11c1e72Sjeremylt **/
229d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
230d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
231d7b241e6Sjeremylt   if (ierr)
232c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2331d102b48SJeremy L Thompson     return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd "
2341d102b48SJeremy L Thompson                      "members of size %zd\n", n, unit);
235c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
236c042f62fSJeremy L Thompson 
237d7b241e6Sjeremylt   return 0;
238d7b241e6Sjeremylt }
239d7b241e6Sjeremylt 
240b11c1e72Sjeremylt /**
241b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
242b11c1e72Sjeremylt 
243b11c1e72Sjeremylt   Memory usage can be tracked by the library.
244b11c1e72Sjeremylt 
245b11c1e72Sjeremylt   @param n Number of units to allocate
246b11c1e72Sjeremylt   @param unit Size of each unit
247b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
248b11c1e72Sjeremylt 
249b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
250b11c1e72Sjeremylt 
251b11c1e72Sjeremylt   @sa CeedFree()
252dfdf5a53Sjeremylt 
253dfdf5a53Sjeremylt   @ref Advanced
254b11c1e72Sjeremylt **/
255d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
256d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
257d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
258c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2591d102b48SJeremy L Thompson     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size "
2601d102b48SJeremy L Thompson                      "%zd\n", n, unit);
261c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
262c042f62fSJeremy L Thompson 
263d7b241e6Sjeremylt   return 0;
264d7b241e6Sjeremylt }
265d7b241e6Sjeremylt 
266b11c1e72Sjeremylt /**
267b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
268b11c1e72Sjeremylt 
269b11c1e72Sjeremylt   Memory usage can be tracked by the library.
270b11c1e72Sjeremylt 
271b11c1e72Sjeremylt   @param n Number of units to allocate
272b11c1e72Sjeremylt   @param unit Size of each unit
273b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
274b11c1e72Sjeremylt 
275b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
276b11c1e72Sjeremylt 
277b11c1e72Sjeremylt   @sa CeedFree()
278dfdf5a53Sjeremylt 
279dfdf5a53Sjeremylt   @ref Advanced
280b11c1e72Sjeremylt **/
281d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
282d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
283d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
284c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2851d102b48SJeremy L Thompson     return CeedError(NULL, 1, "realloc failed to allocate %zd members of size "
2861d102b48SJeremy L Thompson                      "%zd\n", n, unit);
287c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
288c042f62fSJeremy L Thompson 
289d7b241e6Sjeremylt   return 0;
290d7b241e6Sjeremylt }
291d7b241e6Sjeremylt 
292d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc()
293d7b241e6Sjeremylt ///
294d7b241e6Sjeremylt /// @param p address of pointer to memory.  This argument is of type void* to
295d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed)
296d7b241e6Sjeremylt /// rather than the pointer.
297d7b241e6Sjeremylt int CeedFree(void *p) {
298d7b241e6Sjeremylt   free(*(void **)p);
299d7b241e6Sjeremylt   *(void **)p = NULL;
300d7b241e6Sjeremylt   return 0;
301d7b241e6Sjeremylt }
302d7b241e6Sjeremylt 
303d7b241e6Sjeremylt /**
304b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
305d7b241e6Sjeremylt 
306d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
307d7b241e6Sjeremylt 
308d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
309b11c1e72Sjeremylt 
310b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
311dfdf5a53Sjeremylt 
312dfdf5a53Sjeremylt   @ref Advanced
313b11c1e72Sjeremylt **/
314d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
3151d102b48SJeremy L Thompson   if (!*req)
3161d102b48SJeremy L Thompson     return 0;
317d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
318d7b241e6Sjeremylt }
319d7b241e6Sjeremylt 
320b11c1e72Sjeremylt /**
321b11c1e72Sjeremylt   @brief Initialize a \ref Ceed to use the specified resource.
322b11c1e72Sjeremylt 
323b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
324b11c1e72Sjeremylt   @param ceed The library context
325b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
326b11c1e72Sjeremylt 
327b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
328dfdf5a53Sjeremylt 
329dfdf5a53Sjeremylt   @ref Basic
330b11c1e72Sjeremylt **/
331d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
332d7b241e6Sjeremylt   int ierr;
333aedaa0e5Sjeremylt   size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority;
334d7b241e6Sjeremylt 
335fe2413ffSjeremylt   // Find matching backend
3361d102b48SJeremy L Thompson   if (!resource)
3371d102b48SJeremy L Thompson     return CeedError(NULL, 1, "No resource provided");
338d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
339d7b241e6Sjeremylt     size_t n;
340d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
341d7b241e6Sjeremylt     for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {}
342d7b241e6Sjeremylt     priority = backends[i].priority;
343d7b241e6Sjeremylt     if (n > matchlen || (n == matchlen && matchpriority > priority)) {
344d7b241e6Sjeremylt       matchlen = n;
345d7b241e6Sjeremylt       matchpriority = priority;
346d7b241e6Sjeremylt       matchidx = i;
347d7b241e6Sjeremylt     }
348d7b241e6Sjeremylt   }
3491d102b48SJeremy L Thompson   if (!matchlen)
3501d102b48SJeremy L Thompson     return CeedError(NULL, 1, "No suitable backend");
351fe2413ffSjeremylt 
352fe2413ffSjeremylt   // Setup Ceed
353d7b241e6Sjeremylt   ierr = CeedCalloc(1,ceed); CeedChk(ierr);
354bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
3551d102b48SJeremy L Thompson   if (!ceed_error_handler)
3561d102b48SJeremy L Thompson     ceed_error_handler = "abort";
357bc81ce41Sjeremylt   if (!strcmp(ceed_error_handler, "exit"))
35856e866f4SJed Brown     (*ceed)->Error = CeedErrorExit;
35956e866f4SJed Brown   else
360d7b241e6Sjeremylt     (*ceed)->Error = CeedErrorAbort;
361d7b241e6Sjeremylt   (*ceed)->refcount = 1;
362d7b241e6Sjeremylt   (*ceed)->data = NULL;
363fe2413ffSjeremylt 
364fe2413ffSjeremylt   // Set lookup table
3656e79d475Sjeremylt   foffset foffsets[] = {
3666e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Error),
3676e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
3686e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Destroy),
369f8902d9eSjeremylt     CEED_FTABLE_ENTRY(Ceed, VectorCreate),
3706e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
3716e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
3726e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
3736e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
3746e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
3756e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
3766e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
3776e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
3786e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetArray),
3796e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetValue),
3806e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArray),
3816e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
3826e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
3836e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
3846e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Destroy),
3856e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
3866e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
3876e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
3886e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Apply),
3896e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Destroy),
3906e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
3916e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
3926e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Apply),
3936e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
3941d102b48SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction),
395b7ec98d8SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal),
3966e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Apply),
3976e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
3986e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Destroy),
3996e79d475Sjeremylt     {NULL, 0} // End of lookup table - used in SetBackendFunction loop
4001dfeef1dSjeremylt   };
401fe2413ffSjeremylt 
4026e79d475Sjeremylt   ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr);
4036e79d475Sjeremylt   memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets));
404fe2413ffSjeremylt 
405fe2413ffSjeremylt   // Backend specific setup
406d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
407fe2413ffSjeremylt 
408*e07206deSjeremylt   // Copy resource prefix, if backend setup sucessful
409*e07206deSjeremylt   size_t len = strlen(backends[matchidx].prefix);
410*e07206deSjeremylt   char *tmp;
411*e07206deSjeremylt   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
412*e07206deSjeremylt   memcpy(tmp, backends[matchidx].prefix, len+1);
413*e07206deSjeremylt   (*ceed)->resource = tmp;
414*e07206deSjeremylt 
415d7b241e6Sjeremylt   return 0;
416d7b241e6Sjeremylt }
417d7b241e6Sjeremylt 
418d7b241e6Sjeremylt /**
4192f86a920SJeremy L Thompson   @brief Retrieve a parent CEED
4202f86a920SJeremy L Thompson 
4212f86a920SJeremy L Thompson   @param ceed           Ceed to retrieve parent of
4222f86a920SJeremy L Thompson   @param[out] parent    Address to save the parent to
4232f86a920SJeremy L Thompson 
4242f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4252f86a920SJeremy L Thompson 
4262f86a920SJeremy L Thompson   @ref Developer
4272f86a920SJeremy L Thompson **/
4282f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
4292f86a920SJeremy L Thompson   int ierr;
4302f86a920SJeremy L Thompson   if (ceed->parent) {
4312f86a920SJeremy L Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
4322f86a920SJeremy L Thompson     return 0;
4332f86a920SJeremy L Thompson   }
4342f86a920SJeremy L Thompson   *parent = ceed;
4352f86a920SJeremy L Thompson   return 0;
4362f86a920SJeremy L Thompson }
4372f86a920SJeremy L Thompson 
4382f86a920SJeremy L Thompson /**
4395fe0d4faSjeremylt   @brief Retrieve a delegate CEED
4405fe0d4faSjeremylt 
4415fe0d4faSjeremylt   @param ceed           Ceed to retrieve delegate of
4425fe0d4faSjeremylt   @param[out] delegate  Address to save the delegate to
4435fe0d4faSjeremylt 
4445fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
4455fe0d4faSjeremylt 
44623617272Sjeremylt   @ref Developer
4475fe0d4faSjeremylt **/
4485fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
4494ce2993fSjeremylt   *delegate = ceed->delegate;
4504ce2993fSjeremylt   return 0;
4514ce2993fSjeremylt }
4524ce2993fSjeremylt 
4534ce2993fSjeremylt /**
4544ce2993fSjeremylt   @brief Set a delegate CEED
4554ce2993fSjeremylt 
456f29ffe77Sjeremylt   This function allows a CEED to set a delegate CEED. All backend
457f29ffe77Sjeremylt   implementations default to the delegate CEED, unless overridden.
458f29ffe77Sjeremylt 
4594ce2993fSjeremylt   @param ceed           Ceed to set delegate of
4604ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
4614ce2993fSjeremylt 
4624ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4634ce2993fSjeremylt 
46423617272Sjeremylt   @ref Advanced
4654ce2993fSjeremylt **/
466a4999eddSjeremylt int CeedSetDelegate(Ceed ceed, Ceed delegate) {
467a4999eddSjeremylt   ceed->delegate = delegate;
468a4999eddSjeremylt   delegate->parent = ceed;
4694ce2993fSjeremylt   return 0;
4704ce2993fSjeremylt }
4714ce2993fSjeremylt 
4724ce2993fSjeremylt /**
473aefd8378Sjeremylt   @brief Retrieve a delegate CEED for a specific object type
474aefd8378Sjeremylt 
475aefd8378Sjeremylt   @param ceed           Ceed to retrieve delegate of
476aefd8378Sjeremylt   @param[out] delegate  Address to save the delegate to
477288c0443SJeremy L Thompson   @param[in] objname    Name of the object type to retrieve delegate for
478aefd8378Sjeremylt 
479aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
480aefd8378Sjeremylt 
481aefd8378Sjeremylt   @ref Developer
482aefd8378Sjeremylt **/
483aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) {
484aefd8378Sjeremylt   CeedInt ierr;
485aefd8378Sjeremylt 
486aefd8378Sjeremylt   // Check for object delegate
4871d102b48SJeremy L Thompson   for (CeedInt i=0; i<ceed->objdelegatecount; i++)
488aefd8378Sjeremylt     if (!strcmp(objname, ceed->objdelegates->objname)) {
489aefd8378Sjeremylt       *delegate = ceed->objdelegates->delegate;
490aefd8378Sjeremylt       return 0;
491aefd8378Sjeremylt     }
492aefd8378Sjeremylt 
493aefd8378Sjeremylt   // Use default delegate if no object delegate
494aefd8378Sjeremylt   ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr);
495aefd8378Sjeremylt 
496aefd8378Sjeremylt   return 0;
497aefd8378Sjeremylt }
498aefd8378Sjeremylt 
499aefd8378Sjeremylt /**
500aefd8378Sjeremylt   @brief Set a delegate CEED for a specific object type
501aefd8378Sjeremylt 
502f29ffe77Sjeremylt   This function allows a CEED to set a delegate CEED for a given type of
503f29ffe77Sjeremylt   CEED object. All backend implementations default to the delegate CEED for
504f29ffe77Sjeremylt   this object. For example,
505f29ffe77Sjeremylt     CeedSetObjectDelegate(ceed, refceed, "Basis")
506f29ffe77Sjeremylt   uses refceed implementations for all CeedBasis backend functions.
507f29ffe77Sjeremylt 
508aefd8378Sjeremylt   @param ceed           Ceed to set delegate of
509aefd8378Sjeremylt   @param[out] delegate  Address to set the delegate to
510288c0443SJeremy L Thompson   @param[in] objname    Name of the object type to set delegate for
511aefd8378Sjeremylt 
512aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
513aefd8378Sjeremylt 
514aefd8378Sjeremylt   @ref Advanced
515aefd8378Sjeremylt **/
516a4999eddSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) {
517aefd8378Sjeremylt   CeedInt ierr;
518aefd8378Sjeremylt   CeedInt count = ceed->objdelegatecount;
519aefd8378Sjeremylt 
520aefd8378Sjeremylt   // Malloc or Realloc
521aefd8378Sjeremylt   if (count) {
5221d102b48SJeremy L Thompson     ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr);
523aefd8378Sjeremylt   } else {
524aefd8378Sjeremylt     ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr);
525aefd8378Sjeremylt   }
526aefd8378Sjeremylt   ceed->objdelegatecount++;
527aefd8378Sjeremylt 
528aefd8378Sjeremylt   // Set object delegate
529a4999eddSjeremylt   ceed->objdelegates[count].delegate = delegate;
53007a02837SJed Brown   size_t slen = strlen(objname) + 1;
53107a02837SJed Brown   ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr);
53207a02837SJed Brown   memcpy(ceed->objdelegates[count].objname, objname, slen);
533aefd8378Sjeremylt 
534aefd8378Sjeremylt   // Set delegate parent
535a4999eddSjeremylt   delegate->parent = ceed;
536aefd8378Sjeremylt 
537aefd8378Sjeremylt   return 0;
538aefd8378Sjeremylt }
539aefd8378Sjeremylt 
540aefd8378Sjeremylt /**
5418c91a0c9SJeremy L Thompson   @brief Return Ceed preferred memory type
542c907536fSjeremylt 
543c907536fSjeremylt   @param ceed           Ceed to get preferred memory type of
544288c0443SJeremy L Thompson   @param[out] type      Address to save preferred memory type to
545c907536fSjeremylt 
546c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
547c907536fSjeremylt 
548c907536fSjeremylt   @ref Basic
549c907536fSjeremylt **/
550c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) {
551c907536fSjeremylt   int ierr;
552c263cd57Sjeremylt 
553c907536fSjeremylt   if (ceed->GetPreferredMemType) {
554c907536fSjeremylt     ierr = ceed->GetPreferredMemType(type); CeedChk(ierr);
555c907536fSjeremylt   } else {
556c263cd57Sjeremylt     Ceed delegate;
557c263cd57Sjeremylt     ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr);
558c263cd57Sjeremylt 
559c263cd57Sjeremylt     if (delegate) {
560c263cd57Sjeremylt       ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr);
561c263cd57Sjeremylt     } else {
562c907536fSjeremylt       *type = CEED_MEM_HOST;
563c907536fSjeremylt     }
564c263cd57Sjeremylt   }
565c907536fSjeremylt 
566c907536fSjeremylt   return 0;
567c907536fSjeremylt }
568c907536fSjeremylt 
569c907536fSjeremylt /**
570fe2413ffSjeremylt   @brief Set a backend function
571fe2413ffSjeremylt 
572cb37edd8Sjeremylt   This function is used for a backend to set the function associated with
573cb37edd8Sjeremylt   the CEED objects. For example,
574f8902d9eSjeremylt     CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate)
575cb37edd8Sjeremylt   sets the backend implementation of 'CeedVectorCreate' and
576cb37edd8Sjeremylt     CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply)
577cb37edd8Sjeremylt   sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed'
578cb37edd8Sjeremylt   is not required for the object type ("Basis" vs "CeedBasis").
579cb37edd8Sjeremylt 
580fe2413ffSjeremylt   @param ceed           Ceed for error handling
581fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
582fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
583fe2413ffSjeremylt   @param fname          Name of function to set
584fe2413ffSjeremylt   @param f              Function to set
585fe2413ffSjeremylt 
586fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
587fe2413ffSjeremylt 
588fe2413ffSjeremylt   @ref Advanced
589fe2413ffSjeremylt **/
590fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed,
591fe2413ffSjeremylt                            const char *type, void *object,
592fe2413ffSjeremylt                            const char *fname, int (*f)()) {
593409ab9adSjeremylt   char lookupname[CEED_MAX_RESOURCE_LEN+1] = "";
594fe2413ffSjeremylt 
595fe2413ffSjeremylt   // Build lookup name
5966e79d475Sjeremylt   if (strcmp(type, "Ceed"))
5976e79d475Sjeremylt     strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN);
598409ab9adSjeremylt   strncat(lookupname, type, CEED_MAX_RESOURCE_LEN);
599409ab9adSjeremylt   strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN);
600fe2413ffSjeremylt 
601fe2413ffSjeremylt   // Find and use offset
6021d102b48SJeremy L Thompson   for (CeedInt i = 0; ceed->foffsets[i].fname; i++)
603fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
604fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
605a7a2e802Sjeremylt       int (**fpointer)(void) = (int (* *)(void))((char *)object + offset);
606a7a2e802Sjeremylt       *fpointer = f;
607fe2413ffSjeremylt       return 0;
608fe2413ffSjeremylt     }
609fe2413ffSjeremylt 
610c042f62fSJeremy L Thompson   // LCOV_EXCL_START
6111d102b48SJeremy L Thompson   return CeedError(ceed, 1, "Requested function '%s' was not found for CEED "
6121d102b48SJeremy L Thompson                    "object '%s'", fname, type);
613c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
614fe2413ffSjeremylt }
615fe2413ffSjeremylt 
616fe2413ffSjeremylt /**
6174ce2993fSjeremylt   @brief Retrieve backend data for a CEED
6184ce2993fSjeremylt 
619fe2413ffSjeremylt   @param ceed           Ceed to retrieve data of
6204ce2993fSjeremylt   @param[out] data      Address to save data to
6214ce2993fSjeremylt 
6224ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6234ce2993fSjeremylt 
62423617272Sjeremylt   @ref Advanced
6254ce2993fSjeremylt **/
6264ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) {
6274ce2993fSjeremylt   *data = ceed->data;
6285fe0d4faSjeremylt   return 0;
6295fe0d4faSjeremylt }
6305fe0d4faSjeremylt 
6315fe0d4faSjeremylt /**
632fe2413ffSjeremylt   @brief Set backend data for a CEED
633fe2413ffSjeremylt 
634fe2413ffSjeremylt   @param ceed           Ceed to set data of
635fe2413ffSjeremylt   @param data           Address of data to set
636fe2413ffSjeremylt 
637fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
638fe2413ffSjeremylt 
639fe2413ffSjeremylt   @ref Advanced
640fe2413ffSjeremylt **/
641fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) {
642fe2413ffSjeremylt   ceed->data = *data;
643fe2413ffSjeremylt   return 0;
644fe2413ffSjeremylt }
645fe2413ffSjeremylt 
646fe2413ffSjeremylt /**
647*e07206deSjeremylt   @brief Get the full resource name for a CEED
648*e07206deSjeremylt 
649*e07206deSjeremylt   @param ceed            Ceed to get resource name of
650*e07206deSjeremylt   @param[out] resource   Variable to store resource name
651*e07206deSjeremylt 
652*e07206deSjeremylt   @return An error code: 0 - success, otherwise - failure
653*e07206deSjeremylt 
654*e07206deSjeremylt   @ref Basic
655*e07206deSjeremylt **/
656*e07206deSjeremylt 
657*e07206deSjeremylt int CeedGetResource(Ceed ceed, const char **resource) {
658*e07206deSjeremylt   *resource = (const char *)ceed->resource;
659*e07206deSjeremylt   return 0;
660*e07206deSjeremylt }
661*e07206deSjeremylt 
662*e07206deSjeremylt /**
663b11c1e72Sjeremylt   @brief Destroy a Ceed context
664d7b241e6Sjeremylt 
665d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
666b11c1e72Sjeremylt 
667b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
668dfdf5a53Sjeremylt 
669dfdf5a53Sjeremylt   @ref Basic
670b11c1e72Sjeremylt **/
671d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
672d7b241e6Sjeremylt   int ierr;
673d7b241e6Sjeremylt 
6741d102b48SJeremy L Thompson   if (!*ceed || --(*ceed)->refcount > 0)
6751d102b48SJeremy L Thompson     return 0;
6765fe0d4faSjeremylt   if ((*ceed)->delegate) {
6775fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
6785fe0d4faSjeremylt   }
679aefd8378Sjeremylt   if ((*ceed)->objdelegatecount > 0) {
680aefd8378Sjeremylt     for (int i=0; i<(*ceed)->objdelegatecount; i++) {
681aefd8378Sjeremylt       ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr);
682aefd8378Sjeremylt       ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr);
683aefd8378Sjeremylt     }
684aefd8378Sjeremylt     ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr);
685aefd8378Sjeremylt   }
686d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
687d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
688d7b241e6Sjeremylt   }
6896e79d475Sjeremylt   ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr);
690*e07206deSjeremylt   ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr);
691d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
692d7b241e6Sjeremylt   return 0;
693d7b241e6Sjeremylt }
694d7b241e6Sjeremylt 
695d7b241e6Sjeremylt /// @}
696