xref: /libCEED/interface/ceed.c (revision aefd83785c2df88dfccc51fc4901501fa3238add)
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 
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;
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,
138d7b241e6Sjeremylt                    const char *func, int ecode,
139d7b241e6Sjeremylt                    const char *format, 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) {
200d7b241e6Sjeremylt   if (num_backends >= sizeof(backends) / sizeof(backends[0])) {
201d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
202d7b241e6Sjeremylt   }
203d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
204d7b241e6Sjeremylt   backends[num_backends].init = init;
205d7b241e6Sjeremylt   backends[num_backends].priority = priority;
206d7b241e6Sjeremylt   num_backends++;
207d7b241e6Sjeremylt   return 0;
208d7b241e6Sjeremylt }
209d7b241e6Sjeremylt 
210b11c1e72Sjeremylt /**
211b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
212b11c1e72Sjeremylt 
213b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
214b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
215b11c1e72Sjeremylt 
216b11c1e72Sjeremylt   @param n Number of units to allocate
217b11c1e72Sjeremylt   @param unit Size of each unit
218b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
219b11c1e72Sjeremylt 
220b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
221b11c1e72Sjeremylt 
222b11c1e72Sjeremylt   @sa CeedFree()
223dfdf5a53Sjeremylt 
224dfdf5a53Sjeremylt   @ref Advanced
225b11c1e72Sjeremylt **/
226d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
227d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
228d7b241e6Sjeremylt   if (ierr)
229d7b241e6Sjeremylt     return CeedError(NULL, ierr,
230d7b241e6Sjeremylt                      "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
231d7b241e6Sjeremylt   return 0;
232d7b241e6Sjeremylt }
233d7b241e6Sjeremylt 
234b11c1e72Sjeremylt /**
235b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
236b11c1e72Sjeremylt 
237b11c1e72Sjeremylt   Memory usage can be tracked by the library.
238b11c1e72Sjeremylt 
239b11c1e72Sjeremylt   @param n Number of units to allocate
240b11c1e72Sjeremylt   @param unit Size of each unit
241b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
242b11c1e72Sjeremylt 
243b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
244b11c1e72Sjeremylt 
245b11c1e72Sjeremylt   @sa CeedFree()
246dfdf5a53Sjeremylt 
247dfdf5a53Sjeremylt   @ref Advanced
248b11c1e72Sjeremylt **/
249d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
250d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
251d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
252d7b241e6Sjeremylt     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size %zd\n",
253d7b241e6Sjeremylt                      n, unit);
254d7b241e6Sjeremylt   return 0;
255d7b241e6Sjeremylt }
256d7b241e6Sjeremylt 
257b11c1e72Sjeremylt /**
258b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
259b11c1e72Sjeremylt 
260b11c1e72Sjeremylt   Memory usage can be tracked by the library.
261b11c1e72Sjeremylt 
262b11c1e72Sjeremylt   @param n Number of units to allocate
263b11c1e72Sjeremylt   @param unit Size of each unit
264b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
265b11c1e72Sjeremylt 
266b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
267b11c1e72Sjeremylt 
268b11c1e72Sjeremylt   @sa CeedFree()
269dfdf5a53Sjeremylt 
270dfdf5a53Sjeremylt   @ref Advanced
271b11c1e72Sjeremylt **/
272d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
273d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
274d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
275d7b241e6Sjeremylt     return CeedError(NULL, 1,
276d7b241e6Sjeremylt                      "realloc failed to allocate %zd members of size %zd\n",
277d7b241e6Sjeremylt                      n, unit);
278d7b241e6Sjeremylt   return 0;
279d7b241e6Sjeremylt }
280d7b241e6Sjeremylt 
281d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc()
282d7b241e6Sjeremylt ///
283d7b241e6Sjeremylt /// @param p address of pointer to memory.  This argument is of type void* to
284d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed)
285d7b241e6Sjeremylt /// rather than the pointer.
286d7b241e6Sjeremylt int CeedFree(void *p) {
287d7b241e6Sjeremylt   free(*(void **)p);
288d7b241e6Sjeremylt   *(void **)p = NULL;
289d7b241e6Sjeremylt   return 0;
290d7b241e6Sjeremylt }
291d7b241e6Sjeremylt 
292d7b241e6Sjeremylt /**
293b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
294d7b241e6Sjeremylt 
295d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
296d7b241e6Sjeremylt 
297d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
298b11c1e72Sjeremylt 
299b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
300dfdf5a53Sjeremylt 
301dfdf5a53Sjeremylt   @ref Advanced
302b11c1e72Sjeremylt **/
303d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
304d7b241e6Sjeremylt   if (!*req) return 0;
305d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
306d7b241e6Sjeremylt }
307d7b241e6Sjeremylt 
308b11c1e72Sjeremylt /**
309b11c1e72Sjeremylt   @brief Initialize a \ref Ceed to use the specified resource.
310b11c1e72Sjeremylt 
311b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
312b11c1e72Sjeremylt   @param ceed The library context
313b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
314b11c1e72Sjeremylt 
315b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
316dfdf5a53Sjeremylt 
317dfdf5a53Sjeremylt   @ref Basic
318b11c1e72Sjeremylt **/
319d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
320d7b241e6Sjeremylt   int ierr;
321aedaa0e5Sjeremylt   size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority;
322d7b241e6Sjeremylt 
323fe2413ffSjeremylt   // Find matching backend
324d7b241e6Sjeremylt   if (!resource) return CeedError(NULL, 1, "No resource provided");
325d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
326d7b241e6Sjeremylt     size_t n;
327d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
328d7b241e6Sjeremylt     for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {}
329d7b241e6Sjeremylt     priority = backends[i].priority;
330d7b241e6Sjeremylt     if (n > matchlen || (n == matchlen && matchpriority > priority)) {
331d7b241e6Sjeremylt       matchlen = n;
332d7b241e6Sjeremylt       matchpriority = priority;
333d7b241e6Sjeremylt       matchidx = i;
334d7b241e6Sjeremylt     }
335d7b241e6Sjeremylt   }
336d7b241e6Sjeremylt   if (!matchlen) return CeedError(NULL, 1, "No suitable backend");
337fe2413ffSjeremylt 
338fe2413ffSjeremylt   // Setup Ceed
339d7b241e6Sjeremylt   ierr = CeedCalloc(1,ceed); CeedChk(ierr);
340bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
341bc81ce41Sjeremylt   if (!ceed_error_handler) ceed_error_handler = "abort";
342bc81ce41Sjeremylt   if (!strcmp(ceed_error_handler, "exit"))
34356e866f4SJed Brown     (*ceed)->Error = CeedErrorExit;
34456e866f4SJed Brown   else
345d7b241e6Sjeremylt     (*ceed)->Error = CeedErrorAbort;
346d7b241e6Sjeremylt   (*ceed)->refcount = 1;
347d7b241e6Sjeremylt   (*ceed)->data = NULL;
348fe2413ffSjeremylt 
349fe2413ffSjeremylt   // Set lookup table
3506e79d475Sjeremylt   foffset foffsets[] = {
3516e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Error),
3526e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
3536e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Destroy),
354f8902d9eSjeremylt     CEED_FTABLE_ENTRY(Ceed, VectorCreate),
3556e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
3566e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
3576e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
3586e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
3596e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
3606e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
3616e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
3626e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
3636e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetArray),
3646e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetValue),
3656e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArray),
3666e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
3676e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
3686e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
3696e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Destroy),
3706e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
3716e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
3726e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
3736e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Apply),
3746e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Destroy),
3756e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
3766e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
3776e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Apply),
3786e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
3796e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Apply),
3806e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
3816e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Destroy),
3826e79d475Sjeremylt     {NULL, 0} // End of lookup table - used in SetBackendFunction loop
3831dfeef1dSjeremylt   };
384fe2413ffSjeremylt 
3856e79d475Sjeremylt   ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr);
3866e79d475Sjeremylt   memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets));
387fe2413ffSjeremylt 
388fe2413ffSjeremylt   // Backend specific setup
389d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
390fe2413ffSjeremylt 
391d7b241e6Sjeremylt   return 0;
392d7b241e6Sjeremylt }
393d7b241e6Sjeremylt 
394d7b241e6Sjeremylt /**
3952f86a920SJeremy L Thompson   @brief Retrieve a parent CEED
3962f86a920SJeremy L Thompson 
3972f86a920SJeremy L Thompson   @param ceed           Ceed to retrieve parent of
3982f86a920SJeremy L Thompson   @param[out] parent    Address to save the parent to
3992f86a920SJeremy L Thompson 
4002f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4012f86a920SJeremy L Thompson 
4022f86a920SJeremy L Thompson   @ref Developer
4032f86a920SJeremy L Thompson **/
4042f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
4052f86a920SJeremy L Thompson   int ierr;
4062f86a920SJeremy L Thompson   if (ceed->parent) {
4072f86a920SJeremy L Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
4082f86a920SJeremy L Thompson     return 0;
4092f86a920SJeremy L Thompson   }
4102f86a920SJeremy L Thompson   *parent = ceed;
4112f86a920SJeremy L Thompson   return 0;
4122f86a920SJeremy L Thompson }
4132f86a920SJeremy L Thompson 
4142f86a920SJeremy L Thompson /**
4155fe0d4faSjeremylt   @brief Retrieve a delegate CEED
4165fe0d4faSjeremylt 
4175fe0d4faSjeremylt   @param ceed           Ceed to retrieve delegate of
4185fe0d4faSjeremylt   @param[out] delegate  Address to save the delegate to
4195fe0d4faSjeremylt 
4205fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
4215fe0d4faSjeremylt 
42223617272Sjeremylt   @ref Developer
4235fe0d4faSjeremylt **/
4245fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
4254ce2993fSjeremylt   *delegate = ceed->delegate;
4264ce2993fSjeremylt   return 0;
4274ce2993fSjeremylt }
4284ce2993fSjeremylt 
4294ce2993fSjeremylt /**
4304ce2993fSjeremylt   @brief Set a delegate CEED
4314ce2993fSjeremylt 
4324ce2993fSjeremylt   @param ceed           Ceed to set delegate of
4334ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
4344ce2993fSjeremylt 
4354ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4364ce2993fSjeremylt 
43723617272Sjeremylt   @ref Advanced
4384ce2993fSjeremylt **/
4394ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) {
4404ce2993fSjeremylt   ceed->delegate = *delegate;
4412f86a920SJeremy L Thompson   (*delegate)->parent = ceed;
4424ce2993fSjeremylt   return 0;
4434ce2993fSjeremylt }
4444ce2993fSjeremylt 
4454ce2993fSjeremylt /**
446*aefd8378Sjeremylt   @brief Retrieve a delegate CEED for a specific object type
447*aefd8378Sjeremylt 
448*aefd8378Sjeremylt   @param ceed           Ceed to retrieve delegate of
449*aefd8378Sjeremylt   @param[out] delegate  Address to save the delegate to
450*aefd8378Sjeremylt 
451*aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
452*aefd8378Sjeremylt 
453*aefd8378Sjeremylt   @ref Developer
454*aefd8378Sjeremylt **/
455*aefd8378Sjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) {
456*aefd8378Sjeremylt   CeedInt ierr;
457*aefd8378Sjeremylt 
458*aefd8378Sjeremylt   // Check for object delegate
459*aefd8378Sjeremylt   for (CeedInt i=0; i<ceed->objdelegatecount; i++) {
460*aefd8378Sjeremylt     if (!strcmp(objname, ceed->objdelegates->objname)) {
461*aefd8378Sjeremylt       *delegate = ceed->objdelegates->delegate;
462*aefd8378Sjeremylt       return 0;
463*aefd8378Sjeremylt     }
464*aefd8378Sjeremylt   }
465*aefd8378Sjeremylt 
466*aefd8378Sjeremylt   // Use default delegate if no object delegate
467*aefd8378Sjeremylt   ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr);
468*aefd8378Sjeremylt 
469*aefd8378Sjeremylt   return 0;
470*aefd8378Sjeremylt }
471*aefd8378Sjeremylt 
472*aefd8378Sjeremylt /**
473*aefd8378Sjeremylt   @brief Set a delegate CEED for a specific object type
474*aefd8378Sjeremylt 
475*aefd8378Sjeremylt   @param ceed           Ceed to set delegate of
476*aefd8378Sjeremylt   @param[out] delegate  Address to set the delegate to
477*aefd8378Sjeremylt 
478*aefd8378Sjeremylt   @return An error code: 0 - success, otherwise - failure
479*aefd8378Sjeremylt 
480*aefd8378Sjeremylt   @ref Advanced
481*aefd8378Sjeremylt **/
482*aefd8378Sjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) {
483*aefd8378Sjeremylt   CeedInt ierr;
484*aefd8378Sjeremylt   CeedInt count = ceed->objdelegatecount;
485*aefd8378Sjeremylt 
486*aefd8378Sjeremylt   // Malloc or Realloc
487*aefd8378Sjeremylt   if (count) {
488*aefd8378Sjeremylt     ierr = CeedRealloc(count+1, &ceed->objdelegates);
489*aefd8378Sjeremylt     CeedChk(ierr);
490*aefd8378Sjeremylt   } else {
491*aefd8378Sjeremylt     ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr);
492*aefd8378Sjeremylt   }
493*aefd8378Sjeremylt   ceed->objdelegatecount++;
494*aefd8378Sjeremylt 
495*aefd8378Sjeremylt   // Set object delegate
496*aefd8378Sjeremylt   ceed->objdelegates[count].delegate = *delegate;
497*aefd8378Sjeremylt   ierr = CeedCalloc(strlen(objname)+1, &ceed->objdelegates[count].objname);
498*aefd8378Sjeremylt   CeedChk(ierr);
499*aefd8378Sjeremylt   strncpy(ceed->objdelegates[count].objname, objname, strlen(objname)+1);
500*aefd8378Sjeremylt 
501*aefd8378Sjeremylt   // Set delegate parent
502*aefd8378Sjeremylt   (*delegate)->parent = ceed;
503*aefd8378Sjeremylt 
504*aefd8378Sjeremylt   return 0;
505*aefd8378Sjeremylt }
506*aefd8378Sjeremylt 
507*aefd8378Sjeremylt /**
508c907536fSjeremylt   @brief Return Ceed perferred memory type
509c907536fSjeremylt 
510c907536fSjeremylt   @param ceed           Ceed to get preferred memory type of
511c907536fSjeremylt   @param[out] delegate  Address to save preferred memory type to
512c907536fSjeremylt 
513c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
514c907536fSjeremylt 
515c907536fSjeremylt   @ref Basic
516c907536fSjeremylt **/
517c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) {
518c907536fSjeremylt   int ierr;
519c907536fSjeremylt   if (ceed->GetPreferredMemType) {
520c907536fSjeremylt     ierr = ceed->GetPreferredMemType(type); CeedChk(ierr);
521c907536fSjeremylt   } else {
522c907536fSjeremylt     *type = CEED_MEM_HOST;
523c907536fSjeremylt   }
524c907536fSjeremylt 
525c907536fSjeremylt   return 0;
526c907536fSjeremylt }
527c907536fSjeremylt 
528c907536fSjeremylt /**
529fe2413ffSjeremylt   @brief Set a backend function
530fe2413ffSjeremylt 
531cb37edd8Sjeremylt   This function is used for a backend to set the function associated with
532cb37edd8Sjeremylt   the CEED objects. For example,
533f8902d9eSjeremylt     CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate)
534cb37edd8Sjeremylt   sets the backend implementation of 'CeedVectorCreate' and
535cb37edd8Sjeremylt     CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply)
536cb37edd8Sjeremylt   sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed'
537cb37edd8Sjeremylt   is not required for the object type ("Basis" vs "CeedBasis").
538cb37edd8Sjeremylt 
539fe2413ffSjeremylt   @param ceed           Ceed for error handling
540fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
541fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
542fe2413ffSjeremylt   @param fname          Name of function to set
543fe2413ffSjeremylt   @param f              Function to set
544fe2413ffSjeremylt 
545fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
546fe2413ffSjeremylt 
547fe2413ffSjeremylt   @ref Advanced
548fe2413ffSjeremylt **/
549fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed,
550fe2413ffSjeremylt                            const char *type, void *object,
551fe2413ffSjeremylt                            const char *fname, int (*f)()) {
552409ab9adSjeremylt   char lookupname[CEED_MAX_RESOURCE_LEN+1] = "";
553fe2413ffSjeremylt 
554fe2413ffSjeremylt   // Build lookup name
5556e79d475Sjeremylt   if (strcmp(type, "Ceed"))
5566e79d475Sjeremylt     strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN);
557409ab9adSjeremylt   strncat(lookupname, type, CEED_MAX_RESOURCE_LEN);
558409ab9adSjeremylt   strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN);
559fe2413ffSjeremylt 
560fe2413ffSjeremylt   // Find and use offset
5616e79d475Sjeremylt   for (CeedInt i = 0; ceed->foffsets[i].fname; i++) {
562fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
563fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
564a7a2e802Sjeremylt       int (**fpointer)(void) = (int (**)(void))((char*)object + offset);
565a7a2e802Sjeremylt       *fpointer = f;
566fe2413ffSjeremylt       return 0;
567fe2413ffSjeremylt     }
568fe2413ffSjeremylt   }
569fe2413ffSjeremylt 
5701dfeef1dSjeremylt   return CeedError(ceed, 1,
5711dfeef1dSjeremylt                    "Requested function '%s' was not found for CEED object '%s'", fname, type);
572fe2413ffSjeremylt }
573fe2413ffSjeremylt 
574fe2413ffSjeremylt /**
5754ce2993fSjeremylt   @brief Retrieve backend data for a CEED
5764ce2993fSjeremylt 
577fe2413ffSjeremylt   @param ceed           Ceed to retrieve data of
5784ce2993fSjeremylt   @param[out] data      Address to save data to
5794ce2993fSjeremylt 
5804ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
5814ce2993fSjeremylt 
58223617272Sjeremylt   @ref Advanced
5834ce2993fSjeremylt **/
5844ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) {
5854ce2993fSjeremylt   *data = ceed->data;
5865fe0d4faSjeremylt   return 0;
5875fe0d4faSjeremylt }
5885fe0d4faSjeremylt 
5895fe0d4faSjeremylt /**
590fe2413ffSjeremylt   @brief Set backend data for a CEED
591fe2413ffSjeremylt 
592fe2413ffSjeremylt   @param ceed           Ceed to set data of
593fe2413ffSjeremylt   @param data           Address of data to set
594fe2413ffSjeremylt 
595fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
596fe2413ffSjeremylt 
597fe2413ffSjeremylt   @ref Advanced
598fe2413ffSjeremylt **/
599fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) {
600fe2413ffSjeremylt   ceed->data = *data;
601fe2413ffSjeremylt   return 0;
602fe2413ffSjeremylt }
603fe2413ffSjeremylt 
604fe2413ffSjeremylt /**
605b11c1e72Sjeremylt   @brief Destroy a Ceed context
606d7b241e6Sjeremylt 
607d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
608b11c1e72Sjeremylt 
609b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
610dfdf5a53Sjeremylt 
611dfdf5a53Sjeremylt   @ref Basic
612b11c1e72Sjeremylt **/
613d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
614d7b241e6Sjeremylt   int ierr;
615d7b241e6Sjeremylt 
616d7b241e6Sjeremylt   if (!*ceed || --(*ceed)->refcount > 0) return 0;
6175fe0d4faSjeremylt   if ((*ceed)->delegate) {
6185fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
6195fe0d4faSjeremylt   }
620*aefd8378Sjeremylt   if ((*ceed)->objdelegatecount > 0) {
621*aefd8378Sjeremylt     for (int i=0; i<(*ceed)->objdelegatecount; i++) {
622*aefd8378Sjeremylt       ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr);
623*aefd8378Sjeremylt       ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr);
624*aefd8378Sjeremylt     }
625*aefd8378Sjeremylt     ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr);
626*aefd8378Sjeremylt   }
627d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
628d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
629d7b241e6Sjeremylt   }
6306e79d475Sjeremylt   ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr);
631d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
632d7b241e6Sjeremylt   return 0;
633d7b241e6Sjeremylt }
634d7b241e6Sjeremylt 
635d7b241e6Sjeremylt /// @}
636