xref: /libCEED/interface/ceed.c (revision c907536f492a0d8a515e9b59267362cd88b5caa9)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17d7b241e6Sjeremylt #define _POSIX_C_SOURCE 200112
18d7b241e6Sjeremylt #include <ceed-impl.h>
19d863ab9bSjeremylt #include <ceed-backend.h>
20aedaa0e5Sjeremylt #include <limits.h>
21d7b241e6Sjeremylt #include <stdarg.h>
22d7b241e6Sjeremylt #include <stdio.h>
23d7b241e6Sjeremylt #include <stdlib.h>
24d7b241e6Sjeremylt #include <string.h>
25d7b241e6Sjeremylt 
26d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
27d7b241e6Sjeremylt static CeedRequest ceed_request_immediate;
28d7b241e6Sjeremylt static CeedRequest ceed_request_ordered;
29d7b241e6Sjeremylt 
30d7b241e6Sjeremylt static struct {
31d7b241e6Sjeremylt   char prefix[CEED_MAX_RESOURCE_LEN];
32d7b241e6Sjeremylt   int (*init)(const char *resource, Ceed f);
33d7b241e6Sjeremylt   unsigned int priority;
34d7b241e6Sjeremylt } backends[32];
35d7b241e6Sjeremylt static size_t num_backends;
36fe2413ffSjeremylt 
37fe2413ffSjeremylt #define ceedoffsetof(st, m) \
38fe2413ffSjeremylt     ((size_t) ( (char *)&((st)(0))->m - (char *)0 ))
39d7b241e6Sjeremylt /// @endcond
40d7b241e6Sjeremylt 
41d7b241e6Sjeremylt /// @file
42d7b241e6Sjeremylt /// Implementation of core components of Ceed library
43d7b241e6Sjeremylt ///
44dfdf5a53Sjeremylt /// @addtogroup Ceed
45d7b241e6Sjeremylt /// @{
46d7b241e6Sjeremylt 
47dfdf5a53Sjeremylt /**
48dfdf5a53Sjeremylt   @brief Request immediate completion
49dfdf5a53Sjeremylt 
50dfdf5a53Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
51dfdf5a53Sjeremylt   interfaces when the caller wishes for the operation to be performed
52dfdf5a53Sjeremylt   immediately.  The code
53dfdf5a53Sjeremylt 
54dfdf5a53Sjeremylt   @code
55dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
56dfdf5a53Sjeremylt   @endcode
57dfdf5a53Sjeremylt 
58dfdf5a53Sjeremylt   is semantically equivalent to
59dfdf5a53Sjeremylt 
60dfdf5a53Sjeremylt   @code
61dfdf5a53Sjeremylt     CeedRequest request;
62dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
63dfdf5a53Sjeremylt     CeedRequestWait(&request);
64dfdf5a53Sjeremylt   @endcode
65dfdf5a53Sjeremylt 
66dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
67dfdf5a53Sjeremylt **/
68d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
69d7b241e6Sjeremylt 
70d7b241e6Sjeremylt /**
71b11c1e72Sjeremylt   @brief Request ordered completion
72d7b241e6Sjeremylt 
73d7b241e6Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
74d7b241e6Sjeremylt   interfaces when the caller wishes for the operation to be completed in the
75d7b241e6Sjeremylt   order that it is submitted to the device.  It is typically used in a construct
76d7b241e6Sjeremylt   such as
77d7b241e6Sjeremylt 
78d7b241e6Sjeremylt   @code
79d7b241e6Sjeremylt     CeedRequest request;
80d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
81d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
82d7b241e6Sjeremylt     // other optional work
83d7b241e6Sjeremylt     CeedWait(&request);
84d7b241e6Sjeremylt   @endcode
85d7b241e6Sjeremylt 
86d7b241e6Sjeremylt   which allows the sequence to complete asynchronously but does not start
87d7b241e6Sjeremylt   `op2` until `op1` has completed.
88d7b241e6Sjeremylt 
89d7b241e6Sjeremylt   @fixme The current implementation is overly strict, offering equivalent
90d7b241e6Sjeremylt   semantics to CEED_REQUEST_IMMEDIATE.
91d7b241e6Sjeremylt 
92d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
93d7b241e6Sjeremylt  */
94d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
95d7b241e6Sjeremylt 
96b11c1e72Sjeremylt /**
97b11c1e72Sjeremylt   @brief Error handling implementation; use \ref CeedError instead.
98dfdf5a53Sjeremylt 
99dfdf5a53Sjeremylt   @ref Developer
100b11c1e72Sjeremylt **/
101d7b241e6Sjeremylt int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func,
102d7b241e6Sjeremylt                   int ecode, const char *format, ...) {
103d7b241e6Sjeremylt   va_list args;
104d7b241e6Sjeremylt   va_start(args, format);
105d7b241e6Sjeremylt   if (ceed) return ceed->Error(ceed, filename, lineno, func, ecode, format, args);
106d7b241e6Sjeremylt   return CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args);
107d7b241e6Sjeremylt }
108d7b241e6Sjeremylt 
109b11c1e72Sjeremylt /**
110b11c1e72Sjeremylt   @brief Error handler that returns without printing anything.
111b11c1e72Sjeremylt 
112b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
113dfdf5a53Sjeremylt 
114dfdf5a53Sjeremylt   @ref Developer
115b11c1e72Sjeremylt **/
116d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno,
117d7b241e6Sjeremylt                     const char *func, int ecode, const char *format,
118d7b241e6Sjeremylt                     va_list args) {
119d7b241e6Sjeremylt   return ecode;
120d7b241e6Sjeremylt }
121d7b241e6Sjeremylt 
122b11c1e72Sjeremylt /**
123b11c1e72Sjeremylt   @brief Error handler that prints to stderr and aborts
124b11c1e72Sjeremylt 
125b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
126dfdf5a53Sjeremylt 
127dfdf5a53Sjeremylt   @ref Developer
128b11c1e72Sjeremylt **/
129d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno,
130d7b241e6Sjeremylt                    const char *func, int ecode,
131d7b241e6Sjeremylt                    const char *format, va_list args) {
132d7b241e6Sjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
133d7b241e6Sjeremylt   vfprintf(stderr, format, args);
134d7b241e6Sjeremylt   fprintf(stderr, "\n");
135d7b241e6Sjeremylt   abort();
136d7b241e6Sjeremylt   return ecode;
137d7b241e6Sjeremylt }
138d7b241e6Sjeremylt 
139b11c1e72Sjeremylt /**
14056e866f4SJed Brown   @brief Error handler that prints to stderr and exits
14156e866f4SJed Brown 
14256e866f4SJed Brown   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
14356e866f4SJed Brown 
14456e866f4SJed Brown   In contrast to CeedErrorAbort(), this exits without a signal, so atexit()
14556e866f4SJed Brown   handlers (e.g., as used by gcov) are run.
14656e866f4SJed Brown 
14756e866f4SJed Brown   @ref Developer
14856e866f4SJed Brown **/
14956e866f4SJed Brown int CeedErrorExit(Ceed ceed, const char *filename, int lineno,
15056e866f4SJed Brown                   const char *func, int ecode,
15156e866f4SJed Brown                   const char *format, va_list args) {
15256e866f4SJed Brown   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
15356e866f4SJed Brown   vfprintf(stderr, format, args);
15456e866f4SJed Brown   fprintf(stderr, "\n");
15556e866f4SJed Brown   exit(ecode);
15656e866f4SJed Brown   return ecode;
15756e866f4SJed Brown }
15856e866f4SJed Brown 
15956e866f4SJed Brown /**
160dfdf5a53Sjeremylt   @brief Set error handler
161b11c1e72Sjeremylt 
162b11c1e72Sjeremylt   A default error handler is set in CeedInit().  Use this function to change
163b11c1e72Sjeremylt   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
164b11c1e72Sjeremylt   error handler.
165dfdf5a53Sjeremylt 
166dfdf5a53Sjeremylt   @ref Developer
167b11c1e72Sjeremylt **/
168d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed,
169d7b241e6Sjeremylt                         int (eh)(Ceed, const char *, int, const char *,
170d7b241e6Sjeremylt                                  int, const char *, va_list)) {
171d7b241e6Sjeremylt   ceed->Error = eh;
172d7b241e6Sjeremylt   return 0;
173d7b241e6Sjeremylt }
174d7b241e6Sjeremylt 
175d7b241e6Sjeremylt /**
176b11c1e72Sjeremylt   @brief Register a Ceed backend
177d7b241e6Sjeremylt 
178d7b241e6Sjeremylt   @param prefix   Prefix of resources for this backend to respond to.  For
179d7b241e6Sjeremylt                     example, the reference backend responds to "/cpu/self".
180d7b241e6Sjeremylt   @param init     Initialization function called by CeedInit() when the backend
181d7b241e6Sjeremylt                     is selected to drive the requested resource.
182d7b241e6Sjeremylt   @param priority Integer priority.  Lower values are preferred in case the
183d7b241e6Sjeremylt                     resource requested by CeedInit() has non-unique best prefix
184d7b241e6Sjeremylt                     match.
185b11c1e72Sjeremylt 
186b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
187dfdf5a53Sjeremylt 
188dfdf5a53Sjeremylt   @ref Advanced
189b11c1e72Sjeremylt **/
190d7b241e6Sjeremylt int CeedRegister(const char *prefix,
191d7b241e6Sjeremylt                  int (*init)(const char *, Ceed), unsigned int priority) {
192d7b241e6Sjeremylt   if (num_backends >= sizeof(backends) / sizeof(backends[0])) {
193d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
194d7b241e6Sjeremylt   }
195d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
196d7b241e6Sjeremylt   backends[num_backends].init = init;
197d7b241e6Sjeremylt   backends[num_backends].priority = priority;
198d7b241e6Sjeremylt   num_backends++;
199d7b241e6Sjeremylt   return 0;
200d7b241e6Sjeremylt }
201d7b241e6Sjeremylt 
202b11c1e72Sjeremylt /**
203b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
204b11c1e72Sjeremylt 
205b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
206b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
207b11c1e72Sjeremylt 
208b11c1e72Sjeremylt   @param n Number of units to allocate
209b11c1e72Sjeremylt   @param unit Size of each unit
210b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
211b11c1e72Sjeremylt 
212b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
213b11c1e72Sjeremylt 
214b11c1e72Sjeremylt   @sa CeedFree()
215dfdf5a53Sjeremylt 
216dfdf5a53Sjeremylt   @ref Advanced
217b11c1e72Sjeremylt **/
218d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
219d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
220d7b241e6Sjeremylt   if (ierr)
221d7b241e6Sjeremylt     return CeedError(NULL, ierr,
222d7b241e6Sjeremylt                      "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
223d7b241e6Sjeremylt   return 0;
224d7b241e6Sjeremylt }
225d7b241e6Sjeremylt 
226b11c1e72Sjeremylt /**
227b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
228b11c1e72Sjeremylt 
229b11c1e72Sjeremylt   Memory usage can be tracked by the library.
230b11c1e72Sjeremylt 
231b11c1e72Sjeremylt   @param n Number of units to allocate
232b11c1e72Sjeremylt   @param unit Size of each unit
233b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
234b11c1e72Sjeremylt 
235b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
236b11c1e72Sjeremylt 
237b11c1e72Sjeremylt   @sa CeedFree()
238dfdf5a53Sjeremylt 
239dfdf5a53Sjeremylt   @ref Advanced
240b11c1e72Sjeremylt **/
241d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
242d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
243d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
244d7b241e6Sjeremylt     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size %zd\n",
245d7b241e6Sjeremylt                      n, unit);
246d7b241e6Sjeremylt   return 0;
247d7b241e6Sjeremylt }
248d7b241e6Sjeremylt 
249b11c1e72Sjeremylt /**
250b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
251b11c1e72Sjeremylt 
252b11c1e72Sjeremylt   Memory usage can be tracked by the library.
253b11c1e72Sjeremylt 
254b11c1e72Sjeremylt   @param n Number of units to allocate
255b11c1e72Sjeremylt   @param unit Size of each unit
256b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
257b11c1e72Sjeremylt 
258b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
259b11c1e72Sjeremylt 
260b11c1e72Sjeremylt   @sa CeedFree()
261dfdf5a53Sjeremylt 
262dfdf5a53Sjeremylt   @ref Advanced
263b11c1e72Sjeremylt **/
264d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
265d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
266d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
267d7b241e6Sjeremylt     return CeedError(NULL, 1,
268d7b241e6Sjeremylt                      "realloc failed to allocate %zd members of size %zd\n",
269d7b241e6Sjeremylt                      n, unit);
270d7b241e6Sjeremylt   return 0;
271d7b241e6Sjeremylt }
272d7b241e6Sjeremylt 
273d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc()
274d7b241e6Sjeremylt ///
275d7b241e6Sjeremylt /// @param p address of pointer to memory.  This argument is of type void* to
276d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed)
277d7b241e6Sjeremylt /// rather than the pointer.
278d7b241e6Sjeremylt int CeedFree(void *p) {
279d7b241e6Sjeremylt   free(*(void **)p);
280d7b241e6Sjeremylt   *(void **)p = NULL;
281d7b241e6Sjeremylt   return 0;
282d7b241e6Sjeremylt }
283d7b241e6Sjeremylt 
284d7b241e6Sjeremylt /**
285b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
286d7b241e6Sjeremylt 
287d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
288d7b241e6Sjeremylt 
289d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
290b11c1e72Sjeremylt 
291b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
292dfdf5a53Sjeremylt 
293dfdf5a53Sjeremylt   @ref Advanced
294b11c1e72Sjeremylt **/
295d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
296d7b241e6Sjeremylt   if (!*req) return 0;
297d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
298d7b241e6Sjeremylt }
299d7b241e6Sjeremylt 
300b11c1e72Sjeremylt /**
301b11c1e72Sjeremylt   @brief Initialize a \ref Ceed to use the specified resource.
302b11c1e72Sjeremylt 
303b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
304b11c1e72Sjeremylt   @param ceed The library context
305b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
306b11c1e72Sjeremylt 
307b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
308dfdf5a53Sjeremylt 
309dfdf5a53Sjeremylt   @ref Basic
310b11c1e72Sjeremylt **/
311d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
312d7b241e6Sjeremylt   int ierr;
313aedaa0e5Sjeremylt   size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority;
314d7b241e6Sjeremylt 
315fe2413ffSjeremylt   // Find matching backend
316d7b241e6Sjeremylt   if (!resource) return CeedError(NULL, 1, "No resource provided");
317d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
318d7b241e6Sjeremylt     size_t n;
319d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
320d7b241e6Sjeremylt     for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {}
321d7b241e6Sjeremylt     priority = backends[i].priority;
322d7b241e6Sjeremylt     if (n > matchlen || (n == matchlen && matchpriority > priority)) {
323d7b241e6Sjeremylt       matchlen = n;
324d7b241e6Sjeremylt       matchpriority = priority;
325d7b241e6Sjeremylt       matchidx = i;
326d7b241e6Sjeremylt     }
327d7b241e6Sjeremylt   }
328d7b241e6Sjeremylt   if (!matchlen) return CeedError(NULL, 1, "No suitable backend");
329fe2413ffSjeremylt 
330fe2413ffSjeremylt   // Setup Ceed
331d7b241e6Sjeremylt   ierr = CeedCalloc(1,ceed); CeedChk(ierr);
332bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
333bc81ce41Sjeremylt   if (!ceed_error_handler) ceed_error_handler = "abort";
334bc81ce41Sjeremylt   if (!strcmp(ceed_error_handler, "exit"))
33556e866f4SJed Brown     (*ceed)->Error = CeedErrorExit;
33656e866f4SJed Brown   else
337d7b241e6Sjeremylt     (*ceed)->Error = CeedErrorAbort;
338d7b241e6Sjeremylt   (*ceed)->refcount = 1;
339d7b241e6Sjeremylt   (*ceed)->data = NULL;
340fe2413ffSjeremylt 
341fe2413ffSjeremylt   // Set lookup table
34228d161eeSjeremylt   foffset foffsets[CEED_NUM_BACKEND_FUNCTIONS] = {
3432c8abac2Sjeremylt     {"CeedError",                  ceedoffsetof(Ceed, Error)},
344*c907536fSjeremylt     {"CeedGetPreferredMemType",    ceedoffsetof(Ceed, GetPreferredMemType)},
345fe2413ffSjeremylt     {"CeedDestroy",                ceedoffsetof(Ceed, Destroy)},
3462c8abac2Sjeremylt     {"CeedVecCreate",              ceedoffsetof(Ceed, VecCreate)},
3472c8abac2Sjeremylt     {"CeedElemRestrictionCreate",  ceedoffsetof(Ceed, ElemRestrictionCreate)},
3489f0427d9SYohann     {
3499f0427d9SYohann       "CeedElemRestrictionCreateBlocked",
3501dfeef1dSjeremylt       ceedoffsetof(Ceed, ElemRestrictionCreateBlocked)
3511dfeef1dSjeremylt     },
3522c8abac2Sjeremylt     {"CeedBasisCreateTensorH1",    ceedoffsetof(Ceed, BasisCreateTensorH1)},
3532c8abac2Sjeremylt     {"CeedBasisCreateH1",          ceedoffsetof(Ceed, BasisCreateH1)},
3542f86a920SJeremy L Thompson     {"CeedTensorContractCreate",   ceedoffsetof(Ceed, TensorContractCreate)},
3552c8abac2Sjeremylt     {"CeedQFunctionCreate",        ceedoffsetof(Ceed, QFunctionCreate)},
3562c8abac2Sjeremylt     {"CeedOperatorCreate",         ceedoffsetof(Ceed, OperatorCreate)},
35752d6035fSJeremy L Thompson     {"CeedCompositeOperatorCreate",ceedoffsetof(Ceed, CompositeOperatorCreate)},
3582c8abac2Sjeremylt     {"VectorSetArray",             ceedoffsetof(CeedVector, SetArray)},
3592c8abac2Sjeremylt     {"VectorSetValue",             ceedoffsetof(CeedVector, SetValue)},
3602c8abac2Sjeremylt     {"VectorGetArray",             ceedoffsetof(CeedVector, GetArray)},
3612c8abac2Sjeremylt     {"VectorGetArrayRead",         ceedoffsetof(CeedVector, GetArrayRead)},
3622c8abac2Sjeremylt     {"VectorRestoreArray",         ceedoffsetof(CeedVector, RestoreArray)},
3632c8abac2Sjeremylt     {"VectorRestoreArrayRead",     ceedoffsetof(CeedVector, RestoreArrayRead)},
364fe2413ffSjeremylt     {"VectorDestroy",              ceedoffsetof(CeedVector, Destroy)},
365fe2413ffSjeremylt     {"ElemRestrictionApply",       ceedoffsetof(CeedElemRestriction, Apply)},
366fe2413ffSjeremylt     {"ElemRestrictionDestroy",     ceedoffsetof(CeedElemRestriction, Destroy)},
367fe2413ffSjeremylt     {"BasisApply",                 ceedoffsetof(CeedBasis, Apply)},
368fe2413ffSjeremylt     {"BasisDestroy",               ceedoffsetof(CeedBasis, Destroy)},
3692f86a920SJeremy L Thompson     {"TensorContractApply",        ceedoffsetof(CeedTensorContract, Apply)},
3702f86a920SJeremy L Thompson     {"TensorContractDestroy",      ceedoffsetof(CeedTensorContract, Destroy)},
371fe2413ffSjeremylt     {"QFunctionApply",             ceedoffsetof(CeedQFunction, Apply)},
372fe2413ffSjeremylt     {"QFunctionDestroy",           ceedoffsetof(CeedQFunction, Destroy)},
373fe2413ffSjeremylt     {"OperatorApply",              ceedoffsetof(CeedOperator, Apply)},
3742c8abac2Sjeremylt     {"OperatorApplyJacobian",      ceedoffsetof(CeedOperator, ApplyJacobian)},
3751dfeef1dSjeremylt     {"OperatorDestroy",            ceedoffsetof(CeedOperator, Destroy)}
3761dfeef1dSjeremylt   };
377fe2413ffSjeremylt 
37828d161eeSjeremylt   memcpy((*ceed)->foffsets, foffsets,
37928d161eeSjeremylt          CEED_NUM_BACKEND_FUNCTIONS*sizeof(foffset));
380fe2413ffSjeremylt 
381fe2413ffSjeremylt   // Backend specific setup
382d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
383fe2413ffSjeremylt 
384d7b241e6Sjeremylt   return 0;
385d7b241e6Sjeremylt }
386d7b241e6Sjeremylt 
387d7b241e6Sjeremylt /**
3882f86a920SJeremy L Thompson   @brief Retrieve a parent CEED
3892f86a920SJeremy L Thompson 
3902f86a920SJeremy L Thompson   @param ceed           Ceed to retrieve parent of
3912f86a920SJeremy L Thompson   @param[out] parent    Address to save the parent to
3922f86a920SJeremy L Thompson 
3932f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3942f86a920SJeremy L Thompson 
3952f86a920SJeremy L Thompson   @ref Developer
3962f86a920SJeremy L Thompson **/
3972f86a920SJeremy L Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
3982f86a920SJeremy L Thompson   int ierr;
3992f86a920SJeremy L Thompson   if (ceed->parent) {
4002f86a920SJeremy L Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
4012f86a920SJeremy L Thompson     return 0;
4022f86a920SJeremy L Thompson   }
4032f86a920SJeremy L Thompson   *parent = ceed;
4042f86a920SJeremy L Thompson   return 0;
4052f86a920SJeremy L Thompson }
4062f86a920SJeremy L Thompson 
4072f86a920SJeremy L Thompson /**
4085fe0d4faSjeremylt   @brief Retrieve a delegate CEED
4095fe0d4faSjeremylt 
4105fe0d4faSjeremylt   @param ceed           Ceed to retrieve delegate of
4115fe0d4faSjeremylt   @param[out] delegate  Address to save the delegate to
4125fe0d4faSjeremylt 
4135fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
4145fe0d4faSjeremylt 
41523617272Sjeremylt   @ref Developer
4165fe0d4faSjeremylt **/
4175fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
4184ce2993fSjeremylt   *delegate = ceed->delegate;
4194ce2993fSjeremylt   return 0;
4204ce2993fSjeremylt }
4214ce2993fSjeremylt 
4224ce2993fSjeremylt /**
4234ce2993fSjeremylt   @brief Set a delegate CEED
4244ce2993fSjeremylt 
4254ce2993fSjeremylt   @param ceed           Ceed to set delegate of
4264ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
4274ce2993fSjeremylt 
4284ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4294ce2993fSjeremylt 
43023617272Sjeremylt   @ref Advanced
4314ce2993fSjeremylt **/
4324ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) {
4334ce2993fSjeremylt   ceed->delegate = *delegate;
4342f86a920SJeremy L Thompson   (*delegate)->parent = ceed;
4354ce2993fSjeremylt   return 0;
4364ce2993fSjeremylt }
4374ce2993fSjeremylt 
4384ce2993fSjeremylt /**
439*c907536fSjeremylt   @brief Return Ceed perferred memory type
440*c907536fSjeremylt 
441*c907536fSjeremylt   @param ceed           Ceed to get preferred memory type of
442*c907536fSjeremylt   @param[out] delegate  Address to save preferred memory type to
443*c907536fSjeremylt 
444*c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
445*c907536fSjeremylt 
446*c907536fSjeremylt   @ref Basic
447*c907536fSjeremylt **/
448*c907536fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) {
449*c907536fSjeremylt   int ierr;
450*c907536fSjeremylt   if (ceed->GetPreferredMemType) {
451*c907536fSjeremylt     ierr = ceed->GetPreferredMemType(type); CeedChk(ierr);
452*c907536fSjeremylt   } else {
453*c907536fSjeremylt     *type = CEED_MEM_HOST;
454*c907536fSjeremylt   }
455*c907536fSjeremylt 
456*c907536fSjeremylt   return 0;
457*c907536fSjeremylt }
458*c907536fSjeremylt 
459*c907536fSjeremylt /**
460fe2413ffSjeremylt   @brief Set a backend function
461fe2413ffSjeremylt 
462fe2413ffSjeremylt   @param ceed           Ceed for error handling
463fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
464fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
465fe2413ffSjeremylt   @param fname          Name of function to set
466fe2413ffSjeremylt   @param f              Function to set
467fe2413ffSjeremylt 
468fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
469fe2413ffSjeremylt 
470fe2413ffSjeremylt   @ref Advanced
471fe2413ffSjeremylt **/
472fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed,
473fe2413ffSjeremylt                            const char *type, void *object,
474fe2413ffSjeremylt                            const char *fname, int (*f)()) {
475fe2413ffSjeremylt   char lookupname[100];
476fe2413ffSjeremylt   strcpy(lookupname, "");
477fe2413ffSjeremylt 
478fe2413ffSjeremylt   // Build lookup name
479fe2413ffSjeremylt   strcat(strcat(lookupname, type), fname);
480fe2413ffSjeremylt 
481fe2413ffSjeremylt   // Find and use offset
48228d161eeSjeremylt   for (CeedInt i = 0; i < CEED_NUM_BACKEND_FUNCTIONS; i++) {
483fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
484fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
485fe2413ffSjeremylt       size_t *fpointer;
486fe2413ffSjeremylt       fpointer = (size_t *)(object + offset);
487fe2413ffSjeremylt       *fpointer = (size_t) f;
488fe2413ffSjeremylt       return 0;
489fe2413ffSjeremylt     }
490fe2413ffSjeremylt   }
491fe2413ffSjeremylt 
4921dfeef1dSjeremylt   return CeedError(ceed, 1,
4931dfeef1dSjeremylt                    "Requested function '%s' was not found for CEED object '%s'", fname, type);
494fe2413ffSjeremylt }
495fe2413ffSjeremylt 
496fe2413ffSjeremylt /**
4974ce2993fSjeremylt   @brief Retrieve backend data for a CEED
4984ce2993fSjeremylt 
499fe2413ffSjeremylt   @param ceed           Ceed to retrieve data of
5004ce2993fSjeremylt   @param[out] data      Address to save data to
5014ce2993fSjeremylt 
5024ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
5034ce2993fSjeremylt 
50423617272Sjeremylt   @ref Advanced
5054ce2993fSjeremylt **/
5064ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) {
5074ce2993fSjeremylt   *data = ceed->data;
5085fe0d4faSjeremylt   return 0;
5095fe0d4faSjeremylt }
5105fe0d4faSjeremylt 
5115fe0d4faSjeremylt /**
512fe2413ffSjeremylt   @brief Set backend data for a CEED
513fe2413ffSjeremylt 
514fe2413ffSjeremylt   @param ceed           Ceed to set data of
515fe2413ffSjeremylt   @param data           Address of data to set
516fe2413ffSjeremylt 
517fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
518fe2413ffSjeremylt 
519fe2413ffSjeremylt   @ref Advanced
520fe2413ffSjeremylt **/
521fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) {
522fe2413ffSjeremylt   ceed->data = *data;
523fe2413ffSjeremylt   return 0;
524fe2413ffSjeremylt }
525fe2413ffSjeremylt 
526fe2413ffSjeremylt /**
527b11c1e72Sjeremylt   @brief Destroy a Ceed context
528d7b241e6Sjeremylt 
529d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
530b11c1e72Sjeremylt 
531b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
532dfdf5a53Sjeremylt 
533dfdf5a53Sjeremylt   @ref Basic
534b11c1e72Sjeremylt **/
535d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
536d7b241e6Sjeremylt   int ierr;
537d7b241e6Sjeremylt 
538d7b241e6Sjeremylt   if (!*ceed || --(*ceed)->refcount > 0) return 0;
5395fe0d4faSjeremylt   if ((*ceed)->delegate) {
5405fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
5415fe0d4faSjeremylt   }
542d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
543d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
544d7b241e6Sjeremylt   }
545d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
546d7b241e6Sjeremylt   return 0;
547d7b241e6Sjeremylt }
548d7b241e6Sjeremylt 
549d7b241e6Sjeremylt /// @}
550